aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/pquery.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-02-28 23:27:18 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2011-02-28 23:28:06 -0500
commitc0b00760365c74308e9e0719c993eadfbcd090c2 (patch)
tree28226f24ffb13c5788e1e29606b56bad4d672b72 /src/backend/tcop/pquery.c
parent57e9bda5ec6a032e1e6d51dad5e534a11669c6bf (diff)
downloadpostgresql-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/tcop/pquery.c')
-rw-r--r--src/backend/tcop/pquery.c52
1 files changed, 41 insertions, 11 deletions
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index a338006a3a5..edde5642ee7 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -170,11 +170,6 @@ ProcessQuery(PlannedStmt *plan,
elog(DEBUG3, "ProcessQuery");
/*
- * Must always set a snapshot for plannable queries.
- */
- PushActiveSnapshot(GetTransactionSnapshot());
-
- /*
* Create the QueryDesc object
*/
queryDesc = CreateQueryDesc(plan, sourceText,
@@ -233,8 +228,6 @@ ProcessQuery(PlannedStmt *plan,
ExecutorEnd(queryDesc);
FreeQueryDesc(queryDesc);
-
- PopActiveSnapshot();
}
/*
@@ -1164,8 +1157,8 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
* seems to be to enumerate those that do not need one; this is a short
* list. Transaction control, LOCK, and SET must *not* set a snapshot
* since they need to be executable at the start of a transaction-snapshot
- * mode transaction without freezing a snapshot. By extension we allow SHOW
- * not to set a snapshot. The other stmts listed are just efficiency
+ * mode transaction without freezing a snapshot. By extension we allow
+ * SHOW not to set a snapshot. The other stmts listed are just efficiency
* hacks. Beware of listing anything that can modify the database --- if,
* say, it has to update an index with expressions that invoke
* user-defined functions, then it had better have a snapshot.
@@ -1219,6 +1212,7 @@ PortalRunMulti(Portal portal, bool isTopLevel,
DestReceiver *dest, DestReceiver *altdest,
char *completionTag)
{
+ bool active_snapshot_set = false;
ListCell *stmtlist_item;
/*
@@ -1262,6 +1256,20 @@ PortalRunMulti(Portal portal, bool isTopLevel,
if (log_executor_stats)
ResetUsage();
+ /*
+ * Must always have a snapshot for plannable queries. First time
+ * through, take a new snapshot; for subsequent queries in the
+ * same portal, just update the snapshot's copy of the command
+ * counter.
+ */
+ if (!active_snapshot_set)
+ {
+ PushActiveSnapshot(GetTransactionSnapshot());
+ active_snapshot_set = true;
+ }
+ else
+ UpdateActiveSnapshotCommandId();
+
if (pstmt->canSetTag)
{
/* statement can set tag string */
@@ -1291,11 +1299,29 @@ PortalRunMulti(Portal portal, bool isTopLevel,
*
* These are assumed canSetTag if they're the only stmt in the
* portal.
+ *
+ * We must not set a snapshot here for utility commands (if one is
+ * needed, PortalRunUtility will do it). If a utility command is
+ * alone in a portal then everything's fine. The only case where
+ * a utility command can be part of a longer list is that rules
+ * are allowed to include NotifyStmt. NotifyStmt doesn't care
+ * whether it has a snapshot or not, so we just leave the current
+ * snapshot alone if we have one.
*/
if (list_length(portal->stmts) == 1)
- PortalRunUtility(portal, stmt, isTopLevel, dest, completionTag);
+ {
+ Assert(!active_snapshot_set);
+ /* statement can set tag string */
+ PortalRunUtility(portal, stmt, isTopLevel,
+ dest, completionTag);
+ }
else
- PortalRunUtility(portal, stmt, isTopLevel, altdest, NULL);
+ {
+ Assert(IsA(stmt, NotifyStmt));
+ /* stmt added by rewrite cannot set tag */
+ PortalRunUtility(portal, stmt, isTopLevel,
+ altdest, NULL);
+ }
}
/*
@@ -1313,6 +1339,10 @@ PortalRunMulti(Portal portal, bool isTopLevel,
MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
}
+ /* Pop the snapshot if we pushed one. */
+ if (active_snapshot_set)
+ PopActiveSnapshot();
+
/*
* If a command completion tag was supplied, use it. Otherwise use the
* portal's commandTag as the default completion tag.