]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/spi.c
Re-implement LIMIT/OFFSET as a plan node type, instead of a hack in
[postgresql] / src / backend / executor / spi.c
index 186c0f0313ef145e066d27d3397e3974f6872301..07a05561a64701c8e13959ee0a3c9941b04d09b3 100644 (file)
@@ -1,66 +1,37 @@
 /*-------------------------------------------------------------------------
  *
- * 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;
@@ -69,37 +40,17 @@ extern void ShowUsage(void);
 
 #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)
        {
@@ -125,20 +76,24 @@ SPI_connect()
        _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;
 
 }
 
@@ -149,11 +104,14 @@ SPI_finish()
 
        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);
 
@@ -168,6 +126,7 @@ SPI_finish()
        {
                free(_SPI_stack);
                _SPI_stack = NULL;
+               _SPI_current = NULL;
        }
        else
        {
@@ -176,8 +135,39 @@ SPI_finish()
                _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
@@ -186,32 +176,32 @@ SPI_exec(char *src, int tcount)
        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);
@@ -219,23 +209,23 @@ SPI_execp(void *plan, Datum * Values, char *Nulls, int tcount)
        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;
@@ -250,11 +240,11 @@ SPI_prepare(char *src, int nargs, Oid * argtypes)
 
        _SPI_end_call(true);
 
-       return ((void *) plan);
+       return (void *) plan;
 
 }
 
-void      *
+void *
 SPI_saveplan(void *plan)
 {
        _SPI_plan  *newplan;
@@ -262,19 +252,19 @@ SPI_saveplan(void *plan)
        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;
 
 }
 
@@ -287,7 +277,7 @@ SPI_copytuple(HeapTuple tuple)
        if (tuple == NULL)
        {
                SPI_result = SPI_ERROR_ARGUMENT;
-               return (NULL);
+               return NULL;
        }
 
        if (_SPI_curid + 1 == _SPI_connected)           /* connected */
@@ -302,12 +292,12 @@ SPI_copytuple(HeapTuple tuple)
        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;
@@ -321,7 +311,7 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
        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 */
@@ -338,7 +328,7 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
        /* 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' : ' ';
        }
 
@@ -351,14 +341,15 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
                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
        {
@@ -372,7 +363,7 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
        if (oldcxt)
                MemoryContextSwitchTo(oldcxt);
 
-       return (mtuple);
+       return mtuple;
 }
 
 int
@@ -382,14 +373,14 @@ SPI_fnumber(TupleDesc tupdesc, char *fname)
 
        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)
 {
 
@@ -397,52 +388,62 @@ 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;
@@ -451,20 +452,20 @@ SPI_gettype(TupleDesc tupdesc, int fnumber)
        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
@@ -475,26 +476,70 @@ SPI_gettypeid(TupleDesc tupdesc, int fnumber)
        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;
@@ -539,20 +584,19 @@ spi_printtup(HeapTuple tuple, TupleDesc tupdesc)
  */
 
 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();
@@ -567,18 +611,20 @@ _SPI_execute(char *src, int tcount, _SPI_plan * plan)
                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)
                {
@@ -587,68 +633,67 @@ _SPI_execute(char *src, int tcount, _SPI_plan * plan)
                                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();
@@ -658,25 +703,26 @@ _SPI_execute_plan(_SPI_plan * plan, Datum * Values, char *Nulls, int tcount)
        _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)
                        {
@@ -695,33 +741,28 @@ _SPI_execute_plan(_SPI_plan * plan, Datum * Values, char *Nulls, int tcount)
                        }
                        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:
@@ -732,13 +773,14 @@ _SPI_pquery(QueryDesc * queryDesc, EState * state, int tcount)
                                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:
@@ -751,35 +793,32 @@ _SPI_pquery(QueryDesc * queryDesc, EState * state, int tcount)
                        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");
        }
 
@@ -793,91 +832,38 @@ _SPI_pquery(QueryDesc * queryDesc, EState * state, int tcount)
        }
 #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");
@@ -885,10 +871,9 @@ _SPI_begin_call(bool execmem)
        if (execmem)                            /* switch to the Executor memory context */
        {
                _SPI_execmem();
-               StartPortalAllocMode(DefaultAllocMode, 0);
        }
 
-       return (0);
+       return 0;
 }
 
 static int
@@ -900,24 +885,20 @@ _SPI_end_call(bool procmem)
         */
        _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;
@@ -932,41 +913,27 @@ _SPI_checktuples(bool isRetrieveIntoRelation)
 /* 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)
@@ -977,8 +944,8 @@ _SPI_copy_plan(_SPI_plan * plan, int location)
        else
                newplan->argtypes = NULL;
 
-       if (location != _SPI_CPLAN_CURCXT)
+       if (oldcxt != NULL)
                MemoryContextSwitchTo(oldcxt);
 
-       return (newplan);
+       return newplan;
 }