]> 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 e2e87d88e069aadfa07a6eb6a020444a346468d4..07a05561a64701c8e13959ee0a3c9941b04d09b3 100644 (file)
@@ -1,60 +1,30 @@
 /*-------------------------------------------------------------------------
  *
- * 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 "catalog/pg_type.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;
-
-void           spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
-
-typedef struct
-{
-       QueryTreeList *qtlist;
-       List       *ptlist;
-       int                     nargs;
-       Oid                *argtypes;
-} _SPI_plan;
+DLLIMPORT uint32 SPI_processed = 0;
+DLLIMPORT SPITupleTable *SPI_tuptable = NULL;
+DLLIMPORT int SPI_result;
 
 static int     _SPI_execute(char *src, int tcount, _SPI_plan *plan);
 static int     _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount);
 
-#if 0
-static void _SPI_fetch(FetchStmt *stmt);
-
-#endif
-static int
-_SPI_execute_plan(_SPI_plan *plan,
+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 int     _SPI_begin_call(bool execmem);
@@ -75,34 +45,12 @@ extern void ShowUsage(void);
 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)
        {
@@ -128,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;
 
 }
 
@@ -152,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);
 
@@ -171,6 +126,7 @@ SPI_finish()
        {
                free(_SPI_stack);
                _SPI_stack = NULL;
+               _SPI_current = NULL;
        }
        else
        {
@@ -179,26 +135,57 @@ 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
 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
@@ -207,14 +194,14 @@ 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);
@@ -222,7 +209,7 @@ 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 *
@@ -233,12 +220,12 @@ SPI_prepare(char *src, int nargs, Oid *argtypes)
        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;
@@ -253,7 +240,7 @@ SPI_prepare(char *src, int nargs, Oid *argtypes)
 
        _SPI_end_call(true);
 
-       return ((void *) plan);
+       return (void *) plan;
 
 }
 
@@ -265,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;
 
 }
 
@@ -290,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 */
@@ -305,7 +292,7 @@ SPI_copytuple(HeapTuple tuple)
        if (oldcxt)
                MemoryContextSwitchTo(oldcxt);
 
-       return (ctuple);
+       return ctuple;
 }
 
 HeapTuple
@@ -324,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 */
@@ -354,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
        {
@@ -375,7 +363,7 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
        if (oldcxt)
                MemoryContextSwitchTo(oldcxt);
 
-       return (mtuple);
+       return mtuple;
 }
 
 int
@@ -385,11 +373,11 @@ 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 *
@@ -400,10 +388,10 @@ 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 *
@@ -411,28 +399,30 @@ 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)
+       if (tuple->t_data->t_natts < fnumber || fnumber <= 0)
        {
                SPI_result = SPI_ERROR_NOATTRIBUTE;
-               return (NULL);
+               return NULL;
        }
 
        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),
-                                tupdesc->attrs[fnumber - 1]->atttypmod));
+       return DatumGetCString(OidFunctionCall3(foutoid,
+                                                  val,
+                                                  ObjectIdGetDatum(typelem),
+                                                  Int32GetDatum(tupdesc->attrs[fnumber - 1]->atttypmod)));
 }
 
 Datum
@@ -442,15 +432,15 @@ SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
 
        *isnull = true;
        SPI_result = 0;
-       if (tuple->t_natts < fnumber || fnumber <= 0)
+       if (tuple->t_data->t_natts < fnumber || fnumber <= 0)
        {
                SPI_result = SPI_ERROR_NOATTRIBUTE;
-               return ((Datum) NULL);
+               return (Datum) NULL;
        }
 
        val = heap_getattr(tuple, fnumber, tupdesc, isnull);
 
-       return (val);
+       return val;
 }
 
 char *
@@ -462,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,
-                                        ObjectIdGetDatum(tupdesc->attrs[fnumber - 1]->atttypid),
+       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
@@ -486,16 +476,16 @@ 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 *
 SPI_getrelname(Relation rel)
 {
-       return (pstrdup(rel->rd_rel->relname.data));
+       return pstrdup(RelationGetRelationName(rel));
 }
 
 void *
@@ -516,59 +506,40 @@ SPI_palloc(Size size)
        if (oldcxt)
                MemoryContextSwitchTo(oldcxt);
 
-       return (pointer);
+       return pointer;
 }
 
 void *
 SPI_repalloc(void *pointer, Size size)
 {
-       MemoryContext oldcxt = NULL;
-
-       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 = repalloc(pointer, size);
-
-       if (oldcxt)
-               MemoryContextSwitchTo(oldcxt);
-
-       return (pointer);
+       /* No longer need to worry which context chunk was in... */
+       return repalloc(pointer, size);
 }
 
 void
 SPI_pfree(void *pointer)
 {
-       MemoryContext oldcxt = NULL;
-
-       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);
-       }
-
+       /* No longer need to worry which context chunk was in... */
        pfree(pointer);
+}
 
-       if (oldcxt)
-               MemoryContextSwitchTo(oldcxt);
-
-       return;
+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;
@@ -615,18 +586,17 @@ spi_printtup(HeapTuple tuple, TupleDesc tupdesc)
 static int
 _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();
@@ -641,18 +611,20 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
                nargs = plan->nargs;
                argtypes = plan->argtypes;
        }
-       ptlist = planTree_list = (List *)
-               pg_parse_and_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)
                {
@@ -661,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)
 {
-       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();
@@ -732,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)
                        {
@@ -769,22 +741,20 @@ _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)
 {
        Query      *parseTree = queryDesc->parsetree;
-       Plan       *plan = queryDesc->plantree;
        int                     operation = queryDesc->operation;
        CommandDest dest = queryDesc->dest;
        TupleDesc       tupdesc;
@@ -803,7 +773,7 @@ _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 */
@@ -823,30 +793,27 @@ _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)
@@ -872,85 +839,31 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
        }
        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())
-               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");
@@ -958,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
@@ -973,20 +885,16 @@ _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
@@ -1010,7 +918,7 @@ _SPI_checktuples()
                        failed = true;
        }
 
-       return (failed);
+       return failed;
 }
 
 static _SPI_plan *
@@ -1018,23 +926,14 @@ _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)
@@ -1045,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;
 }