vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/system_tables.go (about) 1 /* 2 Copyright 2020 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 planbuilder 18 19 import ( 20 "strings" 21 22 "vitess.io/vitess/go/mysql/collations" 23 24 "vitess.io/vitess/go/vt/vterrors" 25 26 "vitess.io/vitess/go/sqltypes" 27 "vitess.io/vitess/go/vt/sqlparser" 28 "vitess.io/vitess/go/vt/vtgate/evalengine" 29 ) 30 31 type notImplementedSchemaInfoConverter struct{} 32 33 func (f *notImplementedSchemaInfoConverter) ColumnLookup(*sqlparser.ColName) (int, error) { 34 return 0, vterrors.VT12001("comparing table schema name with a column name") 35 } 36 37 func (f *notImplementedSchemaInfoConverter) CollationForExpr(sqlparser.Expr) collations.ID { 38 return collations.Unknown 39 } 40 41 func (f *notImplementedSchemaInfoConverter) DefaultCollation() collations.ID { 42 return collations.Default() 43 } 44 45 func (pb *primitiveBuilder) findSysInfoRoutingPredicates(expr sqlparser.Expr, rut *route, reservedVars *sqlparser.ReservedVars) error { 46 isTableSchema, bvName, out, err := extractInfoSchemaRoutingPredicate(expr, reservedVars) 47 if err != nil { 48 return err 49 } 50 if out == nil { 51 // we didn't find a predicate to use for routing, so we just exit early 52 return nil 53 } 54 55 if isTableSchema { 56 rut.eroute.SysTableTableSchema = append(rut.eroute.SysTableTableSchema, out) 57 } else { 58 if rut.eroute.SysTableTableName == nil { 59 rut.eroute.SysTableTableName = map[string]evalengine.Expr{} 60 } 61 rut.eroute.SysTableTableName[bvName] = out 62 } 63 64 return nil 65 } 66 67 func findOtherComparator(cmp *sqlparser.ComparisonExpr) (bool, sqlparser.Expr, sqlparser.Expr, func(arg sqlparser.Argument)) { 68 if schema, table := isTableSchemaOrName(cmp.Left); schema || table { 69 return schema, cmp.Left, cmp.Right, func(arg sqlparser.Argument) { 70 cmp.Right = arg 71 } 72 } 73 if schema, table := isTableSchemaOrName(cmp.Right); schema || table { 74 return schema, cmp.Right, cmp.Left, func(arg sqlparser.Argument) { 75 cmp.Left = arg 76 } 77 } 78 79 return false, nil, nil, nil 80 } 81 82 func isTableSchemaOrName(e sqlparser.Expr) (isTableSchema bool, isTableName bool) { 83 col, ok := e.(*sqlparser.ColName) 84 if !ok { 85 return false, false 86 } 87 return isDbNameCol(col), isTableNameCol(col) 88 } 89 90 var schemaColumns = map[string]any{ 91 "table_schema": nil, 92 "constraint_schema": nil, 93 "schema_name": nil, 94 "routine_schema": nil, 95 "specific_schema": nil, 96 "event_schema": nil, 97 "referenced_table_schema": nil, 98 "index_schema": nil, 99 "trigger_schema": nil, 100 "event_object_schema": nil, 101 } 102 103 func isDbNameCol(col *sqlparser.ColName) bool { 104 _, found := schemaColumns[col.Name.Lowered()] 105 return found 106 } 107 108 func isTableNameCol(col *sqlparser.ColName) bool { 109 return col.Name.EqualString("table_name") || col.Name.EqualString("referenced_table_name") 110 } 111 112 func extractInfoSchemaRoutingPredicate( 113 in sqlparser.Expr, 114 reservedVars *sqlparser.ReservedVars, 115 ) (isSchemaName bool, name string, evalExpr evalengine.Expr, err error) { 116 cmp, ok := in.(*sqlparser.ComparisonExpr) 117 if !ok || cmp.Operator != sqlparser.EqualOp { 118 return 119 } 120 121 isSchemaName, col, other, replaceOther := findOtherComparator(cmp) 122 if col == nil || !shouldRewrite(other) { 123 return 124 } 125 126 evalExpr, err = evalengine.Translate(other, ¬ImplementedSchemaInfoConverter{}) 127 if err != nil { 128 if strings.Contains(err.Error(), evalengine.ErrTranslateExprNotSupported) { 129 // This just means we can't rewrite this particular expression, 130 // not that we have to exit altogether 131 err = nil 132 return 133 } 134 return false, "", nil, err 135 } 136 137 if isSchemaName { 138 name = sqltypes.BvSchemaName 139 } else { 140 name = reservedVars.ReserveColName(col.(*sqlparser.ColName)) 141 } 142 replaceOther(sqlparser.NewArgument(name)) 143 return isSchemaName, name, evalExpr, nil 144 } 145 146 func shouldRewrite(e sqlparser.Expr) bool { 147 switch node := e.(type) { 148 case *sqlparser.FuncExpr: 149 // we should not rewrite database() calls against information_schema 150 return !(node.Name.EqualString("database") || node.Name.EqualString("schema")) 151 } 152 return true 153 }