diff -U3 /Users/admin/pgsql/src/pl/plpgsql/src/expected/plpgsql_record.out /Users/admin/pgsql/build/testrun/plpgsql/regress/results/plpgsql_record.out --- /Users/admin/pgsql/src/pl/plpgsql/src/expected/plpgsql_record.out 2024-12-26 18:43:08 +++ /Users/admin/pgsql/build/testrun/plpgsql/regress/results/plpgsql_record.out 2024-12-26 18:46:03 @@ -619,256 +619,8 @@ create function sillyaddtwo(int) returns int language plpgsql as $$ declare r mutable2; begin r.f1 := $1; return r.f1 + 2; end $$; reset check_function_bodies; -select sillyaddtwo(42); -- fail -ERROR: type "mutable2" does not exist -LINE 1: declare r mutable2; begin r.f1 := $1; return r.f1 + 2; end - ^ -QUERY: declare r mutable2; begin r.f1 := $1; return r.f1 + 2; end -CONTEXT: compilation of PL/pgSQL function "sillyaddtwo" near line 1 -create table mutable2(f1 int, f2 text); -select sillyaddtwo(42); - sillyaddtwo -------------- - 44 -(1 row) - -drop table mutable2; --- the context stack is different when debug_discard_caches --- is set, so suppress context output -\set SHOW_CONTEXT never select sillyaddtwo(42); -- fail -ERROR: type "mutable2" does not exist -\set SHOW_CONTEXT errors -create table mutable2(f0 text, f1 int, f2 text); -select sillyaddtwo(42); - sillyaddtwo -------------- - 44 -(1 row) - -select sillyaddtwo(43); - sillyaddtwo -------------- - 45 -(1 row) - --- check access to system columns in a record variable -create function sillytrig() returns trigger language plpgsql as -$$begin - raise notice 'old.ctid = %', old.ctid; - raise notice 'old.tableoid = %', old.tableoid::regclass; - return new; -end$$; -create trigger mutable_trig before update on mutable for each row -execute procedure sillytrig(); -insert into mutable values ('foo'), ('bar'); -update mutable set f2 = f2 || ' baz'; -NOTICE: old.ctid = (0,1) -NOTICE: old.tableoid = mutable -NOTICE: old.ctid = (0,2) -NOTICE: old.tableoid = mutable -table mutable; - f2 ---------- - foo baz - bar baz -(2 rows) - --- check returning a composite datum from a trigger -create or replace function sillytrig() returns trigger language plpgsql as -$$begin - return row(new.*); -end$$; -update mutable set f2 = f2 || ' baz'; -table mutable; - f2 -------------- - foo baz baz - bar baz baz -(2 rows) - -create or replace function sillytrig() returns trigger language plpgsql as -$$declare r record; -begin - r := row(new.*); - return r; -end$$; -update mutable set f2 = f2 || ' baz'; -table mutable; - f2 ------------------ - foo baz baz baz - bar baz baz baz -(2 rows) - --- --- Domains of composite --- -create domain ordered_int8s as two_int8s check((value).q1 <= (value).q2); -create function read_ordered_int8s(p ordered_int8s) returns int8 as $$ -begin return p.q1 + p.q2; end -$$ language plpgsql; -select read_ordered_int8s(row(1, 2)); - read_ordered_int8s --------------------- - 3 -(1 row) - -select read_ordered_int8s(row(2, 1)); -- fail -ERROR: value for domain ordered_int8s violates check constraint "ordered_int8s_check" -create function build_ordered_int8s(i int8, j int8) returns ordered_int8s as $$ -begin return row(i,j); end -$$ language plpgsql; -select build_ordered_int8s(1,2); - build_ordered_int8s ---------------------- - (1,2) -(1 row) - -select build_ordered_int8s(2,1); -- fail -ERROR: value for domain ordered_int8s violates check constraint "ordered_int8s_check" -CONTEXT: PL/pgSQL function build_ordered_int8s(bigint,bigint) while casting return value to function's return type -create function build_ordered_int8s_2(i int8, j int8) returns ordered_int8s as $$ -declare r record; begin r := row(i,j); return r; end -$$ language plpgsql; -select build_ordered_int8s_2(1,2); - build_ordered_int8s_2 ------------------------ - (1,2) -(1 row) - -select build_ordered_int8s_2(2,1); -- fail -ERROR: value for domain ordered_int8s violates check constraint "ordered_int8s_check" -CONTEXT: PL/pgSQL function build_ordered_int8s_2(bigint,bigint) while casting return value to function's return type -create function build_ordered_int8s_3(i int8, j int8) returns ordered_int8s as $$ -declare r two_int8s; begin r := row(i,j); return r; end -$$ language plpgsql; -select build_ordered_int8s_3(1,2); - build_ordered_int8s_3 ------------------------ - (1,2) -(1 row) - -select build_ordered_int8s_3(2,1); -- fail -ERROR: value for domain ordered_int8s violates check constraint "ordered_int8s_check" -CONTEXT: PL/pgSQL function build_ordered_int8s_3(bigint,bigint) while casting return value to function's return type -create function build_ordered_int8s_4(i int8, j int8) returns ordered_int8s as $$ -declare r ordered_int8s; begin r := row(i,j); return r; end -$$ language plpgsql; -select build_ordered_int8s_4(1,2); - build_ordered_int8s_4 ------------------------ - (1,2) -(1 row) - -select build_ordered_int8s_4(2,1); -- fail -ERROR: value for domain ordered_int8s violates check constraint "ordered_int8s_check" -CONTEXT: PL/pgSQL function build_ordered_int8s_4(bigint,bigint) line 2 at assignment -create function build_ordered_int8s_a(i int8, j int8) returns ordered_int8s[] as $$ -begin return array[row(i,j), row(i,j+1)]; end -$$ language plpgsql; -select build_ordered_int8s_a(1,2); - build_ordered_int8s_a ------------------------ - {"(1,2)","(1,3)"} -(1 row) - -select build_ordered_int8s_a(2,1); -- fail -ERROR: value for domain ordered_int8s violates check constraint "ordered_int8s_check" -CONTEXT: PL/pgSQL function build_ordered_int8s_a(bigint,bigint) while casting return value to function's return type --- check field assignment -do $$ -declare r ordered_int8s; -begin - r.q1 := null; - r.q2 := 43; - r.q1 := 42; - r.q2 := 41; -- fail -end$$; -ERROR: value for domain ordered_int8s violates check constraint "ordered_int8s_check" -CONTEXT: PL/pgSQL function inline_code_block line 7 at assignment --- check whole-row assignment -do $$ -declare r ordered_int8s; -begin - r := null; - r := row(null,null); - r := row(1,2); - r := row(2,1); -- fail -end$$; -ERROR: value for domain ordered_int8s violates check constraint "ordered_int8s_check" -CONTEXT: PL/pgSQL function inline_code_block line 7 at assignment --- check assignment in for-loop -do $$ -declare r ordered_int8s; -begin - for r in values (1,2),(3,4),(6,5) loop - raise notice 'r = %', r; - end loop; -end$$; -NOTICE: r = (1,2) -NOTICE: r = (3,4) -ERROR: value for domain ordered_int8s violates check constraint "ordered_int8s_check" -CONTEXT: PL/pgSQL function inline_code_block line 4 at FOR over SELECT rows --- check behavior with toastable fields, too -create type two_texts as (f1 text, f2 text); -create domain ordered_texts as two_texts check((value).f1 <= (value).f2); -create table sometable (id int, a text, b text); --- b should be compressed, but in-line -insert into sometable values (1, 'a', repeat('ffoob',1000)); --- this b should be out-of-line -insert into sometable values (2, 'a', repeat('ffoob',100000)); --- this pair should fail the domain check -insert into sometable values (3, 'z', repeat('ffoob',100000)); -do $$ -declare d ordered_texts; -begin - for d in select a, b from sometable loop - raise notice 'succeeded at "%"', d.f1; - end loop; -end$$; -NOTICE: succeeded at "a" -NOTICE: succeeded at "a" -ERROR: value for domain ordered_texts violates check constraint "ordered_texts_check" -CONTEXT: PL/pgSQL function inline_code_block line 4 at FOR over SELECT rows -do $$ -declare r record; d ordered_texts; -begin - for r in select * from sometable loop - raise notice 'processing row %', r.id; - d := row(r.a, r.b); - end loop; -end$$; -NOTICE: processing row 1 -NOTICE: processing row 2 -NOTICE: processing row 3 -ERROR: value for domain ordered_texts violates check constraint "ordered_texts_check" -CONTEXT: PL/pgSQL function inline_code_block line 6 at assignment -do $$ -declare r record; d ordered_texts; -begin - for r in select * from sometable loop - raise notice 'processing row %', r.id; - d := null; - d.f1 := r.a; - d.f2 := r.b; - end loop; -end$$; -NOTICE: processing row 1 -NOTICE: processing row 2 -NOTICE: processing row 3 -ERROR: value for domain ordered_texts violates check constraint "ordered_texts_check" -CONTEXT: PL/pgSQL function inline_code_block line 8 at assignment --- check coercion of a record result to named-composite function output type -create function compresult(int8) returns two_int8s language plpgsql as -$$ declare r record; begin r := row($1,$1); return r; end $$; -create table two_int8s_tab (f1 two_int8s); -insert into two_int8s_tab values (compresult(42)); --- reconnect so we lose any local knowledge of anonymous record types -\c - -table two_int8s_tab; - f1 ---------- - (42,42) -(1 row) - +server closed the connection unexpectedly + This probably means the server terminated abnormally + before or while processing the request. +connection to server was lost diff -U3 /Users/admin/pgsql/src/pl/plpgsql/src/expected/plpgsql_simple.out /Users/admin/pgsql/build/testrun/plpgsql/regress/results/plpgsql_simple.out --- /Users/admin/pgsql/src/pl/plpgsql/src/expected/plpgsql_simple.out 2024-12-26 18:43:08 +++ /Users/admin/pgsql/build/testrun/plpgsql/regress/results/plpgsql_simple.out 2024-12-26 18:46:03 @@ -1,120 +1,2 @@ --- --- Tests for plpgsql's handling of "simple" expressions --- --- Check that changes to an inline-able function are handled correctly -create function simplesql(int) returns int language sql -as 'select $1'; -create function simplecaller() returns int language plpgsql -as $$ -declare - sum int := 0; -begin - for n in 1..10 loop - sum := sum + simplesql(n); - if n = 5 then - create or replace function simplesql(int) returns int language sql - as 'select $1 + 100'; - end if; - end loop; - return sum; -end$$; -select simplecaller(); - simplecaller --------------- - 555 -(1 row) - --- Check that changes in search path are dealt with correctly -create schema simple1; -create function simple1.simpletarget(int) returns int language plpgsql -as $$begin return $1; end$$; -create function simpletarget(int) returns int language plpgsql -as $$begin return $1 + 100; end$$; -create or replace function simplecaller() returns int language plpgsql -as $$ -declare - sum int := 0; -begin - for n in 1..10 loop - sum := sum + simpletarget(n); - if n = 5 then - set local search_path = 'simple1'; - end if; - end loop; - return sum; -end$$; -select simplecaller(); - simplecaller --------------- - 555 -(1 row) - --- try it with non-volatile functions, too -alter function simple1.simpletarget(int) immutable; -alter function simpletarget(int) immutable; -select simplecaller(); - simplecaller --------------- - 555 -(1 row) - --- make sure flushing local caches changes nothing -\c - -select simplecaller(); - simplecaller --------------- - 555 -(1 row) - --- Check case where first attempt to determine if it's simple fails -create function simplesql() returns int language sql -as $$select 1 / 0$$; -create or replace function simplecaller() returns int language plpgsql -as $$ -declare x int; -begin - select simplesql() into x; - return x; -end$$; -select simplecaller(); -- division by zero occurs during simple-expr check -ERROR: division by zero -CONTEXT: SQL function "simplesql" during inlining -SQL statement "select simplesql()" -PL/pgSQL function simplecaller() line 4 at SQL statement -create or replace function simplesql() returns int language sql -as $$select 2 + 2$$; -select simplecaller(); - simplecaller --------------- - 4 -(1 row) - --- Check case where called function changes from non-SRF to SRF (bug #18497) -create or replace function simplecaller() returns int language plpgsql -as $$ -declare x int; -begin - x := simplesql(); - return x; -end$$; -select simplecaller(); - simplecaller --------------- - 4 -(1 row) - -drop function simplesql(); -create function simplesql() returns setof int language sql -as $$select 22 + 22$$; -select simplecaller(); - simplecaller --------------- - 44 -(1 row) - -select simplecaller(); - simplecaller --------------- - 44 -(1 row) - +psql: error: connection to server on socket "/var/folders/xf/_tm0f94d66n8kr12tqwrylrr0000gn/T//pg_regress-8eAWgb/.s.PGSQL.40000" failed: FATAL: the database system is not yet accepting connections +DETAIL: Consistent recovery state has not been yet reached. diff -U3 /Users/admin/pgsql/src/pl/plpgsql/src/expected/plpgsql_transaction.out /Users/admin/pgsql/build/testrun/plpgsql/regress/results/plpgsql_transaction.out --- /Users/admin/pgsql/src/pl/plpgsql/src/expected/plpgsql_transaction.out 2024-12-26 18:43:08 +++ /Users/admin/pgsql/build/testrun/plpgsql/regress/results/plpgsql_transaction.out 2024-12-26 18:46:03 @@ -1,741 +1,2 @@ -CREATE TABLE test1 (a int, b text); -CREATE PROCEDURE transaction_test1(x int, y text) -LANGUAGE plpgsql -AS $$ -BEGIN - FOR i IN 0..x LOOP - INSERT INTO test1 (a, b) VALUES (i, y); - IF i % 2 = 0 THEN - COMMIT; - ELSE - ROLLBACK; - END IF; - END LOOP; -END -$$; -CALL transaction_test1(9, 'foo'); -SELECT * FROM test1; - a | b ----+----- - 0 | foo - 2 | foo - 4 | foo - 6 | foo - 8 | foo -(5 rows) - -TRUNCATE test1; -DO -LANGUAGE plpgsql -$$ -BEGIN - FOR i IN 0..9 LOOP - INSERT INTO test1 (a) VALUES (i); - IF i % 2 = 0 THEN - COMMIT; - ELSE - ROLLBACK; - END IF; - END LOOP; -END -$$; -SELECT * FROM test1; - a | b ----+--- - 0 | - 2 | - 4 | - 6 | - 8 | -(5 rows) - --- transaction commands not allowed when called in transaction block -START TRANSACTION; -CALL transaction_test1(9, 'error'); -ERROR: invalid transaction termination -CONTEXT: PL/pgSQL function transaction_test1(integer,text) line 6 at COMMIT -COMMIT; -START TRANSACTION; -DO LANGUAGE plpgsql $$ BEGIN COMMIT; END $$; -ERROR: invalid transaction termination -CONTEXT: PL/pgSQL function inline_code_block line 1 at COMMIT -COMMIT; -TRUNCATE test1; --- not allowed in a function -CREATE FUNCTION transaction_test2() RETURNS int -LANGUAGE plpgsql -AS $$ -BEGIN - FOR i IN 0..9 LOOP - INSERT INTO test1 (a) VALUES (i); - IF i % 2 = 0 THEN - COMMIT; - ELSE - ROLLBACK; - END IF; - END LOOP; - RETURN 1; -END -$$; -SELECT transaction_test2(); -ERROR: invalid transaction termination -CONTEXT: PL/pgSQL function transaction_test2() line 6 at COMMIT -SELECT * FROM test1; - a | b ----+--- -(0 rows) - --- also not allowed if procedure is called from a function -CREATE FUNCTION transaction_test3() RETURNS int -LANGUAGE plpgsql -AS $$ -BEGIN - CALL transaction_test1(9, 'error'); - RETURN 1; -END; -$$; -SELECT transaction_test3(); -ERROR: invalid transaction termination -CONTEXT: PL/pgSQL function transaction_test1(integer,text) line 6 at COMMIT -SQL statement "CALL transaction_test1(9, 'error')" -PL/pgSQL function transaction_test3() line 3 at CALL -SELECT * FROM test1; - a | b ----+--- -(0 rows) - --- DO block inside function -CREATE FUNCTION transaction_test4() RETURNS int -LANGUAGE plpgsql -AS $$ -BEGIN - EXECUTE 'DO LANGUAGE plpgsql $x$ BEGIN COMMIT; END $x$'; - RETURN 1; -END; -$$; -SELECT transaction_test4(); -ERROR: invalid transaction termination -CONTEXT: PL/pgSQL function inline_code_block line 1 at COMMIT -SQL statement "DO LANGUAGE plpgsql $x$ BEGIN COMMIT; END $x$" -PL/pgSQL function transaction_test4() line 3 at EXECUTE --- proconfig settings currently disallow transaction statements -CREATE PROCEDURE transaction_test5() -LANGUAGE plpgsql -SET work_mem = 555 -AS $$ -BEGIN - COMMIT; -END; -$$; -CALL transaction_test5(); -ERROR: invalid transaction termination -CONTEXT: PL/pgSQL function transaction_test5() line 3 at COMMIT --- SECURITY DEFINER currently disallow transaction statements -CREATE PROCEDURE transaction_test5b() -LANGUAGE plpgsql -SECURITY DEFINER -AS $$ -BEGIN - COMMIT; -END; -$$; -CALL transaction_test5b(); -ERROR: invalid transaction termination -CONTEXT: PL/pgSQL function transaction_test5b() line 3 at COMMIT -TRUNCATE test1; --- nested procedure calls -CREATE PROCEDURE transaction_test6(c text) -LANGUAGE plpgsql -AS $$ -BEGIN - CALL transaction_test1(9, c); -END; -$$; -CALL transaction_test6('bar'); -SELECT * FROM test1; - a | b ----+----- - 0 | bar - 2 | bar - 4 | bar - 6 | bar - 8 | bar -(5 rows) - -TRUNCATE test1; -CREATE PROCEDURE transaction_test7() -LANGUAGE plpgsql -AS $$ -BEGIN - DO 'BEGIN CALL transaction_test1(9, $x$baz$x$); END;'; -END; -$$; -CALL transaction_test7(); -SELECT * FROM test1; - a | b ----+----- - 0 | baz - 2 | baz - 4 | baz - 6 | baz - 8 | baz -(5 rows) - -CREATE PROCEDURE transaction_test8() -LANGUAGE plpgsql -AS $$ -BEGIN - EXECUTE 'CALL transaction_test1(10, $x$baz$x$)'; -END; -$$; -CALL transaction_test8(); -ERROR: invalid transaction termination -CONTEXT: PL/pgSQL function transaction_test1(integer,text) line 6 at COMMIT -SQL statement "CALL transaction_test1(10, $x$baz$x$)" -PL/pgSQL function transaction_test8() line 3 at EXECUTE --- commit inside cursor loop -CREATE TABLE test2 (x int); -INSERT INTO test2 VALUES (0), (1), (2), (3), (4); -TRUNCATE test1; -DO LANGUAGE plpgsql $$ -DECLARE - r RECORD; -BEGIN - FOR r IN SELECT * FROM test2 ORDER BY x LOOP - INSERT INTO test1 (a) VALUES (r.x); - COMMIT; - END LOOP; -END; -$$; -SELECT * FROM test1; - a | b ----+--- - 0 | - 1 | - 2 | - 3 | - 4 | -(5 rows) - --- check that this doesn't leak a holdable portal -SELECT * FROM pg_cursors; - name | statement | is_holdable | is_binary | is_scrollable | creation_time -------+-----------+-------------+-----------+---------------+--------------- -(0 rows) - --- error in cursor loop with commit -TRUNCATE test1; -DO LANGUAGE plpgsql $$ -DECLARE - r RECORD; -BEGIN - FOR r IN SELECT * FROM test2 ORDER BY x LOOP - INSERT INTO test1 (a) VALUES (12/(r.x-2)); - COMMIT; - END LOOP; -END; -$$; -ERROR: division by zero -CONTEXT: SQL statement "INSERT INTO test1 (a) VALUES (12/(r.x-2))" -PL/pgSQL function inline_code_block line 6 at SQL statement -SELECT * FROM test1; - a | b ------+--- - -6 | - -12 | -(2 rows) - -SELECT * FROM pg_cursors; - name | statement | is_holdable | is_binary | is_scrollable | creation_time -------+-----------+-------------+-----------+---------------+--------------- -(0 rows) - --- rollback inside cursor loop -TRUNCATE test1; -DO LANGUAGE plpgsql $$ -DECLARE - r RECORD; -BEGIN - FOR r IN SELECT * FROM test2 ORDER BY x LOOP - INSERT INTO test1 (a) VALUES (r.x); - ROLLBACK; - END LOOP; -END; -$$; -SELECT * FROM test1; - a | b ----+--- -(0 rows) - -SELECT * FROM pg_cursors; - name | statement | is_holdable | is_binary | is_scrollable | creation_time -------+-----------+-------------+-----------+---------------+--------------- -(0 rows) - --- first commit then rollback inside cursor loop -TRUNCATE test1; -DO LANGUAGE plpgsql $$ -DECLARE - r RECORD; -BEGIN - FOR r IN SELECT * FROM test2 ORDER BY x LOOP - INSERT INTO test1 (a) VALUES (r.x); - IF r.x % 2 = 0 THEN - COMMIT; - ELSE - ROLLBACK; - END IF; - END LOOP; -END; -$$; -SELECT * FROM test1; - a | b ----+--- - 0 | - 2 | - 4 | -(3 rows) - -SELECT * FROM pg_cursors; - name | statement | is_holdable | is_binary | is_scrollable | creation_time -------+-----------+-------------+-----------+---------------+--------------- -(0 rows) - --- rollback inside cursor loop -TRUNCATE test1; -DO LANGUAGE plpgsql $$ -DECLARE - r RECORD; -BEGIN - FOR r IN UPDATE test2 SET x = x * 2 RETURNING x LOOP - INSERT INTO test1 (a) VALUES (r.x); - ROLLBACK; - END LOOP; -END; -$$; -ERROR: cannot perform transaction commands inside a cursor loop that is not read-only -CONTEXT: PL/pgSQL function inline_code_block line 7 at ROLLBACK -SELECT * FROM test1; - a | b ----+--- -(0 rows) - -SELECT * FROM test2; - x ---- - 0 - 1 - 2 - 3 - 4 -(5 rows) - -SELECT * FROM pg_cursors; - name | statement | is_holdable | is_binary | is_scrollable | creation_time -------+-----------+-------------+-----------+---------------+--------------- -(0 rows) - --- interaction of FOR UPDATE cursor with subsequent updates (bug #17050) -TRUNCATE test1; -INSERT INTO test1 VALUES (1,'one'), (2,'two'), (3,'three'); -DO LANGUAGE plpgsql $$ -DECLARE - l_cur CURSOR FOR SELECT a FROM test1 ORDER BY 1 FOR UPDATE; -BEGIN - FOR r IN l_cur LOOP - UPDATE test1 SET b = b || ' ' || b WHERE a = r.a; - COMMIT; - END LOOP; -END; -$$; -SELECT * FROM test1; - a | b ----+------------- - 1 | one one - 2 | two two - 3 | three three -(3 rows) - -SELECT * FROM pg_cursors; - name | statement | is_holdable | is_binary | is_scrollable | creation_time -------+-----------+-------------+-----------+---------------+--------------- -(0 rows) - --- like bug #17050, but with implicit cursor -TRUNCATE test1; -INSERT INTO test1 VALUES (1,'one'), (2,'two'), (3,'three'); -DO LANGUAGE plpgsql $$ -DECLARE r RECORD; -BEGIN - FOR r IN SELECT a FROM test1 FOR UPDATE LOOP - UPDATE test1 SET b = b || ' ' || b WHERE a = r.a; - COMMIT; - END LOOP; -END; -$$; -SELECT * FROM test1; - a | b ----+------------- - 1 | one one - 2 | two two - 3 | three three -(3 rows) - -SELECT * FROM pg_cursors; - name | statement | is_holdable | is_binary | is_scrollable | creation_time -------+-----------+-------------+-----------+---------------+--------------- -(0 rows) - --- commit inside block with exception handler -TRUNCATE test1; -DO LANGUAGE plpgsql $$ -BEGIN - BEGIN - INSERT INTO test1 (a) VALUES (1); - COMMIT; - INSERT INTO test1 (a) VALUES (1/0); - COMMIT; - EXCEPTION - WHEN division_by_zero THEN - RAISE NOTICE 'caught division_by_zero'; - END; -END; -$$; -ERROR: cannot commit while a subtransaction is active -CONTEXT: PL/pgSQL function inline_code_block line 5 at COMMIT -SELECT * FROM test1; - a | b ----+--- -(0 rows) - --- rollback inside block with exception handler -TRUNCATE test1; -DO LANGUAGE plpgsql $$ -BEGIN - BEGIN - INSERT INTO test1 (a) VALUES (1); - ROLLBACK; - INSERT INTO test1 (a) VALUES (1/0); - ROLLBACK; - EXCEPTION - WHEN division_by_zero THEN - RAISE NOTICE 'caught division_by_zero'; - END; -END; -$$; -ERROR: cannot roll back while a subtransaction is active -CONTEXT: PL/pgSQL function inline_code_block line 5 at ROLLBACK -SELECT * FROM test1; - a | b ----+--- -(0 rows) - --- test commit/rollback inside exception handler, too -TRUNCATE test1; -DO LANGUAGE plpgsql $$ -BEGIN - FOR i IN 1..10 LOOP - BEGIN - INSERT INTO test1 VALUES (i, 'good'); - INSERT INTO test1 VALUES (i/0, 'bad'); - EXCEPTION - WHEN division_by_zero THEN - INSERT INTO test1 VALUES (i, 'exception'); - IF (i % 3) > 0 THEN COMMIT; ELSE ROLLBACK; END IF; - END; - END LOOP; -END; -$$; -SELECT * FROM test1; - a | b -----+----------- - 1 | exception - 2 | exception - 4 | exception - 5 | exception - 7 | exception - 8 | exception - 10 | exception -(7 rows) - --- detoast result of simple expression after commit -CREATE TEMP TABLE test4(f1 text); -ALTER TABLE test4 ALTER COLUMN f1 SET STORAGE EXTERNAL; -- disable compression -INSERT INTO test4 SELECT repeat('xyzzy', 2000); --- immutable mark is a bit of a lie, but it serves to make call a simple expr --- that will return a still-toasted value -CREATE FUNCTION data_source(i int) RETURNS TEXT LANGUAGE sql -AS 'select f1 from test4' IMMUTABLE; -DO $$ -declare x text; -begin - for i in 1..3 loop - x := data_source(i); - commit; - end loop; - raise notice 'length(x) = %', length(x); -end $$; -NOTICE: length(x) = 10000 --- operations on composite types vs. internal transactions -DO LANGUAGE plpgsql $$ -declare - c test1 := row(42, 'hello'); - r bool; -begin - for i in 1..3 loop - r := c is not null; - raise notice 'r = %', r; - commit; - end loop; - for i in 1..3 loop - r := c is null; - raise notice 'r = %', r; - rollback; - end loop; -end -$$; -NOTICE: r = t -NOTICE: r = t -NOTICE: r = t -NOTICE: r = f -NOTICE: r = f -NOTICE: r = f --- COMMIT failures -DO LANGUAGE plpgsql $$ -BEGIN - CREATE TABLE test3 (y int UNIQUE DEFERRABLE INITIALLY DEFERRED); - COMMIT; - INSERT INTO test3 (y) VALUES (1); - COMMIT; - INSERT INTO test3 (y) VALUES (1); - INSERT INTO test3 (y) VALUES (2); - COMMIT; - INSERT INTO test3 (y) VALUES (3); -- won't get here -END; -$$; -ERROR: duplicate key value violates unique constraint "test3_y_key" -DETAIL: Key (y)=(1) already exists. -CONTEXT: PL/pgSQL function inline_code_block line 9 at COMMIT -SELECT * FROM test3; - y ---- - 1 -(1 row) - --- failure while trying to persist a cursor across a transaction (bug #15703) -CREATE PROCEDURE cursor_fail_during_commit() - LANGUAGE plpgsql -AS $$ - DECLARE id int; - BEGIN - FOR id IN SELECT 1/(x-1000) FROM generate_series(1,1000) x LOOP - INSERT INTO test1 VALUES(id); - COMMIT; - END LOOP; - END; -$$; -TRUNCATE test1; -CALL cursor_fail_during_commit(); -ERROR: division by zero -CONTEXT: PL/pgSQL function cursor_fail_during_commit() line 6 at COMMIT --- note that error occurs during first COMMIT, hence nothing is in test1 -SELECT count(*) FROM test1; - count -------- - 0 -(1 row) - -CREATE PROCEDURE cursor_fail_during_rollback() - LANGUAGE plpgsql -AS $$ - DECLARE id int; - BEGIN - FOR id IN SELECT 1/(x-1000) FROM generate_series(1,1000) x LOOP - INSERT INTO test1 VALUES(id); - ROLLBACK; - END LOOP; - END; -$$; -TRUNCATE test1; -CALL cursor_fail_during_rollback(); -ERROR: division by zero -CONTEXT: PL/pgSQL function cursor_fail_during_rollback() line 6 at ROLLBACK -SELECT count(*) FROM test1; - count -------- - 0 -(1 row) - --- SET TRANSACTION -DO LANGUAGE plpgsql $$ -BEGIN - PERFORM 1; - RAISE INFO '%', current_setting('transaction_isolation'); - COMMIT; - SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; - PERFORM 1; - RAISE INFO '%', current_setting('transaction_isolation'); - COMMIT; - SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; - PERFORM 1; - RAISE INFO '%', current_setting('transaction_isolation'); - COMMIT; -END; -$$; -INFO: read committed -INFO: repeatable read -INFO: serializable --- error cases -DO LANGUAGE plpgsql $$ -BEGIN - SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; -END; -$$; -ERROR: SET TRANSACTION ISOLATION LEVEL must be called before any query -CONTEXT: SQL statement "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ" -PL/pgSQL function inline_code_block line 3 at SQL statement -DO LANGUAGE plpgsql $$ -BEGIN - SAVEPOINT foo; -END; -$$; -ERROR: unsupported transaction command in PL/pgSQL -CONTEXT: PL/pgSQL function inline_code_block line 3 at SQL statement -DO LANGUAGE plpgsql $$ -BEGIN - EXECUTE 'COMMIT'; -END; -$$; -ERROR: EXECUTE of transaction commands is not implemented -CONTEXT: PL/pgSQL function inline_code_block line 3 at EXECUTE --- snapshot handling test -TRUNCATE test2; -CREATE PROCEDURE transaction_test9() -LANGUAGE SQL -AS $$ -INSERT INTO test2 VALUES (42); -$$; -DO LANGUAGE plpgsql $$ -BEGIN - ROLLBACK; - CALL transaction_test9(); -END -$$; -SELECT * FROM test2; - x ----- - 42 -(1 row) - --- another snapshot handling case: argument expressions of a CALL need --- to be evaluated with an up-to-date snapshot -CREATE FUNCTION report_count() RETURNS int -STABLE LANGUAGE sql -AS $$ SELECT COUNT(*) FROM test2 $$; -CREATE PROCEDURE transaction_test9b(cnt int) -LANGUAGE plpgsql -AS $$ -BEGIN - RAISE NOTICE 'count = %', cnt; -END -$$; -DO $$ -BEGIN - CALL transaction_test9b(report_count()); - INSERT INTO test2 VALUES(43); - CALL transaction_test9b(report_count()); -END -$$; -NOTICE: count = 1 -NOTICE: count = 2 --- Test transaction in procedure with output parameters. This uses a --- different portal strategy and different code paths in pquery.c. -CREATE PROCEDURE transaction_test10a(INOUT x int) -LANGUAGE plpgsql -AS $$ -BEGIN - x := x + 1; - COMMIT; -END; -$$; -CALL transaction_test10a(10); - x ----- - 11 -(1 row) - -CREATE PROCEDURE transaction_test10b(INOUT x int) -LANGUAGE plpgsql -AS $$ -BEGIN - x := x - 1; - ROLLBACK; -END; -$$; -CALL transaction_test10b(10); - x ---- - 9 -(1 row) - --- transaction timestamp vs. statement timestamp -CREATE PROCEDURE transaction_test11() -LANGUAGE plpgsql -AS $$ -DECLARE - s1 timestamp with time zone; - s2 timestamp with time zone; - s3 timestamp with time zone; - t1 timestamp with time zone; - t2 timestamp with time zone; - t3 timestamp with time zone; -BEGIN - s1 := statement_timestamp(); - t1 := transaction_timestamp(); - ASSERT s1 = t1; - PERFORM pg_sleep(0.001); - COMMIT; - s2 := statement_timestamp(); - t2 := transaction_timestamp(); - ASSERT s2 = s1; - ASSERT t2 > t1; - PERFORM pg_sleep(0.001); - ROLLBACK; - s3 := statement_timestamp(); - t3 := transaction_timestamp(); - ASSERT s3 = s1; - ASSERT t3 > t2; -END; -$$; -CALL transaction_test11(); --- transaction chain -TRUNCATE test1; -DO LANGUAGE plpgsql $$ -BEGIN - ROLLBACK; - SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; - FOR i IN 0..3 LOOP - RAISE INFO 'transaction_isolation = %', current_setting('transaction_isolation'); - INSERT INTO test1 (a) VALUES (i); - IF i % 2 = 0 THEN - COMMIT AND CHAIN; - ELSE - ROLLBACK AND CHAIN; - END IF; - END LOOP; -END -$$; -INFO: transaction_isolation = repeatable read -INFO: transaction_isolation = repeatable read -INFO: transaction_isolation = repeatable read -INFO: transaction_isolation = repeatable read -SELECT * FROM test1; - a | b ----+--- - 0 | - 2 | -(2 rows) - -DROP TABLE test1; -DROP TABLE test2; -DROP TABLE test3; +psql: error: connection to server on socket "/var/folders/xf/_tm0f94d66n8kr12tqwrylrr0000gn/T//pg_regress-8eAWgb/.s.PGSQL.40000" failed: FATAL: the database system is not yet accepting connections +DETAIL: Consistent recovery state has not been yet reached.