vitess.io/vitess@v0.16.2/go/vt/vtgate/evalengine/mysql_test.go (about) 1 /* 2 Copyright 2021 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 evalengine 18 19 import ( 20 "encoding/json" 21 "errors" 22 "fmt" 23 "os" 24 "path/filepath" 25 "strings" 26 "testing" 27 28 "vitess.io/vitess/go/mysql/collations" 29 "vitess.io/vitess/go/vt/sqlparser" 30 ) 31 32 func knownBadQuery(expr Expr) bool { 33 isNullSafeComparison := func(expr Expr) bool { 34 if cmp, ok := expr.(*ComparisonExpr); ok { 35 return cmp.Op.String() == "<=>" 36 } 37 return false 38 } 39 40 if isNullSafeComparison(expr) { 41 cmp := expr.(*ComparisonExpr) 42 return isNullSafeComparison(cmp.Left) || isNullSafeComparison(cmp.Right) 43 } 44 return false 45 } 46 47 var errKnownBadQuery = errors.New("this query is known to give bad results in MySQL") 48 49 func convert(t *testing.T, query string, simplify bool) (Expr, error) { 50 stmt, err := sqlparser.Parse(query) 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 astExpr := stmt.(*sqlparser.Select).SelectExprs[0].(*sqlparser.AliasedExpr).Expr 56 converted, err := TranslateEx(astExpr, LookupDefaultCollation(collations.CollationUtf8mb4ID), simplify) 57 if err == nil { 58 if knownBadQuery(converted) { 59 return nil, errKnownBadQuery 60 } 61 return converted, nil 62 } 63 return nil, err 64 } 65 66 func testSingle(t *testing.T, query string) (EvalResult, error) { 67 converted, err := convert(t, query, true) 68 if err == nil { 69 return EnvWithBindVars(nil, collations.CollationUtf8mb4ID).Evaluate(converted) 70 } 71 return EvalResult{}, err 72 } 73 74 func TestMySQLGolden(t *testing.T) { 75 golden, _ := filepath.Glob("integration/testdata/*.json") 76 for _, gld := range golden { 77 t.Run(filepath.Base(gld), func(t *testing.T) { 78 var testcases []struct { 79 Query string 80 Value string 81 Error string 82 } 83 84 infile, err := os.Open(gld) 85 if err != nil { 86 t.Fatal(err) 87 } 88 89 if err := json.NewDecoder(infile).Decode(&testcases); err != nil { 90 t.Fatal(err) 91 } 92 93 var ok int 94 95 for _, tc := range testcases { 96 debug := fmt.Sprintf("\n// Debug\neval, err := testSingle(t, `%s`)\nt.Logf(\"eval=%%s err=%%v\", eval.Value(), err) // want value=%q\n", tc.Query, tc.Value) 97 eval, err := testSingle(t, tc.Query) 98 if err == errKnownBadQuery { 99 ok++ 100 continue 101 } 102 if err != nil { 103 if tc.Error == "" { 104 t.Errorf("query: %s\nmysql val: %s\nvitess err: %s\n%s", tc.Query, tc.Value, err.Error(), debug) 105 } else if !strings.HasPrefix(tc.Error, err.Error()) { 106 t.Errorf("query: %s\nmysql err: %s\nvitess err: %s\n%s", tc.Query, tc.Error, err.Error(), debug) 107 } else { 108 ok++ 109 } 110 continue 111 } 112 if tc.Error != "" { 113 t.Errorf("query: %s\nmysql err: %s\nvitess val: %s\n%s", tc.Query, tc.Error, eval.Value(), debug) 114 continue 115 } 116 if eval.Value().String() != tc.Value { 117 t.Errorf("query: %s\nmysql val: %s\nvitess val: %s\n%s", tc.Query, tc.Value, eval.Value(), debug) 118 continue 119 } 120 ok++ 121 } 122 123 t.Logf("passed %d/%d tests (%.02f%%)", ok, len(testcases), 100*float64(ok)/float64(len(testcases))) 124 }) 125 } 126 } 127 128 func TestDebug1(t *testing.T) { 129 // Debu g 130 eval, err := testSingle(t, `SELECT LCASE(-999999999999999999999999)`) 131 t.Logf("eval=%s err=%v coll=%s", eval.String(), err, collations.Local().LookupByID(eval.Collation()).Name()) 132 }