*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.68 2001/01/12 00:12:58 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.69 2001/01/29 00:39:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
- ExecSetSlotDescriptor(slot, htupdesc);
+ ExecSetSlotDescriptor(slot, htupdesc, false);
}
else
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.47 2001/01/24 19:42:47 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.48 2001/01/29 00:39:13 tgl Exp $
*
* NOTES
* This file contains only the public interface routines.
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
- ExecSetSlotDescriptor(slot, htupdesc);
+ ExecSetSlotDescriptor(slot, htupdesc, false);
}
else
{
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.76 2001/01/26 01:24:31 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.77 2001/01/29 00:39:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
- ExecSetSlotDescriptor(slot, htupdesc);
+ ExecSetSlotDescriptor(slot, htupdesc, false);
/*
* we never want to use sort/build if we are extending an existing
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.58 2001/01/24 19:42:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.59 2001/01/29 00:39:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
- ExecSetSlotDescriptor(slot, htupdesc);
+ ExecSetSlotDescriptor(slot, htupdesc, false);
}
else
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.139 2001/01/24 19:42:51 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.140 2001/01/29 00:39:16 tgl Exp $
*
*
* INTERFACE ROUTINES
{
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
- ExecSetSlotDescriptor(slot, heapDescriptor);
+ ExecSetSlotDescriptor(slot, heapDescriptor, false);
}
else
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.119 2001/01/24 19:42:52 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.120 2001/01/29 00:39:20 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
bool successful = true;
HeapScanDesc scan;
ExprContext *econtext;
- TupleTableSlot *slot = makeNode(TupleTableSlot);
+ TupleTableSlot *slot;
HeapTuple tuple;
RangeTblEntry *rte;
List *qual;
qual = makeList1(expr);
+ /* Make tuple slot to hold tuples */
+ slot = MakeTupleTableSlot();
+ ExecSetSlotDescriptor(slot, RelationGetDescr(rel), false);
+ /* Make an expression context for ExecQual */
+ econtext = MakeExprContext(slot, CurrentMemoryContext);
+
/*
- * Scan through the rows now, making the necessary things
- * for ExecQual, and then call it to evaluate the
- * expression.
+ * Scan through the rows now, checking the expression
+ * at each row.
*/
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
{
- slot->val = tuple;
- slot->ttc_shouldFree = false;
- slot->ttc_descIsNew = true;
- slot->ttc_tupleDescriptor = rel->rd_att;
- slot->ttc_buffer = InvalidBuffer;
-
- econtext = MakeExprContext(slot, CurrentMemoryContext);
+ ExecStoreTuple(tuple, slot, InvalidBuffer, false);
if (!ExecQual(qual, econtext, true))
{
successful=false;
break;
}
- FreeExprContext(econtext);
+ ResetExprContext(econtext);
}
+ FreeExprContext(econtext);
pfree(slot);
heap_endscan(scan);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.132 2001/01/24 19:42:52 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.133 2001/01/29 00:39:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* Set up a dummy tuple table too */
tupleTable = ExecCreateTupleTable(1);
slot = ExecAllocTableSlot(tupleTable);
- ExecSetSlotDescriptor(slot, tupDesc);
+ ExecSetSlotDescriptor(slot, tupDesc, false);
if (!binary)
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.24 2001/01/24 19:42:53 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execJunk.c,v 1.25 2001/01/29 00:39:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
-
-
#include "postgres.h"
#include "access/heapam.h"
* called 'resjunk'. If the value of this attribute is true then the
* corresponding attribute is a "junk" attribute.
*
- * When we initialize a plan we call 'ExecInitJunkFilter' to create
+ * When we initialize a plan we call 'ExecInitJunkFilter' to create
* and store the appropriate information in the 'es_junkFilter' attribute of
* EState.
*
JunkFilter *
ExecInitJunkFilter(List *targetList, TupleDesc tupType)
{
+ MemoryContext oldContext;
+ MemoryContext junkContext;
JunkFilter *junkfilter;
List *cleanTargetList;
int len,
bool resjunk;
AttrNumber cleanResno;
AttrNumber *cleanMap;
- Size size;
Node *expr;
+ /*
+ * Make a memory context that will hold the JunkFilter as well as all
+ * the subsidiary structures we are about to create. We use smaller-
+ * than-default sizing parameters since we don't expect a very large
+ * volume of stuff here.
+ */
+ junkContext = AllocSetContextCreate(CurrentMemoryContext,
+ "JunkFilterContext",
+ 1024,
+ 1024,
+ ALLOCSET_DEFAULT_MAXSIZE);
+ oldContext = MemoryContextSwitchTo(junkContext);
+
/* ---------------------
* First find the "clean" target list, i.e. all the entries
* in the original target list which have a false 'resjunk'
cleanLength = ExecTargetListLength(cleanTargetList);
/* ---------------------
- * Now calculate the "map" between the original tuples attributes
+ * Now calculate the "map" between the original tuple's attributes
* and the "clean" tuple's attributes.
*
* The "map" is an array of "cleanLength" attribute numbers, i.e.
*/
if (cleanLength > 0)
{
- size = cleanLength * sizeof(AttrNumber);
- cleanMap = (AttrNumber *) palloc(size);
+ cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
cleanResno = 1;
foreach(t, targetList)
{
cleanMap = NULL;
/* ---------------------
- * Finally create and initialize the JunkFilter.
+ * Finally create and initialize the JunkFilter struct.
* ---------------------
*/
junkfilter = makeNode(JunkFilter);
junkfilter->jf_cleanLength = cleanLength;
junkfilter->jf_cleanTupType = cleanTupType;
junkfilter->jf_cleanMap = cleanMap;
+ junkfilter->jf_junkContext = junkContext;
+
+ MemoryContextSwitchTo(oldContext);
return junkfilter;
+}
+/*-------------------------------------------------------------------------
+ * ExecFreeJunkFilter
+ *
+ * Release the data structures created by ExecInitJunkFilter.
+ *-------------------------------------------------------------------------
+ */
+void
+ExecFreeJunkFilter(JunkFilter *junkfilter)
+{
+ /*
+ * Since the junkfilter is inside its own context, we just have to
+ * delete the context and we're set.
+ */
+ MemoryContextDelete(junkfilter->jf_junkContext);
}
/*-------------------------------------------------------------------------
* ExecGetJunkAttribute
*
* Given a tuple (slot), the junk filter and a junk attribute's name,
- * extract & return the value of this attribute.
+ * extract & return the value and isNull flag of this attribute.
*
* It returns false iff no junk attribute with such name was found.
- *
- * NOTE: isNull might be NULL !
*-------------------------------------------------------------------------
*/
bool
* ---------------------
*/
tuple = slot->val;
- tupType = (TupleDesc) junkfilter->jf_tupType;
+ tupType = junkfilter->jf_tupType;
*value = heap_getattr(tuple, resno, tupType, isNull);
int cleanLength;
bool isNull;
int i;
- Size size;
Datum *values;
char *nulls;
Datum values_array[64];
*/
tuple = slot->val;
- tupType = (TupleDesc) junkfilter->jf_tupType;
- cleanTupType = (TupleDesc) junkfilter->jf_cleanTupType;
+ tupType = junkfilter->jf_tupType;
+ cleanTupType = junkfilter->jf_cleanTupType;
cleanLength = junkfilter->jf_cleanLength;
cleanMap = junkfilter->jf_cleanMap;
*/
if (cleanLength > 64)
{
- size = cleanLength * sizeof(Datum);
- values = (Datum *) palloc(size);
-
- size = cleanLength * sizeof(char);
- nulls = (char *) palloc(size);
+ values = (Datum *) palloc(cleanLength * sizeof(Datum));
+ nulls = (char *) palloc(cleanLength * sizeof(char));
}
else
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.137 2001/01/27 05:16:58 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.138 2001/01/29 00:39:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* ExecutorEnd
*
- * This routine must be called at the end of any execution of any
+ * This routine must be called at the end of execution of any
* query plan
- *
- * returns (AttrInfo*) which describes the attributes of the tuples to
- * be returned by the query.
- *
* ----------------------------------------------------------------
*/
void
EndPlan(queryDesc->plantree, estate);
- /* XXX - clean up some more from ExecutorStart() - er1p */
- if (NULL == estate->es_snapshot)
- {
- /* nothing to free */
- }
- else
+ if (estate->es_snapshot != NULL)
{
if (estate->es_snapshot->xcnt > 0)
pfree(estate->es_snapshot->xip);
pfree(estate->es_snapshot);
+ estate->es_snapshot = NULL;
}
- if (NULL == estate->es_param_exec_vals)
- {
- /* nothing to free */
- }
- else
+ if (estate->es_param_exec_vals != NULL)
{
pfree(estate->es_param_exec_vals);
estate->es_param_exec_vals = NULL;
/*
* close the result relation(s) if any, but hold locks
- * until xact commit.
+ * until xact commit. Also clean up junkfilters if present.
*/
resultRelInfo = estate->es_result_relations;
for (i = estate->es_num_result_relations; i > 0; i--)
/* Close indices and then the relation itself */
ExecCloseIndices(resultRelInfo);
heap_close(resultRelInfo->ri_RelationDesc, NoLock);
+ /* Delete the junkfilter if any */
+ if (resultRelInfo->ri_junkFilter != NULL)
+ ExecFreeJunkFilter(resultRelInfo->ri_junkFilter);
resultRelInfo++;
}
if (estate->es_into_relation_descriptor != NULL)
heap_close(estate->es_into_relation_descriptor, NoLock);
+ /*
+ * There might be a junkfilter without a result relation.
+ */
+ if (estate->es_num_result_relations == 0 &&
+ estate->es_junkFilter != NULL)
+ {
+ ExecFreeJunkFilter(estate->es_junkFilter);
+ estate->es_junkFilter = NULL;
+ }
+
/*
* close any relations selected FOR UPDATE, again keeping locks
*/
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.24 2001/01/24 19:42:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.25 2001/01/29 00:39:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* ExecInitNode - initialize a plan node and its subplans
* ExecProcNode - get a tuple by executing the plan node
* ExecEndNode - shut down a plan node and its subplans
+ * ExecCountSlotsNode - count tuple slots needed by plan tree
+ * ExecGetTupType - get result tuple type of a plan node
*
* NOTES
* This used to be three files. It is now all combined into
break;
default:
- elog(ERROR, "ExecInitNode: node %d unsupported", nodeTag(node));
+ elog(ERROR, "ExecInitNode: node type %d unsupported",
+ (int) nodeTag(node));
result = FALSE;
}
break;
default:
- elog(ERROR, "ExecProcNode: node %d unsupported", nodeTag(node));
+ elog(ERROR, "ExecProcNode: node type %d unsupported",
+ (int) nodeTag(node));
result = NULL;
}
return ExecCountSlotsAgg((Agg *) node);
default:
- elog(ERROR, "ExecCountSlotsNode: node not yet supported: %d",
- nodeTag(node));
+ elog(ERROR, "ExecCountSlotsNode: node type %d unsupported",
+ (int) nodeTag(node));
break;
}
return 0;
break;
default:
- elog(ERROR, "ExecEndNode: node %d unsupported", nodeTag(node));
+ elog(ERROR, "ExecEndNode: node type %d unsupported",
+ (int) nodeTag(node));
break;
}
}
+
+
+/* ----------------------------------------------------------------
+ * ExecGetTupType
+ *
+ * this gives you the tuple descriptor for tuples returned
+ * by this node. I really wish I could ditch this routine,
+ * but since not all nodes store their type info in the same
+ * place, we have to do something special for each node type.
+ *
+ * ----------------------------------------------------------------
+ */
+TupleDesc
+ExecGetTupType(Plan *node)
+{
+ TupleTableSlot *slot;
+
+ if (node == NULL)
+ return NULL;
+
+ switch (nodeTag(node))
+ {
+ case T_Result:
+ {
+ ResultState *resstate = ((Result *) node)->resstate;
+
+ slot = resstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_SeqScan:
+ {
+ CommonScanState *scanstate = ((SeqScan *) node)->scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_NestLoop:
+ {
+ NestLoopState *nlstate = ((NestLoop *) node)->nlstate;
+
+ slot = nlstate->jstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Append:
+ {
+ AppendState *appendstate = ((Append *) node)->appendstate;
+
+ slot = appendstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_IndexScan:
+ {
+ CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_TidScan:
+ {
+ CommonScanState *scanstate = ((TidScan *) node)->scan.scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_SubqueryScan:
+ {
+ CommonScanState *scanstate = ((SubqueryScan *) node)->scan.scanstate;
+
+ slot = scanstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Material:
+ {
+ MaterialState *matstate = ((Material *) node)->matstate;
+
+ slot = matstate->csstate.css_ScanTupleSlot;
+ }
+ break;
+
+ case T_Sort:
+ {
+ SortState *sortstate = ((Sort *) node)->sortstate;
+
+ slot = sortstate->csstate.css_ScanTupleSlot;
+ }
+ break;
+
+ case T_Agg:
+ {
+ AggState *aggstate = ((Agg *) node)->aggstate;
+
+ slot = aggstate->csstate.cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Group:
+ {
+ GroupState *grpstate = ((Group *) node)->grpstate;
+
+ slot = grpstate->csstate.cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Hash:
+ {
+ HashState *hashstate = ((Hash *) node)->hashstate;
+
+ slot = hashstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Unique:
+ {
+ UniqueState *uniquestate = ((Unique *) node)->uniquestate;
+
+ slot = uniquestate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_SetOp:
+ {
+ SetOpState *setopstate = ((SetOp *) node)->setopstate;
+
+ slot = setopstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_Limit:
+ {
+ LimitState *limitstate = ((Limit *) node)->limitstate;
+
+ slot = limitstate->cstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_MergeJoin:
+ {
+ MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
+
+ slot = mergestate->jstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ case T_HashJoin:
+ {
+ HashJoinState *hashjoinstate = ((HashJoin *) node)->hashjoinstate;
+
+ slot = hashjoinstate->jstate.cs_ResultTupleSlot;
+ }
+ break;
+
+ default:
+ /* ----------------
+ * should never get here
+ * ----------------
+ */
+ elog(ERROR, "ExecGetTupType: node type %d unsupported",
+ (int) nodeTag(node));
+ return NULL;
+ }
+
+ return slot->ttc_tupleDescriptor;
+}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.82 2001/01/24 19:42:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.83 2001/01/29 00:39:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* If the attribute number is invalid, then we are supposed to return
* the entire tuple, we give back a whole slot so that callers know
- * what the tuple looks like.
+ * what the tuple looks like. XXX why copy? Couldn't we just give
+ * back the existing slot?
*/
if (attnum == InvalidAttrNumber)
{
- TupleTableSlot *tempSlot;
+ TupleTableSlot *tempSlot = MakeTupleTableSlot();
TupleDesc td;
HeapTuple tup;
- tempSlot = makeNode(TupleTableSlot);
- tempSlot->ttc_shouldFree = false;
- tempSlot->ttc_descIsNew = true;
- tempSlot->ttc_tupleDescriptor = (TupleDesc) NULL;
- tempSlot->ttc_buffer = InvalidBuffer;
-
tup = heap_copytuple(heapTuple);
td = CreateTupleDescCopy(tuple_type);
- ExecSetSlotDescriptor(tempSlot, td);
-
+ ExecSetSlotDescriptor(tempSlot, td, true);
ExecStoreTuple(tup, tempSlot, InvalidBuffer, true);
return PointerGetDatum(tempSlot);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.45 2001/01/24 19:42:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.46 2001/01/29 00:39:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*
* TABLE CREATE/DELETE
* ExecCreateTupleTable - create a new tuple table
- * ExecDropTupleTable - destroy a table
+ * ExecDropTupleTable - destroy a table
*
- * SLOT RESERVERATION
+ * SLOT RESERVATION
* ExecAllocTableSlot - find an available slot in the table
*
* SLOT ACCESSORS
* ExecStoreTuple - store a tuple in the table
* ExecFetchTuple - fetch a tuple from the table
* ExecClearTuple - clear contents of a table slot
- * ExecSlotPolicy - return slot's tuple pfree policy
- * ExecSetSlotPolicy - diddle the slot policy
- * ExecSlotDescriptor - type of tuple in a slot
* ExecSetSlotDescriptor - set a slot's tuple descriptor
* ExecSetSlotDescriptorIsNew - diddle the slot-desc-is-new flag
- * ExecSetNewSlotDescriptor - set a desc and the is-new-flag all at once
*
* SLOT STATUS PREDICATES
* TupIsNull - true when slot contains no tuple(Macro)
- * ExecSlotDescriptorIsNew - true if we're now storing a different
- * type of tuple in a slot
*
* CONVENIENCE INITIALIZATION ROUTINES
* ExecInitResultTupleSlot \ convenience routines to initialize
* ExecInitExtraTupleSlot / which store copies of tuples.
* ExecInitNullTupleSlot /
*
- * old routines:
- * ExecGetTupType - get type of tuple returned by this node
+ * Routines that probably belong somewhere else:
* ExecTypeFromTL - form a TupleDesc from a target list
*
* EXAMPLE OF HOW TABLE ROUTINES WORK
* and the TupleTableSlot node in execnodes.h.
*
*/
-
#include "postgres.h"
-#include "executor/executor.h"
-
-#undef ExecStoreTuple
-#include "catalog/pg_type.h"
#include "access/heapam.h"
-
-static TupleTableSlot *NodeGetResultTupleSlot(Plan *node);
+#include "catalog/pg_type.h"
+#include "executor/executor.h"
/* ----------------------------------------------------------------
* 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!)
- *
- * Note: we do nothing about the Tuple Descriptor's
- * we store in the slots. This may have to change (ex: we should
- * probably worry about pfreeing tuple descs too) -cim 3/14/91
- *
- * Right now, the handling of tuple pointers and buffer refcounts
- * is clean, but the handling of tuple descriptors is NOT; they
- * are copied around with wild abandon. It would take some work
- * to make tuple descs pfree'able. Fortunately, since they're
- * normally only made once per scan, it's probably not worth
- * worrying about... tgl 9/21/99
* ----------------
*/
if (shouldFree)
{
for (i = 0; i < next; i++)
+ {
ExecClearTuple(&array[i]);
+ if (array[i].ttc_shouldFreeDesc &&
+ array[i].ttc_tupleDescriptor != NULL)
+ FreeTupleDesc(array[i].ttc_tupleDescriptor);
+ }
}
/* ----------------
slot->val = (HeapTuple) NULL;
slot->ttc_shouldFree = true;
slot->ttc_descIsNew = true;
+ slot->ttc_shouldFreeDesc = true;
+ slot->ttc_tupleDescriptor = (TupleDesc) NULL;
+ slot->ttc_buffer = InvalidBuffer;
+
+ return slot;
+}
+
+/* --------------------------------
+ * MakeTupleTableSlot
+ *
+ * This routine makes an empty standalone TupleTableSlot.
+ * It really shouldn't exist, but there are a few places
+ * that do this, so we may as well centralize the knowledge
+ * of what's in one ...
+ * --------------------------------
+ */
+TupleTableSlot *
+MakeTupleTableSlot(void)
+{
+ TupleTableSlot *slot = makeNode(TupleTableSlot);
+
+ /* This should match ExecAllocTableSlot() */
+ slot->val = (HeapTuple) NULL;
+ slot->ttc_shouldFree = true;
+ slot->ttc_descIsNew = true;
+ slot->ttc_shouldFreeDesc = true;
slot->ttc_tupleDescriptor = (TupleDesc) NULL;
slot->ttc_buffer = InvalidBuffer;
* ExecClearTuple
*
* This function is used to clear out a slot in the tuple table.
+ *
+ * NB: only the tuple is cleared, not the tuple descriptor (if any).
* --------------------------------
*/
TupleTableSlot * /* return: slot passed */
return slot;
}
-
-/* --------------------------------
- * ExecSlotPolicy
- *
- * This function is used to get the call/don't call pfree
- * setting of a slot. Most executor routines don't need this.
- * It's only when you do tricky things like marking tuples for
- * merge joins that you need to diddle the slot policy.
- * --------------------------------
- */
-#ifdef NOT_USED
-bool /* return: slot policy */
-ExecSlotPolicy(TupleTableSlot *slot) /* slot to inspect */
-{
- return slot->ttc_shouldFree;
-}
-
-
-/* --------------------------------
- * ExecSetSlotPolicy
- *
- * This function is used to change the call/don't call pfree
- * setting of a slot. Most executor routines don't need this.
- * It's only when you do tricky things like marking tuples for
- * merge joins that you need to diddle the slot policy.
- * --------------------------------
- */
-bool /* return: old slot policy */
-ExecSetSlotPolicy(TupleTableSlot *slot, /* slot to change */
- bool shouldFree) /* true if we call pfree() when we
- * gc. */
-{
- bool old_shouldFree = slot->ttc_shouldFree;
-
- slot->ttc_shouldFree = shouldFree;
-
- return old_shouldFree;
-}
-
-#endif
-
-/* --------------------------------
- * ExecSlotDescriptor
- *
- * This function is used to get the tuple descriptor associated
- * with the slot's tuple.
- *
- * Now a macro in tuptable.h -mer 5 March 1992
- * --------------------------------
- */
-
/* --------------------------------
* ExecSetSlotDescriptor
*
* with the slot's tuple.
* --------------------------------
*/
-TupleDesc /* return: old slot tuple descriptor */
+void
ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
- TupleDesc tupdesc) /* tuple descriptor */
+ TupleDesc tupdesc, /* new tuple descriptor */
+ bool shouldFree) /* is desc owned by slot? */
{
- TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
+ if (slot->ttc_shouldFreeDesc &&
+ slot->ttc_tupleDescriptor != NULL)
+ FreeTupleDesc(slot->ttc_tupleDescriptor);
slot->ttc_tupleDescriptor = tupdesc;
- return old_tupdesc;
+ slot->ttc_shouldFreeDesc = shouldFree;
}
/* --------------------------------
slot->ttc_descIsNew = isNew;
}
-/* --------------------------------
- * ExecSetNewSlotDescriptor
- *
- * This function is used to set the tuple descriptor associated
- * with the slot's tuple, and set the "isNew" flag at the same time.
- * --------------------------------
- */
-#ifdef NOT_USED
-TupleDesc /* return: old slot tuple descriptor */
-ExecSetNewSlotDescriptor(TupleTableSlot *slot, /* slot to change */
- TupleDesc tupdesc) /* tuple descriptor */
-{
- TupleDesc old_tupdesc = slot->ttc_tupleDescriptor;
-
- slot->ttc_tupleDescriptor = tupdesc;
- slot->ttc_descIsNew = true;
-
- return old_tupdesc;
-}
-
-#endif
-
/* ----------------------------------------------------------------
* tuple table slot status predicates
* ----------------------------------------------------------------
*/
-/* --------------------------------
- * ExecSlotDescriptorIsNew
- *
- * This function is used to check if the tuple descriptor
- * associated with this slot has just changed. ie: we are
- * now storing a new type of tuple in this slot
- * --------------------------------
- */
-#ifdef NOT_USED
-bool /* return: descriptor "is new" */
-ExecSlotDescriptorIsNew(TupleTableSlot *slot) /* slot to inspect */
-{
-/* bool isNew = SlotTupleDescriptorIsNew((TupleTableSlot*) slot);
- return isNew; */
- return slot->ttc_descIsNew;
-}
-
-#endif
-
/* ----------------------------------------------------------------
* convenience initialization routines
* ----------------------------------------------------------------
static struct tupleDesc NullTupleDesc; /* we assume this inits to
* zeroes */
- ExecSetSlotDescriptor(slot, tupType);
+ ExecSetSlotDescriptor(slot, tupType, false);
nullTuple = heap_formtuple(&NullTupleDesc, values, nulls);
return ExecStoreTuple(nullTuple, slot, InvalidBuffer, true);
}
-
-static TupleTableSlot *
-NodeGetResultTupleSlot(Plan *node)
-{
- TupleTableSlot *slot;
-
- switch (nodeTag(node))
- {
-
- case T_Result:
- {
- ResultState *resstate = ((Result *) node)->resstate;
-
- slot = resstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_SeqScan:
- {
- CommonScanState *scanstate = ((SeqScan *) node)->scanstate;
-
- slot = scanstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_NestLoop:
- {
- NestLoopState *nlstate = ((NestLoop *) node)->nlstate;
-
- slot = nlstate->jstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Append:
- {
- AppendState *appendstate = ((Append *) node)->appendstate;
-
- slot = appendstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_IndexScan:
- {
- CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
-
- slot = scanstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_TidScan:
- {
- CommonScanState *scanstate = ((TidScan *) node)->scan.scanstate;
-
- slot = scanstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_SubqueryScan:
- {
- CommonScanState *scanstate = ((SubqueryScan *) node)->scan.scanstate;
-
- slot = scanstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Material:
- {
- MaterialState *matstate = ((Material *) node)->matstate;
-
- slot = matstate->csstate.css_ScanTupleSlot;
- }
- break;
-
- case T_Sort:
- {
- SortState *sortstate = ((Sort *) node)->sortstate;
-
- slot = sortstate->csstate.css_ScanTupleSlot;
- }
- break;
-
- case T_Agg:
- {
- AggState *aggstate = ((Agg *) node)->aggstate;
-
- slot = aggstate->csstate.cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Group:
- {
- GroupState *grpstate = ((Group *) node)->grpstate;
-
- slot = grpstate->csstate.cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Hash:
- {
- HashState *hashstate = ((Hash *) node)->hashstate;
-
- slot = hashstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Unique:
- {
- UniqueState *uniquestate = ((Unique *) node)->uniquestate;
-
- slot = uniquestate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_SetOp:
- {
- SetOpState *setopstate = ((SetOp *) node)->setopstate;
-
- slot = setopstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_Limit:
- {
- LimitState *limitstate = ((Limit *) node)->limitstate;
-
- slot = limitstate->cstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_MergeJoin:
- {
- MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
-
- slot = mergestate->jstate.cs_ResultTupleSlot;
- }
- break;
-
- case T_HashJoin:
- {
- HashJoinState *hashjoinstate = ((HashJoin *) node)->hashjoinstate;
-
- slot = hashjoinstate->jstate.cs_ResultTupleSlot;
- }
- break;
-
- default:
- /* ----------------
- * should never get here
- * ----------------
- */
- elog(ERROR, "NodeGetResultTupleSlot: node not yet supported: %d",
- (int) nodeTag(node));
-
- return NULL;
- }
- return slot;
-}
-
-/* ----------------------------------------------------------------
- * ExecGetTupType
- *
- * this gives you the tuple descriptor for tuples returned
- * by this node. I really wish I could ditch this routine,
- * but since not all nodes store their type info in the same
- * place, we have to do something special for each node type.
- *
- * Soon, the system will have to adapt to deal with changing
- * tuple descriptors as we deal with dynamic tuple types
- * being returned from procedure nodes. Perhaps then this
- * routine can be retired. -cim 6/3/91
- *
- * old comments
- * This routine just gets the type information out of the
- * node's state. If you already have a node's state, you
- * can get this information directly, but this is a useful
- * routine if you want to get the type information from
- * the node's inner or outer subplan easily without having
- * to inspect the subplan.. -cim 10/16/89
- *
- * ----------------------------------------------------------------
- */
-
-TupleDesc
-ExecGetTupType(Plan *node)
-{
- TupleTableSlot *slot;
- TupleDesc tupType;
-
- if (node == NULL)
- return NULL;
-
- slot = NodeGetResultTupleSlot(node);
- tupType = slot->ttc_tupleDescriptor;
- return tupType;
-}
-
-#ifdef NOT_USED
-TupleDesc
-ExecCopyTupType(TupleDesc td, int natts)
-{
- TupleDesc newTd;
- int i;
-
- newTd = CreateTemplateTupleDesc(natts);
- i = 0;
- while (i < natts)
- {
- newTd[i] = (Form_pg_attribute)palloc(sizeof(FormData_pg_attribute));
- memmove(newTd[i], td[i], sizeof(FormData_pg_attribute));
- i++;
- }
- return newTd;
-}
-#endif
-
/* ----------------------------------------------------------------
* ExecTypeFromTL
*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.72 2001/01/24 19:42:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.73 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* INTERFACE ROUTINES
* ExecAssignExprContext Common code for plan node init routines.
*
- * ExecGetTypeInfo | old execCStructs interface
- * ExecMakeTypeInfo | code from the version 1
- * ExecOrderTypeInfo | lisp system. These should
- * ExecSetTypeInfo | go away or be updated soon.
- * ExecFreeTypeInfo | -cim 11/1/89
- * ExecTupleAttributes /
- *
-
- * QueryDescGetTypeInfo - moved here from main.c
- * am not sure what uses it -cim 10/12/89
- *
* ExecOpenIndices \
* ExecCloseIndices | referenced by InitPlan, EndPlan,
* ExecInsertIndexTuples / ExecAppend, ExecReplace
*/
void
ExecAssignResultType(CommonState *commonstate,
- TupleDesc tupDesc)
+ TupleDesc tupDesc, bool shouldFree)
{
- TupleTableSlot *slot;
+ TupleTableSlot *slot = commonstate->cs_ResultTupleSlot;
- slot = commonstate->cs_ResultTupleSlot;
- slot->ttc_tupleDescriptor = tupDesc;
+ ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
}
/* ----------------
outerPlan = outerPlan(node);
tupDesc = ExecGetTupType(outerPlan);
- ExecAssignResultType(commonstate, tupDesc);
+ ExecAssignResultType(commonstate, tupDesc, false);
}
/* ----------------
void
ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate)
{
- List *targetList;
TupleDesc tupDesc;
- targetList = node->targetlist;
- tupDesc = ExecTypeFromTL(targetList);
- ExecAssignResultType(commonstate, tupDesc);
+ tupDesc = ExecTypeFromTL(node->targetlist);
+ ExecAssignResultType(commonstate, tupDesc, true);
}
/* ----------------
return slot->ttc_tupleDescriptor;
}
-/* ----------------
- * ExecFreeResultType
- * ----------------
- */
-#ifdef NOT_USED
-void
-ExecFreeResultType(CommonState *commonstate)
-{
- TupleTableSlot *slot;
- TupleDesc tupType;
-
- slot = commonstate->cs_ResultTupleSlot;
- tupType = slot->ttc_tupleDescriptor;
-
- ExecFreeTypeInfo(tupType);
-}
-
-#endif
-
/* ----------------
* ExecAssignProjectionInfo
forms the projection information from the node's targetlist
commonstate->cs_ExprContext = NULL;
}
-/* ----------------
- * ExecFreeTypeInfo
- * ----------------
- */
-#ifdef NOT_USED
-void
-ExecFreeTypeInfo(CommonState *commonstate)
-{
- TupleDesc tupDesc;
-
- tupDesc = commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor;
- if (tupDesc == NULL)
- return;
-
- /* ----------------
- * clean up memory used.
- * ----------------
- */
- FreeTupleDesc(tupDesc);
- commonstate->cs_ResultTupleSlot->ttc_tupleDescriptor = NULL;
-}
-#endif
-
/* ----------------------------------------------------------------
* the following scan type support functions are for
* those nodes which are stubborn and return tuples in
return slot->ttc_tupleDescriptor;
}
-/* ----------------
- * ExecFreeScanType
- * ----------------
- */
-#ifdef NOT_USED
-void
-ExecFreeScanType(CommonScanState *csstate)
-{
- TupleTableSlot *slot;
- TupleDesc tupType;
-
- slot = csstate->css_ScanTupleSlot;
- tupType = slot->ttc_tupleDescriptor;
-
- ExecFreeTypeInfo(tupType);
-}
-
-#endif
-
/* ----------------
* ExecAssignScanType
* ----------------
*/
void
ExecAssignScanType(CommonScanState *csstate,
- TupleDesc tupDesc)
+ TupleDesc tupDesc, bool shouldFree)
{
- TupleTableSlot *slot;
+ TupleTableSlot *slot = csstate->css_ScanTupleSlot;
- slot = (TupleTableSlot *) csstate->css_ScanTupleSlot;
- slot->ttc_tupleDescriptor = tupDesc;
+ ExecSetSlotDescriptor(slot, tupDesc, shouldFree);
}
/* ----------------
outerPlan = outerPlan(node);
tupDesc = ExecGetTupType(outerPlan);
- ExecAssignScanType(csstate, tupDesc);
+ ExecAssignScanType(csstate, tupDesc, false);
}
-/* ----------------------------------------------------------------
- * ExecTypeFromTL support routines.
- *
- * these routines are used mainly from ExecTypeFromTL.
- * -cim 6/12/90
- *
- * old comments
- * Routines dealing with the structure 'attribute' which conatains
- * the type information about attributes in a tuple:
- *
- * ExecMakeTypeInfo(noType)
- * returns pointer to array of 'noType' structure 'attribute'.
- * ExecSetTypeInfo(index, typeInfo, attNum, attLen)
- * sets the element indexed by 'index' in typeInfo with
- * the values: attNum, attLen.
- * ExecFreeTypeInfo(typeInfo)
- * frees the structure 'typeInfo'.
- * ----------------------------------------------------------------
- */
-
-/* ----------------
- * ExecSetTypeInfo
- *
- * This initializes fields of a single attribute in a
- * tuple descriptor from the specified parameters.
- *
- * XXX this duplicates much of the functionality of TupleDescInitEntry.
- * the routines should be moved to the same place and be rewritten
- * to share common code.
- * ----------------
- */
-#ifdef NOT_USED
-void
-ExecSetTypeInfo(int index,
- TupleDesc typeInfo,
- Oid typeID,
- int attNum,
- int attLen,
- char *attName,
- bool attbyVal,
- char attalign)
-{
- Form_pg_attribute att;
-
- /* ----------------
- * get attribute pointer and preform a sanity check..
- * ----------------
- */
- att = typeInfo[index];
- if (att == NULL)
- elog(ERROR, "ExecSetTypeInfo: trying to assign through NULL");
-
- /* ----------------
- * assign values to the tuple descriptor, being careful not
- * to copy a null attName..
- *
- * XXX it is unknown exactly what information is needed to
- * initialize the attribute struct correctly so for now
- * we use 0. this should be fixed -- otherwise we run the
- * risk of using garbage data. -cim 5/5/91
- * ----------------
- */
- att->attrelid = 0; /* dummy value */
-
- if (attName != (char *) NULL)
- StrNCpy(NameStr(att->attname), attName, NAMEDATALEN);
- else
- MemSet(NameStr(att->attname), 0, NAMEDATALEN);
-
- att->atttypid = typeID;
- att->attdefrel = 0; /* dummy value */
- att->attdispersion = 0; /* dummy value */
- att->atttyparg = 0; /* dummy value */
- att->attlen = attLen;
- att->attnum = attNum;
- att->attbound = 0; /* dummy value */
- att->attbyval = attbyVal;
- att->attcanindex = 0; /* dummy value */
- att->attproc = 0; /* dummy value */
- att->attnelems = 0; /* dummy value */
- att->attcacheoff = -1;
- att->atttypmod = -1;
- att->attisset = false;
- att->attstorage = 'p';
- att->attalign = attalign;
-}
-
-/* ----------------
- * ExecFreeTypeInfo frees the array of attributes
- * created by ExecMakeTypeInfo and returned by ExecTypeFromTL
- * ----------------
- */
-void
-ExecFreeTypeInfo(TupleDesc typeInfo)
-{
- /* ----------------
- * do nothing if asked to free a null pointer
- * ----------------
- */
- if (typeInfo == NULL)
- return;
-
- /* ----------------
- * the entire array of typeinfo pointers created by
- * ExecMakeTypeInfo was allocated with a single palloc()
- * so we can deallocate the whole array with a single pfree().
- * (we should not try and free all the elements in the array)
- * -cim 6/12/90
- * ----------------
- */
- pfree(typeInfo);
-}
-
-
-/* ----------------------------------------------------------------
- * QueryDescGetTypeInfo
- *
- *| I don't know how this is used, all I know is that it
- *| appeared one day in main.c so I moved it here. -cim 11/1/89
- * ----------------------------------------------------------------
- */
-TupleDesc
-QueryDescGetTypeInfo(QueryDesc *queryDesc)
-{
- Plan *plan;
- TupleDesc tupleType;
- List *targetList;
- AttrInfo *attinfo = (AttrInfo *) palloc(sizeof(AttrInfo));
-
- plan = queryDesc->plantree;
- tupleType = (TupleDesc) ExecGetTupType(plan);
-/*
- targetList = plan->targetlist;
-
- attinfo->numAttr = ExecTargetListLength(targetList);
- attinfo->attrs = tupleType;
-*/
- attinfo->numAttr = tupleType->natts;
- attinfo->attrs = tupleType->attrs;
- return attinfo;
-}
-
-#endif
-
/* ----------------------------------------------------------------
* ExecInsertIndexTuples support
* ----------------------------------------------------------------
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.42 2001/01/24 19:42:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.43 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
-#include "utils/datum.h"
#include "utils/syscache.h"
static execution_state *init_execution_state(char *src,
Oid *argOidVect, int nargs);
static void init_sql_fcache(FmgrInfo *finfo);
-static TupleDesc postquel_start(execution_state *es);
+static void postquel_start(execution_state *es);
static TupleTableSlot *postquel_getnext(execution_state *es);
static void postquel_end(execution_state *es);
static void postquel_sub_params(execution_state *es, FunctionCallInfo fcinfo);
SQLFunctionCachePtr fcache);
-static Datum
-ProjectAttribute(HeapTuple tup,
- AttrNumber attrno,
- TupleDesc TD,
- bool *isnullP)
-{
- Datum val;
-
- val = heap_getattr(tup, attrno, TD, isnullP);
-
- if (*isnullP)
- return val;
-
- return datumCopy(val,
- TD->attrs[attrno - 1]->attbyval,
- TD->attrs[attrno - 1]->attlen);
-}
-
static execution_state *
init_execution_state(char *src, Oid *argOidVect, int nargs)
{
* allocated by the executor (i.e. slots and tuples) is freed.
*/
if (!finfo->fn_retset && !fcache->typbyval)
- {
- TupleTableSlot *slot;
-
- slot = makeNode(TupleTableSlot);
- slot->val = (HeapTuple) NULL;
- slot->ttc_shouldFree = true;
- slot->ttc_descIsNew = true;
- slot->ttc_tupleDescriptor = (TupleDesc) NULL;
- slot->ttc_buffer = InvalidBuffer;
-
- fcache->funcSlot = slot;
- }
+ fcache->funcSlot = MakeTupleTableSlot();
else
fcache->funcSlot = NULL;
}
-static TupleDesc
+static void
postquel_start(execution_state *es)
{
* 30-8-1996
*/
if (es->qd->operation == CMD_UTILITY)
- return (TupleDesc) NULL;
- return ExecutorStart(es->qd, es->estate);
+ return;
+ ExecutorStart(es->qd, es->estate);
}
static TupleTableSlot *
* If first time through, we have to initialize the funcSlot's
* tuple descriptor.
*/
- if (TupIsNull(funcSlot))
+ if (funcSlot->ttc_tupleDescriptor == NULL)
{
- resultTd = resultSlot->ttc_tupleDescriptor;
- funcSlot->ttc_tupleDescriptor = CreateTupleDescCopy(resultTd);
- funcSlot->ttc_descIsNew = true;
+ resultTd = CreateTupleDescCopy(resultSlot->ttc_tupleDescriptor);
+ ExecSetSlotDescriptor(funcSlot, resultTd, true);
+ ExecSetSlotDescriptorIsNew(funcSlot, true);
}
newTuple = heap_copytuple(resultTuple);
}
else
{
- value = ProjectAttribute(resSlot->val,
- 1,
- resSlot->ttc_tupleDescriptor,
- &fcinfo->isnull);
+ value = heap_getattr(resSlot->val,
+ 1,
+ resSlot->ttc_tupleDescriptor,
+ &(fcinfo->isnull));
+ /*
+ * Note: if result type is pass-by-reference then we are
+ * returning a pointer into the tuple copied by
+ * copy_function_result. This is OK.
+ */
}
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.35 2001/01/24 19:42:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeHashjoin.c,v 1.36 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
ExecAssignProjectionInfo((Plan *) node, &hjstate->jstate);
ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot,
- ExecGetTupType(outerNode));
+ ExecGetTupType(outerNode),
+ false);
/* ----------------
* initialize hash-specific info
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.56 2001/01/24 19:42:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeIndexscan.c,v 1.57 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
return slot; /* return empty slot */
- /* probably ought to use ExecStoreTuple here... */
- slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
- slot->ttc_shouldFree = false;
-
- econtext->ecxt_scantuple = slot;
+ ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
+ slot, InvalidBuffer, false);
/* Does the tuple meet any of the OR'd indxqual conditions? */
+ econtext->ecxt_scantuple = slot;
ResetExprContext(econtext);
* get the scan type from the relation descriptor.
* ----------------
*/
- ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
+ ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
/* ----------------
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.41 2001/01/24 19:42:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.42 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate);
ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot,
- ExecGetTupType(innerPlan((Plan *) node)));
+ ExecGetTupType(innerPlan((Plan *) node)),
+ false);
switch (node->join.jointype)
{
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.26 2001/01/24 19:42:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSeqscan.c,v 1.27 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (estate->es_evTupleNull[node->scanrelid - 1])
return slot; /* return empty slot */
- /* probably ought to use ExecStoreTuple here... */
- slot->val = estate->es_evTuple[node->scanrelid - 1];
- slot->ttc_shouldFree = false;
+ ExecStoreTuple(estate->es_evTuple[node->scanrelid - 1],
+ slot, InvalidBuffer, false);
/*
* Note that unlike IndexScan, SeqScan never use keys in
scanstate->css_currentRelation = currentRelation;
scanstate->css_currentScanDesc = currentScanDesc;
- ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
+ ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
return reloid;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.30 2001/01/24 19:42:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.31 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
break;
tuplesort_puttuple(tuplesortstate, (void *) slot->val);
- ExecClearTuple(slot);
}
/* ----------------
estate->es_direction = dir;
/* ----------------
- * make sure the tuple descriptor is up to date
+ * make sure the tuple descriptor is up to date (is this needed?)
* ----------------
*/
- slot = (TupleTableSlot *) sortstate->csstate.cstate.cs_ResultTupleSlot;
- slot->ttc_tupleDescriptor = tupDesc;
+ ExecAssignResultType(&sortstate->csstate.cstate, tupDesc, false);
/* ----------------
* finally set the sorted flag to true
sortstate->sort_Done = true;
SO1_printf(stderr, "ExecSort: sorting done.\n");
}
- else
- slot = (TupleTableSlot *) sortstate->csstate.cstate.cs_ResultTupleSlot;
SO1_printf("ExecSort: %s\n",
"retrieving tuple from tuplesort");
ScanDirectionIsForward(dir),
&should_free);
+ slot = sortstate->csstate.cstate.cs_ResultTupleSlot;
return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
}
tuplesort_end((Tuplesortstate *) sortstate->tuplesortstate);
sortstate->tuplesortstate = NULL;
+ if (sortstate->sort_Keys != NULL)
+ pfree(sortstate->sort_Keys);
+
+ pfree(sortstate);
+ node->sortstate = NULL;
+
SO1_printf("ExecEndSort: %s\n",
"sort node shutdown");
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.3 2001/01/24 19:42:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.4 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
return slot; /* return empty slot */
- /* probably ought to use ExecStoreTuple here... */
- slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
- slot->ttc_shouldFree = false;
+ ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
+ slot, InvalidBuffer, false);
/* Flag for the next call that no more tuples */
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.13 2001/01/24 19:42:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeTidscan.c,v 1.14 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
return slot; /* return empty slot */
- /* probably ought to use ExecStoreTuple here... */
- slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
- slot->ttc_shouldFree = false;
+ ExecStoreTuple(estate->es_evTuple[node->scan.scanrelid - 1],
+ slot, InvalidBuffer, false);
/* Flag for the next call that no more tuples */
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
* get the scan type from the relation descriptor.
* ----------------
*/
- ExecAssignScanType(scanstate, RelationGetDescr(currentRelation));
+ ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false);
ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate);
/*
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.12 2001/01/24 19:43:18 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplesort.c,v 1.13 2001/01/29 00:39:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
}
if (state->memtupindex)
pfree(state->memtupindex);
+ pfree(state);
}
/*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: executor.h,v 1.55 2001/01/24 19:43:23 momjian Exp $
+ * $Id: executor.h,v 1.56 2001/01/29 00:39:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* prototypes from functions in execJunk.c
*/
extern JunkFilter *ExecInitJunkFilter(List *targetList, TupleDesc tupType);
+extern void ExecFreeJunkFilter(JunkFilter *junkfilter);
extern bool ExecGetJunkAttribute(JunkFilter *junkfilter, TupleTableSlot *slot,
char *attrName, Datum *value, bool *isNull);
extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
extern TupleTableSlot *ExecProcNode(Plan *node, Plan *parent);
extern int ExecCountSlotsNode(Plan *node);
extern void ExecEndNode(Plan *node, Plan *parent);
+extern TupleDesc ExecGetTupType(Plan *node);
/*
* prototypes from functions in execQual.c
extern TupleTable ExecCreateTupleTable(int initialSize);
extern void ExecDropTupleTable(TupleTable table, bool shouldFree);
extern TupleTableSlot *ExecAllocTableSlot(TupleTable table);
+extern TupleTableSlot *MakeTupleTableSlot(void);
extern TupleTableSlot *ExecStoreTuple(HeapTuple tuple,
TupleTableSlot *slot,
Buffer buffer,
bool shouldFree);
extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot);
-extern TupleDesc ExecSetSlotDescriptor(TupleTableSlot *slot,
- TupleDesc tupdesc);
+extern void ExecSetSlotDescriptor(TupleTableSlot *slot,
+ TupleDesc tupdesc, bool shouldFree);
extern void ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, bool isNew);
extern void ExecInitResultTupleSlot(EState *estate, CommonState *commonstate);
extern void ExecInitScanTupleSlot(EState *estate,
extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
TupleDesc tupType);
-
-extern TupleDesc ExecGetTupType(Plan *node);
extern TupleDesc ExecTypeFromTL(List *targetList);
extern void SetChangedParamList(Plan *node, List *newchg);
extern void ResetTupleCount(void);
extern void ExecAssignExprContext(EState *estate, CommonState *commonstate);
extern void ExecAssignResultType(CommonState *commonstate,
- TupleDesc tupDesc);
+ TupleDesc tupDesc, bool shouldFree);
extern void ExecAssignResultTypeFromOuterPlan(Plan *node,
CommonState *commonstate);
extern void ExecAssignResultTypeFromTL(Plan *node, CommonState *commonstate);
extern void ExecFreeExprContext(CommonState *commonstate);
extern TupleDesc ExecGetScanType(CommonScanState *csstate);
extern void ExecAssignScanType(CommonScanState *csstate,
- TupleDesc tupDesc);
+ TupleDesc tupDesc, bool shouldFree);
extern void ExecAssignScanTypeFromOuterPlan(Plan *node,
CommonScanState *csstate);
extern Form_pg_attribute ExecGetTypeInfo(Relation relDesc);
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: tuptable.h,v 1.17 2001/01/24 19:43:23 momjian Exp $
+ * $Id: tuptable.h,v 1.18 2001/01/29 00:39:20 tgl Exp $
*
* NOTES
* The tuple table interface is getting pretty ugly.
/* ----------------
* The executor tuple table is managed and manipulated by special
- * code in executor/execTuples.c and tupTable.h
+ * code in executor/execTuples.c.
*
* TupleTableSlot information
*
- * shouldFree boolean - should we call pfree() on tuple
+ * val current tuple, or NULL if no tuple
+ * shouldFree boolean - should we pfree() tuple
* descIsNew boolean - true when tupleDescriptor changes
- * tupleDescriptor type information kept regarding the tuple data
+ * tupleDescriptor type information for the tuple data
+ * shouldFreeDesc boolean - should we free tupleDescriptor
* buffer the buffer for tuples pointing to disk pages
*
* The executor stores pointers to tuples in a ``tuple table''
- * which is composed of TupleTableSlot's. Some of the tuples
- * are pointers to buffer pages and others are pointers to
- * palloc'ed memory and the shouldFree variable tells us when
+ * which is composed of TupleTableSlots. Sometimes the tuples
+ * are pointers to buffer pages, while others are pointers to
+ * palloc'ed memory; the shouldFree variable tells us when
* we may call pfree() on a tuple. -cim 9/23/90
*
+ * If buffer is not InvalidBuffer, then the slot is holding a pin
+ * on the indicated buffer page; drop the pin when we release the
+ * slot's reference to that buffer.
+ *
* In the implementation of nested-dot queries such as
* "retrieve (EMP.hobbies.all)", a single scan may return tuples
* of many types, so now we return pointers to tuple descriptors
* along with tuples returned via the tuple table. -cim 1/18/90
*
- * Tuple table macros are all excised from the system now.
+ * shouldFreeDesc is similar to shouldFree: if it's true, then the
+ * tupleDescriptor is "owned" by the TupleTableSlot and should be
+ * freed when the slot's reference to the descriptor is dropped.
+ *
* See executor.h for decls of functions defined in execTuples.c
* -jolly
*
HeapTuple val;
bool ttc_shouldFree;
bool ttc_descIsNew;
+ bool ttc_shouldFreeDesc;
TupleDesc ttc_tupleDescriptor;
Buffer ttc_buffer;
} TupleTableSlot;
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: execnodes.h,v 1.55 2001/01/24 19:43:25 momjian Exp $
+ * $Id: execnodes.h,v 1.56 2001/01/29 00:39:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* (including the junk attributes).
* cleanTargetList: the "clean" target list (junk attributes removed).
* cleanLength: the length of 'cleanTargetList'
- * cleanTupTyp: the tuple descriptor of the "clean" tuple (with
+ * cleanTupType: the tuple descriptor of the "clean" tuple (with
* junk attributes removed).
- * cleanMap: A map with the correspondance between the non junk
+ * cleanMap: A map with the correspondance between the non-junk
* attributes of the "original" tuple and the
* attributes of the "clean" tuple.
+ * junkContext: memory context holding the JunkFilter node and all
+ * its subsidiary data structures.
+ *
+ * NOTE: the original targetList and tupType are passed to ExecInitJunkFilter
+ * and do not belong to the JunkFilter. All the other subsidiary structures
+ * are created during ExecInitJunkFilter, and all of them can be freed by
+ * deleting the memory context junkContext. This would not be needed if we
+ * had a cleaner approach to managing query-lifetime data structures...
* ----------------
*/
typedef struct JunkFilter
int jf_cleanLength;
TupleDesc jf_cleanTupType;
AttrNumber *jf_cleanMap;
+ MemoryContext jf_junkContext;
} JunkFilter;
/* ----------------