diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-02-12 04:09:44 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-02-12 04:09:44 +0000 |
commit | 745e6edaaeaccb92a2a5efe44b49c8bcc7d0ce01 (patch) | |
tree | c5fe4bd66878be8422aeb74b58f77404c83411cb /src | |
parent | 953c2c9b71fff6c6e6952641077f29ef10b64398 (diff) | |
download | postgresql-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.c | 20 |
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; |