github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/operator.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 opt 12 13 import ( 14 "fmt" 15 16 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 17 "github.com/cockroachdb/cockroach/pkg/sql/types" 18 "github.com/cockroachdb/cockroach/pkg/util/log" 19 "github.com/cockroachdb/errors" 20 ) 21 22 // Operator describes the type of operation that a memo expression performs. 23 // Some operators are relational (join, select, project) and others are scalar 24 // (and, or, plus, variable). 25 type Operator uint16 26 27 // String returns the name of the operator as a string. 28 func (op Operator) String() string { 29 if op >= Operator(len(opNames)-1) { 30 return fmt.Sprintf("Operator(%d)", op) 31 } 32 return opNames[opNameIndexes[op]:opNameIndexes[op+1]] 33 } 34 35 // SyntaxTag returns the name of the operator using the SQL syntax that most 36 // closely matches it. 37 func (op Operator) SyntaxTag() string { 38 // Handle any special cases where default codegen tag isn't best choice as 39 // switch cases. 40 switch op { 41 default: 42 // Use default codegen tag, which is mechanically derived from the 43 // operator name. 44 if op >= Operator(len(opNames)-1) { 45 // Use UNKNOWN. 46 op = 0 47 } 48 return opSyntaxTags[opSyntaxTagIndexes[op]:opSyntaxTagIndexes[op+1]] 49 } 50 } 51 52 // Expr is a node in an expression tree. It offers methods to traverse and 53 // inspect the tree. Each node in the tree has an enumerated operator type, zero 54 // or more children, and an optional private value. The entire tree can be 55 // easily visited using a pattern like this: 56 // 57 // var visit func(e Expr) 58 // visit := func(e Expr) { 59 // for i, n := 0, e.ChildCount(); i < n; i++ { 60 // visit(e.Child(i)) 61 // } 62 // } 63 // 64 type Expr interface { 65 // Op returns the operator type of the expression. 66 Op() Operator 67 68 // ChildCount returns the number of children of the expression. 69 ChildCount() int 70 71 // Child returns the nth child of the expression. 72 Child(nth int) Expr 73 74 // Private returns operator-specific data. Callers are expected to know the 75 // type and format of the data, which will differ from operator to operator. 76 // For example, an operator may choose to return one of its fields, or perhaps 77 // a pointer to itself, or nil if there is nothing useful to return. 78 Private() interface{} 79 80 // String returns a human-readable string representation for the expression 81 // that can be used for debugging and testing. 82 String() string 83 } 84 85 // ScalarID is the type of the memo-unique identifier given to every scalar 86 // expression. 87 type ScalarID int 88 89 // ScalarExpr is a scalar expression, which is an expression that returns a 90 // primitive-typed value like boolean or string rather than rows and columns. 91 type ScalarExpr interface { 92 Expr 93 94 // ID is a unique (within the context of a memo) ID that can be 95 // used to define a total order over ScalarExprs. 96 ID() ScalarID 97 98 // DataType is the SQL type of the expression. 99 DataType() *types.T 100 } 101 102 // MutableExpr is implemented by expressions that allow their children to be 103 // updated. 104 type MutableExpr interface { 105 // SetChild updates the nth child of the expression to instead be the given 106 // child expression. 107 SetChild(nth int, child Expr) 108 } 109 110 // ComparisonOpMap maps from a semantic tree comparison operator type to an 111 // optimizer operator type. 112 var ComparisonOpMap [tree.NumComparisonOperators]Operator 113 114 // ComparisonOpReverseMap maps from an optimizer operator type to a semantic 115 // tree comparison operator type. 116 var ComparisonOpReverseMap = map[Operator]tree.ComparisonOperator{ 117 EqOp: tree.EQ, 118 LtOp: tree.LT, 119 GtOp: tree.GT, 120 LeOp: tree.LE, 121 GeOp: tree.GE, 122 NeOp: tree.NE, 123 InOp: tree.In, 124 NotInOp: tree.NotIn, 125 LikeOp: tree.Like, 126 NotLikeOp: tree.NotLike, 127 ILikeOp: tree.ILike, 128 NotILikeOp: tree.NotILike, 129 SimilarToOp: tree.SimilarTo, 130 NotSimilarToOp: tree.NotSimilarTo, 131 RegMatchOp: tree.RegMatch, 132 NotRegMatchOp: tree.NotRegMatch, 133 RegIMatchOp: tree.RegIMatch, 134 NotRegIMatchOp: tree.NotRegIMatch, 135 IsOp: tree.IsNotDistinctFrom, 136 IsNotOp: tree.IsDistinctFrom, 137 ContainsOp: tree.Contains, 138 JsonExistsOp: tree.JSONExists, 139 JsonSomeExistsOp: tree.JSONSomeExists, 140 JsonAllExistsOp: tree.JSONAllExists, 141 OverlapsOp: tree.Overlaps, 142 } 143 144 // BinaryOpReverseMap maps from an optimizer operator type to a semantic tree 145 // binary operator type. 146 var BinaryOpReverseMap = map[Operator]tree.BinaryOperator{ 147 BitandOp: tree.Bitand, 148 BitorOp: tree.Bitor, 149 BitxorOp: tree.Bitxor, 150 PlusOp: tree.Plus, 151 MinusOp: tree.Minus, 152 MultOp: tree.Mult, 153 DivOp: tree.Div, 154 FloorDivOp: tree.FloorDiv, 155 ModOp: tree.Mod, 156 PowOp: tree.Pow, 157 ConcatOp: tree.Concat, 158 LShiftOp: tree.LShift, 159 RShiftOp: tree.RShift, 160 FetchValOp: tree.JSONFetchVal, 161 FetchTextOp: tree.JSONFetchText, 162 FetchValPathOp: tree.JSONFetchValPath, 163 FetchTextPathOp: tree.JSONFetchTextPath, 164 } 165 166 // UnaryOpReverseMap maps from an optimizer operator type to a semantic tree 167 // unary operator type. 168 var UnaryOpReverseMap = map[Operator]tree.UnaryOperator{ 169 UnaryMinusOp: tree.UnaryMinus, 170 UnaryComplementOp: tree.UnaryComplement, 171 UnarySqrtOp: tree.UnarySqrt, 172 UnaryCbrtOp: tree.UnaryCbrt, 173 } 174 175 // AggregateOpReverseMap maps from an optimizer operator type to the name of an 176 // aggregation function. 177 var AggregateOpReverseMap = map[Operator]string{ 178 ArrayAggOp: "array_agg", 179 AvgOp: "avg", 180 BitAndAggOp: "bit_and", 181 BitOrAggOp: "bit_or", 182 BoolAndOp: "bool_and", 183 BoolOrOp: "bool_or", 184 ConcatAggOp: "concat_agg", 185 CountOp: "count", 186 CorrOp: "corr", 187 CountRowsOp: "count_rows", 188 MaxOp: "max", 189 MinOp: "min", 190 SumIntOp: "sum_int", 191 SumOp: "sum", 192 SqrDiffOp: "sqrdiff", 193 VarianceOp: "variance", 194 StdDevOp: "stddev", 195 XorAggOp: "xor_agg", 196 JsonAggOp: "json_agg", 197 JsonbAggOp: "jsonb_agg", 198 StringAggOp: "string_agg", 199 ConstAggOp: "any_not_null", 200 ConstNotNullAggOp: "any_not_null", 201 AnyNotNullAggOp: "any_not_null", 202 PercentileDiscOp: "percentile_disc_impl", 203 PercentileContOp: "percentile_cont_impl", 204 } 205 206 // WindowOpReverseMap maps from an optimizer operator type to the name of a 207 // window function. 208 var WindowOpReverseMap = map[Operator]string{ 209 RankOp: "rank", 210 RowNumberOp: "row_number", 211 DenseRankOp: "dense_rank", 212 PercentRankOp: "percent_rank", 213 CumeDistOp: "cume_dist", 214 NtileOp: "ntile", 215 LagOp: "lag", 216 LeadOp: "lead", 217 FirstValueOp: "first_value", 218 LastValueOp: "last_value", 219 NthValueOp: "nth_value", 220 } 221 222 // NegateOpMap maps from a comparison operator type to its negated operator 223 // type, as if the Not operator was applied to it. Some comparison operators, 224 // like Contains and JsonExists, do not have negated versions. 225 var NegateOpMap = map[Operator]Operator{ 226 EqOp: NeOp, 227 LtOp: GeOp, 228 GtOp: LeOp, 229 LeOp: GtOp, 230 GeOp: LtOp, 231 NeOp: EqOp, 232 InOp: NotInOp, 233 NotInOp: InOp, 234 LikeOp: NotLikeOp, 235 NotLikeOp: LikeOp, 236 ILikeOp: NotILikeOp, 237 NotILikeOp: ILikeOp, 238 SimilarToOp: NotSimilarToOp, 239 NotSimilarToOp: SimilarToOp, 240 RegMatchOp: NotRegMatchOp, 241 NotRegMatchOp: RegMatchOp, 242 RegIMatchOp: NotRegIMatchOp, 243 NotRegIMatchOp: RegIMatchOp, 244 IsOp: IsNotOp, 245 IsNotOp: IsOp, 246 } 247 248 // BoolOperatorRequiresNotNullArgs returns true if the operator can never 249 // evaluate to true if one of its children is NULL. 250 func BoolOperatorRequiresNotNullArgs(op Operator) bool { 251 switch op { 252 case 253 EqOp, LtOp, LeOp, GtOp, GeOp, NeOp, 254 LikeOp, NotLikeOp, ILikeOp, NotILikeOp, SimilarToOp, NotSimilarToOp, 255 RegMatchOp, NotRegMatchOp, RegIMatchOp, NotRegIMatchOp: 256 return true 257 } 258 return false 259 } 260 261 // AggregateIgnoresNulls returns true if the given aggregate operator ignores 262 // rows where its first argument evaluates to NULL. In other words, it always 263 // evaluates to the same result even if those rows are filtered. For example: 264 // 265 // SELECT string_agg(x, y) 266 // FROM (VALUES ('foo', ','), ('bar', ','), (NULL, ',')) t(x, y) 267 // 268 // In this example, the NULL row can be removed from the input, and the 269 // string_agg function still returns the same result. Contrast this to the 270 // array_agg function: 271 // 272 // SELECT array_agg(x) 273 // FROM (VALUES ('foo'), (NULL), ('bar')) t(x) 274 // 275 // If the NULL row is removed here, array_agg returns {foo,bar} instead of 276 // {foo,NULL,bar}. 277 func AggregateIgnoresNulls(op Operator) bool { 278 switch op { 279 280 case AnyNotNullAggOp, AvgOp, BitAndAggOp, BitOrAggOp, BoolAndOp, BoolOrOp, 281 ConstNotNullAggOp, CorrOp, CountOp, MaxOp, MinOp, SqrDiffOp, StdDevOp, 282 StringAggOp, SumOp, SumIntOp, VarianceOp, XorAggOp, PercentileDiscOp, PercentileContOp: 283 return true 284 285 case ArrayAggOp, ConcatAggOp, ConstAggOp, CountRowsOp, FirstAggOp, JsonAggOp, 286 JsonbAggOp: 287 return false 288 289 default: 290 panic(errors.AssertionFailedf("unhandled op %s", log.Safe(op))) 291 } 292 } 293 294 // AggregateIsNullOnEmpty returns true if the given aggregate operator returns 295 // NULL when the input set contains no values. This group of aggregates turns 296 // out to be the inverse of AggregateIsNeverNull in practice. 297 func AggregateIsNullOnEmpty(op Operator) bool { 298 switch op { 299 300 case AnyNotNullAggOp, ArrayAggOp, AvgOp, BitAndAggOp, 301 BitOrAggOp, BoolAndOp, BoolOrOp, ConcatAggOp, ConstAggOp, 302 ConstNotNullAggOp, CorrOp, FirstAggOp, JsonAggOp, JsonbAggOp, 303 MaxOp, MinOp, SqrDiffOp, StdDevOp, StringAggOp, SumOp, SumIntOp, 304 VarianceOp, XorAggOp, PercentileDiscOp, PercentileContOp: 305 return true 306 307 case CountOp, CountRowsOp: 308 return false 309 310 default: 311 panic(errors.AssertionFailedf("unhandled op %s", log.Safe(op))) 312 } 313 } 314 315 // AggregateIsNeverNullOnNonNullInput returns true if the given aggregate 316 // operator never returns NULL when the input set contains at least one non-NULL 317 // value. This is true of most aggregates. 318 // 319 // For multi-input aggregations, returns true if the aggregate is never NULL 320 // when all inputs have at least a non-NULL value (though not necessarily on the 321 // same input row). 322 func AggregateIsNeverNullOnNonNullInput(op Operator) bool { 323 switch op { 324 325 case AnyNotNullAggOp, ArrayAggOp, AvgOp, BitAndAggOp, 326 BitOrAggOp, BoolAndOp, BoolOrOp, ConcatAggOp, ConstAggOp, 327 ConstNotNullAggOp, CountOp, CountRowsOp, FirstAggOp, 328 JsonAggOp, JsonbAggOp, MaxOp, MinOp, SqrDiffOp, 329 StringAggOp, SumOp, SumIntOp, XorAggOp, PercentileDiscOp, PercentileContOp: 330 return true 331 332 case VarianceOp, StdDevOp, CorrOp: 333 // These aggregations return NULL if they are given a single not-NULL input. 334 return false 335 336 default: 337 panic(errors.AssertionFailedf("unhandled op %s", log.Safe(op))) 338 } 339 } 340 341 // AggregateIsNeverNull returns true if the given aggregate operator never 342 // returns NULL, even if the input is empty, or one more more inputs are NULL. 343 func AggregateIsNeverNull(op Operator) bool { 344 switch op { 345 case CountOp, CountRowsOp: 346 return true 347 } 348 return false 349 } 350 351 // AggregatesCanMerge returns true if the given inner and outer operators can be 352 // replaced with a single equivalent operator, assuming the outer operator is 353 // aggregating on the inner. In other words, the inner-outer aggregate pair 354 // forms a valid "decomposition" of a single aggregate. For example, the 355 // following pairs of queries are equivalent: 356 // 357 // SELECT sum(s) FROM (SELECT sum(y) FROM xy GROUP BY x) AS f(s); 358 // SELECT sum(y) FROM xy; 359 // 360 // SELECT sum_int(c) FROM (SELECT count(y) FROM xy GROUP BY x) AS f(c); 361 // SELECT count(y) FROM xy; 362 // 363 // Note: some aggregates like StringAggOp are decomposable in theory, but in 364 // practice can not be easily merged as in the examples above. 365 func AggregatesCanMerge(inner, outer Operator) bool { 366 switch inner { 367 368 case AnyNotNullAggOp, BitAndAggOp, BitOrAggOp, BoolAndOp, 369 BoolOrOp, ConstAggOp, ConstNotNullAggOp, FirstAggOp, 370 MaxOp, MinOp, SumOp, SumIntOp, XorAggOp: 371 return inner == outer 372 373 case CountOp, CountRowsOp: 374 // Only SumIntOp can be used here because SumOp outputs a decimal value, 375 // while CountOp and CountRowsOp both output int values. 376 return outer == SumIntOp 377 378 case ArrayAggOp, AvgOp, ConcatAggOp, CorrOp, JsonAggOp, 379 JsonbAggOp, PercentileContOp, PercentileDiscOp, SqrDiffOp, 380 StdDevOp, StringAggOp, VarianceOp: 381 return false 382 383 default: 384 panic(errors.AssertionFailedf("unhandled ops: %s, %s", log.Safe(inner), log.Safe(outer))) 385 } 386 } 387 388 // AggregateIgnoresDuplicates returns true if the output of the given aggregate 389 // operator does not change when duplicate rows are added to the input. 390 func AggregateIgnoresDuplicates(op Operator) bool { 391 switch op { 392 case AnyNotNullAggOp, BitAndAggOp, BitOrAggOp, BoolAndOp, BoolOrOp, 393 ConstAggOp, ConstNotNullAggOp, FirstAggOp, MaxOp, MinOp: 394 return true 395 396 case ArrayAggOp, AvgOp, ConcatAggOp, CountOp, CorrOp, CountRowsOp, SumIntOp, 397 SumOp, SqrDiffOp, VarianceOp, StdDevOp, XorAggOp, JsonAggOp, JsonbAggOp, 398 StringAggOp, PercentileDiscOp, PercentileContOp: 399 return false 400 401 default: 402 panic(errors.AssertionFailedf("unhandled op %s", log.Safe(op))) 403 } 404 } 405 406 // OpaqueMetadata is an object stored in OpaqueRelExpr and passed 407 // through to the exec factory. 408 type OpaqueMetadata interface { 409 ImplementsOpaqueMetadata() 410 411 // String is a short description used when printing optimizer trees and when 412 // forming error messages; it should be the SQL statement tag. 413 String() string 414 } 415 416 func init() { 417 for optOp, treeOp := range ComparisonOpReverseMap { 418 ComparisonOpMap[treeOp] = optOp 419 } 420 }