gdb_func.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gdb
  7. import (
  8. "bytes"
  9. "context"
  10. "fmt"
  11. "reflect"
  12. "regexp"
  13. "strings"
  14. "time"
  15. "github.com/gogf/gf/v2/container/garray"
  16. "github.com/gogf/gf/v2/encoding/gjson"
  17. "github.com/gogf/gf/v2/internal/empty"
  18. "github.com/gogf/gf/v2/internal/reflection"
  19. "github.com/gogf/gf/v2/internal/utils"
  20. "github.com/gogf/gf/v2/os/gstructs"
  21. "github.com/gogf/gf/v2/os/gtime"
  22. "github.com/gogf/gf/v2/text/gregex"
  23. "github.com/gogf/gf/v2/text/gstr"
  24. "github.com/gogf/gf/v2/util/gconv"
  25. "github.com/gogf/gf/v2/util/gmeta"
  26. "github.com/gogf/gf/v2/util/gutil"
  27. )
  28. // iString is the type assert api for String.
  29. type iString interface {
  30. String() string
  31. }
  32. // iIterator is the type assert api for Iterator.
  33. type iIterator interface {
  34. Iterator(f func(key, value interface{}) bool)
  35. }
  36. // iInterfaces is the type assert api for Interfaces.
  37. type iInterfaces interface {
  38. Interfaces() []interface{}
  39. }
  40. // iNil if the type assert api for IsNil.
  41. type iNil interface {
  42. IsNil() bool
  43. }
  44. // iTableName is the interface for retrieving table name for struct.
  45. type iTableName interface {
  46. TableName() string
  47. }
  48. const (
  49. OrmTagForStruct = "orm"
  50. OrmTagForTable = "table"
  51. OrmTagForWith = "with"
  52. OrmTagForWithWhere = "where"
  53. OrmTagForWithOrder = "order"
  54. OrmTagForDo = "do"
  55. )
  56. var (
  57. // quoteWordReg is the regular expression object for a word check.
  58. quoteWordReg = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`)
  59. // structTagPriority tags for struct converting for orm field mapping.
  60. structTagPriority = append([]string{OrmTagForStruct}, gconv.StructTagPriority...)
  61. )
  62. // WithDB injects given db object into context and returns a new context.
  63. func WithDB(ctx context.Context, db DB) context.Context {
  64. if db == nil {
  65. return ctx
  66. }
  67. dbCtx := db.GetCtx()
  68. if ctxDb := DBFromCtx(dbCtx); ctxDb != nil {
  69. return dbCtx
  70. }
  71. ctx = context.WithValue(ctx, ctxKeyForDB, db)
  72. return ctx
  73. }
  74. // DBFromCtx retrieves and returns DB object from context.
  75. func DBFromCtx(ctx context.Context) DB {
  76. if ctx == nil {
  77. return nil
  78. }
  79. v := ctx.Value(ctxKeyForDB)
  80. if v != nil {
  81. return v.(DB)
  82. }
  83. return nil
  84. }
  85. // ToSQL formats and returns the last one of sql statements in given closure function
  86. // WITHOUT TRULY EXECUTING IT.
  87. // Be caution that, all the following sql statements should use the context object passing by function `f`.
  88. func ToSQL(ctx context.Context, f func(ctx context.Context) error) (sql string, err error) {
  89. var manager = &CatchSQLManager{
  90. SQLArray: garray.NewStrArray(),
  91. DoCommit: false,
  92. }
  93. ctx = context.WithValue(ctx, ctxKeyCatchSQL, manager)
  94. err = f(ctx)
  95. sql, _ = manager.SQLArray.PopRight()
  96. return
  97. }
  98. // CatchSQL catches and returns all sql statements that are EXECUTED in given closure function.
  99. // Be caution that, all the following sql statements should use the context object passing by function `f`.
  100. func CatchSQL(ctx context.Context, f func(ctx context.Context) error) (sqlArray []string, err error) {
  101. var manager = &CatchSQLManager{
  102. SQLArray: garray.NewStrArray(),
  103. DoCommit: true,
  104. }
  105. ctx = context.WithValue(ctx, ctxKeyCatchSQL, manager)
  106. err = f(ctx)
  107. return manager.SQLArray.Slice(), err
  108. }
  109. // isDoStruct checks and returns whether given type is a DO struct.
  110. func isDoStruct(object interface{}) bool {
  111. // It checks by struct name like "XxxForDao", to be compatible with old version.
  112. // TODO remove this compatible codes in future.
  113. reflectType := reflect.TypeOf(object)
  114. if gstr.HasSuffix(reflectType.String(), modelForDaoSuffix) {
  115. return true
  116. }
  117. // It checks by struct meta for DO struct in version.
  118. if ormTag := gmeta.Get(object, OrmTagForStruct); !ormTag.IsEmpty() {
  119. match, _ := gregex.MatchString(
  120. fmt.Sprintf(`%s\s*:\s*([^,]+)`, OrmTagForDo),
  121. ormTag.String(),
  122. )
  123. if len(match) > 1 {
  124. return gconv.Bool(match[1])
  125. }
  126. }
  127. return false
  128. }
  129. // getTableNameFromOrmTag retrieves and returns the table name from struct object.
  130. func getTableNameFromOrmTag(object interface{}) string {
  131. var tableName string
  132. // Use the interface value.
  133. if r, ok := object.(iTableName); ok {
  134. tableName = r.TableName()
  135. }
  136. // User meta data tag "orm".
  137. if tableName == "" {
  138. if ormTag := gmeta.Get(object, OrmTagForStruct); !ormTag.IsEmpty() {
  139. match, _ := gregex.MatchString(
  140. fmt.Sprintf(`%s\s*:\s*([^,]+)`, OrmTagForTable),
  141. ormTag.String(),
  142. )
  143. if len(match) > 1 {
  144. tableName = match[1]
  145. }
  146. }
  147. }
  148. // Use the struct name of snake case.
  149. if tableName == "" {
  150. if t, err := gstructs.StructType(object); err != nil {
  151. panic(err)
  152. } else {
  153. tableName = gstr.CaseSnakeFirstUpper(
  154. gstr.StrEx(t.String(), "."),
  155. )
  156. }
  157. }
  158. return tableName
  159. }
  160. // ListItemValues retrieves and returns the elements of all item struct/map with key `key`.
  161. // Note that the parameter `list` should be type of slice which contains elements of map or struct,
  162. // or else it returns an empty slice.
  163. //
  164. // The parameter `list` supports types like:
  165. // []map[string]interface{}
  166. // []map[string]sub-map
  167. // []struct
  168. // []struct:sub-struct
  169. // Note that the sub-map/sub-struct makes sense only if the optional parameter `subKey` is given.
  170. // See gutil.ListItemValues.
  171. func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (values []interface{}) {
  172. return gutil.ListItemValues(list, key, subKey...)
  173. }
  174. // ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`.
  175. // Note that the parameter `list` should be type of slice which contains elements of map or struct,
  176. // or else it returns an empty slice.
  177. // See gutil.ListItemValuesUnique.
  178. func ListItemValuesUnique(list interface{}, key string, subKey ...interface{}) []interface{} {
  179. return gutil.ListItemValuesUnique(list, key, subKey...)
  180. }
  181. // GetInsertOperationByOption returns proper insert option with given parameter `option`.
  182. func GetInsertOperationByOption(option InsertOption) string {
  183. var operator string
  184. switch option {
  185. case InsertOptionReplace:
  186. operator = InsertOperationReplace
  187. case InsertOptionIgnore:
  188. operator = InsertOperationIgnore
  189. default:
  190. operator = InsertOperationInsert
  191. }
  192. return operator
  193. }
  194. func anyValueToMapBeforeToRecord(value interface{}) map[string]interface{} {
  195. return gconv.Map(value, gconv.MapOption{
  196. Tags: structTagPriority,
  197. OmitEmpty: true, // To be compatible with old version from v2.6.0.
  198. })
  199. }
  200. // DaToMapDeep is deprecated, use MapOrStructToMapDeep instead.
  201. func DaToMapDeep(value interface{}) map[string]interface{} {
  202. return MapOrStructToMapDeep(value, true)
  203. }
  204. // MapOrStructToMapDeep converts `value` to map type recursively(if attribute struct is embedded).
  205. // The parameter `value` should be type of *map/map/*struct/struct.
  206. // It supports embedded struct definition for struct.
  207. func MapOrStructToMapDeep(value interface{}, omitempty bool) map[string]interface{} {
  208. m := gconv.Map(value, gconv.MapOption{
  209. Tags: structTagPriority,
  210. OmitEmpty: omitempty,
  211. })
  212. for k, v := range m {
  213. switch v.(type) {
  214. case time.Time, *time.Time, gtime.Time, *gtime.Time, gjson.Json, *gjson.Json:
  215. m[k] = v
  216. }
  217. }
  218. return m
  219. }
  220. // doQuoteTableName adds prefix string and quote chars for table name. It handles table string like:
  221. // "user", "user u", "user,user_detail", "user u, user_detail ut", "user as u, user_detail as ut",
  222. // "user.user u", "`user`.`user` u".
  223. //
  224. // Note that, this will automatically check the table prefix whether already added, if true it does
  225. // nothing to the table name, or else adds the prefix to the table name and returns new table name with prefix.
  226. func doQuoteTableName(table, prefix, charLeft, charRight string) string {
  227. var (
  228. index int
  229. chars = charLeft + charRight
  230. array1 = gstr.SplitAndTrim(table, ",")
  231. )
  232. for k1, v1 := range array1 {
  233. array2 := gstr.SplitAndTrim(v1, " ")
  234. // Trim the security chars.
  235. array2[0] = gstr.Trim(array2[0], chars)
  236. // Check whether it has database name.
  237. array3 := gstr.Split(gstr.Trim(array2[0]), ".")
  238. for k, v := range array3 {
  239. array3[k] = gstr.Trim(v, chars)
  240. }
  241. index = len(array3) - 1
  242. // If the table name already has the prefix, skips the prefix adding.
  243. if len(array3[index]) <= len(prefix) || array3[index][:len(prefix)] != prefix {
  244. array3[index] = prefix + array3[index]
  245. }
  246. array2[0] = gstr.Join(array3, ".")
  247. // Add the security chars.
  248. array2[0] = doQuoteString(array2[0], charLeft, charRight)
  249. array1[k1] = gstr.Join(array2, " ")
  250. }
  251. return gstr.Join(array1, ",")
  252. }
  253. // doQuoteWord checks given string `s` a word, if true quotes it with `charLeft` and `charRight`
  254. // and returns the quoted string; or else returns `s` without any change.
  255. func doQuoteWord(s, charLeft, charRight string) string {
  256. if quoteWordReg.MatchString(s) && !gstr.ContainsAny(s, charLeft+charRight) {
  257. return charLeft + s + charRight
  258. }
  259. return s
  260. }
  261. // doQuoteString quotes string with quote chars.
  262. // For example, if quote char is '`':
  263. // "null" => "NULL"
  264. // "user" => "`user`"
  265. // "user u" => "`user` u"
  266. // "user,user_detail" => "`user`,`user_detail`"
  267. // "user u, user_detail ut" => "`user` u,`user_detail` ut"
  268. // "user.user u, user.user_detail ut" => "`user`.`user` u,`user`.`user_detail` ut"
  269. // "u.id, u.name, u.age" => "`u`.`id`,`u`.`name`,`u`.`age`"
  270. // "u.id asc" => "`u`.`id` asc".
  271. func doQuoteString(s, charLeft, charRight string) string {
  272. array1 := gstr.SplitAndTrim(s, ",")
  273. for k1, v1 := range array1 {
  274. array2 := gstr.SplitAndTrim(v1, " ")
  275. array3 := gstr.Split(gstr.Trim(array2[0]), ".")
  276. if len(array3) == 1 {
  277. if strings.EqualFold(array3[0], "NULL") {
  278. array3[0] = doQuoteWord(array3[0], "", "")
  279. } else {
  280. array3[0] = doQuoteWord(array3[0], charLeft, charRight)
  281. }
  282. } else if len(array3) >= 2 {
  283. array3[0] = doQuoteWord(array3[0], charLeft, charRight)
  284. // Note:
  285. // mysql: u.uid
  286. // mssql double dots: Database..Table
  287. array3[len(array3)-1] = doQuoteWord(array3[len(array3)-1], charLeft, charRight)
  288. }
  289. array2[0] = gstr.Join(array3, ".")
  290. array1[k1] = gstr.Join(array2, " ")
  291. }
  292. return gstr.Join(array1, ",")
  293. }
  294. func getFieldsFromStructOrMap(structOrMap interface{}) (fields []string) {
  295. fields = []string{}
  296. if utils.IsStruct(structOrMap) {
  297. structFields, _ := gstructs.Fields(gstructs.FieldsInput{
  298. Pointer: structOrMap,
  299. RecursiveOption: gstructs.RecursiveOptionEmbeddedNoTag,
  300. })
  301. var ormTagValue string
  302. for _, structField := range structFields {
  303. ormTagValue = structField.Tag(OrmTagForStruct)
  304. ormTagValue = gstr.Split(gstr.Trim(ormTagValue), ",")[0]
  305. if ormTagValue != "" && gregex.IsMatchString(regularFieldNameRegPattern, ormTagValue) {
  306. fields = append(fields, ormTagValue)
  307. } else {
  308. fields = append(fields, structField.Name())
  309. }
  310. }
  311. } else {
  312. fields = gutil.Keys(structOrMap)
  313. }
  314. return
  315. }
  316. // GetPrimaryKeyCondition returns a new where condition by primary field name.
  317. // The optional parameter `where` is like follows:
  318. // 123 => primary=123
  319. // []int{1, 2, 3} => primary IN(1,2,3)
  320. // "john" => primary='john'
  321. // []string{"john", "smith"} => primary IN('john','smith')
  322. // g.Map{"id": g.Slice{1,2,3}} => id IN(1,2,3)
  323. // g.Map{"id": 1, "name": "john"} => id=1 AND name='john'
  324. // etc.
  325. //
  326. // Note that it returns the given `where` parameter directly if the `primary` is empty
  327. // or length of `where` > 1.
  328. func GetPrimaryKeyCondition(primary string, where ...interface{}) (newWhereCondition []interface{}) {
  329. if len(where) == 0 {
  330. return nil
  331. }
  332. if primary == "" {
  333. return where
  334. }
  335. if len(where) == 1 {
  336. var (
  337. rv = reflect.ValueOf(where[0])
  338. kind = rv.Kind()
  339. )
  340. if kind == reflect.Ptr {
  341. rv = rv.Elem()
  342. kind = rv.Kind()
  343. }
  344. switch kind {
  345. case reflect.Map, reflect.Struct:
  346. // Ignore the parameter `primary`.
  347. break
  348. default:
  349. return []interface{}{map[string]interface{}{
  350. primary: where[0],
  351. }}
  352. }
  353. }
  354. return where
  355. }
  356. type formatWhereHolderInput struct {
  357. WhereHolder
  358. OmitNil bool
  359. OmitEmpty bool
  360. Schema string
  361. Table string // Table is used for fields mapping and filtering internally.
  362. }
  363. func isKeyValueCanBeOmitEmpty(omitEmpty bool, whereType string, key, value interface{}) bool {
  364. if !omitEmpty {
  365. return false
  366. }
  367. // Eg:
  368. // Where("id", []int{}).All() -> SELECT xxx FROM xxx WHERE 0=1
  369. // Where("name", "").All() -> SELECT xxx FROM xxx WHERE `name`=''
  370. // OmitEmpty().Where("id", []int{}).All() -> SELECT xxx FROM xxx
  371. // OmitEmpty().Where("name", "").All() -> SELECT xxx FROM xxx
  372. // OmitEmpty().Where("1").All() -> SELECT xxx FROM xxx WHERE 1
  373. switch whereType {
  374. case whereHolderTypeNoArgs:
  375. return false
  376. case whereHolderTypeIn:
  377. return gutil.IsEmpty(value)
  378. default:
  379. if gstr.Count(gconv.String(key), "?") == 0 && gutil.IsEmpty(value) {
  380. return true
  381. }
  382. }
  383. return false
  384. }
  385. // formatWhereHolder formats where statement and its arguments for `Where` and `Having` statements.
  386. func formatWhereHolder(ctx context.Context, db DB, in formatWhereHolderInput) (newWhere string, newArgs []interface{}) {
  387. var (
  388. buffer = bytes.NewBuffer(nil)
  389. reflectInfo = reflection.OriginValueAndKind(in.Where)
  390. )
  391. switch reflectInfo.OriginKind {
  392. case reflect.Array, reflect.Slice:
  393. newArgs = formatWhereInterfaces(db, gconv.Interfaces(in.Where), buffer, newArgs)
  394. case reflect.Map:
  395. for key, value := range MapOrStructToMapDeep(in.Where, true) {
  396. if in.OmitNil && empty.IsNil(value) {
  397. continue
  398. }
  399. if in.OmitEmpty && empty.IsEmpty(value) {
  400. continue
  401. }
  402. newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
  403. Db: db,
  404. Buffer: buffer,
  405. Args: newArgs,
  406. Key: key,
  407. Value: value,
  408. Prefix: in.Prefix,
  409. Type: in.Type,
  410. })
  411. }
  412. case reflect.Struct:
  413. // If the `where` parameter is `DO` struct, it then adds `OmitNil` option for this condition,
  414. // which will filter all nil parameters in `where`.
  415. if isDoStruct(in.Where) {
  416. in.OmitNil = true
  417. }
  418. // If `where` struct implements `iIterator` interface,
  419. // it then uses its Iterate function to iterate its key-value pairs.
  420. // For example, ListMap and TreeMap are ordered map,
  421. // which implement `iIterator` interface and are index-friendly for where conditions.
  422. if iterator, ok := in.Where.(iIterator); ok {
  423. iterator.Iterator(func(key, value interface{}) bool {
  424. ketStr := gconv.String(key)
  425. if in.OmitNil && empty.IsNil(value) {
  426. return true
  427. }
  428. if in.OmitEmpty && empty.IsEmpty(value) {
  429. return true
  430. }
  431. newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
  432. Db: db,
  433. Buffer: buffer,
  434. Args: newArgs,
  435. Key: ketStr,
  436. Value: value,
  437. OmitEmpty: in.OmitEmpty,
  438. Prefix: in.Prefix,
  439. Type: in.Type,
  440. })
  441. return true
  442. })
  443. break
  444. }
  445. // Automatically mapping and filtering the struct attribute.
  446. var (
  447. reflectType = reflectInfo.OriginValue.Type()
  448. structField reflect.StructField
  449. data = MapOrStructToMapDeep(in.Where, true)
  450. )
  451. // If `Prefix` is given, it checks and retrieves the table name.
  452. if in.Prefix != "" {
  453. hasTable, _ := db.GetCore().HasTable(in.Prefix)
  454. if hasTable {
  455. in.Table = in.Prefix
  456. } else {
  457. ormTagTableName := getTableNameFromOrmTag(in.Where)
  458. if ormTagTableName != "" {
  459. in.Table = ormTagTableName
  460. }
  461. }
  462. }
  463. // Mapping and filtering fields if `Table` is given.
  464. if in.Table != "" {
  465. data, _ = db.GetCore().mappingAndFilterData(ctx, in.Schema, in.Table, data, true)
  466. }
  467. // Put the struct attributes in sequence in Where statement.
  468. var ormTagValue string
  469. for i := 0; i < reflectType.NumField(); i++ {
  470. structField = reflectType.Field(i)
  471. // Use tag value from `orm` as field name if specified.
  472. ormTagValue = structField.Tag.Get(OrmTagForStruct)
  473. ormTagValue = gstr.Split(gstr.Trim(ormTagValue), ",")[0]
  474. if ormTagValue == "" {
  475. ormTagValue = structField.Name
  476. }
  477. foundKey, foundValue := gutil.MapPossibleItemByKey(data, ormTagValue)
  478. if foundKey != "" {
  479. if in.OmitNil && empty.IsNil(foundValue) {
  480. continue
  481. }
  482. if in.OmitEmpty && empty.IsEmpty(foundValue) {
  483. continue
  484. }
  485. newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
  486. Db: db,
  487. Buffer: buffer,
  488. Args: newArgs,
  489. Key: foundKey,
  490. Value: foundValue,
  491. OmitEmpty: in.OmitEmpty,
  492. Prefix: in.Prefix,
  493. Type: in.Type,
  494. })
  495. }
  496. }
  497. default:
  498. // Where filter.
  499. var omitEmptyCheckValue interface{}
  500. if len(in.Args) == 1 {
  501. omitEmptyCheckValue = in.Args[0]
  502. } else {
  503. omitEmptyCheckValue = in.Args
  504. }
  505. if isKeyValueCanBeOmitEmpty(in.OmitEmpty, in.Type, in.Where, omitEmptyCheckValue) {
  506. return
  507. }
  508. // Usually a string.
  509. whereStr := gstr.Trim(gconv.String(in.Where))
  510. // Is `whereStr` a field name which composed as a key-value condition?
  511. // Eg:
  512. // Where("id", 1)
  513. // Where("id", g.Slice{1,2,3})
  514. if gregex.IsMatchString(regularFieldNameWithoutDotRegPattern, whereStr) && len(in.Args) == 1 {
  515. newArgs = formatWhereKeyValue(formatWhereKeyValueInput{
  516. Db: db,
  517. Buffer: buffer,
  518. Args: newArgs,
  519. Key: whereStr,
  520. Value: in.Args[0],
  521. OmitEmpty: in.OmitEmpty,
  522. Prefix: in.Prefix,
  523. Type: in.Type,
  524. })
  525. in.Args = in.Args[:0]
  526. break
  527. }
  528. // If the first part is column name, it automatically adds prefix to the column.
  529. if in.Prefix != "" {
  530. array := gstr.Split(whereStr, " ")
  531. if ok, _ := db.GetCore().HasField(ctx, in.Table, array[0]); ok {
  532. whereStr = in.Prefix + "." + whereStr
  533. }
  534. }
  535. // Regular string and parameter place holder handling.
  536. // Eg:
  537. // Where("id in(?) and name=?", g.Slice{1,2,3}, "john")
  538. i := 0
  539. for {
  540. if i >= len(in.Args) {
  541. break
  542. }
  543. // ===============================================================
  544. // Sub query, which is always used along with a string condition.
  545. // ===============================================================
  546. if subModel, ok := in.Args[i].(*Model); ok {
  547. index := -1
  548. whereStr, _ = gregex.ReplaceStringFunc(`(\?)`, whereStr, func(s string) string {
  549. index++
  550. if i+len(newArgs) == index {
  551. sqlWithHolder, holderArgs := subModel.getHolderAndArgsAsSubModel(ctx)
  552. in.Args = gutil.SliceInsertAfter(in.Args, i, holderArgs...)
  553. // Automatically adding the brackets.
  554. return "(" + sqlWithHolder + ")"
  555. }
  556. return s
  557. })
  558. in.Args = gutil.SliceDelete(in.Args, i)
  559. continue
  560. }
  561. i++
  562. }
  563. buffer.WriteString(whereStr)
  564. }
  565. if buffer.Len() == 0 {
  566. return "", in.Args
  567. }
  568. if len(in.Args) > 0 {
  569. newArgs = append(newArgs, in.Args...)
  570. }
  571. newWhere = buffer.String()
  572. if len(newArgs) > 0 {
  573. if gstr.Pos(newWhere, "?") == -1 {
  574. if gregex.IsMatchString(lastOperatorRegPattern, newWhere) {
  575. // Eg: Where/And/Or("uid>=", 1)
  576. newWhere += "?"
  577. } else if gregex.IsMatchString(regularFieldNameRegPattern, newWhere) {
  578. newWhere = db.GetCore().QuoteString(newWhere)
  579. if len(newArgs) > 0 {
  580. if utils.IsArray(newArgs[0]) {
  581. // Eg:
  582. // Where("id", []int{1,2,3})
  583. // Where("user.id", []int{1,2,3})
  584. newWhere += " IN (?)"
  585. } else if empty.IsNil(newArgs[0]) {
  586. // Eg:
  587. // Where("id", nil)
  588. // Where("user.id", nil)
  589. newWhere += " IS NULL"
  590. newArgs = nil
  591. } else {
  592. // Eg:
  593. // Where/And/Or("uid", 1)
  594. // Where/And/Or("user.uid", 1)
  595. newWhere += "=?"
  596. }
  597. }
  598. }
  599. }
  600. }
  601. return handleArguments(newWhere, newArgs)
  602. }
  603. // formatWhereInterfaces formats `where` as []interface{}.
  604. func formatWhereInterfaces(db DB, where []interface{}, buffer *bytes.Buffer, newArgs []interface{}) []interface{} {
  605. if len(where) == 0 {
  606. return newArgs
  607. }
  608. if len(where)%2 != 0 {
  609. buffer.WriteString(gstr.Join(gconv.Strings(where), ""))
  610. return newArgs
  611. }
  612. var str string
  613. for i := 0; i < len(where); i += 2 {
  614. str = gconv.String(where[i])
  615. if buffer.Len() > 0 {
  616. buffer.WriteString(" AND " + db.GetCore().QuoteWord(str) + "=?")
  617. } else {
  618. buffer.WriteString(db.GetCore().QuoteWord(str) + "=?")
  619. }
  620. if s, ok := where[i+1].(Raw); ok {
  621. buffer.WriteString(gconv.String(s))
  622. } else {
  623. newArgs = append(newArgs, where[i+1])
  624. }
  625. }
  626. return newArgs
  627. }
  628. type formatWhereKeyValueInput struct {
  629. Db DB // Db is the underlying DB object for current operation.
  630. Buffer *bytes.Buffer // Buffer is the sql statement string without Args for current operation.
  631. Args []interface{} // Args is the full arguments of current operation.
  632. Key string // The field name, eg: "id", "name", etc.
  633. Value interface{} // The field value, can be any types.
  634. Type string // The value in Where type.
  635. OmitEmpty bool // Ignores current condition key if `value` is empty.
  636. Prefix string // Field prefix, eg: "user", "order", etc.
  637. }
  638. // formatWhereKeyValue handles each key-value pair of the parameter map.
  639. func formatWhereKeyValue(in formatWhereKeyValueInput) (newArgs []interface{}) {
  640. var (
  641. quotedKey = in.Db.GetCore().QuoteWord(in.Key)
  642. holderCount = gstr.Count(quotedKey, "?")
  643. )
  644. if isKeyValueCanBeOmitEmpty(in.OmitEmpty, in.Type, quotedKey, in.Value) {
  645. return in.Args
  646. }
  647. if in.Prefix != "" && !gstr.Contains(quotedKey, ".") {
  648. quotedKey = in.Prefix + "." + quotedKey
  649. }
  650. if in.Buffer.Len() > 0 {
  651. in.Buffer.WriteString(" AND ")
  652. }
  653. // If the value is type of slice, and there's only one '?' holder in
  654. // the key string, it automatically adds '?' holder chars according to its arguments count
  655. // and converts it to "IN" statement.
  656. var (
  657. reflectValue = reflect.ValueOf(in.Value)
  658. reflectKind = reflectValue.Kind()
  659. )
  660. switch reflectKind {
  661. // Slice argument.
  662. case reflect.Slice, reflect.Array:
  663. if holderCount == 0 {
  664. in.Buffer.WriteString(quotedKey + " IN(?)")
  665. in.Args = append(in.Args, in.Value)
  666. } else {
  667. if holderCount != reflectValue.Len() {
  668. in.Buffer.WriteString(quotedKey)
  669. in.Args = append(in.Args, in.Value)
  670. } else {
  671. in.Buffer.WriteString(quotedKey)
  672. in.Args = append(in.Args, gconv.Interfaces(in.Value)...)
  673. }
  674. }
  675. default:
  676. if in.Value == nil || empty.IsNil(reflectValue) {
  677. if gregex.IsMatchString(regularFieldNameRegPattern, in.Key) {
  678. // The key is a single field name.
  679. in.Buffer.WriteString(quotedKey + " IS NULL")
  680. } else {
  681. // The key may have operation chars.
  682. in.Buffer.WriteString(quotedKey)
  683. }
  684. } else {
  685. // It also supports "LIKE" statement, which we consider it an operator.
  686. quotedKey = gstr.Trim(quotedKey)
  687. if gstr.Pos(quotedKey, "?") == -1 {
  688. like := " LIKE"
  689. if len(quotedKey) > len(like) && gstr.Equal(quotedKey[len(quotedKey)-len(like):], like) {
  690. // Eg: Where(g.Map{"name like": "john%"})
  691. in.Buffer.WriteString(quotedKey + " ?")
  692. } else if gregex.IsMatchString(lastOperatorRegPattern, quotedKey) {
  693. // Eg: Where(g.Map{"age > ": 16})
  694. in.Buffer.WriteString(quotedKey + " ?")
  695. } else if gregex.IsMatchString(regularFieldNameRegPattern, in.Key) {
  696. // The key is a regular field name.
  697. in.Buffer.WriteString(quotedKey + "=?")
  698. } else {
  699. // The key is not a regular field name.
  700. // Eg: Where(g.Map{"age > 16": nil})
  701. // Issue: https://github.com/gogf/gf/issues/765
  702. if empty.IsEmpty(in.Value) {
  703. in.Buffer.WriteString(quotedKey)
  704. break
  705. } else {
  706. in.Buffer.WriteString(quotedKey + "=?")
  707. }
  708. }
  709. } else {
  710. in.Buffer.WriteString(quotedKey)
  711. }
  712. if s, ok := in.Value.(Raw); ok {
  713. in.Buffer.WriteString(gconv.String(s))
  714. } else {
  715. in.Args = append(in.Args, in.Value)
  716. }
  717. }
  718. }
  719. return in.Args
  720. }
  721. // handleArguments is an important function, which handles the sql and all its arguments
  722. // before committing them to underlying driver.
  723. func handleArguments(sql string, args []interface{}) (newSql string, newArgs []interface{}) {
  724. newSql = sql
  725. // insertHolderCount is used to calculate the inserting position for the '?' holder.
  726. insertHolderCount := 0
  727. // Handles the slice arguments.
  728. if len(args) > 0 {
  729. for index, arg := range args {
  730. reflectInfo := reflection.OriginValueAndKind(arg)
  731. switch reflectInfo.OriginKind {
  732. case reflect.Slice, reflect.Array:
  733. // It does not split the type of []byte.
  734. // Eg: table.Where("name = ?", []byte("john"))
  735. if _, ok := arg.([]byte); ok {
  736. newArgs = append(newArgs, arg)
  737. continue
  738. }
  739. if reflectInfo.OriginValue.Len() == 0 {
  740. // Empty slice argument, it converts the sql to a false sql.
  741. // Eg:
  742. // Query("select * from xxx where id in(?)", g.Slice{}) -> select * from xxx where 0=1
  743. // Where("id in(?)", g.Slice{}) -> WHERE 0=1
  744. if gstr.Contains(newSql, "?") {
  745. whereKeyWord := " WHERE "
  746. if p := gstr.PosI(newSql, whereKeyWord); p == -1 {
  747. return "0=1", []interface{}{}
  748. } else {
  749. return gstr.SubStr(newSql, 0, p+len(whereKeyWord)) + "0=1", []interface{}{}
  750. }
  751. }
  752. } else {
  753. for i := 0; i < reflectInfo.OriginValue.Len(); i++ {
  754. newArgs = append(newArgs, reflectInfo.OriginValue.Index(i).Interface())
  755. }
  756. }
  757. // If the '?' holder count equals the length of the slice,
  758. // it does not implement the arguments splitting logic.
  759. // Eg: db.Query("SELECT ?+?", g.Slice{1, 2})
  760. if len(args) == 1 && gstr.Count(newSql, "?") == reflectInfo.OriginValue.Len() {
  761. break
  762. }
  763. // counter is used to finding the inserting position for the '?' holder.
  764. var (
  765. counter = 0
  766. replaced = false
  767. )
  768. newSql, _ = gregex.ReplaceStringFunc(`\?`, newSql, func(s string) string {
  769. if replaced {
  770. return s
  771. }
  772. counter++
  773. if counter == index+insertHolderCount+1 {
  774. replaced = true
  775. insertHolderCount += reflectInfo.OriginValue.Len() - 1
  776. return "?" + strings.Repeat(",?", reflectInfo.OriginValue.Len()-1)
  777. }
  778. return s
  779. })
  780. // Special struct handling.
  781. case reflect.Struct:
  782. switch arg.(type) {
  783. // The underlying driver supports time.Time/*time.Time types.
  784. case time.Time, *time.Time:
  785. newArgs = append(newArgs, arg)
  786. continue
  787. case gtime.Time:
  788. newArgs = append(newArgs, arg.(gtime.Time).Time)
  789. continue
  790. case *gtime.Time:
  791. newArgs = append(newArgs, arg.(*gtime.Time).Time)
  792. continue
  793. default:
  794. // It converts the struct to string in default
  795. // if it has implemented the String interface.
  796. if v, ok := arg.(iString); ok {
  797. newArgs = append(newArgs, v.String())
  798. continue
  799. }
  800. }
  801. newArgs = append(newArgs, arg)
  802. default:
  803. newArgs = append(newArgs, arg)
  804. }
  805. }
  806. }
  807. return
  808. }
  809. // FormatSqlWithArgs binds the arguments to the sql string and returns a complete
  810. // sql string, just for debugging.
  811. func FormatSqlWithArgs(sql string, args []interface{}) string {
  812. index := -1
  813. newQuery, _ := gregex.ReplaceStringFunc(
  814. `(\?|:v\d+|\$\d+|@p\d+)`,
  815. sql,
  816. func(s string) string {
  817. index++
  818. if len(args) > index {
  819. if args[index] == nil {
  820. return "null"
  821. }
  822. // Parameters of type Raw do not require special treatment
  823. if v, ok := args[index].(Raw); ok {
  824. return gconv.String(v)
  825. }
  826. reflectInfo := reflection.OriginValueAndKind(args[index])
  827. if reflectInfo.OriginKind == reflect.Ptr &&
  828. (reflectInfo.OriginValue.IsNil() || !reflectInfo.OriginValue.IsValid()) {
  829. return "null"
  830. }
  831. switch reflectInfo.OriginKind {
  832. case reflect.String, reflect.Map, reflect.Slice, reflect.Array:
  833. return `'` + gstr.QuoteMeta(gconv.String(args[index]), `'`) + `'`
  834. case reflect.Struct:
  835. if t, ok := args[index].(time.Time); ok {
  836. return `'` + t.Format(`2006-01-02 15:04:05`) + `'`
  837. }
  838. return `'` + gstr.QuoteMeta(gconv.String(args[index]), `'`) + `'`
  839. }
  840. return gconv.String(args[index])
  841. }
  842. return s
  843. })
  844. return newQuery
  845. }