session_convert.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. // Copyright 2017 The Xorm Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package xorm
  5. import (
  6. "database/sql"
  7. "database/sql/driver"
  8. "encoding/json"
  9. "errors"
  10. "fmt"
  11. "reflect"
  12. "strconv"
  13. "strings"
  14. "time"
  15. "github.com/go-xorm/core"
  16. )
  17. func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) {
  18. sdata := strings.TrimSpace(data)
  19. var x time.Time
  20. var err error
  21. var parseLoc = session.engine.DatabaseTZ
  22. if col.TimeZone != nil {
  23. parseLoc = col.TimeZone
  24. }
  25. if sdata == zeroTime0 || sdata == zeroTime1 {
  26. } else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column
  27. // time stamp
  28. sd, err := strconv.ParseInt(sdata, 10, 64)
  29. if err == nil {
  30. x = time.Unix(sd, 0)
  31. //session.engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
  32. } else {
  33. //session.engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
  34. }
  35. } else if len(sdata) > 19 && strings.Contains(sdata, "-") {
  36. x, err = time.ParseInLocation(time.RFC3339Nano, sdata, parseLoc)
  37. session.engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
  38. if err != nil {
  39. x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, parseLoc)
  40. //session.engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
  41. }
  42. if err != nil {
  43. x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, parseLoc)
  44. //session.engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
  45. }
  46. } else if len(sdata) == 19 && strings.Contains(sdata, "-") {
  47. x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, parseLoc)
  48. //session.engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
  49. } else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' {
  50. x, err = time.ParseInLocation("2006-01-02", sdata, parseLoc)
  51. //session.engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
  52. } else if col.SQLType.Name == core.Time {
  53. if strings.Contains(sdata, " ") {
  54. ssd := strings.Split(sdata, " ")
  55. sdata = ssd[1]
  56. }
  57. sdata = strings.TrimSpace(sdata)
  58. if session.engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 {
  59. sdata = sdata[len(sdata)-8:]
  60. }
  61. st := fmt.Sprintf("2006-01-02 %v", sdata)
  62. x, err = time.ParseInLocation("2006-01-02 15:04:05", st, parseLoc)
  63. //session.engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata)
  64. } else {
  65. outErr = fmt.Errorf("unsupported time format %v", sdata)
  66. return
  67. }
  68. if err != nil {
  69. outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err)
  70. return
  71. }
  72. outTime = x.In(session.engine.TZLocation)
  73. return
  74. }
  75. func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) {
  76. return session.str2Time(col, string(data))
  77. }
  78. // convert a db data([]byte) to a field value
  79. func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error {
  80. if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
  81. return structConvert.FromDB(data)
  82. }
  83. if structConvert, ok := fieldValue.Interface().(core.Conversion); ok {
  84. return structConvert.FromDB(data)
  85. }
  86. var v interface{}
  87. key := col.Name
  88. fieldType := fieldValue.Type()
  89. switch fieldType.Kind() {
  90. case reflect.Complex64, reflect.Complex128:
  91. x := reflect.New(fieldType)
  92. if len(data) > 0 {
  93. err := json.Unmarshal(data, x.Interface())
  94. if err != nil {
  95. session.engine.logger.Error(err)
  96. return err
  97. }
  98. fieldValue.Set(x.Elem())
  99. }
  100. case reflect.Slice, reflect.Array, reflect.Map:
  101. v = data
  102. t := fieldType.Elem()
  103. k := t.Kind()
  104. if col.SQLType.IsText() {
  105. x := reflect.New(fieldType)
  106. if len(data) > 0 {
  107. err := json.Unmarshal(data, x.Interface())
  108. if err != nil {
  109. session.engine.logger.Error(err)
  110. return err
  111. }
  112. fieldValue.Set(x.Elem())
  113. }
  114. } else if col.SQLType.IsBlob() {
  115. if k == reflect.Uint8 {
  116. fieldValue.Set(reflect.ValueOf(v))
  117. } else {
  118. x := reflect.New(fieldType)
  119. if len(data) > 0 {
  120. err := json.Unmarshal(data, x.Interface())
  121. if err != nil {
  122. session.engine.logger.Error(err)
  123. return err
  124. }
  125. fieldValue.Set(x.Elem())
  126. }
  127. }
  128. } else {
  129. return ErrUnSupportedType
  130. }
  131. case reflect.String:
  132. fieldValue.SetString(string(data))
  133. case reflect.Bool:
  134. v, err := asBool(data)
  135. if err != nil {
  136. return fmt.Errorf("arg %v as bool: %s", key, err.Error())
  137. }
  138. fieldValue.Set(reflect.ValueOf(v))
  139. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  140. sdata := string(data)
  141. var x int64
  142. var err error
  143. // for mysql, when use bit, it returned \x01
  144. if col.SQLType.Name == core.Bit &&
  145. session.engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
  146. if len(data) == 1 {
  147. x = int64(data[0])
  148. } else {
  149. x = 0
  150. }
  151. } else if strings.HasPrefix(sdata, "0x") {
  152. x, err = strconv.ParseInt(sdata, 16, 64)
  153. } else if strings.HasPrefix(sdata, "0") {
  154. x, err = strconv.ParseInt(sdata, 8, 64)
  155. } else if strings.EqualFold(sdata, "true") {
  156. x = 1
  157. } else if strings.EqualFold(sdata, "false") {
  158. x = 0
  159. } else {
  160. x, err = strconv.ParseInt(sdata, 10, 64)
  161. }
  162. if err != nil {
  163. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  164. }
  165. fieldValue.SetInt(x)
  166. case reflect.Float32, reflect.Float64:
  167. x, err := strconv.ParseFloat(string(data), 64)
  168. if err != nil {
  169. return fmt.Errorf("arg %v as float64: %s", key, err.Error())
  170. }
  171. fieldValue.SetFloat(x)
  172. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
  173. x, err := strconv.ParseUint(string(data), 10, 64)
  174. if err != nil {
  175. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  176. }
  177. fieldValue.SetUint(x)
  178. //Currently only support Time type
  179. case reflect.Struct:
  180. // !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
  181. if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
  182. if err := nulVal.Scan(data); err != nil {
  183. return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error())
  184. }
  185. } else {
  186. if fieldType.ConvertibleTo(core.TimeType) {
  187. x, err := session.byte2Time(col, data)
  188. if err != nil {
  189. return err
  190. }
  191. v = x
  192. fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
  193. } else if session.statement.UseCascade {
  194. table, err := session.engine.autoMapType(*fieldValue)
  195. if err != nil {
  196. return err
  197. }
  198. // TODO: current only support 1 primary key
  199. if len(table.PrimaryKeys) > 1 {
  200. return errors.New("unsupported composited primary key cascade")
  201. }
  202. var pk = make(core.PK, len(table.PrimaryKeys))
  203. rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
  204. pk[0], err = str2PK(string(data), rawValueType)
  205. if err != nil {
  206. return err
  207. }
  208. if !isPKZero(pk) {
  209. // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
  210. // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
  211. // property to be fetched lazily
  212. structInter := reflect.New(fieldValue.Type())
  213. has, err := session.ID(pk).NoCascade().get(structInter.Interface())
  214. if err != nil {
  215. return err
  216. }
  217. if has {
  218. v = structInter.Elem().Interface()
  219. fieldValue.Set(reflect.ValueOf(v))
  220. } else {
  221. return errors.New("cascade obj is not exist")
  222. }
  223. }
  224. }
  225. }
  226. case reflect.Ptr:
  227. // !nashtsai! TODO merge duplicated codes above
  228. //typeStr := fieldType.String()
  229. switch fieldType.Elem().Kind() {
  230. // case "*string":
  231. case core.StringType.Kind():
  232. x := string(data)
  233. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  234. // case "*bool":
  235. case core.BoolType.Kind():
  236. d := string(data)
  237. v, err := strconv.ParseBool(d)
  238. if err != nil {
  239. return fmt.Errorf("arg %v as bool: %s", key, err.Error())
  240. }
  241. fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType))
  242. // case "*complex64":
  243. case core.Complex64Type.Kind():
  244. var x complex64
  245. if len(data) > 0 {
  246. err := json.Unmarshal(data, &x)
  247. if err != nil {
  248. session.engine.logger.Error(err)
  249. return err
  250. }
  251. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  252. }
  253. // case "*complex128":
  254. case core.Complex128Type.Kind():
  255. var x complex128
  256. if len(data) > 0 {
  257. err := json.Unmarshal(data, &x)
  258. if err != nil {
  259. session.engine.logger.Error(err)
  260. return err
  261. }
  262. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  263. }
  264. // case "*float64":
  265. case core.Float64Type.Kind():
  266. x, err := strconv.ParseFloat(string(data), 64)
  267. if err != nil {
  268. return fmt.Errorf("arg %v as float64: %s", key, err.Error())
  269. }
  270. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  271. // case "*float32":
  272. case core.Float32Type.Kind():
  273. var x float32
  274. x1, err := strconv.ParseFloat(string(data), 32)
  275. if err != nil {
  276. return fmt.Errorf("arg %v as float32: %s", key, err.Error())
  277. }
  278. x = float32(x1)
  279. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  280. // case "*uint64":
  281. case core.Uint64Type.Kind():
  282. var x uint64
  283. x, err := strconv.ParseUint(string(data), 10, 64)
  284. if err != nil {
  285. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  286. }
  287. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  288. // case "*uint":
  289. case core.UintType.Kind():
  290. var x uint
  291. x1, err := strconv.ParseUint(string(data), 10, 64)
  292. if err != nil {
  293. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  294. }
  295. x = uint(x1)
  296. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  297. // case "*uint32":
  298. case core.Uint32Type.Kind():
  299. var x uint32
  300. x1, err := strconv.ParseUint(string(data), 10, 64)
  301. if err != nil {
  302. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  303. }
  304. x = uint32(x1)
  305. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  306. // case "*uint8":
  307. case core.Uint8Type.Kind():
  308. var x uint8
  309. x1, err := strconv.ParseUint(string(data), 10, 64)
  310. if err != nil {
  311. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  312. }
  313. x = uint8(x1)
  314. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  315. // case "*uint16":
  316. case core.Uint16Type.Kind():
  317. var x uint16
  318. x1, err := strconv.ParseUint(string(data), 10, 64)
  319. if err != nil {
  320. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  321. }
  322. x = uint16(x1)
  323. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  324. // case "*int64":
  325. case core.Int64Type.Kind():
  326. sdata := string(data)
  327. var x int64
  328. var err error
  329. // for mysql, when use bit, it returned \x01
  330. if col.SQLType.Name == core.Bit &&
  331. strings.Contains(session.engine.DriverName(), "mysql") {
  332. if len(data) == 1 {
  333. x = int64(data[0])
  334. } else {
  335. x = 0
  336. }
  337. } else if strings.HasPrefix(sdata, "0x") {
  338. x, err = strconv.ParseInt(sdata, 16, 64)
  339. } else if strings.HasPrefix(sdata, "0") {
  340. x, err = strconv.ParseInt(sdata, 8, 64)
  341. } else {
  342. x, err = strconv.ParseInt(sdata, 10, 64)
  343. }
  344. if err != nil {
  345. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  346. }
  347. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  348. // case "*int":
  349. case core.IntType.Kind():
  350. sdata := string(data)
  351. var x int
  352. var x1 int64
  353. var err error
  354. // for mysql, when use bit, it returned \x01
  355. if col.SQLType.Name == core.Bit &&
  356. strings.Contains(session.engine.DriverName(), "mysql") {
  357. if len(data) == 1 {
  358. x = int(data[0])
  359. } else {
  360. x = 0
  361. }
  362. } else if strings.HasPrefix(sdata, "0x") {
  363. x1, err = strconv.ParseInt(sdata, 16, 64)
  364. x = int(x1)
  365. } else if strings.HasPrefix(sdata, "0") {
  366. x1, err = strconv.ParseInt(sdata, 8, 64)
  367. x = int(x1)
  368. } else {
  369. x1, err = strconv.ParseInt(sdata, 10, 64)
  370. x = int(x1)
  371. }
  372. if err != nil {
  373. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  374. }
  375. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  376. // case "*int32":
  377. case core.Int32Type.Kind():
  378. sdata := string(data)
  379. var x int32
  380. var x1 int64
  381. var err error
  382. // for mysql, when use bit, it returned \x01
  383. if col.SQLType.Name == core.Bit &&
  384. session.engine.dialect.DBType() == core.MYSQL {
  385. if len(data) == 1 {
  386. x = int32(data[0])
  387. } else {
  388. x = 0
  389. }
  390. } else if strings.HasPrefix(sdata, "0x") {
  391. x1, err = strconv.ParseInt(sdata, 16, 64)
  392. x = int32(x1)
  393. } else if strings.HasPrefix(sdata, "0") {
  394. x1, err = strconv.ParseInt(sdata, 8, 64)
  395. x = int32(x1)
  396. } else {
  397. x1, err = strconv.ParseInt(sdata, 10, 64)
  398. x = int32(x1)
  399. }
  400. if err != nil {
  401. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  402. }
  403. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  404. // case "*int8":
  405. case core.Int8Type.Kind():
  406. sdata := string(data)
  407. var x int8
  408. var x1 int64
  409. var err error
  410. // for mysql, when use bit, it returned \x01
  411. if col.SQLType.Name == core.Bit &&
  412. strings.Contains(session.engine.DriverName(), "mysql") {
  413. if len(data) == 1 {
  414. x = int8(data[0])
  415. } else {
  416. x = 0
  417. }
  418. } else if strings.HasPrefix(sdata, "0x") {
  419. x1, err = strconv.ParseInt(sdata, 16, 64)
  420. x = int8(x1)
  421. } else if strings.HasPrefix(sdata, "0") {
  422. x1, err = strconv.ParseInt(sdata, 8, 64)
  423. x = int8(x1)
  424. } else {
  425. x1, err = strconv.ParseInt(sdata, 10, 64)
  426. x = int8(x1)
  427. }
  428. if err != nil {
  429. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  430. }
  431. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  432. // case "*int16":
  433. case core.Int16Type.Kind():
  434. sdata := string(data)
  435. var x int16
  436. var x1 int64
  437. var err error
  438. // for mysql, when use bit, it returned \x01
  439. if col.SQLType.Name == core.Bit &&
  440. strings.Contains(session.engine.DriverName(), "mysql") {
  441. if len(data) == 1 {
  442. x = int16(data[0])
  443. } else {
  444. x = 0
  445. }
  446. } else if strings.HasPrefix(sdata, "0x") {
  447. x1, err = strconv.ParseInt(sdata, 16, 64)
  448. x = int16(x1)
  449. } else if strings.HasPrefix(sdata, "0") {
  450. x1, err = strconv.ParseInt(sdata, 8, 64)
  451. x = int16(x1)
  452. } else {
  453. x1, err = strconv.ParseInt(sdata, 10, 64)
  454. x = int16(x1)
  455. }
  456. if err != nil {
  457. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  458. }
  459. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  460. // case "*SomeStruct":
  461. case reflect.Struct:
  462. switch fieldType {
  463. // case "*.time.Time":
  464. case core.PtrTimeType:
  465. x, err := session.byte2Time(col, data)
  466. if err != nil {
  467. return err
  468. }
  469. v = x
  470. fieldValue.Set(reflect.ValueOf(&x))
  471. default:
  472. if session.statement.UseCascade {
  473. structInter := reflect.New(fieldType.Elem())
  474. table, err := session.engine.autoMapType(structInter.Elem())
  475. if err != nil {
  476. return err
  477. }
  478. if len(table.PrimaryKeys) > 1 {
  479. return errors.New("unsupported composited primary key cascade")
  480. }
  481. var pk = make(core.PK, len(table.PrimaryKeys))
  482. rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
  483. pk[0], err = str2PK(string(data), rawValueType)
  484. if err != nil {
  485. return err
  486. }
  487. if !isPKZero(pk) {
  488. // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
  489. // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
  490. // property to be fetched lazily
  491. has, err := session.ID(pk).NoCascade().get(structInter.Interface())
  492. if err != nil {
  493. return err
  494. }
  495. if has {
  496. v = structInter.Interface()
  497. fieldValue.Set(reflect.ValueOf(v))
  498. } else {
  499. return errors.New("cascade obj is not exist")
  500. }
  501. }
  502. } else {
  503. return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
  504. }
  505. }
  506. default:
  507. return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
  508. }
  509. default:
  510. return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
  511. }
  512. return nil
  513. }
  514. // convert a field value of a struct to interface for put into db
  515. func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) {
  516. if fieldValue.CanAddr() {
  517. if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
  518. data, err := fieldConvert.ToDB()
  519. if err != nil {
  520. return 0, err
  521. }
  522. if col.SQLType.IsBlob() {
  523. return data, nil
  524. }
  525. return string(data), nil
  526. }
  527. }
  528. if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok {
  529. data, err := fieldConvert.ToDB()
  530. if err != nil {
  531. return 0, err
  532. }
  533. if col.SQLType.IsBlob() {
  534. return data, nil
  535. }
  536. return string(data), nil
  537. }
  538. fieldType := fieldValue.Type()
  539. k := fieldType.Kind()
  540. if k == reflect.Ptr {
  541. if fieldValue.IsNil() {
  542. return nil, nil
  543. } else if !fieldValue.IsValid() {
  544. session.engine.logger.Warn("the field[", col.FieldName, "] is invalid")
  545. return nil, nil
  546. } else {
  547. // !nashtsai! deference pointer type to instance type
  548. fieldValue = fieldValue.Elem()
  549. fieldType = fieldValue.Type()
  550. k = fieldType.Kind()
  551. }
  552. }
  553. switch k {
  554. case reflect.Bool:
  555. return fieldValue.Bool(), nil
  556. case reflect.String:
  557. return fieldValue.String(), nil
  558. case reflect.Struct:
  559. if fieldType.ConvertibleTo(core.TimeType) {
  560. t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
  561. tf := session.engine.formatColTime(col, t)
  562. return tf, nil
  563. }
  564. if !col.SQLType.IsJson() {
  565. // !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
  566. if v, ok := fieldValue.Interface().(driver.Valuer); ok {
  567. return v.Value()
  568. }
  569. fieldTable, err := session.engine.autoMapType(fieldValue)
  570. if err != nil {
  571. return nil, err
  572. }
  573. if len(fieldTable.PrimaryKeys) == 1 {
  574. pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
  575. return pkField.Interface(), nil
  576. }
  577. return 0, fmt.Errorf("no primary key for col %v", col.Name)
  578. }
  579. if col.SQLType.IsText() {
  580. bytes, err := json.Marshal(fieldValue.Interface())
  581. if err != nil {
  582. session.engine.logger.Error(err)
  583. return 0, err
  584. }
  585. return string(bytes), nil
  586. } else if col.SQLType.IsBlob() {
  587. bytes, err := json.Marshal(fieldValue.Interface())
  588. if err != nil {
  589. session.engine.logger.Error(err)
  590. return 0, err
  591. }
  592. return bytes, nil
  593. }
  594. return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
  595. case reflect.Complex64, reflect.Complex128:
  596. bytes, err := json.Marshal(fieldValue.Interface())
  597. if err != nil {
  598. session.engine.logger.Error(err)
  599. return 0, err
  600. }
  601. return string(bytes), nil
  602. case reflect.Array, reflect.Slice, reflect.Map:
  603. if !fieldValue.IsValid() {
  604. return fieldValue.Interface(), nil
  605. }
  606. if col.SQLType.IsText() {
  607. bytes, err := json.Marshal(fieldValue.Interface())
  608. if err != nil {
  609. session.engine.logger.Error(err)
  610. return 0, err
  611. }
  612. return string(bytes), nil
  613. } else if col.SQLType.IsBlob() {
  614. var bytes []byte
  615. var err error
  616. if (k == reflect.Array || k == reflect.Slice) &&
  617. (fieldValue.Type().Elem().Kind() == reflect.Uint8) {
  618. bytes = fieldValue.Bytes()
  619. } else {
  620. bytes, err = json.Marshal(fieldValue.Interface())
  621. if err != nil {
  622. session.engine.logger.Error(err)
  623. return 0, err
  624. }
  625. }
  626. return bytes, nil
  627. }
  628. return nil, ErrUnSupportedType
  629. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
  630. return int64(fieldValue.Uint()), nil
  631. default:
  632. return fieldValue.Interface(), nil
  633. }
  634. }