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 }