Skip to content

Commit d102aaf

Browse files
committed
Restore the portal-level snapshot for simple expressions, too.
Commits 84f5c29 et al missed the need to cover plpgsql's "simple expression" code path. If the first thing we execute after a COMMIT/ROLLBACK is one of those, rather than a full-fledged SPI command, we must explicitly do EnsurePortalSnapshotExists() to make sure we have an outer snapshot. Note that it wouldn't be good enough to just push a snapshot for the duration of the expression execution: what comes back might be toasted, so we'd better have a snapshot protecting it. The test case demonstrating this fact cheats a bit by marking a SQL function immutable even though it fetches from a table. That's nothing that users haven't been seen to do, though. Per report from Jim Nasby. Back-patch to v11, like the previous fix. Discussion: https://postgr.es/m/378885e4-f85f-fc28-6c91-c4d1c080bf26@amazon.com
1 parent 8e63884 commit d102aaf

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

src/pl/plpgsql/src/expected/plpgsql_transaction.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,24 @@ SELECT * FROM test1;
430430
---+---
431431
(0 rows)
432432

433+
-- detoast result of simple expression after commit
434+
CREATE TEMP TABLE test4(f1 text);
435+
ALTER TABLE test4 ALTER COLUMN f1 SET STORAGE EXTERNAL; -- disable compression
436+
INSERT INTO test4 SELECT repeat('xyzzy', 2000);
437+
-- immutable mark is a bit of a lie, but it serves to make call a simple expr
438+
-- that will return a still-toasted value
439+
CREATE FUNCTION data_source(i int) RETURNS TEXT LANGUAGE sql
440+
AS 'select f1 from test4' IMMUTABLE;
441+
DO $$
442+
declare x text;
443+
begin
444+
for i in 1..3 loop
445+
x := data_source(i);
446+
commit;
447+
end loop;
448+
raise notice 'length(x) = %', length(x);
449+
end $$;
450+
NOTICE: length(x) = 10000
433451
-- operations on composite types vs. internal transactions
434452
DO LANGUAGE plpgsql $$
435453
declare

src/pl/plpgsql/src/pl_exec.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "plpgsql.h"
3939
#include "storage/proc.h"
4040
#include "tcop/cmdtag.h"
41+
#include "tcop/pquery.h"
4142
#include "tcop/tcopprot.h"
4243
#include "tcop/utility.h"
4344
#include "utils/array.h"
@@ -5958,6 +5959,15 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
59585959
expr->expr_simple_lxid == curlxid)
59595960
return false;
59605961

5962+
/*
5963+
* Ensure that there's a portal-level snapshot, in case this simple
5964+
* expression is the first thing evaluated after a COMMIT or ROLLBACK.
5965+
* We'd have to do this anyway before executing the expression, so we
5966+
* might as well do it now to ensure that any possible replanning doesn't
5967+
* need to take a new snapshot.
5968+
*/
5969+
EnsurePortalSnapshotExists();
5970+
59615971
/*
59625972
* Check to see if the cached plan has been invalidated. If not, and this
59635973
* is the first use in the current transaction, save a plan refcount in

src/pl/plpgsql/src/sql/plpgsql_transaction.sql

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,27 @@ $$;
354354
SELECT * FROM test1;
355355

356356

357+
-- detoast result of simple expression after commit
358+
CREATE TEMP TABLE test4(f1 text);
359+
ALTER TABLE test4 ALTER COLUMN f1 SET STORAGE EXTERNAL; -- disable compression
360+
INSERT INTO test4 SELECT repeat('xyzzy', 2000);
361+
362+
-- immutable mark is a bit of a lie, but it serves to make call a simple expr
363+
-- that will return a still-toasted value
364+
CREATE FUNCTION data_source(i int) RETURNS TEXT LANGUAGE sql
365+
AS 'select f1 from test4' IMMUTABLE;
366+
367+
DO $$
368+
declare x text;
369+
begin
370+
for i in 1..3 loop
371+
x := data_source(i);
372+
commit;
373+
end loop;
374+
raise notice 'length(x) = %', length(x);
375+
end $$;
376+
377+
357378
-- operations on composite types vs. internal transactions
358379
DO LANGUAGE plpgsql $$
359380
declare

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy