mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
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.
This commit is contained in:
parent
953c2c9b71
commit
745e6edaae
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.59 2007/09/14 04:18:27 momjian Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.60 2008/02/12 04:09:44 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="spi">
|
<chapter id="spi">
|
||||||
<title>Server Programming Interface</title>
|
<title>Server Programming Interface</title>
|
||||||
@ -1077,9 +1077,12 @@ bool SPI_is_cursor_plan(SPIPlanPtr <parameter>plan</parameter>)
|
|||||||
<title>Return Value</title>
|
<title>Return Value</title>
|
||||||
<para>
|
<para>
|
||||||
<symbol>true</symbol> or <symbol>false</symbol> to indicate if the
|
<symbol>true</symbol> or <symbol>false</symbol> to indicate if the
|
||||||
<parameter>plan</parameter> can produce a cursor or not.
|
<parameter>plan</parameter> can produce a cursor or not, with
|
||||||
If the <parameter>plan</parameter> is <symbol>NULL</symbol> or invalid,
|
<varname>SPI_result</varname> set to zero.
|
||||||
<varname>SPI_result</varname> is set to <symbol>SPI_ERROR_ARGUMENT</symbol>
|
If it is not possible to determine the answer (for example,
|
||||||
|
if the <parameter>plan</parameter> is <symbol>NULL</symbol> or invalid,
|
||||||
|
or if called when not connected to SPI), then
|
||||||
|
<varname>SPI_result</varname> is set to a suitable error code
|
||||||
and <symbol>false</symbol> is returned.
|
and <symbol>false</symbol> is returned.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
@ -1442,8 +1445,8 @@ Portal SPI_cursor_open(const char * <parameter>name</parameter>, SPIPlanPtr <par
|
|||||||
<title>Return Value</title>
|
<title>Return Value</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
pointer to portal containing the cursor, or <symbol>NULL</symbol>
|
Pointer to portal containing the cursor. Note there is no error
|
||||||
on error
|
return convention; any error will be reported via <function>elog</>.
|
||||||
</para>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
</refentry>
|
</refentry>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
Assert(list_length(plan->plancache_list) == 1);
|
||||||
plansource = (CachedPlanSource *) linitial(plan->plancache_list);
|
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) */
|
/* Reset SPI result (note we deliberately don't touch lastoid) */
|
||||||
SPI_processed = 0;
|
SPI_processed = 0;
|
||||||
SPI_tuptable = NULL;
|
SPI_tuptable = NULL;
|
||||||
@ -1041,6 +1045,9 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
|
|||||||
|
|
||||||
Assert(portal->strategy != PORTAL_MULTI_QUERY);
|
Assert(portal->strategy != PORTAL_MULTI_QUERY);
|
||||||
|
|
||||||
|
/* Pop the SPI stack */
|
||||||
|
_SPI_end_call(false);
|
||||||
|
|
||||||
/* Return the created portal */
|
/* Return the created portal */
|
||||||
return portal;
|
return portal;
|
||||||
}
|
}
|
||||||
@ -1180,9 +1187,17 @@ SPI_is_cursor_plan(SPIPlanPtr plan)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (list_length(plan->plancache_list) != 1)
|
if (list_length(plan->plancache_list) != 1)
|
||||||
|
{
|
||||||
|
SPI_result = 0;
|
||||||
return false; /* not exactly 1 pre-rewrite command */
|
return false; /* not exactly 1 pre-rewrite command */
|
||||||
|
}
|
||||||
plansource = (CachedPlanSource *) linitial(plan->plancache_list);
|
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)
|
if (plan->saved)
|
||||||
{
|
{
|
||||||
/* Make sure the plan is up to date */
|
/* Make sure the plan is up to date */
|
||||||
@ -1190,6 +1205,9 @@ SPI_is_cursor_plan(SPIPlanPtr plan)
|
|||||||
ReleaseCachedPlan(cplan, true);
|
ReleaseCachedPlan(cplan, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_SPI_end_call(false);
|
||||||
|
SPI_result = 0;
|
||||||
|
|
||||||
/* Does it return tuples? */
|
/* Does it return tuples? */
|
||||||
if (plansource->resultDesc)
|
if (plansource->resultDesc)
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user