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