Skip to content

Commit 3693f3f

Browse files
committed
plpgsql: fix parameter ordinal references
Previously, variable assignment in PL/pgSQL routines did not update the `paramOrd` field. As a result, referencing a variable via the `$1` ordinal syntax did not always reflect updates to the variable. In addition, it was possible to reference variables declared in blocks within the routine body, rather than just the original routine parameters. This commit fixes both issues by always setting `paramOrd` and setting a `maxParamOrd` while building SQL expressions and statements, which prevents the user from referencing block variables via ordinal syntax. We use a `maxParamOrd` instead of simply not setting `paramOrd` for block variables to allow the builder to internally reference any variable with ordinal syntax. Fixes #143887 Release note (bug fix): Fixed a bug existing since v24.1 that prevented variable references using ordinal syntax (like `$1`) from reflecting updates to the variable. Referencing variables declared in PL/pgSQL blocks (instead of parameters) via ordinal syntax is now disallowed.
1 parent 37603e9 commit 3693f3f

File tree

7 files changed

+444
-43
lines changed

7 files changed

+444
-43
lines changed

pkg/ccl/logictestccl/testdata/logic_test/plpgsql_assign

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,62 @@ CREATE FUNCTION f(val xy) RETURNS xy AS $$
122122
$$ LANGUAGE PLpgSQL;
123123

124124
subtest end
125+
126+
# Ordinal parameter references should reflect updates made by variable
127+
# assignment.
128+
subtest regression_143887
129+
130+
statement ok
131+
CREATE FUNCTION f(x INT) RETURNS INT AS $$
132+
BEGIN
133+
RAISE NOTICE '% = %', x, $1;
134+
x := $1 + 1;
135+
RAISE NOTICE '% = %', x, $1;
136+
IF x IS NOT NULL THEN
137+
x := $1 + 100;
138+
RAISE NOTICE '% = %', x, $1;
139+
END IF;
140+
RAISE NOTICE '% = %', x, $1;
141+
RETURN x + $1;
142+
END
143+
$$ LANGUAGE PLpgSQL;
144+
145+
query T noticetrace
146+
SELECT f(0);
147+
----
148+
NOTICE: 0 = 0
149+
NOTICE: 1 = 1
150+
NOTICE: 101 = 101
151+
NOTICE: 101 = 101
152+
153+
query I
154+
SELECT f(0);
155+
----
156+
202
157+
158+
statement ok
159+
DROP FUNCTION f
160+
161+
statement ok
162+
CREATE FUNCTION f(foo xy) RETURNS INT AS $$
163+
BEGIN
164+
foo := ROW(1, 2);
165+
RAISE NOTICE '% = %', foo, $1;
166+
RETURN (foo).x + ($1).x;
167+
END
168+
$$ LANGUAGE PLpgSQL;
169+
170+
query T noticetrace
171+
SELECT f((100, 200));
172+
----
173+
NOTICE: (1,2) = (1,2)
174+
175+
query I
176+
SELECT f((100, 200));
177+
----
178+
2
179+
180+
statement ok
181+
DROP FUNCTION f(xy);
182+
183+
subtest end

pkg/ccl/logictestccl/testdata/logic_test/plpgsql_call

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
statement ok
2+
CREATE TABLE xy (x INT, y INT);
3+
14
statement ok
25
CREATE PROCEDURE p_nested() AS $$
36
BEGIN
@@ -456,9 +459,6 @@ subtest end
456459
# parameters.
457460
subtest regression_143171
458461

459-
statement ok
460-
CREATE TABLE xy (x INT, y INT);
461-
462462
statement ok
463463
CREATE PROCEDURE p_143171(OUT foo INT) LANGUAGE PLpgSQL AS $$
464464
BEGIN
@@ -489,7 +489,83 @@ DROP PROCEDURE p2_143171;
489489
statement ok
490490
DROP PROCEDURE p_143171;
491491

492+
subtest end
493+
494+
# Ordinal parameter references should reflect updates made by
495+
# CALL statements.
496+
subtest regression_143887
497+
498+
statement ok
499+
CREATE PROCEDURE p143887(INOUT x INT) LANGUAGE PLpgSQL AS $$
500+
BEGIN
501+
IF x = 0 THEN
502+
x := 1;
503+
ELSE
504+
x := x + 100;
505+
END IF;
506+
END
507+
$$;
508+
509+
statement ok
510+
CREATE FUNCTION f(x INT) RETURNS INT AS $$
511+
BEGIN
512+
RAISE NOTICE '% = %', x, $1;
513+
CALL p143887(x);
514+
RAISE NOTICE '% = %', x, $1;
515+
IF x IS NOT NULL THEN
516+
CALL p143887(x);
517+
RAISE NOTICE '% = %', x, $1;
518+
END IF;
519+
RAISE NOTICE '% = %', x, $1;
520+
RETURN x + $1;
521+
END
522+
$$ LANGUAGE PLpgSQL;
523+
524+
query T noticetrace
525+
SELECT f(0);
526+
----
527+
NOTICE: 0 = 0
528+
NOTICE: 1 = 1
529+
NOTICE: 101 = 101
530+
NOTICE: 101 = 101
531+
532+
query I
533+
SELECT f(0);
534+
----
535+
202
536+
537+
statement ok
538+
DROP FUNCTION f(INT);
539+
DROP PROCEDURE p143887;
540+
541+
statement ok
542+
CREATE PROCEDURE p143887(INOUT foo xy) LANGUAGE PLpgSQL AS $$
543+
BEGIN
544+
foo := ROW(1, 2);
545+
END
546+
$$;
547+
548+
statement ok
549+
CREATE FUNCTION f(foo xy) RETURNS INT AS $$
550+
BEGIN
551+
CALL p143887(foo);
552+
RAISE NOTICE '% = %', foo, $1;
553+
RETURN (foo).x + ($1).x;
554+
END
555+
$$ LANGUAGE PLpgSQL;
556+
557+
query T noticetrace
558+
SELECT f((100, 200));
559+
----
560+
NOTICE: (1,2) = (1,2)
561+
562+
query I
563+
SELECT f((100, 200));
564+
----
565+
2
566+
492567
statement ok
493-
DROP TABLE xy;
568+
DROP FUNCTION f(xy);
569+
DROP PROCEDURE p143887;
494570

495571
subtest end

pkg/ccl/logictestccl/testdata/logic_test/plpgsql_cursor

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,3 +2104,68 @@ subtest end
21042104

21052105
statement ok
21062106
RESET autocommit_before_ddl
2107+
2108+
# Ordinal parameter references should reflect updates made by
2109+
# FETCH statements.
2110+
subtest regression_143887
2111+
2112+
statement ok
2113+
DROP FUNCTION f(INT);
2114+
CREATE FUNCTION f(x INT) RETURNS INT AS $$
2115+
DECLARE foo REFCURSOR;
2116+
BEGIN
2117+
OPEN foo FOR SELECT bar FROM (VALUES (1), (100)) AS v(bar);
2118+
RAISE NOTICE '% = %', x, $1;
2119+
FETCH foo INTO x;
2120+
RAISE NOTICE '% = %', x, $1;
2121+
IF x IS NOT NULL THEN
2122+
FETCH foo INTO x;
2123+
RAISE NOTICE '% = %', x, $1;
2124+
END IF;
2125+
RAISE NOTICE '% = %', x, $1;
2126+
RETURN x + $1;
2127+
END
2128+
$$ LANGUAGE PLpgSQL;
2129+
2130+
query T noticetrace
2131+
SELECT f(0);
2132+
----
2133+
NOTICE: 0 = 0
2134+
NOTICE: 1 = 1
2135+
NOTICE: 100 = 100
2136+
NOTICE: 100 = 100
2137+
2138+
query I
2139+
SELECT f(0);
2140+
----
2141+
200
2142+
2143+
statement ok
2144+
DROP FUNCTION f(INT);
2145+
2146+
statement ok
2147+
CREATE FUNCTION f(foo xy) RETURNS INT AS $$
2148+
DECLARE
2149+
bar REFCURSOR;
2150+
BEGIN
2151+
OPEN bar FOR SELECT 1, 2;
2152+
FETCH bar INTO foo;
2153+
RAISE NOTICE '% = %', foo, $1;
2154+
RETURN (foo).x + ($1).x;
2155+
END
2156+
$$ LANGUAGE PLpgSQL;
2157+
2158+
query T noticetrace
2159+
SELECT f((100, 200));
2160+
----
2161+
NOTICE: (1,2) = (1,2)
2162+
2163+
query I
2164+
SELECT f((100, 200));
2165+
----
2166+
2
2167+
2168+
statement ok
2169+
DROP FUNCTION f(xy);
2170+
2171+
subtest end

pkg/ccl/logictestccl/testdata/logic_test/plpgsql_into

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,3 +523,63 @@ statement ok
523523
RESET plpgsql_use_strict_into;
524524

525525
subtest end
526+
527+
# Ordinal parameter references should reflect updates made by
528+
# SELECT INTO statements.
529+
subtest regression_143887
530+
531+
statement ok
532+
DROP FUNCTION f(INT);
533+
CREATE FUNCTION f(x INT) RETURNS INT AS $$
534+
BEGIN
535+
RAISE NOTICE '% = %', x, $1;
536+
SELECT $1 + 1 INTO x;
537+
RAISE NOTICE '% = %', x, $1;
538+
IF x IS NOT NULL THEN
539+
SELECT $1 + 100 INTO x;
540+
RAISE NOTICE '% = %', x, $1;
541+
END IF;
542+
RAISE NOTICE '% = %', x, $1;
543+
RETURN x + $1;
544+
END
545+
$$ LANGUAGE PLpgSQL;
546+
547+
query T noticetrace
548+
SELECT f(0);
549+
----
550+
NOTICE: 0 = 0
551+
NOTICE: 1 = 1
552+
NOTICE: 101 = 101
553+
NOTICE: 101 = 101
554+
555+
query I
556+
SELECT f(0);
557+
----
558+
202
559+
560+
statement ok
561+
DROP FUNCTION f(INT);
562+
563+
statement ok
564+
CREATE FUNCTION f(foo xy) RETURNS INT AS $$
565+
BEGIN
566+
SELECT 1, 2 INTO foo;
567+
RAISE NOTICE '% = %', foo, $1;
568+
RETURN (foo).x + ($1).x;
569+
END
570+
$$ LANGUAGE PLpgSQL;
571+
572+
query T noticetrace
573+
SELECT f((100, 200));
574+
----
575+
NOTICE: (1,2) = (1,2)
576+
577+
query I
578+
SELECT f((100, 200));
579+
----
580+
2
581+
582+
statement ok
583+
DROP FUNCTION f(xy);
584+
585+
subtest end

pkg/ccl/logictestccl/testdata/logic_test/udf_plpgsql

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3294,3 +3294,82 @@ statement ok
32943294
EXECUTE foo (100);
32953295

32963296
subtest end
3297+
3298+
# Make sure that only the original function parameters can be referenced by
3299+
# ordinal syntax.
3300+
subtest regression_143887
3301+
3302+
# Case with SQL expression.
3303+
statement error pgcode 42P02 pq: no value provided for placeholder: \$3
3304+
CREATE FUNCTION f143887(x INT, y INT) RETURNS INT LANGUAGE PLpgSQL AS $$ BEGIN RETURN $3; END $$;
3305+
3306+
# Case with SQL statement.
3307+
statement error pgcode 42P02 pq: no value provided for placeholder: \$3
3308+
CREATE FUNCTION f143887(x INT, y INT) RETURNS INT LANGUAGE PLpgSQL AS $$ BEGIN SELECT $3; RETURN 0; END $$;
3309+
3310+
# Case with SQL expression.
3311+
statement error pgcode 42P02 pq: no value provided for placeholder: \$3
3312+
CREATE FUNCTION f143887(x INT, y INT) RETURNS INT LANGUAGE PLpgSQL AS $$
3313+
DECLARE
3314+
z INT := x + y;
3315+
BEGIN
3316+
RETURN $3;
3317+
END
3318+
$$;
3319+
3320+
# Case with SQL statement.
3321+
statement error pgcode 42P02 pq: no value provided for placeholder: \$3
3322+
CREATE FUNCTION f143887(x INT, y INT) RETURNS INT LANGUAGE PLpgSQL AS $$
3323+
DECLARE
3324+
z INT := x + y;
3325+
BEGIN
3326+
SELECT $3;
3327+
RETURN 0;
3328+
END
3329+
$$;
3330+
3331+
statement error pgcode 42P02 pq: no value provided for placeholder: \$3
3332+
CREATE FUNCTION f143887(x INT, y INT) RETURNS INT LANGUAGE PLpgSQL AS $$
3333+
DECLARE
3334+
z INT := x + y;
3335+
BEGIN
3336+
z := z * 100 * x;
3337+
IF x > y THEN
3338+
RETURN $3;
3339+
END IF;
3340+
RETURN 0;
3341+
END
3342+
$$;
3343+
3344+
statement error pgcode 42P02 pq: no value provided for placeholder: \$3
3345+
CREATE FUNCTION f143887(x INT, y INT) RETURNS INT LANGUAGE PLpgSQL AS $$
3346+
DECLARE
3347+
z INT := x + y;
3348+
BEGIN
3349+
DECLARE
3350+
w INT := z + x + y;
3351+
BEGIN
3352+
z := z * 100 * x;
3353+
RETURN $3 + $4;
3354+
END;
3355+
RETURN 0;
3356+
END
3357+
$$;
3358+
3359+
# Make sure that function parameters can still be referenced via ordinal syntax.
3360+
statement ok
3361+
CREATE FUNCTION f143887(x INT, y INT) RETURNS INT LANGUAGE PLpgSQL AS $$
3362+
DECLARE
3363+
z INT := x + y;
3364+
BEGIN
3365+
SELECT $1 + $2;
3366+
RETURN $1 + $2;
3367+
END
3368+
$$;
3369+
3370+
query I
3371+
SELECT f143887(100, 200);
3372+
----
3373+
300
3374+
3375+
subtest end

0 commit comments

Comments
 (0)