http urls monitor.

convert.go 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package sqlbuilder
  2. import (
  3. "database/sql/driver"
  4. "reflect"
  5. "strings"
  6. "upper.io/db.v3"
  7. "upper.io/db.v3/internal/sqladapter/exql"
  8. )
  9. var (
  10. sqlDefault = exql.RawValue(`DEFAULT`)
  11. )
  12. func expandQuery(in string, args []interface{}, fn func(interface{}) (string, []interface{})) (string, []interface{}) {
  13. argn := 0
  14. argx := make([]interface{}, 0, len(args))
  15. for i := 0; i < len(in); i++ {
  16. if in[i] != '?' {
  17. continue
  18. }
  19. if len(args) > argn {
  20. k, values := fn(args[argn])
  21. k, values = expandQuery(k, values, fn)
  22. if k != "" {
  23. in = in[:i] + k + in[i+1:]
  24. i += len(k) - 1
  25. }
  26. if len(values) > 0 {
  27. argx = append(argx, values...)
  28. }
  29. argn++
  30. }
  31. }
  32. if len(argx) < len(args) {
  33. argx = append(argx, args[argn:]...)
  34. }
  35. return in, argx
  36. }
  37. // toInterfaceArguments converts the given value into an array of interfaces.
  38. func toInterfaceArguments(value interface{}) (args []interface{}, isSlice bool) {
  39. v := reflect.ValueOf(value)
  40. if value == nil {
  41. return nil, false
  42. }
  43. switch t := value.(type) {
  44. case driver.Valuer:
  45. return []interface{}{t}, false
  46. }
  47. if v.Type().Kind() == reflect.Slice {
  48. var i, total int
  49. // Byte slice gets transformed into a string.
  50. if v.Type().Elem().Kind() == reflect.Uint8 {
  51. return []interface{}{string(value.([]byte))}, false
  52. }
  53. total = v.Len()
  54. args = make([]interface{}, total)
  55. for i = 0; i < total; i++ {
  56. args[i] = v.Index(i).Interface()
  57. }
  58. return args, true
  59. }
  60. return []interface{}{value}, false
  61. }
  62. // toColumnsValuesAndArguments maps the given columnNames and columnValues into
  63. // expr's Columns and Values, it also extracts and returns query arguments.
  64. func toColumnsValuesAndArguments(columnNames []string, columnValues []interface{}) (*exql.Columns, *exql.Values, []interface{}, error) {
  65. var arguments []interface{}
  66. columns := new(exql.Columns)
  67. columns.Columns = make([]exql.Fragment, 0, len(columnNames))
  68. for i := range columnNames {
  69. columns.Columns = append(columns.Columns, exql.ColumnWithName(columnNames[i]))
  70. }
  71. values := new(exql.Values)
  72. arguments = make([]interface{}, 0, len(columnValues))
  73. values.Values = make([]exql.Fragment, 0, len(columnValues))
  74. for i := range columnValues {
  75. switch v := columnValues[i].(type) {
  76. case *exql.Raw, exql.Raw:
  77. values.Values = append(values.Values, sqlDefault)
  78. case *exql.Value:
  79. // Adding value.
  80. values.Values = append(values.Values, v)
  81. case exql.Value:
  82. // Adding value.
  83. values.Values = append(values.Values, &v)
  84. default:
  85. // Adding both value and placeholder.
  86. values.Values = append(values.Values, sqlPlaceholder)
  87. arguments = append(arguments, v)
  88. }
  89. }
  90. return columns, values, arguments, nil
  91. }
  92. func preprocessFn(arg interface{}) (string, []interface{}) {
  93. values, isSlice := toInterfaceArguments(arg)
  94. if isSlice {
  95. if len(values) == 0 {
  96. return `(NULL)`, nil
  97. }
  98. return `(?` + strings.Repeat(`, ?`, len(values)-1) + `)`, values
  99. }
  100. if len(values) == 1 {
  101. switch t := arg.(type) {
  102. case db.RawValue:
  103. return Preprocess(t.Raw(), t.Arguments())
  104. case compilable:
  105. c, err := t.Compile()
  106. if err == nil {
  107. return `(` + c + `)`, t.Arguments()
  108. }
  109. panic(err.Error())
  110. }
  111. } else if len(values) == 0 {
  112. return `NULL`, nil
  113. }
  114. return "", []interface{}{arg}
  115. }
  116. // Preprocess expands arguments that needs to be expanded and compiles a query
  117. // into a single string.
  118. func Preprocess(in string, args []interface{}) (string, []interface{}) {
  119. return expandQuery(in, args, preprocessFn)
  120. }