github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/norm/general_funcs.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 norm 12 13 import ( 14 "github.com/cockroachdb/apd" 15 "github.com/cockroachdb/cockroach/pkg/sql/opt" 16 "github.com/cockroachdb/cockroach/pkg/sql/opt/cat" 17 "github.com/cockroachdb/cockroach/pkg/sql/opt/constraint" 18 "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" 19 "github.com/cockroachdb/cockroach/pkg/sql/opt/props" 20 "github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical" 21 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 22 "github.com/cockroachdb/cockroach/pkg/sql/types" 23 "github.com/cockroachdb/cockroach/pkg/util/arith" 24 "github.com/cockroachdb/errors" 25 ) 26 27 // CustomFuncs contains all the custom match and replace functions used by 28 // the normalization rules. These are also imported and used by the explorer. 29 type CustomFuncs struct { 30 f *Factory 31 mem *memo.Memo 32 } 33 34 // Init initializes a new CustomFuncs with the given factory. 35 func (c *CustomFuncs) Init(f *Factory) { 36 c.f = f 37 c.mem = f.Memo() 38 } 39 40 // Succeeded returns true if a result expression is not nil. 41 func (c *CustomFuncs) Succeeded(result opt.Expr) bool { 42 return result != nil 43 } 44 45 // ---------------------------------------------------------------------- 46 // 47 // Typing functions 48 // General functions used to test and construct expression data types. 49 // 50 // ---------------------------------------------------------------------- 51 52 // HasColType returns true if the given scalar expression has a static type 53 // that's identical to the requested coltype. 54 func (c *CustomFuncs) HasColType(scalar opt.ScalarExpr, dstTyp *types.T) bool { 55 return scalar.DataType().Identical(dstTyp) 56 } 57 58 // IsString returns true if the given scalar expression is of type String. 59 func (c *CustomFuncs) IsString(scalar opt.ScalarExpr) bool { 60 return scalar.DataType().Family() == types.StringFamily 61 } 62 63 // IsTimestamp returns true if the given scalar expression is of type Timestamp. 64 func (c *CustomFuncs) IsTimestamp(scalar opt.ScalarExpr) bool { 65 return scalar.DataType().Family() == types.TimestampFamily 66 } 67 68 // IsTimestampTZ returns true if the given scalar expression is of type 69 // TimestampTZ. 70 func (c *CustomFuncs) IsTimestampTZ(scalar opt.ScalarExpr) bool { 71 return scalar.DataType().Family() == types.TimestampTZFamily 72 } 73 74 // BoolType returns the boolean SQL type. 75 func (c *CustomFuncs) BoolType() *types.T { 76 return types.Bool 77 } 78 79 // AnyType returns the wildcard Any type. 80 func (c *CustomFuncs) AnyType() *types.T { 81 return types.Any 82 } 83 84 // CanConstructBinary returns true if (op left right) has a valid binary op 85 // overload and is therefore legal to construct. For example, while 86 // (Minus <date> <int>) is valid, (Minus <int> <date>) is not. 87 func (c *CustomFuncs) CanConstructBinary(op opt.Operator, left, right opt.ScalarExpr) bool { 88 return memo.BinaryOverloadExists(op, left.DataType(), right.DataType()) 89 } 90 91 // ArrayType returns the type of the given column wrapped 92 // in an array. 93 func (c *CustomFuncs) ArrayType(inCol opt.ColumnID) *types.T { 94 inTyp := c.mem.Metadata().ColumnMeta(inCol).Type 95 return types.MakeArray(inTyp) 96 } 97 98 // BinaryType returns the type of the binary overload for the given operator and 99 // operands. 100 func (c *CustomFuncs) BinaryType(op opt.Operator, left, right opt.ScalarExpr) *types.T { 101 o, _ := memo.FindBinaryOverload(op, left.DataType(), right.DataType()) 102 return o.ReturnType 103 } 104 105 // TypeOf returns the type of the expression. 106 func (c *CustomFuncs) TypeOf(e opt.ScalarExpr) *types.T { 107 return e.DataType() 108 } 109 110 // IsConstArray returns true if the expression is a constant array. 111 func (c *CustomFuncs) IsConstArray(scalar opt.ScalarExpr) bool { 112 if cnst, ok := scalar.(*memo.ConstExpr); ok { 113 if _, ok := cnst.Value.(*tree.DArray); ok { 114 return true 115 } 116 } 117 return false 118 } 119 120 // IsAdditiveType returns true if the given type supports addition and 121 // subtraction in the natural way. This differs from "has a +/- Numeric 122 // implementation" because JSON has an implementation for "- INT" which doesn't 123 // obey x - 0 = x. Additive types include all numeric types as well as 124 // timestamps and dates. 125 func (c *CustomFuncs) IsAdditiveType(typ *types.T) bool { 126 return types.IsAdditiveType(typ) 127 } 128 129 // ---------------------------------------------------------------------- 130 // 131 // Column functions 132 // General custom match and replace functions related to columns. 133 // 134 // ---------------------------------------------------------------------- 135 136 // OutputCols returns the set of columns returned by the input expression. 137 func (c *CustomFuncs) OutputCols(input memo.RelExpr) opt.ColSet { 138 return input.Relational().OutputCols 139 } 140 141 // OutputCols2 returns the union of columns returned by the left and right 142 // expressions. 143 func (c *CustomFuncs) OutputCols2(left, right memo.RelExpr) opt.ColSet { 144 return left.Relational().OutputCols.Union(right.Relational().OutputCols) 145 } 146 147 // NotNullCols returns the set of columns returned by the input expression that 148 // are guaranteed to never be NULL. 149 func (c *CustomFuncs) NotNullCols(input memo.RelExpr) opt.ColSet { 150 return input.Relational().NotNullCols 151 } 152 153 // IsColNotNull returns true if the given input column is never null. 154 func (c *CustomFuncs) IsColNotNull(col opt.ColumnID, input memo.RelExpr) bool { 155 return input.Relational().NotNullCols.Contains(col) 156 } 157 158 // IsColNotNull2 returns true if the given column is part of the left or right 159 // expressions' set of not-null columns. 160 func (c *CustomFuncs) IsColNotNull2(col opt.ColumnID, left, right memo.RelExpr) bool { 161 return left.Relational().NotNullCols.Contains(col) || 162 right.Relational().NotNullCols.Contains(col) 163 } 164 165 // HasNoCols returns true if the input expression has zero output columns. 166 func (c *CustomFuncs) HasNoCols(input memo.RelExpr) bool { 167 return input.Relational().OutputCols.Empty() 168 } 169 170 // HasOneCol returns true if the input expression has exactly one output column. 171 func (c *CustomFuncs) HasOneCol(input memo.RelExpr) bool { 172 return input.Relational().OutputCols.Len() == 1 173 } 174 175 // ColsAreConst returns true if the given columns have the same values for all 176 // rows in the given input expression. 177 func (c *CustomFuncs) ColsAreConst(cols opt.ColSet, input memo.RelExpr) bool { 178 return cols.SubsetOf(input.Relational().FuncDeps.ConstantCols()) 179 } 180 181 // ColsAreEmpty returns true if the column set is empty. 182 func (c *CustomFuncs) ColsAreEmpty(cols opt.ColSet) bool { 183 return cols.Empty() 184 } 185 186 // MakeEmptyColSet returns a column set with no columns in it. 187 func (c *CustomFuncs) MakeEmptyColSet() opt.ColSet { 188 return opt.ColSet{} 189 } 190 191 // ColsAreSubset returns true if the left columns are a subset of the right 192 // columns. 193 func (c *CustomFuncs) ColsAreSubset(left, right opt.ColSet) bool { 194 return left.SubsetOf(right) 195 } 196 197 // ColsAreEqual returns true if left and right contain the same set of columns. 198 func (c *CustomFuncs) ColsAreEqual(left, right opt.ColSet) bool { 199 return left.Equals(right) 200 } 201 202 // ColsIntersect returns true if at least one column appears in both the left 203 // and right sets. 204 func (c *CustomFuncs) ColsIntersect(left, right opt.ColSet) bool { 205 return left.Intersects(right) 206 } 207 208 // IntersectionCols returns the intersection of the left and right column sets. 209 func (c *CustomFuncs) IntersectionCols(left, right opt.ColSet) opt.ColSet { 210 return left.Intersection(right) 211 } 212 213 // UnionCols returns the union of the left and right column sets. 214 func (c *CustomFuncs) UnionCols(left, right opt.ColSet) opt.ColSet { 215 return left.Union(right) 216 } 217 218 // UnionCols3 returns the union of the three column sets. 219 func (c *CustomFuncs) UnionCols3(cols1, cols2, cols3 opt.ColSet) opt.ColSet { 220 cols := cols1.Union(cols2) 221 cols.UnionWith(cols3) 222 return cols 223 } 224 225 // UnionCols4 returns the union of the four column sets. 226 func (c *CustomFuncs) UnionCols4(cols1, cols2, cols3, cols4 opt.ColSet) opt.ColSet { 227 cols := cols1.Union(cols2) 228 cols.UnionWith(cols3) 229 cols.UnionWith(cols4) 230 return cols 231 } 232 233 // DifferenceCols returns the difference of the left and right column sets. 234 func (c *CustomFuncs) DifferenceCols(left, right opt.ColSet) opt.ColSet { 235 return left.Difference(right) 236 } 237 238 // AddColToSet returns a set containing both the given set and the given column. 239 func (c *CustomFuncs) AddColToSet(set opt.ColSet, col opt.ColumnID) opt.ColSet { 240 if set.Contains(col) { 241 return set 242 } 243 newSet := set.Copy() 244 newSet.Add(col) 245 return newSet 246 } 247 248 // SingleColFromSet returns the single column in s. Panics if s does not contain 249 // exactly one column. 250 func (c *CustomFuncs) SingleColFromSet(s opt.ColSet) opt.ColumnID { 251 return s.SingleColumn() 252 } 253 254 // RedundantCols returns the subset of the given columns that are functionally 255 // determined by the remaining columns. In many contexts (such as if they are 256 // grouping columns), these columns can be dropped. The input expression's 257 // functional dependencies are used to make the decision. 258 func (c *CustomFuncs) RedundantCols(input memo.RelExpr, cols opt.ColSet) opt.ColSet { 259 reducedCols := input.Relational().FuncDeps.ReduceCols(cols) 260 if reducedCols.Equals(cols) { 261 return opt.ColSet{} 262 } 263 return cols.Difference(reducedCols) 264 } 265 266 // ---------------------------------------------------------------------- 267 // 268 // Outer column functions 269 // General custom functions related to outer column references. 270 // 271 // ---------------------------------------------------------------------- 272 273 // OuterCols returns the set of outer columns associated with the given 274 // expression, whether it be a relational or scalar operator. 275 func (c *CustomFuncs) OuterCols(e opt.Expr) opt.ColSet { 276 return c.sharedProps(e).OuterCols 277 } 278 279 // HasOuterCols returns true if the input expression has at least one outer 280 // column, or in other words, a reference to a variable that is not bound within 281 // its own scope. For example: 282 // 283 // SELECT * FROM a WHERE EXISTS(SELECT * FROM b WHERE b.x = a.x) 284 // 285 // The a.x variable in the EXISTS subquery references a column outside the scope 286 // of the subquery. It is an "outer column" for the subquery (see the comment on 287 // RelationalProps.OuterCols for more details). 288 func (c *CustomFuncs) HasOuterCols(input opt.Expr) bool { 289 return !c.OuterCols(input).Empty() 290 } 291 292 // IsCorrelated returns true if any variable in the source expression references 293 // a column from the destination expression. For example: 294 // (InnerJoin 295 // (Scan a) 296 // (Scan b) 297 // [ ... (FiltersItem $item:(Eq (Variable a.x) (Const 1))) ... ] 298 // ) 299 // 300 // The $item expression is correlated with the (Scan a) expression because it 301 // references one of its columns. But the $item expression is not correlated 302 // with the (Scan b) expression. 303 func (c *CustomFuncs) IsCorrelated(src, dst memo.RelExpr) bool { 304 return src.Relational().OuterCols.Intersects(dst.Relational().OutputCols) 305 } 306 307 // IsBoundBy returns true if all outer references in the source expression are 308 // bound by the given columns. For example: 309 // 310 // (InnerJoin 311 // (Scan a) 312 // (Scan b) 313 // [ ... $item:(FiltersItem (Eq (Variable a.x) (Const 1))) ... ] 314 // ) 315 // 316 // The $item expression is fully bound by the output columns of the (Scan a) 317 // expression because all of its outer references are satisfied by the columns 318 // produced by the Scan. 319 func (c *CustomFuncs) IsBoundBy(src opt.Expr, cols opt.ColSet) bool { 320 return c.OuterCols(src).SubsetOf(cols) 321 } 322 323 // ColsAreDeterminedBy returns true if the given columns are functionally 324 // determined by the "in" ColSet according to the functional dependencies of the 325 // input expression. 326 func (c *CustomFuncs) ColsAreDeterminedBy(cols, in opt.ColSet, input memo.RelExpr) bool { 327 return input.Relational().FuncDeps.InClosureOf(cols, in) 328 } 329 330 // AreProjectionsCorrelated returns true if any element in the projections 331 // references any of the given columns. 332 func (c *CustomFuncs) AreProjectionsCorrelated( 333 projections memo.ProjectionsExpr, cols opt.ColSet, 334 ) bool { 335 for i := range projections { 336 if projections[i].ScalarProps().OuterCols.Intersects(cols) { 337 return true 338 } 339 } 340 return false 341 } 342 343 // IsZipCorrelated returns true if any element in the zip references 344 // any of the given columns. 345 func (c *CustomFuncs) IsZipCorrelated(zip memo.ZipExpr, cols opt.ColSet) bool { 346 for i := range zip { 347 if zip[i].ScalarProps().OuterCols.Intersects(cols) { 348 return true 349 } 350 } 351 return false 352 } 353 354 // FilterOuterCols returns the union of all outer columns from the given filter 355 // conditions. 356 func (c *CustomFuncs) FilterOuterCols(filters memo.FiltersExpr) opt.ColSet { 357 var colSet opt.ColSet 358 for i := range filters { 359 colSet.UnionWith(filters[i].ScalarProps().OuterCols) 360 } 361 return colSet 362 } 363 364 // FiltersBoundBy returns true if all outer references in any of the filter 365 // conditions are bound by the given columns. For example: 366 // 367 // (InnerJoin 368 // (Scan a) 369 // (Scan b) 370 // $filters:[ (FiltersItem (Eq (Variable a.x) (Const 1))) ] 371 // ) 372 // 373 // The $filters expression is fully bound by the output columns of the (Scan a) 374 // expression because all of its outer references are satisfied by the columns 375 // produced by the Scan. 376 func (c *CustomFuncs) FiltersBoundBy(filters memo.FiltersExpr, cols opt.ColSet) bool { 377 for i := range filters { 378 if !filters[i].ScalarProps().OuterCols.SubsetOf(cols) { 379 return false 380 } 381 } 382 return true 383 } 384 385 // ProjectionOuterCols returns the union of all outer columns from the given 386 // projection expressions. 387 func (c *CustomFuncs) ProjectionOuterCols(projections memo.ProjectionsExpr) opt.ColSet { 388 var colSet opt.ColSet 389 for i := range projections { 390 colSet.UnionWith(projections[i].ScalarProps().OuterCols) 391 } 392 return colSet 393 } 394 395 // AggregationOuterCols returns the union of all outer columns from the given 396 // aggregation expressions. 397 func (c *CustomFuncs) AggregationOuterCols(aggregations memo.AggregationsExpr) opt.ColSet { 398 var colSet opt.ColSet 399 for i := range aggregations { 400 colSet.UnionWith(aggregations[i].ScalarProps().OuterCols) 401 } 402 return colSet 403 } 404 405 // ZipOuterCols returns the union of all outer columns from the given 406 // zip expressions. 407 func (c *CustomFuncs) ZipOuterCols(zip memo.ZipExpr) opt.ColSet { 408 var colSet opt.ColSet 409 for i := range zip { 410 colSet.UnionWith(zip[i].ScalarProps().OuterCols) 411 } 412 return colSet 413 } 414 415 // ---------------------------------------------------------------------- 416 // 417 // Row functions 418 // General custom match and replace functions related to rows. 419 // 420 // ---------------------------------------------------------------------- 421 422 // HasZeroRows returns true if the input expression never returns any rows. 423 func (c *CustomFuncs) HasZeroRows(input memo.RelExpr) bool { 424 return input.Relational().Cardinality.IsZero() 425 } 426 427 // HasOneRow returns true if the input expression always returns exactly one 428 // row. 429 func (c *CustomFuncs) HasOneRow(input memo.RelExpr) bool { 430 return input.Relational().Cardinality.IsOne() 431 } 432 433 // HasZeroOrOneRow returns true if the input expression returns at most one row. 434 func (c *CustomFuncs) HasZeroOrOneRow(input memo.RelExpr) bool { 435 return input.Relational().Cardinality.IsZeroOrOne() 436 } 437 438 // CanHaveZeroRows returns true if the input expression might return zero rows. 439 func (c *CustomFuncs) CanHaveZeroRows(input memo.RelExpr) bool { 440 return input.Relational().Cardinality.CanBeZero() 441 } 442 443 // ---------------------------------------------------------------------- 444 // 445 // Key functions 446 // General custom match and replace functions related to keys. 447 // 448 // ---------------------------------------------------------------------- 449 450 // CandidateKey returns the candidate key columns from the given input 451 // expression. If there is no candidate key, CandidateKey returns ok=false. 452 func (c *CustomFuncs) CandidateKey(input memo.RelExpr) (key opt.ColSet, ok bool) { 453 return input.Relational().FuncDeps.StrictKey() 454 } 455 456 // HasStrictKey returns true if the input expression has one or more columns 457 // that form a strict key (see comment for ColsAreStrictKey for definition). 458 func (c *CustomFuncs) HasStrictKey(input memo.RelExpr) bool { 459 inputFDs := &input.Relational().FuncDeps 460 _, hasKey := inputFDs.StrictKey() 461 return hasKey 462 } 463 464 // ColsAreStrictKey returns true if the given columns form a strict key for the 465 // given input expression. A strict key means that any two rows will have unique 466 // key column values. Nulls are treated as equal to one another (i.e. no 467 // duplicate nulls allowed). Having a strict key means that the set of key 468 // column values uniquely determine the values of all other columns in the 469 // relation. 470 func (c *CustomFuncs) ColsAreStrictKey(cols opt.ColSet, input memo.RelExpr) bool { 471 return input.Relational().FuncDeps.ColsAreStrictKey(cols) 472 } 473 474 // PrimaryKeyCols returns the key columns of the primary key of the table. 475 func (c *CustomFuncs) PrimaryKeyCols(table opt.TableID) opt.ColSet { 476 tabMeta := c.mem.Metadata().TableMeta(table) 477 return tabMeta.IndexKeyColumns(cat.PrimaryIndex) 478 } 479 480 // ---------------------------------------------------------------------- 481 // 482 // Property functions 483 // General custom functions related to expression properties. 484 // 485 // ---------------------------------------------------------------------- 486 487 // ExprIsNeverNull returns true if we can prove that the given scalar expression 488 // is always non-NULL. Any variables that refer to columns in the notNullCols 489 // set are assumed to be non-NULL. See memo.ExprIsNeverNull. 490 func (c *CustomFuncs) ExprIsNeverNull(e opt.ScalarExpr, notNullCols opt.ColSet) bool { 491 return memo.ExprIsNeverNull(e, notNullCols) 492 } 493 494 // sharedProps returns the shared logical properties for the given expression. 495 // Only relational expressions and certain scalar list items (e.g. FiltersItem, 496 // ProjectionsItem, AggregationsItem) have shared properties. 497 func (c *CustomFuncs) sharedProps(e opt.Expr) *props.Shared { 498 switch t := e.(type) { 499 case memo.RelExpr: 500 return &t.Relational().Shared 501 case memo.ScalarPropsExpr: 502 return &t.ScalarProps().Shared 503 default: 504 var p props.Shared 505 memo.BuildSharedProps(e, &p) 506 return &p 507 } 508 } 509 510 // ---------------------------------------------------------------------- 511 // 512 // Ordering functions 513 // General functions related to orderings. 514 // 515 // ---------------------------------------------------------------------- 516 517 // OrderingCanProjectCols returns true if the given OrderingChoice can be 518 // expressed using only the given columns. Or in other words, at least one 519 // column from every ordering group is a member of the given ColSet. 520 func (c *CustomFuncs) OrderingCanProjectCols( 521 ordering physical.OrderingChoice, cols opt.ColSet, 522 ) bool { 523 return ordering.CanProjectCols(cols) 524 } 525 526 // OrderingCols returns all non-optional columns that are part of the given 527 // OrderingChoice. 528 func (c *CustomFuncs) OrderingCols(ordering physical.OrderingChoice) opt.ColSet { 529 return ordering.ColSet() 530 } 531 532 // PruneOrdering removes any columns referenced by an OrderingChoice that are 533 // not part of the needed column set. Should only be called if 534 // OrderingCanProjectCols is true. 535 func (c *CustomFuncs) PruneOrdering( 536 ordering physical.OrderingChoice, needed opt.ColSet, 537 ) physical.OrderingChoice { 538 if ordering.SubsetOfCols(needed) { 539 return ordering 540 } 541 ordCopy := ordering.Copy() 542 ordCopy.ProjectCols(needed) 543 return ordCopy 544 } 545 546 // EmptyOrdering returns a pseudo-choice that does not require any 547 // ordering. 548 func (c *CustomFuncs) EmptyOrdering() physical.OrderingChoice { 549 return physical.OrderingChoice{} 550 } 551 552 // OrderingIntersects returns true if <ordering1> and <ordering2> have an 553 // intersection. See OrderingChoice.Intersection for more information. 554 func (c *CustomFuncs) OrderingIntersects(ordering1, ordering2 physical.OrderingChoice) bool { 555 return ordering1.Intersects(&ordering2) 556 } 557 558 // OrderingIntersection returns the intersection of two orderings. Should only be 559 // called if it is known that an intersection exists. 560 // See OrderingChoice.Intersection for more information. 561 func (c *CustomFuncs) OrderingIntersection( 562 ordering1, ordering2 physical.OrderingChoice, 563 ) physical.OrderingChoice { 564 return ordering1.Intersection(&ordering2) 565 } 566 567 // OrdinalityOrdering returns an ordinality operator's ordering choice. 568 func (c *CustomFuncs) OrdinalityOrdering(private *memo.OrdinalityPrivate) physical.OrderingChoice { 569 return private.Ordering 570 } 571 572 // IsSameOrdering evaluates whether the two orderings are equal. 573 func (c *CustomFuncs) IsSameOrdering( 574 first physical.OrderingChoice, other physical.OrderingChoice, 575 ) bool { 576 return first.Equals(&other) 577 } 578 579 // ----------------------------------------------------------------------- 580 // 581 // Filter functions 582 // General functions used to test and construct filters. 583 // 584 // ----------------------------------------------------------------------- 585 586 // FilterHasCorrelatedSubquery returns true if any of the filter conditions 587 // contain a correlated subquery. 588 func (c *CustomFuncs) FilterHasCorrelatedSubquery(filters memo.FiltersExpr) bool { 589 for i := range filters { 590 if filters[i].ScalarProps().HasCorrelatedSubquery { 591 return true 592 } 593 } 594 return false 595 } 596 597 // IsFilterFalse returns true if the filters always evaluate to false. The only 598 // case that's checked is the fully normalized case, when the list contains a 599 // single False condition. 600 func (c *CustomFuncs) IsFilterFalse(filters memo.FiltersExpr) bool { 601 return filters.IsFalse() 602 } 603 604 // IsContradiction returns true if the given filter item contains a 605 // contradiction constraint. 606 func (c *CustomFuncs) IsContradiction(item *memo.FiltersItem) bool { 607 return item.ScalarProps().Constraints == constraint.Contradiction 608 } 609 610 // ConcatFilters creates a new Filters operator that contains conditions from 611 // both the left and right boolean filter expressions. 612 func (c *CustomFuncs) ConcatFilters(left, right memo.FiltersExpr) memo.FiltersExpr { 613 // No need to recompute properties on the new filters, since they should 614 // still be valid. 615 newFilters := make(memo.FiltersExpr, len(left)+len(right)) 616 copy(newFilters, left) 617 copy(newFilters[len(left):], right) 618 return newFilters 619 } 620 621 // RemoveFiltersItem returns a new list that is a copy of the given list, except 622 // that it does not contain the given search item. If the list contains the item 623 // multiple times, then only the first instance is removed. If the list does not 624 // contain the item, then the method panics. 625 func (c *CustomFuncs) RemoveFiltersItem( 626 filters memo.FiltersExpr, search *memo.FiltersItem, 627 ) memo.FiltersExpr { 628 newFilters := make(memo.FiltersExpr, len(filters)-1) 629 for i := range filters { 630 if search == &filters[i] { 631 copy(newFilters, filters[:i]) 632 copy(newFilters[i:], filters[i+1:]) 633 return newFilters 634 } 635 } 636 panic(errors.AssertionFailedf("item to remove is not in the list: %v", search)) 637 } 638 639 // ReplaceFiltersItem returns a new list that is a copy of the given list, 640 // except that the given search item has been replaced by the given replace 641 // item. If the list contains the search item multiple times, then only the 642 // first instance is replaced. If the list does not contain the item, then the 643 // method panics. 644 func (c *CustomFuncs) ReplaceFiltersItem( 645 filters memo.FiltersExpr, search *memo.FiltersItem, replace opt.ScalarExpr, 646 ) memo.FiltersExpr { 647 newFilters := make([]memo.FiltersItem, len(filters)) 648 for i := range filters { 649 if search == &filters[i] { 650 copy(newFilters, filters[:i]) 651 newFilters[i] = c.f.ConstructFiltersItem(replace) 652 copy(newFilters[i+1:], filters[i+1:]) 653 return newFilters 654 } 655 } 656 panic(errors.AssertionFailedf("item to replace is not in the list: %v", search)) 657 } 658 659 // ExtractBoundConditions returns a new list containing only those expressions 660 // from the given list that are fully bound by the given columns (i.e. all 661 // outer references are to one of these columns). For example: 662 // 663 // (InnerJoin 664 // (Scan a) 665 // (Scan b) 666 // (Filters [ 667 // (Eq (Variable a.x) (Variable b.x)) 668 // (Gt (Variable a.x) (Const 1)) 669 // ]) 670 // ) 671 // 672 // Calling ExtractBoundConditions with the filter conditions list and the output 673 // columns of (Scan a) would extract the (Gt) expression, since its outer 674 // references only reference columns from a. 675 func (c *CustomFuncs) ExtractBoundConditions( 676 filters memo.FiltersExpr, cols opt.ColSet, 677 ) memo.FiltersExpr { 678 newFilters := make(memo.FiltersExpr, 0, len(filters)) 679 for i := range filters { 680 if c.IsBoundBy(&filters[i], cols) { 681 newFilters = append(newFilters, filters[i]) 682 } 683 } 684 return newFilters 685 } 686 687 // ExtractUnboundConditions is the opposite of ExtractBoundConditions. Instead of 688 // extracting expressions that are bound by the given columns, it extracts 689 // list expressions that have at least one outer reference that is *not* bound 690 // by the given columns (i.e. it has a "free" variable). 691 func (c *CustomFuncs) ExtractUnboundConditions( 692 filters memo.FiltersExpr, cols opt.ColSet, 693 ) memo.FiltersExpr { 694 newFilters := make(memo.FiltersExpr, 0, len(filters)) 695 for i := range filters { 696 if !c.IsBoundBy(&filters[i], cols) { 697 newFilters = append(newFilters, filters[i]) 698 } 699 } 700 return newFilters 701 } 702 703 // ---------------------------------------------------------------------- 704 // 705 // Project functions 706 // General functions related to Project operators. 707 // 708 // ---------------------------------------------------------------------- 709 710 // ProjectionCols returns the ids of the columns synthesized by the given 711 // Projections operator. 712 func (c *CustomFuncs) ProjectionCols(projections memo.ProjectionsExpr) opt.ColSet { 713 var colSet opt.ColSet 714 for i := range projections { 715 colSet.Add(projections[i].Col) 716 } 717 return colSet 718 } 719 720 // ProjectExtraCol constructs a new Project operator that passes through all 721 // columns in the given "in" expression, and then adds the given "extra" 722 // expression as an additional column. 723 func (c *CustomFuncs) ProjectExtraCol( 724 in memo.RelExpr, extra opt.ScalarExpr, extraID opt.ColumnID, 725 ) memo.RelExpr { 726 projections := memo.ProjectionsExpr{c.f.ConstructProjectionsItem(extra, extraID)} 727 return c.f.ConstructProject(in, projections, in.Relational().OutputCols) 728 } 729 730 // ---------------------------------------------------------------------- 731 // 732 // Values functions 733 // General functions related to Values operators. 734 // 735 // ---------------------------------------------------------------------- 736 737 // ValuesCols returns the Cols field of the ValuesPrivate struct. 738 func (c *CustomFuncs) ValuesCols(valuesPrivate *memo.ValuesPrivate) opt.ColList { 739 return valuesPrivate.Cols 740 } 741 742 // ConstructEmptyValues constructs a Values expression with no rows. 743 func (c *CustomFuncs) ConstructEmptyValues(cols opt.ColSet) memo.RelExpr { 744 colList := make(opt.ColList, 0, cols.Len()) 745 for i, ok := cols.Next(0); ok; i, ok = cols.Next(i + 1) { 746 colList = append(colList, i) 747 } 748 return c.f.ConstructValues(memo.EmptyScalarListExpr, &memo.ValuesPrivate{ 749 Cols: colList, 750 ID: c.mem.Metadata().NextUniqueID(), 751 }) 752 } 753 754 // ---------------------------------------------------------------------- 755 // 756 // Grouping functions 757 // General functions related to grouping expressions such as GroupBy, 758 // DistinctOn, etc. 759 // 760 // ---------------------------------------------------------------------- 761 762 // GroupingOutputCols returns the output columns of a GroupBy, ScalarGroupBy, or 763 // DistinctOn expression. 764 func (c *CustomFuncs) GroupingOutputCols( 765 grouping *memo.GroupingPrivate, aggs memo.AggregationsExpr, 766 ) opt.ColSet { 767 result := grouping.GroupingCols.Copy() 768 for i := range aggs { 769 result.Add(aggs[i].Col) 770 } 771 return result 772 } 773 774 // GroupingCols returns the grouping columns from the given grouping private. 775 func (c *CustomFuncs) GroupingCols(grouping *memo.GroupingPrivate) opt.ColSet { 776 return grouping.GroupingCols 777 } 778 779 // AddColsToGrouping returns a new GroupByDef that is a copy of the given 780 // GroupingPrivate, except with the given set of grouping columns union'ed with 781 // the existing grouping columns. 782 func (c *CustomFuncs) AddColsToGrouping( 783 private *memo.GroupingPrivate, groupingCols opt.ColSet, 784 ) *memo.GroupingPrivate { 785 p := *private 786 p.GroupingCols = private.GroupingCols.Union(groupingCols) 787 return &p 788 } 789 790 // ExtractAggInputColumns returns the set of columns the aggregate depends on. 791 func (c *CustomFuncs) ExtractAggInputColumns(e opt.ScalarExpr) opt.ColSet { 792 return memo.ExtractAggInputColumns(e) 793 } 794 795 // IsUnorderedGrouping returns true if the given grouping ordering is not 796 // specified. 797 func (c *CustomFuncs) IsUnorderedGrouping(grouping *memo.GroupingPrivate) bool { 798 return grouping.Ordering.Any() 799 } 800 801 // MakeGrouping constructs a new GroupingPrivate using the given grouping 802 // columns and OrderingChoice. ErrorOnDup will be empty and NullsAreDistinct 803 // will be false. 804 func (c *CustomFuncs) MakeGrouping( 805 groupingCols opt.ColSet, ordering physical.OrderingChoice, 806 ) *memo.GroupingPrivate { 807 return &memo.GroupingPrivate{GroupingCols: groupingCols, Ordering: ordering} 808 } 809 810 // MakeErrorOnDupGrouping constructs a new GroupingPrivate using the given 811 // grouping columns, OrderingChoice, and ErrorOnDup text. NullsAreDistinct will 812 // be false. 813 func (c *CustomFuncs) MakeErrorOnDupGrouping( 814 groupingCols opt.ColSet, ordering physical.OrderingChoice, errorText string, 815 ) *memo.GroupingPrivate { 816 return &memo.GroupingPrivate{ 817 GroupingCols: groupingCols, Ordering: ordering, ErrorOnDup: errorText, 818 } 819 } 820 821 // NullsAreDistinct returns true if a distinct operator with the given 822 // GroupingPrivate treats NULL values as not equal to one another 823 // (i.e. distinct). UpsertDistinctOp and EnsureUpsertDistinctOp treat NULL 824 // values as distinct, whereas DistinctOp does not. 825 func (c *CustomFuncs) NullsAreDistinct(private *memo.GroupingPrivate) bool { 826 return private.NullsAreDistinct 827 } 828 829 // ErrorOnDup returns the error text contained by the given GroupingPrivate. 830 func (c *CustomFuncs) ErrorOnDup(private *memo.GroupingPrivate) string { 831 return private.ErrorOnDup 832 } 833 834 // ExtractGroupingOrdering returns the ordering associated with the input 835 // GroupingPrivate. 836 func (c *CustomFuncs) ExtractGroupingOrdering( 837 private *memo.GroupingPrivate, 838 ) physical.OrderingChoice { 839 return private.Ordering 840 } 841 842 // ---------------------------------------------------------------------- 843 // 844 // Join functions 845 // General functions related to join operators. 846 // 847 // ---------------------------------------------------------------------- 848 849 // JoinDoesNotDuplicateLeftRows returns true if the given InnerJoin, LeftJoin or 850 // FullJoin is guaranteed not to output any given row from its left input more 851 // than once. 852 func (c *CustomFuncs) JoinDoesNotDuplicateLeftRows(join memo.RelExpr) bool { 853 mult := memo.DeriveJoinMultiplicity(join) 854 return mult.JoinDoesNotDuplicateLeftRows() 855 } 856 857 // JoinDoesNotDuplicateRightRows returns true if the given InnerJoin, LeftJoin 858 // or FullJoin is guaranteed not to output any given row from its right input 859 // more than once. 860 func (c *CustomFuncs) JoinDoesNotDuplicateRightRows(join memo.RelExpr) bool { 861 mult := memo.DeriveJoinMultiplicity(join) 862 return mult.JoinDoesNotDuplicateRightRows() 863 } 864 865 // JoinPreservesLeftRows returns true if the given InnerJoin, LeftJoin or 866 // FullJoin is guaranteed to output every row from its left input at least once. 867 func (c *CustomFuncs) JoinPreservesLeftRows(join memo.RelExpr) bool { 868 mult := memo.DeriveJoinMultiplicity(join) 869 return mult.JoinPreservesLeftRows() 870 } 871 872 // JoinPreservesRightRows returns true if the given InnerJoin, LeftJoin or 873 // FullJoin is guaranteed to output every row from its right input at least 874 // once. 875 func (c *CustomFuncs) JoinPreservesRightRows(join memo.RelExpr) bool { 876 mult := memo.DeriveJoinMultiplicity(join) 877 return mult.JoinPreservesRightRows() 878 } 879 880 // ---------------------------------------------------------------------- 881 // 882 // Constant value functions 883 // General functions related to constant values and datums. 884 // 885 // ---------------------------------------------------------------------- 886 887 // IsPositiveInt is true if the given Datum value is greater than zero. 888 func (c *CustomFuncs) IsPositiveInt(datum tree.Datum) bool { 889 val := int64(*datum.(*tree.DInt)) 890 return val > 0 891 } 892 893 // EqualsString returns true if the given strings are equal. This function is 894 // useful in matching expressions that have string fields. 895 // 896 // For example, NormalizeCmpTimeZoneFunction uses this function implicitly to 897 // match a specific function, like so: 898 // 899 // (Function $args:* (FunctionPrivate "timezone")) 900 // 901 func (c *CustomFuncs) EqualsString(left string, right string) bool { 902 return left == right 903 } 904 905 // EqualsNumber returns true if the given numeric value (decimal, float, or 906 // integer) is equal to the given integer value. 907 func (c *CustomFuncs) EqualsNumber(datum tree.Datum, value int64) bool { 908 switch t := datum.(type) { 909 case *tree.DDecimal: 910 if value == 0 { 911 return t.Decimal.IsZero() 912 } else if value == 1 { 913 return t.Decimal.Cmp(&tree.DecimalOne.Decimal) == 0 914 } 915 var dec apd.Decimal 916 dec.SetInt64(value) 917 return t.Decimal.Cmp(&dec) == 0 918 919 case *tree.DFloat: 920 return *t == tree.DFloat(value) 921 922 case *tree.DInt: 923 return *t == tree.DInt(value) 924 } 925 return false 926 } 927 928 // AddConstInts adds the numeric constants together and constructs a Const. 929 // AddConstInts assumes the sum will not overflow. Call CanAddConstInts on the 930 // constants to guarantee this. 931 func (c *CustomFuncs) AddConstInts(first tree.Datum, second tree.Datum) opt.ScalarExpr { 932 firstVal := int64(*first.(*tree.DInt)) 933 secondVal := int64(*second.(*tree.DInt)) 934 sum, ok := arith.AddWithOverflow(firstVal, secondVal) 935 if !ok { 936 panic(errors.AssertionFailedf("addition of %d and %d overflowed", firstVal, secondVal)) 937 } 938 return c.f.ConstructConst(tree.NewDInt(tree.DInt(sum)), types.Int) 939 } 940 941 // CanAddConstInts returns true if the addition of the two integers overflows. 942 func (c *CustomFuncs) CanAddConstInts(first tree.Datum, second tree.Datum) bool { 943 firstVal := int64(*first.(*tree.DInt)) 944 secondVal := int64(*second.(*tree.DInt)) 945 _, ok := arith.AddWithOverflow(firstVal, secondVal) 946 return ok 947 } 948 949 // IntConst constructs a Const holding a DInt. 950 func (c *CustomFuncs) IntConst(d *tree.DInt) opt.ScalarExpr { 951 return c.f.ConstructConst(d, types.Int) 952 }