vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/route_planning.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 operators 18 19 import ( 20 "bytes" 21 "fmt" 22 "io" 23 24 "vitess.io/vitess/go/vt/vtgate/planbuilder/operators/rewrite" 25 26 "vitess.io/vitess/go/vt/vtgate/planbuilder/operators/ops" 27 28 "vitess.io/vitess/go/vt/key" 29 "vitess.io/vitess/go/vt/sqlparser" 30 "vitess.io/vitess/go/vt/vterrors" 31 "vitess.io/vitess/go/vt/vtgate/engine" 32 "vitess.io/vitess/go/vt/vtgate/evalengine" 33 "vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext" 34 "vitess.io/vitess/go/vt/vtgate/semantics" 35 "vitess.io/vitess/go/vt/vtgate/vindexes" 36 37 querypb "vitess.io/vitess/go/vt/proto/query" 38 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 39 ) 40 41 type ( 42 tableSetPair struct { 43 left, right semantics.TableSet 44 } 45 46 opCacheMap map[tableSetPair]ops.Operator 47 ) 48 49 // TransformToPhysical takes an operator tree and rewrites any parts that have not yet been planned as physical operators. 50 // This is where a lot of the optimisations of the query plans are done. 51 // Here we try to merge query parts into the same route primitives. At the end of this process, 52 // all the operators in the tree are guaranteed to be PhysicalOperators 53 func transformToPhysical(ctx *plancontext.PlanningContext, in ops.Operator) (ops.Operator, error) { 54 op, err := rewrite.BottomUp(in, func(operator ops.Operator) (ops.Operator, rewrite.TreeIdentity, error) { 55 switch op := operator.(type) { 56 case *QueryGraph: 57 return optimizeQueryGraph(ctx, op) 58 case *Join: 59 return optimizeJoin(ctx, op) 60 case *Derived: 61 return optimizeDerived(ctx, op) 62 case *SubQuery: 63 return optimizeSubQuery(ctx, op) 64 case *Filter: 65 return optimizeFilter(op) 66 default: 67 return operator, rewrite.SameTree, nil 68 } 69 }) 70 71 if err != nil { 72 return nil, err 73 } 74 75 err = rewrite.Visit(op, func(op ops.Operator) error { 76 if _, isPhys := op.(ops.PhysicalOperator); !isPhys { 77 return vterrors.VT13001(fmt.Sprintf("failed to transform %T to a physical operator", op)) 78 } 79 return nil 80 }) 81 if err != nil { 82 return nil, err 83 } 84 85 return Compact(ctx, op) 86 } 87 88 func optimizeFilter(op *Filter) (ops.Operator, rewrite.TreeIdentity, error) { 89 if route, ok := op.Source.(*Route); ok { 90 // let's push the filter into the route 91 op.Source = route.Source 92 route.Source = op 93 return route, rewrite.NewTree, nil 94 } 95 96 return op, rewrite.SameTree, nil 97 } 98 99 func optimizeDerived(ctx *plancontext.PlanningContext, op *Derived) (ops.Operator, rewrite.TreeIdentity, error) { 100 innerRoute, ok := op.Source.(*Route) 101 if !ok { 102 return op, rewrite.SameTree, nil 103 } 104 105 if !(innerRoute.RouteOpCode == engine.EqualUnique) && !op.IsMergeable(ctx) { 106 // no need to check anything if we are sure that we will only hit a single shard 107 return op, rewrite.SameTree, nil 108 } 109 110 op.Source = innerRoute.Source 111 innerRoute.Source = op 112 113 return innerRoute, rewrite.NewTree, nil 114 } 115 116 func optimizeJoin(ctx *plancontext.PlanningContext, op *Join) (ops.Operator, rewrite.TreeIdentity, error) { 117 join, err := mergeOrJoin(ctx, op.LHS, op.RHS, sqlparser.SplitAndExpression(nil, op.Predicate), !op.LeftJoin) 118 if err != nil { 119 return nil, rewrite.SameTree, err 120 } 121 return join, rewrite.NewTree, nil 122 } 123 124 func optimizeQueryGraph(ctx *plancontext.PlanningContext, op *QueryGraph) (result ops.Operator, changed rewrite.TreeIdentity, err error) { 125 changed = rewrite.NewTree 126 switch { 127 case ctx.PlannerVersion == querypb.ExecuteOptions_Gen4Left2Right: 128 result, err = leftToRightSolve(ctx, op) 129 default: 130 result, err = greedySolve(ctx, op) 131 } 132 133 unresolved := op.UnsolvedPredicates(ctx.SemTable) 134 if len(unresolved) > 0 { 135 // if we have any predicates that none of the joins or tables took care of, 136 // we add a single filter on top, so we don't lose it. This is used for sub-query planning 137 result = newFilter(result, ctx.SemTable.AndExpressions(unresolved...)) 138 } 139 140 return 141 } 142 143 func buildVindexTableForDML(ctx *plancontext.PlanningContext, tableInfo semantics.TableInfo, table *QueryTable, dmlType string) (*vindexes.Table, engine.Opcode, key.Destination, error) { 144 vindexTable := tableInfo.GetVindexTable() 145 opCode := engine.Unsharded 146 if vindexTable.Keyspace.Sharded { 147 opCode = engine.Scatter 148 } 149 150 if vindexTable.Source != nil { 151 sourceTable, _, _, _, _, err := ctx.VSchema.FindTableOrVindex(vindexTable.Source.TableName) 152 if err != nil { 153 return nil, 0, nil, err 154 } 155 vindexTable = sourceTable 156 } 157 158 var dest key.Destination 159 var typ topodatapb.TabletType 160 var err error 161 tblName, ok := table.Alias.Expr.(sqlparser.TableName) 162 if ok { 163 _, _, _, typ, dest, err = ctx.VSchema.FindTableOrVindex(tblName) 164 if err != nil { 165 return nil, 0, nil, err 166 } 167 if dest != nil { 168 if typ != topodatapb.TabletType_PRIMARY { 169 return nil, 0, nil, vterrors.VT09002(dmlType) 170 } 171 // we are dealing with an explicitly targeted UPDATE 172 opCode = engine.ByDestination 173 } 174 } 175 return vindexTable, opCode, dest, nil 176 } 177 178 func generateOwnedVindexQuery(tblExpr sqlparser.TableExpr, del *sqlparser.Delete, table *vindexes.Table, ksidCols []sqlparser.IdentifierCI) string { 179 buf := sqlparser.NewTrackedBuffer(nil) 180 for idx, col := range ksidCols { 181 if idx == 0 { 182 buf.Myprintf("select %v", col) 183 } else { 184 buf.Myprintf(", %v", col) 185 } 186 } 187 for _, cv := range table.Owned { 188 for _, column := range cv.Columns { 189 buf.Myprintf(", %v", column) 190 } 191 } 192 buf.Myprintf(" from %v%v%v%v for update", tblExpr, del.Where, del.OrderBy, del.Limit) 193 return buf.String() 194 } 195 196 func getUpdateVindexInformation( 197 updStmt *sqlparser.Update, 198 vindexTable *vindexes.Table, 199 tableID semantics.TableSet, 200 predicates []sqlparser.Expr, 201 ) ([]*VindexPlusPredicates, map[string]*engine.VindexValues, string, error) { 202 if !vindexTable.Keyspace.Sharded { 203 return nil, nil, "", nil 204 } 205 206 primaryVindex, vindexAndPredicates, err := getVindexInformation(tableID, predicates, vindexTable) 207 if err != nil { 208 return nil, nil, "", err 209 } 210 211 changedVindexValues, ownedVindexQuery, err := buildChangedVindexesValues(updStmt, vindexTable, primaryVindex.Columns) 212 if err != nil { 213 return nil, nil, "", err 214 } 215 return vindexAndPredicates, changedVindexValues, ownedVindexQuery, nil 216 } 217 218 /* 219 The greedy planner will plan a query by finding first finding the best route plan for every table. 220 Then, iteratively, it finds the cheapest join that can be produced between the remaining plans, 221 and removes the two inputs to this cheapest plan and instead adds the join. 222 As an optimization, it first only considers joining tables that have predicates defined between them 223 */ 224 func greedySolve(ctx *plancontext.PlanningContext, qg *QueryGraph) (ops.Operator, error) { 225 routeOps, err := seedOperatorList(ctx, qg) 226 planCache := opCacheMap{} 227 if err != nil { 228 return nil, err 229 } 230 231 op, err := mergeRoutes(ctx, qg, routeOps, planCache, false) 232 if err != nil { 233 return nil, err 234 } 235 return op, nil 236 } 237 238 func leftToRightSolve(ctx *plancontext.PlanningContext, qg *QueryGraph) (ops.Operator, error) { 239 plans, err := seedOperatorList(ctx, qg) 240 if err != nil { 241 return nil, err 242 } 243 244 var acc ops.Operator 245 for _, plan := range plans { 246 if acc == nil { 247 acc = plan 248 continue 249 } 250 joinPredicates := qg.GetPredicates(TableID(acc), TableID(plan)) 251 acc, err = mergeOrJoin(ctx, acc, plan, joinPredicates, true) 252 if err != nil { 253 return nil, err 254 } 255 } 256 257 return acc, nil 258 } 259 260 // seedOperatorList returns a route for each table in the qg 261 func seedOperatorList(ctx *plancontext.PlanningContext, qg *QueryGraph) ([]ops.Operator, error) { 262 plans := make([]ops.Operator, len(qg.Tables)) 263 264 // we start by seeding the table with the single routes 265 for i, table := range qg.Tables { 266 solves := ctx.SemTable.TableSetFor(table.Alias) 267 plan, err := createRoute(ctx, table, solves) 268 if err != nil { 269 return nil, err 270 } 271 if qg.NoDeps != nil { 272 plan, err = plan.AddPredicate(ctx, qg.NoDeps) 273 if err != nil { 274 return nil, err 275 } 276 } 277 plans[i] = plan 278 } 279 return plans, nil 280 } 281 282 func createInfSchemaRoute(ctx *plancontext.PlanningContext, table *QueryTable) (ops.Operator, error) { 283 ks, err := ctx.VSchema.AnyKeyspace() 284 if err != nil { 285 return nil, err 286 } 287 r := &Route{ 288 RouteOpCode: engine.DBA, 289 Source: &Table{ 290 QTable: table, 291 VTable: &vindexes.Table{ 292 Name: table.Table.Name, 293 Keyspace: ks, 294 }, 295 }, 296 Keyspace: ks, 297 } 298 for _, pred := range table.Predicates { 299 isTableSchema, bvName, out, err := extractInfoSchemaRoutingPredicate(pred, ctx.ReservedVars) 300 if err != nil { 301 return nil, err 302 } 303 if out == nil { 304 // we didn't find a predicate to use for routing, continue to look for next predicate 305 continue 306 } 307 308 if isTableSchema { 309 r.SysTableTableSchema = append(r.SysTableTableSchema, out) 310 } else { 311 if r.SysTableTableName == nil { 312 r.SysTableTableName = map[string]evalengine.Expr{} 313 } 314 r.SysTableTableName[bvName] = out 315 } 316 } 317 return r, nil 318 } 319 320 func mergeRoutes(ctx *plancontext.PlanningContext, qg *QueryGraph, physicalOps []ops.Operator, planCache opCacheMap, crossJoinsOK bool) (ops.Operator, error) { 321 if len(physicalOps) == 0 { 322 return nil, nil 323 } 324 for len(physicalOps) > 1 { 325 bestTree, lIdx, rIdx, err := findBestJoin(ctx, qg, physicalOps, planCache, crossJoinsOK) 326 if err != nil { 327 return nil, err 328 } 329 // if we found a plan, we'll replace the two plans that were joined with the join plan created 330 if bestTree != nil { 331 // we remove one plan, and replace the other 332 if rIdx > lIdx { 333 physicalOps = removeAt(physicalOps, rIdx) 334 physicalOps = removeAt(physicalOps, lIdx) 335 } else { 336 physicalOps = removeAt(physicalOps, lIdx) 337 physicalOps = removeAt(physicalOps, rIdx) 338 } 339 physicalOps = append(physicalOps, bestTree) 340 } else { 341 if crossJoinsOK { 342 return nil, vterrors.VT13001("should not happen: we should be able to merge cross joins") 343 } 344 // we will only fail to find a join plan when there are only cross joins left 345 // when that happens, we switch over to allow cross joins as well. 346 // this way we prioritize joining physicalOps with predicates first 347 crossJoinsOK = true 348 } 349 } 350 return physicalOps[0], nil 351 } 352 353 func removeAt(plans []ops.Operator, idx int) []ops.Operator { 354 return append(plans[:idx], plans[idx+1:]...) 355 } 356 357 func findBestJoin( 358 ctx *plancontext.PlanningContext, 359 qg *QueryGraph, 360 plans []ops.Operator, 361 planCache opCacheMap, 362 crossJoinsOK bool, 363 ) (bestPlan ops.Operator, lIdx int, rIdx int, err error) { 364 for i, lhs := range plans { 365 for j, rhs := range plans { 366 if i == j { 367 continue 368 } 369 joinPredicates := qg.GetPredicates(TableID(lhs), TableID(rhs)) 370 if len(joinPredicates) == 0 && !crossJoinsOK { 371 // if there are no predicates joining the two tables, 372 // creating a join between them would produce a 373 // cartesian product, which is almost always a bad idea 374 continue 375 } 376 plan, err := getJoinFor(ctx, planCache, lhs, rhs, joinPredicates) 377 if err != nil { 378 return nil, 0, 0, err 379 } 380 if bestPlan == nil || CostOf(plan) < CostOf(bestPlan) { 381 bestPlan = plan 382 // remember which plans we based on, so we can remove them later 383 lIdx = i 384 rIdx = j 385 } 386 } 387 } 388 return bestPlan, lIdx, rIdx, nil 389 } 390 391 func getJoinFor(ctx *plancontext.PlanningContext, cm opCacheMap, lhs, rhs ops.Operator, joinPredicates []sqlparser.Expr) (ops.Operator, error) { 392 solves := tableSetPair{left: TableID(lhs), right: TableID(rhs)} 393 cachedPlan := cm[solves] 394 if cachedPlan != nil { 395 return cachedPlan, nil 396 } 397 398 join, err := mergeOrJoin(ctx, lhs, rhs, joinPredicates, true) 399 if err != nil { 400 return nil, err 401 } 402 cm[solves] = join 403 return join, nil 404 } 405 406 // requiresSwitchingSides will return true if any of the operators with the root from the given operator tree 407 // is of the type that should not be on the RHS of a join 408 func requiresSwitchingSides(ctx *plancontext.PlanningContext, op ops.Operator) bool { 409 required := false 410 411 _ = rewrite.Visit(op, func(current ops.Operator) error { 412 derived, isDerived := current.(*Derived) 413 414 if isDerived && !derived.IsMergeable(ctx) { 415 required = true 416 return io.EOF 417 } 418 419 return nil 420 }) 421 422 return required 423 } 424 425 func mergeOrJoin(ctx *plancontext.PlanningContext, lhs, rhs ops.Operator, joinPredicates []sqlparser.Expr, inner bool) (ops.Operator, error) { 426 merger := func(a, b *Route) (*Route, error) { 427 return createRouteOperatorForJoin(ctx, a, b, joinPredicates, inner) 428 } 429 430 newPlan, _ := tryMerge(ctx, lhs, rhs, joinPredicates, merger) 431 if newPlan != nil { 432 return newPlan, nil 433 } 434 435 if len(joinPredicates) > 0 && requiresSwitchingSides(ctx, rhs) { 436 if !inner { 437 return nil, vterrors.VT12001("LEFT JOIN with derived tables") 438 } 439 440 if requiresSwitchingSides(ctx, lhs) { 441 return nil, vterrors.VT12001("JOIN between derived tables") 442 } 443 444 join := NewApplyJoin(Clone(rhs), Clone(lhs), nil, !inner) 445 return pushJoinPredicates(ctx, joinPredicates, join) 446 } 447 448 join := NewApplyJoin(Clone(lhs), Clone(rhs), nil, !inner) 449 return pushJoinPredicates(ctx, joinPredicates, join) 450 } 451 452 func createRouteOperatorForJoin(ctx *plancontext.PlanningContext, aRoute, bRoute *Route, joinPredicates []sqlparser.Expr, inner bool) (*Route, error) { 453 // append system table names from both the routes. 454 sysTableName := aRoute.SysTableTableName 455 if sysTableName == nil { 456 sysTableName = bRoute.SysTableTableName 457 } else { 458 for k, v := range bRoute.SysTableTableName { 459 sysTableName[k] = v 460 } 461 } 462 463 join := NewApplyJoin(aRoute.Source, bRoute.Source, ctx.SemTable.AndExpressions(joinPredicates...), !inner) 464 r := &Route{ 465 RouteOpCode: aRoute.RouteOpCode, 466 Keyspace: aRoute.Keyspace, 467 VindexPreds: append(aRoute.VindexPreds, bRoute.VindexPreds...), 468 SysTableTableSchema: append(aRoute.SysTableTableSchema, bRoute.SysTableTableSchema...), 469 SeenPredicates: append(aRoute.SeenPredicates, bRoute.SeenPredicates...), 470 SysTableTableName: sysTableName, 471 Source: join, 472 MergedWith: []*Route{bRoute}, 473 } 474 475 if aRoute.SelectedVindex() == bRoute.SelectedVindex() { 476 r.Selected = aRoute.Selected 477 } 478 479 return r, nil 480 } 481 482 type mergeFunc func(a, b *Route) (*Route, error) 483 484 func operatorsToRoutes(a, b ops.Operator) (*Route, *Route) { 485 aRoute, ok := a.(*Route) 486 if !ok { 487 return nil, nil 488 } 489 bRoute, ok := b.(*Route) 490 if !ok { 491 return nil, nil 492 } 493 return aRoute, bRoute 494 } 495 496 func tryMerge( 497 ctx *plancontext.PlanningContext, 498 a, b ops.Operator, 499 joinPredicates []sqlparser.Expr, 500 merger mergeFunc, 501 ) (ops.Operator, error) { 502 aRoute, bRoute := operatorsToRoutes(Clone(a), Clone(b)) 503 if aRoute == nil || bRoute == nil { 504 return nil, nil 505 } 506 507 sameKeyspace := aRoute.Keyspace == bRoute.Keyspace 508 509 if !sameKeyspace { 510 if altARoute := aRoute.AlternateInKeyspace(bRoute.Keyspace); altARoute != nil { 511 aRoute = altARoute 512 sameKeyspace = true 513 } else if altBRoute := bRoute.AlternateInKeyspace(aRoute.Keyspace); altBRoute != nil { 514 bRoute = altBRoute 515 sameKeyspace = true 516 } 517 } 518 519 if sameKeyspace || (isDualTable(aRoute) || isDualTable(bRoute)) { 520 tree, err := tryMergeReferenceTable(aRoute, bRoute, merger) 521 if tree != nil || err != nil { 522 return tree, err 523 } 524 } 525 526 switch aRoute.RouteOpCode { 527 case engine.Unsharded, engine.DBA: 528 if aRoute.RouteOpCode == bRoute.RouteOpCode && sameKeyspace { 529 return merger(aRoute, bRoute) 530 } 531 case engine.EqualUnique: 532 // If the two routes fully match, they can be merged together. 533 if bRoute.RouteOpCode == engine.EqualUnique { 534 aVdx := aRoute.SelectedVindex() 535 bVdx := bRoute.SelectedVindex() 536 aExpr := aRoute.VindexExpressions() 537 bExpr := bRoute.VindexExpressions() 538 if aVdx == bVdx && gen4ValuesEqual(ctx, aExpr, bExpr) { 539 return merger(aRoute, bRoute) 540 } 541 } 542 543 // If the two routes don't match, fall through to the next case and see if we 544 // can merge via join predicates instead. 545 fallthrough 546 547 case engine.Scatter, engine.IN, engine.None: 548 if len(joinPredicates) == 0 { 549 // If we are doing two Scatters, we have to make sure that the 550 // joins are on the correct vindex to allow them to be merged 551 // no join predicates - no vindex 552 return nil, nil 553 } 554 555 if !sameKeyspace { 556 return nil, vterrors.VT12001("cross-shard correlated subquery") 557 } 558 559 canMerge := canMergeOnFilters(ctx, aRoute, bRoute, joinPredicates) 560 if !canMerge { 561 return nil, nil 562 } 563 r, err := merger(aRoute, bRoute) 564 if err != nil { 565 return nil, err 566 } 567 568 // If we have a `None` route opcode, we want to keep it - 569 // we only try to find a better Vindex for other route opcodes 570 if aRoute.RouteOpCode != engine.None { 571 r.PickBestAvailableVindex() 572 } 573 574 return r, nil 575 } 576 return nil, nil 577 } 578 579 func isDualTable(route *Route) bool { 580 sources := leaves(route) 581 if len(sources) > 1 { 582 return false 583 } 584 src, ok := sources[0].(*Table) 585 if !ok { 586 return false 587 } 588 return src.VTable.Name.String() == "dual" && src.QTable.Table.Qualifier.IsEmpty() 589 } 590 591 func leaves(op ops.Operator) (sources []ops.Operator) { 592 switch op := op.(type) { 593 // these are the leaves 594 case *Table: 595 return []ops.Operator{op} 596 // physical 597 case *ApplyJoin: 598 return []ops.Operator{op.LHS, op.RHS} 599 case *Filter: 600 return []ops.Operator{op.Source} 601 case *Route: 602 return []ops.Operator{op.Source} 603 } 604 605 panic(fmt.Sprintf("leaves unknown type: %T", op)) 606 } 607 608 func tryMergeReferenceTable(aRoute, bRoute *Route, merger mergeFunc) (*Route, error) { 609 var ( 610 // if either side is a reference table, we can just merge it and use the opcode of the other side 611 opCode engine.Opcode 612 vindex *VindexOption 613 ks *vindexes.Keyspace 614 ) 615 616 switch { 617 case aRoute.RouteOpCode == engine.Reference: 618 vindex = bRoute.Selected 619 opCode = bRoute.RouteOpCode 620 ks = bRoute.Keyspace 621 case bRoute.RouteOpCode == engine.Reference: 622 vindex = aRoute.Selected 623 opCode = aRoute.RouteOpCode 624 ks = aRoute.Keyspace 625 default: 626 return nil, nil 627 } 628 629 r, err := merger(aRoute, bRoute) 630 if err != nil { 631 return nil, err 632 } 633 r.RouteOpCode = opCode 634 r.Selected = vindex 635 r.Keyspace = ks 636 return r, nil 637 } 638 639 func canMergeOnFilter(ctx *plancontext.PlanningContext, a, b *Route, predicate sqlparser.Expr) bool { 640 comparison, ok := predicate.(*sqlparser.ComparisonExpr) 641 if !ok { 642 return false 643 } 644 if comparison.Operator != sqlparser.EqualOp { 645 return false 646 } 647 left := comparison.Left 648 right := comparison.Right 649 650 lVindex := findColumnVindex(ctx, a, left) 651 if lVindex == nil { 652 left, right = right, left 653 lVindex = findColumnVindex(ctx, a, left) 654 } 655 if lVindex == nil || !lVindex.IsUnique() { 656 return false 657 } 658 rVindex := findColumnVindex(ctx, b, right) 659 if rVindex == nil { 660 return false 661 } 662 return rVindex == lVindex 663 } 664 665 func findColumnVindex(ctx *plancontext.PlanningContext, a ops.Operator, exp sqlparser.Expr) vindexes.SingleColumn { 666 _, isCol := exp.(*sqlparser.ColName) 667 if !isCol { 668 return nil 669 } 670 671 exp = unwrapDerivedTables(ctx, exp) 672 if exp == nil { 673 return nil 674 } 675 676 var singCol vindexes.SingleColumn 677 678 // for each equality expression that exp has with other column name, we check if it 679 // can be solved by any table in our routeTree. If an equality expression can be solved, 680 // we check if the equality expression and our table share the same vindex, if they do: 681 // the method will return the associated vindexes.SingleColumn. 682 for _, expr := range ctx.SemTable.GetExprAndEqualities(exp) { 683 col, isCol := expr.(*sqlparser.ColName) 684 if !isCol { 685 continue 686 } 687 688 deps := ctx.SemTable.RecursiveDeps(expr) 689 690 _ = rewrite.Visit(a, func(rel ops.Operator) error { 691 to, isTableOp := rel.(TableIDIntroducer) 692 if !isTableOp { 693 return nil 694 } 695 id := to.Introduces() 696 if deps.IsSolvedBy(id) { 697 tableInfo, err := ctx.SemTable.TableInfoFor(id) 698 if err != nil { 699 // an error here is OK, we just can't ask this operator about its column vindexes 700 return nil 701 } 702 vtable := tableInfo.GetVindexTable() 703 if vtable != nil { 704 for _, vindex := range vtable.ColumnVindexes { 705 sC, isSingle := vindex.Vindex.(vindexes.SingleColumn) 706 if isSingle && vindex.Columns[0].Equal(col.Name) { 707 singCol = sC 708 return io.EOF 709 } 710 } 711 } 712 } 713 return nil 714 }) 715 if singCol != nil { 716 return singCol 717 } 718 } 719 720 return singCol 721 } 722 723 // unwrapDerivedTables we want to find the bottom layer of derived tables 724 // nolint 725 func unwrapDerivedTables(ctx *plancontext.PlanningContext, exp sqlparser.Expr) sqlparser.Expr { 726 for { 727 // if we are dealing with derived tables in derived tables 728 tbl, err := ctx.SemTable.TableInfoForExpr(exp) 729 if err != nil { 730 return nil 731 } 732 _, ok := tbl.(*semantics.DerivedTable) 733 if !ok { 734 break 735 } 736 737 exp = semantics.RewriteDerivedTableExpression(exp, tbl) 738 exp = getColName(exp) 739 if exp == nil { 740 return nil 741 } 742 } 743 return exp 744 } 745 746 func getColName(exp sqlparser.Expr) *sqlparser.ColName { 747 switch exp := exp.(type) { 748 case *sqlparser.ColName: 749 return exp 750 case *sqlparser.Max, *sqlparser.Min: 751 aggr := exp.(sqlparser.AggrFunc).GetArg() 752 colName, ok := aggr.(*sqlparser.ColName) 753 if ok { 754 return colName 755 } 756 } 757 // for any other expression than a column, or the extremum of a column, we return nil 758 return nil 759 } 760 761 func canMergeOnFilters(ctx *plancontext.PlanningContext, a, b *Route, joinPredicates []sqlparser.Expr) bool { 762 for _, predicate := range joinPredicates { 763 for _, expr := range sqlparser.SplitAndExpression(nil, predicate) { 764 if canMergeOnFilter(ctx, a, b, expr) { 765 return true 766 } 767 } 768 } 769 return false 770 } 771 772 func gen4ValuesEqual(ctx *plancontext.PlanningContext, a, b []sqlparser.Expr) bool { 773 if len(a) != len(b) { 774 return false 775 } 776 777 // TODO: check SemTable's columnEqualities for better plan 778 779 for i, aExpr := range a { 780 bExpr := b[i] 781 if !gen4ValEqual(ctx, aExpr, bExpr) { 782 return false 783 } 784 } 785 return true 786 } 787 788 func gen4ValEqual(ctx *plancontext.PlanningContext, a, b sqlparser.Expr) bool { 789 switch a := a.(type) { 790 case *sqlparser.ColName: 791 if b, ok := b.(*sqlparser.ColName); ok { 792 if !a.Name.Equal(b.Name) { 793 return false 794 } 795 796 return ctx.SemTable.DirectDeps(a) == ctx.SemTable.DirectDeps(b) 797 } 798 case sqlparser.Argument: 799 b, ok := b.(sqlparser.Argument) 800 if !ok { 801 return false 802 } 803 return a == b 804 case *sqlparser.Literal: 805 b, ok := b.(*sqlparser.Literal) 806 if !ok { 807 return false 808 } 809 switch a.Type { 810 case sqlparser.StrVal: 811 switch b.Type { 812 case sqlparser.StrVal: 813 return a.Val == b.Val 814 case sqlparser.HexVal: 815 return hexEqual(b, a) 816 } 817 case sqlparser.HexVal: 818 return hexEqual(a, b) 819 case sqlparser.IntVal: 820 if b.Type == (sqlparser.IntVal) { 821 return a.Val == b.Val 822 } 823 } 824 } 825 return false 826 } 827 828 func hexEqual(a, b *sqlparser.Literal) bool { 829 v, err := a.HexDecode() 830 if err != nil { 831 return false 832 } 833 switch b.Type { 834 case sqlparser.StrVal: 835 return bytes.Equal(v, b.Bytes()) 836 case sqlparser.HexVal: 837 v2, err := b.HexDecode() 838 if err != nil { 839 return false 840 } 841 return bytes.Equal(v, v2) 842 } 843 return false 844 } 845 846 func pushJoinPredicates(ctx *plancontext.PlanningContext, exprs []sqlparser.Expr, op *ApplyJoin) (ops.Operator, error) { 847 if len(exprs) == 0 { 848 return op, nil 849 } 850 851 for _, expr := range exprs { 852 _, err := AddPredicate(op, ctx, expr, true, newFilter) 853 if err != nil { 854 return nil, err 855 } 856 } 857 858 return op, nil 859 }