github.com/wfusion/gofusion@v1.1.14/common/utils/sqlparser/ast_test.go (about) 1 package sqlparser_test 2 3 import ( 4 "reflect" 5 "strings" 6 "testing" 7 8 "github.com/go-test/deep" 9 "github.com/wfusion/gofusion/common/utils/sqlparser" 10 ) 11 12 func TestExprString(t *testing.T) { 13 if got, want := sqlparser.ExprString(&sqlparser.NullLit{}), "NULL"; got != want { 14 t.Fatalf("ExprString()=%q, want %q", got, want) 15 } else if got, want := sqlparser.ExprString(nil), ""; got != want { 16 t.Fatalf("ExprString()=%q, want %q", got, want) 17 } 18 } 19 20 func TestSplitExprTree(t *testing.T) { 21 t.Run("AND-only", func(t *testing.T) { 22 AssertSplitExprTree(t, `x = 1 AND y = 2 AND z = 3`, []sqlparser.Expr{ 23 &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "x"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "1"}}, 24 &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "y"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "2"}}, 25 &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "z"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "3"}}, 26 }) 27 }) 28 29 t.Run("OR", func(t *testing.T) { 30 AssertSplitExprTree(t, `x = 1 AND (y = 2 OR y = 3) AND z = 4`, []sqlparser.Expr{ 31 &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "x"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "1"}}, 32 &sqlparser.BinaryExpr{ 33 X: &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "y"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "2"}}, 34 Op: sqlparser.OR, 35 Y: &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "y"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "3"}}, 36 }, 37 &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "z"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "4"}}, 38 }) 39 }) 40 41 t.Run("ParenExpr", func(t *testing.T) { 42 AssertSplitExprTree(t, `x = 1 AND (y = 2 AND z = 3)`, []sqlparser.Expr{ 43 &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "x"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "1"}}, 44 &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "y"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "2"}}, 45 &sqlparser.BinaryExpr{X: &sqlparser.Ident{Name: "z"}, Op: sqlparser.EQ, Y: &sqlparser.NumberLit{Value: "3"}}, 46 }) 47 }) 48 } 49 50 func AssertSplitExprTree(tb testing.TB, s string, want []sqlparser.Expr) { 51 tb.Helper() 52 e := sqlparser.MustParseExprString(s) 53 if diff := deep.Equal(sqlparser.SplitExprTree(StripExprPos(e)), want); diff != nil { 54 tb.Fatal("mismatch: \n" + strings.Join(diff, "\n")) 55 } 56 } 57 58 func TestDeleteStatement_String(t *testing.T) { 59 AssertStatementStringer(t, &sqlparser.DeleteStatement{ 60 TableName: &sqlparser.TableName{ 61 Name: &sqlparser.Ident{Name: "tbl"}, 62 Alias: &sqlparser.Ident{Name: "tbl2"}, 63 }, 64 }, `DELETE FROM tbl AS tbl2`) 65 66 AssertStatementStringer(t, &sqlparser.DeleteStatement{ 67 TableName: &sqlparser.TableName{ 68 Name: &sqlparser.Ident{Name: "tbl", Quoted: true, QuoteChar: `"`}, 69 }, 70 }, `DELETE FROM "tbl"`) 71 72 AssertStatementStringer(t, &sqlparser.DeleteStatement{ 73 TableName: &sqlparser.TableName{ 74 Name: &sqlparser.Ident{Name: "tbl", Quoted: true, QuoteChar: "`"}, 75 }, 76 }, "DELETE FROM `tbl`") 77 78 AssertStatementStringer(t, &sqlparser.DeleteStatement{ 79 TableName: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 80 Condition: &sqlparser.BoolLit{Value: true}, 81 }, `DELETE FROM tbl WHERE TRUE`) 82 } 83 84 func TestInsertStatement_String(t *testing.T) { 85 AssertStatementStringer(t, &sqlparser.InsertStatement{ 86 TableName: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 87 DefaultValues: true, 88 }, `INSERT INTO tbl DEFAULT VALUES`) 89 90 AssertStatementStringer(t, &sqlparser.InsertStatement{ 91 TableName: &sqlparser.TableName{ 92 Name: &sqlparser.Ident{Name: "tbl"}, 93 Alias: &sqlparser.Ident{Name: "x"}, 94 }, 95 DefaultValues: true, 96 }, `INSERT INTO tbl AS x DEFAULT VALUES`) 97 98 AssertStatementStringer(t, &sqlparser.InsertStatement{ 99 TableName: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 100 Query: &sqlparser.SelectStatement{ 101 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 102 }, 103 }, `INSERT INTO tbl SELECT *`) 104 105 AssertStatementStringer(t, &sqlparser.InsertStatement{ 106 TableName: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 107 ColumnNames: []*sqlparser.Ident{ 108 {Name: "x"}, 109 {Name: "y", Quoted: true, QuoteChar: `"`}, 110 }, 111 Expressions: []*sqlparser.Exprs{ 112 {Exprs: []sqlparser.Expr{&sqlparser.NullLit{}, &sqlparser.NullLit{}}}, 113 {Exprs: []sqlparser.Expr{&sqlparser.NullLit{}, &sqlparser.NullLit{}}}, 114 }, 115 }, `INSERT INTO tbl (x, "y") VALUES (NULL, NULL), (NULL, NULL)`) 116 117 AssertStatementStringer(t, &sqlparser.InsertStatement{ 118 TableName: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 119 DefaultValues: true, 120 UpsertClause: &sqlparser.UpsertClause{ 121 DoNothing: true, 122 }, 123 }, `INSERT INTO tbl DEFAULT VALUES ON CONFLICT DO NOTHING`) 124 125 AssertStatementStringer(t, &sqlparser.InsertStatement{ 126 TableName: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 127 DefaultValues: true, 128 UpsertClause: &sqlparser.UpsertClause{ 129 Columns: []*sqlparser.IndexedColumn{ 130 {X: &sqlparser.Ident{Name: "x"}, Asc: true}, 131 {X: &sqlparser.Ident{Name: "y"}, Desc: true}, 132 }, 133 WhereExpr: &sqlparser.BoolLit{Value: true}, 134 Assignments: []*sqlparser.Assignment{ 135 {Columns: []*sqlparser.Ident{{Name: "x"}}, Expr: &sqlparser.NumberLit{Value: "100"}}, 136 {Columns: []*sqlparser.Ident{{Name: "y"}, {Name: "z"}}, Expr: &sqlparser.NumberLit{Value: "200"}}, 137 }, 138 UpdateWhereExpr: &sqlparser.BoolLit{Value: false}, 139 }, 140 }, `INSERT INTO tbl DEFAULT VALUES ON CONFLICT (x ASC, y DESC) WHERE TRUE DO UPDATE SET x = 100, (y, z) = 200 WHERE FALSE`) 141 142 AssertStatementStringer(t, &sqlparser.InsertStatement{ 143 TableName: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 144 DefaultValues: true, 145 OutputExpressions: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 146 }, `INSERT INTO tbl DEFAULT VALUES RETURNING *`) 147 148 AssertStatementStringer(t, &sqlparser.InsertStatement{ 149 TableName: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 150 DefaultValues: true, 151 OutputExpressions: &sqlparser.OutputNames{ 152 &sqlparser.ResultColumn{Expr: &sqlparser.Ident{Name: "x"}, Alias: &sqlparser.Ident{Name: "y"}}, 153 &sqlparser.ResultColumn{Expr: &sqlparser.Ident{Name: "z"}}, 154 }, 155 }, `INSERT INTO tbl DEFAULT VALUES RETURNING x AS y, z`) 156 } 157 158 func TestSelectStatement_String(t *testing.T) { 159 AssertStatementStringer(t, &sqlparser.SelectStatement{ 160 Columns: &sqlparser.OutputNames{ 161 &sqlparser.ResultColumn{Expr: &sqlparser.Ident{Name: "x"}, Alias: &sqlparser.Ident{Name: "y"}}, 162 &sqlparser.ResultColumn{Expr: &sqlparser.Ident{Name: "z"}}, 163 }, 164 }, `SELECT x AS y, z`) 165 166 AssertStatementStringer(t, &sqlparser.SelectStatement{ 167 Distinct: true, 168 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{ 169 Expr: &sqlparser.Ident{Name: "x"}, 170 }}, 171 }, `SELECT DISTINCT x`) 172 173 AssertStatementStringer(t, &sqlparser.SelectStatement{ 174 All: true, 175 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Expr: &sqlparser.Ident{Name: "x"}}}, 176 }, `SELECT ALL x`) 177 178 AssertStatementStringer(t, &sqlparser.SelectStatement{ 179 Hint: &sqlparser.Hint{Value: "HINT"}, 180 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Expr: &sqlparser.Ident{Name: "x"}}}, 181 }, `SELECT /* HINT */ x`) 182 183 AssertStatementStringer(t, &sqlparser.SelectStatement{ 184 Hint: &sqlparser.Hint{Value: "HINT"}, 185 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Expr: &sqlparser.Ident{Name: "x", Quoted: true, QuoteChar: `"`}}}, 186 }, `SELECT /* HINT */ "x"`) 187 188 AssertStatementStringer(t, &sqlparser.SelectStatement{ 189 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 190 FromItems: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 191 Condition: &sqlparser.BoolLit{Value: true}, 192 GroupingElements: []sqlparser.Expr{&sqlparser.Ident{Name: "x"}, &sqlparser.Ident{Name: "y"}}, 193 HavingCondition: &sqlparser.Ident{Name: "z"}, 194 }, `SELECT * FROM tbl WHERE TRUE GROUP BY x, y HAVING z`) 195 196 AssertStatementStringer(t, &sqlparser.SelectStatement{ 197 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 198 FromItems: &sqlparser.ParenSource{ 199 X: &sqlparser.SelectStatement{Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}}, 200 Alias: &sqlparser.Ident{Name: "tbl"}, 201 }, 202 }, `SELECT * FROM (SELECT *) AS tbl`) 203 204 AssertStatementStringer(t, &sqlparser.SelectStatement{ 205 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 206 FromItems: &sqlparser.ParenSource{ 207 X: &sqlparser.SelectStatement{Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}}, 208 }, 209 }, `SELECT * FROM (SELECT *)`) 210 211 AssertStatementStringer(t, &sqlparser.SelectStatement{ 212 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 213 Union: true, 214 Compound: &sqlparser.SelectStatement{ 215 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 216 }, 217 }, `SELECT * UNION SELECT *`) 218 219 AssertStatementStringer(t, &sqlparser.SelectStatement{ 220 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 221 Union: true, 222 UnionAll: true, 223 Compound: &sqlparser.SelectStatement{ 224 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 225 }, 226 }, `SELECT * UNION ALL SELECT *`) 227 228 AssertStatementStringer(t, &sqlparser.SelectStatement{ 229 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 230 Intersect: true, 231 Compound: &sqlparser.SelectStatement{ 232 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 233 }, 234 }, `SELECT * INTERSECT SELECT *`) 235 236 AssertStatementStringer(t, &sqlparser.SelectStatement{ 237 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 238 Except: true, 239 Compound: &sqlparser.SelectStatement{ 240 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 241 }, 242 }, `SELECT * EXCEPT SELECT *`) 243 244 AssertStatementStringer(t, &sqlparser.SelectStatement{ 245 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 246 OrderBy: []*sqlparser.OrderingTerm{ 247 {X: &sqlparser.Ident{Name: "x"}}, 248 {X: &sqlparser.Ident{Name: "y"}}, 249 }, 250 }, `SELECT * ORDER BY x, y`) 251 252 AssertStatementStringer(t, &sqlparser.SelectStatement{ 253 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 254 Limit: &sqlparser.NumberLit{Value: "1"}, 255 Offset: &sqlparser.NumberLit{Value: "2"}, 256 }, `SELECT * LIMIT 1 OFFSET 2`) 257 258 AssertStatementStringer(t, &sqlparser.SelectStatement{ 259 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 260 FromItems: &sqlparser.JoinClause{ 261 X: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "x"}}, 262 Operator: &sqlparser.JoinOperator{Comma: true}, 263 Y: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "y"}}, 264 }, 265 }, `SELECT * FROM x, y`) 266 267 AssertStatementStringer(t, &sqlparser.SelectStatement{ 268 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 269 FromItems: &sqlparser.JoinClause{ 270 X: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "x"}}, 271 Operator: &sqlparser.JoinOperator{}, 272 Y: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "y"}}, 273 Constraint: &sqlparser.OnConstraint{X: &sqlparser.BoolLit{Value: true}}, 274 }, 275 }, `SELECT * FROM x JOIN y ON TRUE`) 276 277 AssertStatementStringer(t, &sqlparser.SelectStatement{ 278 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 279 FromItems: &sqlparser.JoinClause{ 280 X: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "x"}}, 281 Operator: &sqlparser.JoinOperator{Natural: true, Inner: true}, 282 Y: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "y"}}, 283 Constraint: &sqlparser.UsingConstraint{ 284 Columns: []*sqlparser.Ident{{Name: "a"}, {Name: "b"}}, 285 }, 286 }, 287 }, `SELECT * FROM x NATURAL INNER JOIN y USING (a, b)`) 288 289 AssertStatementStringer(t, &sqlparser.SelectStatement{ 290 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 291 FromItems: &sqlparser.JoinClause{ 292 X: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "x"}}, 293 Operator: &sqlparser.JoinOperator{Left: true}, 294 Y: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "y"}}, 295 }, 296 }, `SELECT * FROM x LEFT JOIN y`) 297 298 AssertStatementStringer(t, &sqlparser.SelectStatement{ 299 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 300 FromItems: &sqlparser.JoinClause{ 301 X: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "x"}}, 302 Operator: &sqlparser.JoinOperator{Left: true, Outer: true}, 303 Y: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "y"}}, 304 }, 305 }, `SELECT * FROM x LEFT OUTER JOIN y`) 306 307 AssertStatementStringer(t, &sqlparser.SelectStatement{ 308 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 309 FromItems: &sqlparser.JoinClause{ 310 X: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "x"}}, 311 Operator: &sqlparser.JoinOperator{Cross: true}, 312 Y: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "y"}}, 313 }, 314 }, `SELECT * FROM x CROSS JOIN y`) 315 } 316 317 func TestUpdateStatement_String(t *testing.T) { 318 AssertStatementStringer(t, &sqlparser.UpdateStatement{ 319 TableName: &sqlparser.TableName{Name: &sqlparser.Ident{Name: "tbl"}}, 320 Assignments: []*sqlparser.Assignment{ 321 {Columns: []*sqlparser.Ident{{Name: "x"}}, Expr: &sqlparser.NumberLit{Value: "100"}}, 322 {Columns: []*sqlparser.Ident{{Name: "y"}}, Expr: &sqlparser.NumberLit{Value: "200"}}, 323 }, 324 Condition: &sqlparser.BoolLit{Value: true}, 325 }, `UPDATE tbl SET x = 100, y = 200 WHERE TRUE`) 326 } 327 328 func TestIdent_String(t *testing.T) { 329 AssertExprStringer(t, &sqlparser.Ident{Name: "foo"}, `foo`) 330 AssertExprStringer(t, &sqlparser.Ident{Name: "foo \" bar", Quoted: true, QuoteChar: `"`}, `"foo "" bar"`) 331 AssertExprStringer(t, &sqlparser.Ident{Name: `foo " bar`, Quoted: true, QuoteChar: "`"}, "`foo \" bar`") 332 } 333 334 func TestStringLit_String(t *testing.T) { 335 AssertExprStringer(t, &sqlparser.StringLit{Value: "foo"}, `'foo'`) 336 AssertExprStringer(t, &sqlparser.StringLit{Value: "foo ' bar"}, `'foo '' bar'`) 337 } 338 339 func TestNumberLit_String(t *testing.T) { 340 AssertExprStringer(t, &sqlparser.NumberLit{Value: "123.45"}, `123.45`) 341 } 342 343 func TestBlobLit_String(t *testing.T) { 344 AssertExprStringer(t, &sqlparser.BlobLit{Value: "0123abcd"}, `x'0123abcd'`) 345 } 346 347 func TestBoolLit_String(t *testing.T) { 348 AssertExprStringer(t, &sqlparser.BoolLit{Value: true}, `TRUE`) 349 AssertExprStringer(t, &sqlparser.BoolLit{Value: false}, `FALSE`) 350 } 351 352 func TestNullLit_String(t *testing.T) { 353 AssertExprStringer(t, &sqlparser.NullLit{}, `NULL`) 354 } 355 356 func TestBindExpr_String(t *testing.T) { 357 AssertExprStringer(t, &sqlparser.BindExpr{Name: "foo"}, `foo`) 358 } 359 360 func TestParenExpr_String(t *testing.T) { 361 AssertExprStringer(t, &sqlparser.ParenExpr{X: &sqlparser.NullLit{}}, `(NULL)`) 362 } 363 364 func TestUnaryExpr_String(t *testing.T) { 365 AssertExprStringer(t, &sqlparser.UnaryExpr{Op: sqlparser.PLUS, X: &sqlparser.NumberLit{Value: "100"}}, `+100`) 366 AssertExprStringer(t, &sqlparser.UnaryExpr{Op: sqlparser.MINUS, X: &sqlparser.NumberLit{Value: "100"}}, `-100`) 367 AssertNodeStringerPanic(t, &sqlparser.UnaryExpr{X: &sqlparser.NumberLit{Value: "100"}}, `sqlparser.UnaryExpr.String(): invalid op ILLEGAL`) 368 } 369 370 func TestBinaryExpr_String(t *testing.T) { 371 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.PLUS, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 + 2`) 372 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.MINUS, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 - 2`) 373 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.STAR, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 * 2`) 374 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.SLASH, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 / 2`) 375 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.REM, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 % 2`) 376 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.CONCAT, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 || 2`) 377 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.BETWEEN, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.Range{X: &sqlparser.NumberLit{Value: "2"}, Y: &sqlparser.NumberLit{Value: "3"}}}, `1 BETWEEN 2 AND 3`) 378 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.NOTBETWEEN, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.BinaryExpr{Op: sqlparser.AND, X: &sqlparser.NumberLit{Value: "2"}, Y: &sqlparser.NumberLit{Value: "3"}}}, `1 NOT BETWEEN 2 AND 3`) 379 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.LSHIFT, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 << 2`) 380 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.RSHIFT, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 >> 2`) 381 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.BITAND, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 & 2`) 382 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.BITOR, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 | 2`) 383 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.LT, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 < 2`) 384 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.LG, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 <> 2`) 385 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.LE, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 <= 2`) 386 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.GT, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 > 2`) 387 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.GE, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 >= 2`) 388 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.EQ, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 = 2`) 389 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.NE, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 != 2`) 390 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.IS, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 IS 2`) 391 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.ISNOT, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 IS NOT 2`) 392 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.IN, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.Exprs{Exprs: []sqlparser.Expr{&sqlparser.NumberLit{Value: "2"}}}}, `1 IN (2)`) 393 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.NOTIN, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.Exprs{Exprs: []sqlparser.Expr{&sqlparser.NumberLit{Value: "2"}}}}, `1 NOT IN (2)`) 394 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.LIKE, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 LIKE 2`) 395 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.NOTLIKE, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 NOT LIKE 2`) 396 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.GLOB, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 GLOB 2`) 397 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.NOTGLOB, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 NOT GLOB 2`) 398 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.MATCH, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 MATCH 2`) 399 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.NOTMATCH, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 NOT MATCH 2`) 400 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.REGEXP, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 REGEXP 2`) 401 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.NOTREGEXP, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 NOT REGEXP 2`) 402 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.AND, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 AND 2`) 403 AssertExprStringer(t, &sqlparser.BinaryExpr{Op: sqlparser.OR, X: &sqlparser.NumberLit{Value: "1"}, Y: &sqlparser.NumberLit{Value: "2"}}, `1 OR 2`) 404 AssertNodeStringerPanic(t, &sqlparser.BinaryExpr{}, `sqlparser.BinaryExpr.String(): invalid op ILLEGAL`) 405 } 406 407 func TestCaseExpr_String(t *testing.T) { 408 AssertExprStringer(t, &sqlparser.CaseExpr{ 409 Operand: &sqlparser.Ident{Name: "foo"}, 410 Blocks: []*sqlparser.CaseBlock{ 411 {Condition: &sqlparser.NumberLit{Value: "1"}, Body: &sqlparser.BoolLit{Value: true}}, 412 {Condition: &sqlparser.NumberLit{Value: "2"}, Body: &sqlparser.BoolLit{Value: false}}, 413 }, 414 ElseExpr: &sqlparser.NullLit{}, 415 }, `CASE foo WHEN 1 THEN TRUE WHEN 2 THEN FALSE ELSE NULL END`) 416 417 AssertExprStringer(t, &sqlparser.CaseExpr{ 418 Blocks: []*sqlparser.CaseBlock{ 419 {Condition: &sqlparser.NumberLit{Value: "1"}, Body: &sqlparser.BoolLit{Value: true}}, 420 }, 421 }, `CASE WHEN 1 THEN TRUE END`) 422 } 423 424 func TestExprs_String(t *testing.T) { 425 AssertExprStringer(t, &sqlparser.Exprs{Exprs: []sqlparser.Expr{&sqlparser.NullLit{}}}, `(NULL)`) 426 AssertExprStringer(t, &sqlparser.Exprs{Exprs: []sqlparser.Expr{&sqlparser.NullLit{}, &sqlparser.NullLit{}}}, `(NULL, NULL)`) 427 } 428 429 func TestQualifiedRef_String(t *testing.T) { 430 AssertExprStringer(t, 431 &sqlparser.QualifiedRef{ 432 Table: &sqlparser.Ident{Name: "tbl"}, 433 Column: &sqlparser.Ident{Name: "col"}, 434 }, 435 `tbl.col`, 436 ) 437 AssertExprStringer(t, 438 &sqlparser.QualifiedRef{Table: &sqlparser.Ident{Name: "tbl"}, Star: true}, 439 `tbl.*`, 440 ) 441 } 442 443 func TestCall_String(t *testing.T) { 444 AssertExprStringer(t, &sqlparser.Call{Name: &sqlparser.Ident{Name: "foo"}}, `foo()`) 445 AssertExprStringer(t, &sqlparser.Call{Name: &sqlparser.Ident{Name: "foo"}, Star: true}, `foo(*)`) 446 447 AssertExprStringer(t, &sqlparser.Call{ 448 Name: &sqlparser.Ident{Name: "foo"}, 449 Distinct: true, 450 Args: []sqlparser.Expr{ 451 &sqlparser.NullLit{}, 452 &sqlparser.NullLit{}, 453 }, 454 }, `foo(DISTINCT NULL, NULL)`) 455 456 AssertExprStringer(t, &sqlparser.Call{ 457 Name: &sqlparser.Ident{Name: "foo"}, 458 Filter: &sqlparser.FilterClause{ 459 X: &sqlparser.BoolLit{Value: true}, 460 }, 461 }, `foo() FILTER (WHERE TRUE)`) 462 } 463 464 func TestExists_String(t *testing.T) { 465 AssertExprStringer(t, &sqlparser.Exists{ 466 Select: &sqlparser.SelectStatement{ 467 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 468 }, 469 }, `EXISTS (SELECT *)`) 470 471 AssertExprStringer(t, &sqlparser.Exists{ 472 Not: true, 473 Select: &sqlparser.SelectStatement{ 474 Columns: &sqlparser.OutputNames{&sqlparser.ResultColumn{Star: true}}, 475 }, 476 }, `NOT EXISTS (SELECT *)`) 477 } 478 479 func AssertExprStringer(tb testing.TB, expr sqlparser.Expr, s string) { 480 tb.Helper() 481 if str := expr.String(); str != s { 482 tb.Fatalf("String()=%s, expected %s", str, s) 483 } else if _, err := sqlparser.NewParser(strings.NewReader(str)).ParseExpr(); err != nil { 484 tb.Fatalf("cannot parse string: %s; err=%s", str, err) 485 } 486 } 487 488 func AssertStatementStringer(tb testing.TB, stmt sqlparser.Statement, s string) { 489 tb.Helper() 490 if str := stmt.String(); str != s { 491 tb.Fatalf("String()=%s, expected %s", str, s) 492 } else if _, err := sqlparser.NewParser(strings.NewReader(str)).ParseStatement(); err != nil { 493 tb.Fatalf("cannot parse string: %s; err=%s", str, err) 494 } 495 } 496 497 func AssertNodeStringerPanic(tb testing.TB, node sqlparser.Node, msg string) { 498 tb.Helper() 499 var r interface{} 500 func() { 501 defer func() { r = recover() }() 502 _ = node.String() 503 }() 504 if r == nil { 505 tb.Fatal("expected node stringer to panic") 506 } else if r != msg { 507 tb.Fatalf("recover()=%s, want %s", r, msg) 508 } 509 } 510 511 // StripPos removes the position data from a node and its children. 512 // This function returns the root argument passed in. 513 func StripPos(root sqlparser.Node) sqlparser.Node { 514 zero := reflect.ValueOf(sqlparser.Pos{}) 515 516 _ = sqlparser.Walk(sqlparser.VisitFunc(func(node sqlparser.Node) error { 517 value := reflect.Indirect(reflect.ValueOf(node)) 518 for i := 0; i < value.NumField(); i++ { 519 if field := value.Field(i); field.Type() == zero.Type() { 520 field.Set(zero) 521 } 522 } 523 return nil 524 }), root) 525 return root 526 } 527 528 func StripExprPos(root sqlparser.Expr) sqlparser.Expr { 529 StripPos(root) 530 return root 531 }