github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/norm/select_funcs.go (about)

     1  // Copyright 2020 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 norm
    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/sqlbase"
    17  	"github.com/cockroachdb/cockroach/pkg/util"
    18  	"github.com/cockroachdb/errors"
    19  )
    20  
    21  // CanMapOnSetOp determines whether the filter can be mapped to either
    22  // side of a set operator.
    23  func (c *CustomFuncs) CanMapOnSetOp(src *memo.FiltersItem) bool {
    24  	filterProps := src.ScalarProps()
    25  	for i, ok := filterProps.OuterCols.Next(0); ok; i, ok = filterProps.OuterCols.Next(i + 1) {
    26  		colType := c.f.Metadata().ColumnMeta(i).Type
    27  		if sqlbase.HasCompositeKeyEncoding(colType) {
    28  			return false
    29  		}
    30  	}
    31  	return !filterProps.HasCorrelatedSubquery
    32  }
    33  
    34  // MapSetOpFilterLeft maps the filter onto the left expression by replacing
    35  // the out columns of the filter with the appropriate corresponding columns in
    36  // the left side of the operator.
    37  // Useful for pushing filters to relations the set operation is composed of.
    38  func (c *CustomFuncs) MapSetOpFilterLeft(
    39  	filter *memo.FiltersItem, set *memo.SetPrivate,
    40  ) opt.ScalarExpr {
    41  	colMap := makeMapFromColLists(set.OutCols, set.LeftCols)
    42  	return c.MapFiltersItemCols(filter, colMap)
    43  }
    44  
    45  // MapSetOpFilterRight maps the filter onto the right expression by replacing
    46  // the out columns of the filter with the appropriate corresponding columns in
    47  // the right side of the operator.
    48  // Useful for pushing filters to relations the set operation is composed of.
    49  func (c *CustomFuncs) MapSetOpFilterRight(
    50  	filter *memo.FiltersItem, set *memo.SetPrivate,
    51  ) opt.ScalarExpr {
    52  	colMap := makeMapFromColLists(set.OutCols, set.RightCols)
    53  	return c.MapFiltersItemCols(filter, colMap)
    54  }
    55  
    56  // makeMapFromColLists maps each column ID in src to a column ID in dst. The
    57  // columns IDs are mapped based on their relative positions in the column lists,
    58  // e.g. the third item in src maps to the third item in dst. The lists must be
    59  // of equal length.
    60  func makeMapFromColLists(src opt.ColList, dst opt.ColList) util.FastIntMap {
    61  	if len(src) != len(dst) {
    62  		panic(errors.AssertionFailedf("src and dst must have the same length, src: %v, dst: %v", src, dst))
    63  	}
    64  
    65  	var colMap util.FastIntMap
    66  	for colIndex, outColID := range src {
    67  		colMap.Set(int(outColID), int(dst[colIndex]))
    68  	}
    69  	return colMap
    70  }
    71  
    72  // MapFiltersItemCols maps filter expressions by replacing occurrences of
    73  // the keys of colMap with the corresponding values. Outer columns are not
    74  // replaced.
    75  func (c *CustomFuncs) MapFiltersItemCols(
    76  	filter *memo.FiltersItem, colMap util.FastIntMap,
    77  ) opt.ScalarExpr {
    78  	// Recursively walk the scalar sub-tree looking for references to columns
    79  	// that need to be replaced and then replace them appropriately.
    80  	var replace ReplaceFunc
    81  	replace = func(nd opt.Expr) opt.Expr {
    82  		switch t := nd.(type) {
    83  		case *memo.VariableExpr:
    84  			dstCol, ok := colMap.Get(int(t.Col))
    85  			if !ok {
    86  				// It is not part of the output cols so no replacement required.
    87  				return nd
    88  			}
    89  			return c.f.ConstructVariable(opt.ColumnID(dstCol))
    90  		}
    91  		return c.f.Replace(nd, replace)
    92  	}
    93  
    94  	return replace(filter.Condition).(opt.ScalarExpr)
    95  }
    96  
    97  // GroupingAndConstCols returns the grouping columns and ConstAgg columns (for
    98  // which the input and output column IDs match). A filter on these columns can
    99  // be pushed through a GroupBy.
   100  func (c *CustomFuncs) GroupingAndConstCols(
   101  	grouping *memo.GroupingPrivate, aggs memo.AggregationsExpr,
   102  ) opt.ColSet {
   103  	result := grouping.GroupingCols.Copy()
   104  
   105  	// Add any ConstAgg columns.
   106  	for i := range aggs {
   107  		item := &aggs[i]
   108  		if constAgg, ok := item.Agg.(*memo.ConstAggExpr); ok {
   109  			// Verify that the input and output column IDs match.
   110  			if item.Col == constAgg.Input.(*memo.VariableExpr).Col {
   111  				result.Add(item.Col)
   112  			}
   113  		}
   114  	}
   115  	return result
   116  }
   117  
   118  // CanConsolidateFilters returns true if there are at least two different
   119  // filter conditions that contain the same variable, where the conditions
   120  // have tight constraints and contain a single variable. For example,
   121  // CanConsolidateFilters returns true with filters {x > 5, x < 10}, but false
   122  // with {x > 5, y < 10} and {x > 5, x = y}.
   123  func (c *CustomFuncs) CanConsolidateFilters(filters memo.FiltersExpr) bool {
   124  	var seen opt.ColSet
   125  	for i := range filters {
   126  		if col, ok := c.canConsolidateFilter(&filters[i]); ok {
   127  			if seen.Contains(col) {
   128  				return true
   129  			}
   130  			seen.Add(col)
   131  		}
   132  	}
   133  	return false
   134  }
   135  
   136  // canConsolidateFilter determines whether a filter condition can be
   137  // consolidated. Filters can be consolidated if they have tight constraints
   138  // and contain a single variable. Examples of such filters include x < 5 and
   139  // x IS NULL. If the filter can be consolidated, canConsolidateFilter returns
   140  // the column ID of the variable and ok=true. Otherwise, canConsolidateFilter
   141  // returns ok=false.
   142  func (c *CustomFuncs) canConsolidateFilter(filter *memo.FiltersItem) (col opt.ColumnID, ok bool) {
   143  	if !filter.ScalarProps().TightConstraints {
   144  		return 0, false
   145  	}
   146  
   147  	outerCols := c.OuterCols(filter)
   148  	if outerCols.Len() != 1 {
   149  		return 0, false
   150  	}
   151  
   152  	col, _ = outerCols.Next(0)
   153  	return col, true
   154  }
   155  
   156  // ConsolidateFilters consolidates filter conditions that contain the same
   157  // variable, where the conditions have tight constraints and contain a single
   158  // variable. The consolidated filters are combined with a tree of nested
   159  // And operations, and wrapped with a Range expression.
   160  //
   161  // See the ConsolidateSelectFilters rule for more details about why this is
   162  // necessary.
   163  func (c *CustomFuncs) ConsolidateFilters(filters memo.FiltersExpr) memo.FiltersExpr {
   164  	// First find the columns that have filter conditions that can be
   165  	// consolidated.
   166  	var seen, seenTwice opt.ColSet
   167  	for i := range filters {
   168  		if col, ok := c.canConsolidateFilter(&filters[i]); ok {
   169  			if seen.Contains(col) {
   170  				seenTwice.Add(col)
   171  			} else {
   172  				seen.Add(col)
   173  			}
   174  		}
   175  	}
   176  
   177  	newFilters := make(memo.FiltersExpr, seenTwice.Len(), len(filters)-seenTwice.Len())
   178  
   179  	// newFilters contains an empty item for each of the new Range expressions
   180  	// that will be created below. Fill in rangeMap to track which column
   181  	// corresponds to each item.
   182  	var rangeMap util.FastIntMap
   183  	i := 0
   184  	for col, ok := seenTwice.Next(0); ok; col, ok = seenTwice.Next(col + 1) {
   185  		rangeMap.Set(int(col), i)
   186  		i++
   187  	}
   188  
   189  	// Iterate through each existing filter condition, and either consolidate it
   190  	// into one of the new Range expressions or add it unchanged to the new
   191  	// filters.
   192  	for i := range filters {
   193  		if col, ok := c.canConsolidateFilter(&filters[i]); ok && seenTwice.Contains(col) {
   194  			// This is one of the filter conditions that can be consolidated into a
   195  			// Range.
   196  			cond := filters[i].Condition
   197  			switch t := cond.(type) {
   198  			case *memo.RangeExpr:
   199  				// If it is already a range expression, unwrap it.
   200  				cond = t.And
   201  			}
   202  			rangeIdx, _ := rangeMap.Get(int(col))
   203  			rangeItem := &newFilters[rangeIdx]
   204  			if rangeItem.Condition == nil {
   205  				// This is the first condition.
   206  				rangeItem.Condition = cond
   207  			} else {
   208  				// Build a left-deep tree of ANDs sorted by ID.
   209  				rangeItem.Condition = c.mergeSortedAnds(rangeItem.Condition, cond)
   210  			}
   211  		} else {
   212  			newFilters = append(newFilters, filters[i])
   213  		}
   214  	}
   215  
   216  	// Construct each of the new Range operators now that we have built the
   217  	// conjunctions.
   218  	for i, n := 0, seenTwice.Len(); i < n; i++ {
   219  		newFilters[i] = c.f.ConstructFiltersItem(c.f.ConstructRange(newFilters[i].Condition))
   220  	}
   221  
   222  	return newFilters
   223  }
   224  
   225  // mergeSortedAnds merges two left-deep trees of nested AndExprs sorted by ID.
   226  // Returns a single sorted, left-deep tree of nested AndExprs, with any
   227  // duplicate expressions eliminated.
   228  func (c *CustomFuncs) mergeSortedAnds(left, right opt.ScalarExpr) opt.ScalarExpr {
   229  	if right == nil {
   230  		return left
   231  	}
   232  	if left == nil {
   233  		return right
   234  	}
   235  
   236  	// Since both trees are left-deep, perform a merge-sort from right to left.
   237  	nextLeft := left
   238  	nextRight := right
   239  	var remainingLeft, remainingRight opt.ScalarExpr
   240  	if and, ok := left.(*memo.AndExpr); ok {
   241  		remainingLeft = and.Left
   242  		nextLeft = and.Right
   243  	}
   244  	if and, ok := right.(*memo.AndExpr); ok {
   245  		remainingRight = and.Left
   246  		nextRight = and.Right
   247  	}
   248  
   249  	if nextLeft.ID() == nextRight.ID() {
   250  		// Eliminate duplicates.
   251  		return c.mergeSortedAnds(left, remainingRight)
   252  	}
   253  	if nextLeft.ID() < nextRight.ID() {
   254  		return c.f.ConstructAnd(c.mergeSortedAnds(left, remainingRight), nextRight)
   255  	}
   256  	return c.f.ConstructAnd(c.mergeSortedAnds(remainingLeft, right), nextLeft)
   257  }
   258  
   259  // AreFiltersSorted determines whether the expressions in a FiltersExpr are
   260  // ordered by their expression IDs.
   261  func (c *CustomFuncs) AreFiltersSorted(f memo.FiltersExpr) bool {
   262  	for i, n := 0, f.ChildCount(); i < n-1; i++ {
   263  		if f.Child(i).Child(0).(opt.ScalarExpr).ID() > f.Child(i+1).Child(0).(opt.ScalarExpr).ID() {
   264  			return false
   265  		}
   266  	}
   267  	return true
   268  }
   269  
   270  // SortFilters sorts a filter list by the IDs of the expressions. This has the
   271  // effect of canonicalizing FiltersExprs which may have the same filters, but
   272  // in a different order.
   273  func (c *CustomFuncs) SortFilters(f memo.FiltersExpr) memo.FiltersExpr {
   274  	result := make(memo.FiltersExpr, len(f))
   275  	for i, n := 0, f.ChildCount(); i < n; i++ {
   276  		fi := f.Child(i).(*memo.FiltersItem)
   277  		result[i] = *fi
   278  	}
   279  	result.Sort()
   280  	return result
   281  }
   282  
   283  // SimplifyFilters removes True operands from a FiltersExpr, and normalizes any
   284  // False or Null condition to a single False condition. Null values map to False
   285  // because FiltersExpr are only used by Select and Join, both of which treat a
   286  // Null filter conjunct exactly as if it were false.
   287  //
   288  // SimplifyFilters also "flattens" any And operator child by merging its
   289  // conditions into a new FiltersExpr list. If, after simplification, no operands
   290  // remain, then SimplifyFilters returns an empty FiltersExpr.
   291  //
   292  // This method assumes that the NormalizeNestedAnds rule has already run and
   293  // ensured a left deep And tree. If not (maybe because it's a testing scenario),
   294  // then this rule may rematch, but it should still make forward progress).
   295  func (c *CustomFuncs) SimplifyFilters(filters memo.FiltersExpr) memo.FiltersExpr {
   296  	// Start by counting the number of conjuncts that will be flattened so that
   297  	// the capacity of the FiltersExpr list can be determined.
   298  	cnt := 0
   299  	for _, item := range filters {
   300  		cnt++
   301  		condition := item.Condition
   302  		for condition.Op() == opt.AndOp {
   303  			cnt++
   304  			condition = condition.(*memo.AndExpr).Left
   305  		}
   306  	}
   307  
   308  	// Construct new filter list.
   309  	newFilters := make(memo.FiltersExpr, 0, cnt)
   310  	for _, item := range filters {
   311  		var ok bool
   312  		if newFilters, ok = c.addConjuncts(item.Condition, newFilters); !ok {
   313  			return memo.FiltersExpr{c.f.ConstructFiltersItem(memo.FalseSingleton)}
   314  		}
   315  	}
   316  
   317  	return newFilters
   318  }
   319  
   320  // IsUnsimplifiableOr returns true if this is an OR where neither side is
   321  // NULL. SimplifyFilters simplifies ORs with a NULL on one side to its other
   322  // side. However other ORs don't simplify. This function is used to prevent
   323  // infinite recursion during ConstructFilterItem in SimplifyFilters. This
   324  // function must be kept in sync with SimplifyFilters.
   325  func (c *CustomFuncs) IsUnsimplifiableOr(item *memo.FiltersItem) bool {
   326  	or, ok := item.Condition.(*memo.OrExpr)
   327  	if !ok {
   328  		return false
   329  	}
   330  	return or.Left.Op() != opt.NullOp && or.Right.Op() != opt.NullOp
   331  }
   332  
   333  // addConjuncts recursively walks a scalar expression as long as it continues to
   334  // find nested And operators. It adds any conjuncts (ignoring True operators) to
   335  // the given FiltersExpr and returns true. If it finds a False or Null operator,
   336  // it propagates a false return value all the up the call stack, and
   337  // SimplifyFilters maps that to a FiltersExpr that is always false.
   338  func (c *CustomFuncs) addConjuncts(
   339  	scalar opt.ScalarExpr, filters memo.FiltersExpr,
   340  ) (_ memo.FiltersExpr, ok bool) {
   341  	switch t := scalar.(type) {
   342  	case *memo.AndExpr:
   343  		var ok bool
   344  		if filters, ok = c.addConjuncts(t.Left, filters); !ok {
   345  			return nil, false
   346  		}
   347  		return c.addConjuncts(t.Right, filters)
   348  
   349  	case *memo.FalseExpr, *memo.NullExpr:
   350  		// Filters expression evaluates to False if any operand is False or Null.
   351  		return nil, false
   352  
   353  	case *memo.TrueExpr:
   354  		// Filters operator skips True operands.
   355  
   356  	case *memo.OrExpr:
   357  		// If NULL is on either side, take the other side.
   358  		if t.Left.Op() == opt.NullOp {
   359  			filters = append(filters, c.f.ConstructFiltersItem(t.Right))
   360  		} else if t.Right.Op() == opt.NullOp {
   361  			filters = append(filters, c.f.ConstructFiltersItem(t.Left))
   362  		} else {
   363  			filters = append(filters, c.f.ConstructFiltersItem(t))
   364  		}
   365  
   366  	default:
   367  		filters = append(filters, c.f.ConstructFiltersItem(t))
   368  	}
   369  	return filters, true
   370  }