Replace the array-style TupleTable data structure with a simple List of
authorTom Lane
Sun, 27 Sep 2009 20:09:58 +0000 (20:09 +0000)
committerTom Lane
Sun, 27 Sep 2009 20:09:58 +0000 (20:09 +0000)
TupleTableSlot nodes.  This eliminates the need to count in advance
how many Slots will be needed, which seems more than worth the small
increase in the amount of palloc traffic during executor startup.

The ExecCountSlots infrastructure is now all dead code, but I'll remove it
in a separate commit for clarity.

Per a comment from Robert Haas.

src/backend/executor/execMain.c
src/backend/executor/execTuples.c
src/backend/executor/execUtils.c
src/backend/executor/nodeSubplan.c
src/include/executor/tuptable.h
src/include/nodes/execnodes.h

index 1fcf2afdd91e58b367aec530fc4d592c1586f997..d18d66c64a9190af50c2c4e90b7a0f9fd9a731a6 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.328 2009/09/26 22:42:01 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.329 2009/09/27 20:09:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -755,40 +755,12 @@ InitPlan(QueryDesc *queryDesc, int eflags)
    }
 
    /*
-    * Initialize the executor "tuple" table.  We need slots for all the plan
-    * nodes, plus possibly output slots for the junkfilter(s). At this point
-    * we aren't sure if we need junkfilters, so just add slots for them
-    * unconditionally.  Also, if it's not a SELECT, set up a slot for use for
-    * trigger output tuples.  Also, one for RETURNING-list evaluation.
+    * Initialize the executor's tuple table.  Also, if it's not a SELECT,
+    * set up a tuple table slot for use for trigger output tuples.
     */
-   {
-       int         nSlots;
-
-       /* Slots for the main plan tree */
-       nSlots = ExecCountSlotsNode(plan);
-       /* Add slots for subplans and initplans */
-       foreach(l, plannedstmt->subplans)
-       {
-           Plan       *subplan = (Plan *) lfirst(l);
-
-           nSlots += ExecCountSlotsNode(subplan);
-       }
-       /* Add slots for junkfilter(s) */
-       if (plannedstmt->resultRelations != NIL)
-           nSlots += list_length(plannedstmt->resultRelations);
-       else
-           nSlots += 1;
-       if (operation != CMD_SELECT)
-           nSlots++;           /* for es_trig_tuple_slot */
-       if (plannedstmt->returningLists)
-           nSlots++;           /* for RETURNING projection */
-
-       estate->es_tupleTable = ExecCreateTupleTable(nSlots);
-
-       if (operation != CMD_SELECT)
-           estate->es_trig_tuple_slot =
-               ExecAllocTableSlot(estate->es_tupleTable);
-   }
+   estate->es_tupleTable = NIL;
+   if (operation != CMD_SELECT)
+       estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate);
 
    /* mark EvalPlanQual not active */
    estate->es_plannedstmt = plannedstmt;
@@ -909,7 +881,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
 
                    j = ExecInitJunkFilter(subplan->plan->targetlist,
                            resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,
-                                 ExecAllocTableSlot(estate->es_tupleTable));
+                                          ExecInitExtraTupleSlot(estate));
 
                    /*
                     * Since it must be UPDATE/DELETE, there had better be a
@@ -953,7 +925,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
 
                j = ExecInitJunkFilter(planstate->plan->targetlist,
                                       tupType->tdhasoid,
-                                 ExecAllocTableSlot(estate->es_tupleTable));
+                                      ExecInitExtraTupleSlot(estate));
                estate->es_junkFilter = j;
                if (estate->es_result_relation_info)
                    estate->es_result_relation_info->ri_junkFilter = j;
@@ -1026,7 +998,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
                                 false);
 
        /* Set up a slot for the output of the RETURNING projection(s) */
-       slot = ExecAllocTableSlot(estate->es_tupleTable);
+       slot = ExecInitExtraTupleSlot(estate);
        ExecSetSlotDescriptor(slot, tupType);
        /* Need an econtext too */
        econtext = CreateExprContext(estate);
@@ -1387,10 +1359,12 @@ ExecEndPlan(PlanState *planstate, EState *estate)
    }
 
    /*
-    * destroy the executor "tuple" table.
+    * destroy the executor's tuple table.  Actually we only care about
+    * releasing buffer pins and tupdesc refcounts; there's no need to
+    * pfree the TupleTableSlots, since the containing memory context
+    * is about to go away anyway.
     */
-   ExecDropTupleTable(estate->es_tupleTable, true);
-   estate->es_tupleTable = NULL;
+   ExecResetTupleTable(estate->es_tupleTable, false);
 
    /*
     * close the result relation(s) if any, but hold locks until xact commit.
@@ -2712,10 +2686,9 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
        epqstate->es_evTuple = priorepq->estate->es_evTuple;
 
    /*
-    * Create sub-tuple-table; we needn't redo the CountSlots work though.
+    * Each epqstate also has its own tuple table.
     */
-   epqstate->es_tupleTable =
-       ExecCreateTupleTable(estate->es_tupleTable->size);
+   epqstate->es_tupleTable = NIL;
 
    /*
     * Initialize private state information for each SubPlan.  We must do this
@@ -2770,8 +2743,9 @@ EvalPlanQualStop(evalPlanQual *epq)
        ExecEndNode(subplanstate);
    }
 
-   ExecDropTupleTable(epqstate->es_tupleTable, true);
-   epqstate->es_tupleTable = NULL;
+   /* throw away the per-epqstate tuple table completely */
+   ExecResetTupleTable(epqstate->es_tupleTable, true);
+   epqstate->es_tupleTable = NIL;
 
    if (epqstate->es_evTuple[epq->rti - 1] != NULL)
    {
index d92ba062d44a73177014990cd3f4cfa646dcb251..73a882c6a151810b7689464233767cee20df4455 100644 (file)
@@ -1,9 +1,11 @@
 /*-------------------------------------------------------------------------
  *
  * execTuples.c
- *   Routines dealing with the executor tuple tables.  These are used to
- *   ensure that the executor frees copies of tuples (made by
- *   ExecTargetList) properly.
+ *   Routines dealing with TupleTableSlots.  These are used for resource
+ *   management associated with tuples (eg, releasing buffer pins for
+ *   tuples in disk buffers, or freeing the memory occupied by transient
+ *   tuples).  Slots also provide access abstraction that lets us implement
+ *   "virtual" tuples to reduce data-copying overhead.
  *
  *   Routines dealing with the type information for tuples. Currently,
  *   the type information for a tuple is an array of FormData_pg_attribute.
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.109 2009/07/23 21:27:10 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.110 2009/09/27 20:09:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * INTERFACE ROUTINES
  *
- *  TABLE CREATE/DELETE
- *     ExecCreateTupleTable    - create a new tuple table
- *     ExecDropTupleTable      - destroy a table
- *     MakeSingleTupleTableSlot - make a single-slot table
- *     ExecDropSingleTupleTableSlot - destroy same
- *
- *  SLOT RESERVATION
- *     ExecAllocTableSlot      - find an available slot in the table
+ *  SLOT CREATION/DESTRUCTION
+ *     MakeTupleTableSlot      - create an empty slot
+ *     ExecAllocTableSlot      - create a slot within a tuple table
+ *     ExecResetTupleTable     - clear and optionally delete a tuple table
+ *     MakeSingleTupleTableSlot - make a standalone slot, set its descriptor
+ *     ExecDropSingleTupleTableSlot - destroy a standalone slot
  *
  *  SLOT ACCESSORS
  *     ExecSetSlotDescriptor   - set a slot's tuple descriptor
  *
  *     At ExecutorStart()
  *     ----------------
- *     - InitPlan() calls ExecCreateTupleTable() to create the tuple
- *       table which will hold tuples processed by the executor.
- *
  *     - ExecInitSeqScan() calls ExecInitScanTupleSlot() and
- *       ExecInitResultTupleSlot() to reserve places in the tuple
- *       table for the tuples returned by the access methods and the
+ *       ExecInitResultTupleSlot() to construct TupleTableSlots
+ *       for the tuples returned by the access methods and the
  *       tuples resulting from performing target list projections.
  *
  *     During ExecutorRun()
@@ -79,7 +76,7 @@
  *
  *     At ExecutorEnd()
  *     ----------------
- *     - EndPlan() calls ExecDropTupleTable() to clean up any remaining
+ *     - EndPlan() calls ExecResetTupleTable() to clean up any remaining
  *       tuples left over from executing the query.
  *
  *     The important thing to watch in the executor code is how pointers
@@ -110,103 +107,91 @@ static TupleDesc ExecTypeFromTLInternal(List *targetList,
  */
 
 /* --------------------------------
- *     ExecCreateTupleTable
- *
- *     This creates a new tuple table of the specified size.
+ *     MakeTupleTableSlot
  *
- *     This should be used by InitPlan() to allocate the table.
- *     The table's address will be stored in the EState structure.
+ *     Basic routine to make an empty TupleTableSlot.
  * --------------------------------
  */
-TupleTable
-ExecCreateTupleTable(int tableSize)
+TupleTableSlot *
+MakeTupleTableSlot(void)
 {
-   TupleTable  newtable;
-   int         i;
+   TupleTableSlot *slot = makeNode(TupleTableSlot);
 
-   /*
-    * sanity checks
-    */
-   Assert(tableSize >= 1);
+   slot->tts_isempty = true;
+   slot->tts_shouldFree = false;
+   slot->tts_shouldFreeMin = false;
+   slot->tts_tuple = NULL;
+   slot->tts_tupleDescriptor = NULL;
+   slot->tts_mcxt = CurrentMemoryContext;
+   slot->tts_buffer = InvalidBuffer;
+   slot->tts_nvalid = 0;
+   slot->tts_values = NULL;
+   slot->tts_isnull = NULL;
+   slot->tts_mintuple = NULL;
 
-   /*
-    * allocate the table itself
-    */
-   newtable = (TupleTable) palloc(sizeof(TupleTableData) +
-                                  (tableSize - 1) *sizeof(TupleTableSlot));
-   newtable->size = tableSize;
-   newtable->next = 0;
+   return slot;
+}
 
-   /*
-    * initialize all the slots to empty states
-    */
-   for (i = 0; i < tableSize; i++)
-   {
-       TupleTableSlot *slot = &(newtable->array[i]);
-
-       slot->type = T_TupleTableSlot;
-       slot->tts_isempty = true;
-       slot->tts_shouldFree = false;
-       slot->tts_shouldFreeMin = false;
-       slot->tts_tuple = NULL;
-       slot->tts_tupleDescriptor = NULL;
-       slot->tts_mcxt = CurrentMemoryContext;
-       slot->tts_buffer = InvalidBuffer;
-       slot->tts_nvalid = 0;
-       slot->tts_values = NULL;
-       slot->tts_isnull = NULL;
-       slot->tts_mintuple = NULL;
-   }
+/* --------------------------------
+ *     ExecAllocTableSlot
+ *
+ *     Create a tuple table slot within a tuple table (which is just a List).
+ * --------------------------------
+ */
+TupleTableSlot *
+ExecAllocTableSlot(List **tupleTable)
+{
+   TupleTableSlot *slot = MakeTupleTableSlot();
+
+   *tupleTable = lappend(*tupleTable, slot);
 
-   return newtable;
+   return slot;
 }
 
 /* --------------------------------
- *     ExecDropTupleTable
+ *     ExecResetTupleTable
  *
- *     This frees the storage used by the tuple table itself
- *     and optionally frees the contents of the table also.
+ *     This releases any resources (buffer pins, tupdesc refcounts)
+ *     held by the tuple table, and optionally releases the memory
+ *     occupied by the tuple table data structure.
  *     It is expected that this routine be called by EndPlan().
  * --------------------------------
  */
 void
-ExecDropTupleTable(TupleTable table,   /* tuple table */
-                  bool shouldFree)     /* true if we should free slot
-                                        * contents */
+ExecResetTupleTable(List *tupleTable,  /* tuple table */
+                   bool shouldFree)    /* true if we should free memory */
 {
-   /*
-    * sanity checks
-    */
-   Assert(table != NULL);
+   ListCell   *lc;
 
-   /*
-    * first free all the valid pointers in the tuple array and drop refcounts
-    * of any referenced buffers, if that's what the caller wants.  (There is
-    * probably no good reason for the caller ever not to want it!)
-    */
-   if (shouldFree)
+   foreach(lc, tupleTable)
    {
-       int         next = table->next;
-       int         i;
+       TupleTableSlot *slot = (TupleTableSlot *) lfirst(lc);
 
-       for (i = 0; i < next; i++)
+       /* Sanity checks */
+       Assert(IsA(slot, TupleTableSlot));
+
+       /* Always release resources and reset the slot to empty */
+       ExecClearTuple(slot);
+       if (slot->tts_tupleDescriptor)
        {
-           TupleTableSlot *slot = &(table->array[i]);
+           ReleaseTupleDesc(slot->tts_tupleDescriptor);
+           slot->tts_tupleDescriptor = NULL;
+       }
 
-           ExecClearTuple(slot);
-           if (slot->tts_tupleDescriptor)
-               ReleaseTupleDesc(slot->tts_tupleDescriptor);
+       /* If shouldFree, release memory occupied by the slot itself */
+       if (shouldFree)
+       {
            if (slot->tts_values)
                pfree(slot->tts_values);
            if (slot->tts_isnull)
                pfree(slot->tts_isnull);
+           pfree(slot);
        }
    }
 
-   /*
-    * finally free the tuple table itself.
-    */
-   pfree(table);
+   /* If shouldFree, release the list structure */
+   if (shouldFree)
+       list_free(tupleTable);
 }
 
 /* --------------------------------
@@ -214,27 +199,14 @@ ExecDropTupleTable(TupleTable table,  /* tuple table */
  *
  *     This is a convenience routine for operations that need a
  *     standalone TupleTableSlot not gotten from the main executor
- *     tuple table.  It makes a single slot and initializes it as
- *     though by ExecSetSlotDescriptor(slot, tupdesc).
+ *     tuple table.  It makes a single slot and initializes it
+ *     to use the given tuple descriptor.
  * --------------------------------
  */
 TupleTableSlot *
 MakeSingleTupleTableSlot(TupleDesc tupdesc)
 {
-   TupleTableSlot *slot = makeNode(TupleTableSlot);
-
-   /* This should match ExecCreateTupleTable() */
-   slot->tts_isempty = true;
-   slot->tts_shouldFree = false;
-   slot->tts_shouldFreeMin = false;
-   slot->tts_tuple = NULL;
-   slot->tts_tupleDescriptor = NULL;
-   slot->tts_mcxt = CurrentMemoryContext;
-   slot->tts_buffer = InvalidBuffer;
-   slot->tts_nvalid = 0;
-   slot->tts_values = NULL;
-   slot->tts_isnull = NULL;
-   slot->tts_mintuple = NULL;
+   TupleTableSlot *slot = MakeTupleTableSlot();
 
    ExecSetSlotDescriptor(slot, tupdesc);
 
@@ -245,16 +217,14 @@ MakeSingleTupleTableSlot(TupleDesc tupdesc)
  *     ExecDropSingleTupleTableSlot
  *
  *     Release a TupleTableSlot made with MakeSingleTupleTableSlot.
+ *     DON'T use this on a slot that's part of a tuple table list!
  * --------------------------------
  */
 void
 ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
 {
-   /*
-    * sanity checks
-    */
-   Assert(slot != NULL);
-
+   /* This should match ExecResetTupleTable's processing of one slot */
+   Assert(IsA(slot, TupleTableSlot));
    ExecClearTuple(slot);
    if (slot->tts_tupleDescriptor)
        ReleaseTupleDesc(slot->tts_tupleDescriptor);
@@ -262,50 +232,10 @@ ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
        pfree(slot->tts_values);
    if (slot->tts_isnull)
        pfree(slot->tts_isnull);
-
    pfree(slot);
 }
 
 
-/* ----------------------------------------------------------------
- *               tuple table slot reservation functions
- * ----------------------------------------------------------------
- */
-
-/* --------------------------------
- *     ExecAllocTableSlot
- *
- *     This routine is used to reserve slots in the table for
- *     use by the various plan nodes.  It is expected to be
- *     called by the node init routines (ex: ExecInitNestLoop)
- *     once per slot needed by the node.  Not all nodes need
- *     slots (some just pass tuples around).
- * --------------------------------
- */
-TupleTableSlot *
-ExecAllocTableSlot(TupleTable table)
-{
-   int         slotnum;        /* new slot number */
-
-   /*
-    * sanity checks
-    */
-   Assert(table != NULL);
-
-   /*
-    * We expect that the table was made big enough to begin with. We cannot
-    * reallocate it on the fly since previous plan nodes have already got
-    * pointers to individual entries.
-    */
-   if (table->next >= table->size)
-       elog(ERROR, "plan requires more slots than are available");
-
-   slotnum = table->next;
-   table->next++;
-
-   return &(table->array[slotnum]);
-}
-
 /* ----------------------------------------------------------------
  *               tuple table slot accessor functions
  * ----------------------------------------------------------------
@@ -915,7 +845,7 @@ ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
 void
 ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
 {
-   planstate->ps_ResultTupleSlot = ExecAllocTableSlot(estate->es_tupleTable);
+   planstate->ps_ResultTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable);
 }
 
 /* ----------------
@@ -925,7 +855,7 @@ ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
 void
 ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
 {
-   scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(estate->es_tupleTable);
+   scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable);
 }
 
 /* ----------------
@@ -935,7 +865,7 @@ ExecInitScanTupleSlot(EState *estate, ScanState *scanstate)
 TupleTableSlot *
 ExecInitExtraTupleSlot(EState *estate)
 {
-   return ExecAllocTableSlot(estate->es_tupleTable);
+   return ExecAllocTableSlot(&estate->es_tupleTable);
 }
 
 /* ----------------
index 43c0e54065359ac0847017c2a0098a05f37c517e..c20c76cbae0087f659d312802d3d10c498135e8f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.161 2009/07/29 20:56:18 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.162 2009/09/27 20:09:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -197,7 +197,7 @@ CreateExecutorState(void)
 
    estate->es_query_cxt = qcontext;
 
-   estate->es_tupleTable = NULL;
+   estate->es_tupleTable = NIL;
 
    estate->es_processed = 0;
    estate->es_lastoid = InvalidOid;
index 016dbc378b4954fa4404ea13b7d3618a0d23e763..753655e9a49eb23d08c9aba7446ca3b210f8db5e 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.99 2009/06/11 14:48:57 momjian Exp $
+ *   $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.100 2009/09/27 20:09:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -721,7 +721,6 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
        int         ncols,
                    i;
        TupleDesc   tupDesc;
-       TupleTable  tupTable;
        TupleTableSlot *slot;
        List       *oplist,
                   *lefttlist,
@@ -852,15 +851,6 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
            i++;
        }
 
-       /*
-        * Create a tupletable to hold these tuples.  (Note: we never bother
-        * to free the tupletable explicitly; that's okay because it will
-        * never store raw disk tuples that might have associated buffer pins.
-        * The only resource involved is memory, which will be cleaned up by
-        * freeing the query context.)
-        */
-       tupTable = ExecCreateTupleTable(2);
-
        /*
         * Construct tupdescs, slots and projection nodes for left and right
         * sides.  The lefthand expressions will be evaluated in the parent
@@ -870,7 +860,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
         * own innerecontext.
         */
        tupDesc = ExecTypeFromTL(leftptlist, false);
-       slot = ExecAllocTableSlot(tupTable);
+       slot = ExecInitExtraTupleSlot(estate);
        ExecSetSlotDescriptor(slot, tupDesc);
        sstate->projLeft = ExecBuildProjectionInfo(lefttlist,
                                                   NULL,
@@ -878,7 +868,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
                                                   NULL);
 
        tupDesc = ExecTypeFromTL(rightptlist, false);
-       slot = ExecAllocTableSlot(tupTable);
+       slot = ExecInitExtraTupleSlot(estate);
        ExecSetSlotDescriptor(slot, tupDesc);
        sstate->projRight = ExecBuildProjectionInfo(righttlist,
                                                    sstate->innerecontext,
index 879a310c68bde584bb49cc7a949c1018317ba165..ffac7e0162064a5b6c23a23dec1c4c62790d4fcf 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/tuptable.h,v 1.42 2009/06/11 14:49:11 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/tuptable.h,v 1.43 2009/09/27 20:09:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,7 +19,7 @@
 #include "storage/buf.h"
 
 /*----------
- * The executor stores tuples in a "tuple table" which is composed of
+ * The executor stores tuples in a "tuple table" which is a List of
  * independent TupleTableSlots.  There are several cases we need to handle:
  *     1. physical tuple in a disk buffer page
  *     2. physical tuple constructed in palloc'ed memory
  */
 typedef struct TupleTableSlot
 {
-   NodeTag     type;           /* vestigial ... allows IsA tests */
+   NodeTag     type;
    bool        tts_isempty;    /* true = slot is empty */
    bool        tts_shouldFree; /* should pfree tts_tuple? */
    bool        tts_shouldFreeMin;      /* should pfree tts_mintuple? */
@@ -132,19 +132,6 @@ typedef struct TupleTableSlot
 #define TTS_HAS_PHYSICAL_TUPLE(slot)  \
    ((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr))
 
-/*
- * Tuple table data structure: an array of TupleTableSlots.
- */
-typedef struct TupleTableData
-{
-   int         size;           /* size of the table (number of slots) */
-   int         next;           /* next available slot number */
-   TupleTableSlot array[1];    /* VARIABLE LENGTH ARRAY - must be last */
-} TupleTableData;              /* VARIABLE LENGTH STRUCT */
-
-typedef TupleTableData *TupleTable;
-
-
 /*
  * TupIsNull -- is a TupleTableSlot empty?
  */
@@ -152,11 +139,11 @@ typedef TupleTableData *TupleTable;
    ((slot) == NULL || (slot)->tts_isempty)
 
 /* in executor/execTuples.c */
-extern TupleTable ExecCreateTupleTable(int tableSize);
-extern void ExecDropTupleTable(TupleTable table, bool shouldFree);
+extern TupleTableSlot *MakeTupleTableSlot(void);
+extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable);
+extern void ExecResetTupleTable(List *tupleTable, bool shouldFree);
 extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc);
 extern void ExecDropSingleTupleTableSlot(TupleTableSlot *slot);
-extern TupleTableSlot *ExecAllocTableSlot(TupleTable table);
 extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc);
 extern TupleTableSlot *ExecStoreTuple(HeapTuple tuple,
               TupleTableSlot *slot,
index 742ff325752234db5e9a84590c954c1a42bd0305..ea66e109c15621db0090620b7a6a146ff938fb31 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.207 2009/08/23 18:26:08 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.208 2009/09/27 20:09:58 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -352,7 +352,7 @@ typedef struct EState
    /* Other working state: */
    MemoryContext es_query_cxt; /* per-query context in which EState lives */
 
-   TupleTable  es_tupleTable;  /* Array of TupleTableSlots */
+   List       *es_tupleTable;  /* List of TupleTableSlots */
 
    uint32      es_processed;   /* # of tuples processed */
    Oid         es_lastoid;     /* last oid processed (by INSERT) */