vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/system_tables.go (about) 1 /* 2 Copyright 2022 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 operators 18 19 import ( 20 "strings" 21 22 "vitess.io/vitess/go/mysql/collations" 23 "vitess.io/vitess/go/sqltypes" 24 "vitess.io/vitess/go/vt/sqlparser" 25 "vitess.io/vitess/go/vt/vterrors" 26 "vitess.io/vitess/go/vt/vtgate/evalengine" 27 ) 28 29 func (r *Route) findSysInfoRoutingPredicatesGen4(predicates []sqlparser.Expr, reservedVars *sqlparser.ReservedVars) error { 30 for _, pred := range predicates { 31 isTableSchema, bvName, out, err := extractInfoSchemaRoutingPredicate(pred, reservedVars) 32 if err != nil { 33 return err 34 } 35 if out == nil { 36 // we didn't find a predicate to use for routing, continue to look for next predicate 37 continue 38 } 39 40 if r.SysTableTableName == nil { 41 r.SysTableTableName = map[string]evalengine.Expr{} 42 } 43 44 if isTableSchema { 45 r.SysTableTableSchema = append(r.SysTableTableSchema, out) 46 } else { 47 r.SysTableTableName[bvName] = out 48 } 49 } 50 return nil 51 } 52 53 func extractInfoSchemaRoutingPredicate( 54 in sqlparser.Expr, 55 reservedVars *sqlparser.ReservedVars, 56 ) (isSchemaName bool, name string, evalExpr evalengine.Expr, err error) { 57 cmp, ok := in.(*sqlparser.ComparisonExpr) 58 if !ok || cmp.Operator != sqlparser.EqualOp { 59 return 60 } 61 62 isSchemaName, col := isTableOrSchemaRouteable(cmp) 63 if col == nil || !shouldRewrite(cmp.Right) { 64 return 65 } 66 67 evalExpr, err = evalengine.Translate(cmp.Right, ¬ImplementedSchemaInfoConverter{}) 68 if err != nil { 69 if strings.Contains(err.Error(), evalengine.ErrTranslateExprNotSupported) { 70 // This just means we can't rewrite this particular expression, 71 // not that we have to exit altogether 72 err = nil 73 return 74 } 75 return 76 } 77 if isSchemaName { 78 name = sqltypes.BvSchemaName 79 } else { 80 name = reservedVars.ReserveColName(col) 81 } 82 cmp.Right = sqlparser.NewArgument(name) 83 return isSchemaName, name, evalExpr, nil 84 } 85 86 // isTableOrSchemaRouteable searches for a comparison where one side is a table or schema name column. 87 // if it finds the correct column name being used, 88 // it also makes sure that the LHS of the comparison contains the column, and the RHS the value sought after 89 func isTableOrSchemaRouteable(cmp *sqlparser.ComparisonExpr) ( 90 isSchema bool, // tells if we are dealing with a table or a schema name comparator 91 col *sqlparser.ColName, // which is the colName we are comparing against 92 ) { 93 if col, schema, table := isTableSchemaOrName(cmp.Left); schema || table { 94 return schema, col 95 } 96 if col, schema, table := isTableSchemaOrName(cmp.Right); schema || table { 97 // to make the rest of the code easier, we shuffle these around so the ColName is always on the LHS 98 cmp.Right, cmp.Left = cmp.Left, cmp.Right 99 return schema, col 100 } 101 102 return false, nil 103 } 104 105 func shouldRewrite(e sqlparser.Expr) bool { 106 switch node := e.(type) { 107 case *sqlparser.FuncExpr: 108 // we should not rewrite database() calls against information_schema 109 return !(node.Name.EqualString("database") || node.Name.EqualString("schema")) 110 } 111 return true 112 } 113 114 func isTableSchemaOrName(e sqlparser.Expr) (col *sqlparser.ColName, isTableSchema bool, isTableName bool) { 115 col, ok := e.(*sqlparser.ColName) 116 if !ok { 117 return nil, false, false 118 } 119 return col, isDbNameCol(col), isTableNameCol(col) 120 } 121 122 func isDbNameCol(col *sqlparser.ColName) bool { 123 return col.Name.EqualString("table_schema") || col.Name.EqualString("constraint_schema") || col.Name.EqualString("schema_name") || col.Name.EqualString("routine_schema") 124 } 125 126 func isTableNameCol(col *sqlparser.ColName) bool { 127 return col.Name.EqualString("table_name") 128 } 129 130 type notImplementedSchemaInfoConverter struct{} 131 132 func (f *notImplementedSchemaInfoConverter) ColumnLookup(*sqlparser.ColName) (int, error) { 133 return 0, vterrors.VT12001("comparing table schema name with a column name") 134 } 135 136 func (f *notImplementedSchemaInfoConverter) CollationForExpr(sqlparser.Expr) collations.ID { 137 return collations.Unknown 138 } 139 140 func (f *notImplementedSchemaInfoConverter) DefaultCollation() collations.ID { 141 return collations.Default() 142 }