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  }