* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.241 2008/11/21 20:14:27 mha Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.242 2008/12/13 02:00:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (!stmt->deferred)
{
AfterTriggerEventList *events = &afterTriggers->events;
+ bool snapshot_set = false;
while (afterTriggerMarkEvents(events, NULL, true))
{
CommandId firing_id = afterTriggers->firing_counter++;
+ /*
+ * Make sure a snapshot has been established in case trigger
+ * functions need one. Note that we avoid setting a snapshot if
+ * we don't find at least one trigger that has to be fired now.
+ * This is so that BEGIN; SET CONSTRAINTS ...; SET TRANSACTION
+ * ISOLATION LEVEL SERIALIZABLE; ... works properly. (If we are
+ * at the start of a transaction it's not possible for any trigger
+ * events to be queued yet.)
+ */
+ if (!snapshot_set)
+ {
+ PushActiveSnapshot(GetTransactionSnapshot());
+ snapshot_set = true;
+ }
+
/*
* We can delete fired events if we are at top transaction level,
* but we'd better not if inside a subtransaction, since the
!IsSubTransaction()))
break; /* all fired */
}
+
+ if (snapshot_set)
+ PopActiveSnapshot();
}
}
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.383 2008/11/15 19:43:46 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.384 2008/12/13 02:00:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return result;
}
+/*
+ * analyze_requires_snapshot
+ * Returns true if a snapshot must be set before doing parse analysis
+ * on the given raw parse tree.
+ *
+ * Classification here should match transformStmt().
+ */
+bool
+analyze_requires_snapshot(Node *parseTree)
+{
+ bool result;
+
+ switch (nodeTag(parseTree))
+ {
+ /*
+ * Optimizable statements
+ */
+ case T_InsertStmt:
+ case T_DeleteStmt:
+ case T_UpdateStmt:
+ case T_SelectStmt:
+ result = true;
+ break;
+
+ /*
+ * Special cases
+ */
+ case T_DeclareCursorStmt:
+ /* yes, because it's analyzed just like SELECT */
+ result = true;
+ break;
+
+ case T_ExplainStmt:
+ /*
+ * We only need a snapshot in varparams case, but it doesn't seem
+ * worth complicating this function's API to distinguish that.
+ */
+ result = true;
+ break;
+
+ default:
+ /* utility statements don't have any active parse analysis */
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
/*
* transformDeleteStmt -
* transforms a Delete Statement
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.560 2008/12/09 15:59:39 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.561 2008/12/13 02:00:19 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
if (querytree->commandType == CMD_UTILITY)
return NULL;
+ /* Planner must have a snapshot in case it calls user-defined functions. */
+ Assert(ActiveSnapshotSet());
+
TRACE_POSTGRESQL_QUERY_PLAN_START();
if (log_planner_stats)
foreach(parsetree_item, parsetree_list)
{
Node *parsetree = (Node *) lfirst(parsetree_item);
+ bool snapshot_set = false;
const char *commandTag;
char completionTag[COMPLETION_TAG_BUFSIZE];
List *querytree_list,
/* If we got a cancel signal in parsing or prior command, quit */
CHECK_FOR_INTERRUPTS();
+ /*
+ * Set up a snapshot if parse analysis/planning will need one.
+ */
+ if (analyze_requires_snapshot(parsetree))
+ {
+ PushActiveSnapshot(GetTransactionSnapshot());
+ snapshot_set = true;
+ }
+
/*
* OK to analyze, rewrite, and plan this query.
*
querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
NULL, 0);
- plantree_list = pg_plan_queries(querytree_list, 0, NULL, true);
+ plantree_list = pg_plan_queries(querytree_list, 0, NULL, false);
+
+ /* Done with the snapshot used for parsing/planning */
+ if (snapshot_set)
+ PopActiveSnapshot();
/* If we got a cancel signal in analysis or planning, quit */
CHECK_FOR_INTERRUPTS();
/*
* We don't have to copy anything into the portal, because everything
- * we are passsing here is in MessageContext, which will outlive the
+ * we are passing here is in MessageContext, which will outlive the
* portal anyway.
*/
PortalDefineQuery(portal,
if (parsetree_list != NIL)
{
Query *query;
+ bool snapshot_set = false;
int i;
raw_parse_tree = (Node *) linitial(parsetree_list);
errmsg("current transaction is aborted, "
"commands ignored until end of transaction block")));
+ /*
+ * Set up a snapshot if parse analysis/planning will need one.
+ */
+ if (analyze_requires_snapshot(raw_parse_tree))
+ {
+ PushActiveSnapshot(GetTransactionSnapshot());
+ snapshot_set = true;
+ }
+
/*
* OK to analyze, rewrite, and plan this query. Note that the
* originally specified parameter set is not required to be complete,
}
else
{
- stmt_list = pg_plan_queries(querytree_list, 0, NULL, true);
+ stmt_list = pg_plan_queries(querytree_list, 0, NULL, false);
fully_planned = true;
}
+
+ /* Done with the snapshot used for parsing/planning */
+ if (snapshot_set)
+ PopActiveSnapshot();
}
else
{
List *plan_list;
MemoryContext oldContext;
bool save_log_statement_stats = log_statement_stats;
+ bool snapshot_set = false;
char msec_str[32];
/* Get the fixed part of the message */
else
saved_stmt_name = NULL;
+ /*
+ * Set a snapshot if we have parameters to fetch (since the input
+ * functions might need it) or the query isn't a utility command (and
+ * hence could require redoing parse analysis and planning).
+ */
+ if (numParams > 0 || analyze_requires_snapshot(psrc->raw_parse_tree))
+ {
+ PushActiveSnapshot(GetTransactionSnapshot());
+ snapshot_set = true;
+ }
+
/*
* Fetch parameters, if any, and store in the portal's memory context.
*/
*/
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
query_list = copyObject(cplan->stmt_list);
- plan_list = pg_plan_queries(query_list, 0, params, true);
+ plan_list = pg_plan_queries(query_list, 0, params, false);
MemoryContextSwitchTo(oldContext);
/* We no longer need the cached plan refcount ... */
cplan = NULL;
}
+ /* Done with the snapshot used for parameter I/O and parsing/planning */
+ if (snapshot_set)
+ PopActiveSnapshot();
+
/*
* Define portal and start execution.
*/
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.23 2008/10/04 21:56:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.24 2008/12/13 02:00:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
if (!plan)
{
+ bool snapshot_set = false;
List *slist;
TupleDesc resultDesc;
*/
PushOverrideSearchPath(plansource->search_path);
+ /*
+ * If a snapshot is already set (the normal case), we can just use
+ * that for parsing/planning. But if it isn't, install one. Note:
+ * no point in checking whether parse analysis requires a snapshot;
+ * utility commands don't have invalidatable plans, so we'd not get
+ * here for such a command.
+ */
+ if (!ActiveSnapshotSet())
+ {
+ PushActiveSnapshot(GetTransactionSnapshot());
+ snapshot_set = true;
+ }
+
/*
* Run parse analysis and rule rewriting. The parser tends to
* scribble on its input, so we must copy the raw parse tree to
{
/*
* Generate plans for queries.
- *
- * If a snapshot is already set (the normal case), we can just use
- * that for planning. But if it isn't, we have to tell
- * pg_plan_queries to make a snap if it needs one.
*/
slist = pg_plan_queries(slist, plansource->cursor_options,
- NULL, !ActiveSnapshotSet());
+ NULL, false);
}
/*
MemoryContextSwitchTo(oldcxt);
}
+ /* Release snapshot if we got one */
+ if (snapshot_set)
+ PopActiveSnapshot();
+
/* Now we can restore current search path */
PopOverrideSearchPath();
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.38 2008/01/01 19:45:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.39 2008/12/13 02:00:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Query *parse_sub_analyze(Node *parseTree, ParseState *parentParseState);
extern Query *transformStmt(ParseState *pstate, Node *parseTree);
+extern bool analyze_requires_snapshot(Node *parseTree);
+
extern void CheckSelectLocking(Query *qry);
extern void applyLockingClause(Query *qry, Index rtindex,
bool forUpdate, bool noWait);