aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execTuples.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2001-01-29 00:39:20 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2001-01-29 00:39:20 +0000
commit0d54d6ac44444c05f7c0f5058d3d3f32cc188b48 (patch)
treecccee5d61e1afc1982c363ed3e4876a09ed82b52 /src/backend/executor/execTuples.c
parent51cd0377460839d25a5fc5f2a2499de43126a3b2 (diff)
downloadpostgresql-0d54d6ac44444c05f7c0f5058d3d3f32cc188b48.tar.gz
postgresql-0d54d6ac44444c05f7c0f5058d3d3f32cc188b48.zip
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.
Diffstat (limited to 'src/backend/executor/execTuples.c')
-rw-r--r--src/backend/executor/execTuples.c388
1 files changed, 47 insertions, 341 deletions
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c
index ecb8ae48b50..e5f1a269d81 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
*