diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index cd20e231ecbb1fdfc4af7ee897caa0404c3aece4..d6551cc9c9cdd2d26b10ab79e680e61e5024944c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.66 2000/06/08 22:36:54 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.67 2000/06/18 22:43:51 tgl Exp $
  *
  * NOTES
  *		Transaction aborts can now occur two ways:
@@ -878,14 +878,6 @@ StartTransaction()
 	AtStart_Locks();
 	AtStart_Memory();
 
-	/* --------------
-	   initialize temporary relations list
-	   the tempRelList is a list of temporary relations that
-	   are created in the course of the transactions
-	   they need to be destroyed properly at the end of the transactions
-	 */
-	InitNoNameRelList();
-
 	/* ----------------
 	 *	Tell the trigger manager to we're starting a transaction
 	 * ----------------
@@ -960,7 +952,6 @@ CommitTransaction()
 	AtCommit_Notify();
 
 	CloseSequences();
-	DropNoNameRels();
 	AtEOXact_portals();
 	RecordTransactionCommit();
 
@@ -1056,7 +1047,6 @@ AbortTransaction()
 		CommonSpecialPortalClose();
 	RecordTransactionAbort();
 	RelationPurgeLocalRelation(false);
-	DropNoNameRels();
 	invalidate_temp_relations();
 	AtEOXact_nbtree();
 	AtAbort_Cache();
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index d7a1d9de899e48eee21c07c1dccfecafd65a6b18..0a6f9d55ace6de2c998a3f030147501eb7113695 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.29 2000/01/26 05:56:07 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.30 2000/06/18 22:43:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -166,7 +166,7 @@ Boot_CreateStmt:
 							puts("creating bootstrap relation");
 						tupdesc = CreateTupleDesc(numattr,attrtypes);
 						reldesc = heap_create(LexIDStr($3), tupdesc,
-											  false, false, true);
+											  false, true);
 						if (DebugMode)
 							puts("bootstrap relation created ok");
 					}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 451eb7f7de2998f7bd2e213a630fd0ca9fff964e..7aeec8adb085c21c3a55a55def274c38b39d3a4a 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.132 2000/06/17 23:41:31 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.133 2000/06/18 22:43:55 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -70,14 +70,11 @@ static void AddNewRelationTuple(Relation pg_class_desc,
 					Relation new_rel_desc, Oid new_rel_oid,
 					int natts,
 					char relkind, char *temp_relname);
-static void AddToNoNameRelList(Relation r);
-
 static void DeleteAttributeTuples(Relation rel);
 static void DeleteRelationTuple(Relation rel);
 static void DeleteTypeTuple(Relation rel);
 static void RelationRemoveIndexes(Relation relation);
 static void RelationRemoveInheritance(Relation relation);
-static void RemoveFromNoNameRelList(Relation r);
 static void AddNewRelationType(char *typeName, Oid new_rel_oid);
 static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
 				 bool updatePgAttribute);
@@ -141,22 +138,6 @@ static Form_pg_attribute HeapAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6};
  * ----------------------------------------------------------------
  */
 
-/* the tempRelList holds
-   the list of temporary uncatalogued relations that are created.
-   these relations should be destroyed at the end of transactions
-*/
-typedef struct tempRelList
-{
-	Relation   *rels;			/* array of relation descriptors */
-	int			num;			/* number of temporary relations */
-	int			size;			/* size of space allocated for the rels
-								 * array */
-} TempRelList;
-
-#define NONAME_REL_LIST_SIZE	32
-
-static TempRelList *tempRels = NULL;
-
 
 /* ----------------------------------------------------------------
  *		heap_create		- Create an uncataloged heap relation
@@ -170,15 +151,16 @@ static TempRelList *tempRels = NULL;
  *		Eventually, must place information about this temporary relation
  *		into the transaction context block.
  *
+ * NOTE: if istemp is TRUE then heap_create will overwrite relname with
+ * the unique "real" name chosen for the temp relation.
  *
- * if heap_create is called with "" as the name, then heap_create will create
- * a temporary name "pg_noname.$PID.$SEQUENCE" for the relation
+ * If storage_create is TRUE then heap_storage_create is called here,
+ * else caller must call heap_storage_create later.
  * ----------------------------------------------------------------
  */
 Relation
 heap_create(char *relname,
 			TupleDesc tupDesc,
-			bool isnoname,
 			bool istemp,
 			bool storage_create)
 {
@@ -245,18 +227,11 @@ heap_create(char *relname,
 	else
 		relid = newoid();
 
-	if (isnoname)
-	{
-		Assert(!relname);
-		relname = palloc(NAMEDATALEN);
-		snprintf(relname, NAMEDATALEN, "pg_noname.%d.%u",
-				 (int) MyProcPid, uniqueId++);
-	}
-
 	if (istemp)
 	{
-		/* replace relname of caller */
-		snprintf(relname, NAMEDATALEN, "pg_temp.%d.%u", MyProcPid, uniqueId++);
+		/* replace relname of caller with a unique name for a temp relation */
+		snprintf(relname, NAMEDATALEN, "pg_temp.%d.%u",
+				 (int) MyProcPid, uniqueId++);
 	}
 
 	/* ----------------
@@ -268,7 +243,7 @@ heap_create(char *relname,
 	rel = (Relation) palloc(len);
 	MemSet((char *) rel, 0, len);
 	rel->rd_fd = -1;			/* table is not open */
-	rel->rd_unlinked = TRUE;	/* table is not created yet */
+	rel->rd_unlinked = true;	/* table is not created yet */
 
 	/*
 	 * create a new tuple descriptor from the one passed in
@@ -310,12 +285,6 @@ heap_create(char *relname,
 		rel->rd_rel->reltype = relid;
 	}
 
-	/* ----------------
-	 *	remember if this is a noname relation
-	 * ----------------
-	 */
-	rel->rd_isnoname = isnoname;
-
 	/* ----------------
 	 *	have the storage manager create the relation.
 	 * ----------------
@@ -329,13 +298,6 @@ heap_create(char *relname,
 
 	MemoryContextSwitchTo(oldcxt);
 
-	/*
-	 * add all noname relations to the tempRels list so they can be
-	 * properly disposed of at the end of transaction
-	 */
-	if (isnoname)
-		AddToNoNameRelList(rel);
-
 	return rel;
 }
 
@@ -347,7 +309,7 @@ heap_storage_create(Relation rel)
 	if (rel->rd_unlinked)
 	{
 		rel->rd_fd = (File) smgrcreate(DEFAULT_SMGR, rel);
-		rel->rd_unlinked = FALSE;
+		rel->rd_unlinked = false;
 		smgrcall = true;
 	}
 	return smgrcall;
@@ -810,7 +772,7 @@ heap_create_with_catalog(char *relname,
 	 *	get_temp_rel_by_username() couldn't check the simultaneous
 	 *	creation. Uniqueness will be really checked by unique
 	 *	indexes of system tables but we couldn't check it here.
-	 *	We have to pospone to create the disk file for this
+	 *	We have to postpone creating the disk file for this
 	 *	relation.
 	 *	Another boolean parameter "storage_create" was added
 	 *	to heap_create() function. If the parameter is false
@@ -821,12 +783,12 @@ heap_create_with_catalog(char *relname,
 	 *	relation descriptor.
 	 *
 	 *	Note: The call to heap_create() changes relname for
-	 *	noname and temp tables.
+	 *	temp tables; it becomes the true physical relname.
 	 *	The call to heap_storage_create() does all the "real"
 	 *	work of creating the disk file for the relation.
 	 * ----------------
 	 */
-	new_rel_desc = heap_create(relname, tupdesc, false, istemp, false);
+	new_rel_desc = heap_create(relname, tupdesc, istemp, false);
 
 	new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid;
 
@@ -1546,10 +1508,9 @@ heap_drop_with_catalog(const char *relname)
 	 *	unlink the relation's physical file and finish up.
 	 * ----------------
 	 */
-	if (!(rel->rd_isnoname) || !(rel->rd_unlinked))
+	if (! rel->rd_unlinked)
 		smgrunlink(DEFAULT_SMGR, rel);
-
-	rel->rd_unlinked = TRUE;
+	rel->rd_unlinked = true;
 
 	/*
 	 * Close relcache entry, but *keep* AccessExclusiveLock on the
@@ -1568,133 +1529,6 @@ heap_drop_with_catalog(const char *relname)
 		remove_temp_relation(rid);
 }
 
-/*
- * heap_drop
- *	  destroy and close temporary relations
- *
- */
-
-void
-heap_drop(Relation rel)
-{
-	Oid			rid = RelationGetRelid(rel);
-
-	ReleaseRelationBuffers(rel);
-	if (!(rel->rd_isnoname) || !(rel->rd_unlinked))
-		smgrunlink(DEFAULT_SMGR, rel);
-	rel->rd_unlinked = TRUE;
-	heap_close(rel, NoLock);
-	RemoveFromNoNameRelList(rel);
-	RelationForgetRelation(rid);
-}
-
-
-/**************************************************************
-  functions to deal with the list of temporary relations
-**************************************************************/
-
-/* --------------
-   InitTempRellist():
-
-   initialize temporary relations list
-   the tempRelList is a list of temporary relations that
-   are created in the course of the transactions
-   they need to be destroyed properly at the end of the transactions
-
-   MODIFIES the global variable tempRels
-
- >> NOTE <<
-
-   malloc is used instead of palloc because we KNOW when we are
-   going to free these things.	Keeps us away from the memory context
-   hairyness
-
-*/
-void
-InitNoNameRelList(void)
-{
-	if (tempRels)
-	{
-		free(tempRels->rels);
-		free(tempRels);
-	}
-
-	tempRels = (TempRelList *) malloc(sizeof(TempRelList));
-	tempRels->size = NONAME_REL_LIST_SIZE;
-	tempRels->rels = (Relation *) malloc(sizeof(Relation) * tempRels->size);
-	MemSet(tempRels->rels, 0, sizeof(Relation) * tempRels->size);
-	tempRels->num = 0;
-}
-
-/*
-   removes a relation from the TempRelList
-
-   MODIFIES the global variable tempRels
-	  we don't really remove it, just mark it as NULL
-	  and DropNoNameRels will look for NULLs
-*/
-static void
-RemoveFromNoNameRelList(Relation r)
-{
-	int			i;
-
-	if (!tempRels)
-		return;
-
-	for (i = 0; i < tempRels->num; i++)
-	{
-		if (tempRels->rels[i] == r)
-		{
-			tempRels->rels[i] = NULL;
-			break;
-		}
-	}
-}
-
-/*
-   add a temporary relation to the TempRelList
-
-   MODIFIES the global variable tempRels
-*/
-static void
-AddToNoNameRelList(Relation r)
-{
-	if (!tempRels)
-		return;
-
-	if (tempRels->num == tempRels->size)
-	{
-		tempRels->size += NONAME_REL_LIST_SIZE;
-		tempRels->rels = realloc(tempRels->rels,
-								 sizeof(Relation) * tempRels->size);
-	}
-	tempRels->rels[tempRels->num] = r;
-	tempRels->num++;
-}
-
-/*
-   go through the tempRels list and destroy each of the relations
-*/
-void
-DropNoNameRels(void)
-{
-	int			i;
-	Relation	rel;
-
-	if (!tempRels)
-		return;
-
-	for (i = 0; i < tempRels->num; i++)
-	{
-		rel = tempRels->rels[i];
-		/* rel may be NULL if it has been removed from the list already */
-		if (rel)
-			heap_drop(rel);
-	}
-	free(tempRels->rels);
-	free(tempRels);
-	tempRels = NULL;
-}
 
 /*
  * Store a default expression for column attnum of relation rel.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index b18ae9af64ace594ed25be9e09908ce1907d1c15..5b8e005c5f646bd3ec08d9d2de57158ec437249d 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.118 2000/06/17 23:41:34 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.119 2000/06/18 22:43:55 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -976,7 +976,6 @@ index_create(char *heapRelationName,
 
 	/* ----------------
 	 *	  get heap relation oid and open the heap relation
-	 *	  XXX ADD INDEXING
 	 * ----------------
 	 */
 	heapoid = GetHeapRelationOid(heapRelationName, indexRelationName, istemp);
@@ -1012,8 +1011,8 @@ index_create(char *heapRelationName,
 	 *	create the index relation
 	 * ----------------
 	 */
-	indexRelation = heap_create(indexRelationName,
-								indexTupDesc, false, istemp, false);
+	indexRelation = heap_create(indexRelationName, indexTupDesc,
+								istemp, false);
 
 	/* ----------------
 	 *	  construct the index relation descriptor
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index d51053c20a17724169acfccb5c07b1d0b0316ab8..25915fe42bd014e0c552763d3b4067b2b5d88947 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.56 2000/04/12 17:14:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.57 2000/06/18 22:43:58 tgl Exp $
  *
  */
 
@@ -176,9 +176,6 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
 		case T_IndexScan:
 			pname = "Index Scan";
 			break;
-		case T_Noname:
-			pname = "Noname Scan";
-			break;
 		case T_Material:
 			pname = "Materialize";
 			break;
diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c
index ed20aec5a8755cee4f3dad453b740ecf4d883a69..ff3fa0b6ed12d2f0d7a9d68a8412cfa3a687883f 100644
--- a/src/backend/executor/execAmi.c
+++ b/src/backend/executor/execAmi.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Id: execAmi.c,v 1.47 2000/06/15 04:09:50 momjian Exp $
+ *	$Id: execAmi.c,v 1.48 2000/06/18 22:44:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,13 +17,9 @@
  *		ExecBeginScan	 \							 /	ambeginscan
  *		ExecCloseR		  \							/	amclose
  *		ExecInsert		   \  executor interface   /	aminsert
- *		ExecReScanNode	   /  to access methods    \	amrescan
- *		ExecReScanR		  /							\	amrescan
- *		ExecMarkPos		 /							 \	ammarkpos
- *		ExecRestrPos	/							  \ amrestpos
- *
- *		ExecCreatR		function to create temporary relations
- *
+ *		ExecReScanR		   /  to access methods    \	amrescan
+ *		ExecMarkPos		  /							\	ammarkpos
+ *		ExecRestrPos	 /							 \  amrestpos
  */
 
 #include "postgres.h"
@@ -49,7 +45,6 @@
 #include "executor/nodeSort.h"
 #include "executor/nodeSubplan.h"
 #include "executor/nodeUnique.h"
-#include "optimizer/internal.h"
 
 static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
 			  bool isindex, ScanDirection dir, Snapshot snapshot);
@@ -170,7 +165,6 @@ ExecBeginScan(Relation relation,
 	if (scanDesc == NULL)
 		elog(DEBUG, "ExecBeginScan: scanDesc = NULL, heap_beginscan failed.");
 
-
 	return scanDesc;
 }
 
@@ -179,9 +173,6 @@ ExecBeginScan(Relation relation,
  *
  *		closes the relation and scan descriptor for a scan or sort
  *		node.  Also closes index relations and scans for index scans.
- *
- * old comments
- *		closes the relation indicated in 'relID'
  * ----------------------------------------------------------------
  */
 void
@@ -206,10 +197,6 @@ ExecCloseR(Plan *node)
 			state = ((IndexScan *) node)->scan.scanstate;
 			break;
 
-		case T_Material:
-			state = &(((Material *) node)->matstate->csstate);
-			break;
-
 		case T_Sort:
 			state = &(((Sort *) node)->sortstate->csstate);
 			break;
@@ -223,7 +210,7 @@ ExecCloseR(Plan *node)
 			break;
 
 		default:
-			elog(DEBUG, "ExecCloseR: not a scan, material, or sort node!");
+			elog(DEBUG, "ExecCloseR: not a scan or sort node!");
 			return;
 	}
 
@@ -423,7 +410,7 @@ ExecMarkPos(Plan *node)
 {
 	switch (nodeTag(node))
 	{
-			case T_SeqScan:
+		case T_SeqScan:
 			ExecSeqMarkPos((SeqScan *) node);
 			break;
 
@@ -431,6 +418,10 @@ ExecMarkPos(Plan *node)
 			ExecIndexMarkPos((IndexScan *) node);
 			break;
 
+		case T_Material:
+			ExecMaterialMarkPos((Material *) node);
+			break;
+
 		case T_Sort:
 			ExecSortMarkPos((Sort *) node);
 			break;
@@ -457,7 +448,7 @@ ExecRestrPos(Plan *node)
 {
 	switch (nodeTag(node))
 	{
-			case T_SeqScan:
+		case T_SeqScan:
 			ExecSeqRestrPos((SeqScan *) node);
 			return;
 
@@ -465,6 +456,10 @@ ExecRestrPos(Plan *node)
 			ExecIndexRestrPos((IndexScan *) node);
 			return;
 
+		case T_Material:
+			ExecMaterialRestrPos((Material *) node);
+			return;
+
 		case T_Sort:
 			ExecSortRestrPos((Sort *) node);
 			return;
@@ -474,65 +469,3 @@ ExecRestrPos(Plan *node)
 			return;
 	}
 }
-
-/* ----------------------------------------------------------------
- *		ExecCreatR
- *
- * old comments
- *		Creates a relation.
- *
- *		Parameters:
- *		  attrType	-- type information on the attributes.
- *		  accessMtd -- access methods used to access the created relation.
- *		  relation	-- optional. Either an index to the range table or
- *					   negative number indicating a temporary relation.
- *					   A temporary relation is assume if this field is absent.
- * ----------------------------------------------------------------
- */
-
-Relation
-ExecCreatR(TupleDesc tupType,
-		   Oid relationOid)
-{
-	Relation	relDesc;
-
-	EU3_printf("ExecCreatR: %s type=%d oid=%u\n",
-			   "entering: ", tupType, relationOid);
-	CXT1_printf("ExecCreatR: context is %d\n", CurrentMemoryContext);
-
-	relDesc = NULL;
-
-	if (relationOid == _NONAME_RELATION_ID_)
-	{
-		/* ----------------
-		 *	 create a temporary relation
-		 *	 (currently the planner always puts a _NONAME_RELATION_ID
-		 *	 in the relation argument so we expect this to be the case although
-		 *	 it's possible that someday we'll get the name from
-		 *	 from the range table.. -cim 10/12/89)
-		 * ----------------
-		 */
-
-		/*
-		 * heap_create creates a name if the argument to heap_create is
-		 * '\0 '
-		 */
-		relDesc = heap_create(NULL, tupType, true, false, true);
-	}
-	else
-	{
-		/* ----------------
-		 *		use a relation from the range table
-		 * ----------------
-		 */
-		elog(DEBUG, "ExecCreatR: %s",
-			 "stuff using range table id's is not functional");
-	}
-
-	if (relDesc == NULL)
-		elog(DEBUG, "ExecCreatR: failed to create relation.");
-
-	EU1_printf("ExecCreatR: returning relDesc=%d\n", relDesc);
-
-	return relDesc;
-}
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 4348f89ccc9746b4a8c0b845fa3c31d001c1fc8e..1d5c90424896ac32ff362b9be26056e584da207d 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -8,42 +8,37 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.30 2000/03/02 04:06:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeMaterial.c,v 1.31 2000/06/18 22:44:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * INTERFACE ROUTINES
- *		ExecMaterial			- generate a temporary relation
- *		ExecInitMaterial		- initialize node and subnodes..
+ *		ExecMaterial			- materialize the result of a subplan
+ *		ExecInitMaterial		- initialize node and subnodes
  *		ExecEndMaterial			- shutdown node and subnodes
  *
  */
 #include "postgres.h"
 
-
-#include "access/heapam.h"
-#include "catalog/heap.h"
 #include "executor/executor.h"
 #include "executor/nodeMaterial.h"
-#include "optimizer/internal.h"
+#include "miscadmin.h"
+#include "utils/tuplestore.h"
 
 /* ----------------------------------------------------------------
  *		ExecMaterial
  *
  *		The first time this is called, ExecMaterial retrieves tuples
- *		from this node's outer subplan and inserts them into a temporary
- *		relation.  After this is done, a flag is set indicating that
- *		the subplan has been materialized.	Once the relation is
- *		materialized, the first tuple is then returned.  Successive
- *		calls to ExecMaterial return successive tuples from the temp
- *		relation.
+ *		from this node's outer subplan and inserts them into a tuplestore
+ *		(a temporary tuple storage structure).  The first tuple is then
+ *		returned.  Successive calls to ExecMaterial return successive
+ *		tuples from the tuplestore.
  *
  *		Initial State:
  *
- *		ExecMaterial assumes the temporary relation has been
- *		created and opened by ExecInitMaterial during the prior
- *		InitPlan() phase.
+ *		matstate->tuplestorestate is initially NULL, indicating we
+ *		haven't yet collected the results of the subplan.
  *
  * ----------------------------------------------------------------
  */
@@ -52,13 +47,11 @@ ExecMaterial(Material *node)
 {
 	EState	   *estate;
 	MaterialState *matstate;
-	Plan	   *outerNode;
 	ScanDirection dir;
-	Relation	tempRelation;
-	Relation	currentRelation;
-	HeapScanDesc currentScanDesc;
+	Tuplestorestate *tuplestorestate;
 	HeapTuple	heapTuple;
 	TupleTableSlot *slot;
+	bool		should_free;
 
 	/* ----------------
 	 *	get state info from node
@@ -67,42 +60,42 @@ ExecMaterial(Material *node)
 	matstate = node->matstate;
 	estate = node->plan.state;
 	dir = estate->es_direction;
+	tuplestorestate = (Tuplestorestate *) matstate->tuplestorestate;
 
 	/* ----------------
-	 *	the first time we call this, we retrieve all tuples
-	 *	from the subplan into a temporary relation and then
-	 *	we sort the relation.  Subsequent calls return tuples
-	 *	from the temporary relation.
+	 *	If first time through, read all tuples from outer plan and
+	 *	pass them to tuplestore.c.
+	 *	Subsequent calls just fetch tuples from tuplestore.
 	 * ----------------
 	 */
 
-	if (matstate->mat_Flag == false)
+	if (tuplestorestate == NULL)
 	{
+		Plan	   *outerNode;
+
 		/* ----------------
-		 *	set all relations to be scanned in the forward direction
-		 *	while creating the temporary relation.
+		 *	Want to scan subplan in the forward direction while creating
+		 *	the stored data.  (Does setting my direction actually affect
+		 *	the subplan?  I bet this is useless code...)
 		 * ----------------
 		 */
 		estate->es_direction = ForwardScanDirection;
 
 		/* ----------------
-		 *	 if we couldn't create the temp relation then
-		 *	 we print a warning and return NULL.
+		 *	 Initialize tuplestore module.
 		 * ----------------
 		 */
-		tempRelation = matstate->mat_TempRelation;
-		if (tempRelation == NULL)
-		{
-			elog(DEBUG, "ExecMaterial: temp relation is NULL! aborting...");
-			return NULL;
-		}
+		tuplestorestate = tuplestore_begin_heap(true, /* randomAccess */
+												SortMem);
+
+		matstate->tuplestorestate = (void *) tuplestorestate;
 
 		/* ----------------
-		 *	 retrieve tuples from the subplan and
-		 *	 insert them in the temporary relation
+		 *	 Scan the subplan and feed all the tuples to tuplestore.
 		 * ----------------
 		 */
 		outerNode = outerPlan((Plan *) node);
+
 		for (;;)
 		{
 			slot = ExecProcNode(outerNode, (Plan *) node);
@@ -110,63 +103,34 @@ ExecMaterial(Material *node)
 			if (TupIsNull(slot))
 				break;
 
-			heap_insert(tempRelation, slot->val);
-
+			tuplestore_puttuple(tuplestorestate, (void *) slot->val);
 			ExecClearTuple(slot);
 		}
 
 		/* ----------------
-		 *	 restore to user specified direction
+		 *	 Complete the store.
 		 * ----------------
 		 */
-		estate->es_direction = dir;
+		tuplestore_donestoring(tuplestorestate);
 
 		/* ----------------
-		 *	 now initialize the scan descriptor to scan the
-		 *	 sorted relation and update the sortstate information
-		 * ----------------
-		 */
-		currentRelation = tempRelation;
-		currentScanDesc = heap_beginscan(currentRelation,		/* relation */
-										 ScanDirectionIsBackward(dir),
-										 SnapshotSelf,	/* seeself */
-										 0,		/* num scan keys */
-										 NULL); /* scan keys */
-		matstate->csstate.css_currentRelation = currentRelation;
-		matstate->csstate.css_currentScanDesc = currentScanDesc;
-
-		ExecAssignScanType(&matstate->csstate,
-						   RelationGetDescr(currentRelation));
-
-		/* ----------------
-		 *	finally set the sorted flag to true
+		 *	 restore to user specified direction
 		 * ----------------
 		 */
-		matstate->mat_Flag = true;
+		estate->es_direction = dir;
 	}
 
 	/* ----------------
-	 *	at this point we know we have a sorted relation so
-	 *	we perform a simple scan on it with amgetnext()..
-	 * ----------------
-	 */
-	currentScanDesc = matstate->csstate.css_currentScanDesc;
-
-	heapTuple = heap_getnext(currentScanDesc, ScanDirectionIsBackward(dir));
-
-	/* ----------------
-	 *	put the tuple into the scan tuple slot and return the slot.
-	 *	Note: since the tuple is really a pointer to a page, we don't want
-	 *	to call pfree() on it..
+	 *	Get the first or next tuple from tuplestore.
+	 *	Returns NULL if no more tuples.
 	 * ----------------
 	 */
-	slot = (TupleTableSlot *) matstate->csstate.css_ScanTupleSlot;
-
-	return ExecStoreTuple(heapTuple,	/* tuple to store */
-						  slot, /* slot to store in */
-						  currentScanDesc->rs_cbuf,		/* buffer for this tuple */
-						  false);		/* don't pfree this pointer */
+	slot = (TupleTableSlot *) matstate->csstate.cstate.cs_ResultTupleSlot;
+	heapTuple = tuplestore_getheaptuple(tuplestorestate,
+										ScanDirectionIsForward(dir),
+										&should_free);
 
+	return ExecStoreTuple(heapTuple, slot, InvalidBuffer, should_free);
 }
 
 /* ----------------------------------------------------------------
@@ -178,10 +142,6 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
 {
 	MaterialState *matstate;
 	Plan	   *outerPlan;
-	TupleDesc	tupType;
-	Relation	tempDesc;
-
-	/* int						len; */
 
 	/* ----------------
 	 *	assign the node's execution state
@@ -194,8 +154,7 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
 	 * ----------------
 	 */
 	matstate = makeNode(MaterialState);
-	matstate->mat_Flag = false;
-	matstate->mat_TempRelation = NULL;
+	matstate->tuplestorestate = NULL;
 	node->matstate = matstate;
 
 	/* ----------------
@@ -214,8 +173,12 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
 #define MATERIAL_NSLOTS 1
 	/* ----------------
 	 * tuple table initialization
+	 *
+	 *	material nodes only return tuples from their materialized
+	 *	relation.
 	 * ----------------
 	 */
+	ExecInitResultTupleSlot(estate, &matstate->csstate.cstate);
 	ExecInitScanTupleSlot(estate, &matstate->csstate);
 
 	/* ----------------
@@ -225,53 +188,15 @@ ExecInitMaterial(Material *node, EState *estate, Plan *parent)
 	outerPlan = outerPlan((Plan *) node);
 	ExecInitNode(outerPlan, estate, (Plan *) node);
 
-	/* ----------------
-	 *	initialize matstate information
-	 * ----------------
-	 */
-	matstate->mat_Flag = false;
-
 	/* ----------------
 	 *	initialize tuple type.	no need to initialize projection
 	 *	info because this node doesn't do projections.
 	 * ----------------
 	 */
+	ExecAssignResultTypeFromOuterPlan((Plan *) node, &matstate->csstate.cstate);
 	ExecAssignScanTypeFromOuterPlan((Plan *) node, &matstate->csstate);
 	matstate->csstate.cstate.cs_ProjInfo = NULL;
 
-	/* ----------------
-	 *	get type information needed for ExecCreatR
-	 * ----------------
-	 */
-	tupType = ExecGetScanType(&matstate->csstate);
-
-	/* ----------------
-	 *	ExecCreatR wants its second argument to be an object id of
-	 *	a relation in the range table or a _NONAME_RELATION_ID
-	 *	indicating that the relation is not in the range table.
-	 *
-	 *	In the second case ExecCreatR creates a temp relation.
-	 *	(currently this is the only case we support -cim 10/16/89)
-	 * ----------------
-	 */
-	/* ----------------
-	 *	create the temporary relation
-	 * ----------------
-	 */
-	tempDesc = ExecCreatR(tupType, _NONAME_RELATION_ID_);
-
-	/* ----------------
-	 *	save the relation descriptor in the sortstate
-	 * ----------------
-	 */
-	matstate->mat_TempRelation = tempDesc;
-	matstate->csstate.css_currentRelation = NULL;
-
-	/* ----------------
-	 *	return relation oid of temporary relation in a list
-	 *	(someday -- for now we return LispTrue... cim 10/12/89)
-	 * ----------------
-	 */
 	return TRUE;
 }
 
@@ -285,16 +210,12 @@ ExecCountSlotsMaterial(Material *node)
 
 /* ----------------------------------------------------------------
  *		ExecEndMaterial
- *
- * old comments
- *		destroys the temporary relation.
  * ----------------------------------------------------------------
  */
 void
 ExecEndMaterial(Material *node)
 {
 	MaterialState *matstate;
-	Relation	tempRelation;
 	Plan	   *outerPlan;
 
 	/* ----------------
@@ -302,14 +223,6 @@ ExecEndMaterial(Material *node)
 	 * ----------------
 	 */
 	matstate = node->matstate;
-	tempRelation = matstate->mat_TempRelation;
-
-	/* ----------------
-	 *	shut down the scan, but don't close the temp relation
-	 * ----------------
-	 */
-	matstate->csstate.css_currentRelation = NULL;
-	ExecCloseR((Plan *) node);
 
 	/* ----------------
 	 *	shut down the subplan
@@ -325,88 +238,92 @@ ExecEndMaterial(Material *node)
 	ExecClearTuple(matstate->csstate.css_ScanTupleSlot);
 
 	/* ----------------
-	 *	delete the temp relation
+	 *	Release tuplestore resources
 	 * ----------------
 	 */
-	if (tempRelation != NULL)
-		heap_drop(tempRelation);
+	if (matstate->tuplestorestate != NULL)
+		tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
+	matstate->tuplestorestate = NULL;
 }
 
 /* ----------------------------------------------------------------
- *		ExecMaterialReScan
+ *		ExecMaterialMarkPos
  *
- *		Rescans the temporary relation.
+ *		Calls tuplestore to save the current position in the stored file.
  * ----------------------------------------------------------------
  */
 void
-ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
+ExecMaterialMarkPos(Material *node)
 {
-	MaterialState *matstate = node->matstate;
+	MaterialState  *matstate = node->matstate;
 
-	if (matstate->mat_Flag == false)
+	/* ----------------
+	 *	if we haven't materialized yet, just return.
+	 * ----------------
+	 */
+	if (!matstate->tuplestorestate)
 		return;
 
-	matstate->csstate.css_currentScanDesc = ExecReScanR(matstate->csstate.css_currentRelation,
-								   matstate->csstate.css_currentScanDesc,
-								node->plan.state->es_direction, 0, NULL);
-
+	tuplestore_markpos((Tuplestorestate *) matstate->tuplestorestate);
 }
 
-#ifdef NOT_USED					/* not used */
 /* ----------------------------------------------------------------
- *		ExecMaterialMarkPos
+ *		ExecMaterialRestrPos
+ *
+ *		Calls tuplestore to restore the last saved file position.
  * ----------------------------------------------------------------
  */
-List							/* nothing of interest */
-ExecMaterialMarkPos(Material node)
+void
+ExecMaterialRestrPos(Material *node)
 {
-	MaterialState matstate;
-	HeapScanDesc scan;
+	MaterialState  *matstate = node->matstate;
 
 	/* ----------------
-	 *	if we haven't materialized yet, just return NIL.
+	 *	if we haven't materialized yet, just return.
 	 * ----------------
 	 */
-	matstate = get_matstate(node);
-	if (get_mat_Flag(matstate) == false)
-		return NIL;
+	if (!matstate->tuplestorestate)
+		return;
 
 	/* ----------------
-	 *	XXX access methods don't return positions yet so
-	 *		for now we return NIL.	It's possible that
-	 *		they will never return positions for all I know -cim 10/16/89
+	 *	restore the scan to the previously marked position
 	 * ----------------
 	 */
-	scan = get_css_currentScanDesc((CommonScanState) matstate);
-	heap_markpos(scan);
-
-	return NIL;
+	tuplestore_restorepos((Tuplestorestate *) matstate->tuplestorestate);
 }
 
 /* ----------------------------------------------------------------
- *		ExecMaterialRestrPos
+ *		ExecMaterialReScan
+ *
+ *		Rescans the materialized relation.
  * ----------------------------------------------------------------
  */
 void
-ExecMaterialRestrPos(Material node)
+ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent)
 {
-	MaterialState matstate;
-	HeapScanDesc scan;
+	MaterialState *matstate = node->matstate;
 
-	/* ----------------
-	 *	if we haven't materialized yet, just return.
-	 * ----------------
+	/*
+	 * If we haven't materialized yet, just return. If outerplan' chgParam is
+	 * not NULL then it will be re-scanned by ExecProcNode, else - no
+	 * reason to re-scan it at all.
 	 */
-	matstate = get_matstate(node);
-	if (get_mat_Flag(matstate) == false)
+	if (!matstate->tuplestorestate)
 		return;
 
-	/* ----------------
-	 *	restore the scan to the previously marked position
-	 * ----------------
+	ExecClearTuple(matstate->csstate.cstate.cs_ResultTupleSlot);
+
+	/*
+	 * If subnode is to be rescanned then we forget previous stored results;
+	 * we have to re-read the subplan and re-store.
+	 *
+	 * Otherwise we can just rewind and rescan the stored output.
 	 */
-	scan = get_css_currentScanDesc((CommonScanState) matstate);
-	heap_restrpos(scan);
+	if (((Plan *) node)->lefttree->chgParam != NULL)
+	{
+		tuplestore_end((Tuplestorestate *) matstate->tuplestorestate);
+		matstate->tuplestorestate = NULL;
+	}
+	else
+		tuplestore_rescan((Tuplestorestate *) matstate->tuplestorestate);
 }
-
-#endif
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e146661fb84dd015a4e11ed13a40029a60c5dc63..fba792cc8454117eba75182ac20321b578da7f26 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.113 2000/04/12 17:15:16 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.114 2000/06/18 22:44:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -414,41 +414,6 @@ _copyHashJoin(HashJoin *from)
 }
 
 
-/* ----------------
- *		CopyNonameFields
- *
- *		This function copies the fields of the Noname node.  It is used by
- *		all the copy functions for classes which inherit from Noname.
- * ----------------
- */
-static void
-CopyNonameFields(Noname *from, Noname *newnode)
-{
-	newnode->nonameid = from->nonameid;
-	newnode->keycount = from->keycount;
-	return;
-}
-
-
-/* ----------------
- *		_copyNoname
- * ----------------
- */
-static Noname *
-_copyNoname(Noname *from)
-{
-	Noname	   *newnode = makeNode(Noname);
-
-	/* ----------------
-	 *	copy node superclass fields
-	 * ----------------
-	 */
-	CopyPlanFields((Plan *) from, (Plan *) newnode);
-	CopyNonameFields(from, newnode);
-
-	return newnode;
-}
-
 /* ----------------
  *		_copyMaterial
  * ----------------
@@ -463,7 +428,6 @@ _copyMaterial(Material *from)
 	 * ----------------
 	 */
 	CopyPlanFields((Plan *) from, (Plan *) newnode);
-	CopyNonameFields((Noname *) from, (Noname *) newnode);
 
 	return newnode;
 }
@@ -483,7 +447,8 @@ _copySort(Sort *from)
 	 * ----------------
 	 */
 	CopyPlanFields((Plan *) from, (Plan *) newnode);
-	CopyNonameFields((Noname *) from, (Noname *) newnode);
+
+	newnode->keycount = from->keycount;
 
 	return newnode;
 }
@@ -552,7 +517,6 @@ _copyUnique(Unique *from)
 	 * ----------------
 	 */
 	CopyPlanFields((Plan *) from, (Plan *) newnode);
-	CopyNonameFields((Noname *) from, (Noname *) newnode);
 
 	/* ----------------
 	 *	copy remainder of node
@@ -1695,9 +1659,6 @@ copyObject(void *from)
 		case T_HashJoin:
 			retval = _copyHashJoin(from);
 			break;
-		case T_Noname:
-			retval = _copyNoname(from);
-			break;
 		case T_Material:
 			retval = _copyMaterial(from);
 			break;
diff --git a/src/backend/nodes/freefuncs.c b/src/backend/nodes/freefuncs.c
index 59e2ac1154ea20e64e9af4157c718ec3fd6d58fa..3353a82d9d72c4a08f7b2aa07c98572b06786f0c 100644
--- a/src/backend/nodes/freefuncs.c
+++ b/src/backend/nodes/freefuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.41 2000/05/28 17:55:57 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.42 2000/06/18 22:44:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -305,37 +305,6 @@ _freeHashJoin(HashJoin *node)
 }
 
 
-/* ----------------
- *		FreeNonameFields
- *
- *		This function frees the fields of the Noname node.	It is used by
- *		all the free functions for classes which inherit node Noname.
- * ----------------
- */
-static void
-FreeNonameFields(Noname *node)
-{
-	return;
-}
-
-
-/* ----------------
- *		_freeNoname
- * ----------------
- */
-static void
-_freeNoname(Noname *node)
-{
-	/* ----------------
-	 *	free node superclass fields
-	 * ----------------
-	 */
-	FreePlanFields((Plan *) node);
-	FreeNonameFields(node);
-
-	pfree(node);
-}
-
 /* ----------------
  *		_freeMaterial
  * ----------------
@@ -348,7 +317,6 @@ _freeMaterial(Material *node)
 	 * ----------------
 	 */
 	FreePlanFields((Plan *) node);
-	FreeNonameFields((Noname *) node);
 
 	pfree(node);
 }
@@ -366,7 +334,6 @@ _freeSort(Sort *node)
 	 * ----------------
 	 */
 	FreePlanFields((Plan *) node);
-	FreeNonameFields((Noname *) node);
 
 	pfree(node);
 }
@@ -421,7 +388,6 @@ _freeUnique(Unique *node)
 	 * ----------------
 	 */
 	FreePlanFields((Plan *) node);
-	FreeNonameFields((Noname *) node);
 
 	/* ----------------
 	 *	free remainder of node
@@ -1194,9 +1160,6 @@ freeObject(void *node)
 		case T_HashJoin:
 			_freeHashJoin(node);
 			break;
-		case T_Noname:
-			_freeNoname(node);
-			break;
 		case T_Material:
 			_freeMaterial(node);
 			break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 78585425624ead564a84dfe1b1401315fb2ad9eb..b9830edc22ffcf323396393933bb22b174b1e9ae 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.119 2000/06/16 05:27:02 tgl Exp $
+ *	$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.120 2000/06/18 22:44:05 tgl Exp $
  *
  * NOTES
  *	  Every (plan) node in POSTGRES has an associated "out" routine which
@@ -531,51 +531,29 @@ _outTidScan(StringInfo str, TidScan *node)
 }
 
 /*
- *	Noname is a subclass of Plan
- */
-static void
-_outNoname(StringInfo str, Noname *node)
-{
-	appendStringInfo(str, " NONAME ");
-	_outPlanInfo(str, (Plan *) node);
-
-	appendStringInfo(str, " :nonameid %u :keycount %d ",
-					 node->nonameid,
-					 node->keycount);
-}
-
-/*
- *	Material is a subclass of Noname
+ *	Material is a subclass of Plan
  */
 static void
 _outMaterial(StringInfo str, Material *node)
 {
 	appendStringInfo(str, " MATERIAL ");
 	_outPlanInfo(str, (Plan *) node);
-
-	appendStringInfo(str, " :nonameid %u :keycount %d ",
-					 node->nonameid,
-					 node->keycount);
 }
 
 /*
- *	Sort is a subclass of Noname
+ *	Sort is a subclass of Plan
  */
 static void
 _outSort(StringInfo str, Sort *node)
 {
 	appendStringInfo(str, " SORT ");
 	_outPlanInfo(str, (Plan *) node);
-
-	appendStringInfo(str, " :nonameid %u :keycount %d ",
-					 node->nonameid,
-					 node->keycount);
+	appendStringInfo(str, " :keycount %d ", node->keycount);
 }
 
 static void
 _outAgg(StringInfo str, Agg *node)
 {
-
 	appendStringInfo(str, " AGG ");
 	_outPlanInfo(str, (Plan *) node);
 }
@@ -592,9 +570,6 @@ _outGroup(StringInfo str, Group *node)
 					 node->tuplePerGroup ? "true" : "false");
 }
 
-/*
- *	For some reason, unique is a subclass of Noname.
- */
 static void
 _outUnique(StringInfo str, Unique *node)
 {
@@ -603,17 +578,14 @@ _outUnique(StringInfo str, Unique *node)
 	appendStringInfo(str, " UNIQUE ");
 	_outPlanInfo(str, (Plan *) node);
 
-	appendStringInfo(str, " :nonameid %u :keycount %d :numCols %d :uniqColIdx ",
-					 node->nonameid,
-					 node->keycount,
+	appendStringInfo(str, " :numCols %d :uniqColIdx ",
 					 node->numCols);
-
 	for (i = 0; i < node->numCols; i++)
 		appendStringInfo(str, "%d ", (int) node->uniqColIdx[i]);
 }
 
 /*
- *	Hash is a subclass of Noname
+ *	Hash is a subclass of Plan
  */
 static void
 _outHash(StringInfo str, Hash *node)
@@ -1502,9 +1474,6 @@ _outNode(StringInfo str, void *obj)
 			case T_TidScan:
 				_outTidScan(str, obj);
 				break;
-			case T_Noname:
-				_outNoname(str, obj);
-				break;
 			case T_Material:
 				_outMaterial(str, obj);
 				break;
diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c
index 8d3cd8d2a7b7f17efb5a35fb86d3f34d827ba181..104735cf6f63813c72ae865163ca44127ca4c8dc 100644
--- a/src/backend/nodes/print.c
+++ b/src/backend/nodes/print.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.38 2000/04/12 17:15:16 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.39 2000/06/18 22:44:05 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -315,9 +315,6 @@ plannode_type(Plan *p)
 		case T_HashJoin:
 			return "HASHJOIN";
 			break;
-		case T_Noname:
-			return "NONAME";
-			break;
 		case T_Material:
 			return "MATERIAL";
 			break;
@@ -333,9 +330,6 @@ plannode_type(Plan *p)
 		case T_Hash:
 			return "HASH";
 			break;
-		case T_Choose:
-			return "CHOOSE";
-			break;
 		case T_Group:
 			return "GROUP";
 			break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 99d25696ced53205286c4100352bef03796c09d4..f872d952d03e1bbfcd849d9762709ba07b277493 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.90 2000/06/16 05:27:03 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.91 2000/06/18 22:44:05 tgl Exp $
  *
  * NOTES
  *	  Most of the read functions for plan nodes are tested. (In fact, they
@@ -555,38 +555,10 @@ _readTidScan()
 	return local_node;
 }
 
-/* ----------------
- *		_readNoname
- *
- *	Noname is a subclass of Plan
- * ----------------
- */
-static Noname *
-_readNoname()
-{
-	Noname	   *local_node;
-	char	   *token;
-	int			length;
-
-	local_node = makeNode(Noname);
-
-	_getPlan((Plan *) local_node);
-
-	token = lsptok(NULL, &length);		/* eat :nonameid */
-	token = lsptok(NULL, &length);		/* get nonameid */
-	local_node->nonameid = atol(token);
-
-	token = lsptok(NULL, &length);		/* eat :keycount */
-	token = lsptok(NULL, &length);		/* get keycount */
-	local_node->keycount = atoi(token);
-
-	return local_node;
-}
-
 /* ----------------
  *		_readSort
  *
- *	Sort is a subclass of Noname
+ *	Sort is a subclass of Plan
  * ----------------
  */
 static Sort *
@@ -600,10 +572,6 @@ _readSort()
 
 	_getPlan((Plan *) local_node);
 
-	token = lsptok(NULL, &length);		/* eat :nonameid */
-	token = lsptok(NULL, &length);		/* get nonameid */
-	local_node->nonameid = atol(token);
-
 	token = lsptok(NULL, &length);		/* eat :keycount */
 	token = lsptok(NULL, &length);		/* get keycount */
 	local_node->keycount = atoi(token);
@@ -625,7 +593,7 @@ _readAgg()
 /* ----------------
  *		_readHash
  *
- *	Hash is a subclass of Noname
+ *	Hash is a subclass of Plan
  * ----------------
  */
 static Hash *
@@ -1853,8 +1821,6 @@ parsePlanString(void)
 		return_value = _readIndexScan();
 	else if (length == 7 && strncmp(token, "TIDSCAN", length) == 0)
 		return_value = _readTidScan();
-	else if (length == 6 && strncmp(token, "NONAME", length) == 0)
-		return_value = _readNoname();
 	else if (length == 4 && strncmp(token, "SORT", length) == 0)
 		return_value = _readSort();
 	else if (length == 6 && strncmp(token, "AGGREG", length) == 0)
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index b718f8fea18a4f7ef3a47f70e537a6ef33ee09cd..0f26dc78722cfa65f7be63007e09e472b95bec73 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -42,7 +42,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.61 2000/05/31 00:28:22 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.62 2000/06/18 22:44:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,10 +55,15 @@
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
-#include "optimizer/internal.h"
 #include "utils/lsyscache.h"
 
 
+/*
+ * The length of a variable-length field in bytes (stupid estimate...)
+ */
+#define _DEFAULT_ATTRIBUTE_WIDTH_ 12
+
+
 #define LOG2(x)  (log(x) / 0.693147180559945)
 #define LOG6(x)  (log(x) / 1.79175946922805)
 
@@ -114,29 +119,17 @@ cost_seqscan(Path *path, RelOptInfo *baserel)
 	if (!enable_seqscan)
 		startup_cost += disable_cost;
 
-	/* disk costs */
-	if (lfirsti(baserel->relids) < 0)
-	{
-
-		/*
-		 * cost of sequentially scanning a materialized temporary relation
-		 */
-		run_cost += _NONAME_SCAN_COST_;
-	}
-	else
-	{
-
-		/*
-		 * The cost of reading a page sequentially is 1.0, by definition.
-		 * Note that the Unix kernel will typically do some amount of
-		 * read-ahead optimization, so that this cost is less than the
-		 * true cost of reading a page from disk.  We ignore that issue
-		 * here, but must take it into account when estimating the cost of
-		 * non-sequential accesses!
-		 */
-		run_cost += baserel->pages;		/* sequential fetches with cost
-										 * 1.0 */
-	}
+	/*
+	 * disk costs
+	 *
+	 * The cost of reading a page sequentially is 1.0, by definition.
+	 * Note that the Unix kernel will typically do some amount of
+	 * read-ahead optimization, so that this cost is less than the
+	 * true cost of reading a page from disk.  We ignore that issue
+	 * here, but must take it into account when estimating the cost of
+	 * non-sequential accesses!
+	 */
+	run_cost += baserel->pages;	/* sequential fetches with cost 1.0 */
 
 	/* CPU costs */
 	cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost;
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 015b6b2b10af8683dfa09347e5e1ebd306caad81..4915133d0a6cb14e40dc6519dae61f6e40f96b2b 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.92 2000/06/15 03:32:13 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.93 2000/06/18 22:44:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,7 +23,6 @@
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
-#include "optimizer/internal.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
@@ -34,7 +33,6 @@
 
 
 static List *switch_outer(List *clauses);
-static int	set_tlist_sort_info(List *tlist, List *pathkeys);
 static Scan *create_scan_node(Query *root, Path *best_path, List *tlist);
 static Join *create_join_node(Query *root, JoinPath *best_path, List *tlist);
 static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
@@ -71,8 +69,6 @@ static HashJoin *make_hashjoin(List *tlist, List *qpqual,
 static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree);
 static MergeJoin *make_mergejoin(List *tlist, List *qpqual,
 			   List *mergeclauses, Plan *righttree, Plan *lefttree);
-static Material *make_material(List *tlist, Oid nonameid, Plan *lefttree,
-			  int keycount);
 static void copy_path_costsize(Plan *dest, Path *src);
 static void copy_plan_costsize(Plan *dest, Plan *src);
 static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
@@ -560,10 +556,12 @@ create_nestloop_node(NestPath *best_path,
 	}
 	else if (IsA(inner_node, TidScan))
 	{
-		List	   *inner_tideval = ((TidScan *) inner_node)->tideval;
 		TidScan    *innerscan = (TidScan *) inner_node;
 
-		((TidScan *) inner_node)->tideval = join_references(inner_tideval, outer_tlist, inner_tlist, innerscan->scan.scanrelid);
+		innerscan->tideval = join_references(innerscan->tideval,
+											 outer_tlist,
+											 inner_tlist,
+											 innerscan->scan.scanrelid);
 	}
 	else if (IsA_Join(inner_node))
 	{
@@ -575,9 +573,8 @@ create_nestloop_node(NestPath *best_path,
 		 * join --- how can we estimate whether this is a good thing to
 		 * do?
 		 */
-		inner_node = (Plan *) make_noname(inner_tlist,
-										  NIL,
-										  inner_node);
+		inner_node = (Plan *) make_material(inner_tlist,
+											inner_node);
 	}
 
 	join_node = make_nestloop(tlist,
@@ -632,14 +629,16 @@ create_mergejoin_node(MergePath *best_path,
 	 * necessary.  The sort cost was already accounted for in the path.
 	 */
 	if (best_path->outersortkeys)
-		outer_node = (Plan *) make_noname(outer_tlist,
-										  best_path->outersortkeys,
-										  outer_node);
+		outer_node = (Plan *)
+			make_sort_from_pathkeys(outer_tlist,
+									outer_node,
+									best_path->outersortkeys);
 
 	if (best_path->innersortkeys)
-		inner_node = (Plan *) make_noname(inner_tlist,
-										  best_path->innersortkeys,
-										  inner_node);
+		inner_node = (Plan *)
+			make_sort_from_pathkeys(inner_tlist,
+									inner_node,
+									best_path->innersortkeys);
 
 	join_node = make_mergejoin(tlist,
 							   qpqual,
@@ -958,72 +957,6 @@ switch_outer(List *clauses)
 	return t_list;
 }
 
-/*
- * set_tlist_sort_info
- *	  Sets the reskey and reskeyop fields of resdom nodes in a target list
- *	  for a sort node.
- *
- * 'tlist' is the target list (which is modified in-place).
- *			tlist's reskey fields must be clear to start with.
- * 'pathkeys' is the desired pathkeys for the sort.  NIL means no sort.
- *
- * Returns the number of sort keys assigned (which might be less than
- * length(pathkeys)!)
- */
-static int
-set_tlist_sort_info(List *tlist, List *pathkeys)
-{
-	int			keysassigned = 0;
-	List	   *i;
-
-	foreach(i, pathkeys)
-	{
-		List	   *keysublist = (List *) lfirst(i);
-		PathKeyItem *pathkey = NULL;
-		Resdom	   *resdom = NULL;
-		List	   *j;
-
-		/*
-		 * We can sort by any one of the sort key items listed in this
-		 * sublist.  For now, we take the first one that corresponds to an
-		 * available Var in the tlist.
-		 *
-		 * XXX if we have a choice, is there any way of figuring out which
-		 * might be cheapest to execute?  (For example, int4lt is likely
-		 * much cheaper to execute than numericlt, but both might appear
-		 * in the same pathkey sublist...)	Not clear that we ever will
-		 * have a choice in practice, so it may not matter.
-		 */
-		foreach(j, keysublist)
-		{
-			pathkey = lfirst(j);
-			Assert(IsA(pathkey, PathKeyItem));
-			resdom = tlist_member(pathkey->key, tlist);
-			if (resdom)
-				break;
-		}
-		if (!resdom)
-			elog(ERROR, "set_tlist_sort_info: cannot find tlist item to sort");
-
-		/*
-		 * The resdom might be already marked as a sort key, if the
-		 * pathkeys contain duplicate entries.	(This can happen in
-		 * scenarios where multiple mergejoinable clauses mention the same
-		 * var, for example.) In that case the current pathkey is
-		 * essentially a no-op, because only one value can be seen within
-		 * any subgroup where it would be consulted.  We can ignore it.
-		 */
-		if (resdom->reskey == 0)
-		{
-			/* OK, mark it as a sort key and set the sort operator regproc */
-			resdom->reskey = ++keysassigned;
-			resdom->reskeyop = get_opcode(pathkey->sortop);
-		}
-	}
-
-	return keysassigned;
-}
-
 /*
  * Copy cost and size info from a Path node to the Plan node created from it.
  * The executor won't use this info, but it's needed by EXPLAIN.
@@ -1078,50 +1011,7 @@ copy_plan_costsize(Plan *dest, Plan *src)
  *
  *****************************************************************************/
 
-/*
- * make_noname
- *	  Create plan node to sort or materialize relations into noname.
- *
- *	  'tlist' is the target list of the scan to be sorted or materialized
- *	  'pathkeys' is the list of pathkeys by which the result is to be sorted
- *			(NIL implies no sort needed, just materialize it)
- *	  'subplan' is the node which yields input tuples
- */
-Noname *
-make_noname(List *tlist,
-			List *pathkeys,
-			Plan *subplan)
-{
-	List	   *noname_tlist;
-	int			numsortkeys;
-	Plan	   *retval;
-
-	/* Create a new target list for the noname, with sort keys set. */
-	noname_tlist = new_unsorted_tlist(tlist);
-	numsortkeys = set_tlist_sort_info(noname_tlist, pathkeys);
-
-	if (numsortkeys > 0)
-	{
-		/* need to sort */
-		retval = (Plan *) make_sort(noname_tlist,
-									_NONAME_RELATION_ID_,
-									subplan,
-									numsortkeys);
-	}
-	else
-	{
-		/* no sort */
-		retval = (Plan *) make_material(noname_tlist,
-										_NONAME_RELATION_ID_,
-										subplan,
-										0);
-	}
-
-	return (Noname *) retval;
-}
-
-
-static SeqScan    *
+static SeqScan *
 make_seqscan(List *qptlist,
 			 List *qpqual,
 			 Index scanrelid)
@@ -1256,8 +1146,14 @@ make_mergejoin(List *tlist,
 	return node;
 }
 
+/*
+ * To use make_sort directly, you must already have marked the tlist
+ * with reskey and reskeyop information.  The keys had better be
+ * non-redundant, too (ie, there had better be tlist items marked with
+ * each key number from 1 to keycount), or the executor will get confused!
+ */
 Sort *
-make_sort(List *tlist, Oid nonameid, Plan *lefttree, int keycount)
+make_sort(List *tlist, Plan *lefttree, int keycount)
 {
 	Sort	   *node = makeNode(Sort);
 	Plan	   *plan = &node->plan;
@@ -1272,17 +1168,84 @@ make_sort(List *tlist, Oid nonameid, Plan *lefttree, int keycount)
 	plan->qual = NIL;
 	plan->lefttree = lefttree;
 	plan->righttree = NULL;
-	node->nonameid = nonameid;
 	node->keycount = keycount;
 
 	return node;
 }
 
-static Material *
-make_material(List *tlist,
-			  Oid nonameid,
-			  Plan *lefttree,
-			  int keycount)
+/*
+ * make_sort_from_pathkeys
+ *	  Create sort plan to sort according to given pathkeys
+ *
+ *	  'tlist' is the target list of the input plan
+ *	  'lefttree' is the node which yields input tuples
+ *	  'pathkeys' is the list of pathkeys by which the result is to be sorted
+ *
+ * We must convert the pathkey information into reskey and reskeyop fields
+ * of resdom nodes in the sort plan's target list.
+ */
+Sort *
+make_sort_from_pathkeys(List *tlist, Plan *lefttree, List *pathkeys)
+{
+	List	   *sort_tlist;
+	List	   *i;
+	int			numsortkeys = 0;
+
+	/* Create a new target list for the sort, with sort keys set. */
+	sort_tlist = new_unsorted_tlist(tlist);
+
+	foreach(i, pathkeys)
+	{
+		List	   *keysublist = (List *) lfirst(i);
+		PathKeyItem *pathkey = NULL;
+		Resdom	   *resdom = NULL;
+		List	   *j;
+
+		/*
+		 * We can sort by any one of the sort key items listed in this
+		 * sublist.  For now, we take the first one that corresponds to an
+		 * available Var in the sort_tlist.
+		 *
+		 * XXX if we have a choice, is there any way of figuring out which
+		 * might be cheapest to execute?  (For example, int4lt is likely
+		 * much cheaper to execute than numericlt, but both might appear
+		 * in the same pathkey sublist...)	Not clear that we ever will
+		 * have a choice in practice, so it may not matter.
+		 */
+		foreach(j, keysublist)
+		{
+			pathkey = lfirst(j);
+			Assert(IsA(pathkey, PathKeyItem));
+			resdom = tlist_member(pathkey->key, sort_tlist);
+			if (resdom)
+				break;
+		}
+		if (!resdom)
+			elog(ERROR, "make_sort_from_pathkeys: cannot find tlist item to sort");
+
+		/*
+		 * The resdom might be already marked as a sort key, if the
+		 * pathkeys contain duplicate entries.	(This can happen in
+		 * scenarios where multiple mergejoinable clauses mention the same
+		 * var, for example.) In that case the current pathkey is
+		 * essentially a no-op, because only one value can be seen within
+		 * any subgroup where it would be consulted.  We can ignore it.
+		 */
+		if (resdom->reskey == 0)
+		{
+			/* OK, mark it as a sort key and set the sort operator regproc */
+			resdom->reskey = ++numsortkeys;
+			resdom->reskeyop = get_opcode(pathkey->sortop);
+		}
+	}
+
+	Assert(numsortkeys > 0);
+
+	return make_sort(sort_tlist, lefttree, numsortkeys);
+}
+
+Material *
+make_material(List *tlist, Plan *lefttree)
 {
 	Material   *node = makeNode(Material);
 	Plan	   *plan = &node->plan;
@@ -1291,8 +1254,9 @@ make_material(List *tlist,
 
 	/*
 	 * For plausibility, make startup & total costs equal total cost of
-	 * input plan; this only affects EXPLAIN display not decisions. XXX
-	 * shouldn't we charge some additional cost for materialization?
+	 * input plan; this only affects EXPLAIN display not decisions.
+	 *
+	 * XXX shouldn't we charge some additional cost for materialization?
 	 */
 	plan->startup_cost = plan->total_cost;
 	plan->state = (EState *) NULL;
@@ -1300,8 +1264,6 @@ make_material(List *tlist,
 	plan->qual = NIL;
 	plan->lefttree = lefttree;
 	plan->righttree = NULL;
-	node->nonameid = nonameid;
-	node->keycount = keycount;
 
 	return node;
 }
@@ -1420,8 +1382,6 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList)
 	plan->qual = NIL;
 	plan->lefttree = lefttree;
 	plan->righttree = NULL;
-	node->nonameid = _NONAME_RELATION_ID_;
-	node->keycount = 0;
 
 	/*
 	 * convert SortClause list into array of attr indexes, as wanted by
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index fdb7be92447344297d2e812b77aa5a27da10c414..49d400dee9dfd2b5dc0054a1f14967129994af58 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.83 2000/06/15 03:32:13 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.84 2000/06/18 22:44:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,6 @@
 #include "executor/executor.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
-#include "optimizer/internal.h"
 #include "optimizer/paths.h"
 #include "optimizer/plancat.h"
 #include "optimizer/planmain.h"
@@ -40,7 +39,7 @@ static List *make_subplanTargetList(Query *parse, List *tlist,
 static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup,
 			   List *groupClause, AttrNumber *grpColIdx,
 			   bool is_presorted, Plan *subplan);
-static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode);
+static Plan *make_sortplan(List *tlist, Plan *plannode, List *sortcls);
 
 /*****************************************************************************
  *
@@ -641,7 +640,8 @@ union_planner(Query *parse,
 	if (parse->sortClause)
 	{
 		if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys))
-			result_plan = make_sortplan(tlist, parse->sortClause, result_plan);
+			result_plan = make_sortplan(tlist, result_plan,
+										parse->sortClause);
 	}
 
 	/*
@@ -818,10 +818,9 @@ make_groupplan(List *group_tlist,
 			}
 		}
 
-		subplan = (Plan *) make_sort(sort_tlist,
-									 _NONAME_RELATION_ID_,
-									 subplan,
-									 keyno);
+		Assert(keyno > 0);
+
+		subplan = (Plan *) make_sort(sort_tlist, subplan, keyno);
 	}
 
 	return (Plan *) make_group(group_tlist, tuplePerGroup, numCols,
@@ -833,9 +832,9 @@ make_groupplan(List *group_tlist,
  *	  Add a Sort node to implement an explicit ORDER BY clause.
  */
 static Plan *
-make_sortplan(List *tlist, List *sortcls, Plan *plannode)
+make_sortplan(List *tlist, Plan *plannode, List *sortcls)
 {
-	List	   *temp_tlist;
+	List	   *sort_tlist;
 	List	   *i;
 	int			keyno = 0;
 
@@ -843,13 +842,12 @@ make_sortplan(List *tlist, List *sortcls, Plan *plannode)
 	 * First make a copy of the tlist so that we don't corrupt the
 	 * original.
 	 */
-
-	temp_tlist = new_unsorted_tlist(tlist);
+	sort_tlist = new_unsorted_tlist(tlist);
 
 	foreach(i, sortcls)
 	{
 		SortClause *sortcl = (SortClause *) lfirst(i);
-		TargetEntry *tle = get_sortgroupclause_tle(sortcl, temp_tlist);
+		TargetEntry *tle = get_sortgroupclause_tle(sortcl, sort_tlist);
 		Resdom	   *resdom = tle->resdom;
 
 		/*
@@ -865,10 +863,9 @@ make_sortplan(List *tlist, List *sortcls, Plan *plannode)
 		}
 	}
 
-	return (Plan *) make_sort(temp_tlist,
-							  _NONAME_RELATION_ID_,
-							  plannode,
-							  keyno);
+	Assert(keyno > 0);
+
+	return (Plan *) make_sort(sort_tlist, plannode, keyno);
 }
 
 /*
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 87e508ef8f7bc41e5bbfce506e3203c620c5b057..cd624fb111d41b9a8f3d8d562dbe175806847363 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.37 2000/05/30 00:49:47 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.38 2000/06/18 22:44:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -363,9 +363,7 @@ make_subplan(SubLink *slink)
 			}
 			if (use_material)
 			{
-				plan = (Plan *) make_noname(plan->targetlist,
-											NIL,
-											plan);
+				plan = (Plan *) make_material(plan->targetlist, plan);
 				node->plan = plan;
 			}
 		}
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index da7059ce9151f3921b7a1fadd80d3cc52a42428d..070fabf7669049e3b6c5e207f630050d2262c649 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -8,14 +8,13 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.26 2000/04/12 17:15:24 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.27 2000/06/18 22:44:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "optimizer/cost.h"
-#include "optimizer/internal.h"
 #include "optimizer/joininfo.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/plancat.h"
@@ -76,26 +75,9 @@ get_base_rel(Query *root, int relid)
 	rel->joininfo = NIL;
 	rel->innerjoin = NIL;
 
-	if (relid < 0)
-	{
-
-		/*
-		 * If the relation is a materialized relation, assume constants
-		 * for sizes.
-		 */
-		rel->pages = _NONAME_RELATION_PAGES_;
-		rel->tuples = _NONAME_RELATION_TUPLES_;
-	}
-	else
-	{
-
-		/*
-		 * Otherwise, retrieve relation statistics from the system
-		 * catalogs.
-		 */
-		relation_info(root, relid,
-					  &rel->indexed, &rel->pages, &rel->tuples);
-	}
+	/* Retrieve relation statistics from the system catalogs. */
+	relation_info(root, relid,
+				  &rel->indexed, &rel->pages, &rel->tuples);
 
 	root->base_rel_list = lcons(rel, root->base_rel_list);
 
diff --git a/src/backend/utils/adt/chunk.c b/src/backend/utils/adt/chunk.c
index 1d8ec1aec8e8b4be57d2e44b5a2c9d7745477ce7..55776769493c514c532d83502f4212c945d317aa 100644
--- a/src/backend/utils/adt/chunk.c
+++ b/src/backend/utils/adt/chunk.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/chunk.c,v 1.27 2000/06/13 07:35:03 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/chunk.c,v 1.28 2000/06/18 22:44:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,6 @@
 #include "fmgr.h"
 #include "libpq/be-fsstubs.h"
 #include "libpq/libpq-fs.h"
-#include "optimizer/internal.h"
 #include "utils/array.h"
 #include "utils/memutils.h"
 
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 4fe3e35b1e86dc5f635284b09b41c1f2a236039d..93375a7c15824e92f4d992f0267ae01fffe1e775 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.101 2000/06/17 21:48:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.102 2000/06/18 22:44:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1784,21 +1784,15 @@ RelationPurgeLocalRelation(bool xactCommitted)
 
 		if (!xactCommitted)
 		{
-
 			/*
 			 * remove the file if we abort. This is so that files for
 			 * tables created inside a transaction block get removed.
 			 */
-			if (reln->rd_isnoname)
+			if (! reln->rd_unlinked)
 			{
-				if (!(reln->rd_unlinked))
-				{
-					smgrunlink(DEFAULT_SMGR, reln);
-					reln->rd_unlinked = TRUE;
-				}
-			}
-			else
 				smgrunlink(DEFAULT_SMGR, reln);
+				reln->rd_unlinked = true;
+			}
 		}
 
 		if (!IsBootstrapProcessingMode())
diff --git a/src/backend/utils/sort/Makefile b/src/backend/utils/sort/Makefile
index f0e56ace0a811e2d5fc4939f5bb20f2550d04630..2ae96894b9283f9261a6f5e3967d8e983f70b746 100644
--- a/src/backend/utils/sort/Makefile
+++ b/src/backend/utils/sort/Makefile
@@ -4,14 +4,14 @@
 #    Makefile for utils/sort
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/utils/sort/Makefile,v 1.10 2000/05/29 05:45:40 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/utils/sort/Makefile,v 1.11 2000/06/18 22:44:20 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
 SRCDIR = ../../..
 include ../../../Makefile.global
 
-OBJS = logtape.o tuplesort.o
+OBJS = logtape.o tuplesort.o tuplestore.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/utils/sort/tuplestore.c b/src/backend/utils/sort/tuplestore.c
new file mode 100644
index 0000000000000000000000000000000000000000..b1eb56cc2a05d2ec5374efc8c75a7e661cd3d537
--- /dev/null
+++ b/src/backend/utils/sort/tuplestore.c
@@ -0,0 +1,685 @@
+/*-------------------------------------------------------------------------
+ *
+ * tuplestore.c
+ *	  Generalized routines for temporary tuple storage.
+ *
+ * This module handles temporary storage of tuples for purposes such
+ * as Materialize nodes, hashjoin batch files, etc.  It is essentially
+ * a dumbed-down version of tuplesort.c; it does no sorting of tuples
+ * but can only store a sequence of tuples and regurgitate it later.
+ * A temporary file is used to handle the data if it exceeds the
+ * space limit specified by the caller.
+ *
+ * The (approximate) amount of memory allowed to the tuplestore is specified
+ * in kilobytes by the caller.  We absorb tuples and simply store them in an
+ * in-memory array as long as we haven't exceeded maxKBytes.  If we reach the
+ * end of the input without exceeding maxKBytes, we just return tuples during
+ * the read phase by scanning the tuple array sequentially.  If we do exceed
+ * maxKBytes, we dump all the tuples into a temp file and then read from that
+ * during the read phase.
+ *
+ * When the caller requests random access to the data, we write the temp file
+ * in a format that allows either forward or backward scan.
+ *
+ *
+ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/sort/tuplestore.c,v 1.1 2000/06/18 22:44:20 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "storage/buffile.h"
+#include "utils/tuplestore.h"
+
+/*
+ * Possible states of a Tuplestore object.  These denote the states that
+ * persist between calls of Tuplestore routines.
+ */
+typedef enum
+{
+	TSS_INITIAL,				/* Loading tuples; still within memory
+								 * limit */
+	TSS_WRITEFILE,				/* Loading tuples; writing to temp file */
+	TSS_READMEM,				/* Reading tuples; entirely in memory */
+	TSS_READFILE				/* Reading tuples from temp file */
+} TupStoreStatus;
+
+/*
+ * Private state of a Tuplestore operation.
+ */
+struct Tuplestorestate
+{
+	TupStoreStatus status;		/* enumerated value as shown above */
+	bool		randomAccess;	/* did caller request random access? */
+	long		availMem;		/* remaining memory available, in bytes */
+	BufFile    *myfile;			/* underlying file, or NULL if none */
+
+	/*
+	 * These function pointers decouple the routines that must know what
+	 * kind of tuple we are handling from the routines that don't need to
+	 * know it. They are set up by the tuplestore_begin_xxx routines.
+	 *
+	 * (Although tuplestore.c currently only supports heap tuples, I've
+	 * copied this part of tuplesort.c so that extension to other kinds
+	 * of objects will be easy if it's ever needed.)
+	 *
+	 * Function to copy a supplied input tuple into palloc'd space. (NB:
+	 * we assume that a single pfree() is enough to release the tuple
+	 * later, so the representation must be "flat" in one palloc chunk.)
+	 * state->availMem must be decreased by the amount of space used.
+	 */
+	void	   *(*copytup) (Tuplestorestate *state, void *tup);
+
+	/*
+	 * Function to write a stored tuple onto tape.	The representation of
+	 * the tuple on tape need not be the same as it is in memory;
+	 * requirements on the tape representation are given below.  After
+	 * writing the tuple, pfree() it, and increase state->availMem by the
+	 * amount of memory space thereby released.
+	 */
+	void		(*writetup) (Tuplestorestate *state, void *tup);
+
+	/*
+	 * Function to read a stored tuple from tape back into memory. 'len'
+	 * is the already-read length of the stored tuple.	Create and return
+	 * a palloc'd copy, and decrease state->availMem by the amount of
+	 * memory space consumed.
+	 */
+	void	   *(*readtup) (Tuplestorestate *state, unsigned int len);
+
+	/*
+	 * This array holds pointers to tuples in memory if we are in state
+	 * INITIAL or READMEM.  In states WRITEFILE and READFILE it's not used.
+	 */
+	void	  **memtuples;		/* array of pointers to palloc'd tuples */
+	int			memtupcount;	/* number of tuples currently present */
+	int			memtupsize;		/* allocated length of memtuples array */
+
+	/*
+	 * These variables are used after completion of storing to keep track
+	 * of the next tuple to return.  (In the tape case, the tape's current
+	 * read position is also critical state.)
+	 */
+	int			current;		/* array index (only used if READMEM) */
+	bool		eof_reached;	/* reached EOF (needed for cursors) */
+
+	/* markpos_xxx holds marked position for mark and restore */
+	int			markpos_file;	/* file# (only used if READFILE) */
+	long		markpos_offset; /* saved "current", or offset in tape file */
+	bool		markpos_eof;	/* saved "eof_reached" */
+};
+
+#define COPYTUP(state,tup)	((*(state)->copytup) (state, tup))
+#define WRITETUP(state,tup)	((*(state)->writetup) (state, tup))
+#define READTUP(state,len)	((*(state)->readtup) (state, len))
+#define LACKMEM(state)		((state)->availMem < 0)
+#define USEMEM(state,amt)	((state)->availMem -= (amt))
+#define FREEMEM(state,amt)	((state)->availMem += (amt))
+
+/*--------------------
+ *
+ * NOTES about on-tape representation of tuples:
+ *
+ * We require the first "unsigned int" of a stored tuple to be the total size
+ * on-tape of the tuple, including itself (so it is never zero; an all-zero
+ * unsigned int is used to delimit runs).  The remainder of the stored tuple
+ * may or may not match the in-memory representation of the tuple ---
+ * any conversion needed is the job of the writetup and readtup routines.
+ *
+ * If state->randomAccess is true, then the stored representation of the
+ * tuple must be followed by another "unsigned int" that is a copy of the
+ * length --- so the total tape space used is actually sizeof(unsigned int)
+ * more than the stored length value.  This allows read-backwards.	When
+ * randomAccess is not true, the write/read routines may omit the extra
+ * length word.
+ *
+ * writetup is expected to write both length words as well as the tuple
+ * data.  When readtup is called, the tape is positioned just after the
+ * front length word; readtup must read the tuple data and advance past
+ * the back length word (if present).
+ *
+ * The write/read routines can make use of the tuple description data
+ * stored in the Tuplestorestate record, if needed.	They are also expected
+ * to adjust state->availMem by the amount of memory space (not tape space!)
+ * released or consumed.  There is no error return from either writetup
+ * or readtup; they should elog() on failure.
+ *
+ *
+ * NOTES about memory consumption calculations:
+ *
+ * We count space requested for tuples against the maxKBytes limit.
+ * Fixed-size space (primarily the BufFile I/O buffer) is not
+ * counted, nor do we count the variable-size memtuples array.
+ * (Even though that could grow pretty large, it should be small compared
+ * to the tuples proper, so this is not unreasonable.)
+ *
+ * The major deficiency in this approach is that it ignores palloc overhead.
+ * The memory space actually allocated for a palloc chunk is always more
+ * than the request size, and could be considerably more (as much as 2X
+ * larger, in the current aset.c implementation).  So the space used could
+ * be considerably more than maxKBytes says.
+ *
+ * One way to fix this is to add a memory management function that, given
+ * a pointer to a palloc'd chunk, returns the actual space consumed by the
+ * chunk.  This would be very easy in the current aset.c module, but I'm
+ * hesitant to do it because it might be unpleasant to support in future
+ * implementations of memory management.  (For example, a direct
+ * implementation of palloc as malloc could not support such a function
+ * portably.)
+ *
+ * A cruder answer is just to apply a fudge factor, say by initializing
+ * availMem to only three-quarters of what maxKBytes indicates.  This is
+ * probably the right answer if anyone complains that maxKBytes is not being
+ * obeyed very faithfully.
+ *
+ *--------------------
+ */
+
+
+static Tuplestorestate *tuplestore_begin_common(bool randomAccess,
+												int maxKBytes);
+static void dumptuples(Tuplestorestate *state);
+static unsigned int getlen(Tuplestorestate *state, bool eofOK);
+static void markrunend(Tuplestorestate *state);
+static void *copytup_heap(Tuplestorestate *state, void *tup);
+static void writetup_heap(Tuplestorestate *state, void *tup);
+static void *readtup_heap(Tuplestorestate *state, unsigned int len);
+
+
+/*
+ *		tuplestore_begin_xxx
+ *
+ * Initialize for a tuple store operation.
+ *
+ * After calling tuplestore_begin, the caller should call tuplestore_puttuple
+ * zero or more times, then call tuplestore_donestoring when all the tuples
+ * have been supplied.	After donestoring, retrieve the tuples in order
+ * by calling tuplestore_gettuple until it returns NULL.  (If random
+ * access was requested, rescan, markpos, and restorepos can also be called.)
+ * Call tuplestore_end to terminate the operation and release memory/disk
+ * space.
+ */
+
+static Tuplestorestate *
+tuplestore_begin_common(bool randomAccess, int maxKBytes)
+{
+	Tuplestorestate *state;
+
+	state = (Tuplestorestate *) palloc(sizeof(Tuplestorestate));
+
+	MemSet((char *) state, 0, sizeof(Tuplestorestate));
+
+	state->status = TSS_INITIAL;
+	state->randomAccess = randomAccess;
+	state->availMem = maxKBytes * 1024L;
+	state->myfile = NULL;
+
+	state->memtupcount = 0;
+	if (maxKBytes > 0)
+		state->memtupsize = 1024; /* initial guess */
+	else
+		state->memtupsize = 1;	/* won't really need any space */
+	state->memtuples = (void **) palloc(state->memtupsize * sizeof(void *));
+
+	return state;
+}
+
+Tuplestorestate *
+tuplestore_begin_heap(bool randomAccess, int maxKBytes)
+{
+	Tuplestorestate *state = tuplestore_begin_common(randomAccess, maxKBytes);
+
+	state->copytup = copytup_heap;
+	state->writetup = writetup_heap;
+	state->readtup = readtup_heap;
+
+	return state;
+}
+
+/*
+ * tuplestore_end
+ *
+ *	Release resources and clean up.
+ */
+void
+tuplestore_end(Tuplestorestate *state)
+{
+	int			i;
+
+	if (state->myfile)
+		BufFileClose(state->myfile);
+	if (state->memtuples)
+	{
+		for (i = 0; i < state->memtupcount; i++)
+			pfree(state->memtuples[i]);
+		pfree(state->memtuples);
+	}
+}
+
+/*
+ * Accept one tuple while collecting input data.
+ *
+ * Note that the input tuple is always copied; the caller need not save it.
+ */
+void
+tuplestore_puttuple(Tuplestorestate *state, void *tuple)
+{
+	/*
+	 * Copy the tuple.  (Must do this even in WRITEFILE case.)
+	 */
+	tuple = COPYTUP(state, tuple);
+
+	switch (state->status)
+	{
+		case TSS_INITIAL:
+			/*
+			 * Stash the tuple in the in-memory array.
+			 */
+			if (state->memtupcount >= state->memtupsize)
+			{
+				/* Grow the array as needed. */
+				state->memtupsize *= 2;
+				state->memtuples = (void **)
+					repalloc(state->memtuples,
+							 state->memtupsize * sizeof(void *));
+			}
+			state->memtuples[state->memtupcount++] = tuple;
+
+			/*
+			 * Done if we still fit in available memory.
+			 */
+			if (!LACKMEM(state))
+				return;
+
+			/*
+			 * Nope; time to switch to tape-based operation.
+			 */
+			state->myfile = BufFileCreateTemp();
+			state->status = TSS_WRITEFILE;
+			dumptuples(state);
+			break;
+		case TSS_WRITEFILE:
+			WRITETUP(state, tuple);
+			break;
+		default:
+			elog(ERROR, "tuplestore_puttuple: invalid state");
+			break;
+	}
+}
+
+/*
+ * All tuples have been provided; finish writing.
+ */
+void
+tuplestore_donestoring(Tuplestorestate *state)
+{
+	switch (state->status)
+	{
+		case TSS_INITIAL:
+			/*
+			 * We were able to accumulate all the tuples within the
+			 * allowed amount of memory.  Just set up to scan them.
+			 */
+			state->current = 0;
+			state->eof_reached = false;
+			state->markpos_offset = 0L;
+			state->markpos_eof = false;
+			state->status = TSS_READMEM;
+			break;
+		case TSS_WRITEFILE:
+			/*
+			 * Write the EOF marker.
+			 */
+			markrunend(state);
+			/*
+			 * Set up for reading from tape.
+			 */
+			if (BufFileSeek(state->myfile, 0, 0L, SEEK_SET) != 0)
+				elog(ERROR, "tuplestore_donestoring: seek(0) failed");
+			state->eof_reached = false;
+			state->markpos_file = 0;
+			state->markpos_offset = 0L;
+			state->markpos_eof = false;
+			state->status = TSS_READFILE;
+			break;
+		default:
+			elog(ERROR, "tuplestore_donestoring: invalid state");
+			break;
+	}
+}
+
+/*
+ * Fetch the next tuple in either forward or back direction.
+ * Returns NULL if no more tuples.	If should_free is set, the
+ * caller must pfree the returned tuple when done with it.
+ */
+void *
+tuplestore_gettuple(Tuplestorestate *state, bool forward,
+				   bool *should_free)
+{
+	unsigned int tuplen;
+	void	   *tup;
+
+	switch (state->status)
+	{
+		case TSS_READMEM:
+			Assert(forward || state->randomAccess);
+			*should_free = false;
+			if (forward)
+			{
+				if (state->current < state->memtupcount)
+					return state->memtuples[state->current++];
+				state->eof_reached = true;
+				return NULL;
+			}
+			else
+			{
+				if (state->current <= 0)
+					return NULL;
+
+				/*
+				 * if all tuples are fetched already then we return last
+				 * tuple, else - tuple before last returned.
+				 */
+				if (state->eof_reached)
+					state->eof_reached = false;
+				else
+				{
+					state->current--;	/* last returned tuple */
+					if (state->current <= 0)
+						return NULL;
+				}
+				return state->memtuples[state->current - 1];
+			}
+			break;
+
+		case TSS_READFILE:
+			Assert(forward || state->randomAccess);
+			*should_free = true;
+			if (forward)
+			{
+				if (state->eof_reached)
+					return NULL;
+				if ((tuplen = getlen(state, true)) != 0)
+				{
+					tup = READTUP(state, tuplen);
+					return tup;
+				}
+				else
+				{
+					state->eof_reached = true;
+					return NULL;
+				}
+			}
+
+			/*
+			 * Backward.
+			 *
+			 * if all tuples are fetched already then we return last tuple,
+			 * else - tuple before last returned.
+			 */
+			if (state->eof_reached)
+			{
+
+				/*
+				 * Seek position is pointing just past the zero tuplen at
+				 * the end of file; back up to fetch last tuple's ending
+				 * length word.  If seek fails we must have a completely
+				 * empty file.
+				 */
+				if (BufFileSeek(state->myfile, 0,
+								- (long) (2 * sizeof(unsigned int)),
+								SEEK_CUR) != 0)
+					return NULL;
+				state->eof_reached = false;
+			}
+			else
+			{
+
+				/*
+				 * Back up and fetch previously-returned tuple's ending
+				 * length word.  If seek fails, assume we are at start of
+				 * file.
+				 */
+				if (BufFileSeek(state->myfile, 0,
+								- (long) sizeof(unsigned int),
+								SEEK_CUR) != 0)
+					return NULL;
+				tuplen = getlen(state, false);
+
+				/*
+				 * Back up to get ending length word of tuple before it.
+				 */
+				if (BufFileSeek(state->myfile, 0,
+								- (long) (tuplen + 2 * sizeof(unsigned int)),
+								SEEK_CUR) != 0)
+				{
+
+					/*
+					 * If that fails, presumably the prev tuple is the
+					 * first in the file.  Back up so that it becomes next
+					 * to read in forward direction (not obviously right,
+					 * but that is what in-memory case does).
+					 */
+					if (BufFileSeek(state->myfile, 0,
+									- (long) (tuplen + sizeof(unsigned int)),
+									SEEK_CUR) != 0)
+						elog(ERROR, "tuplestore_gettuple: bogus tuple len in backward scan");
+					return NULL;
+				}
+			}
+
+			tuplen = getlen(state, false);
+
+			/*
+			 * Now we have the length of the prior tuple, back up and read
+			 * it. Note: READTUP expects we are positioned after the
+			 * initial length word of the tuple, so back up to that point.
+			 */
+			if (BufFileSeek(state->myfile, 0,
+							- (long) tuplen,
+							SEEK_CUR) != 0)
+				elog(ERROR, "tuplestore_gettuple: bogus tuple len in backward scan");
+			tup = READTUP(state, tuplen);
+			return tup;
+
+		default:
+			elog(ERROR, "tuplestore_gettuple: invalid state");
+			return NULL;		/* keep compiler quiet */
+	}
+}
+
+/*
+ * dumptuples - remove tuples from memory and write to tape
+ */
+static void
+dumptuples(Tuplestorestate *state)
+{
+	int			i;
+
+	for (i = 0; i < state->memtupcount; i++)
+	{
+		WRITETUP(state, state->memtuples[i]);
+	}
+	state->memtupcount = 0;
+}
+
+/*
+ * tuplestore_rescan		- rewind and replay the scan
+ */
+void
+tuplestore_rescan(Tuplestorestate *state)
+{
+	Assert(state->randomAccess);
+
+	switch (state->status)
+	{
+		case TSS_READMEM:
+			state->current = 0;
+			state->eof_reached = false;
+			state->markpos_offset = 0L;
+			state->markpos_eof = false;
+			break;
+		case TSS_READFILE:
+			if (BufFileSeek(state->myfile, 0, 0L, SEEK_SET) != 0)
+				elog(ERROR, "tuplestore_rescan: seek(0) failed");
+			state->eof_reached = false;
+			state->markpos_file = 0;
+			state->markpos_offset = 0L;
+			state->markpos_eof = false;
+			break;
+		default:
+			elog(ERROR, "tuplestore_rescan: invalid state");
+			break;
+	}
+}
+
+/*
+ * tuplestore_markpos	- saves current position in the tuple sequence
+ */
+void
+tuplestore_markpos(Tuplestorestate *state)
+{
+	Assert(state->randomAccess);
+
+	switch (state->status)
+	{
+		case TSS_READMEM:
+			state->markpos_offset = state->current;
+			state->markpos_eof = state->eof_reached;
+			break;
+		case TSS_READFILE:
+			BufFileTell(state->myfile,
+						&state->markpos_file,
+						&state->markpos_offset);
+			state->markpos_eof = state->eof_reached;
+			break;
+		default:
+			elog(ERROR, "tuplestore_markpos: invalid state");
+			break;
+	}
+}
+
+/*
+ * tuplestore_restorepos - restores current position in tuple sequence to
+ *						  last saved position
+ */
+void
+tuplestore_restorepos(Tuplestorestate *state)
+{
+	Assert(state->randomAccess);
+
+	switch (state->status)
+	{
+		case TSS_READMEM:
+			state->current = (int) state->markpos_offset;
+			state->eof_reached = state->markpos_eof;
+			break;
+		case TSS_READFILE:
+			if (BufFileSeek(state->myfile,
+							state->markpos_file,
+							state->markpos_offset,
+							SEEK_SET) != 0)
+				elog(ERROR, "tuplestore_restorepos failed");
+			state->eof_reached = state->markpos_eof;
+			break;
+		default:
+			elog(ERROR, "tuplestore_restorepos: invalid state");
+			break;
+	}
+}
+
+
+/*
+ * Tape interface routines
+ */
+
+static unsigned int
+getlen(Tuplestorestate *state, bool eofOK)
+{
+	unsigned int len;
+
+	if (BufFileRead(state->myfile, (void *) &len, sizeof(len)) != sizeof(len))
+		elog(ERROR, "tuplestore: unexpected end of tape");
+	if (len == 0 && !eofOK)
+		elog(ERROR, "tuplestore: unexpected end of data");
+	return len;
+}
+
+static void
+markrunend(Tuplestorestate *state)
+{
+	unsigned int len = 0;
+
+	if (BufFileWrite(state->myfile, (void *) &len, sizeof(len)) != sizeof(len))
+		elog(ERROR, "tuplestore: write failed");
+}
+
+
+/*
+ * Routines specialized for HeapTuple case
+ */
+
+static void *
+copytup_heap(Tuplestorestate *state, void *tup)
+{
+	HeapTuple	tuple = (HeapTuple) tup;
+
+	USEMEM(state, HEAPTUPLESIZE + tuple->t_len);
+	return (void *) heap_copytuple(tuple);
+}
+
+/*
+ * We don't bother to write the HeapTupleData part of the tuple.
+ */
+
+static void
+writetup_heap(Tuplestorestate *state, void *tup)
+{
+	HeapTuple	tuple = (HeapTuple) tup;
+	unsigned int tuplen;
+
+	tuplen = tuple->t_len + sizeof(tuplen);
+	if (BufFileWrite(state->myfile, (void *) &tuplen,
+					 sizeof(tuplen)) != sizeof(tuplen))
+		elog(ERROR, "tuplestore: write failed");
+	if (BufFileWrite(state->myfile, (void *) tuple->t_data,
+					 tuple->t_len) != (size_t) tuple->t_len)
+		elog(ERROR, "tuplestore: write failed");
+	if (state->randomAccess)	/* need trailing length word? */
+		if (BufFileWrite(state->myfile, (void *) &tuplen,
+						 sizeof(tuplen)) != sizeof(tuplen))
+			elog(ERROR, "tuplestore: write failed");
+
+	FREEMEM(state, HEAPTUPLESIZE + tuple->t_len);
+	heap_freetuple(tuple);
+}
+
+static void *
+readtup_heap(Tuplestorestate *state, unsigned int len)
+{
+	unsigned int tuplen = len - sizeof(unsigned int) + HEAPTUPLESIZE;
+	HeapTuple	tuple = (HeapTuple) palloc(tuplen);
+
+	USEMEM(state, tuplen);
+	/* reconstruct the HeapTupleData portion */
+	tuple->t_len = len - sizeof(unsigned int);
+	ItemPointerSetInvalid(&(tuple->t_self));
+	tuple->t_datamcxt = CurrentMemoryContext;
+	tuple->t_data = (HeapTupleHeader) (((char *) tuple) + HEAPTUPLESIZE);
+	/* read in the tuple proper */
+	if (BufFileRead(state->myfile, (void *) tuple->t_data,
+					tuple->t_len) != (size_t) tuple->t_len)
+		elog(ERROR, "tuplestore: unexpected end of data");
+	if (state->randomAccess)	/* need trailing length word? */
+		if (BufFileRead(state->myfile, (void *) &tuplen,
+						sizeof(tuplen)) != sizeof(tuplen))
+			elog(ERROR, "tuplestore: unexpected end of data");
+	return (void *) tuple;
+}
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index dae57528c71e74c5385cbd115dc7e70b81e21337..9880d2aa3219d2ba584cf3150bb6ecb59dd7d85b 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: heapam.h,v 1.52 2000/04/12 17:16:25 momjian Exp $
+ * $Id: heapam.h,v 1.53 2000/06/18 22:44:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -242,9 +242,11 @@ extern HeapAccessStatistics heap_access_stats;	/* in stats.c */
 
 /* ----------------
  *		function prototypes for heap access method
+ *
+ * heap_create, heap_create_with_catalog, and heap_drop_with_catalog
+ * are declared in catalog/heap.h
  * ----------------
  */
-/* heap_create, heap_creatr, and heap_destroy are declared in catalog/heap.h */
 
 /* heapam.c */
 
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 468eef4d3dfb3296ae05c7d8accc37e6789e0494..c59509e152987b4037c45941ac86a9647837d991 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: heap.h,v 1.29 2000/04/12 17:16:27 momjian Exp $
+ * $Id: heap.h,v 1.30 2000/06/18 22:44:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,8 +24,9 @@ typedef struct RawColumnDefault
 } RawColumnDefault;
 
 extern Oid	RelnameFindRelid(const char *relname);
-extern Relation heap_create(char *relname, TupleDesc att,
-			bool isnoname, bool istemp, bool storage_create);
+
+extern Relation heap_create(char *relname, TupleDesc tupDesc,
+							bool istemp, bool storage_create);
 extern bool heap_storage_create(Relation rel);
 
 extern Oid heap_create_with_catalog(char *relname, TupleDesc tupdesc,
@@ -33,13 +34,9 @@ extern Oid heap_create_with_catalog(char *relname, TupleDesc tupdesc,
 
 extern void heap_drop_with_catalog(const char *relname);
 extern void heap_truncate(char *relname);
-extern void heap_drop(Relation rel);
 
 extern void AddRelationRawConstraints(Relation rel,
 						  List *rawColDefaults,
 						  List *rawConstraints);
 
-extern void InitNoNameRelList(void);
-extern void DropNoNameRels(void);
-
 #endif	 /* HEAP_H */
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 6d196eb5a2c7fef942211ca2a4eefcca440c7cda..703c907e127ccd14fc5f230af32268b47d358690 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.44 2000/06/17 21:48:56 tgl Exp $
+ * $Id: executor.h,v 1.45 2000/06/18 22:44:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,7 +39,6 @@ extern HeapScanDesc ExecReScanR(Relation relDesc, HeapScanDesc scanDesc,
 			ScanDirection direction, int nkeys, ScanKey skeys);
 extern void ExecMarkPos(Plan *node);
 extern void ExecRestrPos(Plan *node);
-extern Relation ExecCreatR(TupleDesc tupType, Oid relationOid);
 
 /*
  * prototypes from functions in execJunk.c
diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h
index 1daf0bd0afeb42a481e49244b1f25f9a67b562f2..b99d54b78d85af484b40dc0c080ddc93291f1cf0 100644
--- a/src/include/executor/nodeMaterial.h
+++ b/src/include/executor/nodeMaterial.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodeMaterial.h,v 1.12 2000/01/26 05:58:05 momjian Exp $
+ * $Id: nodeMaterial.h,v 1.13 2000/06/18 22:44:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,11 +20,8 @@ extern TupleTableSlot *ExecMaterial(Material *node);
 extern bool ExecInitMaterial(Material *node, EState *estate, Plan *parent);
 extern int	ExecCountSlotsMaterial(Material *node);
 extern void ExecEndMaterial(Material *node);
-extern void ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent);
-
-#ifdef NOT_USED
-extern List ExecMaterialMarkPos(Material *node);
+extern void ExecMaterialMarkPos(Material *node);
 extern void ExecMaterialRestrPos(Material *node);
+extern void ExecMaterialReScan(Material *node, ExprContext *exprCtxt, Plan *parent);
 
-#endif
 #endif	 /* NODEMATERIAL_H */
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 044cee23eab9859bc4d0fa96124c4fda3d6b0718..a74f16348d27f31258bcbea1277a9580297b91ea 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.41 2000/04/12 17:16:39 momjian Exp $
+ * $Id: execnodes.h,v 1.42 2000/06/18 22:44:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -565,11 +565,9 @@ typedef struct HashJoinState
  *	 MaterialState information
  *
  *		materialize nodes are used to materialize the results
- *		of a subplan into a temporary relation.
+ *		of a subplan into a temporary file.
  *
- *		Flag			indicated whether subplan has been materialized
- *		TempRelation	temporary relation containing result of executing
- *						the subplan.
+ *		tuplestorestate		private state of tuplestore.c
  *
  *	 CommonScanState information
  *
@@ -590,8 +588,7 @@ typedef struct HashJoinState
 typedef struct MaterialState
 {
 	CommonScanState csstate;	/* its first field is NodeTag */
-	bool		mat_Flag;
-	Relation	mat_TempRelation;
+	void	   *tuplestorestate;
 } MaterialState;
 
 /* ---------------------
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 5d049dadfb25ed644d841333b52d483fc5813043..3be483177895c7445f05f24e480f54d817d9490b 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.68 2000/05/29 01:59:12 tgl Exp $
+ * $Id: nodes.h,v 1.69 2000/06/18 22:44:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,13 +39,13 @@ typedef enum NodeTag
 	T_NestLoop,
 	T_MergeJoin,
 	T_HashJoin,
-	T_Noname,
+	T_Noname_XXX,				/* not used anymore; this tag# is available */
 	T_Material,
 	T_Sort,
 	T_Agg,
 	T_Unique,
 	T_Hash,
-	T_Choose,
+	T_Choose_XXX,				/* not used anymore; this tag# is available */
 	T_Group,
 	T_SubPlan,
 	T_TidScan,
@@ -261,10 +261,6 @@ typedef struct Node
 	(IsA(jp, Join) || IsA(jp, NestLoop) || \
 	 IsA(jp, MergeJoin) || IsA(jp, HashJoin))
 
-#define IsA_Noname(t) \
-	(IsA(t, Noname) || IsA(t, Material) || IsA(t, Sort) || \
-	 IsA(t, Unique))
-
 #define IsA_Value(t) \
 	(IsA(t, Integer) || IsA(t, Float) || IsA(t, String))
 
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 1cab6e03fc0fecb2ef599bd6fe238519b60b3a11..37006e621f488ce889675c43c86d20855c1fb132 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plannodes.h,v 1.39 2000/04/12 17:16:40 momjian Exp $
+ * $Id: plannodes.h,v 1.40 2000/06/18 22:44:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -277,27 +277,13 @@ typedef struct Group
 	GroupState *grpstate;
 } Group;
 
-/*
- * ==========
- * Noname nodes
- * ==========
- */
-typedef struct Noname
-{
-	Plan		plan;
-	Oid			nonameid;
-	int			keycount;
-} Noname;
-
 /* ----------------
  *		materialization node
  * ----------------
  */
 typedef struct Material
 {
-	Plan		plan;			/* noname node flattened out */
-	Oid			nonameid;
-	int			keycount;
+	Plan		plan;
 	MaterialState *matstate;
 } Material;
 
@@ -307,8 +293,7 @@ typedef struct Material
  */
 typedef struct Sort
 {
-	Plan		plan;			/* noname node flattened out */
-	Oid			nonameid;
+	Plan		plan;
 	int			keycount;
 	SortState  *sortstate;
 } Sort;
@@ -319,9 +304,7 @@ typedef struct Sort
  */
 typedef struct Unique
 {
-	Plan		plan;			/* noname node flattened out */
-	Oid			nonameid;
-	int			keycount;
+	Plan		plan;
 	int			numCols;		/* number of columns to check for
 								 * uniqueness */
 	AttrNumber *uniqColIdx;		/* indexes into the target list */
diff --git a/src/include/optimizer/internal.h b/src/include/optimizer/internal.h
deleted file mode 100644
index e9b0c8e4bc1b4d96abcd94e2be9a651c554385e2..0000000000000000000000000000000000000000
--- a/src/include/optimizer/internal.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * internal.h
- *	  Definitions required throughout the query optimizer.
- *
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: internal.h,v 1.27 2000/06/15 03:32:51 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef INTERNAL_H
-#define INTERNAL_H
-
-/*
- *		---------- SHARED MACROS
- *
- *		Macros common to modules for creating, accessing, and modifying
- *		query tree and query plan components.
- *		Shared with the executor.
- *
- */
-
-
-/*
- *		Size estimates
- *
- */
-
-/*	   The cost of sequentially scanning a materialized temporary relation
- */
-#define _NONAME_SCAN_COST_		10
-
-/*	   The number of pages and tuples in a materialized relation
- */
-#define _NONAME_RELATION_PAGES_			1
-#define _NONAME_RELATION_TUPLES_	10
-
-/*	   The length of a variable-length field in bytes (stupid estimate...)
- */
-#define _DEFAULT_ATTRIBUTE_WIDTH_ 12
-
-/*
- *		Flags and identifiers
- *
- */
-
-/*	   Identifier for (sort) temp relations   */
-/* used to be -1 */
-#define _NONAME_RELATION_ID_	 InvalidOid
-
-#endif	 /* INTERNAL_H */
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index e76ba2014499c2c894e2eb9a36f4676feee6e233..6c16364f67e8bfb5857fb70351af8a684b0362dd 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: planmain.h,v 1.41 2000/06/08 22:37:51 momjian Exp $
+ * $Id: planmain.h,v 1.42 2000/06/18 22:44:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,12 +27,13 @@ extern Plan *query_planner(Query *root, List *tlist, List *qual,
  * prototypes for plan/createplan.c
  */
 extern Plan *create_plan(Query *root, Path *best_path);
-extern Sort *make_sort(List *tlist, Oid nonameid, Plan *lefttree,
-		  int keycount);
+extern Sort *make_sort(List *tlist, Plan *lefttree, int keycount);
+extern Sort *make_sort_from_pathkeys(List *tlist, Plan *lefttree,
+									 List *pathkeys);
 extern Agg *make_agg(List *tlist, List *qual, Plan *lefttree);
 extern Group *make_group(List *tlist, bool tuplePerGroup, int ngrp,
 		   AttrNumber *grpColIdx, Plan *lefttree);
-extern Noname *make_noname(List *tlist, List *pathkeys, Plan *subplan);
+extern Material *make_material(List *tlist, Plan *lefttree);
 extern Unique *make_unique(List *tlist, Plan *lefttree, List *distinctList);
 extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
 
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 2a585c0e7ea2b710e30ce39d65cb29efdc58f230..901020611aca5547708c18ca58c73668a1d5dffd 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: rel.h,v 1.37 2000/06/17 21:49:02 tgl Exp $
+ * $Id: rel.h,v 1.38 2000/06/18 22:44:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -90,7 +90,6 @@ typedef struct RelationData
 	uint16		rd_refcnt;		/* reference count */
 	bool		rd_myxactonly;	/* rel uses the local buffer mgr */
 	bool		rd_isnailed;	/* rel is nailed in cache */
-	bool		rd_isnoname;	/* rel has no name */
 	bool		rd_unlinked;	/* rel already unlinked or not created yet */
 	bool		rd_indexfound;	/* true if rd_indexlist is valid */
 	Form_pg_am	rd_am;			/* AM tuple */
diff --git a/src/include/utils/tuplestore.h b/src/include/utils/tuplestore.h
new file mode 100644
index 0000000000000000000000000000000000000000..702d3b73c917e2e795bbb21b52d8a81533d9b977
--- /dev/null
+++ b/src/include/utils/tuplestore.h
@@ -0,0 +1,60 @@
+/*-------------------------------------------------------------------------
+ *
+ * tuplestore.h
+ *	  Generalized routines for temporary tuple storage.
+ *
+ * This module handles temporary storage of tuples for purposes such
+ * as Materialize nodes, hashjoin batch files, etc.  It is essentially
+ * a dumbed-down version of tuplesort.c; it does no sorting of tuples
+ * but can only store a sequence of tuples and regurgitate it later.
+ * A temporary file is used to handle the data if it exceeds the
+ * space limit specified by the caller.
+ *
+ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: tuplestore.h,v 1.1 2000/06/18 22:44:35 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef TUPLESTORE_H
+#define TUPLESTORE_H
+
+#include "access/htup.h"
+
+/* Tuplestorestate is an opaque type whose details are not known outside
+ * tuplestore.c.
+ */
+typedef struct Tuplestorestate Tuplestorestate;
+
+/*
+ * Currently we only need to store HeapTuples, but it would be easy
+ * to support the same behavior for IndexTuples and/or bare Datums.
+ */
+
+extern Tuplestorestate *tuplestore_begin_heap(bool randomAccess,
+											  int maxKBytes);
+
+extern void tuplestore_puttuple(Tuplestorestate *state, void *tuple);
+
+extern void tuplestore_donestoring(Tuplestorestate *state);
+
+extern void *tuplestore_gettuple(Tuplestorestate *state, bool forward,
+								 bool *should_free);
+
+#define tuplestore_getheaptuple(state, forward, should_free) \
+	((HeapTuple) tuplestore_gettuple(state, forward, should_free))
+
+extern void tuplestore_end(Tuplestorestate *state);
+
+/*
+ * These routines may only be called if randomAccess was specified 'true'.
+ * Likewise, backwards scan in gettuple/getdatum is only allowed if
+ * randomAccess was specified.
+ */
+
+extern void tuplestore_rescan(Tuplestorestate *state);
+extern void tuplestore_markpos(Tuplestorestate *state);
+extern void tuplestore_restorepos(Tuplestorestate *state);
+
+#endif	 /* TUPLESTORE_H */