github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/join_predicate.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  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    15  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    16  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    17  	"github.com/cockroachdb/cockroach/pkg/util"
    18  )
    19  
    20  // joinPredicate implements the predicate logic for joins.
    21  type joinPredicate struct {
    22  	// This struct must be allocated on the heap and its location stay
    23  	// stable after construction because it implements
    24  	// IndexedVarContainer and the IndexedVar objects in sub-expressions
    25  	// will link to it by reference after checkRenderStar / analyzeExpr.
    26  	// Enforce this using NoCopy.
    27  	_ util.NoCopy
    28  
    29  	joinType sqlbase.JoinType
    30  
    31  	// numLeft/RightCols are the number of columns in the left and right
    32  	// operands.
    33  	numLeftCols, numRightCols int
    34  
    35  	// left/rightEqualityIndices give the position of equality columns
    36  	// on the left and right input row arrays, respectively.
    37  	// Only columns with the same left and right value types can be equality
    38  	// columns.
    39  	leftEqualityIndices  []int
    40  	rightEqualityIndices []int
    41  
    42  	// The list of names for the columns listed in leftEqualityIndices.
    43  	// Used mainly for pretty-printing.
    44  	leftColNames tree.NameList
    45  	// The list of names for the columns listed in rightEqualityIndices.
    46  	// Used mainly for pretty-printing.
    47  	rightColNames tree.NameList
    48  
    49  	// For ON predicates or joins with an added filter expression,
    50  	// we need an IndexedVarHelper, the DataSourceInfo, a row buffer
    51  	// and the expression itself.
    52  	iVarHelper tree.IndexedVarHelper
    53  	curRow     tree.Datums
    54  	// The ON condition that needs to be evaluated (in addition to the
    55  	// equality columns).
    56  	onCond tree.TypedExpr
    57  
    58  	leftCols  sqlbase.ResultColumns
    59  	rightCols sqlbase.ResultColumns
    60  	cols      sqlbase.ResultColumns
    61  
    62  	// If set, the left equality columns form a key in the left input. Used as a
    63  	// hint for optimizing execution.
    64  	leftEqKey bool
    65  	// If set, the right equality columns form a key in the right input. Used as a
    66  	// hint for optimizing execution.
    67  	rightEqKey bool
    68  }
    69  
    70  // makePredicate constructs a joinPredicate object for joins. The equality
    71  // columns / on condition must be initialized separately.
    72  func makePredicate(
    73  	joinType sqlbase.JoinType, left, right sqlbase.ResultColumns,
    74  ) (*joinPredicate, error) {
    75  	// For anti and semi joins, the right columns are omitted from the output (but
    76  	// they must be available internally for the ON condition evaluation).
    77  	omitRightColumns := joinType == sqlbase.LeftSemiJoin || joinType == sqlbase.LeftAntiJoin
    78  
    79  	// Prepare the metadata for the result columns.
    80  	// The structure of the join data source results is like this:
    81  	// - all the left columns,
    82  	// - then all the right columns (except for anti/semi join).
    83  	columns := make(sqlbase.ResultColumns, 0, len(left)+len(right))
    84  	columns = append(columns, left...)
    85  	if !omitRightColumns {
    86  		columns = append(columns, right...)
    87  	}
    88  
    89  	pred := &joinPredicate{
    90  		joinType:     joinType,
    91  		numLeftCols:  len(left),
    92  		numRightCols: len(right),
    93  		leftCols:     left,
    94  		rightCols:    right,
    95  		cols:         columns,
    96  	}
    97  	// We must initialize the indexed var helper in all cases, even when
    98  	// there is no on condition, so that getNeededColumns() does not get
    99  	// confused.
   100  	pred.curRow = make(tree.Datums, len(left)+len(right))
   101  	pred.iVarHelper = tree.MakeIndexedVarHelper(pred, len(pred.curRow))
   102  
   103  	return pred, nil
   104  }
   105  
   106  // IndexedVarEval implements the tree.IndexedVarContainer interface.
   107  func (p *joinPredicate) IndexedVarEval(idx int, ctx *tree.EvalContext) (tree.Datum, error) {
   108  	return p.curRow[idx].Eval(ctx)
   109  }
   110  
   111  // IndexedVarResolvedType implements the tree.IndexedVarContainer interface.
   112  func (p *joinPredicate) IndexedVarResolvedType(idx int) *types.T {
   113  	if idx < p.numLeftCols {
   114  		return p.leftCols[idx].Typ
   115  	}
   116  	return p.rightCols[idx-p.numLeftCols].Typ
   117  }
   118  
   119  // IndexedVarNodeFormatter implements the tree.IndexedVarContainer interface.
   120  func (p *joinPredicate) IndexedVarNodeFormatter(idx int) tree.NodeFormatter {
   121  	if idx < p.numLeftCols {
   122  		return p.leftCols.NodeFormatter(idx)
   123  	}
   124  	return p.rightCols.NodeFormatter(idx - p.numLeftCols)
   125  }
   126  
   127  // eval for joinPredicate runs the on condition across the columns that do
   128  // not participate in the equality (the equality columns are checked
   129  // in the join algorithm already).
   130  // Returns true if there is no on condition or the on condition accepts the
   131  // row.
   132  func (p *joinPredicate) eval(ctx *tree.EvalContext, leftRow, rightRow tree.Datums) (bool, error) {
   133  	if p.onCond != nil {
   134  		copy(p.curRow[:len(leftRow)], leftRow)
   135  		copy(p.curRow[len(leftRow):], rightRow)
   136  		ctx.PushIVarContainer(p.iVarHelper.Container())
   137  		pred, err := sqlbase.RunFilter(p.onCond, ctx)
   138  		ctx.PopIVarContainer()
   139  		return pred, err
   140  	}
   141  	return true, nil
   142  }
   143  
   144  // prepareRow prepares the output row by combining values from the
   145  // input data sources.
   146  func (p *joinPredicate) prepareRow(result, leftRow, rightRow tree.Datums) {
   147  	copy(result[:len(leftRow)], leftRow)
   148  	copy(result[len(leftRow):], rightRow)
   149  }