aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-02-12 04:09:44 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-02-12 04:09:44 +0000
commit745e6edaaeaccb92a2a5efe44b49c8bcc7d0ce01 (patch)
treec5fe4bd66878be8422aeb74b58f77404c83411cb /src
parent953c2c9b71fff6c6e6952641077f29ef10b64398 (diff)
downloadpostgresql-745e6edaaeaccb92a2a5efe44b49c8bcc7d0ce01.tar.gz
postgresql-745e6edaaeaccb92a2a5efe44b49c8bcc7d0ce01.zip
Fix SPI_cursor_open() and SPI_is_cursor_plan() to push the SPI stack before
doing anything interesting, such as calling RevalidateCachedPlan(). The necessity of this is demonstrated by an example from Willem Buitendyk: during a replan, the planner might try to evaluate SPI-using functions, and so we'd better be in a clean SPI context. A small downside of this fix is that these two functions will now fail outright if called when not inside a SPI-using procedure (ie, a SPI_connect/SPI_finish pair). The documentation never promised or suggested that that would work, though; and they are normally used in concert with other functions, mainly SPI_prepare, that always have failed in such a case. So the odds of breaking something seem pretty low. In passing, make SPI_is_cursor_plan's error handling convention clearer, and fix documentation's erroneous claim that SPI_cursor_open would return NULL on error. Before 8.3 these functions could not invoke replanning, so there is probably no need for back-patching.
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/spi.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index ae083f7225d..a23c4d017a8 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.187 2008/01/01 19:45:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.188 2008/02/12 04:09:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -886,6 +886,10 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
Assert(list_length(plan->plancache_list) == 1);
plansource = (CachedPlanSource *) linitial(plan->plancache_list);
+ /* Push the SPI stack */
+ if (_SPI_begin_call(false) < 0)
+ elog(ERROR, "SPI_cursor_open called while not connected");
+
/* Reset SPI result (note we deliberately don't touch lastoid) */
SPI_processed = 0;
SPI_tuptable = NULL;
@@ -1041,6 +1045,9 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
Assert(portal->strategy != PORTAL_MULTI_QUERY);
+ /* Pop the SPI stack */
+ _SPI_end_call(false);
+
/* Return the created portal */
return portal;
}
@@ -1180,9 +1187,17 @@ SPI_is_cursor_plan(SPIPlanPtr plan)
}
if (list_length(plan->plancache_list) != 1)
+ {
+ SPI_result = 0;
return false; /* not exactly 1 pre-rewrite command */
+ }
plansource = (CachedPlanSource *) linitial(plan->plancache_list);
+ /* Need _SPI_begin_call in case replanning invokes SPI-using functions */
+ SPI_result = _SPI_begin_call(false);
+ if (SPI_result < 0)
+ return false;
+
if (plan->saved)
{
/* Make sure the plan is up to date */
@@ -1190,6 +1205,9 @@ SPI_is_cursor_plan(SPIPlanPtr plan)
ReleaseCachedPlan(cplan, true);
}
+ _SPI_end_call(false);
+ SPI_result = 0;
+
/* Does it return tuples? */
if (plansource->resultDesc)
return true;