Clean up handling of tuple descriptors so that result-tuple descriptors

allocated by plan nodes are not leaked at end of query.  This doesn't
really matter for normal queries, but it sure does for queries invoked
repetitively inside SQL functions.  Clean up some other grotty code
associated with tupdescs, and fix a few other memory leaks exposed by
tests with simple SQL functions.
This commit is contained in:
Tom Lane 2001-01-29 00:39:20 +00:00
parent 51cd037746
commit 0d54d6ac44
25 changed files with 423 additions and 748 deletions

View File

@ -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
{

View File

@ -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
{

View File

@ -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

View File

@ -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
{

View File

@ -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
{

View File

@ -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);

View File

@ -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)
{

View File

@ -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
{

View File

@ -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
*/

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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
*

View File

@ -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
* ----------------------------------------------------------------

View File

@ -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.
*/
}
/*

View File

@ -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

View File

@ -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);
/* ----------------

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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;

View File

@ -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);
/*

View File

@ -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);
}
/*

View File

@ -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);

View File

@ -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;

View File

@ -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;
/* ----------------