session_convert.go 20 KB

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