vitess.io/vitess@v0.16.2/go/vt/sqlparser/precedence_test.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package sqlparser 18 19 import ( 20 "fmt" 21 "testing" 22 "time" 23 24 "github.com/stretchr/testify/assert" 25 "github.com/stretchr/testify/require" 26 ) 27 28 func readable(node Expr) string { 29 switch node := node.(type) { 30 case *OrExpr: 31 return fmt.Sprintf("(%s or %s)", readable(node.Left), readable(node.Right)) 32 case *AndExpr: 33 return fmt.Sprintf("(%s and %s)", readable(node.Left), readable(node.Right)) 34 case *XorExpr: 35 return fmt.Sprintf("(%s xor %s)", readable(node.Left), readable(node.Right)) 36 case *BinaryExpr: 37 return fmt.Sprintf("(%s %s %s)", readable(node.Left), node.Operator.ToString(), readable(node.Right)) 38 case *IsExpr: 39 return fmt.Sprintf("(%s %s)", readable(node.Left), node.Right.ToString()) 40 default: 41 return String(node) 42 } 43 } 44 45 func TestAndOrPrecedence(t *testing.T) { 46 validSQL := []struct { 47 input string 48 output string 49 }{{ 50 input: "select * from a where a=b and c=d or e=f", 51 output: "((a = b and c = d) or e = f)", 52 }, { 53 input: "select * from a where a=b or c=d and e=f", 54 output: "(a = b or (c = d and e = f))", 55 }} 56 for _, tcase := range validSQL { 57 tree, err := Parse(tcase.input) 58 if err != nil { 59 t.Error(err) 60 continue 61 } 62 expr := readable(tree.(*Select).Where.Expr) 63 if expr != tcase.output { 64 t.Errorf("Parse: \n%s, want: \n%s", expr, tcase.output) 65 } 66 } 67 } 68 69 func TestNotInSubqueryPrecedence(t *testing.T) { 70 tree, err := Parse("select * from a where not id in (select 42)") 71 require.NoError(t, err) 72 not := tree.(*Select).Where.Expr.(*NotExpr) 73 cmp := not.Expr.(*ComparisonExpr) 74 subq := cmp.Right.(*Subquery) 75 76 extracted := &ExtractedSubquery{ 77 Original: cmp, 78 OpCode: 1, 79 Subquery: subq, 80 OtherSide: cmp.Left, 81 } 82 extracted.SetArgName("arg1") 83 extracted.SetHasValuesArg("has_values1") 84 85 not.Expr = extracted 86 output := readable(not) 87 assert.Equal(t, "not (:has_values1 = 1 and id in ::arg1)", output) 88 } 89 90 func TestSubqueryPrecedence(t *testing.T) { 91 tree, err := Parse("select * from a where id in (select 42) and false") 92 require.NoError(t, err) 93 where := tree.(*Select).Where 94 andExpr := where.Expr.(*AndExpr) 95 cmp := andExpr.Left.(*ComparisonExpr) 96 subq := cmp.Right.(*Subquery) 97 98 extracted := &ExtractedSubquery{ 99 Original: andExpr.Left, 100 OpCode: 1, 101 Subquery: subq, 102 OtherSide: cmp.Left, 103 } 104 extracted.SetArgName("arg1") 105 extracted.SetHasValuesArg("has_values1") 106 107 andExpr.Left = extracted 108 output := readable(extracted) 109 assert.Equal(t, ":has_values1 = 1 and id in ::arg1", output) 110 } 111 112 func TestPlusStarPrecedence(t *testing.T) { 113 validSQL := []struct { 114 input string 115 output string 116 }{{ 117 input: "select 1+2*3 from a", 118 output: "(1 + (2 * 3))", 119 }, { 120 input: "select 1*2+3 from a", 121 output: "((1 * 2) + 3)", 122 }} 123 for _, tcase := range validSQL { 124 tree, err := Parse(tcase.input) 125 if err != nil { 126 t.Error(err) 127 continue 128 } 129 expr := readable(tree.(*Select).SelectExprs[0].(*AliasedExpr).Expr) 130 if expr != tcase.output { 131 t.Errorf("Parse: \n%s, want: \n%s", expr, tcase.output) 132 } 133 } 134 } 135 136 func TestIsPrecedence(t *testing.T) { 137 validSQL := []struct { 138 input string 139 output string 140 }{{ 141 input: "select * from a where a+b is true", 142 output: "((a + b) is true)", 143 }, { 144 input: "select * from a where a=1 and b=2 is true", 145 output: "(a = 1 and (b = 2 is true))", 146 }, { 147 input: "select * from a where (a=1 and b=2) is true", 148 output: "((a = 1 and b = 2) is true)", 149 }} 150 for _, tcase := range validSQL { 151 tree, err := Parse(tcase.input) 152 if err != nil { 153 t.Error(err) 154 continue 155 } 156 expr := readable(tree.(*Select).Where.Expr) 157 if expr != tcase.output { 158 t.Errorf("Parse: \n%s, want: \n%s", expr, tcase.output) 159 } 160 } 161 } 162 163 func TestParens(t *testing.T) { 164 tests := []struct { 165 in, expected string 166 }{ 167 {in: "12", expected: "12"}, 168 {in: "(12)", expected: "12"}, 169 {in: "((12))", expected: "12"}, 170 {in: "((true) and (false))", expected: "true and false"}, 171 {in: "((true) and (false)) and (true)", expected: "true and false and true"}, 172 {in: "((true) and (false))", expected: "true and false"}, 173 {in: "a=b and (c=d or e=f)", expected: "a = b and (c = d or e = f)"}, 174 {in: "(a=b and c=d) or e=f", expected: "a = b and c = d or e = f"}, 175 {in: "a & (b | c)", expected: "a & (b | c)"}, 176 {in: "(a & b) | c", expected: "a & b | c"}, 177 {in: "not (a=b and c=d)", expected: "not (a = b and c = d)"}, 178 {in: "not (a=b) and c=d", expected: "not a = b and c = d"}, 179 {in: "(not (a=b)) and c=d", expected: "not a = b and c = d"}, 180 {in: "-(12)", expected: "-12"}, 181 {in: "-(12 + 12)", expected: "-(12 + 12)"}, 182 {in: "(1 > 2) and (1 = b)", expected: "1 > 2 and 1 = b"}, 183 {in: "(a / b) + c", expected: "a / b + c"}, 184 {in: "a / (b + c)", expected: "a / (b + c)"}, 185 {in: "(1,2,3)", expected: "(1, 2, 3)"}, 186 {in: "(a) between (5) and (7)", expected: "a between 5 and 7"}, 187 {in: "(a | b) between (5) and (7)", expected: "a | b between 5 and 7"}, 188 {in: "(a and b) between (5) and (7)", expected: "(a and b) between 5 and 7"}, 189 {in: "(true is true) is null", expected: "(true is true) is null"}, 190 {in: "3 * (100 div 3)", expected: "3 * (100 div 3)"}, 191 {in: "100 div 2 div 2", expected: "100 div 2 div 2"}, 192 {in: "100 div (2 div 2)", expected: "100 div (2 div 2)"}, 193 {in: "(100 div 2) div 2", expected: "100 div 2 div 2"}, 194 {in: "((((((1000))))))", expected: "1000"}, 195 {in: "100 - (50 + 10)", expected: "100 - (50 + 10)"}, 196 {in: "100 - 50 + 10", expected: "100 - 50 + 10"}, 197 {in: "true and (true and true)", expected: "true and (true and true)"}, 198 {in: "10 - 2 - 1", expected: "10 - 2 - 1"}, 199 {in: "(10 - 2) - 1", expected: "10 - 2 - 1"}, 200 {in: "10 - (2 - 1)", expected: "10 - (2 - 1)"}, 201 {in: "0 <=> (1 and 0)", expected: "0 <=> (1 and 0)"}, 202 } 203 204 for _, tc := range tests { 205 t.Run(tc.in, func(t *testing.T) { 206 stmt, err := Parse("select " + tc.in) 207 require.NoError(t, err) 208 out := String(stmt) 209 require.Equal(t, "select "+tc.expected+" from dual", out) 210 }) 211 } 212 } 213 214 func TestRandom(t *testing.T) { 215 // The purpose of this test is to find discrepancies between Format and parsing. If for example our precedence rules are not consistent between the two, this test should find it. 216 // The idea is to generate random queries, and pass them through the parser and then the unparser, and one more time. The result of the first unparse should be the same as the second result. 217 seed := time.Now().UnixNano() 218 fmt.Println(fmt.Sprintf("seed is %d", seed)) // nolint 219 g := newGenerator(seed, 5) 220 endBy := time.Now().Add(1 * time.Second) 221 222 for { 223 if time.Now().After(endBy) { 224 break 225 } 226 // Given a random expression 227 randomExpr := g.expression() 228 inputQ := "select " + String(randomExpr) + " from t" 229 230 // When it's parsed and unparsed 231 parsedInput, err := Parse(inputQ) 232 require.NoError(t, err, inputQ) 233 234 // Then the unparsing should be the same as the input query 235 outputOfParseResult := String(parsedInput) 236 require.Equal(t, outputOfParseResult, inputQ) 237 } 238 }