github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/join.go (about) 1 // Copyright 2016 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 sql 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 17 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 18 ) 19 20 // joinNode is a planNode whose rows are the result of an inner or 21 // left/right outer join. 22 type joinNode struct { 23 joinType sqlbase.JoinType 24 25 // The data sources. 26 left planDataSource 27 right planDataSource 28 29 // pred represents the join predicate. 30 pred *joinPredicate 31 32 // mergeJoinOrdering is set if the left and right sides have similar ordering 33 // on the equality columns (or a subset of them). The column indices refer to 34 // equality columns: a ColIdx of i refers to left column 35 // pred.leftEqualityIndices[i] and right column pred.rightEqualityIndices[i]. 36 mergeJoinOrdering sqlbase.ColumnOrdering 37 38 reqOrdering ReqOrdering 39 40 // columns contains the metadata for the results of this node. 41 columns sqlbase.ResultColumns 42 } 43 44 func (p *planner) makeJoinNode( 45 left planDataSource, right planDataSource, pred *joinPredicate, 46 ) *joinNode { 47 n := &joinNode{ 48 left: left, 49 right: right, 50 joinType: pred.joinType, 51 pred: pred, 52 columns: pred.cols, 53 } 54 return n 55 } 56 57 func (n *joinNode) startExec(params runParams) error { 58 panic("joinNode cannot be run in local mode") 59 } 60 61 // Next implements the planNode interface. 62 func (n *joinNode) Next(params runParams) (res bool, err error) { 63 panic("joinNode cannot be run in local mode") 64 } 65 66 // Values implements the planNode interface. 67 func (n *joinNode) Values() tree.Datums { 68 panic("joinNode cannot be run in local mode") 69 } 70 71 // Close implements the planNode interface. 72 func (n *joinNode) Close(ctx context.Context) { 73 n.right.plan.Close(ctx) 74 n.left.plan.Close(ctx) 75 } 76 77 // interleavedNodes returns the ancestor on which an interleaved join is 78 // defined as well as the descendants of this ancestor which participate in 79 // the join. One of the left/right scan nodes is the ancestor and the other 80 // descendant. Nils are returned if there is no interleaved relationship. 81 // TODO(richardwu): For sibling joins, both left and right tables are 82 // "descendants" while the ancestor is some common ancestor. We will need to 83 // probably return descendants as a slice. 84 // 85 // An interleaved join has an equality on some columns of the interleave prefix. 86 // The "interleaved join ancestor" is the ancestor which contains all these 87 // join columns in its primary key. 88 // TODO(richardwu): For prefix/subset joins, this ancestor will be the furthest 89 // ancestor down the interleaved hierarchy which contains all the columns of 90 // the maximal join prefix (see maximalJoinPrefix in distsql_join.go). 91 func (n *joinNode) interleavedNodes() (ancestor *scanNode, descendant *scanNode) { 92 leftScan, leftOk := n.left.plan.(*scanNode) 93 rightScan, rightOk := n.right.plan.(*scanNode) 94 95 if !leftOk || !rightOk { 96 return nil, nil 97 } 98 99 leftAncestors := leftScan.index.Interleave.Ancestors 100 rightAncestors := rightScan.index.Interleave.Ancestors 101 102 // A join between an ancestor and descendant: the descendant of the two 103 // tables must have have more interleaved ancestors than the other, 104 // which makes the other node the potential interleaved ancestor. 105 // TODO(richardwu): The general case where we can have a join 106 // on a common ancestor's primary key requires traversing both 107 // ancestor slices. 108 if len(leftAncestors) > len(rightAncestors) { 109 ancestor = rightScan 110 descendant = leftScan 111 } else { 112 ancestor = leftScan 113 descendant = rightScan 114 } 115 116 // We check the ancestors of the potential descendant to see if any of 117 // them match the potential ancestor. 118 for _, descAncestor := range descendant.index.Interleave.Ancestors { 119 if descAncestor.TableID == ancestor.desc.ID && descAncestor.IndexID == ancestor.index.ID { 120 // If the tables are indeed interleaved, then we return 121 // the potentials as confirmed ancestor-descendant. 122 return ancestor, descendant 123 } 124 } 125 126 // We could not establish an ancestor-descendant relationship so we 127 // return nils for both. 128 return nil, nil 129 }