diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 969b3309f760f914395ef325941c1ad0ef84b0aa..c631f38503733fe260f98c1fe60873c058df8baf 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -6,7 +6,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -154,7 +154,7 @@ gistbuild(PG_FUNCTION_ARGS) { tupleTable = ExecCreateTupleTable(1); slot = ExecAllocTableSlot(tupleTable); - ExecSetSlotDescriptor(slot, htupdesc); + ExecSetSlotDescriptor(slot, htupdesc, false); } else { diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 1fcc54575de31cfedeb68185c45bb8d36448e3e3..2f4448e107e238fb468bf3eaaf0326df2002e63b 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -8,7 +8,7 @@ * * * 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. @@ -92,7 +92,7 @@ hashbuild(PG_FUNCTION_ARGS) { tupleTable = ExecCreateTupleTable(1); slot = ExecAllocTableSlot(tupleTable); - ExecSetSlotDescriptor(slot, htupdesc); + ExecSetSlotDescriptor(slot, htupdesc, false); } else { diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 8685975edf5752ac2376104d140013d5764f1a92..89720f8e2a1b8955927d4237252401f267d401c7 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -12,7 +12,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -128,7 +128,7 @@ btbuild(PG_FUNCTION_ARGS) { 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 diff --git a/src/backend/access/rtree/rtree.c b/src/backend/access/rtree/rtree.c index 17f03e390c98063e0babf7a2d3afba8c2568fdbd..9f3948657c9af06cf867c892edb8f968c1e7447e 100644 --- a/src/backend/access/rtree/rtree.c +++ b/src/backend/access/rtree/rtree.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -125,7 +125,7 @@ rtbuild(PG_FUNCTION_ARGS) { tupleTable = ExecCreateTupleTable(1); slot = ExecAllocTableSlot(tupleTable); - ExecSetSlotDescriptor(slot, htupdesc); + ExecSetSlotDescriptor(slot, htupdesc, false); } else { diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 9f1cf041495f9980e3e379d81ad1611956dfc97c..1c2d6324cfc24431bdb09ae5d7065208813600ba 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * 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 @@ -1817,7 +1817,7 @@ DefaultBuild(Relation heapRelation, { tupleTable = ExecCreateTupleTable(1); slot = ExecAllocTableSlot(tupleTable); - ExecSetSlotDescriptor(slot, heapDescriptor); + ExecSetSlotDescriptor(slot, heapDescriptor, false); } else { diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 618322645f3f7f4af3caffb70153b13054d5e5dd..30695a7a90bd4cace0ec01611233ef165baef987 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -8,7 +8,7 @@ * * * 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 @@ -1102,7 +1102,7 @@ AlterTableAddConstraint(char *relationName, bool successful = true; HeapScanDesc scan; ExprContext *econtext; - TupleTableSlot *slot = makeNode(TupleTableSlot); + TupleTableSlot *slot; HeapTuple tuple; RangeTblEntry *rte; List *qual; @@ -1169,28 +1169,28 @@ AlterTableAddConstraint(char *relationName, 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); diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index f992ac865b4a9aa3149c2895c4c0b08eb2f6f762..7d0352506ca8316a158db9a66323302e8832c9c8 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -638,7 +638,7 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, /* Set up a dummy tuple table too */ tupleTable = ExecCreateTupleTable(1); slot = ExecAllocTableSlot(tupleTable); - ExecSetSlotDescriptor(slot, tupDesc); + ExecSetSlotDescriptor(slot, tupDesc, false); if (!binary) { diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c index e9556900ca4f3ee78b47c29234343ba7b5066de5..f23ba27346219e09aab38e80a5f6760a29b49692 100644 --- a/src/backend/executor/execJunk.c +++ b/src/backend/executor/execJunk.c @@ -8,12 +8,10 @@ * * * 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" @@ -37,7 +35,7 @@ * 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. * @@ -63,6 +61,8 @@ JunkFilter * ExecInitJunkFilter(List *targetList, TupleDesc tupType) { + MemoryContext oldContext; + MemoryContext junkContext; JunkFilter *junkfilter; List *cleanTargetList; int len, @@ -75,9 +75,21 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType) 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' @@ -166,7 +178,7 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType) 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. @@ -177,8 +189,7 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType) */ if (cleanLength > 0) { - size = cleanLength * sizeof(AttrNumber); - cleanMap = (AttrNumber *) palloc(size); + cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber)); cleanResno = 1; foreach(t, targetList) { @@ -226,7 +237,7 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType) cleanMap = NULL; /* --------------------- - * Finally create and initialize the JunkFilter. + * Finally create and initialize the JunkFilter struct. * --------------------- */ junkfilter = makeNode(JunkFilter); @@ -238,20 +249,36 @@ ExecInitJunkFilter(List *targetList, TupleDesc tupType) 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 @@ -304,7 +331,7 @@ ExecGetJunkAttribute(JunkFilter *junkfilter, * --------------------- */ tuple = slot->val; - tupType = (TupleDesc) junkfilter->jf_tupType; + tupType = junkfilter->jf_tupType; *value = heap_getattr(tuple, resno, tupType, isNull); @@ -328,7 +355,6 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot) int cleanLength; bool isNull; int i; - Size size; Datum *values; char *nulls; Datum values_array[64]; @@ -340,8 +366,8 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot) */ 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; @@ -363,11 +389,8 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot) */ 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 { diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 77af5e7eccef33046361f1a04b5312561aa5e0b7..929134209ba4759d0d9a11a159528af347ecc0be 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -27,7 +27,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -252,12 +252,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count) /* ---------------------------------------------------------------- * 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 @@ -268,23 +264,15 @@ ExecutorEnd(QueryDesc *queryDesc, EState *estate) 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; @@ -870,7 +858,7 @@ EndPlan(Plan *plan, EState *estate) /* * 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--) @@ -878,6 +866,9 @@ EndPlan(Plan *plan, EState *estate) /* 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++; } @@ -887,6 +878,16 @@ EndPlan(Plan *plan, EState *estate) 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 */ diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 549f612d7eba9033eba61a07c885d0323d5d0183..bc1b6d0b2f78835e2cae382dea66a65fa51bb910 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -12,7 +12,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,8 @@ * 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 @@ -218,7 +220,8 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent) break; default: - elog(ERROR, "ExecInitNode: node %d unsupported", nodeTag(node)); + elog(ERROR, "ExecInitNode: node type %d unsupported", + (int) nodeTag(node)); result = FALSE; } @@ -347,7 +350,8 @@ ExecProcNode(Plan *node, Plan *parent) break; default: - elog(ERROR, "ExecProcNode: node %d unsupported", nodeTag(node)); + elog(ERROR, "ExecProcNode: node type %d unsupported", + (int) nodeTag(node)); result = NULL; } @@ -430,8 +434,8 @@ ExecCountSlotsNode(Plan *node) 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; @@ -558,7 +562,178 @@ ExecEndNode(Plan *node, Plan *parent) 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; +} diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index f0721f57bd52810229bdebd7fa3c2fda325c2ebd..bab2851df9d408d7b39c0f1656f1b2597572d6bc 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -328,25 +328,19 @@ ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull) /* * 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); } diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index ecb8ae48b5006f3a37242228fb4d94d2052dce2a..e5f1a269d817bb8bd091f31114fab638b66d28e2 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -15,7 +15,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -24,26 +24,20 @@ * * 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 @@ -51,8 +45,7 @@ * 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 @@ -112,16 +105,11 @@ * 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" /* ---------------------------------------------------------------- @@ -212,23 +200,17 @@ ExecDropTupleTable(TupleTable table, /* tuple table */ * 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); + } } /* ---------------- @@ -301,6 +283,32 @@ ExecAllocTableSlot(TupleTable table) 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; @@ -384,6 +392,8 @@ ExecStoreTuple(HeapTuple tuple, * 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 */ @@ -426,57 +436,6 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */ 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 * @@ -484,14 +443,17 @@ ExecSetSlotPolicy(TupleTableSlot *slot, /* slot to change */ * 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; } /* -------------------------------- @@ -507,52 +469,11 @@ ExecSetSlotDescriptorIsNew(TupleTableSlot *slot, /* slot to change */ 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 * ---------------------------------------------------------------- @@ -632,228 +553,13 @@ ExecInitNullTupleSlot(EState *estate, TupleDesc tupType) 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 * diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 703767cb715db59180d7da4e4786855264206d84..6b030b64a0e9a6a8be8008198bf899a9c4d33e5d 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -16,17 +16,6 @@ * 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 @@ -261,12 +250,11 @@ MakePerTupleExprContext(EState *estate) */ 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); } /* ---------------- @@ -282,7 +270,7 @@ ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate) outerPlan = outerPlan(node); tupDesc = ExecGetTupType(outerPlan); - ExecAssignResultType(commonstate, tupDesc); + ExecAssignResultType(commonstate, tupDesc, false); } /* ---------------- @@ -292,12 +280,10 @@ ExecAssignResultTypeFromOuterPlan(Plan *node, CommonState *commonstate) 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); } /* ---------------- @@ -312,25 +298,6 @@ ExecGetResultType(CommonState *commonstate) 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 @@ -413,29 +380,6 @@ ExecFreeExprContext(CommonState *commonstate) 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 @@ -458,37 +402,17 @@ ExecGetScanType(CommonScanState *csstate) 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); } /* ---------------- @@ -504,154 +428,10 @@ ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate) 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 * ---------------------------------------------------------------- diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 18a0e0cbb3b5159719a529a2acb21ccb28c05ce8..575f33d84b690c4c8bab63f5dd86be2cbcc88a37 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -24,7 +24,6 @@ #include "tcop/tcopprot.h" #include "tcop/utility.h" #include "utils/builtins.h" -#include "utils/datum.h" #include "utils/syscache.h" @@ -73,7 +72,7 @@ typedef SQLFunctionCache *SQLFunctionCachePtr; 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); @@ -82,24 +81,6 @@ static Datum postquel_execute(execution_state *es, 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) { @@ -240,18 +221,7 @@ init_sql_fcache(FmgrInfo *finfo) * 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; @@ -289,7 +259,7 @@ init_sql_fcache(FmgrInfo *finfo) } -static TupleDesc +static void postquel_start(execution_state *es) { @@ -298,8 +268,8 @@ 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 * @@ -379,11 +349,11 @@ copy_function_result(SQLFunctionCachePtr fcache, * 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); @@ -460,10 +430,15 @@ postquel_execute(execution_state *es, } 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. + */ } /* diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 0c6703fb70cd49c2a6876b83b0ae40f5025130d9..a3fc2f545cbde9df6d4a011eb0e593b7c548adb6 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -400,7 +400,8 @@ ExecInitHashJoin(HashJoin *node, EState *estate, Plan *parent) ExecAssignProjectionInfo((Plan *) node, &hjstate->jstate); ExecSetSlotDescriptor(hjstate->hj_OuterTupleSlot, - ExecGetTupType(outerNode)); + ExecGetTupType(outerNode), + false); /* ---------------- * initialize hash-specific info diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 7ed93de0848f5a3c57e4f46353efd9226239a15f..c0369e8f4cdfeaf117365ce1357dbc868cbe1c34 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -121,13 +121,11 @@ IndexNext(IndexScan *node) 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); @@ -1043,7 +1041,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, Plan *parent) * get the scan type from the relation descriptor. * ---------------- */ - ExecAssignScanType(scanstate, RelationGetDescr(currentRelation)); + ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false); ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate); /* ---------------- diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index 359d0c7bc5dae2951a25471c99311d38e75e9de2..fd8868a4a54a62203b170a32d28d46d44039dcbe 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -1505,7 +1505,8 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, Plan *parent) mergestate->mj_MarkedTupleSlot = ExecInitExtraTupleSlot(estate); ExecSetSlotDescriptor(mergestate->mj_MarkedTupleSlot, - ExecGetTupType(innerPlan((Plan *) node))); + ExecGetTupType(innerPlan((Plan *) node)), + false); switch (node->join.jointype) { diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index a10e8d4ed969ad61ad4b6fbe514f70482e22e10a..a39128ff2f073f5204a4d41982b65820d0a79b79 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -77,9 +77,8 @@ SeqNext(SeqScan *node) 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 @@ -181,7 +180,7 @@ InitScanRelation(SeqScan *node, EState *estate, scanstate->css_currentRelation = currentRelation; scanstate->css_currentScanDesc = currentScanDesc; - ExecAssignScanType(scanstate, RelationGetDescr(currentRelation)); + ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false); return reloid; } diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index 99bd3b7643790825b609ec63f65ef7d21136a2ca..b8c057c33977e3f9088bf146321d3f67bd276f05 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -172,7 +172,6 @@ ExecSort(Sort *node) break; tuplesort_puttuple(tuplesortstate, (void *) slot->val); - ExecClearTuple(slot); } /* ---------------- @@ -188,11 +187,10 @@ ExecSort(Sort *node) 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 @@ -201,8 +199,6 @@ ExecSort(Sort *node) 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"); @@ -216,6 +212,7 @@ ExecSort(Sort *node) ScanDirectionIsForward(dir), &should_free); + slot = sortstate->csstate.cstate.cs_ResultTupleSlot; return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free); } @@ -347,6 +344,12 @@ ExecEndSort(Sort *node) 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"); } diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index 617a41d447d71d41ca3be0cdac25645b2e3a43fe..4c9144bc3a82aebb631a2fe0be9df6a1f56f3222 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -12,7 +12,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -77,9 +77,8 @@ SubqueryNext(SubqueryScan *node) 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; diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index 49f7594c6f7186ec7cf693ffaec3335323f8579f..a5c0299d2896821d781c511b6653aefb1cde7dee 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -8,7 +8,7 @@ * * * 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 $ * *------------------------------------------------------------------------- */ @@ -110,9 +110,8 @@ TidNext(TidScan *node) 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; @@ -487,7 +486,7 @@ ExecInitTidScan(TidScan *node, EState *estate, Plan *parent) * get the scan type from the relation descriptor. * ---------------- */ - ExecAssignScanType(scanstate, RelationGetDescr(currentRelation)); + ExecAssignScanType(scanstate, RelationGetDescr(currentRelation), false); ExecAssignResultTypeFromTL((Plan *) node, &scanstate->cstate); /* diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index 7808f297649b52446172287cd58c2f2c23a8f41b..6dbcc701290fd3d0fbf4661074d30b543447904a 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -78,7 +78,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -546,6 +546,7 @@ tuplesort_end(Tuplesortstate *state) } if (state->memtupindex) pfree(state->memtupindex); + pfree(state); } /* diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 0282e7e7140dd79542fbbf67421671244afd46c9..091841a9c1c7969cf5b20b069ec1c40661d313cd 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -44,6 +44,7 @@ extern void ExecRestrPos(Plan *node); * 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); @@ -68,6 +69,7 @@ extern bool ExecInitNode(Plan *node, EState *estate, Plan *parent); 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 @@ -106,13 +108,14 @@ extern TupleTableSlot *ExecScan(Scan *node, ExecScanAccessMtd accessMtd); 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, @@ -120,8 +123,6 @@ 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); @@ -131,7 +132,7 @@ 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); @@ -141,7 +142,7 @@ extern void ExecFreeProjectionInfo(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); diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h index 47018666a78fe2b46a3b47874144a6d4178d837f..7def0be4b69c2079131514ec7ddbabe26f8a4793 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -7,7 +7,7 @@ * 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. @@ -22,27 +22,36 @@ /* ---------------- * 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 * @@ -54,6 +63,7 @@ typedef struct TupleTableSlot HeapTuple val; bool ttc_shouldFree; bool ttc_descIsNew; + bool ttc_shouldFreeDesc; TupleDesc ttc_tupleDescriptor; Buffer ttc_buffer; } TupleTableSlot; diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 5552210de81da9dee419c05a734bb17c0d256a3c..b9c10e6b310279d4f2bc7a52d52ca2832a60dfd8 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -164,11 +164,19 @@ typedef struct ProjectionInfo * (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 @@ -181,6 +189,7 @@ typedef struct JunkFilter int jf_cleanLength; TupleDesc jf_cleanTupType; AttrNumber *jf_cleanMap; + MemoryContext jf_junkContext; } JunkFilter; /* ----------------