session_convert.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  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/xormplus/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. d := string(data)
  135. v, err := strconv.ParseBool(d)
  136. if err != nil {
  137. return fmt.Errorf("arg %v as bool: %s", key, err.Error())
  138. }
  139. fieldValue.Set(reflect.ValueOf(v))
  140. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  141. sdata := string(data)
  142. var x int64
  143. var err error
  144. // for mysql, when use bit, it returned \x01
  145. if col.SQLType.Name == core.Bit &&
  146. session.Engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API
  147. if len(data) == 1 {
  148. x = int64(data[0])
  149. } else {
  150. x = 0
  151. }
  152. } else if strings.HasPrefix(sdata, "0x") {
  153. x, err = strconv.ParseInt(sdata, 16, 64)
  154. } else if strings.HasPrefix(sdata, "0") {
  155. x, err = strconv.ParseInt(sdata, 8, 64)
  156. } else if strings.EqualFold(sdata, "true") {
  157. x = 1
  158. } else if strings.EqualFold(sdata, "false") {
  159. x = 0
  160. } else {
  161. x, err = strconv.ParseInt(sdata, 10, 64)
  162. }
  163. if err != nil {
  164. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  165. }
  166. fieldValue.SetInt(x)
  167. case reflect.Float32, reflect.Float64:
  168. x, err := strconv.ParseFloat(string(data), 64)
  169. if err != nil {
  170. return fmt.Errorf("arg %v as float64: %s", key, err.Error())
  171. }
  172. fieldValue.SetFloat(x)
  173. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
  174. x, err := strconv.ParseUint(string(data), 10, 64)
  175. if err != nil {
  176. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  177. }
  178. fieldValue.SetUint(x)
  179. //Currently only support Time type
  180. case reflect.Struct:
  181. // !<winxxp>! 增加支持sql.Scanner接口的结构,如sql.NullString
  182. if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok {
  183. if err := nulVal.Scan(data); err != nil {
  184. return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error())
  185. }
  186. } else {
  187. if fieldType.ConvertibleTo(core.TimeType) {
  188. x, err := session.byte2Time(col, data)
  189. if err != nil {
  190. return err
  191. }
  192. v = x
  193. fieldValue.Set(reflect.ValueOf(v).Convert(fieldType))
  194. } else if session.Statement.UseCascade {
  195. table, err := session.Engine.autoMapType(*fieldValue)
  196. if err != nil {
  197. return err
  198. }
  199. // TODO: current only support 1 primary key
  200. if len(table.PrimaryKeys) > 1 {
  201. return errors.New("unsupported composited primary key cascade")
  202. }
  203. var pk = make(core.PK, len(table.PrimaryKeys))
  204. rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
  205. pk[0], err = str2PK(string(data), rawValueType)
  206. if err != nil {
  207. return err
  208. }
  209. if !isPKZero(pk) {
  210. // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
  211. // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
  212. // property to be fetched lazily
  213. structInter := reflect.New(fieldValue.Type())
  214. newsession := session.Engine.NewSession()
  215. defer newsession.Close()
  216. has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
  217. if err != nil {
  218. return err
  219. }
  220. if has {
  221. v = structInter.Elem().Interface()
  222. fieldValue.Set(reflect.ValueOf(v))
  223. } else {
  224. return errors.New("cascade obj is not exist")
  225. }
  226. }
  227. }
  228. }
  229. case reflect.Ptr:
  230. // !nashtsai! TODO merge duplicated codes above
  231. //typeStr := fieldType.String()
  232. switch fieldType.Elem().Kind() {
  233. // case "*string":
  234. case core.StringType.Kind():
  235. x := string(data)
  236. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  237. // case "*bool":
  238. case core.BoolType.Kind():
  239. d := string(data)
  240. v, err := strconv.ParseBool(d)
  241. if err != nil {
  242. return fmt.Errorf("arg %v as bool: %s", key, err.Error())
  243. }
  244. fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType))
  245. // case "*complex64":
  246. case core.Complex64Type.Kind():
  247. var x complex64
  248. if len(data) > 0 {
  249. err := json.Unmarshal(data, &x)
  250. if err != nil {
  251. session.Engine.logger.Error(err)
  252. return err
  253. }
  254. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  255. }
  256. // case "*complex128":
  257. case core.Complex128Type.Kind():
  258. var x complex128
  259. if len(data) > 0 {
  260. err := json.Unmarshal(data, &x)
  261. if err != nil {
  262. session.Engine.logger.Error(err)
  263. return err
  264. }
  265. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  266. }
  267. // case "*float64":
  268. case core.Float64Type.Kind():
  269. x, err := strconv.ParseFloat(string(data), 64)
  270. if err != nil {
  271. return fmt.Errorf("arg %v as float64: %s", key, err.Error())
  272. }
  273. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  274. // case "*float32":
  275. case core.Float32Type.Kind():
  276. var x float32
  277. x1, err := strconv.ParseFloat(string(data), 32)
  278. if err != nil {
  279. return fmt.Errorf("arg %v as float32: %s", key, err.Error())
  280. }
  281. x = float32(x1)
  282. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  283. // case "*uint64":
  284. case core.Uint64Type.Kind():
  285. var x uint64
  286. x, err := strconv.ParseUint(string(data), 10, 64)
  287. if err != nil {
  288. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  289. }
  290. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  291. // case "*uint":
  292. case core.UintType.Kind():
  293. var x uint
  294. x1, err := strconv.ParseUint(string(data), 10, 64)
  295. if err != nil {
  296. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  297. }
  298. x = uint(x1)
  299. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  300. // case "*uint32":
  301. case core.Uint32Type.Kind():
  302. var x uint32
  303. x1, err := strconv.ParseUint(string(data), 10, 64)
  304. if err != nil {
  305. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  306. }
  307. x = uint32(x1)
  308. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  309. // case "*uint8":
  310. case core.Uint8Type.Kind():
  311. var x uint8
  312. x1, err := strconv.ParseUint(string(data), 10, 64)
  313. if err != nil {
  314. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  315. }
  316. x = uint8(x1)
  317. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  318. // case "*uint16":
  319. case core.Uint16Type.Kind():
  320. var x uint16
  321. x1, err := strconv.ParseUint(string(data), 10, 64)
  322. if err != nil {
  323. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  324. }
  325. x = uint16(x1)
  326. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  327. // case "*int64":
  328. case core.Int64Type.Kind():
  329. sdata := string(data)
  330. var x int64
  331. var err error
  332. // for mysql, when use bit, it returned \x01
  333. if col.SQLType.Name == core.Bit &&
  334. strings.Contains(session.Engine.DriverName(), "mysql") {
  335. if len(data) == 1 {
  336. x = int64(data[0])
  337. } else {
  338. x = 0
  339. }
  340. } else if strings.HasPrefix(sdata, "0x") {
  341. x, err = strconv.ParseInt(sdata, 16, 64)
  342. } else if strings.HasPrefix(sdata, "0") {
  343. x, err = strconv.ParseInt(sdata, 8, 64)
  344. } else {
  345. x, err = strconv.ParseInt(sdata, 10, 64)
  346. }
  347. if err != nil {
  348. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  349. }
  350. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  351. // case "*int":
  352. case core.IntType.Kind():
  353. sdata := string(data)
  354. var x int
  355. var x1 int64
  356. var err error
  357. // for mysql, when use bit, it returned \x01
  358. if col.SQLType.Name == core.Bit &&
  359. strings.Contains(session.Engine.DriverName(), "mysql") {
  360. if len(data) == 1 {
  361. x = int(data[0])
  362. } else {
  363. x = 0
  364. }
  365. } else if strings.HasPrefix(sdata, "0x") {
  366. x1, err = strconv.ParseInt(sdata, 16, 64)
  367. x = int(x1)
  368. } else if strings.HasPrefix(sdata, "0") {
  369. x1, err = strconv.ParseInt(sdata, 8, 64)
  370. x = int(x1)
  371. } else {
  372. x1, err = strconv.ParseInt(sdata, 10, 64)
  373. x = int(x1)
  374. }
  375. if err != nil {
  376. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  377. }
  378. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  379. // case "*int32":
  380. case core.Int32Type.Kind():
  381. sdata := string(data)
  382. var x int32
  383. var x1 int64
  384. var err error
  385. // for mysql, when use bit, it returned \x01
  386. if col.SQLType.Name == core.Bit &&
  387. session.Engine.dialect.DBType() == core.MYSQL {
  388. if len(data) == 1 {
  389. x = int32(data[0])
  390. } else {
  391. x = 0
  392. }
  393. } else if strings.HasPrefix(sdata, "0x") {
  394. x1, err = strconv.ParseInt(sdata, 16, 64)
  395. x = int32(x1)
  396. } else if strings.HasPrefix(sdata, "0") {
  397. x1, err = strconv.ParseInt(sdata, 8, 64)
  398. x = int32(x1)
  399. } else {
  400. x1, err = strconv.ParseInt(sdata, 10, 64)
  401. x = int32(x1)
  402. }
  403. if err != nil {
  404. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  405. }
  406. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  407. // case "*int8":
  408. case core.Int8Type.Kind():
  409. sdata := string(data)
  410. var x int8
  411. var x1 int64
  412. var err error
  413. // for mysql, when use bit, it returned \x01
  414. if col.SQLType.Name == core.Bit &&
  415. strings.Contains(session.Engine.DriverName(), "mysql") {
  416. if len(data) == 1 {
  417. x = int8(data[0])
  418. } else {
  419. x = 0
  420. }
  421. } else if strings.HasPrefix(sdata, "0x") {
  422. x1, err = strconv.ParseInt(sdata, 16, 64)
  423. x = int8(x1)
  424. } else if strings.HasPrefix(sdata, "0") {
  425. x1, err = strconv.ParseInt(sdata, 8, 64)
  426. x = int8(x1)
  427. } else {
  428. x1, err = strconv.ParseInt(sdata, 10, 64)
  429. x = int8(x1)
  430. }
  431. if err != nil {
  432. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  433. }
  434. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  435. // case "*int16":
  436. case core.Int16Type.Kind():
  437. sdata := string(data)
  438. var x int16
  439. var x1 int64
  440. var err error
  441. // for mysql, when use bit, it returned \x01
  442. if col.SQLType.Name == core.Bit &&
  443. strings.Contains(session.Engine.DriverName(), "mysql") {
  444. if len(data) == 1 {
  445. x = int16(data[0])
  446. } else {
  447. x = 0
  448. }
  449. } else if strings.HasPrefix(sdata, "0x") {
  450. x1, err = strconv.ParseInt(sdata, 16, 64)
  451. x = int16(x1)
  452. } else if strings.HasPrefix(sdata, "0") {
  453. x1, err = strconv.ParseInt(sdata, 8, 64)
  454. x = int16(x1)
  455. } else {
  456. x1, err = strconv.ParseInt(sdata, 10, 64)
  457. x = int16(x1)
  458. }
  459. if err != nil {
  460. return fmt.Errorf("arg %v as int: %s", key, err.Error())
  461. }
  462. fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType))
  463. // case "*SomeStruct":
  464. case reflect.Struct:
  465. switch fieldType {
  466. // case "*.time.Time":
  467. case core.PtrTimeType:
  468. x, err := session.byte2Time(col, data)
  469. if err != nil {
  470. return err
  471. }
  472. v = x
  473. fieldValue.Set(reflect.ValueOf(&x))
  474. default:
  475. if session.Statement.UseCascade {
  476. structInter := reflect.New(fieldType.Elem())
  477. table, err := session.Engine.autoMapType(structInter.Elem())
  478. if err != nil {
  479. return err
  480. }
  481. if len(table.PrimaryKeys) > 1 {
  482. return errors.New("unsupported composited primary key cascade")
  483. }
  484. var pk = make(core.PK, len(table.PrimaryKeys))
  485. rawValueType := table.ColumnType(table.PKColumns()[0].FieldName)
  486. pk[0], err = str2PK(string(data), rawValueType)
  487. if err != nil {
  488. return err
  489. }
  490. if !isPKZero(pk) {
  491. // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch
  492. // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne
  493. // property to be fetched lazily
  494. newsession := session.Engine.NewSession()
  495. defer newsession.Close()
  496. has, err := newsession.Id(pk).NoCascade().Get(structInter.Interface())
  497. if err != nil {
  498. return err
  499. }
  500. if has {
  501. v = structInter.Interface()
  502. fieldValue.Set(reflect.ValueOf(v))
  503. } else {
  504. return errors.New("cascade obj is not exist")
  505. }
  506. }
  507. } else {
  508. return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String())
  509. }
  510. }
  511. default:
  512. return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
  513. }
  514. default:
  515. return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String())
  516. }
  517. return nil
  518. }
  519. // convert a field value of a struct to interface for put into db
  520. func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) {
  521. if fieldValue.CanAddr() {
  522. if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok {
  523. data, err := fieldConvert.ToDB()
  524. if err != nil {
  525. return 0, err
  526. }
  527. if col.SQLType.IsBlob() {
  528. return data, nil
  529. }
  530. return string(data), nil
  531. }
  532. }
  533. if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok {
  534. data, err := fieldConvert.ToDB()
  535. if err != nil {
  536. return 0, err
  537. }
  538. if col.SQLType.IsBlob() {
  539. return data, nil
  540. }
  541. return string(data), nil
  542. }
  543. fieldType := fieldValue.Type()
  544. k := fieldType.Kind()
  545. if k == reflect.Ptr {
  546. if fieldValue.IsNil() {
  547. return nil, nil
  548. } else if !fieldValue.IsValid() {
  549. session.Engine.logger.Warn("the field[", col.FieldName, "] is invalid")
  550. return nil, nil
  551. } else {
  552. // !nashtsai! deference pointer type to instance type
  553. fieldValue = fieldValue.Elem()
  554. fieldType = fieldValue.Type()
  555. k = fieldType.Kind()
  556. }
  557. }
  558. switch k {
  559. case reflect.Bool:
  560. return fieldValue.Bool(), nil
  561. case reflect.String:
  562. return fieldValue.String(), nil
  563. case reflect.Struct:
  564. if fieldType.ConvertibleTo(core.TimeType) {
  565. t := fieldValue.Convert(core.TimeType).Interface().(time.Time)
  566. tf := session.Engine.formatColTime(col, t)
  567. return tf, nil
  568. }
  569. if !col.SQLType.IsJson() {
  570. // !<winxxp>! 增加支持driver.Valuer接口的结构,如sql.NullString
  571. if v, ok := fieldValue.Interface().(driver.Valuer); ok {
  572. return v.Value()
  573. }
  574. fieldTable, err := session.Engine.autoMapType(fieldValue)
  575. if err != nil {
  576. return nil, err
  577. }
  578. if len(fieldTable.PrimaryKeys) == 1 {
  579. pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName)
  580. return pkField.Interface(), nil
  581. }
  582. return 0, fmt.Errorf("no primary key for col %v", col.Name)
  583. }
  584. if col.SQLType.IsText() {
  585. bytes, err := json.Marshal(fieldValue.Interface())
  586. if err != nil {
  587. session.Engine.logger.Error(err)
  588. return 0, err
  589. }
  590. return string(bytes), nil
  591. } else if col.SQLType.IsBlob() {
  592. bytes, err := json.Marshal(fieldValue.Interface())
  593. if err != nil {
  594. session.Engine.logger.Error(err)
  595. return 0, err
  596. }
  597. return bytes, nil
  598. }
  599. return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type())
  600. case reflect.Complex64, reflect.Complex128:
  601. bytes, err := json.Marshal(fieldValue.Interface())
  602. if err != nil {
  603. session.Engine.logger.Error(err)
  604. return 0, err
  605. }
  606. return string(bytes), nil
  607. case reflect.Array, reflect.Slice, reflect.Map:
  608. if !fieldValue.IsValid() {
  609. return fieldValue.Interface(), nil
  610. }
  611. if col.SQLType.IsText() {
  612. bytes, err := json.Marshal(fieldValue.Interface())
  613. if err != nil {
  614. session.Engine.logger.Error(err)
  615. return 0, err
  616. }
  617. return string(bytes), nil
  618. } else if col.SQLType.IsBlob() {
  619. var bytes []byte
  620. var err error
  621. if (k == reflect.Array || k == reflect.Slice) &&
  622. (fieldValue.Type().Elem().Kind() == reflect.Uint8) {
  623. bytes = fieldValue.Bytes()
  624. } else {
  625. bytes, err = json.Marshal(fieldValue.Interface())
  626. if err != nil {
  627. session.Engine.logger.Error(err)
  628. return 0, err
  629. }
  630. }
  631. return bytes, nil
  632. }
  633. return nil, ErrUnSupportedType
  634. case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
  635. return int64(fieldValue.Uint()), nil
  636. default:
  637. return fieldValue.Interface(), nil
  638. }
  639. }