vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/logical.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 "fmt" 21 22 "vitess.io/vitess/go/vt/sqlparser" 23 "vitess.io/vitess/go/vt/vterrors" 24 "vitess.io/vitess/go/vt/vtgate/engine" 25 "vitess.io/vitess/go/vt/vtgate/planbuilder/operators/ops" 26 "vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext" 27 "vitess.io/vitess/go/vt/vtgate/semantics" 28 ) 29 30 // createLogicalOperatorFromAST creates an operator tree that represents the input SELECT or UNION query 31 func createLogicalOperatorFromAST(ctx *plancontext.PlanningContext, selStmt sqlparser.Statement) (op ops.Operator, err error) { 32 switch node := selStmt.(type) { 33 case *sqlparser.Select: 34 op, err = createOperatorFromSelect(ctx, node) 35 case *sqlparser.Union: 36 op, err = createOperatorFromUnion(ctx, node) 37 case *sqlparser.Update: 38 op, err = createOperatorFromUpdate(ctx, node) 39 case *sqlparser.Delete: 40 op, err = createOperatorFromDelete(ctx, node) 41 default: 42 err = vterrors.VT12001(fmt.Sprintf("operator: %T", selStmt)) 43 } 44 if err != nil { 45 return nil, err 46 } 47 48 return op, nil 49 } 50 51 // createOperatorFromSelect creates an operator tree that represents the input SELECT query 52 func createOperatorFromSelect(ctx *plancontext.PlanningContext, sel *sqlparser.Select) (ops.Operator, error) { 53 subq, err := createSubqueryFromStatement(ctx, sel) 54 if err != nil { 55 return nil, err 56 } 57 op, err := crossJoin(ctx, sel.From) 58 if err != nil { 59 return nil, err 60 } 61 if sel.Where != nil { 62 exprs := sqlparser.SplitAndExpression(nil, sel.Where.Expr) 63 for _, expr := range exprs { 64 sqlparser.RemoveKeyspaceFromColName(expr) 65 op, err = op.AddPredicate(ctx, expr) 66 if err != nil { 67 return nil, err 68 } 69 addColumnEquality(ctx, expr) 70 } 71 } 72 if subq == nil { 73 return &Horizon{ 74 Source: op, 75 Select: sel, 76 }, nil 77 } 78 subq.Outer = op 79 return &Horizon{ 80 Source: subq, 81 Select: sel, 82 }, nil 83 } 84 85 func createOperatorFromUnion(ctx *plancontext.PlanningContext, node *sqlparser.Union) (ops.Operator, error) { 86 opLHS, err := createLogicalOperatorFromAST(ctx, node.Left) 87 if err != nil { 88 return nil, err 89 } 90 91 _, isRHSUnion := node.Right.(*sqlparser.Union) 92 if isRHSUnion { 93 return nil, vterrors.VT12001("nesting of UNIONs on the right-hand side") 94 } 95 opRHS, err := createLogicalOperatorFromAST(ctx, node.Right) 96 if err != nil { 97 return nil, err 98 } 99 100 union := &Union{ 101 Distinct: node.Distinct, 102 Sources: []ops.Operator{opLHS, opRHS}, 103 Ordering: node.OrderBy, 104 } 105 return &Horizon{Source: union, Select: node}, nil 106 } 107 108 func createOperatorFromUpdate(ctx *plancontext.PlanningContext, updStmt *sqlparser.Update) (ops.Operator, error) { 109 tableInfo, qt, err := createQueryTableForDML(ctx, updStmt.TableExprs[0], updStmt.Where) 110 if err != nil { 111 return nil, err 112 } 113 114 assignments := make(map[string]sqlparser.Expr) 115 for _, set := range updStmt.Exprs { 116 assignments[set.Name.Name.String()] = set.Expr 117 } 118 119 vindexTable, opCode, dest, err := buildVindexTableForDML(ctx, tableInfo, qt, "update") 120 if err != nil { 121 return nil, err 122 } 123 124 vp, cvv, ovq, err := getUpdateVindexInformation(updStmt, vindexTable, qt.ID, qt.Predicates) 125 if err != nil { 126 return nil, err 127 } 128 129 r := &Route{ 130 Source: &Update{ 131 QTable: qt, 132 VTable: vindexTable, 133 Assignments: assignments, 134 ChangedVindexValues: cvv, 135 OwnedVindexQuery: ovq, 136 AST: updStmt, 137 }, 138 RouteOpCode: opCode, 139 Keyspace: vindexTable.Keyspace, 140 VindexPreds: vp, 141 TargetDestination: dest, 142 } 143 144 for _, predicate := range qt.Predicates { 145 err := r.UpdateRoutingLogic(ctx, predicate) 146 if err != nil { 147 return nil, err 148 } 149 } 150 151 if r.RouteOpCode == engine.Scatter && updStmt.Limit != nil { 152 // TODO systay: we should probably check for other op code types - IN could also hit multiple shards (2022-04-07) 153 return nil, vterrors.VT12001("multi shard UPDATE with LIMIT") 154 } 155 156 subq, err := createSubqueryFromStatement(ctx, updStmt) 157 if err != nil { 158 return nil, err 159 } 160 if subq == nil { 161 return r, nil 162 } 163 subq.Outer = r 164 return subq, nil 165 } 166 167 func createOperatorFromDelete(ctx *plancontext.PlanningContext, deleteStmt *sqlparser.Delete) (ops.Operator, error) { 168 tableInfo, qt, err := createQueryTableForDML(ctx, deleteStmt.TableExprs[0], deleteStmt.Where) 169 if err != nil { 170 return nil, err 171 } 172 173 vindexTable, opCode, dest, err := buildVindexTableForDML(ctx, tableInfo, qt, "delete") 174 if err != nil { 175 return nil, err 176 } 177 178 del := &Delete{ 179 QTable: qt, 180 VTable: vindexTable, 181 AST: deleteStmt, 182 } 183 route := &Route{ 184 Source: del, 185 RouteOpCode: opCode, 186 Keyspace: vindexTable.Keyspace, 187 TargetDestination: dest, 188 } 189 190 if !vindexTable.Keyspace.Sharded { 191 return route, nil 192 } 193 194 primaryVindex, vindexAndPredicates, err := getVindexInformation(qt.ID, qt.Predicates, vindexTable) 195 if err != nil { 196 return nil, err 197 } 198 199 route.VindexPreds = vindexAndPredicates 200 201 var ovq string 202 if len(vindexTable.Owned) > 0 { 203 tblExpr := &sqlparser.AliasedTableExpr{Expr: sqlparser.TableName{Name: vindexTable.Name}, As: qt.Alias.As} 204 ovq = generateOwnedVindexQuery(tblExpr, deleteStmt, vindexTable, primaryVindex.Columns) 205 } 206 207 del.OwnedVindexQuery = ovq 208 209 for _, predicate := range qt.Predicates { 210 err := route.UpdateRoutingLogic(ctx, predicate) 211 if err != nil { 212 return nil, err 213 } 214 } 215 216 if route.RouteOpCode == engine.Scatter && deleteStmt.Limit != nil { 217 // TODO systay: we should probably check for other op code types - IN could also hit multiple shards (2022-04-07) 218 return nil, vterrors.VT12001("multi shard DELETE with LIMIT") 219 } 220 221 subq, err := createSubqueryFromStatement(ctx, deleteStmt) 222 if err != nil { 223 return nil, err 224 } 225 if subq == nil { 226 return route, nil 227 } 228 subq.Outer = route 229 return subq, nil 230 } 231 232 func getOperatorFromTableExpr(ctx *plancontext.PlanningContext, tableExpr sqlparser.TableExpr) (ops.Operator, error) { 233 switch tableExpr := tableExpr.(type) { 234 case *sqlparser.AliasedTableExpr: 235 return getOperatorFromAliasedTableExpr(ctx, tableExpr) 236 case *sqlparser.JoinTableExpr: 237 return getOperatorFromJoinTableExpr(ctx, tableExpr) 238 case *sqlparser.ParenTableExpr: 239 return crossJoin(ctx, tableExpr.Exprs) 240 default: 241 return nil, vterrors.VT13001(fmt.Sprintf("unable to use: %T table type", tableExpr)) 242 } 243 } 244 245 func getOperatorFromJoinTableExpr(ctx *plancontext.PlanningContext, tableExpr *sqlparser.JoinTableExpr) (ops.Operator, error) { 246 lhs, err := getOperatorFromTableExpr(ctx, tableExpr.LeftExpr) 247 if err != nil { 248 return nil, err 249 } 250 rhs, err := getOperatorFromTableExpr(ctx, tableExpr.RightExpr) 251 if err != nil { 252 return nil, err 253 } 254 255 switch tableExpr.Join { 256 case sqlparser.NormalJoinType: 257 return createInnerJoin(ctx, tableExpr, lhs, rhs) 258 case sqlparser.LeftJoinType, sqlparser.RightJoinType: 259 return createOuterJoin(tableExpr, lhs, rhs) 260 default: 261 return nil, vterrors.VT13001("unsupported: %s", tableExpr.Join.ToString()) 262 } 263 } 264 265 func getOperatorFromAliasedTableExpr(ctx *plancontext.PlanningContext, tableExpr *sqlparser.AliasedTableExpr) (ops.Operator, error) { 266 switch tbl := tableExpr.Expr.(type) { 267 case sqlparser.TableName: 268 tableID := ctx.SemTable.TableSetFor(tableExpr) 269 tableInfo, err := ctx.SemTable.TableInfoFor(tableID) 270 if err != nil { 271 return nil, err 272 } 273 274 if vt, isVindex := tableInfo.(*semantics.VindexTable); isVindex { 275 solves := ctx.SemTable.TableSetFor(tableExpr) 276 return &Vindex{ 277 Table: VindexTable{ 278 TableID: tableID, 279 Alias: tableExpr, 280 Table: tbl, 281 VTable: vt.Table.GetVindexTable(), 282 }, 283 Vindex: vt.Vindex, 284 Solved: solves, 285 }, nil 286 } 287 qg := newQueryGraph() 288 isInfSchema := tableInfo.IsInfSchema() 289 qt := &QueryTable{Alias: tableExpr, Table: tbl, ID: tableID, IsInfSchema: isInfSchema} 290 qg.Tables = append(qg.Tables, qt) 291 return qg, nil 292 case *sqlparser.DerivedTable: 293 inner, err := createLogicalOperatorFromAST(ctx, tbl.Select) 294 if err != nil { 295 return nil, err 296 } 297 if horizon, ok := inner.(*Horizon); ok { 298 inner = horizon.Source 299 } 300 301 return &Derived{Alias: tableExpr.As.String(), Source: inner, Query: tbl.Select, ColumnAliases: tableExpr.Columns}, nil 302 default: 303 return nil, vterrors.VT13001(fmt.Sprintf("unable to use: %T", tbl)) 304 } 305 } 306 307 func crossJoin(ctx *plancontext.PlanningContext, exprs sqlparser.TableExprs) (ops.Operator, error) { 308 var output ops.Operator 309 for _, tableExpr := range exprs { 310 op, err := getOperatorFromTableExpr(ctx, tableExpr) 311 if err != nil { 312 return nil, err 313 } 314 if output == nil { 315 output = op 316 } else { 317 output = createJoin(ctx, output, op) 318 } 319 } 320 return output, nil 321 } 322 323 func createQueryTableForDML(ctx *plancontext.PlanningContext, tableExpr sqlparser.TableExpr, whereClause *sqlparser.Where) (semantics.TableInfo, *QueryTable, error) { 324 alTbl, ok := tableExpr.(*sqlparser.AliasedTableExpr) 325 if !ok { 326 return nil, nil, vterrors.VT13001("expected AliasedTableExpr") 327 } 328 tblName, ok := alTbl.Expr.(sqlparser.TableName) 329 if !ok { 330 return nil, nil, vterrors.VT13001("expected TableName") 331 } 332 333 tableID := ctx.SemTable.TableSetFor(alTbl) 334 tableInfo, err := ctx.SemTable.TableInfoFor(tableID) 335 if err != nil { 336 return nil, nil, err 337 } 338 339 if tableInfo.IsInfSchema() { 340 return nil, nil, vterrors.VT12001("update information schema tables") 341 } 342 343 var predicates []sqlparser.Expr 344 if whereClause != nil { 345 predicates = sqlparser.SplitAndExpression(nil, whereClause.Expr) 346 } 347 qt := &QueryTable{ 348 ID: tableID, 349 Alias: alTbl, 350 Table: tblName, 351 Predicates: predicates, 352 IsInfSchema: false, 353 } 354 return tableInfo, qt, nil 355 } 356 357 func addColumnEquality(ctx *plancontext.PlanningContext, expr sqlparser.Expr) { 358 switch expr := expr.(type) { 359 case *sqlparser.ComparisonExpr: 360 if expr.Operator != sqlparser.EqualOp { 361 return 362 } 363 364 if left, isCol := expr.Left.(*sqlparser.ColName); isCol { 365 ctx.SemTable.AddColumnEquality(left, expr.Right) 366 } 367 if right, isCol := expr.Right.(*sqlparser.ColName); isCol { 368 ctx.SemTable.AddColumnEquality(right, expr.Left) 369 } 370 } 371 }