diff --git a/src/pl/plpgsql/src/expected/plpgsql_transaction.out b/src/pl/plpgsql/src/expected/plpgsql_transaction.out index 76cbdca0c56..57ab0bc0e7d 100644 --- a/src/pl/plpgsql/src/expected/plpgsql_transaction.out +++ b/src/pl/plpgsql/src/expected/plpgsql_transaction.out @@ -430,6 +430,24 @@ SELECT * FROM test1; ---+--- (0 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 diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 0ce382e1232..96bb77e0b1e 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -38,6 +38,7 @@ #include "plpgsql.h" #include "storage/proc.h" #include "tcop/cmdtag.h" +#include "tcop/pquery.h" #include "tcop/tcopprot.h" #include "tcop/utility.h" #include "utils/array.h" @@ -5958,6 +5959,15 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, expr->expr_simple_lxid == curlxid) return false; + /* + * Ensure that there's a portal-level snapshot, in case this simple + * expression is the first thing evaluated after a COMMIT or ROLLBACK. + * We'd have to do this anyway before executing the expression, so we + * might as well do it now to ensure that any possible replanning doesn't + * need to take a new snapshot. + */ + EnsurePortalSnapshotExists(); + /* * Check to see if the cached plan has been invalidated. If not, and this * is the first use in the current transaction, save a plan refcount in diff --git a/src/pl/plpgsql/src/sql/plpgsql_transaction.sql b/src/pl/plpgsql/src/sql/plpgsql_transaction.sql index cc26788b9ae..8e4783c9a51 100644 --- a/src/pl/plpgsql/src/sql/plpgsql_transaction.sql +++ b/src/pl/plpgsql/src/sql/plpgsql_transaction.sql @@ -354,6 +354,27 @@ $$; SELECT * FROM test1; +-- 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 $$; + + -- operations on composite types vs. internal transactions DO LANGUAGE plpgsql $$ declare