From 3b0da628cec5f1a1aeb85ec7e1b68a5bf258967a Mon Sep 17 00:00:00 2001 From: Drew Kimball Date: Wed, 26 Jul 2023 23:21:55 -0600 Subject: [PATCH 1/2] plpgsql: validate PLpgSQL functions during creation This patch ensures that PLpgSQL functions are built during function creation, not just during invocation. This ensures that compile-time errors are thrown when the function is created. This commit also tests and corrects the codes for some of the errors that can be thrown while building a PLpgSQL function. Note that some of the existing tests had to be removed since they called UDFs within other UDFs. We didn't catch this before because the restriction is only checked during function creation when the body statements are first built. Fixes #107681 Release note: None --- .../logictest/testdata/logic_test/udf_plpgsql | 225 ++++-------------- .../testdata/logic_test/udf_volatility_check | 33 +++ pkg/sql/opt/optbuilder/create_function.go | 25 +- pkg/sql/opt/optbuilder/plpgsql.go | 10 +- 4 files changed, 109 insertions(+), 184 deletions(-) diff --git a/pkg/sql/logictest/testdata/logic_test/udf_plpgsql b/pkg/sql/logictest/testdata/logic_test/udf_plpgsql index ea4d8de982e3..0e35deb9489e 100644 --- a/pkg/sql/logictest/testdata/logic_test/udf_plpgsql +++ b/pkg/sql/logictest/testdata/logic_test/udf_plpgsql @@ -325,172 +325,16 @@ SELECT f(1, 5), f(-5, 5), f(0, 1) ---- 10 10 0 -# Dijkstra's Algorithm -# -# ┌─┬────8──┬─┬──7────┬─┐ -# ┌─────┤1│ │2│ │3├─────┐ -# │ └┬┘ └┬┴───┐ └┬┘ │ -# │ │ │ │ │ │ -# 4 │ 2 │ │ 9 -# │ │ │ │ │ │ -# ┌┴┐ │ ┌┴┐ │ │ ┌┴┐ -# │0│ 11 ┌───┤8│ │ 14 │4│ -# └┬┘ │ │ └┬┘ │ │ └┬┘ -# │ │ 7 │ │ │ │ -# 8 │ │ 6 │ │ 10 -# │ │ │ │ │ │ │ -# │ ┌┴┬───┘ ┌┴┐ └───┬┴┐ │ -# └─────┤7│ │6│ │5├─────┘ -# └─┴────1──┴─┴──4────┴─┘ -# -# Encode the graph as a series of undirected edges, where "a" and "b" are the -# "to" and "from" nodes and "weight" is the weight of the edge. -statement ok -CREATE TABLE edges (a INT, b INT, weight INT); -INSERT INTO edges VALUES -(0, 1, 4), -(0, 7, 8), -(1, 7, 11), -(1, 2, 8), -(2, 8, 2), -(7, 8, 7), -(7, 6, 1), -(6, 8, 6), -(2, 5, 4), -(5, 6, 2), -(2, 3, 7), -(3, 5, 14), -(3, 4, 9), -(4, 5, 10); - -# Get the number of vertexes in the graph. -statement ok -CREATE FUNCTION vertexes() RETURNS INT AS $$ SELECT max(greatest(a, b)) + 1 FROM edges $$ LANGUAGE SQL; - -# Get the maximum int32 value. -statement ok -CREATE FUNCTION max_int() RETURNS INT AS $$ SELECT 2147483647 $$ LANGUAGE SQL; - -# Get the weight of the edge between the two given nodes, if any. -statement ok -CREATE FUNCTION graph(x INT, y INT) RETURNS INT AS $$ - SELECT coalesce((SELECT weight FROM edges WHERE (a = x AND b = y) OR (a = y AND b = x) LIMIT 1), 0); -$$ LANGUAGE SQL; - -# Replace the element at the given index of the array with the given value. -statement ok -CREATE FUNCTION replace(arr INT[], idx INT, val INT) RETURNS INT[] AS $$ - DECLARE - i INT; - n INT := array_length(arr, 1); - res INT[] := ARRAY[]::INT[]; - BEGIN - i := 0; - LOOP - IF i = idx THEN - res := res || val; - ELSE - res := res || arr[i+1]; - END IF; - i := i + 1; - IF i >= n THEN EXIT; END IF; - END LOOP; - RETURN res; - END -$$ LANGUAGE PLpgSQL; - -# Return the node with the minimum distance from the source node known so far -# out of the nodes that don't already have a shortest path calculated. -statement ok -CREATE FUNCTION min_distance(dist INT[], spt_set INT[]) RETURNS INT AS $$ - DECLARE - n INT := vertexes(); - i INT; - min INT := max_int(); - min_index INT := 0; - BEGIN - i := 0; - LOOP - IF spt_set[i+1] = 0 AND dist[i+1] <= min THEN - min := dist[i+1]; - min_index := i; - END IF; - i := i + 1; - IF i >= n THEN EXIT; END IF; - END LOOP; - RETURN min_index; - END -$$ LANGUAGE PLPGSQL; +# TODO(drewk): add back the dijkstra test once UDFs calling other UDFs is +# allowed. -# Implement dijkstra's algorithm using the "edges" table. -statement ok -CREATE FUNCTION dijkstra(src INT) RETURNS INT[] AS $$ - DECLARE - n INT := vertexes(); - i INT; - count INT; - dist INT[] := ARRAY[]::INT[]; - spt_set INT[] := ARRAY[]::INT[]; - u INT; - BEGIN - i := 0; - LOOP - dist := dist || max_int(); - spt_set := spt_set || 0; - i := i + 1; - IF i >= n THEN EXIT; END IF; - END LOOP; - dist := replace(dist, src, 0); - count := 0; - LOOP - u := min_distance(dist, spt_set); - spt_set := replace(spt_set, u, 1); - i := 0; - LOOP - IF - spt_set[i+1] = 0 AND - graph(u, i) > 0 AND - dist[u+1] <> max_int() AND - dist[u+1] + graph(u, i) < dist[i+1] - THEN - dist := replace(dist, i, dist[u+1] + graph(u, i)); - END IF; - i := i + 1; - IF i >= n THEN EXIT; END IF; - END LOOP; - count := count + 1; - IF count >= n THEN EXIT; END IF; - END LOOP; - RETURN dist; - END -$$ LANGUAGE PLPGSQL; - -# Run dijkstra's algorithm using node 0 as the source. -query II nosort,colnames -SELECT i AS "Vertex", dist[i+1] AS "Distance From Source" -FROM generate_series(0, vertexes() - 1) f(i), dijkstra(0) g(dist); ----- -Vertex Distance From Source -0 0 -1 4 -2 12 -3 19 -4 21 -5 11 -6 9 -7 8 -8 14 - -statement ok +statement error pgcode 2F005 control reached end of function without RETURN CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ BEGIN END $$ LANGUAGE PLpgSQL; statement error pgcode 2F005 control reached end of function without RETURN -SELECT f(1, 2); - -statement ok CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ DECLARE i INT; @@ -500,9 +344,6 @@ CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ $$ LANGUAGE PLpgSQL; statement error pgcode 2F005 control reached end of function without RETURN -SELECT f(1, 2); - -statement ok CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ BEGIN IF a < b THEN @@ -512,9 +353,6 @@ CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ $$ LANGUAGE PLpgSQL; statement error pgcode 2F005 control reached end of function without RETURN -SELECT f(1, 2); - -statement ok CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ DECLARE i INT; @@ -528,9 +366,6 @@ CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ $$ LANGUAGE PLpgSQL; statement error pgcode 2F005 control reached end of function without RETURN -SELECT f(1, 2); - -statement ok CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ BEGIN LOOP @@ -540,9 +375,6 @@ CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ $$ LANGUAGE PLpgSQL; statement error pgcode 2F005 control reached end of function without RETURN -SELECT f(1, 2); - -statement ok CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ BEGIN LOOP @@ -554,9 +386,6 @@ CREATE OR REPLACE FUNCTION f(a INT, b INT) RETURNS INT AS $$ END $$ LANGUAGE PLpgSQL; -statement error pgcode 2F005 control reached end of function without RETURN -SELECT f(1, 2); - statement error pgcode 0A000 PL/pgSQL functions with RECORD input arguments are not yet supported CREATE FUNCTION f_err(p1 RECORD) RETURNS RECORD AS $$ BEGIN @@ -831,3 +660,51 @@ $$ LANGUAGE PLpgSQL; query error pgcode P0001 pq: foo SELECT f(); + +statement error pgcode 42601 pq: too few parameters specified for RAISE +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + BEGIN + RAISE 'foo% % %', 1, 2; + RETURN 0; + END +$$ LANGUAGE PLpgSQL; + +statement error pgcode 42601 pq: too many parameters specified for RAISE +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + BEGIN + RAISE 'foo%', 1, 2; + RETURN 0; + END +$$ LANGUAGE PLpgSQL; + +statement error pgcode 42601 pq: RAISE option already specified: ERRCODE +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + BEGIN + RAISE EXCEPTION USING ERRCODE = '22012', ERRCODE = '22013'; + return 0; + END +$$ LANGUAGE PLpgSQL; + +statement error pgcode 42601 pq: \"i\" is not a known variable +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + BEGIN + i := 0; + RETURN i; + END +$$ LANGUAGE PLpgSQL; + +statement error pgcode 42601 CONTINUE cannot be used outside a loop +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + BEGIN + CONTINUE; + RETURN i; + END +$$ LANGUAGE PLpgSQL; + +statement error pgcode 42601 EXIT cannot be used outside a loop, unless it has a label +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + BEGIN + EXIT; + RETURN i; + END +$$ LANGUAGE PLpgSQL; diff --git a/pkg/sql/logictest/testdata/logic_test/udf_volatility_check b/pkg/sql/logictest/testdata/logic_test/udf_volatility_check index 8e7c719efa54..a3bce3258887 100644 --- a/pkg/sql/logictest/testdata/logic_test/udf_volatility_check +++ b/pkg/sql/logictest/testdata/logic_test/udf_volatility_check @@ -102,3 +102,36 @@ statement error pgcode 22023 pq: volatile statement not allowed in immutable fun ALTER FUNCTION f IMMUTABLE subtest end + +subtest plpgsql_volatility + +statement error pgcode 22023 pq: referencing relations is not allowed in immutable function +CREATE FUNCTION f() RETURNS FLOAT LANGUAGE PLpgSQL IMMUTABLE AS $$ BEGIN RETURN (SELECT a FROM t1); END $$; + +statement error pgcode 22023 pq: volatile statement not allowed in immutable function: BEGIN +CREATE FUNCTION f() RETURNS FLOAT LANGUAGE PLpgSQL IMMUTABLE AS $$ BEGIN RETURN (SELECT random()); END $$; + +statement error pgcode 22023 pq: stable statement not allowed in immutable function: BEGIN +CREATE FUNCTION f() RETURNS TIMESTAMP LANGUAGE PLpgSQL IMMUTABLE AS $$ BEGIN RETURN (SELECT statement_timestamp()); END $$; + +statement error pgcode 22023 pq: volatile statement not allowed in stable function: BEGIN +CREATE FUNCTION f() RETURNS FLOAT LANGUAGE PLpgSQL STABLE AS $$ BEGIN RETURN (SELECT random()); END $$; + +statement error pgcode 22023 pq: volatile statement not allowed in immutable function: BEGIN +CREATE FUNCTION f() RETURNS FLOAT LANGUAGE PLpgSQL IMMUTABLE AS $$ BEGIN RETURN (SELECT @1 FROM random()); END $$; + +statement error pgcode 22023 pq: volatile statement not allowed in immutable function: BEGIN +CREATE FUNCTION f() RETURNS INT LANGUAGE PLpgSQL IMMUTABLE AS $$ + BEGIN + RETURN (SELECT t1.a FROM t1 JOIN t2 ON t1.a = t2.a + random()::INT); + END +$$; + +statement error pgcode 22023 pq: volatile statement not allowed in immutable function: BEGIN +CREATE FUNCTION f() RETURNS INT LANGUAGE PLpgSQL IMMUTABLE AS $$ + BEGIN + RETURN (SELECT a FROM t1 WHERE b = 1 + random()); + END +$$; + +subtest end diff --git a/pkg/sql/opt/optbuilder/create_function.go b/pkg/sql/opt/optbuilder/create_function.go index 893b00c9c146..ee9550642f0e 100644 --- a/pkg/sql/opt/optbuilder/create_function.go +++ b/pkg/sql/opt/optbuilder/create_function.go @@ -143,6 +143,7 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o // named parameters to the scope so that references to them in the body can // be resolved. bodyScope := b.allocScope() + var paramTypes tree.ParamTypes for i := range cf.Params { param := &cf.Params[i] typ, err := tree.ResolveType(b.ctx, param.Type, b.semaCtx.TypeResolver) @@ -170,6 +171,14 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o typedesc.GetTypeDescriptorClosure(typ).ForEach(func(id descpb.ID) { typeDeps.Add(int(id)) }) + + // Collect the parameters for PLpgSQL routines. + if language == tree.RoutineLangPLpgSQL { + paramTypes = append(paramTypes, tree.ParamType{ + Name: param.Name.String(), + Typ: typ, + }) + } } // Collect the user defined type dependency of the return type. @@ -205,8 +214,8 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o b.evalCtx.Annotations = &ann // We need to disable stable function folding because we want to catch the - // volatility of stable functions. If folded, we only get a scalar and lose - // the volatility. + // volatility of stable functions. If folded, we only get a scalar and + // lose the volatility. b.factory.FoldingControl().TemporarilyDisallowStableFolds(func() { stmtScope = b.buildStmtAtRootWithScope(stmts[i].AST, nil /* desiredTypes */, bodyScope) }) @@ -230,8 +239,16 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o panic(err) } - // TODO(drewk): build and check volatility. We will need to remove the hack - // to disable UDFs calling other UDFs before doing this. + // We need to disable stable function folding because we want to catch the + // volatility of stable functions. If folded, we only get a scalar and lose + // the volatility. + b.factory.FoldingControl().TemporarilyDisallowStableFolds(func() { + var plBuilder plpgsqlBuilder + plBuilder.init(b, nil /* colRefs */, paramTypes, stmt.AST, funcReturnType) + stmtScope = plBuilder.build(stmt.AST, bodyScope) + }) + checkStmtVolatility(targetVolatility, stmtScope, stmt) + // Format the statements with qualified datasource names. formatFuncBodyStmt(fmtCtx, stmt.AST, false /* newLine */) afterBuildStmt() diff --git a/pkg/sql/opt/optbuilder/plpgsql.go b/pkg/sql/opt/optbuilder/plpgsql.go index e42efb6af0d9..d1e080d2c7a2 100644 --- a/pkg/sql/opt/optbuilder/plpgsql.go +++ b/pkg/sql/opt/optbuilder/plpgsql.go @@ -401,7 +401,7 @@ func (b *plpgsqlBuilder) addPLpgSQLAssign( ) *scope { typ, ok := b.varTypes[ident] if !ok { - panic(errors.AssertionFailedf("failed to find type for variable %s", ident)) + panic(pgerror.Newf(pgcode.Syntax, "\"%s\" is not a known variable", ident)) } assignScope := inScope.push() for i := range inScope.cols { @@ -448,9 +448,7 @@ func (b *plpgsqlBuilder) getRaiseArgs( // DEBUG log-level maps to severity DEBUG1. severity = makeConstStr("DEBUG1") default: - panic(unimplemented.Newf( - "unimplemented log level", "RAISE log level %s is not yet supported", raise.LogLevel, - )) + panic(errors.AssertionFailedf("unexpected log level %s", raise.LogLevel)) } // Retrieve the message, if it was set with the format syntax. if raise.Message != "" { @@ -537,7 +535,7 @@ func (b *plpgsqlBuilder) makeRaiseFormatMessage( if j > 0 { // Add the next argument at the location of this parameter. if argIdx >= len(args) { - panic(pgerror.Newf(pgcode.PLpgSQL, "too few parameters specified for RAISE")) + panic(pgerror.Newf(pgcode.Syntax, "too few parameters specified for RAISE")) } addToResult(b.buildPLpgSQLExpr(args[argIdx], types.String, s)) argIdx++ @@ -546,7 +544,7 @@ func (b *plpgsqlBuilder) makeRaiseFormatMessage( } } if argIdx < len(args) { - panic(pgerror.Newf(pgcode.PLpgSQL, "too many parameters specified for RAISE")) + panic(pgerror.Newf(pgcode.Syntax, "too many parameters specified for RAISE")) } return result } From a181794cdb7ae74e7bf960374eceae595696d6c1 Mon Sep 17 00:00:00 2001 From: Drew Kimball Date: Wed, 26 Jul 2023 23:42:15 -0600 Subject: [PATCH 2/2] plpgsql: add support for CONSTANT variable declarations It is possible to declare variables as CONSTANT in PLpgSQL. This will cause any attempt to assign to the variable to result in a compile-time error. This patch implements CONSTANT variables by adding a check whenever an assignment is built that the assigned variable is non-constant. Fixes #105241 Release note (sql change): Added support for CONSTANT variable declarations in PLpgSQL routines. Any assignment to a variable declared with the CONSTANT keyword will raise a compile-time error. --- .../logictest/testdata/logic_test/udf_plpgsql | 100 ++++++++++++++++++ pkg/sql/opt/optbuilder/plpgsql.go | 22 ++-- pkg/sql/sem/plpgsqltree/statements.go | 1 - pkg/sql/sem/plpgsqltree/variable.go | 6 -- 4 files changed, 115 insertions(+), 14 deletions(-) diff --git a/pkg/sql/logictest/testdata/logic_test/udf_plpgsql b/pkg/sql/logictest/testdata/logic_test/udf_plpgsql index 0e35deb9489e..bc265dbada58 100644 --- a/pkg/sql/logictest/testdata/logic_test/udf_plpgsql +++ b/pkg/sql/logictest/testdata/logic_test/udf_plpgsql @@ -708,3 +708,103 @@ CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ RETURN i; END $$ LANGUAGE PLpgSQL; + +statement ok +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + DECLARE + i CONSTANT INT; + BEGIN + RETURN i; + END +$$ LANGUAGE PLpgSQL; + +query I +SELECT f(); +---- +NULL + +statement ok +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + DECLARE + i CONSTANT INT := 0; + BEGIN + RETURN i; + END +$$ LANGUAGE PLpgSQL; + +query I +SELECT f(); +---- +0 + +statement ok +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + DECLARE + i CONSTANT INT := (SELECT x FROM xy ORDER BY x LIMIT 1); + BEGIN + RETURN i; + END +$$ LANGUAGE PLpgSQL; + +query I +SELECT f(); +---- +1 + +statement ok +CREATE OR REPLACE FUNCTION f(n INT) RETURNS INT AS $$ + DECLARE + i CONSTANT INT := n; + BEGIN + RETURN i; + END +$$ LANGUAGE PLpgSQL; + +query IIIIII +SELECT f(-100), f(-1), f(0), f(1), f(100), f(NULL); +---- +-100 -1 0 1 100 NULL + +statement error pgcode 22005 pq: variable \"i\" is declared CONSTANT +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + DECLARE + i CONSTANT INT; + BEGIN + i := i + 1; + RETURN i; + END +$$ LANGUAGE PLpgSQL; + +statement error pgcode 22005 pq: variable \"i\" is declared CONSTANT +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + DECLARE + i CONSTANT INT := 0; + BEGIN + i := i + 1; + RETURN i; + END +$$ LANGUAGE PLpgSQL; + +statement error pgcode 22005 pq: variable \"i\" is declared CONSTANT +CREATE OR REPLACE FUNCTION f(n INT) RETURNS INT AS $$ + DECLARE + i CONSTANT INT := 0; + BEGIN + IF n > 0 THEN + i := i + 1; + END IF; + RETURN i; + END +$$ LANGUAGE PLpgSQL; + +statement error pgcode 22005 pq: variable \"i\" is declared CONSTANT +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + DECLARE + i CONSTANT INT := 0; + BEGIN + LOOP IF i >= 10 THEN EXIT; END IF; + i := i + 1; + END LOOP; + RETURN i; + END +$$ LANGUAGE PLpgSQL; diff --git a/pkg/sql/opt/optbuilder/plpgsql.go b/pkg/sql/opt/optbuilder/plpgsql.go index d1e080d2c7a2..f027f00fccba 100644 --- a/pkg/sql/opt/optbuilder/plpgsql.go +++ b/pkg/sql/opt/optbuilder/plpgsql.go @@ -121,6 +121,9 @@ type plpgsqlBuilder struct { // varTypes maps from the name of each variable to its type. varTypes map[tree.Name]*types.T + // constants tracks the variables that were declared as constant. + constants map[tree.Name]struct{} + // returnType is the return type of the PL/pgSQL function. returnType *types.T @@ -164,12 +167,6 @@ func (b *plpgsqlBuilder) init( "not-null PL/pgSQL variables are not yet supported", )) } - if dec.Constant { - panic(unimplemented.NewWithIssueDetail(105241, - "constant variable", - "constant PL/pgSQL variables are not yet supported", - )) - } if dec.Collate != "" { panic(unimplemented.NewWithIssueDetail(105245, "variable collation", @@ -185,14 +182,20 @@ func (b *plpgsqlBuilder) build(block *plpgsqltree.PLpgSQLStmtBlock, s *scope) *s s = s.push() b.ensureScopeHasExpr(s) - // Some variable declarations initialize the variable. + b.constants = make(map[tree.Name]struct{}) for _, dec := range b.decls { if dec.Expr != nil { + // Some variable declarations initialize the variable. s = b.addPLpgSQLAssign(s, dec.Var, dec.Expr) } else { // Uninitialized variables are null. s = b.addPLpgSQLAssign(s, dec.Var, &tree.CastExpr{Expr: tree.DNull, Type: dec.Typ}) } + if dec.Constant { + // Add to the constants map after initializing the variable, since + // constant variables only prevent assignment, not initialization. + b.constants[dec.Var] = struct{}{} + } } if s = b.buildPLpgSQLStatements(block.Body, s); s != nil { return s @@ -399,6 +402,11 @@ func (b *plpgsqlBuilder) buildPLpgSQLStatements( func (b *plpgsqlBuilder) addPLpgSQLAssign( inScope *scope, ident plpgsqltree.PLpgSQLVariable, val plpgsqltree.PLpgSQLExpr, ) *scope { + if b.constants != nil { + if _, ok := b.constants[ident]; ok { + panic(pgerror.Newf(pgcode.ErrorInAssignment, "variable \"%s\" is declared CONSTANT", ident)) + } + } typ, ok := b.varTypes[ident] if !ok { panic(pgerror.Newf(pgcode.Syntax, "\"%s\" is not a known variable", ident)) diff --git a/pkg/sql/sem/plpgsqltree/statements.go b/pkg/sql/sem/plpgsqltree/statements.go index 04584cc8418a..83d04a2a5fd7 100644 --- a/pkg/sql/sem/plpgsqltree/statements.go +++ b/pkg/sql/sem/plpgsqltree/statements.go @@ -60,7 +60,6 @@ type PLpgSQLStmtBlock struct { Decls []PLpgSQLDecl Body []PLpgSQLStatement Exceptions *PLpgSQLExceptionBlock - Scope VariableScope } // TODO(drewk): format Label and Exceptions fields. diff --git a/pkg/sql/sem/plpgsqltree/variable.go b/pkg/sql/sem/plpgsqltree/variable.go index e83b416fde97..a19c74ca4fe8 100644 --- a/pkg/sql/sem/plpgsqltree/variable.go +++ b/pkg/sql/sem/plpgsqltree/variable.go @@ -13,9 +13,3 @@ package plpgsqltree import "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" type PLpgSQLVariable = tree.Name - -// Scope contains all the variables defined in the DECLARE section of current statement block. -type VariableScope struct { - Variables []*PLpgSQLVariable - VarNameToIdx map[string]int // mapping from variable -}