sql_test.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. "io/ioutil"
  9. "os"
  10. "testing"
  11. "github.com/go-xorm/sqlfiddle"
  12. "github.com/stretchr/testify/assert"
  13. )
  14. const placeholderConverterSQL = "SELECT a, b FROM table_a WHERE b_id=(SELECT id FROM table_b WHERE b=?) AND id=? AND c=? AND d=? AND e=? AND f=?"
  15. const placeholderConvertedSQL = "SELECT a, b FROM table_a WHERE b_id=(SELECT id FROM table_b WHERE b=$1) AND id=$2 AND c=$3 AND d=$4 AND e=$5 AND f=$6"
  16. const placeholderBoundSQL = "SELECT a, b FROM table_a WHERE b_id=(SELECT id FROM table_b WHERE b=1) AND id=2.1 AND c='3' AND d=4 AND e='5' AND f=true"
  17. func TestPlaceholderConverter(t *testing.T) {
  18. newSQL, err := ConvertPlaceholder(placeholderConverterSQL, "$")
  19. assert.NoError(t, err)
  20. assert.EqualValues(t, placeholderConvertedSQL, newSQL)
  21. }
  22. func BenchmarkPlaceholderConverter(b *testing.B) {
  23. for i := 0; i < b.N; i++ {
  24. ConvertPlaceholder(placeholderConverterSQL, "$")
  25. }
  26. }
  27. func TestBoundSQLConverter(t *testing.T) {
  28. newSQL, err := ConvertToBoundSQL(placeholderConverterSQL, []interface{}{1, 2.1, "3", uint(4), "5", true})
  29. assert.NoError(t, err)
  30. assert.EqualValues(t, placeholderBoundSQL, newSQL)
  31. newSQL, err = ConvertToBoundSQL(placeholderConverterSQL, []interface{}{1, 2.1, sql2.Named("any", "3"), uint(4), "5", true})
  32. assert.NoError(t, err)
  33. assert.EqualValues(t, placeholderBoundSQL, newSQL)
  34. newSQL, err = ConvertToBoundSQL(placeholderConverterSQL, []interface{}{1, 2.1, "3", 4, "5"})
  35. assert.Error(t, err)
  36. assert.EqualValues(t, ErrNeedMoreArguments, err)
  37. newSQL, err = ToBoundSQL(Select("id").From("table").Where(In("a", 1, 2)))
  38. assert.NoError(t, err)
  39. assert.EqualValues(t, "SELECT id FROM table WHERE a IN (1,2)", newSQL)
  40. newSQL, err = ToBoundSQL(Eq{"a": 1})
  41. assert.NoError(t, err)
  42. assert.EqualValues(t, "a=1", newSQL)
  43. newSQL, err = ToBoundSQL(1)
  44. assert.Error(t, err)
  45. assert.EqualValues(t, ErrNotSupportType, err)
  46. }
  47. func TestSQL(t *testing.T) {
  48. newSQL, args, err := ToSQL(In("a", 1, 2))
  49. assert.NoError(t, err)
  50. assert.EqualValues(t, "a IN (?,?)", newSQL)
  51. assert.EqualValues(t, []interface{}{1, 2}, args)
  52. newSQL, args, err = ToSQL(Select("id").From("table").Where(In("a", 1, 2)))
  53. assert.NoError(t, err)
  54. assert.EqualValues(t, "SELECT id FROM table WHERE a IN (?,?)", newSQL)
  55. assert.EqualValues(t, []interface{}{1, 2}, args)
  56. newSQL, args, err = ToSQL(1)
  57. assert.Error(t, err)
  58. assert.EqualValues(t, ErrNotSupportType, err)
  59. }
  60. type fiddler struct {
  61. sessionCode string
  62. dbType int
  63. f *sqlfiddle.Fiddle
  64. }
  65. func readPreparationSQLFromFile(path string) (string, error) {
  66. file, err := os.Open(path)
  67. defer file.Close()
  68. if err != nil {
  69. return "", err
  70. }
  71. data, err := ioutil.ReadAll(file)
  72. if err != nil {
  73. return "", err
  74. }
  75. return string(data), nil
  76. }
  77. func newFiddler(fiddleServerAddr, dbDialect, preparationSQL string) (*fiddler, error) {
  78. var dbType int
  79. switch dbDialect {
  80. case MYSQL:
  81. dbType = sqlfiddle.Mysql5_6
  82. case MSSQL:
  83. dbType = sqlfiddle.MSSQL2017
  84. case POSTGRES:
  85. dbType = sqlfiddle.PostgreSQL96
  86. case ORACLE:
  87. dbType = sqlfiddle.Oracle11gR2
  88. case SQLITE:
  89. dbType = sqlfiddle.SQLite_WebSQL
  90. default:
  91. return nil, ErrNotSupportDialectType
  92. }
  93. f := sqlfiddle.NewFiddle(fiddleServerAddr)
  94. response, err := f.CreateSchema(dbType, preparationSQL)
  95. if err != nil {
  96. return nil, err
  97. }
  98. return &fiddler{sessionCode: response.Code, f: f, dbType: dbType}, nil
  99. }
  100. func (f *fiddler) executableCheck(obj interface{}) error {
  101. var sql string
  102. var err error
  103. switch obj.(type) {
  104. case *Builder:
  105. sql, err = obj.(*Builder).ToBoundSQL()
  106. if err != nil {
  107. return err
  108. }
  109. case string:
  110. sql = obj.(string)
  111. }
  112. _, err = f.f.RunSQL(f.dbType, f.sessionCode, sql)
  113. if err != nil {
  114. return err
  115. }
  116. return nil
  117. }
  118. func TestReadPreparationSQLFromFile(t *testing.T) {
  119. sqlFromFile, err := readPreparationSQLFromFile("testdata/mysql_fiddle_data.sql")
  120. assert.NoError(t, err)
  121. fmt.Println(sqlFromFile)
  122. }
  123. /*
  124. func TestNewFiddler(t *testing.T) {
  125. sqlFromFile, err := readPreparationSQLFromFile("testdata/mysql_fiddle_data.sql")
  126. assert.NoError(t, err)
  127. f, err := newFiddler("", MYSQL, sqlFromFile)
  128. assert.NoError(t, err)
  129. assert.NotEmpty(t, f.sessionCode)
  130. }
  131. func TestExecutableCheck(t *testing.T) {
  132. sqlFromFile, err := readPreparationSQLFromFile("testdata/mysql_fiddle_data.sql")
  133. assert.NoError(t, err)
  134. f, err := newFiddler("", MYSQL, sqlFromFile)
  135. assert.NoError(t, err)
  136. assert.NotEmpty(t, f.sessionCode)
  137. assert.NoError(t, f.executableCheck("SELECT * FROM table1"))
  138. err = f.executableCheck("SELECT * FROM table3")
  139. assert.Error(t, err)
  140. }*/
  141. func TestToSQLInDifferentDialects(t *testing.T) {
  142. sql, args, err := Postgres().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
  143. assert.NoError(t, err)
  144. assert.EqualValues(t, "SELECT * FROM table1 WHERE a=$1 AND b<>$2", sql)
  145. assert.EqualValues(t, []interface{}{"1", "100"}, args)
  146. sql, args, err = MySQL().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
  147. assert.NoError(t, err)
  148. assert.EqualValues(t, "SELECT * FROM table1 WHERE a=? AND b<>?", sql)
  149. assert.EqualValues(t, []interface{}{"1", "100"}, args)
  150. sql, args, err = MsSQL().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
  151. assert.NoError(t, err)
  152. assert.EqualValues(t, "SELECT * FROM table1 WHERE a=@p1 AND b<>@p2", sql)
  153. assert.EqualValues(t, []interface{}{sql2.Named("p1", "1"), sql2.Named("p2", "100")}, args)
  154. // test sql.NamedArg in cond
  155. sql, args, err = MsSQL().Select().From("table1").Where(Eq{"a": sql2.NamedArg{Name: "param", Value: "1"}}.And(Neq{"b": "100"})).ToSQL()
  156. assert.NoError(t, err)
  157. assert.EqualValues(t, "SELECT * FROM table1 WHERE a=@p1 AND b<>@p2", sql)
  158. assert.EqualValues(t, []interface{}{sql2.Named("p1", "1"), sql2.Named("p2", "100")}, args)
  159. sql, args, err = Oracle().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
  160. assert.NoError(t, err)
  161. assert.EqualValues(t, "SELECT * FROM table1 WHERE a=:p1 AND b<>:p2", sql)
  162. assert.EqualValues(t, []interface{}{sql2.Named("p1", "1"), sql2.Named("p2", "100")}, args)
  163. // test sql.NamedArg in cond
  164. sql, args, err = Oracle().Select().From("table1").Where(Eq{"a": sql2.Named("a", "1")}.And(Neq{"b": "100"})).ToSQL()
  165. assert.NoError(t, err)
  166. assert.EqualValues(t, "SELECT * FROM table1 WHERE a=:p1 AND b<>:p2", sql)
  167. assert.EqualValues(t, []interface{}{sql2.Named("p1", "1"), sql2.Named("p2", "100")}, args)
  168. sql, args, err = SQLite().Select().From("table1").Where(Eq{"a": "1"}.And(Neq{"b": "100"})).ToSQL()
  169. assert.NoError(t, err)
  170. assert.EqualValues(t, "SELECT * FROM table1 WHERE a=? AND b<>?", sql)
  171. assert.EqualValues(t, []interface{}{"1", "100"}, args)
  172. }
  173. func TestToSQLInjectionHarmlessDisposal(t *testing.T) {
  174. sql, err := MySQL().Select("*").From("table1").Where(Cond(Eq{"name": "cat';truncate table table1;"})).ToBoundSQL()
  175. assert.NoError(t, err)
  176. assert.EqualValues(t, "SELECT * FROM table1 WHERE name='cat'';truncate table table1;'", sql)
  177. }