sql.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Copyright 2018 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. "reflect"
  9. "strings"
  10. "time"
  11. )
  12. func condToSQL(cond Cond) (string, []interface{}, error) {
  13. if cond == nil || !cond.IsValid() {
  14. return "", nil, nil
  15. }
  16. w := NewWriter()
  17. if err := cond.WriteTo(w); err != nil {
  18. return "", nil, err
  19. }
  20. return w.writer.String(), w.args, nil
  21. }
  22. func condToBoundSQL(cond Cond) (string, error) {
  23. if cond == nil || !cond.IsValid() {
  24. return "", nil
  25. }
  26. w := NewWriter()
  27. if err := cond.WriteTo(w); err != nil {
  28. return "", err
  29. }
  30. return ConvertToBoundSQL(w.writer.String(), w.args)
  31. }
  32. // ToSQL convert a builder or conditions to SQL and args
  33. func ToSQL(cond interface{}) (string, []interface{}, error) {
  34. switch cond.(type) {
  35. case Cond:
  36. return condToSQL(cond.(Cond))
  37. case *Builder:
  38. return cond.(*Builder).ToSQL()
  39. }
  40. return "", nil, ErrNotSupportType
  41. }
  42. // ToBoundSQL convert a builder or conditions to parameters bound SQL
  43. func ToBoundSQL(cond interface{}) (string, error) {
  44. switch cond.(type) {
  45. case Cond:
  46. return condToBoundSQL(cond.(Cond))
  47. case *Builder:
  48. return cond.(*Builder).ToBoundSQL()
  49. }
  50. return "", ErrNotSupportType
  51. }
  52. func noSQLQuoteNeeded(a interface{}) bool {
  53. switch a.(type) {
  54. case int, int8, int16, int32, int64:
  55. return true
  56. case uint, uint8, uint16, uint32, uint64:
  57. return true
  58. case float32, float64:
  59. return true
  60. case bool:
  61. return true
  62. case string:
  63. return false
  64. case time.Time, *time.Time:
  65. return false
  66. case expr, *expr:
  67. return true
  68. }
  69. t := reflect.TypeOf(a)
  70. switch t.Kind() {
  71. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  72. return true
  73. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  74. return true
  75. case reflect.Float32, reflect.Float64:
  76. return true
  77. case reflect.Bool:
  78. return true
  79. case reflect.String:
  80. return false
  81. }
  82. return false
  83. }
  84. // ConvertToBoundSQL will convert SQL and args to a bound SQL
  85. func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
  86. buf := StringBuilder{}
  87. var i, j, start int
  88. for ; i < len(sql); i++ {
  89. if sql[i] == '?' {
  90. _, err := buf.WriteString(sql[start:i])
  91. if err != nil {
  92. return "", err
  93. }
  94. start = i + 1
  95. if len(args) == j {
  96. return "", ErrNeedMoreArguments
  97. }
  98. arg := args[j]
  99. if namedArg, ok := arg.(sql2.NamedArg); ok {
  100. arg = namedArg.Value
  101. }
  102. if noSQLQuoteNeeded(arg) {
  103. _, err = fmt.Fprint(&buf, arg)
  104. } else {
  105. // replace ' -> '' (standard replacement) to avoid critical SQL injection,
  106. // NOTICE: may allow some injection like % (or _) in LIKE query
  107. _, err = fmt.Fprintf(&buf, "'%v'", strings.Replace(fmt.Sprintf("%v", arg), "'",
  108. "''", -1))
  109. }
  110. if err != nil {
  111. return "", err
  112. }
  113. j = j + 1
  114. }
  115. }
  116. _, err := buf.WriteString(sql[start:])
  117. if err != nil {
  118. return "", err
  119. }
  120. return buf.String(), nil
  121. }
  122. // ConvertToBoundSQL will convert SQL and args to a bound SQL
  123. func ConvertExprToBoundSQL(sql string, args []interface{}) (string,[]interface{}, error) {
  124. buf := StringBuilder{}
  125. var i, j, start int
  126. var sqlArgs []interface{}
  127. for ; i < len(sql); i++ {
  128. if sql[i] == '?' {
  129. _, err := buf.WriteString(sql[start:i])
  130. if err != nil {
  131. return "",sqlArgs, err
  132. }
  133. start = i + 1
  134. if len(args) == j {
  135. return "",sqlArgs, ErrNeedMoreArguments
  136. }
  137. arg := args[j]
  138. if exprArg, ok := arg.(expr);ok{
  139. arg = exprArg.sql
  140. _, err = fmt.Fprint(&buf, arg)
  141. if err != nil {
  142. return "",sqlArgs, err
  143. }
  144. for i,_:=range exprArg.args{
  145. sqlArgs = append(sqlArgs, exprArg.args[i])
  146. }
  147. }else{
  148. _, err = fmt.Fprint(&buf, "?")
  149. if err != nil {
  150. return "",sqlArgs, err
  151. }
  152. sqlArgs = append(sqlArgs, arg)
  153. }
  154. j = j + 1
  155. }
  156. }
  157. _, err := buf.WriteString(sql[start:])
  158. if err != nil {
  159. return "",sqlArgs, err
  160. }
  161. return buf.String(), sqlArgs,nil
  162. }
  163. // ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix
  164. func ConvertPlaceholder(sql, prefix string) (string, error) {
  165. buf := StringBuilder{}
  166. var i, j, start int
  167. for ; i < len(sql); i++ {
  168. if sql[i] == '?' {
  169. if _, err := buf.WriteString(sql[start:i]); err != nil {
  170. return "", err
  171. }
  172. start = i + 1
  173. j = j + 1
  174. if _, err := buf.WriteString(fmt.Sprintf("%v%d", prefix, j)); err != nil {
  175. return "", err
  176. }
  177. }
  178. }
  179. if _, err := buf.WriteString(sql[start:]); err != nil {
  180. return "", err
  181. }
  182. return buf.String(), nil
  183. }