@@ -472,6 +472,7 @@ INSERT INTO test4 SELECT repeat('xyzzy', 2000);
472472-- that will return a still-toasted value
473473CREATE FUNCTION data_source(i int) RETURNS TEXT LANGUAGE sql
474474AS 'select f1 from test4' IMMUTABLE;
475+ /
475476DO $$
476477declare x text;
477478begin
@@ -481,9 +482,8 @@ begin
481482 end loop;
482483 raise notice 'length(x) = %', length(x);
483484end $$;
485+ NOTICE: length(x) = 10000
484486/
485- ERROR: invalid transaction termination
486- CONTEXT: PL/iSQL function inline_code_block line 6 at COMMIT
487487-- operations on composite types vs. internal transactions
488488DO LANGUAGE plisql $$
489489declare
@@ -748,6 +748,162 @@ SELECT * FROM test1;
748748 2 |
749749(2 rows)
750750
751+ -- Test nested procedure calls with COMMIT/ROLLBACK (Issue #1007)
752+ --
753+ -- Note: Oracle-syntax procedures (CREATE PROCEDURE ... IS) default to
754+ -- AUTHID DEFINER (prosecdef=true), which forces atomic mode and blocks
755+ -- COMMIT/ROLLBACK. Use AUTHID CURRENT_USER to allow transaction control.
756+ -- This matches Oracle behavior where COMMIT is allowed regardless of AUTHID.
757+ -- Tests below verify COMMIT/ROLLBACK in nested procedure calls
758+ -- using AUTHID CURRENT_USER (Oracle-compatible syntax).
759+ -- Without AUTHID CURRENT_USER, Oracle-syntax procedures default to
760+ -- SECURITY DEFINER (prosecdef=true), which forces atomic mode and
761+ -- blocks COMMIT/ROLLBACK. This is a known limitation (see Test 0).
762+ CREATE TABLE test_nested_commit (id int);
763+ -- Inner procedure with COMMIT
764+ CREATE OR REPLACE PROCEDURE nested_inner_commit AUTHID CURRENT_USER IS
765+ BEGIN
766+ INSERT INTO test_nested_commit VALUES (1);
767+ COMMIT;
768+ INSERT INTO test_nested_commit VALUES (2);
769+ END;
770+ /
771+ -- Outer procedure calling inner with CALL keyword
772+ CREATE OR REPLACE PROCEDURE nested_outer_commit AUTHID CURRENT_USER IS
773+ BEGIN
774+ INSERT INTO test_nested_commit VALUES (0);
775+ CALL nested_inner_commit();
776+ INSERT INTO test_nested_commit VALUES (3);
777+ END;
778+ /
779+ -- Test 1: Basic nested call with COMMIT
780+ TRUNCATE test_nested_commit;
781+ CALL nested_outer_commit();
782+ SELECT * FROM test_nested_commit ORDER BY id;
783+ id
784+ ----
785+ 0
786+ 1
787+ 2
788+ 3
789+ (4 rows)
790+
791+ -- Test 2: Oracle-style call (without CALL keyword) with COMMIT
792+ CREATE OR REPLACE PROCEDURE nested_outer_oracle_style AUTHID CURRENT_USER IS
793+ BEGIN
794+ INSERT INTO test_nested_commit VALUES (10);
795+ nested_inner_commit(); -- Oracle-style call
796+ INSERT INTO test_nested_commit VALUES (13);
797+ END;
798+ /
799+ TRUNCATE test_nested_commit;
800+ CALL nested_outer_oracle_style();
801+ SELECT * FROM test_nested_commit ORDER BY id;
802+ id
803+ ----
804+ 1
805+ 2
806+ 10
807+ 13
808+ (4 rows)
809+
810+ -- Test 3: Deeply nested Oracle-style calls (4 levels) with COMMIT
811+ CREATE OR REPLACE PROCEDURE nested_level4 AUTHID CURRENT_USER IS
812+ BEGIN
813+ INSERT INTO test_nested_commit VALUES (104);
814+ COMMIT;
815+ INSERT INTO test_nested_commit VALUES (105);
816+ END;
817+ /
818+ CREATE OR REPLACE PROCEDURE nested_level3 AUTHID CURRENT_USER IS
819+ BEGIN
820+ INSERT INTO test_nested_commit VALUES (103);
821+ nested_level4(); -- Oracle-style call
822+ INSERT INTO test_nested_commit VALUES (106);
823+ END;
824+ /
825+ CREATE OR REPLACE PROCEDURE nested_level2 AUTHID CURRENT_USER IS
826+ BEGIN
827+ INSERT INTO test_nested_commit VALUES (102);
828+ nested_level3(); -- Oracle-style call
829+ INSERT INTO test_nested_commit VALUES (107);
830+ END;
831+ /
832+ CREATE OR REPLACE PROCEDURE nested_level1 AUTHID CURRENT_USER IS
833+ BEGIN
834+ INSERT INTO test_nested_commit VALUES (101);
835+ nested_level2(); -- Oracle-style call
836+ INSERT INTO test_nested_commit VALUES (108);
837+ END;
838+ /
839+ TRUNCATE test_nested_commit;
840+ CALL nested_level1();
841+ SELECT * FROM test_nested_commit ORDER BY id;
842+ id
843+ -----
844+ 101
845+ 102
846+ 103
847+ 104
848+ 105
849+ 106
850+ 107
851+ 108
852+ (8 rows)
853+
854+ -- Test 4: ROLLBACK in nested procedure with CALL keyword
855+ CREATE OR REPLACE PROCEDURE nested_inner_rollback AUTHID CURRENT_USER IS
856+ BEGIN
857+ INSERT INTO test_nested_commit VALUES (201);
858+ ROLLBACK;
859+ INSERT INTO test_nested_commit VALUES (202);
860+ END;
861+ /
862+ CREATE OR REPLACE PROCEDURE nested_outer_rollback AUTHID CURRENT_USER IS
863+ BEGIN
864+ INSERT INTO test_nested_commit VALUES (200);
865+ CALL nested_inner_rollback();
866+ INSERT INTO test_nested_commit VALUES (203);
867+ END;
868+ /
869+ TRUNCATE test_nested_commit;
870+ CALL nested_outer_rollback();
871+ SELECT * FROM test_nested_commit ORDER BY id;
872+ id
873+ -----
874+ 202
875+ 203
876+ (2 rows)
877+
878+ -- Test 5: Oracle-style call (without CALL keyword) with ROLLBACK
879+ CREATE OR REPLACE PROCEDURE nested_outer_rollback_oracle_style AUTHID CURRENT_USER IS
880+ BEGIN
881+ INSERT INTO test_nested_commit VALUES (300);
882+ nested_inner_rollback(); -- Oracle-style call
883+ INSERT INTO test_nested_commit VALUES (303);
884+ END;
885+ /
886+ TRUNCATE test_nested_commit;
887+ CALL nested_outer_rollback_oracle_style();
888+ SELECT * FROM test_nested_commit ORDER BY id;
889+ id
890+ -----
891+ 202
892+ 303
893+ (2 rows)
894+
895+ -- Clean up nested commit tests
896+ DROP PROCEDURE nested_inner_commit;
897+ DROP PROCEDURE nested_outer_commit;
898+ DROP PROCEDURE nested_outer_oracle_style;
899+ DROP PROCEDURE nested_level1;
900+ DROP PROCEDURE nested_level2;
901+ DROP PROCEDURE nested_level3;
902+ DROP PROCEDURE nested_level4;
903+ DROP PROCEDURE nested_inner_rollback;
904+ DROP PROCEDURE nested_outer_rollback;
905+ DROP PROCEDURE nested_outer_rollback_oracle_style;
906+ DROP TABLE test_nested_commit;
751907DROP TABLE test1;
752908DROP TABLE test2;
753909DROP TABLE test3;
0 commit comments