You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

statement.go 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. // Copyright 2015 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 statements
  5. import (
  6. "database/sql/driver"
  7. "errors"
  8. "fmt"
  9. "reflect"
  10. "strings"
  11. "time"
  12. "xorm.io/builder"
  13. "xorm.io/xorm/contexts"
  14. "xorm.io/xorm/convert"
  15. "xorm.io/xorm/dialects"
  16. "xorm.io/xorm/internal/json"
  17. "xorm.io/xorm/internal/utils"
  18. "xorm.io/xorm/schemas"
  19. "xorm.io/xorm/tags"
  20. )
  21. var (
  22. // ErrConditionType condition type unsupported
  23. ErrConditionType = errors.New("Unsupported condition type")
  24. // ErrUnSupportedSQLType parameter of SQL is not supported
  25. ErrUnSupportedSQLType = errors.New("Unsupported sql type")
  26. // ErrUnSupportedType unsupported error
  27. ErrUnSupportedType = errors.New("Unsupported type error")
  28. // ErrTableNotFound table not found error
  29. ErrTableNotFound = errors.New("Table not found")
  30. )
  31. // Statement save all the sql info for executing SQL
  32. type Statement struct {
  33. RefTable *schemas.Table
  34. dialect dialects.Dialect
  35. defaultTimeZone *time.Location
  36. tagParser *tags.Parser
  37. Start int
  38. LimitN *int
  39. idParam schemas.PK
  40. OrderStr string
  41. JoinStr string
  42. joinArgs []interface{}
  43. GroupByStr string
  44. HavingStr string
  45. SelectStr string
  46. useAllCols bool
  47. AltTableName string
  48. tableName string
  49. RawSQL string
  50. RawParams []interface{}
  51. UseCascade bool
  52. UseAutoJoin bool
  53. StoreEngine string
  54. Charset string
  55. UseCache bool
  56. UseAutoTime bool
  57. NoAutoCondition bool
  58. IsDistinct bool
  59. IsForUpdate bool
  60. TableAlias string
  61. allUseBool bool
  62. CheckVersion bool
  63. unscoped bool
  64. ColumnMap columnMap
  65. OmitColumnMap columnMap
  66. MustColumnMap map[string]bool
  67. NullableMap map[string]bool
  68. IncrColumns exprParams
  69. DecrColumns exprParams
  70. ExprColumns exprParams
  71. cond builder.Cond
  72. BufferSize int
  73. Context contexts.ContextCache
  74. LastError error
  75. }
  76. // NewStatement creates a new statement
  77. func NewStatement(dialect dialects.Dialect, tagParser *tags.Parser, defaultTimeZone *time.Location) *Statement {
  78. statement := &Statement{
  79. dialect: dialect,
  80. tagParser: tagParser,
  81. defaultTimeZone: defaultTimeZone,
  82. }
  83. statement.Reset()
  84. return statement
  85. }
  86. func (statement *Statement) SetTableName(tableName string) {
  87. statement.tableName = tableName
  88. }
  89. func (statement *Statement) omitStr() string {
  90. return statement.dialect.Quoter().Join(statement.OmitColumnMap, " ,")
  91. }
  92. // GenRawSQL generates correct raw sql
  93. func (statement *Statement) GenRawSQL() string {
  94. return statement.ReplaceQuote(statement.RawSQL)
  95. }
  96. func (statement *Statement) GenCondSQL(condOrBuilder interface{}) (string, []interface{}, error) {
  97. condSQL, condArgs, err := builder.ToSQL(condOrBuilder)
  98. if err != nil {
  99. return "", nil, err
  100. }
  101. return statement.ReplaceQuote(condSQL), condArgs, nil
  102. }
  103. func (statement *Statement) ReplaceQuote(sql string) string {
  104. if sql == "" || statement.dialect.URI().DBType == schemas.MYSQL ||
  105. statement.dialect.URI().DBType == schemas.SQLITE {
  106. return sql
  107. }
  108. return statement.dialect.Quoter().Replace(sql)
  109. }
  110. func (statement *Statement) SetContextCache(ctxCache contexts.ContextCache) {
  111. statement.Context = ctxCache
  112. }
  113. // Init reset all the statement's fields
  114. func (statement *Statement) Reset() {
  115. statement.RefTable = nil
  116. statement.Start = 0
  117. statement.LimitN = nil
  118. statement.OrderStr = ""
  119. statement.UseCascade = true
  120. statement.JoinStr = ""
  121. statement.joinArgs = make([]interface{}, 0)
  122. statement.GroupByStr = ""
  123. statement.HavingStr = ""
  124. statement.ColumnMap = columnMap{}
  125. statement.OmitColumnMap = columnMap{}
  126. statement.AltTableName = ""
  127. statement.tableName = ""
  128. statement.idParam = nil
  129. statement.RawSQL = ""
  130. statement.RawParams = make([]interface{}, 0)
  131. statement.UseCache = true
  132. statement.UseAutoTime = true
  133. statement.NoAutoCondition = false
  134. statement.IsDistinct = false
  135. statement.IsForUpdate = false
  136. statement.TableAlias = ""
  137. statement.SelectStr = ""
  138. statement.allUseBool = false
  139. statement.useAllCols = false
  140. statement.MustColumnMap = make(map[string]bool)
  141. statement.NullableMap = make(map[string]bool)
  142. statement.CheckVersion = true
  143. statement.unscoped = false
  144. statement.IncrColumns = exprParams{}
  145. statement.DecrColumns = exprParams{}
  146. statement.ExprColumns = exprParams{}
  147. statement.cond = builder.NewCond()
  148. statement.BufferSize = 0
  149. statement.Context = nil
  150. statement.LastError = nil
  151. }
  152. // NoAutoCondition if you do not want convert bean's field as query condition, then use this function
  153. func (statement *Statement) SetNoAutoCondition(no ...bool) *Statement {
  154. statement.NoAutoCondition = true
  155. if len(no) > 0 {
  156. statement.NoAutoCondition = no[0]
  157. }
  158. return statement
  159. }
  160. // Alias set the table alias
  161. func (statement *Statement) Alias(alias string) *Statement {
  162. statement.TableAlias = alias
  163. return statement
  164. }
  165. // SQL adds raw sql statement
  166. func (statement *Statement) SQL(query interface{}, args ...interface{}) *Statement {
  167. switch query.(type) {
  168. case (*builder.Builder):
  169. var err error
  170. statement.RawSQL, statement.RawParams, err = query.(*builder.Builder).ToSQL()
  171. if err != nil {
  172. statement.LastError = err
  173. }
  174. case string:
  175. statement.RawSQL = query.(string)
  176. statement.RawParams = args
  177. default:
  178. statement.LastError = ErrUnSupportedSQLType
  179. }
  180. return statement
  181. }
  182. // Where add Where statement
  183. func (statement *Statement) Where(query interface{}, args ...interface{}) *Statement {
  184. return statement.And(query, args...)
  185. }
  186. func (statement *Statement) quote(s string) string {
  187. return statement.dialect.Quoter().Quote(s)
  188. }
  189. // And add Where & and statement
  190. func (statement *Statement) And(query interface{}, args ...interface{}) *Statement {
  191. switch query.(type) {
  192. case string:
  193. cond := builder.Expr(query.(string), args...)
  194. statement.cond = statement.cond.And(cond)
  195. case map[string]interface{}:
  196. queryMap := query.(map[string]interface{})
  197. newMap := make(map[string]interface{})
  198. for k, v := range queryMap {
  199. newMap[statement.quote(k)] = v
  200. }
  201. statement.cond = statement.cond.And(builder.Eq(newMap))
  202. case builder.Cond:
  203. cond := query.(builder.Cond)
  204. statement.cond = statement.cond.And(cond)
  205. for _, v := range args {
  206. if vv, ok := v.(builder.Cond); ok {
  207. statement.cond = statement.cond.And(vv)
  208. }
  209. }
  210. default:
  211. statement.LastError = ErrConditionType
  212. }
  213. return statement
  214. }
  215. // Or add Where & Or statement
  216. func (statement *Statement) Or(query interface{}, args ...interface{}) *Statement {
  217. switch query.(type) {
  218. case string:
  219. cond := builder.Expr(query.(string), args...)
  220. statement.cond = statement.cond.Or(cond)
  221. case map[string]interface{}:
  222. cond := builder.Eq(query.(map[string]interface{}))
  223. statement.cond = statement.cond.Or(cond)
  224. case builder.Cond:
  225. cond := query.(builder.Cond)
  226. statement.cond = statement.cond.Or(cond)
  227. for _, v := range args {
  228. if vv, ok := v.(builder.Cond); ok {
  229. statement.cond = statement.cond.Or(vv)
  230. }
  231. }
  232. default:
  233. // TODO: not support condition type
  234. }
  235. return statement
  236. }
  237. // In generate "Where column IN (?) " statement
  238. func (statement *Statement) In(column string, args ...interface{}) *Statement {
  239. in := builder.In(statement.quote(column), args...)
  240. statement.cond = statement.cond.And(in)
  241. return statement
  242. }
  243. // NotIn generate "Where column NOT IN (?) " statement
  244. func (statement *Statement) NotIn(column string, args ...interface{}) *Statement {
  245. notIn := builder.NotIn(statement.quote(column), args...)
  246. statement.cond = statement.cond.And(notIn)
  247. return statement
  248. }
  249. func (statement *Statement) SetRefValue(v reflect.Value) error {
  250. var err error
  251. statement.RefTable, err = statement.tagParser.ParseWithCache(reflect.Indirect(v))
  252. if err != nil {
  253. return err
  254. }
  255. statement.tableName = dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), v, true)
  256. return nil
  257. }
  258. func rValue(bean interface{}) reflect.Value {
  259. return reflect.Indirect(reflect.ValueOf(bean))
  260. }
  261. func (statement *Statement) SetRefBean(bean interface{}) error {
  262. var err error
  263. statement.RefTable, err = statement.tagParser.ParseWithCache(rValue(bean))
  264. if err != nil {
  265. return err
  266. }
  267. statement.tableName = dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), bean, true)
  268. return nil
  269. }
  270. func (statement *Statement) needTableName() bool {
  271. return len(statement.JoinStr) > 0
  272. }
  273. func (statement *Statement) colName(col *schemas.Column, tableName string) string {
  274. if statement.needTableName() {
  275. var nm = tableName
  276. if len(statement.TableAlias) > 0 {
  277. nm = statement.TableAlias
  278. }
  279. return statement.quote(nm) + "." + statement.quote(col.Name)
  280. }
  281. return statement.quote(col.Name)
  282. }
  283. // TableName return current tableName
  284. func (statement *Statement) TableName() string {
  285. if statement.AltTableName != "" {
  286. return statement.AltTableName
  287. }
  288. return statement.tableName
  289. }
  290. // Incr Generate "Update ... Set column = column + arg" statement
  291. func (statement *Statement) Incr(column string, arg ...interface{}) *Statement {
  292. if len(arg) > 0 {
  293. statement.IncrColumns.addParam(column, arg[0])
  294. } else {
  295. statement.IncrColumns.addParam(column, 1)
  296. }
  297. return statement
  298. }
  299. // Decr Generate "Update ... Set column = column - arg" statement
  300. func (statement *Statement) Decr(column string, arg ...interface{}) *Statement {
  301. if len(arg) > 0 {
  302. statement.DecrColumns.addParam(column, arg[0])
  303. } else {
  304. statement.DecrColumns.addParam(column, 1)
  305. }
  306. return statement
  307. }
  308. // SetExpr Generate "Update ... Set column = {expression}" statement
  309. func (statement *Statement) SetExpr(column string, expression interface{}) *Statement {
  310. if e, ok := expression.(string); ok {
  311. statement.ExprColumns.addParam(column, statement.dialect.Quoter().Replace(e))
  312. } else {
  313. statement.ExprColumns.addParam(column, expression)
  314. }
  315. return statement
  316. }
  317. // Distinct generates "DISTINCT col1, col2 " statement
  318. func (statement *Statement) Distinct(columns ...string) *Statement {
  319. statement.IsDistinct = true
  320. statement.Cols(columns...)
  321. return statement
  322. }
  323. // ForUpdate generates "SELECT ... FOR UPDATE" statement
  324. func (statement *Statement) ForUpdate() *Statement {
  325. statement.IsForUpdate = true
  326. return statement
  327. }
  328. // Select replace select
  329. func (statement *Statement) Select(str string) *Statement {
  330. statement.SelectStr = statement.ReplaceQuote(str)
  331. return statement
  332. }
  333. func col2NewCols(columns ...string) []string {
  334. newColumns := make([]string, 0, len(columns))
  335. for _, col := range columns {
  336. col = strings.Replace(col, "`", "", -1)
  337. col = strings.Replace(col, `"`, "", -1)
  338. ccols := strings.Split(col, ",")
  339. for _, c := range ccols {
  340. newColumns = append(newColumns, strings.TrimSpace(c))
  341. }
  342. }
  343. return newColumns
  344. }
  345. // Cols generate "col1, col2" statement
  346. func (statement *Statement) Cols(columns ...string) *Statement {
  347. cols := col2NewCols(columns...)
  348. for _, nc := range cols {
  349. statement.ColumnMap.Add(nc)
  350. }
  351. return statement
  352. }
  353. func (statement *Statement) ColumnStr() string {
  354. return statement.dialect.Quoter().Join(statement.ColumnMap, ", ")
  355. }
  356. // AllCols update use only: update all columns
  357. func (statement *Statement) AllCols() *Statement {
  358. statement.useAllCols = true
  359. return statement
  360. }
  361. // MustCols update use only: must update columns
  362. func (statement *Statement) MustCols(columns ...string) *Statement {
  363. newColumns := col2NewCols(columns...)
  364. for _, nc := range newColumns {
  365. statement.MustColumnMap[strings.ToLower(nc)] = true
  366. }
  367. return statement
  368. }
  369. // UseBool indicates that use bool fields as update contents and query contiditions
  370. func (statement *Statement) UseBool(columns ...string) *Statement {
  371. if len(columns) > 0 {
  372. statement.MustCols(columns...)
  373. } else {
  374. statement.allUseBool = true
  375. }
  376. return statement
  377. }
  378. // Omit do not use the columns
  379. func (statement *Statement) Omit(columns ...string) {
  380. newColumns := col2NewCols(columns...)
  381. for _, nc := range newColumns {
  382. statement.OmitColumnMap = append(statement.OmitColumnMap, nc)
  383. }
  384. }
  385. // Nullable Update use only: update columns to null when value is nullable and zero-value
  386. func (statement *Statement) Nullable(columns ...string) {
  387. newColumns := col2NewCols(columns...)
  388. for _, nc := range newColumns {
  389. statement.NullableMap[strings.ToLower(nc)] = true
  390. }
  391. }
  392. // Top generate LIMIT limit statement
  393. func (statement *Statement) Top(limit int) *Statement {
  394. statement.Limit(limit)
  395. return statement
  396. }
  397. // Limit generate LIMIT start, limit statement
  398. func (statement *Statement) Limit(limit int, start ...int) *Statement {
  399. statement.LimitN = &limit
  400. if len(start) > 0 {
  401. statement.Start = start[0]
  402. }
  403. return statement
  404. }
  405. // OrderBy generate "Order By order" statement
  406. func (statement *Statement) OrderBy(order string) *Statement {
  407. if len(statement.OrderStr) > 0 {
  408. statement.OrderStr += ", "
  409. }
  410. statement.OrderStr += statement.ReplaceQuote(order)
  411. return statement
  412. }
  413. // Desc generate `ORDER BY xx DESC`
  414. func (statement *Statement) Desc(colNames ...string) *Statement {
  415. var buf strings.Builder
  416. if len(statement.OrderStr) > 0 {
  417. fmt.Fprint(&buf, statement.OrderStr, ", ")
  418. }
  419. for i, col := range colNames {
  420. if i > 0 {
  421. fmt.Fprint(&buf, ", ")
  422. }
  423. statement.dialect.Quoter().QuoteTo(&buf, col)
  424. fmt.Fprint(&buf, " DESC")
  425. }
  426. statement.OrderStr = buf.String()
  427. return statement
  428. }
  429. // Asc provide asc order by query condition, the input parameters are columns.
  430. func (statement *Statement) Asc(colNames ...string) *Statement {
  431. var buf strings.Builder
  432. if len(statement.OrderStr) > 0 {
  433. fmt.Fprint(&buf, statement.OrderStr, ", ")
  434. }
  435. for i, col := range colNames {
  436. if i > 0 {
  437. fmt.Fprint(&buf, ", ")
  438. }
  439. statement.dialect.Quoter().QuoteTo(&buf, col)
  440. fmt.Fprint(&buf, " ASC")
  441. }
  442. statement.OrderStr = buf.String()
  443. return statement
  444. }
  445. func (statement *Statement) Conds() builder.Cond {
  446. return statement.cond
  447. }
  448. // Table tempororily set table name, the parameter could be a string or a pointer of struct
  449. func (statement *Statement) SetTable(tableNameOrBean interface{}) error {
  450. v := rValue(tableNameOrBean)
  451. t := v.Type()
  452. if t.Kind() == reflect.Struct {
  453. var err error
  454. statement.RefTable, err = statement.tagParser.ParseWithCache(v)
  455. if err != nil {
  456. return err
  457. }
  458. }
  459. statement.AltTableName = dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), tableNameOrBean, true)
  460. return nil
  461. }
  462. // Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
  463. func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement {
  464. var buf strings.Builder
  465. if len(statement.JoinStr) > 0 {
  466. fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP)
  467. } else {
  468. fmt.Fprintf(&buf, "%v JOIN ", joinOP)
  469. }
  470. switch tp := tablename.(type) {
  471. case builder.Builder:
  472. subSQL, subQueryArgs, err := tp.ToSQL()
  473. if err != nil {
  474. statement.LastError = err
  475. return statement
  476. }
  477. fields := strings.Split(tp.TableName(), ".")
  478. aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
  479. aliasName = schemas.CommonQuoter.Trim(aliasName)
  480. fmt.Fprintf(&buf, "(%s) %s ON %v", statement.ReplaceQuote(subSQL), aliasName, statement.ReplaceQuote(condition))
  481. statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
  482. case *builder.Builder:
  483. subSQL, subQueryArgs, err := tp.ToSQL()
  484. if err != nil {
  485. statement.LastError = err
  486. return statement
  487. }
  488. fields := strings.Split(tp.TableName(), ".")
  489. aliasName := statement.dialect.Quoter().Trim(fields[len(fields)-1])
  490. aliasName = schemas.CommonQuoter.Trim(aliasName)
  491. fmt.Fprintf(&buf, "(%s) %s ON %v", statement.ReplaceQuote(subSQL), aliasName, statement.ReplaceQuote(condition))
  492. statement.joinArgs = append(statement.joinArgs, subQueryArgs...)
  493. default:
  494. tbName := dialects.FullTableName(statement.dialect, statement.tagParser.GetTableMapper(), tablename, true)
  495. if !utils.IsSubQuery(tbName) {
  496. var buf strings.Builder
  497. statement.dialect.Quoter().QuoteTo(&buf, tbName)
  498. tbName = buf.String()
  499. }
  500. fmt.Fprintf(&buf, "%s ON %v", tbName, statement.ReplaceQuote(condition))
  501. }
  502. statement.JoinStr = buf.String()
  503. statement.joinArgs = append(statement.joinArgs, args...)
  504. return statement
  505. }
  506. // tbName get some table's table name
  507. func (statement *Statement) tbNameNoSchema(table *schemas.Table) string {
  508. if len(statement.AltTableName) > 0 {
  509. return statement.AltTableName
  510. }
  511. return table.Name
  512. }
  513. // GroupBy generate "Group By keys" statement
  514. func (statement *Statement) GroupBy(keys string) *Statement {
  515. statement.GroupByStr = statement.ReplaceQuote(keys)
  516. return statement
  517. }
  518. // Having generate "Having conditions" statement
  519. func (statement *Statement) Having(conditions string) *Statement {
  520. statement.HavingStr = fmt.Sprintf("HAVING %v", statement.ReplaceQuote(conditions))
  521. return statement
  522. }
  523. // Unscoped always disable struct tag "deleted"
  524. func (statement *Statement) SetUnscoped() *Statement {
  525. statement.unscoped = true
  526. return statement
  527. }
  528. func (statement *Statement) GetUnscoped() bool {
  529. return statement.unscoped
  530. }
  531. func (statement *Statement) genColumnStr() string {
  532. if statement.RefTable == nil {
  533. return ""
  534. }
  535. var buf strings.Builder
  536. columns := statement.RefTable.Columns()
  537. for _, col := range columns {
  538. if statement.OmitColumnMap.Contain(col.Name) {
  539. continue
  540. }
  541. if len(statement.ColumnMap) > 0 && !statement.ColumnMap.Contain(col.Name) {
  542. continue
  543. }
  544. if col.MapType == schemas.ONLYTODB {
  545. continue
  546. }
  547. if buf.Len() != 0 {
  548. buf.WriteString(", ")
  549. }
  550. if statement.JoinStr != "" {
  551. if statement.TableAlias != "" {
  552. buf.WriteString(statement.TableAlias)
  553. } else {
  554. buf.WriteString(statement.TableName())
  555. }
  556. buf.WriteString(".")
  557. }
  558. statement.dialect.Quoter().QuoteTo(&buf, col.Name)
  559. }
  560. return buf.String()
  561. }
  562. func (statement *Statement) GenCreateTableSQL() []string {
  563. statement.RefTable.StoreEngine = statement.StoreEngine
  564. statement.RefTable.Charset = statement.Charset
  565. s, _ := statement.dialect.CreateTableSQL(statement.RefTable, statement.TableName())
  566. return s
  567. }
  568. func (statement *Statement) GenIndexSQL() []string {
  569. var sqls []string
  570. tbName := statement.TableName()
  571. for _, index := range statement.RefTable.Indexes {
  572. if index.Type == schemas.IndexType {
  573. sql := statement.dialect.CreateIndexSQL(tbName, index)
  574. sqls = append(sqls, sql)
  575. }
  576. }
  577. return sqls
  578. }
  579. func uniqueName(tableName, uqeName string) string {
  580. return fmt.Sprintf("UQE_%v_%v", tableName, uqeName)
  581. }
  582. func (statement *Statement) GenUniqueSQL() []string {
  583. var sqls []string
  584. tbName := statement.TableName()
  585. for _, index := range statement.RefTable.Indexes {
  586. if index.Type == schemas.UniqueType {
  587. sql := statement.dialect.CreateIndexSQL(tbName, index)
  588. sqls = append(sqls, sql)
  589. }
  590. }
  591. return sqls
  592. }
  593. func (statement *Statement) GenDelIndexSQL() []string {
  594. var sqls []string
  595. tbName := statement.TableName()
  596. idx := strings.Index(tbName, ".")
  597. if idx > -1 {
  598. tbName = tbName[idx+1:]
  599. }
  600. for _, index := range statement.RefTable.Indexes {
  601. sqls = append(sqls, statement.dialect.DropIndexSQL(tbName, index))
  602. }
  603. return sqls
  604. }
  605. func (statement *Statement) buildConds2(table *schemas.Table, bean interface{},
  606. includeVersion bool, includeUpdated bool, includeNil bool,
  607. includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool,
  608. mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) {
  609. var conds []builder.Cond
  610. for _, col := range table.Columns() {
  611. if !includeVersion && col.IsVersion {
  612. continue
  613. }
  614. if !includeUpdated && col.IsUpdated {
  615. continue
  616. }
  617. if !includeAutoIncr && col.IsAutoIncrement {
  618. continue
  619. }
  620. if statement.dialect.URI().DBType == schemas.MSSQL && (col.SQLType.Name == schemas.Text ||
  621. col.SQLType.IsBlob() || col.SQLType.Name == schemas.TimeStampz) {
  622. continue
  623. }
  624. if col.SQLType.IsJson() {
  625. continue
  626. }
  627. var colName string
  628. if addedTableName {
  629. var nm = tableName
  630. if len(aliasName) > 0 {
  631. nm = aliasName
  632. }
  633. colName = statement.quote(nm) + "." + statement.quote(col.Name)
  634. } else {
  635. colName = statement.quote(col.Name)
  636. }
  637. fieldValuePtr, err := col.ValueOf(bean)
  638. if err != nil {
  639. if !strings.Contains(err.Error(), "is not valid") {
  640. //engine.logger.Warn(err)
  641. }
  642. continue
  643. }
  644. if col.IsDeleted && !unscoped { // tag "deleted" is enabled
  645. conds = append(conds, statement.CondDeleted(col))
  646. }
  647. fieldValue := *fieldValuePtr
  648. if fieldValue.Interface() == nil {
  649. continue
  650. }
  651. fieldType := reflect.TypeOf(fieldValue.Interface())
  652. requiredField := useAllCols
  653. if b, ok := getFlagForColumn(mustColumnMap, col); ok {
  654. if b {
  655. requiredField = true
  656. } else {
  657. continue
  658. }
  659. }
  660. if fieldType.Kind() == reflect.Ptr {
  661. if fieldValue.IsNil() {
  662. if includeNil {
  663. conds = append(conds, builder.Eq{colName: nil})
  664. }
  665. continue
  666. } else if !fieldValue.IsValid() {
  667. continue
  668. } else {
  669. // dereference ptr type to instance type
  670. fieldValue = fieldValue.Elem()
  671. fieldType = reflect.TypeOf(fieldValue.Interface())
  672. requiredField = true
  673. }
  674. }
  675. var val interface{}
  676. switch fieldType.Kind() {
  677. case reflect.Bool:
  678. if allUseBool || requiredField {
  679. val = fieldValue.Interface()
  680. } else {
  681. // if a bool in a struct, it will not be as a condition because it default is false,
  682. // please use Where() instead
  683. continue
  684. }
  685. case reflect.String:
  686. if !requiredField && fieldValue.String() == "" {
  687. continue
  688. }
  689. // for MyString, should convert to string or panic
  690. if fieldType.String() != reflect.String.String() {
  691. val = fieldValue.String()
  692. } else {
  693. val = fieldValue.Interface()
  694. }
  695. case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64:
  696. if !requiredField && fieldValue.Int() == 0 {
  697. continue
  698. }
  699. val = fieldValue.Interface()
  700. case reflect.Float32, reflect.Float64:
  701. if !requiredField && fieldValue.Float() == 0.0 {
  702. continue
  703. }
  704. val = fieldValue.Interface()
  705. case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
  706. if !requiredField && fieldValue.Uint() == 0 {
  707. continue
  708. }
  709. t := int64(fieldValue.Uint())
  710. val = reflect.ValueOf(&t).Interface()
  711. case reflect.Struct:
  712. if fieldType.ConvertibleTo(schemas.TimeType) {
  713. t := fieldValue.Convert(schemas.TimeType).Interface().(time.Time)
  714. if !requiredField && (t.IsZero() || !fieldValue.IsValid()) {
  715. continue
  716. }
  717. val = dialects.FormatColumnTime(statement.dialect, statement.defaultTimeZone, col, t)
  718. } else if _, ok := reflect.New(fieldType).Interface().(convert.Conversion); ok {
  719. continue
  720. } else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok {
  721. val, _ = valNul.Value()
  722. if val == nil && !requiredField {
  723. continue
  724. }
  725. } else {
  726. if col.SQLType.IsJson() {
  727. if col.SQLType.IsText() {
  728. bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
  729. if err != nil {
  730. return nil, err
  731. }
  732. val = string(bytes)
  733. } else if col.SQLType.IsBlob() {
  734. var bytes []byte
  735. var err error
  736. bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
  737. if err != nil {
  738. return nil, err
  739. }
  740. val = bytes
  741. }
  742. } else {
  743. table, err := statement.tagParser.ParseWithCache(fieldValue)
  744. if err != nil {
  745. val = fieldValue.Interface()
  746. } else {
  747. if len(table.PrimaryKeys) == 1 {
  748. pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName)
  749. // fix non-int pk issues
  750. //if pkField.Int() != 0 {
  751. if pkField.IsValid() && !utils.IsZero(pkField.Interface()) {
  752. val = pkField.Interface()
  753. } else {
  754. continue
  755. }
  756. } else {
  757. //TODO: how to handler?
  758. return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys)
  759. }
  760. }
  761. }
  762. }
  763. case reflect.Array:
  764. continue
  765. case reflect.Slice, reflect.Map:
  766. if fieldValue == reflect.Zero(fieldType) {
  767. continue
  768. }
  769. if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 {
  770. continue
  771. }
  772. if col.SQLType.IsText() {
  773. bytes, err := json.DefaultJSONHandler.Marshal(fieldValue.Interface())
  774. if err != nil {
  775. return nil, err
  776. }
  777. val = string(bytes)
  778. } else if col.SQLType.IsBlob() {
  779. var bytes []byte
  780. var err error
  781. if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) &&
  782. fieldType.Elem().Kind() == reflect.Uint8 {
  783. if fieldValue.Len() > 0 {
  784. val = fieldValue.Bytes()
  785. } else {
  786. continue
  787. }
  788. } else {
  789. bytes, err = json.DefaultJSONHandler.Marshal(fieldValue.Interface())
  790. if err != nil {
  791. return nil, err
  792. }
  793. val = bytes
  794. }
  795. } else {
  796. continue
  797. }
  798. default:
  799. val = fieldValue.Interface()
  800. }
  801. conds = append(conds, builder.Eq{colName: val})
  802. }
  803. return builder.And(conds...), nil
  804. }
  805. func (statement *Statement) BuildConds(table *schemas.Table, bean interface{}, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, addedTableName bool) (builder.Cond, error) {
  806. return statement.buildConds2(table, bean, includeVersion, includeUpdated, includeNil, includeAutoIncr, statement.allUseBool, statement.useAllCols,
  807. statement.unscoped, statement.MustColumnMap, statement.TableName(), statement.TableAlias, addedTableName)
  808. }
  809. func (statement *Statement) mergeConds(bean interface{}) error {
  810. if !statement.NoAutoCondition && statement.RefTable != nil {
  811. var addedTableName = (len(statement.JoinStr) > 0)
  812. autoCond, err := statement.BuildConds(statement.RefTable, bean, true, true, false, true, addedTableName)
  813. if err != nil {
  814. return err
  815. }
  816. statement.cond = statement.cond.And(autoCond)
  817. }
  818. if err := statement.ProcessIDParam(); err != nil {
  819. return err
  820. }
  821. return nil
  822. }
  823. func (statement *Statement) GenConds(bean interface{}) (string, []interface{}, error) {
  824. if err := statement.mergeConds(bean); err != nil {
  825. return "", nil, err
  826. }
  827. return statement.GenCondSQL(statement.cond)
  828. }
  829. func (statement *Statement) quoteColumnStr(columnStr string) string {
  830. columns := strings.Split(columnStr, ",")
  831. return statement.dialect.Quoter().Join(columns, ",")
  832. }
  833. func (statement *Statement) ConvertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) {
  834. sql, args, err := convertSQLOrArgs(sqlOrArgs...)
  835. if err != nil {
  836. return "", nil, err
  837. }
  838. return statement.ReplaceQuote(sql), args, nil
  839. }
  840. func convertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) {
  841. switch sqlOrArgs[0].(type) {
  842. case string:
  843. return sqlOrArgs[0].(string), sqlOrArgs[1:], nil
  844. case *builder.Builder:
  845. return sqlOrArgs[0].(*builder.Builder).ToSQL()
  846. case builder.Builder:
  847. bd := sqlOrArgs[0].(builder.Builder)
  848. return bd.ToSQL()
  849. }
  850. return "", nil, ErrUnSupportedType
  851. }
  852. func (statement *Statement) joinColumns(cols []*schemas.Column, includeTableName bool) string {
  853. var colnames = make([]string, len(cols))
  854. for i, col := range cols {
  855. if includeTableName {
  856. colnames[i] = statement.quote(statement.TableName()) +
  857. "." + statement.quote(col.Name)
  858. } else {
  859. colnames[i] = statement.quote(col.Name)
  860. }
  861. }
  862. return strings.Join(colnames, ", ")
  863. }
  864. // CondDeleted returns the conditions whether a record is soft deleted.
  865. func (statement *Statement) CondDeleted(col *schemas.Column) builder.Cond {
  866. var colName = col.Name
  867. if statement.JoinStr != "" {
  868. var prefix string
  869. if statement.TableAlias != "" {
  870. prefix = statement.TableAlias
  871. } else {
  872. prefix = statement.TableName()
  873. }
  874. colName = statement.quote(prefix) + "." + statement.quote(col.Name)
  875. }
  876. var cond = builder.NewCond()
  877. if col.SQLType.IsNumeric() {
  878. cond = builder.Eq{colName: 0}
  879. } else {
  880. // FIXME: mssql: The conversion of a nvarchar data type to a datetime data type resulted in an out-of-range value.
  881. if statement.dialect.URI().DBType != schemas.MSSQL {
  882. cond = builder.Eq{colName: utils.ZeroTime1}
  883. }
  884. }
  885. if col.Nullable {
  886. cond = cond.Or(builder.IsNull{colName})
  887. }
  888. return cond
  889. }