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  }