github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/norm/scalar_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  	"sort"
    15  
    16  	"github.com/cockroachdb/cockroach/pkg/sql/opt"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/opt/memo"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    21  	"github.com/cockroachdb/cockroach/pkg/util/json"
    22  	"github.com/cockroachdb/cockroach/pkg/util/log"
    23  	"github.com/cockroachdb/errors"
    24  )
    25  
    26  // NeedSortedUniqueList returns true if the given list is composed entirely of
    27  // constant values that are either not in sorted order or have duplicates. If
    28  // true, then ConstructSortedUniqueList needs to be called on the list to
    29  // normalize it.
    30  func (c *CustomFuncs) NeedSortedUniqueList(list memo.ScalarListExpr) bool {
    31  	if len(list) <= 1 {
    32  		return false
    33  	}
    34  	ls := listSorter{cf: c, list: list}
    35  	var needSortedUniqueList bool
    36  	for i, item := range list {
    37  		if !opt.IsConstValueOp(item) {
    38  			return false
    39  		}
    40  		if i != 0 && !ls.less(i-1, i) {
    41  			needSortedUniqueList = true
    42  		}
    43  	}
    44  	return needSortedUniqueList
    45  }
    46  
    47  // ConstructSortedUniqueList sorts the given list and removes duplicates, and
    48  // returns the resulting list. See the comment for listSorter.compare for
    49  // comparison rule details.
    50  func (c *CustomFuncs) ConstructSortedUniqueList(
    51  	list memo.ScalarListExpr,
    52  ) (memo.ScalarListExpr, *types.T) {
    53  	// Make a copy of the list, since it needs to stay immutable.
    54  	newList := make(memo.ScalarListExpr, len(list))
    55  	copy(newList, list)
    56  	ls := listSorter{cf: c, list: newList}
    57  
    58  	// Sort the list.
    59  	sort.Slice(ls.list, ls.less)
    60  
    61  	// Remove duplicates from the list.
    62  	n := 0
    63  	for i := range newList {
    64  		if i == 0 || ls.compare(i-1, i) < 0 {
    65  			newList[n] = newList[i]
    66  			n++
    67  		}
    68  	}
    69  	newList = newList[:n]
    70  
    71  	// Construct the type of the tuple.
    72  	contents := make([]*types.T, n)
    73  	for i := range newList {
    74  		contents[i] = newList[i].DataType()
    75  	}
    76  	return newList, types.MakeTuple(contents)
    77  }
    78  
    79  // SimplifyCoalesce discards any leading null operands, and then if the next
    80  // operand is a constant, replaces with that constant.
    81  func (c *CustomFuncs) SimplifyCoalesce(args memo.ScalarListExpr) opt.ScalarExpr {
    82  	for i := 0; i < len(args)-1; i++ {
    83  		item := args[i]
    84  
    85  		// If item is not a constant value, then its value may turn out to be
    86  		// null, so no more folding. Return operands from then on.
    87  		if !c.IsConstValueOrTuple(item) {
    88  			return c.f.ConstructCoalesce(args[i:])
    89  		}
    90  
    91  		if item.Op() != opt.NullOp {
    92  			return item
    93  		}
    94  	}
    95  
    96  	// All operands up to the last were null (or the last is the only operand),
    97  	// so return the last operand without the wrapping COALESCE function.
    98  	return args[len(args)-1]
    99  }
   100  
   101  // IsJSONScalar returns if the JSON value is a number, string, true, false, or null.
   102  func (c *CustomFuncs) IsJSONScalar(value opt.ScalarExpr) bool {
   103  	v := value.(*memo.ConstExpr).Value.(*tree.DJSON)
   104  	return v.JSON.Type() != json.ObjectJSONType && v.JSON.Type() != json.ArrayJSONType
   105  }
   106  
   107  // MakeSingleKeyJSONObject returns a JSON object with one entry, mapping key to value.
   108  func (c *CustomFuncs) MakeSingleKeyJSONObject(key, value opt.ScalarExpr) opt.ScalarExpr {
   109  	k := key.(*memo.ConstExpr).Value.(*tree.DString)
   110  	v := value.(*memo.ConstExpr).Value.(*tree.DJSON)
   111  
   112  	builder := json.NewObjectBuilder(1)
   113  	builder.Add(string(*k), v.JSON)
   114  	j := builder.Build()
   115  
   116  	return c.f.ConstructConst(&tree.DJSON{JSON: j}, types.Jsonb)
   117  }
   118  
   119  // IsConstValueEqual returns whether const1 and const2 are equal.
   120  func (c *CustomFuncs) IsConstValueEqual(const1, const2 opt.ScalarExpr) bool {
   121  	op1 := const1.Op()
   122  	op2 := const2.Op()
   123  	if op1 != op2 || op1 == opt.NullOp {
   124  		return false
   125  	}
   126  	switch op1 {
   127  	case opt.TrueOp, opt.FalseOp:
   128  		return true
   129  	case opt.ConstOp:
   130  		datum1 := const1.(*memo.ConstExpr).Value
   131  		datum2 := const2.(*memo.ConstExpr).Value
   132  		return datum1.Compare(c.f.evalCtx, datum2) == 0
   133  	default:
   134  		panic(errors.AssertionFailedf("unexpected Op type: %v", log.Safe(op1)))
   135  	}
   136  }
   137  
   138  // SimplifyWhens removes known unreachable WHEN cases and constructs a new CASE
   139  // statement. Any known true condition is converted to the ELSE. If only the
   140  // ELSE remains, its expression is returned. condition must be a ConstValue.
   141  func (c *CustomFuncs) SimplifyWhens(
   142  	condition opt.ScalarExpr, whens memo.ScalarListExpr, orElse opt.ScalarExpr,
   143  ) opt.ScalarExpr {
   144  	newWhens := make(memo.ScalarListExpr, 0, len(whens))
   145  	for _, item := range whens {
   146  		when := item.(*memo.WhenExpr)
   147  		if opt.IsConstValueOp(when.Condition) {
   148  			if !c.IsConstValueEqual(condition, when.Condition) {
   149  				// Ignore known unmatching conditions.
   150  				continue
   151  			}
   152  
   153  			// If this is true, we won't ever match anything else, so convert this to
   154  			// the ELSE (or just return it if there are no earlier items).
   155  			if len(newWhens) == 0 {
   156  				return c.ensureTyped(when.Value, memo.InferWhensType(whens, orElse))
   157  			}
   158  			return c.f.ConstructCase(condition, newWhens, when.Value)
   159  		}
   160  
   161  		newWhens = append(newWhens, when)
   162  	}
   163  
   164  	// The ELSE value.
   165  	if len(newWhens) == 0 {
   166  		// ELSE is the only clause (there are no WHENs), remove the CASE.
   167  		// NULLs in this position will not be typed, so we tag them with
   168  		// a type we observed earlier.
   169  		// typ will never be nil here because the definition of
   170  		// SimplifyCaseWhenConstValue ensures that whens is nonempty.
   171  		return c.ensureTyped(orElse, memo.InferWhensType(whens, orElse))
   172  	}
   173  
   174  	return c.f.ConstructCase(condition, newWhens, orElse)
   175  }
   176  
   177  // ensureTyped makes sure that any NULL passing through gets tagged with an
   178  // appropriate type.
   179  func (c *CustomFuncs) ensureTyped(d opt.ScalarExpr, typ *types.T) opt.ScalarExpr {
   180  	if d.DataType().Family() == types.UnknownFamily {
   181  		return c.f.ConstructNull(typ)
   182  	}
   183  	return d
   184  }
   185  
   186  // OpsAreSame returns true if the two operators are the same.
   187  func (c *CustomFuncs) OpsAreSame(left, right opt.Operator) bool {
   188  	return left == right
   189  }
   190  
   191  // ConvertConstArrayToTuple converts a constant ARRAY datum to the equivalent
   192  // homogeneous tuple, so ARRAY[1, 2, 3] becomes (1, 2, 3).
   193  func (c *CustomFuncs) ConvertConstArrayToTuple(scalar opt.ScalarExpr) opt.ScalarExpr {
   194  	darr := scalar.(*memo.ConstExpr).Value.(*tree.DArray)
   195  	elems := make(memo.ScalarListExpr, len(darr.Array))
   196  	ts := make([]*types.T, len(darr.Array))
   197  	for i, delem := range darr.Array {
   198  		elems[i] = c.f.ConstructConstVal(delem, delem.ResolvedType())
   199  		ts[i] = darr.ParamTyp
   200  	}
   201  	return c.f.ConstructTuple(elems, types.MakeTuple(ts))
   202  }
   203  
   204  // CastToCollatedString returns the given string or collated string as a
   205  // collated string constant with the given locale.
   206  func (c *CustomFuncs) CastToCollatedString(str opt.ScalarExpr, locale string) opt.ScalarExpr {
   207  	datum := str.(*memo.ConstExpr).Value
   208  	if wrap, ok := datum.(*tree.DOidWrapper); ok {
   209  		datum = wrap.Wrapped
   210  	}
   211  
   212  	var value string
   213  	switch t := datum.(type) {
   214  	case *tree.DString:
   215  		value = string(*t)
   216  	case *tree.DCollatedString:
   217  		value = t.Contents
   218  	default:
   219  		panic(errors.AssertionFailedf("unexpected type for COLLATE: %T", t))
   220  	}
   221  
   222  	d, err := tree.NewDCollatedString(value, locale, &c.f.evalCtx.CollationEnv)
   223  	if err != nil {
   224  		panic(err)
   225  	}
   226  	return c.f.ConstructConst(d, types.MakeCollatedString(str.DataType(), locale))
   227  }
   228  
   229  // MakeUnorderedSubquery returns a SubqueryPrivate that specifies no ordering.
   230  func (c *CustomFuncs) MakeUnorderedSubquery() *memo.SubqueryPrivate {
   231  	return &memo.SubqueryPrivate{}
   232  }
   233  
   234  // SubqueryOrdering returns the ordering property on a SubqueryPrivate.
   235  func (c *CustomFuncs) SubqueryOrdering(sub *memo.SubqueryPrivate) physical.OrderingChoice {
   236  	var oc physical.OrderingChoice
   237  	oc.FromOrdering(sub.Ordering)
   238  	return oc
   239  }
   240  
   241  // SubqueryRequestedCol returns the requested column from a SubqueryPrivate.
   242  // This function should only be used with ArrayFlatten expressions.
   243  func (c *CustomFuncs) SubqueryRequestedCol(sub *memo.SubqueryPrivate) opt.ColumnID {
   244  	return sub.RequestedCol
   245  }
   246  
   247  // SubqueryCmp returns the comparison operation from a SubqueryPrivate.
   248  func (c *CustomFuncs) SubqueryCmp(sub *memo.SubqueryPrivate) opt.Operator {
   249  	return sub.Cmp
   250  }
   251  
   252  // MakeArrayAggCol returns a ColumnID with the given type and an "array_agg"
   253  // label.
   254  func (c *CustomFuncs) MakeArrayAggCol(typ *types.T) opt.ColumnID {
   255  	return c.mem.Metadata().AddColumn("array_agg", typ)
   256  }
   257  
   258  // IsLimited indicates whether a limit was pushed under the subquery
   259  // already. See e.g. the rule IntroduceExistsLimit.
   260  func (c *CustomFuncs) IsLimited(sub *memo.SubqueryPrivate) bool {
   261  	return sub.WasLimited
   262  }
   263  
   264  // MakeLimited specifies that the subquery has a limit set
   265  // already. This prevents e.g. the rule IntroduceExistsLimit from
   266  // applying twice.
   267  func (c *CustomFuncs) MakeLimited(sub *memo.SubqueryPrivate) *memo.SubqueryPrivate {
   268  	newSub := *sub
   269  	newSub.WasLimited = true
   270  	return &newSub
   271  }
   272  
   273  // InlineValues converts a Values operator to a tuple. If there are
   274  // multiple columns, the result is a tuple of tuples.
   275  func (c *CustomFuncs) InlineValues(v memo.RelExpr) *memo.TupleExpr {
   276  	values := v.(*memo.ValuesExpr)
   277  	md := c.mem.Metadata()
   278  	if len(values.Cols) > 1 {
   279  		colTypes := make([]*types.T, len(values.Cols))
   280  		for i, colID := range values.Cols {
   281  			colTypes[i] = md.ColumnMeta(colID).Type
   282  		}
   283  		// Inlining a multi-column VALUES results in a tuple of tuples. Example:
   284  		//
   285  		//   (a,b) IN (VALUES (1,1), (2,2))
   286  		// =>
   287  		//   (a,b) IN ((1,1), (2,2))
   288  		return &memo.TupleExpr{
   289  			Elems: values.Rows,
   290  			Typ:   types.MakeTuple([]*types.T{types.MakeTuple(colTypes)}),
   291  		}
   292  	}
   293  	// Inlining a sngle-column VALUES results in a simple tuple. Example:
   294  	//   a IN (VALUES (1), (2))
   295  	// =>
   296  	//   a IN (1, 2)
   297  	colType := md.ColumnMeta(values.Cols[0]).Type
   298  	tuple := &memo.TupleExpr{
   299  		Elems: make(memo.ScalarListExpr, len(values.Rows)),
   300  		Typ:   types.MakeTuple([]*types.T{colType}),
   301  	}
   302  	for i := range values.Rows {
   303  		tuple.Elems[i] = values.Rows[i].(*memo.TupleExpr).Elems[0]
   304  	}
   305  	return tuple
   306  }
   307  
   308  // IsTupleOfVars returns true if the given tuple contains Variables
   309  // corresponding to the given columns (in the same order).
   310  func (c *CustomFuncs) IsTupleOfVars(tuple opt.ScalarExpr, cols opt.ColList) bool {
   311  	t := tuple.(*memo.TupleExpr)
   312  	if len(t.Elems) != len(cols) {
   313  		return false
   314  	}
   315  	for i := range t.Elems {
   316  		v, ok := t.Elems[i].(*memo.VariableExpr)
   317  		if !ok || v.Col != cols[i] {
   318  			return false
   319  		}
   320  	}
   321  	return true
   322  }
   323  
   324  // VarsAreSame returns true if the two variables are the same.
   325  func (c *CustomFuncs) VarsAreSame(left, right opt.ScalarExpr) bool {
   326  	lv := left.(*memo.VariableExpr)
   327  	rv := right.(*memo.VariableExpr)
   328  	return lv.Col == rv.Col
   329  }