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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright 2016 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 builder
  5. import (
  6. sql2 "database/sql"
  7. "fmt"
  8. )
  9. type optype byte
  10. const (
  11. condType optype = iota // only conditions
  12. selectType // select
  13. insertType // insert
  14. updateType // update
  15. deleteType // delete
  16. setOpType // set operation
  17. )
  18. // all databasees
  19. const (
  20. POSTGRES = "postgres"
  21. SQLITE = "sqlite3"
  22. MYSQL = "mysql"
  23. MSSQL = "mssql"
  24. ORACLE = "oracle"
  25. UNION = "union"
  26. INTERSECT = "intersect"
  27. EXCEPT = "except"
  28. )
  29. type join struct {
  30. joinType string
  31. joinTable interface{}
  32. joinCond Cond
  33. }
  34. type setOp struct {
  35. opType string
  36. distinctType string
  37. builder *Builder
  38. }
  39. type limit struct {
  40. limitN int
  41. offset int
  42. }
  43. // Builder describes a SQL statement
  44. type Builder struct {
  45. optype
  46. dialect string
  47. isNested bool
  48. into string
  49. from string
  50. subQuery *Builder
  51. cond Cond
  52. selects []string
  53. joins []join
  54. setOps []setOp
  55. limitation *limit
  56. insertCols []string
  57. insertVals []interface{}
  58. updates []UpdateCond
  59. orderBy string
  60. groupBy string
  61. having string
  62. }
  63. // Dialect sets the db dialect of Builder.
  64. func Dialect(dialect string) *Builder {
  65. builder := &Builder{cond: NewCond(), dialect: dialect}
  66. return builder
  67. }
  68. // MySQL is shortcut of Dialect(MySQL)
  69. func MySQL() *Builder {
  70. return Dialect(MYSQL)
  71. }
  72. // MsSQL is shortcut of Dialect(MsSQL)
  73. func MsSQL() *Builder {
  74. return Dialect(MSSQL)
  75. }
  76. // Oracle is shortcut of Dialect(Oracle)
  77. func Oracle() *Builder {
  78. return Dialect(ORACLE)
  79. }
  80. // Postgres is shortcut of Dialect(Postgres)
  81. func Postgres() *Builder {
  82. return Dialect(POSTGRES)
  83. }
  84. // SQLite is shortcut of Dialect(SQLITE)
  85. func SQLite() *Builder {
  86. return Dialect(SQLITE)
  87. }
  88. // Where sets where SQL
  89. func (b *Builder) Where(cond Cond) *Builder {
  90. if b.cond.IsValid() {
  91. b.cond = b.cond.And(cond)
  92. } else {
  93. b.cond = cond
  94. }
  95. return b
  96. }
  97. // From sets from subject(can be a table name in string or a builder pointer) and its alias
  98. func (b *Builder) From(subject interface{}, alias ...string) *Builder {
  99. switch subject.(type) {
  100. case *Builder:
  101. b.subQuery = subject.(*Builder)
  102. if len(alias) > 0 {
  103. b.from = alias[0]
  104. } else {
  105. b.isNested = true
  106. }
  107. case string:
  108. b.from = subject.(string)
  109. if len(alias) > 0 {
  110. b.from = b.from + " " + alias[0]
  111. }
  112. }
  113. return b
  114. }
  115. // TableName returns the table name
  116. func (b *Builder) TableName() string {
  117. if b.optype == insertType {
  118. return b.into
  119. }
  120. return b.from
  121. }
  122. // Into sets insert table name
  123. func (b *Builder) Into(tableName string) *Builder {
  124. b.into = tableName
  125. return b
  126. }
  127. // Union sets union conditions
  128. func (b *Builder) Union(distinctType string, cond *Builder) *Builder {
  129. return b.setOperation(UNION, distinctType, cond)
  130. }
  131. // Intersect sets intersect conditions
  132. func (b *Builder) Intersect(distinctType string, cond *Builder) *Builder {
  133. return b.setOperation(INTERSECT, distinctType, cond)
  134. }
  135. // Except sets except conditions
  136. func (b *Builder) Except(distinctType string, cond *Builder) *Builder {
  137. return b.setOperation(EXCEPT, distinctType, cond)
  138. }
  139. func (b *Builder) setOperation(opType, distinctType string, cond *Builder) *Builder {
  140. var builder *Builder
  141. if b.optype != setOpType {
  142. builder = &Builder{cond: NewCond()}
  143. builder.optype = setOpType
  144. builder.dialect = b.dialect
  145. builder.selects = b.selects
  146. currentSetOps := b.setOps
  147. // erase sub setOps (actually append to new Builder.unions)
  148. b.setOps = nil
  149. for e := range currentSetOps {
  150. currentSetOps[e].builder.dialect = b.dialect
  151. }
  152. builder.setOps = append(append(builder.setOps, setOp{opType, "", b}), currentSetOps...)
  153. } else {
  154. builder = b
  155. }
  156. if cond != nil {
  157. if cond.dialect == "" && builder.dialect != "" {
  158. cond.dialect = builder.dialect
  159. }
  160. builder.setOps = append(builder.setOps, setOp{opType, distinctType, cond})
  161. }
  162. return builder
  163. }
  164. // Limit sets limitN condition
  165. func (b *Builder) Limit(limitN int, offset ...int) *Builder {
  166. b.limitation = &limit{limitN: limitN}
  167. if len(offset) > 0 {
  168. b.limitation.offset = offset[0]
  169. }
  170. return b
  171. }
  172. // Select sets select SQL
  173. func (b *Builder) Select(cols ...string) *Builder {
  174. b.selects = cols
  175. if b.optype == condType {
  176. b.optype = selectType
  177. }
  178. return b
  179. }
  180. // And sets AND condition
  181. func (b *Builder) And(cond Cond) *Builder {
  182. b.cond = And(b.cond, cond)
  183. return b
  184. }
  185. // Or sets OR condition
  186. func (b *Builder) Or(cond Cond) *Builder {
  187. b.cond = Or(b.cond, cond)
  188. return b
  189. }
  190. // Update sets update SQL
  191. func (b *Builder) Update(updates ...Cond) *Builder {
  192. b.updates = make([]UpdateCond, 0, len(updates))
  193. for _, update := range updates {
  194. if u, ok := update.(UpdateCond); ok && u.IsValid() {
  195. b.updates = append(b.updates, u)
  196. }
  197. }
  198. b.optype = updateType
  199. return b
  200. }
  201. // Delete sets delete SQL
  202. func (b *Builder) Delete(conds ...Cond) *Builder {
  203. b.cond = b.cond.And(conds...)
  204. b.optype = deleteType
  205. return b
  206. }
  207. // WriteTo implements Writer interface
  208. func (b *Builder) WriteTo(w Writer) error {
  209. switch b.optype {
  210. /*case condType:
  211. return b.cond.WriteTo(w)*/
  212. case selectType:
  213. return b.selectWriteTo(w)
  214. case insertType:
  215. return b.insertWriteTo(w)
  216. case updateType:
  217. return b.updateWriteTo(w)
  218. case deleteType:
  219. return b.deleteWriteTo(w)
  220. case setOpType:
  221. return b.setOpWriteTo(w)
  222. }
  223. return ErrNotSupportType
  224. }
  225. // ToSQL convert a builder to SQL and args
  226. func (b *Builder) ToSQL() (string, []interface{}, error) {
  227. w := NewWriter()
  228. if err := b.WriteTo(w); err != nil {
  229. return "", nil, err
  230. }
  231. // in case of sql.NamedArg in args
  232. for e := range w.args {
  233. if namedArg, ok := w.args[e].(sql2.NamedArg); ok {
  234. w.args[e] = namedArg.Value
  235. }
  236. }
  237. var sql = w.String()
  238. var err error
  239. switch b.dialect {
  240. case ORACLE, MSSQL:
  241. // This is for compatibility with different sql drivers
  242. for e := range w.args {
  243. w.args[e] = sql2.Named(fmt.Sprintf("p%d", e+1), w.args[e])
  244. }
  245. var prefix string
  246. if b.dialect == ORACLE {
  247. prefix = ":p"
  248. } else {
  249. prefix = "@p"
  250. }
  251. if sql, err = ConvertPlaceholder(sql, prefix); err != nil {
  252. return "", nil, err
  253. }
  254. case POSTGRES:
  255. if sql, err = ConvertPlaceholder(sql, "$"); err != nil {
  256. return "", nil, err
  257. }
  258. }
  259. return sql, w.args, nil
  260. }
  261. // ToBoundSQL generated a bound SQL string
  262. func (b *Builder) ToBoundSQL() (string, error) {
  263. w := NewWriter()
  264. if err := b.WriteTo(w); err != nil {
  265. return "", err
  266. }
  267. return ConvertToBoundSQL(w.String(), w.args)
  268. }