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.c149
1 files changed, 67 insertions, 82 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index a565ba3cd2b..33ec21286d9 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.169 2007/01/09 22:00:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.170 2007/02/20 17:32:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -831,8 +831,7 @@ SPI_cursor_open(const char *name, void *plan,
bool read_only)
{
_SPI_plan *spiplan = (_SPI_plan *) plan;
- List *qtlist;
- List *ptlist;
+ List *stmt_list;
ParamListInfo paramLI;
Snapshot snapshot;
MemoryContext oldcontext;
@@ -846,29 +845,22 @@ SPI_cursor_open(const char *name, void *plan,
if (!SPI_is_cursor_plan(spiplan))
{
/* try to give a good error message */
- Query *queryTree;
+ Node *stmt;
- if (list_length(spiplan->qtlist) != 1)
+ if (list_length(spiplan->stmt_list_list) != 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")));
+ stmt = PortalListGetPrimaryStmt((List *) linitial(spiplan->stmt_list_list));
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))));
+ CreateCommandTag(stmt))));
}
- 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");
+ Assert(list_length(spiplan->stmt_list_list) == 1);
+ stmt_list = (List *) linitial(spiplan->stmt_list_list);
/* Reset SPI result (note we deliberately don't touch lastoid) */
SPI_processed = 0;
@@ -888,10 +880,9 @@ SPI_cursor_open(const char *name, void *plan,
portal = CreatePortal(name, false, false);
}
- /* Switch to portal's memory and copy the parsetrees and plans to there */
+ /* Switch to portal's memory and copy the plans to there */
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
- qtlist = copyObject(qtlist);
- ptlist = copyObject(ptlist);
+ stmt_list = copyObject(stmt_list);
/* If the plan has parameters, set them up */
if (spiplan->nargs > 0)
@@ -934,9 +925,8 @@ SPI_cursor_open(const char *name, void *plan,
PortalDefineQuery(portal,
NULL, /* no statement name */
spiplan->query,
- CreateQueryTag(PortalListGetPrimaryQuery(qtlist)),
- qtlist,
- ptlist,
+ CreateCommandTag(PortalListGetPrimaryStmt(stmt_list)),
+ stmt_list,
PortalGetHeapMemory(portal));
MemoryContextSwitchTo(oldcontext);
@@ -945,8 +935,9 @@ SPI_cursor_open(const char *name, void *plan,
* Set up options for portal.
*/
portal->cursorOptions &= ~(CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL);
- if (list_length(ptlist) == 1 &&
- ExecSupportsBackwardScan((Plan *) linitial(ptlist)))
+ if (list_length(stmt_list) == 1 &&
+ IsA((Node *) linitial(stmt_list), PlannedStmt) &&
+ ExecSupportsBackwardScan(((PlannedStmt *) linitial(stmt_list))->planTree))
portal->cursorOptions |= CURSOR_OPT_SCROLL;
else
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
@@ -1076,10 +1067,10 @@ SPI_is_cursor_plan(void *plan)
return false;
}
- if (list_length(spiplan->qtlist) != 1)
+ if (list_length(spiplan->stmt_list_list) != 1)
return false; /* not exactly 1 pre-rewrite command */
- switch (ChoosePortalStrategy((List *) linitial(spiplan->qtlist)))
+ switch (ChoosePortalStrategy((List *) linitial(spiplan->stmt_list_list)))
{
case PORTAL_ONE_SELECT:
case PORTAL_ONE_RETURNING:
@@ -1257,14 +1248,13 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
*
* At entry, plan->argtypes and plan->nargs must be valid.
*
- * Query and plan lists are stored into *plan.
+ * Result lists are stored into *plan.
*/
static void
_SPI_prepare_plan(const char *src, _SPI_plan *plan)
{
List *raw_parsetree_list;
- List *query_list_list;
- List *plan_list;
+ List *stmt_list_list;
ListCell *list_item;
ErrorContextCallback spierrcontext;
Oid *argtypes = plan->argtypes;
@@ -1294,12 +1284,11 @@ _SPI_prepare_plan(const char *src, _SPI_plan *plan)
/*
* Do parse analysis and rule rewrite for each raw parsetree.
*
- * We save the querytrees from each raw parsetree as a separate sublist.
+ * We save the results from each raw parsetree as a separate sublist.
* This allows _SPI_execute_plan() to know where the boundaries between
* original queries fall.
*/
- query_list_list = NIL;
- plan_list = NIL;
+ stmt_list_list = NIL;
foreach(list_item, raw_parsetree_list)
{
@@ -1308,14 +1297,11 @@ _SPI_prepare_plan(const char *src, _SPI_plan *plan)
query_list = pg_analyze_and_rewrite(parsetree, src, argtypes, nargs);
- query_list_list = lappend(query_list_list, query_list);
-
- plan_list = list_concat(plan_list,
- pg_plan_queries(query_list, NULL, false));
+ stmt_list_list = lappend(stmt_list_list,
+ pg_plan_queries(query_list, NULL, false));
}
- plan->qtlist = query_list_list;
- plan->ptlist = plan_list;
+ plan->stmt_list_list = stmt_list_list;
/*
* Pop the error context stack
@@ -1348,9 +1334,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
saveActiveSnapshot = ActiveSnapshot;
PG_TRY();
{
- List *query_list_list = plan->qtlist;
- ListCell *plan_list_item = list_head(plan->ptlist);
- ListCell *query_list_list_item;
+ ListCell *stmt_list_list_item;
ErrorContextCallback spierrcontext;
int nargs = plan->nargs;
ParamListInfo paramLI;
@@ -1386,57 +1370,61 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
spierrcontext.previous = error_context_stack;
error_context_stack = &spierrcontext;
- foreach(query_list_list_item, query_list_list)
+ foreach(stmt_list_list_item, plan->stmt_list_list)
{
- List *query_list = lfirst(query_list_list_item);
- ListCell *query_list_item;
+ List *stmt_list = (List *) lfirst(stmt_list_list_item);
+ ListCell *stmt_list_item;
- foreach(query_list_item, query_list)
+ foreach(stmt_list_item, stmt_list)
{
- Query *queryTree = (Query *) lfirst(query_list_item);
- Plan *planTree;
+ Node *stmt = (Node *) lfirst(stmt_list_item);
+ bool canSetTag;
QueryDesc *qdesc;
DestReceiver *dest;
- planTree = lfirst(plan_list_item);
- plan_list_item = lnext(plan_list_item);
-
_SPI_current->processed = 0;
_SPI_current->lastoid = InvalidOid;
_SPI_current->tuptable = NULL;
- if (queryTree->commandType == CMD_UTILITY)
+ if (IsA(stmt, PlannedStmt))
{
- if (IsA(queryTree->utilityStmt, CopyStmt))
+ canSetTag = ((PlannedStmt *) stmt)->canSetTag;
+ }
+ else
+ {
+ /* utilities are canSetTag if only thing in list */
+ canSetTag = (list_length(stmt_list) == 1);
+
+ if (IsA(stmt, CopyStmt))
{
- CopyStmt *stmt = (CopyStmt *) queryTree->utilityStmt;
+ CopyStmt *cstmt = (CopyStmt *) stmt;
- if (stmt->filename == NULL)
+ if (cstmt->filename == NULL)
{
my_res = SPI_ERROR_COPY;
goto fail;
}
}
- else if (IsA(queryTree->utilityStmt, DeclareCursorStmt) ||
- IsA(queryTree->utilityStmt, ClosePortalStmt) ||
- IsA(queryTree->utilityStmt, FetchStmt))
+ else if (IsA(stmt, DeclareCursorStmt) ||
+ IsA(stmt, ClosePortalStmt) ||
+ IsA(stmt, FetchStmt))
{
my_res = SPI_ERROR_CURSOR;
goto fail;
}
- else if (IsA(queryTree->utilityStmt, TransactionStmt))
+ else if (IsA(stmt, TransactionStmt))
{
my_res = SPI_ERROR_TRANSACTION;
goto fail;
}
}
- if (read_only && !QueryIsReadOnly(queryTree))
+ if (read_only && !CommandIsReadOnly(stmt))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
/* translator: %s is a SQL statement name */
errmsg("%s is not allowed in a non-volatile function",
- CreateQueryTag(queryTree))));
+ CreateCommandTag(stmt))));
/*
* If not read-only mode, advance the command counter before
@@ -1445,7 +1433,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
if (!read_only)
CommandCounterIncrement();
- dest = CreateDestReceiver(queryTree->canSetTag ? DestSPI : DestNone,
+ dest = CreateDestReceiver(canSetTag ? DestSPI : DestNone,
NULL);
if (snapshot == InvalidSnapshot)
@@ -1471,26 +1459,24 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
ActiveSnapshot->curcid = GetCurrentCommandId();
}
- if (queryTree->commandType == CMD_UTILITY)
- {
- ProcessUtility(queryTree->utilityStmt, paramLI,
- dest, NULL);
- /* Update "processed" if stmt returned tuples */
- if (_SPI_current->tuptable)
- _SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free;
- res = SPI_OK_UTILITY;
- }
- else
+ if (IsA(stmt, PlannedStmt))
{
- qdesc = CreateQueryDesc(queryTree, planTree,
+ qdesc = CreateQueryDesc((PlannedStmt *) stmt,
ActiveSnapshot,
crosscheck_snapshot,
dest,
paramLI, false);
- res = _SPI_pquery(qdesc,
- queryTree->canSetTag ? tcount : 0);
+ res = _SPI_pquery(qdesc, canSetTag ? tcount : 0);
FreeQueryDesc(qdesc);
}
+ else
+ {
+ ProcessUtility(stmt, paramLI, dest, NULL);
+ /* Update "processed" if stmt returned tuples */
+ if (_SPI_current->tuptable)
+ _SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free;
+ res = SPI_OK_UTILITY;
+ }
FreeSnapshot(ActiveSnapshot);
ActiveSnapshot = NULL;
@@ -1499,7 +1485,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
* the caller. Be careful to free any tuptables not returned,
* to avoid intratransaction memory leak.
*/
- if (queryTree->canSetTag)
+ if (canSetTag)
{
my_processed = _SPI_current->processed;
my_lastoid = _SPI_current->lastoid;
@@ -1565,7 +1551,7 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
switch (operation)
{
case CMD_SELECT:
- if (queryDesc->parsetree->into) /* select into table? */
+ if (queryDesc->plannedstmt->into) /* select into table? */
res = SPI_OK_SELINTO;
else if (queryDesc->dest->mydest != DestSPI)
{
@@ -1576,19 +1562,19 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
res = SPI_OK_SELECT;
break;
case CMD_INSERT:
- if (queryDesc->parsetree->returningList)
+ if (queryDesc->plannedstmt->returningLists)
res = SPI_OK_INSERT_RETURNING;
else
res = SPI_OK_INSERT;
break;
case CMD_DELETE:
- if (queryDesc->parsetree->returningList)
+ if (queryDesc->plannedstmt->returningLists)
res = SPI_OK_DELETE_RETURNING;
else
res = SPI_OK_DELETE;
break;
case CMD_UPDATE:
- if (queryDesc->parsetree->returningList)
+ if (queryDesc->plannedstmt->returningLists)
res = SPI_OK_UPDATE_RETURNING;
else
res = SPI_OK_UPDATE;
@@ -1611,7 +1597,7 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
_SPI_current->processed = queryDesc->estate->es_processed;
_SPI_current->lastoid = queryDesc->estate->es_lastoid;
- if ((res == SPI_OK_SELECT || queryDesc->parsetree->returningList) &&
+ if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->returningLists) &&
queryDesc->dest->mydest == DestSPI)
{
if (_SPI_checktuples())
@@ -1813,8 +1799,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
newplan->plancxt = plancxt;
newplan->query = pstrdup(plan->query);
- newplan->qtlist = (List *) copyObject(plan->qtlist);
- newplan->ptlist = (List *) copyObject(plan->ptlist);
+ newplan->stmt_list_list = (List *) copyObject(plan->stmt_list_list);
newplan->nargs = plan->nargs;
if (plan->nargs > 0)
{