I wrote: > Hmm. I think the real issue here is that commit 84f5c2908 did > not cover the "simple expression" code path in plpgsql. We > need to re-establish an outer snapshot when the next thing > that happens after COMMIT is a simple expression, too.
The attached seems to be enough to resolve Jim's example. I'd like to invent a test case that involves a detoast of the simple expression's result, too, to show that transiently pushing a snapshot for the duration of the expression is not the right fix. regards, tom lane
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 0ce382e123..96bb77e0b1 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