/*-------------------------------------------------------------------------
*
- * spi.c--
+ * spi.c
* Server Programming Interface
*
+ * $Id: spi.c,v 1.48 2000/10/26 21:35:15 tgl Exp $
+ *
*-------------------------------------------------------------------------
*/
-#include "executor/spi.h"
+#include "executor/spi_priv.h"
#include "access/printtup.h"
-#include "fmgr.h"
-
-typedef struct
-{
- QueryTreeList *qtlist; /* malloced */
- uint32 processed; /* by Executor */
- SPITupleTable *tuptable;
- Portal portal; /* portal per procedure */
- MemoryContext savedcxt;
- CommandId savedId;
-} _SPI_connection;
-static Portal _SPI_portal = (Portal) NULL;
static _SPI_connection *_SPI_stack = NULL;
static _SPI_connection *_SPI_current = NULL;
static int _SPI_connected = -1;
static int _SPI_curid = -1;
-uint32 SPI_processed = 0;
-SPITupleTable *SPI_tuptable;
-int SPI_result;
+DLLIMPORT uint32 SPI_processed = 0;
+DLLIMPORT SPITupleTable *SPI_tuptable = NULL;
+DLLIMPORT int SPI_result;
-void spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
+static int _SPI_execute(char *src, int tcount, _SPI_plan *plan);
+static int _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
-typedef struct
-{
- QueryTreeList *qtlist;
- List *ptlist;
- int nargs;
- Oid *argtypes;
-} _SPI_plan;
-
-static int _SPI_execute(char *src, int tcount, _SPI_plan * plan);
-static int _SPI_pquery(QueryDesc * queryDesc, EState * state, int tcount);
+static int _SPI_execute_plan(_SPI_plan *plan,
+ Datum *Values, char *Nulls, int tcount);
-#if 0
-static void _SPI_fetch(FetchStmt * stmt);
-
-#endif
-static int
-_SPI_execute_plan(_SPI_plan * plan,
- Datum * Values, char *Nulls, int tcount);
-
-#define _SPI_CPLAN_CURCXT 0
-#define _SPI_CPLAN_PROCXT 1
-#define _SPI_CPLAN_TOPCXT 2
-
-static _SPI_plan *_SPI_copy_plan(_SPI_plan * plan, int location);
+static _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location);
static int _SPI_begin_call(bool execmem);
static int _SPI_end_call(bool procmem);
static MemoryContext _SPI_execmem(void);
static MemoryContext _SPI_procmem(void);
-static bool _SPI_checktuples(bool isRetrieveIntoRelation);
+static bool _SPI_checktuples(void);
#ifdef SPI_EXECUTOR_STATS
extern int ShowExecutorStats;
#endif
+/* =================== interface functions =================== */
+
int
SPI_connect()
{
- char pname[64];
- PortalVariableMemory pvmem;
-
- /*
- * It's possible on startup and after commit/abort. In future we'll
- * catch commit/abort in some way...
- */
- strcpy(pname, "<SPI manager>");
- _SPI_portal = GetPortalByName(pname);
- if (!PortalIsValid(_SPI_portal))
- {
- if (_SPI_stack != NULL) /* there was abort */
- free(_SPI_stack);
- _SPI_current = _SPI_stack = NULL;
- _SPI_connected = _SPI_curid = -1;
- SPI_processed = 0;
- SPI_tuptable = NULL;
- _SPI_portal = CreatePortal(pname);
- if (!PortalIsValid(_SPI_portal))
- elog(FATAL, "SPI_connect: global initialization failed");
- }
-
/*
* When procedure called by Executor _SPI_curid expected to be equal
* to _SPI_connected
*/
if (_SPI_curid != _SPI_connected)
- return (SPI_ERROR_CONNECT);
+ return SPI_ERROR_CONNECT;
if (_SPI_stack == NULL)
{
_SPI_current->processed = 0;
_SPI_current->tuptable = NULL;
- /* Create Portal for this procedure ... */
- sprintf(pname, "<SPI %d>", _SPI_connected);
- _SPI_current->portal = CreatePortal(pname);
- if (!PortalIsValid(_SPI_current->portal))
- elog(FATAL, "SPI_connect: initialization failed");
-
- /* ... and switch to Portal' Variable memory - procedure' context */
- pvmem = PortalGetVariableMemory(_SPI_current->portal);
- _SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
+ /* Create memory contexts for this procedure */
+ _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
+ "SPI Proc",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
+ "SPI Exec",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ /* ... and switch to procedure's context */
+ _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
_SPI_current->savedId = GetScanCommandId();
SetScanCommandId(GetCurrentCommandId());
- return (SPI_OK_CONNECT);
+ return SPI_OK_CONNECT;
}
res = _SPI_begin_call(false); /* live in procedure memory */
if (res < 0)
- return (res);
+ return res;
/* Restore memory context as it was before procedure call */
MemoryContextSwitchTo(_SPI_current->savedcxt);
- PortalDestroy(&(_SPI_current->portal));
+
+ /* Release memory used in procedure call */
+ MemoryContextDelete(_SPI_current->execCxt);
+ MemoryContextDelete(_SPI_current->procCxt);
SetScanCommandId(_SPI_current->savedId);
{
free(_SPI_stack);
_SPI_stack = NULL;
+ _SPI_current = NULL;
}
else
{
_SPI_current = &(_SPI_stack[_SPI_connected]);
}
- return (SPI_OK_FINISH);
+ return SPI_OK_FINISH;
+
+}
+
+/*
+ * Clean up SPI state at transaction commit or abort (we don't care which).
+ */
+void
+AtEOXact_SPI(void)
+{
+ /*
+ * Note that memory contexts belonging to SPI stack entries will be
+ * freed automatically, so we can ignore them here. We just need to
+ * restore our static variables to initial state.
+ */
+ if (_SPI_stack != NULL) /* there was abort */
+ free(_SPI_stack);
+ _SPI_current = _SPI_stack = NULL;
+ _SPI_connected = _SPI_curid = -1;
+ SPI_processed = 0;
+ SPI_tuptable = NULL;
+}
+
+void
+SPI_push(void)
+{
+ _SPI_curid++;
+}
+void
+SPI_pop(void)
+{
+ _SPI_curid--;
}
int
int res;
if (src == NULL || tcount < 0)
- return (SPI_ERROR_ARGUMENT);
+ return SPI_ERROR_ARGUMENT;
res = _SPI_begin_call(true);
if (res < 0)
- return (res);
+ return res;
res = _SPI_execute(src, tcount, NULL);
_SPI_end_call(true);
- return (res);
+ return res;
}
int
-SPI_execp(void *plan, Datum * Values, char *Nulls, int tcount)
+SPI_execp(void *plan, Datum *Values, char *Nulls, int tcount)
{
int res;
if (plan == NULL || tcount < 0)
- return (SPI_ERROR_ARGUMENT);
+ return SPI_ERROR_ARGUMENT;
if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
- return (SPI_ERROR_PARAM);
+ return SPI_ERROR_PARAM;
res = _SPI_begin_call(true);
if (res < 0)
- return (res);
+ return res;
/* copy plan to current (executor) context */
plan = (void *) _SPI_copy_plan(plan, _SPI_CPLAN_CURCXT);
res = _SPI_execute_plan((_SPI_plan *) plan, Values, Nulls, tcount);
_SPI_end_call(true);
- return (res);
+ return res;
}
-void *
-SPI_prepare(char *src, int nargs, Oid * argtypes)
+void *
+SPI_prepare(char *src, int nargs, Oid *argtypes)
{
_SPI_plan *plan;
- if (nargs < 0 || (nargs > 0 && argtypes == NULL))
+ if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
{
SPI_result = SPI_ERROR_ARGUMENT;
- return (NULL);
+ return NULL;
}
SPI_result = _SPI_begin_call(true);
if (SPI_result < 0)
- return (NULL);
+ return NULL;
plan = (_SPI_plan *) palloc(sizeof(_SPI_plan)); /* Executor context */
plan->argtypes = argtypes;
_SPI_end_call(true);
- return ((void *) plan);
+ return (void *) plan;
}
-void *
+void *
SPI_saveplan(void *plan)
{
_SPI_plan *newplan;
if (plan == NULL)
{
SPI_result = SPI_ERROR_ARGUMENT;
- return (NULL);
+ return NULL;
}
SPI_result = _SPI_begin_call(false); /* don't change context */
if (SPI_result < 0)
- return (NULL);
+ return NULL;
newplan = _SPI_copy_plan((_SPI_plan *) plan, _SPI_CPLAN_TOPCXT);
_SPI_curid--;
SPI_result = 0;
- return ((void *) newplan);
+ return (void *) newplan;
}
if (tuple == NULL)
{
SPI_result = SPI_ERROR_ARGUMENT;
- return (NULL);
+ return NULL;
}
if (_SPI_curid + 1 == _SPI_connected) /* connected */
if (oldcxt)
MemoryContextSwitchTo(oldcxt);
- return (ctuple);
+ return ctuple;
}
HeapTuple
SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
- Datum * Values, char *Nulls)
+ Datum *Values, char *Nulls)
{
MemoryContext oldcxt = NULL;
HeapTuple mtuple;
if (rel == NULL || tuple == NULL || natts <= 0 || attnum == NULL || Values == NULL)
{
SPI_result = SPI_ERROR_ARGUMENT;
- return (NULL);
+ return NULL;
}
if (_SPI_curid + 1 == _SPI_connected) /* connected */
/* fetch old values and nulls */
for (i = 0; i < numberOfAttributes; i++)
{
- v[i] = heap_getattr(tuple, InvalidBuffer, i + 1, rel->rd_att, &isnull);
+ v[i] = heap_getattr(tuple, i + 1, rel->rd_att, &isnull);
n[i] = (isnull) ? 'n' : ' ';
}
n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? 'n' : ' ';
}
- if (i == natts) /* no errors in attnum[] */
+ if (i == natts) /* no errors in *attnum */
{
mtuple = heap_formtuple(rel->rd_att, v, n);
- infomask = mtuple->t_infomask;
- memmove(&(mtuple->t_ctid), &(tuple->t_ctid),
- ((char *) &(tuple->t_hoff) - (char *) &(tuple->t_ctid)));
- mtuple->t_infomask = infomask;
- mtuple->t_natts = numberOfAttributes;
+ infomask = mtuple->t_data->t_infomask;
+ memmove(&(mtuple->t_data->t_oid), &(tuple->t_data->t_oid),
+ ((char *) &(tuple->t_data->t_hoff) -
+ (char *) &(tuple->t_data->t_oid)));
+ mtuple->t_data->t_infomask = infomask;
+ mtuple->t_data->t_natts = numberOfAttributes;
}
else
{
if (oldcxt)
MemoryContextSwitchTo(oldcxt);
- return (mtuple);
+ return mtuple;
}
int
for (res = 0; res < tupdesc->natts; res++)
{
- if (strcasecmp(tupdesc->attrs[res]->attname.data, fname) == 0)
- return (res + 1);
+ if (strcasecmp(NameStr(tupdesc->attrs[res]->attname), fname) == 0)
+ return res + 1;
}
- return (SPI_ERROR_NOATTRIBUTE);
+ return SPI_ERROR_NOATTRIBUTE;
}
-char *
+char *
SPI_fname(TupleDesc tupdesc, int fnumber)
{
if (tupdesc->natts < fnumber || fnumber <= 0)
{
SPI_result = SPI_ERROR_NOATTRIBUTE;
- return (NULL);
+ return NULL;
}
- return (nameout(&(tupdesc->attrs[fnumber - 1]->attname)));
+ return pstrdup(NameStr(tupdesc->attrs[fnumber - 1]->attname));
}
-char *
+char *
SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
{
Datum val;
bool isnull;
- Oid foutoid;
+ Oid foutoid,
+ typelem;
SPI_result = 0;
- if (tuple->t_natts < fnumber || fnumber <= 0)
- return (NULL);
+ if (tuple->t_data->t_natts < fnumber || fnumber <= 0)
+ {
+ SPI_result = SPI_ERROR_NOATTRIBUTE;
+ return NULL;
+ }
- val = heap_getattr(tuple, InvalidBuffer, fnumber, tupdesc, &isnull);
+ val = heap_getattr(tuple, fnumber, tupdesc, &isnull);
if (isnull)
- return (NULL);
- foutoid = typtoout((Oid) tupdesc->attrs[fnumber - 1]->atttypid);
- if (!OidIsValid(foutoid))
+ return NULL;
+ if (!getTypeOutAndElem((Oid) tupdesc->attrs[fnumber - 1]->atttypid,
+ &foutoid, &typelem))
{
SPI_result = SPI_ERROR_NOOUTFUNC;
- return (NULL);
+ return NULL;
}
- return (fmgr(foutoid, val, gettypelem(tupdesc->attrs[fnumber - 1]->atttypid)));
+ return DatumGetCString(OidFunctionCall3(foutoid,
+ val,
+ ObjectIdGetDatum(typelem),
+ Int32GetDatum(tupdesc->attrs[fnumber - 1]->atttypmod)));
}
Datum
-SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool * isnull)
+SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
{
Datum val;
*isnull = true;
SPI_result = 0;
- if (tuple->t_natts < fnumber || fnumber <= 0)
- return (NULL);
+ if (tuple->t_data->t_natts < fnumber || fnumber <= 0)
+ {
+ SPI_result = SPI_ERROR_NOATTRIBUTE;
+ return (Datum) NULL;
+ }
- val = heap_getattr(tuple, InvalidBuffer, fnumber, tupdesc, isnull);
+ val = heap_getattr(tuple, fnumber, tupdesc, isnull);
- return (val);
+ return val;
}
-char *
+char *
SPI_gettype(TupleDesc tupdesc, int fnumber)
{
HeapTuple typeTuple;
if (tupdesc->natts < fnumber || fnumber <= 0)
{
SPI_result = SPI_ERROR_NOATTRIBUTE;
- return (NULL);
+ return NULL;
}
- typeTuple = SearchSysCacheTuple(TYPOID,
+ typeTuple = SearchSysCacheTuple(TYPEOID,
ObjectIdGetDatum(tupdesc->attrs[fnumber - 1]->atttypid),
0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
{
SPI_result = SPI_ERROR_TYPUNKNOWN;
- return (NULL);
+ return NULL;
}
- return (pstrdup(((TypeTupleForm) GETSTRUCT(typeTuple))->typname.data));
+ return pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
}
Oid
if (tupdesc->natts < fnumber || fnumber <= 0)
{
SPI_result = SPI_ERROR_NOATTRIBUTE;
- return (InvalidOid);
+ return InvalidOid;
}
- return (tupdesc->attrs[fnumber - 1]->atttypid);
+ return tupdesc->attrs[fnumber - 1]->atttypid;
}
-char *
+char *
SPI_getrelname(Relation rel)
{
- return (pstrdup(rel->rd_rel->relname.data));
+ return pstrdup(RelationGetRelationName(rel));
}
+void *
+SPI_palloc(Size size)
+{
+ MemoryContext oldcxt = NULL;
+ void *pointer;
+
+ if (_SPI_curid + 1 == _SPI_connected) /* connected */
+ {
+ if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
+ elog(FATAL, "SPI: stack corrupted");
+ oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
+ }
+
+ pointer = palloc(size);
+
+ if (oldcxt)
+ MemoryContextSwitchTo(oldcxt);
+
+ return pointer;
+}
+
+void *
+SPI_repalloc(void *pointer, Size size)
+{
+ /* No longer need to worry which context chunk was in... */
+ return repalloc(pointer, size);
+}
+
+void
+SPI_pfree(void *pointer)
+{
+ /* No longer need to worry which context chunk was in... */
+ pfree(pointer);
+}
+
+void
+SPI_freetuple(HeapTuple tuple)
+{
+ /* No longer need to worry which context tuple was in... */
+ heap_freetuple(tuple);
+}
+
+/* =================== private functions =================== */
+
/*
- * spi_printtup --
+ * spi_printtup
* store tuple retrieved by Executor into SPITupleTable
* of current SPI procedure
*
*/
void
-spi_printtup(HeapTuple tuple, TupleDesc tupdesc)
+spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver *self)
{
SPITupleTable *tuptable;
MemoryContext oldcxt;
*/
static int
-_SPI_execute(char *src, int tcount, _SPI_plan * plan)
+_SPI_execute(char *src, int tcount, _SPI_plan *plan)
{
- QueryTreeList *queryTree_list;
+ List *queryTree_list;
List *planTree_list;
- List *ptlist;
+ List *queryTree_list_item;
QueryDesc *qdesc;
Query *queryTree;
Plan *planTree;
EState *state;
- int qlen;
int nargs = 0;
Oid *argtypes = NULL;
- int res;
- int i;
+ int res = 0;
+ bool islastquery;
/* Increment CommandCounter to see changes made by now */
CommandCounterIncrement();
nargs = plan->nargs;
argtypes = plan->argtypes;
}
- ptlist = planTree_list = (List *)
- pg_plan(src, argtypes, nargs, &queryTree_list, None);
+
+ queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs);
_SPI_current->qtlist = queryTree_list;
- qlen = queryTree_list->len;
- for (i = 0;; i++)
+ planTree_list = NIL;
+
+ foreach(queryTree_list_item, queryTree_list)
{
- queryTree = (Query *) (queryTree_list->qtrees[i]);
- planTree = lfirst(planTree_list);
+ queryTree = (Query *) lfirst(queryTree_list_item);
+ islastquery = (lnext(queryTree_list_item) == NIL);
- planTree_list = lnext(planTree_list);
+ planTree = pg_plan_query(queryTree);
+ planTree_list = lappend(planTree_list, planTree);
if (queryTree->commandType == CMD_UTILITY)
{
CopyStmt *stmt = (CopyStmt *) (queryTree->utilityStmt);
if (stmt->filename == NULL)
- return (SPI_ERROR_COPY);
+ return SPI_ERROR_COPY;
}
else if (nodeTag(queryTree->utilityStmt) == T_ClosePortalStmt ||
nodeTag(queryTree->utilityStmt) == T_FetchStmt)
- return (SPI_ERROR_CURSOR);
+ return SPI_ERROR_CURSOR;
else if (nodeTag(queryTree->utilityStmt) == T_TransactionStmt)
- return (SPI_ERROR_TRANSACTION);
+ return SPI_ERROR_TRANSACTION;
res = SPI_OK_UTILITY;
if (plan == NULL)
{
ProcessUtility(queryTree->utilityStmt, None);
- if (i < qlen - 1)
+ if (!islastquery)
CommandCounterIncrement();
else
- return (res);
+ return res;
}
- else if (i >= qlen - 1)
+ else if (islastquery)
break;
}
else if (plan == NULL)
{
qdesc = CreateQueryDesc(queryTree, planTree,
- (i < qlen - 1) ? None : SPI);
+ islastquery ? SPI : None);
state = CreateExecutorState();
- res = _SPI_pquery(qdesc, state, (i < qlen - 1) ? 0 : tcount);
- if (res < 0 || i >= qlen - 1)
- return (res);
+ res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
+ if (res < 0 || islastquery)
+ return res;
CommandCounterIncrement();
}
else
{
qdesc = CreateQueryDesc(queryTree, planTree,
- (i < qlen - 1) ? None : SPI);
- res = _SPI_pquery(qdesc, NULL, (i < qlen - 1) ? 0 : tcount);
+ islastquery ? SPI : None);
+ res = _SPI_pquery(qdesc, NULL, islastquery ? tcount : 0);
if (res < 0)
- return (res);
- if (i >= qlen - 1)
+ return res;
+ if (islastquery)
break;
}
}
plan->qtlist = queryTree_list;
- plan->ptlist = ptlist;
-
- return (res);
+ plan->ptlist = planTree_list;
+ return res;
}
static int
-_SPI_execute_plan(_SPI_plan * plan, Datum * Values, char *Nulls, int tcount)
+_SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
{
- QueryTreeList *queryTree_list = plan->qtlist;
+ List *queryTree_list = plan->qtlist;
List *planTree_list = plan->ptlist;
+ List *queryTree_list_item;
QueryDesc *qdesc;
Query *queryTree;
Plan *planTree;
EState *state;
int nargs = plan->nargs;
- int qlen = queryTree_list->len;
- int res;
- int i,
- k;
+ int res = 0;
+ bool islastquery;
+ int k;
/* Increment CommandCounter to see changes made by now */
CommandCounterIncrement();
_SPI_current->tuptable = NULL;
_SPI_current->qtlist = NULL;
- for (i = 0;; i++)
+ foreach(queryTree_list_item, queryTree_list)
{
- queryTree = (Query *) (queryTree_list->qtrees[i]);
+ queryTree = (Query *) lfirst(queryTree_list_item);
planTree = lfirst(planTree_list);
-
planTree_list = lnext(planTree_list);
+ islastquery = (planTree_list == NIL); /* assume lists are same
+ * len */
if (queryTree->commandType == CMD_UTILITY)
{
ProcessUtility(queryTree->utilityStmt, None);
- if (i < qlen - 1)
+ if (!islastquery)
CommandCounterIncrement();
else
- return (SPI_OK_UTILITY);
+ return SPI_OK_UTILITY;
}
else
{
qdesc = CreateQueryDesc(queryTree, planTree,
- (i < qlen - 1) ? None : SPI);
+ islastquery ? SPI : None);
state = CreateExecutorState();
if (nargs > 0)
{
}
else
state->es_param_list_info = NULL;
- res = _SPI_pquery(qdesc, state, (i < qlen - 1) ? 0 : tcount);
- if (res < 0 || i >= qlen - 1)
- return (res);
+ res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
+ if (res < 0 || islastquery)
+ return res;
CommandCounterIncrement();
}
}
- return (res);
-
+ return res;
}
static int
-_SPI_pquery(QueryDesc * queryDesc, EState * state, int tcount)
+_SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
{
- Query *parseTree;
- Plan *plan;
- int operation;
+ Query *parseTree = queryDesc->parsetree;
+ int operation = queryDesc->operation;
+ CommandDest dest = queryDesc->dest;
TupleDesc tupdesc;
bool isRetrieveIntoPortal = false;
bool isRetrieveIntoRelation = false;
char *intoName = NULL;
int res;
- parseTree = queryDesc->parsetree;
- plan = queryDesc->plantree;
- operation = queryDesc->operation;
-
switch (operation)
{
case CMD_SELECT:
intoName = parseTree->into;
parseTree->isBinary = false; /* */
- return (SPI_ERROR_CURSOR);
+ return SPI_ERROR_CURSOR;
}
else if (parseTree->into != NULL) /* select into table */
{
res = SPI_OK_SELINTO;
isRetrieveIntoRelation = true;
+ queryDesc->dest = None; /* */
}
break;
case CMD_INSERT:
res = SPI_OK_UPDATE;
break;
default:
- return (SPI_ERROR_OPUNKNOWN);
+ return SPI_ERROR_OPUNKNOWN;
}
if (state == NULL) /* plan preparation */
- return (res);
+ return res;
#ifdef SPI_EXECUTOR_STATS
if (ShowExecutorStats)
ResetUsage();
#endif
tupdesc = ExecutorStart(queryDesc, state);
- /* Don't work currently */
+ /* Don't work currently --- need to rearrange callers so that
+ * we prepare the portal before doing CreateExecutorState() etc.
+ * See pquery.c for the correct order of operations.
+ */
if (isRetrieveIntoPortal)
{
- ProcessPortal(intoName,
- parseTree,
- plan,
- state,
- tupdesc,
- None);
- return (SPI_OK_CURSOR);
+ elog(FATAL, "SPI_select: retrieve into portal not implemented");
}
- ExecutorRun(queryDesc, state, EXEC_FOR, tcount);
+ ExecutorRun(queryDesc, state, EXEC_FOR, (long) tcount);
_SPI_current->processed = state->es_processed;
if (operation == CMD_SELECT && queryDesc->dest == SPI)
{
- if (_SPI_checktuples(isRetrieveIntoRelation))
+ if (_SPI_checktuples())
elog(FATAL, "SPI_select: # of processed tuples check failed");
}
}
#endif
- if (queryDesc->dest == SPI)
+ if (dest == SPI)
{
SPI_processed = _SPI_current->processed;
SPI_tuptable = _SPI_current->tuptable;
}
+ queryDesc->dest = dest;
- return (res);
+ return res;
}
-#if 0
-static void
-_SPI_fetch(FetchStmt * stmt)
-{
- char *name = stmt->portalname;
- int feature = (stmt->direction == FORWARD) ? EXEC_FOR : EXEC_BACK;
- int count = stmt->howMany;
- Portal portal;
- QueryDesc *queryDesc;
- EState *state;
- MemoryContext context;
-
- if (name == NULL)
- elog(FATAL, "SPI_fetch from blank portal unsupported");
-
- portal = GetPortalByName(name);
- if (!PortalIsValid(portal))
- elog(FATAL, "SPI_fetch: portal \"%s\" not found", name);
-
- context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
-
- queryDesc = PortalGetQueryDesc(portal);
- state = PortalGetState(portal);
-
- ExecutorRun(queryDesc, state, feature, count);
-
- MemoryContextSwitchTo(context); /* switch to the normal Executor
- * context */
-
- _SPI_current->processed = state->es_processed;
- if (_SPI_checktuples(false))
- elog(FATAL, "SPI_fetch: # of processed tuples check failed");
-
- SPI_processed = _SPI_current->processed;
- SPI_tuptable = _SPI_current->tuptable;
-
-}
-
-#endif
-
static MemoryContext
_SPI_execmem()
{
- MemoryContext oldcxt;
- PortalHeapMemory phmem;
-
- phmem = PortalGetHeapMemory(_SPI_current->portal);
- oldcxt = MemoryContextSwitchTo((MemoryContext) phmem);
-
- return (oldcxt);
-
+ return MemoryContextSwitchTo(_SPI_current->execCxt);
}
static MemoryContext
_SPI_procmem()
{
- MemoryContext oldcxt;
- PortalVariableMemory pvmem;
-
- pvmem = PortalGetVariableMemory(_SPI_current->portal);
- oldcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
-
- return (oldcxt);
-
+ return MemoryContextSwitchTo(_SPI_current->procCxt);
}
/*
- * _SPI_begin_call --
+ * _SPI_begin_call
*
*/
static int
_SPI_begin_call(bool execmem)
{
if (_SPI_curid + 1 != _SPI_connected)
- return (SPI_ERROR_UNCONNECTED);
+ return SPI_ERROR_UNCONNECTED;
_SPI_curid++;
if (_SPI_current != &(_SPI_stack[_SPI_curid]))
elog(FATAL, "SPI: stack corrupted");
if (execmem) /* switch to the Executor memory context */
{
_SPI_execmem();
- StartPortalAllocMode(DefaultAllocMode, 0);
}
- return (0);
+ return 0;
}
static int
*/
_SPI_curid--;
- if (_SPI_current->qtlist) /* free _SPI_plan allocations */
- {
- free(_SPI_current->qtlist->qtrees);
- free(_SPI_current->qtlist);
- _SPI_current->qtlist = NULL;
- }
+ _SPI_current->qtlist = NULL;
if (procmem) /* switch to the procedure memory context */
- { /* but free Executor memory before */
- EndPortalAllocMode();
+ {
_SPI_procmem();
+ /* and free Executor memory */
+ MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
}
- return (0);
+ return 0;
}
static bool
-_SPI_checktuples(bool isRetrieveIntoRelation)
+_SPI_checktuples()
{
uint32 processed = _SPI_current->processed;
SPITupleTable *tuptable = _SPI_current->tuptable;
/* some tuples were processed */
{
if (tuptable == NULL) /* spi_printtup was not called */
- {
- if (!isRetrieveIntoRelation)
- failed = true;
- }
- else if (isRetrieveIntoRelation)
failed = true;
else if (processed != (tuptable->alloced - tuptable->free))
failed = true;
}
- return (failed);
+ return failed;
}
static _SPI_plan *
-_SPI_copy_plan(_SPI_plan * plan, int location)
+_SPI_copy_plan(_SPI_plan *plan, int location)
{
_SPI_plan *newplan;
MemoryContext oldcxt = NULL;
- int i;
if (location == _SPI_CPLAN_PROCXT)
- oldcxt = MemoryContextSwitchTo((MemoryContext)
- PortalGetVariableMemory(_SPI_current->portal));
+ oldcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
else if (location == _SPI_CPLAN_TOPCXT)
oldcxt = MemoryContextSwitchTo(TopMemoryContext);
newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
- newplan->qtlist = (QueryTreeList *) palloc(sizeof(QueryTreeList));
- newplan->qtlist->len = plan->qtlist->len;
- newplan->qtlist->qtrees = (Query **) palloc(plan->qtlist->len *
- sizeof(Query *));
- for (i = 0; i < plan->qtlist->len; i++)
- newplan->qtlist->qtrees[i] = (Query *)
- copyObject(plan->qtlist->qtrees[i]);
-
+ newplan->qtlist = (List *) copyObject(plan->qtlist);
newplan->ptlist = (List *) copyObject(plan->ptlist);
newplan->nargs = plan->nargs;
if (plan->nargs > 0)
else
newplan->argtypes = NULL;
- if (location != _SPI_CPLAN_CURCXT)
+ if (oldcxt != NULL)
MemoryContextSwitchTo(oldcxt);
- return (newplan);
+ return newplan;
}