github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/ordering/lookup_join.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package ordering 12 13 import ( 14 "github.com/cockroachdb/cockroach/pkg/sql/opt" 15 "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" 16 "github.com/cockroachdb/cockroach/pkg/sql/opt/props" 17 "github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical" 18 ) 19 20 func lookupOrIndexJoinCanProvideOrdering( 21 expr memo.RelExpr, required *physical.OrderingChoice, 22 ) bool { 23 // LookupJoin and IndexJoin can pass through their ordering if the ordering 24 // depends only on columns present in the input. 25 inputCols := expr.Child(0).(memo.RelExpr).Relational().OutputCols 26 return required.CanProjectCols(inputCols) 27 } 28 29 func lookupOrIndexJoinBuildChildReqOrdering( 30 parent memo.RelExpr, required *physical.OrderingChoice, childIdx int, 31 ) physical.OrderingChoice { 32 if childIdx != 0 { 33 return physical.OrderingChoice{} 34 } 35 36 // We may need to remove ordering columns that are not output by the input 37 // expression. 38 child := parent.Child(0).(memo.RelExpr) 39 res := projectOrderingToInput(child, required) 40 // It is in principle possible that the lookup join has an ON condition that 41 // forces an equality on two columns in the input. In this case we need to 42 // trim the column groups to keep the ordering valid w.r.t the child FDs 43 // (similar to Select). 44 // 45 // This case indicates that we didn't do a good job pushing down equalities 46 // (see #36219), but it should be handled correctly here nevertheless. 47 return trimColumnGroups(&res, &child.Relational().FuncDeps) 48 } 49 50 func indexJoinBuildProvided(expr memo.RelExpr, required *physical.OrderingChoice) opt.Ordering { 51 // If an index join has a requirement on some input columns, those columns 52 // must be output columns (or equivalent to them). We may still need to remap 53 // using column equivalencies. 54 indexJoin := expr.(*memo.IndexJoinExpr) 55 rel := indexJoin.Relational() 56 return remapProvided(indexJoin.Input.ProvidedPhysical().Ordering, &rel.FuncDeps, rel.OutputCols) 57 } 58 59 func lookupJoinBuildProvided(expr memo.RelExpr, required *physical.OrderingChoice) opt.Ordering { 60 lookupJoin := expr.(*memo.LookupJoinExpr) 61 childProvided := lookupJoin.Input.ProvidedPhysical().Ordering 62 63 // The lookup join includes an implicit projection (lookupJoin.Cols); some of 64 // the input columns might not be output columns so we may need to remap them. 65 // First check if we need to. 66 needsRemap := false 67 for i := range childProvided { 68 if !lookupJoin.Cols.Contains(childProvided[i].ID()) { 69 needsRemap = true 70 break 71 } 72 } 73 if !needsRemap { 74 // Fast path: we don't need to remap any columns. 75 return childProvided 76 } 77 78 // Because of the implicit projection, the FDs of the LookupJoin don't include 79 // all the columns we care about; we have to recreate the FDs of the join 80 // before the projection. These are the FDs of the input plus the equality 81 // constraints implied by the lookup join. 82 var fds props.FuncDepSet 83 fds.CopyFrom(&lookupJoin.Input.Relational().FuncDeps) 84 85 md := lookupJoin.Memo().Metadata() 86 index := md.Table(lookupJoin.Table).Index(lookupJoin.Index) 87 for i, colID := range lookupJoin.KeyCols { 88 indexColID := lookupJoin.Table.ColumnID(index.Column(i).Ordinal) 89 fds.AddEquivalency(colID, indexColID) 90 } 91 92 return remapProvided(childProvided, &fds, lookupJoin.Cols) 93 }