aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-12-13 02:00:53 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-12-13 02:00:53 +0000
commit7ae3c0f67baf23ff781f7fd990a1abf3005408be (patch)
treef640fe59eb96f010162cdc0b29fff83a53fa07e2 /src/backend/tcop/postgres.c
parent4914b708471594230caadb8cf2cbb621f2e8c063 (diff)
downloadpostgresql-7ae3c0f67baf23ff781f7fd990a1abf3005408be.tar.gz
postgresql-7ae3c0f67baf23ff781f7fd990a1abf3005408be.zip
Fix failure to ensure that a snapshot is available to datatype input functions
when they are invoked by the parser. We had been setting up a snapshot at plan time but really it needs to be done earlier, before parse analysis. Per report from Dmitry Koterov. Also fix two related problems discovered while poking at this one: exec_bind_message called datatype input functions without establishing a snapshot, and SET CONSTRAINTS IMMEDIATE could call trigger functions without establishing a snapshot. Backpatch to 8.2. The underlying problem goes much further back, but it is masked in 8.1 and before because we didn't attempt to invoke domain check constraints within datatype input. It would only be exposed if a C-language datatype input function used the snapshot; which evidently none do, or we'd have heard complaints sooner. Since this code has changed a lot over time, a back-patch is hardly risk-free, and so I'm disinclined to patch further than absolutely necessary.
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c54
1 files changed, 51 insertions, 3 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index bcb116a50e4..1ebcaa482b6 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.518.2.1 2007/01/04 00:58:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.518.2.2 2008/12/13 02:00:52 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -655,6 +655,9 @@ pg_plan_query(Query *querytree, ParamListInfo boundParams)
if (querytree->commandType == CMD_UTILITY)
return NULL;
+ /* Planner must have a snapshot in case it calls user-defined functions. */
+ Assert(ActiveSnapshot != NULL);
+
if (log_planner_stats)
ResetUsage();
@@ -823,6 +826,7 @@ exec_simple_query(const char *query_string)
foreach(parsetree_item, parsetree_list)
{
Node *parsetree = (Node *) lfirst(parsetree_item);
+ Snapshot mySnapshot = NULL;
const char *commandTag;
char completionTag[COMPLETION_TAG_BUFSIZE];
List *querytree_list,
@@ -865,6 +869,15 @@ exec_simple_query(const char *query_string)
CHECK_FOR_INTERRUPTS();
/*
+ * Set up a snapshot if parse analysis/planning will need one.
+ */
+ if (analyze_requires_snapshot(parsetree))
+ {
+ mySnapshot = CopySnapshot(GetTransactionSnapshot());
+ ActiveSnapshot = mySnapshot;
+ }
+
+ /*
* OK to analyze, rewrite, and plan this query.
*
* Switch to appropriate context for constructing querytrees (again,
@@ -875,7 +888,12 @@ exec_simple_query(const char *query_string)
querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
NULL, 0);
- plantree_list = pg_plan_queries(querytree_list, NULL, true);
+ plantree_list = pg_plan_queries(querytree_list, NULL, false);
+
+ /* Done with the snapshot used for parsing/planning */
+ ActiveSnapshot = NULL;
+ if (mySnapshot)
+ FreeSnapshot(mySnapshot);
/* If we got a cancel signal in analysis or planning, quit */
CHECK_FOR_INTERRUPTS();
@@ -1127,6 +1145,7 @@ exec_parse_message(const char *query_string, /* string to execute */
if (parsetree_list != NIL)
{
Node *parsetree = (Node *) linitial(parsetree_list);
+ Snapshot mySnapshot = NULL;
int i;
/*
@@ -1150,6 +1169,15 @@ exec_parse_message(const char *query_string, /* string to execute */
"commands ignored until end of transaction block")));
/*
+ * Set up a snapshot if parse analysis/planning will need one.
+ */
+ if (analyze_requires_snapshot(parsetree))
+ {
+ mySnapshot = CopySnapshot(GetTransactionSnapshot());
+ ActiveSnapshot = mySnapshot;
+ }
+
+ /*
* OK to analyze, rewrite, and plan this query. Note that the
* originally specified parameter set is not required to be complete,
* so we have to use parse_analyze_varparams().
@@ -1191,7 +1219,12 @@ exec_parse_message(const char *query_string, /* string to execute */
if (!is_named && numParams > 0)
plantree_list = NIL;
else
- plantree_list = pg_plan_queries(querytree_list, NULL, true);
+ plantree_list = pg_plan_queries(querytree_list, NULL, false);
+
+ /* Done with the snapshot used for parsing/planning */
+ ActiveSnapshot = NULL;
+ if (mySnapshot)
+ FreeSnapshot(mySnapshot);
}
else
{
@@ -1401,10 +1434,18 @@ exec_bind_message(StringInfo input_message)
*/
if (numParams > 0)
{
+ Snapshot mySnapshot;
ListCell *l;
MemoryContext oldContext;
int paramno;
+ /*
+ * Set a snapshot if we have parameters to fetch (since the input
+ * functions might need it).
+ */
+ mySnapshot = CopySnapshot(GetTransactionSnapshot());
+ ActiveSnapshot = mySnapshot;
+
oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
/* sizeof(ParamListInfoData) includes the first array element */
@@ -1536,6 +1577,10 @@ exec_bind_message(StringInfo input_message)
}
MemoryContextSwitchTo(oldContext);
+
+ /* Done with the snapshot used for parameter I/O */
+ ActiveSnapshot = NULL;
+ FreeSnapshot(mySnapshot);
}
else
params = NULL;
@@ -3285,6 +3330,9 @@ PostgresMain(int argc, char *argv[], const char *username)
*/
debug_query_string = NULL;
+ /* No active snapshot any more either */
+ ActiveSnapshot = NULL;
+
/*
* Abort the current transaction in order to recover.
*/