_SPI_current->internal_xact = true;
- if (ActiveSnapshotSet())
+ /*
+ * Before committing, pop all active snapshots to avoid error about
+ * "snapshot %p still active".
+ */
+ while (ActiveSnapshotSet())
PopActiveSnapshot();
+
CommitTransactionCommand();
MemoryContextSwitchTo(oldcontext);
$$;
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)
+
DROP TABLE test1;
DROP TABLE test2;
DROP TABLE test3;
ParamListInfo paramLI;
LocalTransactionId before_lxid;
LocalTransactionId after_lxid;
+ bool pushed_active_snap = false;
int rc;
if (expr->plan == NULL)
/*
* The procedure call could end transactions, which would upset the
* snapshot management in SPI_execute*, so don't let it do it.
+ * Instead, we set the snapshots ourselves below.
*/
expr->plan->no_snapshots = true;
}
before_lxid = MyProc->lxid;
+ /*
+ * Set snapshot only for non-read-only procedures, similar to SPI
+ * behavior.
+ */
+ if (!estate->readonly_func)
+ {
+ PushActiveSnapshot(GetTransactionSnapshot());
+ pushed_active_snap = true;
+ }
+
PG_TRY();
{
rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s",
expr->query, SPI_result_code_string(rc));
- /*
- * If we are in a new transaction after the call, we need to reset some
- * internal state.
- */
- if (before_lxid != after_lxid)
+ if (before_lxid == after_lxid)
+ {
+ /*
+ * If we are still in the same transaction after the call, pop the
+ * snapshot that we might have pushed. (If it's a new transaction,
+ * then all the snapshots are gone already.)
+ */
+ if (pushed_active_snap)
+ PopActiveSnapshot();
+ }
+ else
{
+ /*
+ * If we are in a new transaction after the call, we need to reset
+ * some internal state.
+ */
estate->simple_eval_estate = NULL;
plpgsql_create_econtext(estate);
}