github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/exec/execbuilder/scalar.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 execbuilder 12 13 import ( 14 "github.com/cockroachdb/cockroach/pkg/sql/opt" 15 "github.com/cockroachdb/cockroach/pkg/sql/opt/exec" 16 "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" 17 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 18 "github.com/cockroachdb/cockroach/pkg/sql/types" 19 "github.com/cockroachdb/cockroach/pkg/util/log" 20 "github.com/cockroachdb/errors" 21 ) 22 23 type buildScalarCtx struct { 24 ivh tree.IndexedVarHelper 25 26 // ivarMap is a map from opt.ColumnID to the index of an IndexedVar. 27 // If a ColumnID is not in the map, it cannot appear in the expression. 28 ivarMap opt.ColMap 29 } 30 31 type buildFunc func(b *Builder, ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) 32 33 var scalarBuildFuncMap [opt.NumOperators]buildFunc 34 35 func init() { 36 // This code is not inline to avoid an initialization loop error (some of 37 // the functions depend on scalarBuildFuncMap which in turn depends on the 38 // functions). 39 scalarBuildFuncMap = [opt.NumOperators]buildFunc{ 40 opt.VariableOp: (*Builder).buildVariable, 41 opt.ConstOp: (*Builder).buildTypedExpr, 42 opt.NullOp: (*Builder).buildNull, 43 opt.PlaceholderOp: (*Builder).buildTypedExpr, 44 opt.TupleOp: (*Builder).buildTuple, 45 opt.FunctionOp: (*Builder).buildFunction, 46 opt.CaseOp: (*Builder).buildCase, 47 opt.CastOp: (*Builder).buildCast, 48 opt.CoalesceOp: (*Builder).buildCoalesce, 49 opt.ColumnAccessOp: (*Builder).buildColumnAccess, 50 opt.ArrayOp: (*Builder).buildArray, 51 opt.AnyOp: (*Builder).buildAny, 52 opt.AnyScalarOp: (*Builder).buildAnyScalar, 53 opt.IndirectionOp: (*Builder).buildIndirection, 54 opt.CollateOp: (*Builder).buildCollate, 55 opt.ArrayFlattenOp: (*Builder).buildArrayFlatten, 56 opt.IfErrOp: (*Builder).buildIfErr, 57 opt.UnsupportedExprOp: (*Builder).buildUnsupportedExpr, 58 59 // Item operators. 60 opt.ProjectionsItemOp: (*Builder).buildItem, 61 opt.AggregationsItemOp: (*Builder).buildItem, 62 63 // Subquery operators. 64 opt.ExistsOp: (*Builder).buildExistsSubquery, 65 opt.SubqueryOp: (*Builder).buildSubquery, 66 } 67 68 for _, op := range opt.BoolOperators { 69 if scalarBuildFuncMap[op] == nil { 70 scalarBuildFuncMap[op] = (*Builder).buildBoolean 71 } 72 } 73 74 for _, op := range opt.ComparisonOperators { 75 scalarBuildFuncMap[op] = (*Builder).buildComparison 76 } 77 78 for _, op := range opt.BinaryOperators { 79 scalarBuildFuncMap[op] = (*Builder).buildBinary 80 } 81 82 for _, op := range opt.UnaryOperators { 83 scalarBuildFuncMap[op] = (*Builder).buildUnary 84 } 85 } 86 87 // buildScalar converts a scalar expression to a TypedExpr. Variables are mapped 88 // according to ctx. 89 func (b *Builder) buildScalar(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 90 if fn := scalarBuildFuncMap[scalar.Op()]; fn != nil { 91 texpr, err := fn(b, ctx, scalar) 92 if err != nil { 93 return nil, err 94 } 95 if b.evalCtx != nil && b.isConst(texpr) { 96 value, err := texpr.Eval(b.evalCtx) 97 if err != nil { 98 if errors.IsAssertionFailure(err) { 99 return nil, err 100 } 101 // Ignore any errors here (e.g. division by zero), so they can happen 102 // during execution where they are correctly handled. Note that in some 103 // cases we might not even get an error (if this particular expression 104 // does not get evaluated when the query runs, e.g. it's inside a CASE). 105 return texpr, nil 106 } 107 if value == tree.DNull { 108 // We don't want to return an expression that has a different type; cast 109 // the NULL if necessary. 110 return tree.ReType(tree.DNull, texpr.ResolvedType()), nil 111 } 112 return value, nil 113 } 114 return texpr, nil 115 } 116 return nil, errors.Errorf("unsupported op %s", scalar.Op()) 117 } 118 119 func (b *Builder) buildTypedExpr( 120 ctx *buildScalarCtx, scalar opt.ScalarExpr, 121 ) (tree.TypedExpr, error) { 122 return scalar.Private().(tree.TypedExpr), nil 123 } 124 125 func (b *Builder) buildNull(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 126 return tree.ReType(tree.DNull, scalar.DataType()), nil 127 } 128 129 func (b *Builder) buildVariable( 130 ctx *buildScalarCtx, scalar opt.ScalarExpr, 131 ) (tree.TypedExpr, error) { 132 return b.indexedVar(ctx, b.mem.Metadata(), *scalar.Private().(*opt.ColumnID)), nil 133 } 134 135 func (b *Builder) indexedVar( 136 ctx *buildScalarCtx, md *opt.Metadata, colID opt.ColumnID, 137 ) tree.TypedExpr { 138 idx, ok := ctx.ivarMap.Get(int(colID)) 139 if !ok { 140 panic(errors.AssertionFailedf("cannot map variable %d to an indexed var", log.Safe(colID))) 141 } 142 return ctx.ivh.IndexedVarWithType(idx, md.ColumnMeta(colID).Type) 143 } 144 145 func (b *Builder) buildTuple(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 146 if memo.CanExtractConstTuple(scalar) { 147 return memo.ExtractConstDatum(scalar), nil 148 } 149 150 tup := scalar.(*memo.TupleExpr) 151 typedExprs := make(tree.Exprs, len(tup.Elems)) 152 var err error 153 for i, elem := range tup.Elems { 154 typedExprs[i], err = b.buildScalar(ctx, elem) 155 if err != nil { 156 return nil, err 157 } 158 } 159 return tree.NewTypedTuple(tup.Typ, typedExprs), nil 160 } 161 162 func (b *Builder) buildBoolean(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 163 switch scalar.Op() { 164 case opt.FiltersOp: 165 if scalar.ChildCount() == 0 { 166 // This can happen if the expression is not normalized (build tests). 167 return tree.DBoolTrue, nil 168 } 169 fallthrough 170 171 case opt.AndOp, opt.OrOp: 172 expr, err := b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 173 if err != nil { 174 return nil, err 175 } 176 for i, n := 1, scalar.ChildCount(); i < n; i++ { 177 right, err := b.buildScalar(ctx, scalar.Child(i).(opt.ScalarExpr)) 178 if err != nil { 179 return nil, err 180 } 181 if scalar.Op() == opt.OrOp { 182 expr = tree.NewTypedOrExpr(expr, right) 183 } else { 184 expr = tree.NewTypedAndExpr(expr, right) 185 } 186 } 187 return expr, nil 188 189 case opt.NotOp: 190 expr, err := b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 191 if err != nil { 192 return nil, err 193 } 194 return tree.NewTypedNotExpr(expr), nil 195 196 case opt.TrueOp: 197 return tree.DBoolTrue, nil 198 199 case opt.FalseOp: 200 return tree.DBoolFalse, nil 201 202 case opt.FiltersItemOp: 203 return b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 204 205 case opt.RangeOp: 206 return b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 207 208 case opt.IsTupleNullOp: 209 expr, err := b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 210 if err != nil { 211 return nil, err 212 } 213 return tree.NewTypedIsNullExpr(expr), nil 214 215 case opt.IsTupleNotNullOp: 216 expr, err := b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 217 if err != nil { 218 return nil, err 219 } 220 return tree.NewTypedIsNotNullExpr(expr), nil 221 222 default: 223 panic(errors.AssertionFailedf("invalid op %s", log.Safe(scalar.Op()))) 224 } 225 } 226 227 func (b *Builder) buildComparison( 228 ctx *buildScalarCtx, scalar opt.ScalarExpr, 229 ) (tree.TypedExpr, error) { 230 left, err := b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 231 if err != nil { 232 return nil, err 233 } 234 right, err := b.buildScalar(ctx, scalar.Child(1).(opt.ScalarExpr)) 235 if err != nil { 236 return nil, err 237 } 238 239 // When the operator is an IsOp, the right is NULL, and the left is not a 240 // tuple, return the unary tree.IsNullExpr. 241 if scalar.Op() == opt.IsOp && right == tree.DNull && left.ResolvedType().Family() != types.TupleFamily { 242 return tree.NewTypedIsNullExpr(left), nil 243 } 244 245 // When the operator is an IsNotOp, the right is NULL, and the left is not a 246 // tuple, return the unary tree.IsNotNullExpr. 247 if scalar.Op() == opt.IsNotOp && right == tree.DNull && left.ResolvedType().Family() != types.TupleFamily { 248 return tree.NewTypedIsNotNullExpr(left), nil 249 } 250 251 operator := opt.ComparisonOpReverseMap[scalar.Op()] 252 return tree.NewTypedComparisonExpr(operator, left, right), nil 253 } 254 255 func (b *Builder) buildUnary(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 256 input, err := b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 257 if err != nil { 258 return nil, err 259 } 260 operator := opt.UnaryOpReverseMap[scalar.Op()] 261 return tree.NewTypedUnaryExpr(operator, input, scalar.DataType()), nil 262 } 263 264 func (b *Builder) buildBinary(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 265 left, err := b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 266 if err != nil { 267 return nil, err 268 } 269 right, err := b.buildScalar(ctx, scalar.Child(1).(opt.ScalarExpr)) 270 if err != nil { 271 return nil, err 272 } 273 operator := opt.BinaryOpReverseMap[scalar.Op()] 274 return tree.NewTypedBinaryExpr(operator, left, right, scalar.DataType()), nil 275 } 276 277 func (b *Builder) buildFunction( 278 ctx *buildScalarCtx, scalar opt.ScalarExpr, 279 ) (tree.TypedExpr, error) { 280 fn := scalar.(*memo.FunctionExpr) 281 exprs := make(tree.TypedExprs, len(fn.Args)) 282 var err error 283 for i := range exprs { 284 exprs[i], err = b.buildScalar(ctx, fn.Args[i]) 285 if err != nil { 286 return nil, err 287 } 288 } 289 funcRef := tree.WrapFunction(fn.Name) 290 return tree.NewTypedFuncExpr( 291 funcRef, 292 0, /* aggQualifier */ 293 exprs, 294 nil, /* filter */ 295 nil, /* windowDef */ 296 fn.Typ, 297 fn.Properties, 298 fn.Overload, 299 ), nil 300 } 301 302 func (b *Builder) buildCase(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 303 cas := scalar.(*memo.CaseExpr) 304 input, err := b.buildScalar(ctx, cas.Input) 305 if err != nil { 306 return nil, err 307 } 308 309 // A searched CASE statement is represented by the optimizer with input=True. 310 // The executor expects searched CASE statements to have nil inputs. 311 if input == tree.DBoolTrue { 312 input = nil 313 } 314 315 // Extract the list of WHEN ... THEN ... clauses. 316 whens := make([]*tree.When, len(cas.Whens)) 317 for i, expr := range cas.Whens { 318 whenExpr := expr.(*memo.WhenExpr) 319 cond, err := b.buildScalar(ctx, whenExpr.Condition) 320 if err != nil { 321 return nil, err 322 } 323 val, err := b.buildScalar(ctx, whenExpr.Value) 324 if err != nil { 325 return nil, err 326 } 327 whens[i] = &tree.When{Cond: cond, Val: val} 328 } 329 330 elseExpr, err := b.buildScalar(ctx, cas.OrElse) 331 if err != nil { 332 return nil, err 333 } 334 if elseExpr == tree.DNull { 335 elseExpr = nil 336 } 337 338 return tree.NewTypedCaseExpr(input, whens, elseExpr, cas.Typ) 339 } 340 341 func (b *Builder) buildCast(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 342 cast := scalar.(*memo.CastExpr) 343 input, err := b.buildScalar(ctx, cast.Input) 344 if err != nil { 345 return nil, err 346 } 347 return tree.NewTypedCastExpr(input, cast.Typ), nil 348 } 349 350 func (b *Builder) buildCoalesce( 351 ctx *buildScalarCtx, scalar opt.ScalarExpr, 352 ) (tree.TypedExpr, error) { 353 coalesce := scalar.(*memo.CoalesceExpr) 354 exprs := make(tree.TypedExprs, len(coalesce.Args)) 355 var err error 356 for i := range exprs { 357 exprs[i], err = b.buildScalar(ctx, coalesce.Args[i]) 358 if err != nil { 359 return nil, err 360 } 361 } 362 return tree.NewTypedCoalesceExpr(exprs, coalesce.Typ), nil 363 } 364 365 func (b *Builder) buildColumnAccess( 366 ctx *buildScalarCtx, scalar opt.ScalarExpr, 367 ) (tree.TypedExpr, error) { 368 colAccess := scalar.(*memo.ColumnAccessExpr) 369 input, err := b.buildScalar(ctx, colAccess.Input) 370 if err != nil { 371 return nil, err 372 } 373 childTyp := colAccess.Input.DataType() 374 colIdx := int(colAccess.Idx) 375 // Find a label if there is one. It's OK if there isn't. 376 lbl := "" 377 if childTyp.TupleLabels() != nil { 378 lbl = childTyp.TupleLabels()[colIdx] 379 } 380 return tree.NewTypedColumnAccessExpr(input, lbl, colIdx), nil 381 } 382 383 func (b *Builder) buildArray(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 384 arr := scalar.(*memo.ArrayExpr) 385 if memo.CanExtractConstDatum(scalar) { 386 return memo.ExtractConstDatum(scalar), nil 387 } 388 exprs := make(tree.TypedExprs, len(arr.Elems)) 389 var err error 390 for i := range exprs { 391 exprs[i], err = b.buildScalar(ctx, arr.Elems[i]) 392 if err != nil { 393 return nil, err 394 } 395 } 396 return tree.NewTypedArray(exprs, arr.Typ), nil 397 } 398 399 func (b *Builder) buildAnyScalar( 400 ctx *buildScalarCtx, scalar opt.ScalarExpr, 401 ) (tree.TypedExpr, error) { 402 any := scalar.(*memo.AnyScalarExpr) 403 left, err := b.buildScalar(ctx, any.Left) 404 if err != nil { 405 return nil, err 406 } 407 408 right, err := b.buildScalar(ctx, any.Right) 409 if err != nil { 410 return nil, err 411 } 412 413 cmp := opt.ComparisonOpReverseMap[any.Cmp] 414 return tree.NewTypedComparisonExprWithSubOp(tree.Any, cmp, left, right), nil 415 } 416 417 func (b *Builder) buildIndirection( 418 ctx *buildScalarCtx, scalar opt.ScalarExpr, 419 ) (tree.TypedExpr, error) { 420 expr, err := b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 421 if err != nil { 422 return nil, err 423 } 424 425 index, err := b.buildScalar(ctx, scalar.Child(1).(opt.ScalarExpr)) 426 if err != nil { 427 return nil, err 428 } 429 430 return tree.NewTypedIndirectionExpr(expr, index, scalar.DataType()), nil 431 } 432 433 func (b *Builder) buildCollate(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 434 expr, err := b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 435 if err != nil { 436 return nil, err 437 } 438 439 return tree.NewTypedCollateExpr(expr, scalar.(*memo.CollateExpr).Locale), nil 440 } 441 442 func (b *Builder) buildArrayFlatten( 443 ctx *buildScalarCtx, scalar opt.ScalarExpr, 444 ) (tree.TypedExpr, error) { 445 af := scalar.(*memo.ArrayFlattenExpr) 446 447 // The subquery here should always be uncorrelated: if it were not, we would 448 // have converted it to an aggregation. 449 if !af.Input.Relational().OuterCols.Empty() { 450 panic(errors.AssertionFailedf("input to ArrayFlatten should be uncorrelated")) 451 } 452 453 root, err := b.buildRelational(af.Input) 454 if err != nil { 455 return nil, err 456 } 457 458 typ := b.mem.Metadata().ColumnMeta(af.RequestedCol).Type 459 e := b.addSubquery(exec.SubqueryAllRows, typ, root.root, af.OriginalExpr) 460 461 return tree.NewTypedArrayFlattenExpr(e), nil 462 } 463 464 func (b *Builder) buildIfErr(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 465 ifErr := scalar.(*memo.IfErrExpr) 466 cond, err := b.buildScalar(ctx, ifErr.Cond.(opt.ScalarExpr)) 467 if err != nil { 468 return nil, err 469 } 470 471 var orElse tree.TypedExpr 472 if ifErr.OrElse.ChildCount() > 0 { 473 orElse, err = b.buildScalar(ctx, ifErr.OrElse.Child(0).(opt.ScalarExpr)) 474 if err != nil { 475 return nil, err 476 } 477 } 478 479 var errCode tree.TypedExpr 480 if ifErr.ErrCode.ChildCount() > 0 { 481 errCode, err = b.buildScalar(ctx, ifErr.ErrCode.Child(0).(opt.ScalarExpr)) 482 if err != nil { 483 return nil, err 484 } 485 } 486 487 return tree.NewTypedIfErrExpr(cond, orElse, errCode), nil 488 } 489 490 func (b *Builder) buildUnsupportedExpr( 491 ctx *buildScalarCtx, scalar opt.ScalarExpr, 492 ) (tree.TypedExpr, error) { 493 return scalar.(*memo.UnsupportedExprExpr).Value, nil 494 } 495 496 func (b *Builder) buildItem(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 497 return b.buildScalar(ctx, scalar.Child(0).(opt.ScalarExpr)) 498 } 499 500 func (b *Builder) buildAny(ctx *buildScalarCtx, scalar opt.ScalarExpr) (tree.TypedExpr, error) { 501 any := scalar.(*memo.AnyExpr) 502 // We cannot execute correlated subqueries. 503 if !any.Input.Relational().OuterCols.Empty() { 504 return nil, b.decorrelationError() 505 } 506 507 // Build the execution plan for the input subquery. 508 plan, err := b.buildRelational(any.Input) 509 if err != nil { 510 return nil, err 511 } 512 513 // Construct tuple type of columns in the row. 514 contents := make([]*types.T, plan.numOutputCols()) 515 plan.outputCols.ForEach(func(key, val int) { 516 contents[val] = b.mem.Metadata().ColumnMeta(opt.ColumnID(key)).Type 517 }) 518 typs := types.MakeTuple(contents) 519 subqueryExpr := b.addSubquery(exec.SubqueryAnyRows, typs, plan.root, any.OriginalExpr) 520 521 // Build the scalar value that is compared against each row. 522 scalarExpr, err := b.buildScalar(ctx, any.Scalar) 523 if err != nil { 524 return nil, err 525 } 526 527 cmp := opt.ComparisonOpReverseMap[any.Cmp] 528 return tree.NewTypedComparisonExprWithSubOp(tree.Any, cmp, scalarExpr, subqueryExpr), nil 529 } 530 531 func (b *Builder) buildExistsSubquery( 532 ctx *buildScalarCtx, scalar opt.ScalarExpr, 533 ) (tree.TypedExpr, error) { 534 exists := scalar.(*memo.ExistsExpr) 535 // We cannot execute correlated subqueries. 536 if !exists.Input.Relational().OuterCols.Empty() { 537 return nil, b.decorrelationError() 538 } 539 540 // Build the execution plan for the subquery. Note that the subquery could 541 // have subqueries of its own which are added to b.subqueries. 542 plan, err := b.buildRelational(exists.Input) 543 if err != nil { 544 return nil, err 545 } 546 547 return b.addSubquery(exec.SubqueryExists, types.Bool, plan.root, exists.OriginalExpr), nil 548 } 549 550 func (b *Builder) buildSubquery( 551 ctx *buildScalarCtx, scalar opt.ScalarExpr, 552 ) (tree.TypedExpr, error) { 553 subquery := scalar.(*memo.SubqueryExpr) 554 input := subquery.Input 555 556 // TODO(radu): for now we only support the trivial projection. 557 cols := input.Relational().OutputCols 558 if cols.Len() != 1 { 559 return nil, errors.Errorf("subquery input with multiple columns") 560 } 561 562 // We cannot execute correlated subqueries. 563 if !input.Relational().OuterCols.Empty() { 564 return nil, b.decorrelationError() 565 } 566 567 // Build the execution plan for the subquery. Note that the subquery could 568 // have subqueries of its own which are added to b.subqueries. 569 plan, err := b.buildRelational(input) 570 if err != nil { 571 return nil, err 572 } 573 574 return b.addSubquery(exec.SubqueryOneRow, subquery.Typ, plan.root, subquery.OriginalExpr), nil 575 } 576 577 // addSubquery adds an entry to b.subqueries and creates a tree.Subquery 578 // expression node associated with it. 579 func (b *Builder) addSubquery( 580 mode exec.SubqueryMode, typ *types.T, root exec.Node, originalExpr *tree.Subquery, 581 ) *tree.Subquery { 582 var originalSelect tree.SelectStatement 583 if originalExpr != nil { 584 originalSelect = originalExpr.Select 585 } 586 exprNode := &tree.Subquery{ 587 Select: originalSelect, 588 Exists: mode == exec.SubqueryExists, 589 } 590 exprNode.SetType(typ) 591 b.subqueries = append(b.subqueries, exec.Subquery{ 592 ExprNode: exprNode, 593 Mode: mode, 594 Root: root, 595 }) 596 // Associate the tree.Subquery expression node with this subquery 597 // by index (1-based). 598 exprNode.Idx = len(b.subqueries) 599 return exprNode 600 } 601 602 func (b *Builder) isConst(expr tree.Expr) bool { 603 return b.fastIsConstVisitor.run(expr) 604 } 605 606 // fastIsConstVisitor determines if an expression is constant by visiting 607 // at most two levels of the tree (with one exception, see below). 608 // In essence, it determines whether an expression is constant by checking 609 // whether its children are const Datums. 610 // 611 // This can be used by the execbuilder since constants are evaluated 612 // bottom-up. If a child is *not* a const Datum, that means it was already 613 // determined to be non-constant, and therefore was not evaluated. 614 type fastIsConstVisitor struct { 615 isConst bool 616 617 // visited indicates whether we have already visited one level of the tree. 618 // fastIsConstVisitor only visits at most two levels of the tree, with one 619 // exception: If the second level has a Cast expression, fastIsConstVisitor 620 // may visit three levels. 621 visited bool 622 } 623 624 var _ tree.Visitor = &fastIsConstVisitor{} 625 626 func (v *fastIsConstVisitor) VisitPre(expr tree.Expr) (recurse bool, newExpr tree.Expr) { 627 if v.visited { 628 if _, ok := expr.(*tree.CastExpr); ok { 629 // We recurse one more time for cast expressions, since the 630 // execbuilder may have wrapped a NULL. 631 return true, expr 632 } 633 if _, ok := expr.(tree.Datum); !ok || isVar(expr) { 634 // If the child expression is not a const Datum, the parent expression is 635 // not constant. Note that all constant literals have already been 636 // normalized to Datum in TypeCheck. 637 v.isConst = false 638 } 639 return false, expr 640 } 641 v.visited = true 642 643 // If the parent expression is a variable or impure function, we know that it 644 // is not constant. 645 646 if isVar(expr) { 647 v.isConst = false 648 return false, expr 649 } 650 651 switch t := expr.(type) { 652 case *tree.FuncExpr: 653 if t.IsImpure() { 654 v.isConst = false 655 return false, expr 656 } 657 } 658 659 return true, expr 660 } 661 662 func (*fastIsConstVisitor) VisitPost(expr tree.Expr) tree.Expr { return expr } 663 664 func (v *fastIsConstVisitor) run(expr tree.Expr) bool { 665 v.isConst = true 666 v.visited = false 667 tree.WalkExprConst(v, expr) 668 return v.isConst 669 } 670 671 // isVar returns true if the expression's value can vary during plan 672 // execution. 673 func isVar(expr tree.Expr) bool { 674 switch expr.(type) { 675 case tree.VariableExpr: 676 return true 677 case *tree.Placeholder: 678 panic(errors.AssertionFailedf("placeholder should have been replaced")) 679 } 680 return false 681 }