Skip to content

Commit 947ef8b

Browse files
committed
plpgsql: do not drop a CALL statement with unused OUT params
This commit fixes a bug that could cause the routine invocation for a PL/pgSQL CALL statement to be dropped if the stored proc had out params that were all unused by the calling routine. The fix is simple - just add an optimization barrier if the called procedure is volatile. Fixes #143171 Release note (bug fix): Fixed a bug existing since PL/pgSQL CALL statements were introduced in v24.1, where the called procedure could be dropped if it had OUT parameters that were not used by the calling routine.
1 parent 65b2ed4 commit 947ef8b

File tree

3 files changed

+183
-0
lines changed

3 files changed

+183
-0
lines changed

pkg/ccl/logictestccl/testdata/logic_test/plpgsql_call

+35
Original file line numberDiff line numberDiff line change
@@ -451,3 +451,38 @@ statement ok
451451
DROP PROCEDURE p_nested;
452452

453453
subtest end
454+
455+
# Regression test for #143171 - do not drop a CALL statement with unused OUT
456+
# parameters.
457+
subtest regression_143171
458+
459+
statement ok
460+
CREATE TABLE xy (x INT, y INT);
461+
462+
statement ok
463+
CREATE PROCEDURE p_143171(OUT foo INT) LANGUAGE PLpgSQL AS $$
464+
BEGIN
465+
INSERT INTO xy VALUES (1, 2) RETURNING x INTO foo;
466+
END;
467+
$$;
468+
469+
statement ok
470+
CREATE PROCEDURE p2_143171() LANGUAGE PLpgSQL AS $$
471+
DECLARE foo INT;
472+
BEGIN
473+
CALL p_143171(foo);
474+
END;
475+
$$;
476+
477+
statement ok
478+
CALL p2_143171();
479+
480+
# The result of the insert should be visible here.
481+
query II
482+
SELECT * FROM xy;
483+
----
484+
485+
statement ok
486+
DROP TABLE xy;
487+
488+
subtest end

pkg/sql/opt/optbuilder/plpgsql.go

+3
Original file line numberDiff line numberDiff line change
@@ -1055,6 +1055,9 @@ func (b *plpgsqlBuilder) buildPLpgSQLStatements(stmts []ast.Statement, s *scope)
10551055
col.scalar = b.ob.buildRoutine(proc, def, callCon.s, callScope, b.colRefs)
10561056
})
10571057
b.ob.constructProjectForScope(callCon.s, callScope)
1058+
if overload.Volatility == volatility.Volatile {
1059+
b.ob.addBarrier(callScope)
1060+
}
10581061

10591062
// Collect any target variables in OUT-parameter position. The result of
10601063
// the procedure will be assigned to these variables, if any.

pkg/sql/opt/optbuilder/testdata/procedure_plpgsql

+145
Original file line numberDiff line numberDiff line change
@@ -732,3 +732,148 @@ call
732732
│ ├── variable: x:6
733733
│ └── variable: y:7
734734
└── const: 1
735+
736+
exec-ddl
737+
CREATE PROCEDURE p_143171(OUT foo INT) LANGUAGE PLpgSQL AS $$
738+
BEGIN
739+
INSERT INTO t VALUES (1, 2, 'foo') RETURNING i INTO foo;
740+
END;
741+
$$;
742+
----
743+
744+
exec-ddl
745+
CREATE PROCEDURE p2_143171() LANGUAGE PLpgSQL AS $$
746+
DECLARE foo INT;
747+
BEGIN
748+
CALL p_143171(foo);
749+
END;
750+
$$;
751+
----
752+
753+
# Regression test for #143171 - do not drop the routine invocation that
754+
# corresponds to the p_143171 CALL statement.
755+
build format=show-scalars
756+
CALL p2_143171();
757+
----
758+
call
759+
└── procedure: p2_143171
760+
└── body
761+
└── limit
762+
├── columns: "_stmt_call_1":23
763+
├── project
764+
│ ├── columns: "_stmt_call_1":23
765+
│ ├── barrier
766+
│ │ ├── columns: foo:1
767+
│ │ └── project
768+
│ │ ├── columns: foo:1
769+
│ │ ├── values
770+
│ │ │ └── tuple
771+
│ │ └── projections
772+
│ │ └── cast: INT8 [as=foo:1]
773+
│ │ └── null
774+
│ └── projections
775+
│ └── udf: _stmt_call_1 [as="_stmt_call_1":23]
776+
│ ├── args
777+
│ │ └── variable: foo:1
778+
│ ├── params: foo:2
779+
│ └── body
780+
│ └── project
781+
│ ├── columns: "_stmt_call_ret_3":22
782+
│ ├── project
783+
│ │ ├── columns: foo:19
784+
│ │ ├── barrier
785+
│ │ │ ├── columns: stmt_call_2:3
786+
│ │ │ └── project
787+
│ │ │ ├── columns: stmt_call_2:3
788+
│ │ │ ├── values
789+
│ │ │ │ └── tuple
790+
│ │ │ └── projections
791+
│ │ │ └── udf: p_143171 [as=stmt_call_2:3]
792+
│ │ │ └── body
793+
│ │ │ └── limit
794+
│ │ │ ├── columns: "_stmt_exec_1":18
795+
│ │ │ ├── project
796+
│ │ │ │ ├── columns: "_stmt_exec_1":18
797+
│ │ │ │ ├── barrier
798+
│ │ │ │ │ ├── columns: foo:4
799+
│ │ │ │ │ └── project
800+
│ │ │ │ │ ├── columns: foo:4
801+
│ │ │ │ │ ├── values
802+
│ │ │ │ │ │ └── tuple
803+
│ │ │ │ │ └── projections
804+
│ │ │ │ │ └── cast: INT8 [as=foo:4]
805+
│ │ │ │ │ └── null
806+
│ │ │ │ └── projections
807+
│ │ │ │ └── udf: _stmt_exec_1 [as="_stmt_exec_1":18]
808+
│ │ │ │ ├── args
809+
│ │ │ │ │ └── variable: foo:4
810+
│ │ │ │ ├── params: foo:5
811+
│ │ │ │ └── body
812+
│ │ │ │ └── project
813+
│ │ │ │ ├── columns: "_stmt_exec_ret_2":17
814+
│ │ │ │ ├── project
815+
│ │ │ │ │ ├── columns: foo:16
816+
│ │ │ │ │ ├── right-join (cross)
817+
│ │ │ │ │ │ ├── columns: i:7
818+
│ │ │ │ │ │ ├── barrier
819+
│ │ │ │ │ │ │ ├── columns: i:7!null
820+
│ │ │ │ │ │ │ └── limit
821+
│ │ │ │ │ │ │ ├── columns: i:7!null
822+
│ │ │ │ │ │ │ ├── project
823+
│ │ │ │ │ │ │ │ ├── columns: i:7!null
824+
│ │ │ │ │ │ │ │ └── insert t
825+
│ │ │ │ │ │ │ │ ├── columns: k:6!null i:7!null s:8!null
826+
│ │ │ │ │ │ │ │ ├── insert-mapping:
827+
│ │ │ │ │ │ │ │ │ ├── column1:11 => k:6
828+
│ │ │ │ │ │ │ │ │ ├── column2:12 => i:7
829+
│ │ │ │ │ │ │ │ │ └── column3:13 => s:8
830+
│ │ │ │ │ │ │ │ ├── return-mapping:
831+
│ │ │ │ │ │ │ │ │ ├── column1:11 => k:6
832+
│ │ │ │ │ │ │ │ │ ├── column2:12 => i:7
833+
│ │ │ │ │ │ │ │ │ └── column3:13 => s:8
834+
│ │ │ │ │ │ │ │ └── values
835+
│ │ │ │ │ │ │ │ ├── columns: column1:11!null column2:12!null column3:13!null
836+
│ │ │ │ │ │ │ │ └── tuple
837+
│ │ │ │ │ │ │ │ ├── const: 1
838+
│ │ │ │ │ │ │ │ ├── const: 2
839+
│ │ │ │ │ │ │ │ └── const: 'foo'
840+
│ │ │ │ │ │ │ └── const: 1
841+
│ │ │ │ │ │ ├── values
842+
│ │ │ │ │ │ │ └── tuple
843+
│ │ │ │ │ │ └── filters (true)
844+
│ │ │ │ │ └── projections
845+
│ │ │ │ │ └── variable: i:7 [as=foo:16]
846+
│ │ │ │ └── projections
847+
│ │ │ │ └── udf: _stmt_exec_ret_2 [as="_stmt_exec_ret_2":17]
848+
│ │ │ │ ├── tail-call
849+
│ │ │ │ ├── args
850+
│ │ │ │ │ └── variable: foo:16
851+
│ │ │ │ ├── params: foo:14
852+
│ │ │ │ └── body
853+
│ │ │ │ └── project
854+
│ │ │ │ ├── columns: "_implicit_return":15
855+
│ │ │ │ ├── values
856+
│ │ │ │ │ └── tuple
857+
│ │ │ │ └── projections
858+
│ │ │ │ └── cast: RECORD [as="_implicit_return":15]
859+
│ │ │ │ └── tuple
860+
│ │ │ │ └── variable: foo:14
861+
│ │ │ └── const: 1
862+
│ │ └── projections
863+
│ │ └── column-access: 0 [as=foo:19]
864+
│ │ └── variable: stmt_call_2:3
865+
│ └── projections
866+
│ └── udf: _stmt_call_ret_3 [as="_stmt_call_ret_3":22]
867+
│ ├── tail-call
868+
│ ├── args
869+
│ │ └── variable: foo:19
870+
│ ├── params: foo:20
871+
│ └── body
872+
│ └── project
873+
│ ├── columns: "_implicit_return":21
874+
│ ├── values
875+
│ │ └── tuple
876+
│ └── projections
877+
│ └── cast: VOID [as="_implicit_return":21]
878+
│ └── null
879+
└── const: 1

0 commit comments

Comments
 (0)