Commit f92e8a4b authored by Tom Lane's avatar Tom Lane

Replace the array-style TupleTable data structure with a simple List of

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.
parent 61be11ff
......@@ -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)
{
......
This diff is collapsed.
......@@ -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;
......
......@@ -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,
......
......@@ -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
......@@ -112,7 +112,7 @@
*/
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,
......
......@@ -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) */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment