aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor/spi.c')
-rw-r--r--src/backend/executor/spi.c87
1 files changed, 49 insertions, 38 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 165ff962fcd..183969f1b85 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.156 2006/08/14 13:40:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.157 2006/08/14 22:57:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -818,31 +818,44 @@ SPI_cursor_open(const char *name, void *plan,
bool read_only)
{
_SPI_plan *spiplan = (_SPI_plan *) plan;
- List *qtlist = spiplan->qtlist;
- List *ptlist = spiplan->ptlist;
- Query *queryTree;
- Plan *planTree;
+ List *qtlist;
+ List *ptlist;
ParamListInfo paramLI;
Snapshot snapshot;
MemoryContext oldcontext;
Portal portal;
int k;
- /* Ensure that the plan contains only one query */
- if (list_length(ptlist) != 1 || list_length(qtlist) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
- errmsg("cannot open multi-query plan as cursor")));
- queryTree = (Query *) linitial((List *) linitial(qtlist));
- planTree = (Plan *) linitial(ptlist);
-
- /* Must be a query that returns tuples */
- if (!QueryReturnsTuples(queryTree))
+ /*
+ * Check that the plan is something the Portal code will special-case
+ * as returning one tupleset.
+ */
+ if (!SPI_is_cursor_plan(spiplan))
+ {
+ /* try to give a good error message */
+ Query *queryTree;
+
+ if (list_length(spiplan->qtlist) != 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
+ errmsg("cannot open multi-query plan as cursor")));
+ queryTree = PortalListGetPrimaryQuery((List *) linitial(spiplan->qtlist));
+ if (queryTree == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
+ errmsg("cannot open empty query as cursor")));
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
/* translator: %s is name of a SQL command, eg INSERT */
errmsg("cannot open %s query as cursor",
CreateQueryTag(queryTree))));
+ }
+
+ Assert(list_length(spiplan->qtlist) == 1);
+ qtlist = (List *) linitial(spiplan->qtlist);
+ ptlist = spiplan->ptlist;
+ if (list_length(qtlist) != list_length(ptlist))
+ elog(ERROR, "corrupted SPI plan lists");
/* Reset SPI result (note we deliberately don't touch lastoid) */
SPI_processed = 0;
@@ -862,10 +875,10 @@ SPI_cursor_open(const char *name, void *plan,
portal = CreatePortal(name, false, false);
}
- /* Switch to portal's memory and copy the parsetree and plan to there */
+ /* Switch to portal's memory and copy the parsetrees and plans to there */
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
- queryTree = copyObject(queryTree);
- planTree = copyObject(planTree);
+ qtlist = copyObject(qtlist);
+ ptlist = copyObject(ptlist);
/* If the plan has parameters, set them up */
if (spiplan->nargs > 0)
@@ -907,9 +920,9 @@ SPI_cursor_open(const char *name, void *plan,
PortalDefineQuery(portal,
NULL, /* no statement name */
spiplan->query,
- CreateQueryTag(queryTree),
- list_make1(queryTree),
- list_make1(planTree),
+ CreateQueryTag(PortalListGetPrimaryQuery(qtlist)),
+ qtlist,
+ ptlist,
PortalGetHeapMemory(portal));
MemoryContextSwitchTo(oldcontext);
@@ -918,7 +931,8 @@ SPI_cursor_open(const char *name, void *plan,
* Set up options for portal.
*/
portal->cursorOptions &= ~(CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL);
- if (planTree == NULL || ExecSupportsBackwardScan(planTree))
+ if (list_length(ptlist) == 1 &&
+ ExecSupportsBackwardScan((Plan *) linitial(ptlist)))
portal->cursorOptions |= CURSOR_OPT_SCROLL;
else
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
@@ -940,16 +954,7 @@ SPI_cursor_open(const char *name, void *plan,
*/
PortalStart(portal, paramLI, snapshot);
- /*
- * If this test fails then we're out of sync with pquery.c about
- * which queries can return tuples...
- */
- if (portal->strategy == PORTAL_MULTI_QUERY)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
- /* translator: %s is name of a SQL command, eg INSERT */
- errmsg("cannot open %s query as cursor",
- CreateQueryTag(queryTree))));
+ Assert(portal->strategy != PORTAL_MULTI_QUERY);
/* Return the created portal */
return portal;
@@ -1050,7 +1055,6 @@ bool
SPI_is_cursor_plan(void *plan)
{
_SPI_plan *spiplan = (_SPI_plan *) plan;
- List *qtlist;
if (spiplan == NULL)
{
@@ -1058,13 +1062,20 @@ SPI_is_cursor_plan(void *plan)
return false;
}
- qtlist = spiplan->qtlist;
- if (list_length(spiplan->ptlist) == 1 && list_length(qtlist) == 1)
- {
- Query *queryTree = (Query *) linitial((List *) linitial(qtlist));
+ if (list_length(spiplan->qtlist) != 1)
+ return false; /* not exactly 1 pre-rewrite command */
- if (QueryReturnsTuples(queryTree))
+ switch (ChoosePortalStrategy((List *) linitial(spiplan->qtlist)))
+ {
+ case PORTAL_ONE_SELECT:
+ case PORTAL_ONE_RETURNING:
+ case PORTAL_UTIL_SELECT:
+ /* OK */
return true;
+
+ case PORTAL_MULTI_QUERY:
+ /* will not return tuples */
+ break;
}
return false;
}