github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/memo/expr.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 memo
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  	"math/bits"
    17  	"sort"
    18  	"strings"
    19  
    20  	"github.com/cockroachdb/cockroach/pkg/sql/opt"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/opt/cat"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/opt/props"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    25  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    27  	"github.com/cockroachdb/cockroach/pkg/util/log"
    28  	"github.com/cockroachdb/errors"
    29  )
    30  
    31  // RelExpr is implemented by all operators tagged as Relational. Relational
    32  // expressions have a set of logical properties that describe the content and
    33  // characteristics of their behavior and results. They are stored as part of a
    34  // memo group that contains other logically equivalent expressions. Expressions
    35  // in the same memo group are linked together in a list that can be traversed
    36  // via calls to FirstExpr and NextExpr:
    37  //
    38  //      +--------------------------------------+
    39  //      |  +---------------+                   |
    40  //      |  |               |FirstExpr          |FirstExpr
    41  //      v  v               |                   |
    42  //    member #1 -------> member #2 --------> member #3 -------> nil
    43  //              NextExpr           NextExpr            NextExpr
    44  //
    45  // A relational expression's physical properties and cost are defined once it
    46  // has been optimized.
    47  type RelExpr interface {
    48  	opt.Expr
    49  
    50  	// Memo is the memo which contains this relational expression.
    51  	Memo() *Memo
    52  
    53  	// Relational is the set of logical properties that describe the content and
    54  	// characteristics of this expression's behavior and results.
    55  	Relational() *props.Relational
    56  
    57  	// RequiredPhysical is the set of required physical properties with respect to
    58  	// which this expression was optimized. Enforcers may be added to the
    59  	// expression tree to ensure the physical properties are provided.
    60  	//
    61  	// Set when optimization is complete, only for the expressions in the final
    62  	// tree.
    63  	RequiredPhysical() *physical.Required
    64  
    65  	// ProvidedPhysical is the set of provided physical properties (which must be
    66  	// compatible with the set of required physical properties).
    67  	//
    68  	// Set when optimization is complete, only for the expressions in the final
    69  	// tree.
    70  	ProvidedPhysical() *physical.Provided
    71  
    72  	// Cost is an estimate of the cost of executing this expression tree. Set
    73  	// when optimization is complete, only for the expressions in the final tree.
    74  	Cost() Cost
    75  
    76  	// FirstExpr returns the first member expression in the memo group (could be
    77  	// this expression if it happens to be first in the group). Subsequent members
    78  	// can be enumerated by then calling NextExpr. Note that enforcer operators
    79  	// are not part of this list (but do maintain a link to it).
    80  	FirstExpr() RelExpr
    81  
    82  	// NextExpr returns the next member expression in the memo group, or nil if
    83  	// there are no further members in the group.
    84  	NextExpr() RelExpr
    85  
    86  	// group returns the memo group that contains this expression and any other
    87  	// logically equivalent expressions. There is one group struct for each memo
    88  	// group that stores the properties for the group, as well as the pointer to
    89  	// the first member of the group.
    90  	group() exprGroup
    91  
    92  	// bestProps returns the instance of bestProps associated with this
    93  	// expression.
    94  	bestProps() *bestProps
    95  
    96  	// setNext sets this expression's next pointer to point to the given
    97  	// expression. setNext will panic if the next pointer has already been set.
    98  	setNext(e RelExpr)
    99  }
   100  
   101  // ScalarPropsExpr is implemented by scalar expressions which cache scalar
   102  // properties, like FiltersExpr and ProjectionsExpr. These expressions are also
   103  // tagged with the ScalarProps tag.
   104  type ScalarPropsExpr interface {
   105  	opt.ScalarExpr
   106  
   107  	// ScalarProps returns the scalar properties associated with the expression.
   108  	ScalarProps() *props.Scalar
   109  }
   110  
   111  // TrueSingleton is a global instance of TrueExpr, to avoid allocations.
   112  var TrueSingleton = &TrueExpr{}
   113  
   114  // FalseSingleton is a global instance of FalseExpr, to avoid allocations.
   115  var FalseSingleton = &FalseExpr{}
   116  
   117  // NullSingleton is a global instance of NullExpr having the Unknown type (most
   118  // common case), to avoid allocations.
   119  var NullSingleton = &NullExpr{Typ: types.Unknown}
   120  
   121  // TODO(justin): perhaps these should be auto-generated.
   122  
   123  // RankSingleton is the global instance of RankExpr.
   124  var RankSingleton = &RankExpr{}
   125  
   126  // RowNumberSingleton is the global instance of RowNumber.
   127  var RowNumberSingleton = &RowNumberExpr{}
   128  
   129  // DenseRankSingleton is the global instance of DenseRankExpr.
   130  var DenseRankSingleton = &DenseRankExpr{}
   131  
   132  // PercentRankSingleton is the global instance of PercentRankExpr.
   133  var PercentRankSingleton = &PercentRankExpr{}
   134  
   135  // CumeDistSingleton is the global instance of CumeDistExpr.
   136  var CumeDistSingleton = &CumeDistExpr{}
   137  
   138  // CountRowsSingleton maintains a global instance of CountRowsExpr, to avoid
   139  // allocations.
   140  var CountRowsSingleton = &CountRowsExpr{}
   141  
   142  // TrueFilter is a global instance of the empty FiltersExpr, used in situations
   143  // where the filter should always evaluate to true:
   144  //
   145  //   SELECT * FROM a INNER JOIN b ON True
   146  //
   147  var TrueFilter = FiltersExpr{}
   148  
   149  // EmptyTuple is a global instance of a TupleExpr that contains no elements.
   150  // While this cannot be created in SQL, it can be the created by normalizations.
   151  var EmptyTuple = &TupleExpr{Typ: types.EmptyTuple}
   152  
   153  // ScalarListWithEmptyTuple is a global instance of a ScalarListExpr containing
   154  // a TupleExpr that contains no elements. It's used when constructing an empty
   155  // ValuesExpr:
   156  //
   157  //   SELECT 1
   158  //
   159  var ScalarListWithEmptyTuple = ScalarListExpr{EmptyTuple}
   160  
   161  // EmptyGroupingPrivate is a global instance of a GroupingPrivate that has no
   162  // grouping columns and no ordering.
   163  var EmptyGroupingPrivate = &GroupingPrivate{}
   164  
   165  // EmptyJoinPrivate is a global instance of a JoinPrivate that has no fields
   166  // set.
   167  var EmptyJoinPrivate = &JoinPrivate{}
   168  
   169  // LastGroupMember returns the last member in the same memo group of the given
   170  // relational expression.
   171  func LastGroupMember(e RelExpr) RelExpr {
   172  	for {
   173  		next := e.NextExpr()
   174  		if next == nil {
   175  			return e
   176  		}
   177  		e = next
   178  	}
   179  }
   180  
   181  // IsTrue is true if the FiltersExpr always evaluates to true. This is the case
   182  // when it has zero conditions.
   183  func (n FiltersExpr) IsTrue() bool {
   184  	return len(n) == 0
   185  }
   186  
   187  // IsFalse is true if the FiltersExpr always evaluates to false. The only case
   188  // that's checked is the fully normalized case, when the list contains a single
   189  // False condition.
   190  func (n FiltersExpr) IsFalse() bool {
   191  	return len(n) == 1 && n[0].Condition.Op() == opt.FalseOp
   192  }
   193  
   194  // OuterCols returns the set of outer columns needed by any of the filter
   195  // condition expressions.
   196  func (n FiltersExpr) OuterCols(mem *Memo) opt.ColSet {
   197  	var colSet opt.ColSet
   198  	for i := range n {
   199  		colSet.UnionWith(n[i].ScalarProps().OuterCols)
   200  	}
   201  	return colSet
   202  }
   203  
   204  // Sort sorts the FilterItems in n by the IDs of the expression.
   205  func (n *FiltersExpr) Sort() {
   206  	sort.Slice(*n, func(i, j int) bool {
   207  		return (*n)[i].Condition.(opt.ScalarExpr).ID() < (*n)[j].Condition.(opt.ScalarExpr).ID()
   208  	})
   209  }
   210  
   211  // Deduplicate removes all the duplicate filters from n.
   212  func (n *FiltersExpr) Deduplicate() {
   213  	dedup := (*n)[:0]
   214  
   215  	// Only add it if it hasn't already been added.
   216  	for i, filter := range *n {
   217  		found := false
   218  		for j := i - 1; j >= 0; j-- {
   219  			previouslySeenFilter := (*n)[j]
   220  			if previouslySeenFilter.Condition == filter.Condition {
   221  				found = true
   222  				break
   223  			}
   224  		}
   225  		if !found {
   226  			dedup = append(dedup, filter)
   227  		}
   228  	}
   229  
   230  	*n = dedup
   231  }
   232  
   233  // RemoveCommonFilters removes the filters found in other from n.
   234  func (n *FiltersExpr) RemoveCommonFilters(other FiltersExpr) {
   235  	// TODO(ridwanmsharif): Faster intersection using a map
   236  	common := (*n)[:0]
   237  	for _, filter := range *n {
   238  		found := false
   239  		for _, otherFilter := range other {
   240  			if filter.Condition == otherFilter.Condition {
   241  				found = true
   242  				break
   243  			}
   244  		}
   245  		if !found {
   246  			common = append(common, filter)
   247  		}
   248  	}
   249  	*n = common
   250  }
   251  
   252  // OutputCols returns the set of columns constructed by the Aggregations
   253  // expression.
   254  func (n AggregationsExpr) OutputCols() opt.ColSet {
   255  	var colSet opt.ColSet
   256  	for i := range n {
   257  		colSet.Add(n[i].Col)
   258  	}
   259  	return colSet
   260  }
   261  
   262  // OuterCols returns the set of outer columns needed by any of the zip
   263  // expressions.
   264  func (n ZipExpr) OuterCols() opt.ColSet {
   265  	var colSet opt.ColSet
   266  	for i := range n {
   267  		colSet.UnionWith(n[i].ScalarProps().OuterCols)
   268  	}
   269  	return colSet
   270  }
   271  
   272  // OutputCols returns the set of columns constructed by the Zip expression.
   273  func (n ZipExpr) OutputCols() opt.ColSet {
   274  	var colSet opt.ColSet
   275  	for i := range n {
   276  		for _, col := range n[i].Cols {
   277  			colSet.Add(col)
   278  		}
   279  	}
   280  	return colSet
   281  }
   282  
   283  // TupleOrdinal is an ordinal index into an expression of type Tuple. It is
   284  // used by the ColumnAccess scalar expression.
   285  type TupleOrdinal uint32
   286  
   287  // ScanLimit is used for a limited table or index scan and stores the limit as
   288  // well as the desired scan direction. A value of 0 means that there is no
   289  // limit.
   290  type ScanLimit int64
   291  
   292  // MakeScanLimit initializes a ScanLimit with a number of rows and a direction.
   293  func MakeScanLimit(rowCount int64, reverse bool) ScanLimit {
   294  	if reverse {
   295  		return ScanLimit(-rowCount)
   296  	}
   297  	return ScanLimit(rowCount)
   298  }
   299  
   300  // IsSet returns true if there is a limit.
   301  func (sl ScanLimit) IsSet() bool {
   302  	return sl != 0
   303  }
   304  
   305  // RowCount returns the number of rows in the limit.
   306  func (sl ScanLimit) RowCount() int64 {
   307  	if sl.Reverse() {
   308  		return int64(-sl)
   309  	}
   310  	return int64(sl)
   311  }
   312  
   313  // Reverse returns true if the limit requires a reverse scan.
   314  func (sl ScanLimit) Reverse() bool {
   315  	return sl < 0
   316  }
   317  
   318  func (sl ScanLimit) String() string {
   319  	if sl.Reverse() {
   320  		return fmt.Sprintf("%d(rev)", -sl)
   321  	}
   322  	return fmt.Sprintf("%d", sl)
   323  }
   324  
   325  // ScanFlags stores any flags for the scan specified in the query (see
   326  // tree.IndexFlags). These flags may be consulted by transformation rules or the
   327  // coster.
   328  type ScanFlags struct {
   329  	// NoIndexJoin disallows use of non-covering indexes (index-join) for scanning
   330  	// this table.
   331  	NoIndexJoin bool
   332  
   333  	// ForceIndex forces the use of a specific index (specified in Index).
   334  	// ForceIndex and NoIndexJoin cannot both be set at the same time.
   335  	ForceIndex bool
   336  	Direction  tree.Direction
   337  	Index      int
   338  }
   339  
   340  // Empty returns true if there are no flags set.
   341  func (sf *ScanFlags) Empty() bool {
   342  	return !sf.NoIndexJoin && !sf.ForceIndex
   343  }
   344  
   345  // JoinFlags stores restrictions on the join execution method, derived from
   346  // hints for a join specified in the query (see tree.JoinTableExpr).
   347  // It is a bitfield where a bit is 1 if a certain type of join is allowed. The
   348  // value 0 is special and indicates that any join is allowed.
   349  type JoinFlags uint8
   350  
   351  // Each flag indicates if a certain type of join is allowed. The JoinFlags are
   352  // an OR of these flags, with the special case that the value 0 means anything
   353  // is allowed.
   354  const (
   355  	// AllowHashJoinStoreLeft corresponds to a hash join where the left side is
   356  	// stored into the hashtable. Note that execution can override the stored side
   357  	// if it finds that the other side is smaller (up to a certain size).
   358  	AllowHashJoinStoreLeft JoinFlags = (1 << iota)
   359  
   360  	// AllowHashJoinStoreRight corresponds to a hash join where the right side is
   361  	// stored into the hashtable. Note that execution can override the stored side
   362  	// if it finds that the other side is smaller (up to a certain size).
   363  	AllowHashJoinStoreRight
   364  
   365  	// AllowMergeJoin corresponds to a merge join.
   366  	AllowMergeJoin
   367  
   368  	// AllowLookupJoinIntoLeft corresponds to a lookup join where the lookup
   369  	// table is on the left side.
   370  	AllowLookupJoinIntoLeft
   371  
   372  	// AllowLookupJoinIntoRight corresponds to a lookup join where the lookup
   373  	// table is on the right side.
   374  	AllowLookupJoinIntoRight
   375  )
   376  
   377  var joinFlagStr = map[JoinFlags]string{
   378  	AllowHashJoinStoreLeft:   "hash join (store left side)",
   379  	AllowHashJoinStoreRight:  "hash join (store right side)",
   380  	AllowMergeJoin:           "merge join",
   381  	AllowLookupJoinIntoLeft:  "lookup join (into left side)",
   382  	AllowLookupJoinIntoRight: "lookup join (into right side)",
   383  }
   384  
   385  // Empty returns true if this is the default value (where all join types are
   386  // allowed).
   387  func (jf JoinFlags) Empty() bool {
   388  	return jf == 0
   389  }
   390  
   391  // Has returns true if the given flag is set.
   392  func (jf JoinFlags) Has(flag JoinFlags) bool {
   393  	return jf.Empty() || jf&flag != 0
   394  }
   395  
   396  func (jf JoinFlags) String() string {
   397  	if jf.Empty() {
   398  		return "no flags"
   399  	}
   400  
   401  	// Special cases for prettier results.
   402  	switch jf {
   403  	case AllowHashJoinStoreLeft | AllowHashJoinStoreRight:
   404  		return "force hash join"
   405  	case AllowLookupJoinIntoLeft | AllowLookupJoinIntoRight:
   406  		return "force lookup join"
   407  	}
   408  
   409  	var b strings.Builder
   410  	b.WriteString("force ")
   411  	first := true
   412  	for jf != 0 {
   413  		flag := JoinFlags(1 << uint8(bits.TrailingZeros8(uint8(jf))))
   414  		if !first {
   415  			b.WriteString(" or ")
   416  		}
   417  		first = false
   418  		b.WriteString(joinFlagStr[flag])
   419  		jf ^= flag
   420  	}
   421  	return b.String()
   422  }
   423  
   424  func (lj *LookupJoinExpr) initUnexportedFields(mem *Memo) {
   425  	// lookupProps are initialized as necessary by the logical props builder.
   426  }
   427  
   428  func (gj *GeoLookupJoinExpr) initUnexportedFields(mem *Memo) {
   429  	// lookupProps are initialized as necessary by the logical props builder.
   430  }
   431  
   432  func (zj *ZigzagJoinExpr) initUnexportedFields(mem *Memo) {
   433  	// leftProps and rightProps are initialized as necessary by the logical props
   434  	// builder.
   435  }
   436  
   437  // WindowFrame denotes the definition of a window frame for an individual
   438  // window function, excluding the OFFSET expressions, if present.
   439  type WindowFrame struct {
   440  	Mode           tree.WindowFrameMode
   441  	StartBoundType tree.WindowFrameBoundType
   442  	EndBoundType   tree.WindowFrameBoundType
   443  	FrameExclusion tree.WindowFrameExclusion
   444  }
   445  
   446  func (f *WindowFrame) String() string {
   447  	var bld strings.Builder
   448  	switch f.Mode {
   449  	case tree.GROUPS:
   450  		fmt.Fprintf(&bld, "groups")
   451  	case tree.ROWS:
   452  		fmt.Fprintf(&bld, "rows")
   453  	case tree.RANGE:
   454  		fmt.Fprintf(&bld, "range")
   455  	}
   456  
   457  	frameBoundName := func(b tree.WindowFrameBoundType) string {
   458  		switch b {
   459  		case tree.UnboundedFollowing, tree.UnboundedPreceding:
   460  			return "unbounded"
   461  		case tree.CurrentRow:
   462  			return "current-row"
   463  		case tree.OffsetFollowing, tree.OffsetPreceding:
   464  			return "offset"
   465  		}
   466  		panic(errors.AssertionFailedf("unexpected bound"))
   467  	}
   468  	fmt.Fprintf(&bld, " from %s to %s",
   469  		frameBoundName(f.StartBoundType),
   470  		frameBoundName(f.EndBoundType),
   471  	)
   472  	switch f.FrameExclusion {
   473  	case tree.ExcludeCurrentRow:
   474  		bld.WriteString(" exclude current row")
   475  	case tree.ExcludeGroup:
   476  		bld.WriteString(" exclude group")
   477  	case tree.ExcludeTies:
   478  		bld.WriteString(" exclude ties")
   479  	}
   480  	return bld.String()
   481  }
   482  
   483  // IsCanonical returns true if the ScanPrivate indicates an original unaltered
   484  // primary index Scan operator (i.e. unconstrained and not limited).
   485  func (s *ScanPrivate) IsCanonical() bool {
   486  	return s.Index == cat.PrimaryIndex &&
   487  		s.Constraint == nil &&
   488  		s.HardLimit == 0
   489  }
   490  
   491  // IsLocking returns true if the ScanPrivate is configured to use a row-level
   492  // locking mode. This can be the case either because the Scan is in the scope of
   493  // a SELECT .. FOR [KEY] UPDATE/SHARE clause or because the Scan was configured
   494  // as part of the row retrieval of a DELETE or UPDATE statement.
   495  func (s *ScanPrivate) IsLocking() bool {
   496  	return s.Locking != nil
   497  }
   498  
   499  // NeedResults returns true if the mutation operator can return the rows that
   500  // were mutated.
   501  func (m *MutationPrivate) NeedResults() bool {
   502  	return m.ReturnCols != nil
   503  }
   504  
   505  // IsColumnOutput returns true if the i-th ordinal column should be part of the
   506  // mutation's output columns.
   507  func (m *MutationPrivate) IsColumnOutput(i int) bool {
   508  	return i < len(m.ReturnCols) && m.ReturnCols[i] != 0
   509  }
   510  
   511  // MapToInputID maps from the ID of a returned column to the ID of the
   512  // corresponding input column that provides the value for it. If there is no
   513  // matching input column ID, MapToInputID returns 0.
   514  //
   515  // NOTE: This can only be called if the mutation operator returns rows.
   516  func (m *MutationPrivate) MapToInputID(tabColID opt.ColumnID) opt.ColumnID {
   517  	if m.ReturnCols == nil {
   518  		panic(errors.AssertionFailedf("MapToInputID cannot be called if ReturnCols is not defined"))
   519  	}
   520  	ord := m.Table.ColumnOrdinal(tabColID)
   521  	return m.ReturnCols[ord]
   522  }
   523  
   524  // MapToInputCols maps the given set of table columns to a corresponding set of
   525  // input columns using the MapToInputID function.
   526  func (m *MutationPrivate) MapToInputCols(tabCols opt.ColSet) opt.ColSet {
   527  	var inCols opt.ColSet
   528  	tabCols.ForEach(func(t opt.ColumnID) {
   529  		id := m.MapToInputID(t)
   530  		if id == 0 {
   531  			panic(errors.AssertionFailedf("could not find input column for %d", log.Safe(t)))
   532  		}
   533  		inCols.Add(id)
   534  	})
   535  	return inCols
   536  }
   537  
   538  // AddEquivTableCols adds an FD to the given set that declares an equivalence
   539  // between each table column and its corresponding input column.
   540  func (m *MutationPrivate) AddEquivTableCols(md *opt.Metadata, fdset *props.FuncDepSet) {
   541  	for i, n := 0, md.Table(m.Table).DeletableColumnCount(); i < n; i++ {
   542  		t := m.Table.ColumnID(i)
   543  		id := m.MapToInputID(t)
   544  		if id != 0 {
   545  			fdset.AddEquivalency(t, id)
   546  		}
   547  	}
   548  }
   549  
   550  // initUnexportedFields is called when a project expression is created.
   551  func (prj *ProjectExpr) initUnexportedFields(mem *Memo) {
   552  	inputProps := prj.Input.Relational()
   553  	// Determine the not-null columns.
   554  	prj.notNullCols = inputProps.NotNullCols.Copy()
   555  	for i := range prj.Projections {
   556  		item := &prj.Projections[i]
   557  		if ExprIsNeverNull(item.Element, inputProps.NotNullCols) {
   558  			prj.notNullCols.Add(item.Col)
   559  		}
   560  	}
   561  
   562  	// Determine the "internal" functional dependencies (for the union of input
   563  	// columns and synthesized columns).
   564  	prj.internalFuncDeps.CopyFrom(&inputProps.FuncDeps)
   565  	for i := range prj.Projections {
   566  		item := &prj.Projections[i]
   567  		if v, ok := item.Element.(*VariableExpr); ok && inputProps.OutputCols.Contains(v.Col) {
   568  			// Handle any column that is a direct reference to an input column. The
   569  			// optimizer sometimes constructs these in order to generate different
   570  			// column IDs; they can also show up after constant-folding e.g. an ORDER
   571  			// BY expression.
   572  			prj.internalFuncDeps.AddEquivalency(v.Col, item.Col)
   573  			continue
   574  		}
   575  
   576  		if !item.scalar.CanHaveSideEffects {
   577  			from := item.scalar.OuterCols.Intersection(inputProps.OutputCols)
   578  
   579  			// We want to set up the FD: from --> colID.
   580  			// This does not necessarily hold for "composite" types like decimals or
   581  			// collated strings. For example if d is a decimal, d::TEXT can have
   582  			// different values for equal values of d, like 1 and 1.0.
   583  			//
   584  			// We only add the FD if composite types are not involved.
   585  			//
   586  			// TODO(radu): add a whitelist of expressions/operators that are ok, like
   587  			// arithmetic.
   588  			composite := false
   589  			for i, ok := from.Next(0); ok; i, ok = from.Next(i + 1) {
   590  				typ := mem.Metadata().ColumnMeta(i).Type
   591  				if sqlbase.HasCompositeKeyEncoding(typ) {
   592  					composite = true
   593  					break
   594  				}
   595  			}
   596  			if !composite {
   597  				prj.internalFuncDeps.AddSynthesizedCol(from, item.Col)
   598  			}
   599  		}
   600  	}
   601  	prj.internalFuncDeps.MakeNotNull(prj.notNullCols)
   602  }
   603  
   604  // InternalFDs returns the functional dependencies for the set of all input
   605  // columns plus the synthesized columns.
   606  func (prj *ProjectExpr) InternalFDs() *props.FuncDepSet {
   607  	return &prj.internalFuncDeps
   608  }
   609  
   610  // ExprIsNeverNull makes a best-effort attempt to prove that the provided
   611  // scalar is always non-NULL, given the set of outer columns that are known
   612  // to be not null. This is particularly useful with check constraints.
   613  // Check constraints are satisfied when the condition evaluates to NULL,
   614  // whereas filters are not. For example consider the following check constraint:
   615  //
   616  // CHECK (col IN (1, 2, NULL))
   617  //
   618  // Any row evaluating this check constraint with any value for the column will
   619  // satisfy this check constraint, as they would evaluate to true (in the case
   620  // of 1 or 2) or NULL (in the case of everything else).
   621  func ExprIsNeverNull(e opt.ScalarExpr, notNullCols opt.ColSet) bool {
   622  	switch t := e.(type) {
   623  	case *VariableExpr:
   624  		return notNullCols.Contains(t.Col)
   625  
   626  	case *TrueExpr, *FalseExpr, *ConstExpr, *IsExpr, *IsNotExpr, *IsTupleNullExpr, *IsTupleNotNullExpr:
   627  		return true
   628  
   629  	case *NullExpr:
   630  		return false
   631  
   632  	case *TupleExpr:
   633  		// TODO(ridwanmsharif): Make this less conservative and instead update how
   634  		// IN and NOT IN behave w.r.t tuples and how IndirectionExpr works with arrays.
   635  		// Currently, the semantics of this function on Tuples are different
   636  		// as it returns whether a NULL evaluation is possible given the composition of
   637  		// the tuple. Changing this will require some additional logic in the IN cases.
   638  		for i := range t.Elems {
   639  			if !ExprIsNeverNull(t.Elems[i], notNullCols) {
   640  				return false
   641  			}
   642  		}
   643  		return true
   644  
   645  	case *InExpr, *NotInExpr:
   646  		// TODO(ridwanmsharif): If a tuple is found in either side, determine if the
   647  		// expression is nullable based on the composition of the tuples.
   648  		return ExprIsNeverNull(t.Child(0).(opt.ScalarExpr), notNullCols) &&
   649  			ExprIsNeverNull(t.Child(1).(opt.ScalarExpr), notNullCols)
   650  
   651  	case *ArrayExpr:
   652  		for i := range t.Elems {
   653  			if !ExprIsNeverNull(t.Elems[i], notNullCols) {
   654  				return false
   655  			}
   656  		}
   657  		return true
   658  
   659  	case *CaseExpr:
   660  		for i := range t.Whens {
   661  			if !ExprIsNeverNull(t.Whens[i], notNullCols) {
   662  				return false
   663  			}
   664  		}
   665  		return ExprIsNeverNull(t.Input, notNullCols) && ExprIsNeverNull(t.OrElse, notNullCols)
   666  
   667  	case *CastExpr, *NotExpr, *RangeExpr:
   668  		return ExprIsNeverNull(t.Child(0).(opt.ScalarExpr), notNullCols)
   669  
   670  	case *AndExpr, *OrExpr, *GeExpr, *GtExpr, *NeExpr, *EqExpr, *LeExpr, *LtExpr, *LikeExpr,
   671  		*NotLikeExpr, *ILikeExpr, *NotILikeExpr, *SimilarToExpr, *NotSimilarToExpr, *RegMatchExpr,
   672  		*NotRegMatchExpr, *RegIMatchExpr, *NotRegIMatchExpr, *ContainsExpr, *JsonExistsExpr,
   673  		*JsonAllExistsExpr, *JsonSomeExistsExpr, *AnyScalarExpr, *BitandExpr, *BitorExpr, *BitxorExpr,
   674  		*PlusExpr, *MinusExpr, *MultExpr, *DivExpr, *FloorDivExpr, *ModExpr, *PowExpr, *ConcatExpr,
   675  		*LShiftExpr, *RShiftExpr, *WhenExpr:
   676  		return ExprIsNeverNull(t.Child(0).(opt.ScalarExpr), notNullCols) &&
   677  			ExprIsNeverNull(t.Child(1).(opt.ScalarExpr), notNullCols)
   678  
   679  	default:
   680  		return false
   681  	}
   682  }
   683  
   684  // OutputColumnIsAlwaysNull returns true if the expression produces only NULL
   685  // values for the given column. Used to elide foreign key checks.
   686  //
   687  // This could be a logical property but we only care about simple cases (NULLs
   688  // in Projections and Values).
   689  func OutputColumnIsAlwaysNull(e RelExpr, col opt.ColumnID) bool {
   690  	isNullScalar := func(scalar opt.ScalarExpr) bool {
   691  		switch scalar.Op() {
   692  		case opt.NullOp:
   693  			return true
   694  		case opt.CastOp:
   695  			// Normally this cast should have been folded, but we want this to work
   696  			// in "build" opttester mode (disabled normalization rules).
   697  			return scalar.Child(0).Op() == opt.NullOp
   698  		default:
   699  			return false
   700  		}
   701  	}
   702  
   703  	switch e.Op() {
   704  	case opt.ProjectOp:
   705  		p := e.(*ProjectExpr)
   706  		if p.Passthrough.Contains(col) {
   707  			return OutputColumnIsAlwaysNull(p.Input, col)
   708  		}
   709  		for i := range p.Projections {
   710  			if p.Projections[i].Col == col {
   711  				return isNullScalar(p.Projections[i].Element)
   712  			}
   713  		}
   714  
   715  	case opt.ValuesOp:
   716  		v := e.(*ValuesExpr)
   717  		colOrdinal, ok := v.Cols.Find(col)
   718  		if !ok {
   719  			return false
   720  		}
   721  		for i := range v.Rows {
   722  			if !isNullScalar(v.Rows[i].(*TupleExpr).Elems[colOrdinal]) {
   723  				return false
   724  			}
   725  		}
   726  		return true
   727  	}
   728  
   729  	return false
   730  }
   731  
   732  // FKCascades stores metadata necessary for building cascading queries.
   733  type FKCascades []FKCascade
   734  
   735  // FKCascade stores metadata necessary for building a cascading query.
   736  // Cascading queries are built as needed, after the original query is executed.
   737  type FKCascade struct {
   738  	// FKName is the name of the FK constraint.
   739  	FKName string
   740  
   741  	// Builder is an object that can be used as the "optbuilder" for the cascading
   742  	// query.
   743  	Builder CascadeBuilder
   744  
   745  	// WithID identifies the buffer for the mutation input in the original
   746  	// expression tree.
   747  	WithID opt.WithID
   748  
   749  	// OldValues are column IDs from the mutation input that correspond to the
   750  	// old values of the modified rows. The list maps 1-to-1 to foreign key
   751  	// columns.
   752  	OldValues opt.ColList
   753  
   754  	// NewValues are column IDs from the mutation input that correspond to the
   755  	// new values of the modified rows. The list maps 1-to-1 to foreign key columns.
   756  	// It is empty if the mutation is a deletion.
   757  	NewValues opt.ColList
   758  }
   759  
   760  // CascadeBuilder is an interface used to construct a cascading query for a
   761  // specific FK relation. For example: if we are deleting rows from a parent
   762  // table, after deleting the rows from the parent table this interface will be
   763  // used to build the corresponding deletion in the child table.
   764  type CascadeBuilder interface {
   765  	// Build constructs a cascading query that mutates the child table. The input
   766  	// is scanned using WithScan with the given WithID; oldValues and newValues
   767  	// columns correspond 1-to-1 to foreign key columns. For deletes, newValues is
   768  	// empty.
   769  	//
   770  	// The query does not need to be built in the same memo as the original query;
   771  	// the only requirement is that the mutation input columns
   772  	// (oldValues/newValues) are valid in the metadata.
   773  	//
   774  	// The method does not mutate any captured state; it is ok to call Build
   775  	// concurrently (e.g. if the plan it originates from is cached and reused).
   776  	//
   777  	// Note: factory is always *norm.Factory; it is an interface{} only to avoid
   778  	// circular package dependencies.
   779  	Build(
   780  		ctx context.Context,
   781  		semaCtx *tree.SemaContext,
   782  		evalCtx *tree.EvalContext,
   783  		catalog cat.Catalog,
   784  		factory interface{},
   785  		binding opt.WithID,
   786  		bindingProps *props.Relational,
   787  		oldValues, newValues opt.ColList,
   788  	) (RelExpr, error)
   789  }