session_convert.go 19 KB

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