session_convert.go 20 KB

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