diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-02-28 23:27:18 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-02-28 23:28:06 -0500 |
commit | c0b00760365c74308e9e0719c993eadfbcd090c2 (patch) | |
tree | 28226f24ffb13c5788e1e29606b56bad4d672b72 /src/backend/executor/spi.c | |
parent | 57e9bda5ec6a032e1e6d51dad5e534a11669c6bf (diff) | |
download | postgresql-c0b00760365c74308e9e0719c993eadfbcd090c2.tar.gz postgresql-c0b00760365c74308e9e0719c993eadfbcd090c2.zip |
Rearrange snapshot handling to make rule expansion more consistent.
With this patch, portals, SQL functions, and SPI all agree that there
should be only a CommandCounterIncrement between the queries that are
generated from a single SQL command by rule expansion. Fetching a whole
new snapshot now happens only between original queries. This is equivalent
to the existing behavior of EXPLAIN ANALYZE, and it was judged to be the
best choice since it eliminates one source of concurrency hazards for
rules. The patch should also make things marginally faster by reducing the
number of snapshot push/pop operations.
The patch removes pg_parse_and_rewrite(), which is no longer used anywhere.
There was considerable discussion about more aggressive refactoring of the
query-processing functions exported by postgres.c, but for the moment
nothing more has been done there.
I also took the opportunity to refactor snapmgr.c's API slightly: the
former PushUpdatedSnapshot() has been split into two functions.
Marko Tiikkaja, reviewed by Steve Singer and Tom Lane
Diffstat (limited to 'src/backend/executor/spi.c')
-rw-r--r-- | src/backend/executor/spi.c | 96 |
1 files changed, 55 insertions, 41 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 0865e3ebef2..a717a0deead 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -1768,7 +1768,7 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Oid my_lastoid = InvalidOid; SPITupleTable *my_tuptable = NULL; int res = 0; - bool have_active_snap = ActiveSnapshotSet(); + bool pushed_active_snap = false; ErrorContextCallback spierrcontext; CachedPlan *cplan = NULL; ListCell *lc1; @@ -1781,6 +1781,40 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, spierrcontext.previous = error_context_stack; error_context_stack = &spierrcontext; + /* + * We support four distinct snapshot management behaviors: + * + * snapshot != InvalidSnapshot, read_only = true: use exactly the given + * snapshot. + * + * snapshot != InvalidSnapshot, read_only = false: use the given + * snapshot, modified by advancing its command ID before each querytree. + * + * snapshot == InvalidSnapshot, read_only = true: use the entry-time + * ActiveSnapshot, if any (if there isn't one, we run with no snapshot). + * + * snapshot == InvalidSnapshot, read_only = false: take a full new + * snapshot for each user command, and advance its command ID before each + * querytree within the command. + * + * In the first two cases, we can just push the snap onto the stack + * once for the whole plan list. + */ + if (snapshot != InvalidSnapshot) + { + if (read_only) + { + PushActiveSnapshot(snapshot); + pushed_active_snap = true; + } + else + { + /* Make sure we have a private copy of the snapshot to modify */ + PushCopiedSnapshot(snapshot); + pushed_active_snap = true; + } + } + foreach(lc1, plan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1); @@ -1802,12 +1836,23 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, stmt_list = plansource->plan->stmt_list; } + /* + * In the default non-read-only case, get a new snapshot, replacing + * any that we pushed in a previous cycle. + */ + if (snapshot == InvalidSnapshot && !read_only) + { + if (pushed_active_snap) + PopActiveSnapshot(); + PushActiveSnapshot(GetTransactionSnapshot()); + pushed_active_snap = true; + } + foreach(lc2, stmt_list) { Node *stmt = (Node *) lfirst(lc2); bool canSetTag; DestReceiver *dest; - bool pushed_active_snap = false; _SPI_current->processed = 0; _SPI_current->lastoid = InvalidOid; @@ -1848,48 +1893,16 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, /* * If not read-only mode, advance the command counter before each - * command. + * command and update the snapshot. */ if (!read_only) + { CommandCounterIncrement(); + UpdateActiveSnapshotCommandId(); + } dest = CreateDestReceiver(canSetTag ? DestSPI : DestNone); - if (snapshot == InvalidSnapshot) - { - /* - * Default read_only behavior is to use the entry-time - * ActiveSnapshot, if any; if read-write, grab a full new - * snap. - */ - if (read_only) - { - if (have_active_snap) - { - PushActiveSnapshot(GetActiveSnapshot()); - pushed_active_snap = true; - } - } - else - { - PushActiveSnapshot(GetTransactionSnapshot()); - pushed_active_snap = true; - } - } - else - { - /* - * We interpret read_only with a specified snapshot to be - * exactly that snapshot, but read-write means use the snap - * with advancing of command ID. - */ - if (read_only) - PushActiveSnapshot(snapshot); - else - PushUpdatedSnapshot(snapshot); - pushed_active_snap = true; - } - if (IsA(stmt, PlannedStmt) && ((PlannedStmt *) stmt)->utilityStmt == NULL) { @@ -1925,9 +1938,6 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, res = SPI_OK_UTILITY; } - if (pushed_active_snap) - PopActiveSnapshot(); - /* * The last canSetTag query sets the status values returned to the * caller. Be careful to free any tuptables not returned, to @@ -1970,6 +1980,10 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, fail: + /* Pop the snapshot off the stack if we pushed one */ + if (pushed_active_snap) + PopActiveSnapshot(); + /* We no longer need the cached plan refcount, if any */ if (cplan) ReleaseCachedPlan(cplan, true); |