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.

156 lines
3.3 KiB

  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. "time"
  10. )
  11. func condToSQL(cond Cond) (string, []interface{}, error) {
  12. if cond == nil || !cond.IsValid() {
  13. return "", nil, nil
  14. }
  15. w := NewWriter()
  16. if err := cond.WriteTo(w); err != nil {
  17. return "", nil, err
  18. }
  19. return w.writer.String(), w.args, nil
  20. }
  21. func condToBoundSQL(cond Cond) (string, error) {
  22. if cond == nil || !cond.IsValid() {
  23. return "", nil
  24. }
  25. w := NewWriter()
  26. if err := cond.WriteTo(w); err != nil {
  27. return "", err
  28. }
  29. return ConvertToBoundSQL(w.writer.String(), w.args)
  30. }
  31. // ToSQL convert a builder or conditions to SQL and args
  32. func ToSQL(cond interface{}) (string, []interface{}, error) {
  33. switch cond.(type) {
  34. case Cond:
  35. return condToSQL(cond.(Cond))
  36. case *Builder:
  37. return cond.(*Builder).ToSQL()
  38. }
  39. return "", nil, ErrNotSupportType
  40. }
  41. // ToBoundSQL convert a builder or conditions to parameters bound SQL
  42. func ToBoundSQL(cond interface{}) (string, error) {
  43. switch cond.(type) {
  44. case Cond:
  45. return condToBoundSQL(cond.(Cond))
  46. case *Builder:
  47. return cond.(*Builder).ToBoundSQL()
  48. }
  49. return "", ErrNotSupportType
  50. }
  51. func noSQLQuoteNeeded(a interface{}) bool {
  52. switch a.(type) {
  53. case int, int8, int16, int32, int64:
  54. return true
  55. case uint, uint8, uint16, uint32, uint64:
  56. return true
  57. case float32, float64:
  58. return true
  59. case bool:
  60. return true
  61. case string:
  62. return false
  63. case time.Time, *time.Time:
  64. return false
  65. }
  66. t := reflect.TypeOf(a)
  67. switch t.Kind() {
  68. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  69. return true
  70. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  71. return true
  72. case reflect.Float32, reflect.Float64:
  73. return true
  74. case reflect.Bool:
  75. return true
  76. case reflect.String:
  77. return false
  78. }
  79. return false
  80. }
  81. // ConvertToBoundSQL will convert SQL and args to a bound SQL
  82. func ConvertToBoundSQL(sql string, args []interface{}) (string, error) {
  83. buf := StringBuilder{}
  84. var i, j, start int
  85. for ; i < len(sql); i++ {
  86. if sql[i] == '?' {
  87. _, err := buf.WriteString(sql[start:i])
  88. if err != nil {
  89. return "", err
  90. }
  91. start = i + 1
  92. if len(args) == j {
  93. return "", ErrNeedMoreArguments
  94. }
  95. arg := args[j]
  96. if namedArg, ok := arg.(sql2.NamedArg); ok {
  97. arg = namedArg.Value
  98. }
  99. if noSQLQuoteNeeded(arg) {
  100. _, err = fmt.Fprint(&buf, arg)
  101. } else {
  102. _, err = fmt.Fprintf(&buf, "'%v'", arg)
  103. }
  104. if err != nil {
  105. return "", err
  106. }
  107. j = j + 1
  108. }
  109. }
  110. _, err := buf.WriteString(sql[start:])
  111. if err != nil {
  112. return "", err
  113. }
  114. return buf.String(), nil
  115. }
  116. // ConvertPlaceholder replaces ? to $1, $2 ... or :1, :2 ... according prefix
  117. func ConvertPlaceholder(sql, prefix string) (string, error) {
  118. buf := StringBuilder{}
  119. var i, j, start int
  120. for ; i < len(sql); i++ {
  121. if sql[i] == '?' {
  122. if _, err := buf.WriteString(sql[start:i]); err != nil {
  123. return "", err
  124. }
  125. start = i + 1
  126. j = j + 1
  127. if _, err := buf.WriteString(fmt.Sprintf("%v%d", prefix, j)); err != nil {
  128. return "", err
  129. }
  130. }
  131. }
  132. if _, err := buf.WriteString(sql[start:]); err != nil {
  133. return "", err
  134. }
  135. return buf.String(), nil
  136. }