github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/optbuilder/sql_fn.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 optbuilder 12 13 import ( 14 "context" 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/parser" 19 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 20 "github.com/cockroachdb/cockroach/pkg/sql/types" 21 "github.com/cockroachdb/cockroach/pkg/util/errorutil/unimplemented" 22 "github.com/cockroachdb/cockroach/pkg/util/log" 23 ) 24 25 // sqlFnInfo stores information about a tree.SQLClass function, which is a 26 // function that executes a SQL statement as a side effect of the function call. 27 // See the comment above tree.SQLClass for more info. 28 type sqlFnInfo struct { 29 *tree.FuncExpr 30 31 def memo.FunctionPrivate 32 args memo.ScalarListExpr 33 } 34 35 // Walk is part of the tree.Expr interface. 36 func (s *sqlFnInfo) Walk(v tree.Visitor) tree.Expr { 37 return s 38 } 39 40 // TypeCheck is part of the tree.Expr interface. 41 func (s *sqlFnInfo) TypeCheck( 42 ctx context.Context, semaCtx *tree.SemaContext, desired *types.T, 43 ) (tree.TypedExpr, error) { 44 if _, err := s.FuncExpr.TypeCheck(ctx, semaCtx, desired); err != nil { 45 return nil, err 46 } 47 return s, nil 48 } 49 50 // buildSQLFn builds a SQL statement from the given tree.SQLClass function and 51 // hoists it into a CTE. It then builds the original function as a scalar 52 // expression and returns it. 53 func (b *Builder) buildSQLFn( 54 info *sqlFnInfo, inScope, outScope *scope, outCol *scopeColumn, colRefs *opt.ColSet, 55 ) opt.ScalarExpr { 56 // Get the arguments to the function. 57 exprs := make(tree.Datums, len(info.args)) 58 for i := range exprs { 59 if !memo.CanExtractConstDatum(info.args[i]) { 60 panic(unimplemented.NewWithIssuef(49448, "non-constant argument passed to %s\n", 61 log.Safe(info.def.Name), 62 )) 63 } 64 exprs[i] = memo.ExtractConstDatum(info.args[i]) 65 } 66 67 // Get the SQL statement and parse it. 68 sql, err := info.def.Overload.SQLFn(b.evalCtx, exprs) 69 if err != nil { 70 panic(err) 71 } 72 stmt, err := parser.ParseOne(sql) 73 if err != nil { 74 panic(err) 75 } 76 77 // Build the SQL statement and hoist it into a CTE. 78 b.semaCtx.Annotations = tree.MakeAnnotations(stmt.NumAnnotations) 79 emptyScope := b.allocScope() 80 innerScope := b.buildStmt(stmt.AST, nil /* desiredTypes */, emptyScope) 81 82 id := b.factory.Memo().NextWithID() 83 cte := cteSource{ 84 name: tree.AliasClause{}, 85 cols: innerScope.makePresentationWithHiddenCols(), 86 originalExpr: stmt.AST, 87 expr: innerScope.expr, 88 id: id, 89 bindingProps: innerScope.expr.Relational(), 90 } 91 b.cteStack[len(b.cteStack)-1] = append(b.cteStack[len(b.cteStack)-1], cte) 92 93 // Build and return the original function. 94 return b.buildScalar(info.FuncExpr, inScope, outScope, outCol, colRefs) 95 }