diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 29e349bda9e231f5041ed222e86a8e8f19d5cb61..65d8482cad7d4a05813f1c489cf12516124208bb 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.5 1996/11/10 02:59:54 momjian Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/executor/nodeMergejoin.c,v 1.6 1997/08/06 03:41:29 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -374,6 +374,18 @@ ExecMergeTupleDump(ExprContext *econtext, MergeJoinState *mergestate)
     printf("******** \n");
 }
  
+static void
+CleanUpSort(Plan *plan) {
+
+    if (plan == NULL)
+	return;
+    
+    if (plan->type == T_Sort) {
+	Sort *sort = (Sort *)plan;
+	psort_end(sort);
+    }
+}
+
 /* ----------------------------------------------------------------
  *   	ExecMergeJoin
  *
@@ -676,6 +688,8 @@ ExecMergeJoin(MergeJoin *node)
 	     */
             if (TupIsNull(outerTupleSlot)) {
 		MJ_printf("ExecMergeJoin: **** outer tuple is nil ****\n");
+		CleanUpSort(node->join.lefttree->lefttree);
+		CleanUpSort(node->join.righttree->lefttree);
 		return NULL;
 	    }
 	    
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 83d78073bb9d5dbe9f08f882ffd1d886f5cbc4d5..84c6db71f7937d9e974cf321eda8945e6f5766f5 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -1,13 +1,13 @@
 /*-------------------------------------------------------------------------
  *
  * nodeSort.c--
- *    Routines to handle sorting of relations into temporaries.
+ *    Routines to handle sorting of relations.
  *
  * Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.4 1996/11/08 05:56:17 momjian Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.5 1997/08/06 03:41:31 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,10 +86,9 @@ FormSortKeys(Sort *sortnode)
  *   	ExecSort
  *
  * old comments
- *   	Retrieves tuples fron the outer subtree and insert them into a 
- *   	temporary relation. The temporary relation is then sorted and
- *   	the sorted relation is stored in the relation whose ID is indicated
- *   	in the 'tempid' field of this node.
+ *      Sorts tuples from the outer subtree of the node in psort,
+ *      which saves the results in a temporary file or memory. After the
+ *      initial call, returns a tuple from the file with each call.
  *   	Assumes that heap access method is used.
  *   
  *   	Conditions:
@@ -108,13 +107,8 @@ ExecSort(Sort *node)
     ScanDirection  dir;
     int		   keycount;
     ScanKey	   sortkeys;
-    Relation	   tempRelation;
-    Relation	   currentRelation;
-    HeapScanDesc   currentScanDesc;
     HeapTuple      heapTuple;
     TupleTableSlot *slot;
-    Buffer	   buffer;
-    int		   tupCount = 0;
     
     /* ----------------
      *	get state info from node
@@ -128,10 +122,8 @@ ExecSort(Sort *node)
     dir =   	  estate->es_direction;
     
     /* ----------------
-     *	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.
+     *  the first time we call this, psort sorts this into a file.
+     *  Subsequent calls return tuples from psort.
      * ----------------
      */
     
@@ -144,78 +136,23 @@ ExecSort(Sort *node)
 	 * ----------------
 	 */
 	estate->es_direction = ForwardScanDirection;
-	
-	/* ----------------
-	 *   if we couldn't create the temp or current relations then
-	 *   we print a warning and return NULL.
-	 * ----------------
-	 */
-	tempRelation =  sortstate->sort_TempRelation;
-	if (tempRelation == NULL) {
-	    elog(DEBUG, "ExecSort: temp relation is NULL! aborting...");
-	    return NULL;
-	}
-	
-	currentRelation = sortstate->csstate.css_currentRelation;
-	if (currentRelation == NULL) {
-	    elog(DEBUG, "ExecSort: current relation is NULL! aborting...");
-	    return NULL;
-	}
-	
+
 	/* ----------------
-	 *   retrieve tuples from the subplan and
-	 *   insert them in the temporary relation
+	 *   prepare information for psort_begin()
 	 * ----------------
 	 */
 	outerNode = outerPlan((Plan *) node);
-	SO1_printf("ExecSort: %s\n",
-		   "inserting tuples into tempRelation");
-	
-	for (;;) {
-	    slot = ExecProcNode(outerNode, (Plan*)node);
-	    
-	    if (TupIsNull(slot))
-		break;
-	    
-	    tupCount++;
-	    
-	    heapTuple = slot->val;
-	    
-	    heap_insert(tempRelation, 	/* relation desc */
-			heapTuple);	/* heap tuple to insert */
-	    
-	    ExecClearTuple(slot);
-	}
-	
-	/* ----------------
-	 *   now sort the tuples in our temporary relation
-	 *   into a new sorted relation using psort()
-	 *
-	 *   psort() seems to require that the relations
-	 *   are created and opened in advance.
-	 *   -cim 1/25/90
-	 * ----------------
-	 */
+
 	keycount = node->keycount;
 	sortkeys = (ScanKey)sortstate->sort_Keys;
 	SO1_printf("ExecSort: %s\n",
-		   "calling psort");
-	
-	/*
-	 * If no tuples were fetched from the proc node return NULL now
-	 * psort dumps it if 0 tuples are in the relation and I don't want
-	 * to try to debug *that* routine!!
-	 */
-	if (tupCount == 0)
-	    return NULL;
-	
-	psort(tempRelation,	/* old relation */
-	      currentRelation,	/* new relation */
-	      keycount,		/* number keys */
-	      sortkeys);	/* keys */
-	
-	if (currentRelation == NULL) {
-	    elog(DEBUG, "ExecSort: sorted relation is NULL! aborting...");
+		   "calling psort_begin");
+  
+	if (!psort_begin(node,	  	/* this node */
+			 keycount,      /* number keys */
+			 sortkeys))     /* keys */
+	{
+	    /* Psort says, there are no tuples to be sorted */
 	    return NULL;
 	}
 	
@@ -225,67 +162,56 @@ ExecSort(Sort *node)
 	 */
 	estate->es_direction = dir;
 	
-	/* ----------------
-	 *   now initialize the scan descriptor to scan the
-	 *   sorted relation and update the sortstate information
-	 * ----------------
-	 */
-	currentScanDesc = heap_beginscan(currentRelation,    /* relation */
-					 ScanDirectionIsBackward(dir),
-					 /* bkwd flag */
-					 NowTimeQual,        /* time qual */
-					 0, 		  /* num scan keys */
-					 NULL);		  /* scan keys */
-	
-	sortstate->csstate.css_currentRelation = currentRelation;
-	sortstate->csstate.css_currentScanDesc = currentScanDesc;
-	
 	/* ----------------
 	 *  make sure the tuple descriptor is up to date
 	 * ----------------
 	 */
-	slot = sortstate->csstate.css_ScanTupleSlot;
-	
-	slot->ttc_tupleDescriptor = 
-	    RelationGetTupleDescriptor(currentRelation);
-	
+	slot = (TupleTableSlot*)sortstate->csstate.cstate.cs_ResultTupleSlot;
+	/* *** get_cs_ResultTupleSlot((CommonState) sortstate); */
+
+	slot->ttc_tupleDescriptor = ExecGetTupType(outerNode);
+#ifdef 0
+	slot->ttc_execTupDescriptor = ExecGetExecTupDesc(outerNode);
+#endif
 	/* ----------------
 	 *  finally set the sorted flag to true
 	 * ----------------
 	 */
 	sortstate->sort_Flag = true;
+	SO1_printf(stderr, "ExecSort: sorting done.\n");	
     }
     else {
-	slot =  sortstate->csstate.css_ScanTupleSlot; 
+	slot = (TupleTableSlot*)sortstate->csstate.cstate.cs_ResultTupleSlot;
+	/* *** get_cs_ResultTupleSlot((CommonState) sortstate); */
+/*	slot =  sortstate->csstate.css_ScanTupleSlot; orig */
     }
     
     SO1_printf("ExecSort: %s\n",
-	       "retrieveing tuple from sorted relation");
+	       "retrieving tuple from sorted relation");
     
     /* ----------------
-     *	at this point we know we have a sorted relation so
-     *  we preform a simple scan on it with amgetnext()..
+     *  at this point we grab a tuple from psort
      * ----------------
      */
-    currentScanDesc = sortstate->csstate.css_currentScanDesc;
-    
-    heapTuple = heap_getnext(currentScanDesc, 	/* scan desc */
-			     ScanDirectionIsBackward(dir),
-			     /* bkwd flag */
-			     &buffer); 		/* return: buffer */
-    
-    /* Increase the pin count on the buffer page, because the tuple stored in 
-       the slot also points to it (as well as the scan descriptor). If we 
-       don't, ExecStoreTuple will decrease the pin count on the next iteration.
-       - 01/09/93 */
-    
-    if (buffer != InvalidBuffer) 
-        IncrBufferRefCount(buffer);
-    
-    return ExecStoreTuple(heapTuple,  	/* tuple to store */
-			  slot,   	/* slot to store in */
-			  buffer,	/* this tuple's buffer */
-			  false);	/* don't free stuff from amgetnext */
+    heapTuple = psort_grabtuple(node);
+
+    if (heapTuple == NULL) {
+/* 	psort_end(node); */
+	return (ExecClearTuple(slot));
+    }
+
+    ExecStoreTuple(heapTuple,		/* tuple to store */
+			  slot,			/* slot to store in */
+			  InvalidBuffer,	/* no buffer */
+			  true);		/* free the palloc'd tuple */
+/*    printf("ExecSort: (%x)",node);print_slot(slot);printf("\n");*/
+    return slot;
+#if 0
+    return ExecStoreTuple(heapTuple,		/* tuple to store */
+			  slot,			/* slot to store in */
+			  InvalidBuffer,	/* no buffer */
+			  true);		/* free the palloc'd tuple */
+#endif
 }
 
 /* ----------------------------------------------------------------
@@ -302,11 +228,6 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
     SortState		*sortstate;
     Plan		*outerPlan;
     ScanKey		sortkeys;
-    TupleDesc		tupType;
-    Oid			tempOid;
-    Oid			sortOid;
-    Relation		tempDesc;
-    Relation		sortedDesc;
     
     SO1_printf("ExecInitSort: %s\n",
 	       "initializing sort node");
@@ -324,7 +245,7 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
     sortstate = makeNode(SortState);
     sortstate->sort_Flag = 0;
     sortstate->sort_Keys = NULL;
-    sortstate->sort_TempRelation = NULL;
+    node->cleaned = FALSE;
 
     node->sortstate = sortstate;
     
@@ -348,8 +269,8 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
      *  relation.
      * ----------------
      */
-      ExecInitScanTupleSlot(estate, &sortstate->csstate);  
-      ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate); 
+    ExecInitResultTupleSlot(estate, &sortstate->csstate.cstate);
+    ExecInitScanTupleSlot(estate, &sortstate->csstate);
     
     /* ----------------
      * initializes child nodes
@@ -371,41 +292,10 @@ ExecInitSort(Sort *node, EState *estate, Plan *parent)
      *  info because this node doesn't do projections.
      * ----------------
      */
-    ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate); 
+    ExecAssignResultTypeFromOuterPlan((Plan *)node, &sortstate->csstate.cstate);
+    ExecAssignScanTypeFromOuterPlan((Plan *) node, &sortstate->csstate);
     sortstate->csstate.cstate.cs_ProjInfo = NULL;
     
-    /* ----------------
-     *	get type information needed for ExecCreatR
-     * ----------------
-     */
-    tupType = ExecGetScanType(&sortstate->csstate); 
-    
-    /* ----------------
-     *	ExecCreatR wants its second argument to be an object id of
-     *  a relation in the range table or _TEMP_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)
-     * ----------------
-     */
-    tempOid = 	node->tempid;
-    sortOid =	_TEMP_RELATION_ID_;
-    
-    /* ----------------
-     *	create the temporary relations
-     * ----------------
-     */
-/*    len = 		ExecTargetListLength(node->plan.targetlist); */
-    tempDesc = 		ExecCreatR(tupType, tempOid);
-    sortedDesc = 	ExecCreatR(tupType, sortOid);
-    
-    /* ----------------
-     *	save the relation descriptor in the sortstate
-     * ----------------
-     */
-    sortstate->sort_TempRelation = tempDesc;
-    sortstate->csstate.css_currentRelation = sortedDesc;
     SO1_printf("ExecInitSort: %s\n",
 	       "sort node initialized");
     
@@ -429,15 +319,12 @@ ExecCountSlotsSort(Sort *node)
  *   	ExecEndSort(node)
  *
  * old comments
- *   	destroys the temporary relation.
  * ----------------------------------------------------------------
  */
 void
 ExecEndSort(Sort *node)
 {
     SortState	*sortstate;
-    Relation	tempRelation;
-    Relation	sortedRelation;
     Plan	*outerPlan;
     
     /* ----------------
@@ -448,18 +335,6 @@ ExecEndSort(Sort *node)
 	       "shutting down sort node");
     
     sortstate =      node->sortstate;
-    tempRelation =   sortstate->sort_TempRelation;
-    sortedRelation = sortstate->csstate.css_currentRelation;
-    
-    heap_destroyr(tempRelation);
-    heap_destroyr(sortedRelation);
-
-    
-    /* ----------------
-     *	close the sorted relation and shut down the scan.
-     * ----------------
-     */
-    ExecCloseR((Plan *) node);
     
     /* ----------------
      *	shut down the subplan
@@ -473,6 +348,9 @@ ExecEndSort(Sort *node)
      * ----------------
      */
     ExecClearTuple(sortstate->csstate.css_ScanTupleSlot); 
+
+    /* Clean up after psort */
+    psort_end(node);
     
     SO1_printf("ExecEndSort: %s\n",
 	       "sort node shutdown");
@@ -480,37 +358,39 @@ ExecEndSort(Sort *node)
 
 /* ----------------------------------------------------------------
  *	ExecSortMarkPos
+ *
+ *      Calls psort to save the current position in the sorted file.
  * ----------------------------------------------------------------
  */
 void
 ExecSortMarkPos(Sort *node)
 {
-    SortState 	 *sortstate;
-    HeapScanDesc sdesc;
-    
+    SortState    *sortstate;
+
     /* ----------------
-     *	if we haven't sorted yet, just return
+     *  if we haven't sorted yet, just return
      * ----------------
      */
     sortstate =   node->sortstate;
     if (sortstate->sort_Flag == false)
 	return; 
     
-    sdesc = sortstate->csstate.css_currentScanDesc;
-    heap_markpos(sdesc);
+    psort_markpos(node);
+
     return;
 }
 
 /* ----------------------------------------------------------------
  *	ExecSortRestrPos
+ *
+ *      Calls psort to restore the last saved sort file position.
  * ----------------------------------------------------------------
  */
 void
 ExecSortRestrPos(Sort *node)
 {
-    SortState	 *sortstate;
-    HeapScanDesc sdesc;
-    
+    SortState    *sortstate;
+
     /* ----------------
      *	if we haven't sorted yet, just return.
      * ----------------
@@ -520,9 +400,8 @@ ExecSortRestrPos(Sort *node)
 	return;
     
     /* ----------------
-     *	restore the scan to the previously marked position
+     *  restore the scan to the previously marked position
      * ----------------
      */
-    sdesc = sortstate->csstate.css_currentScanDesc;
-    heap_restrpos(sdesc);
+    psort_restorepos(node);
 }
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index a9269da46c0d9ac0346f7f1cefa089c041ef21d8..a14386745f71e07b4b19d4944ed5c5ceb13834e7 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.36 1997/07/29 16:14:40 thomas Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.37 1997/08/06 03:41:41 momjian Exp $
  *
  * NOTES
  *    this is the "main" module of the postgres backend and
@@ -108,6 +108,7 @@ extern int      lockingOff;
 extern int      NBuffers;
 
 int     fsyncOff = 0;
+int	SortMem = 512;
 
 int     dontExecute = 0;
 static int      ShowStats;
@@ -1038,7 +1039,16 @@ PostgresMain(int argc, char *argv[])
              */
             flagQ = 1;
             break;
-            
+
+        case 'S':
+            /* ----------------
+             *  S - amount of sort memory to use in 1k bytes
+             * ----------------
+             */
+            SortMem = atoi(optarg);
+            break;
+
+#ifdef NOT_USED
         case 'S':
             /* ----------------
              *  S - assume stable main memory
@@ -1048,6 +1058,7 @@ PostgresMain(int argc, char *argv[])
             flagS = 1;
             SetTransactionFlushEnabled(false);
             break;
+#endif
             
         case 's':
             /* ----------------
@@ -1173,6 +1184,7 @@ PostgresMain(int argc, char *argv[])
         printf("\ttimings   =    %c\n", ShowStats ? 't' : 'f');
         printf("\tdates     =    %s\n", EuroDates ? "European" : "Normal");
         printf("\tbufsize   =    %d\n", NBuffers);
+        printf("\tsortmem   =    %d\n", SortMem);
         
         printf("\tquery echo =   %c\n", EchoQuery ? 't' : 'f');
         printf("\tmultiplexed backend? =  %c\n", multiplexedBackend ? 't' : 'f');
@@ -1280,7 +1292,7 @@ PostgresMain(int argc, char *argv[])
      */
     if (IsUnderPostmaster == false) {
         puts("\nPOSTGRES backend interactive interface");
-        puts("$Revision: 1.36 $ $Date: 1997/07/29 16:14:40 $");
+        puts("$Revision: 1.37 $ $Date: 1997/08/06 03:41:41 $");
     }
     
     /* ----------------
diff --git a/src/backend/utils/sort/lselect.c b/src/backend/utils/sort/lselect.c
index 8c6c27ef46e22185eaef4cbc87543295a8e248fe..26a3ca385769ef73ed295ac278c27713d0a6225d 100644
--- a/src/backend/utils/sort/lselect.c
+++ b/src/backend/utils/sort/lselect.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/lselect.c,v 1.3 1997/05/20 11:35:48 vadim Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/lselect.c,v 1.4 1997/08/06 03:41:47 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,37 +26,14 @@
 #include "utils/psort.h"
 #include "utils/lselect.h"
 
-extern	Relation	SortRdesc;		/* later static */ 
-
-/*
- *	PUTTUP		- writes the next tuple
- *	ENDRUN		- mark end of run
- *	GETLEN		- reads the length of the next tuple
- *	ALLOCTUP	- returns space for the new tuple
- *	SETTUPLEN	- stores the length into the tuple
- *	GETTUP		- reads the tuple
- *
- *	Note:
- *		LEN field must be a short; FP is a stream
- */
-
 #define	PUTTUP(TUP, FP)	fwrite((char *)TUP, (TUP)->t_len, 1, FP)
-#define	ENDRUN(FP)	fwrite((char *)&shortzero, sizeof (shortzero), 1, FP)
-#define	GETLEN(LEN, FP)	fread(&(LEN), sizeof (shortzero), 1, FP)
-#define	ALLOCTUP(LEN)	((HeapTuple)palloc((unsigned)LEN))
-#define	GETTUP(TUP, LEN, FP)\
-	fread((char *)(TUP) + sizeof (shortzero), 1, (LEN) - sizeof (shortzero), FP)
-#define	SETTUPLEN(TUP, LEN)	(TUP)->t_len = LEN
 
 /*
  *	USEMEM		- record use of memory
  *	FREEMEM		- record freeing of memory
- *	FULLMEM		- 1 iff a tuple will fit
  */
-
-#define	USEMEM(AMT)	SortMemory -= (AMT)
-#define	FREEMEM(AMT)	SortMemory += (AMT)
-#define	LACKMEM()	(SortMemory <= BLCKSZ)		/* not accurate */
+#define	USEMEM(context,AMT)	context->sortMem -= (AMT)
+#define	FREEMEM(context,AMT)	context->sortMem += (AMT)
 
 /*
  *	lmerge		- merges two leftist trees into one
@@ -67,12 +44,12 @@ extern	Relation	SortRdesc;		/* later static */
  *		speed up code significantly.
  */
 struct leftist *
-lmerge(struct leftist *pt, struct leftist *qt)
+lmerge(struct leftist *pt, struct leftist *qt, LeftistContext context)
 {
     register struct	leftist	*root, *majorLeftist, *minorLeftist;
     int		dist;
     
-    if (tuplecmp(pt->lt_tuple, qt->lt_tuple)) {
+    if (tuplecmp(pt->lt_tuple, qt->lt_tuple, context)) {
 	root = pt;
 	majorLeftist = qt;
     } else {
@@ -83,7 +60,7 @@ lmerge(struct leftist *pt, struct leftist *qt)
 	root->lt_left = majorLeftist;
     else {
 	if ((minorLeftist = root->lt_right) != NULL)
-	    majorLeftist = lmerge(majorLeftist, minorLeftist);
+	    majorLeftist = lmerge(majorLeftist, minorLeftist, context);
 	if ((dist = root->lt_left->lt_dist) < majorLeftist->lt_dist) {
 	    root->lt_dist = 1 + dist;
 	    root->lt_right = root->lt_left;
@@ -97,11 +74,11 @@ lmerge(struct leftist *pt, struct leftist *qt)
 }
 
 static struct leftist *
-linsert(struct leftist *root, struct leftist *new1)
+linsert(struct leftist *root, struct leftist *new1, LeftistContext context)
 {
     register struct	leftist	*left, *right;
     
-    if (! tuplecmp(root->lt_tuple, new1->lt_tuple)) {
+    if (! tuplecmp(root->lt_tuple, new1->lt_tuple, context)) {
 	new1->lt_left = root;
 	return(new1);
     }
@@ -116,7 +93,7 @@ linsert(struct leftist *root, struct leftist *new1)
 	}
 	return(root);
     }
-    right = linsert(right, new1);
+    right = linsert(right, new1, context);
     if (right->lt_dist < left->lt_dist) {
 	root->lt_dist = 1 + left->lt_dist;
 	root->lt_left = right;
@@ -142,7 +119,8 @@ linsert(struct leftist *root, struct leftist *new1)
  */
 HeapTuple
 gettuple(struct leftist **treep,
-	 short *devnum)		/* device from which tuple came */
+	 short *devnum,		/* device from which tuple came */
+	 LeftistContext context)
 {
     register struct	leftist	 *tp;
     HeapTuple	tup;
@@ -153,9 +131,9 @@ gettuple(struct leftist **treep,
     if (tp->lt_dist == 1)				/* lt_left == NULL */
 	*treep = tp->lt_left;
     else
-	*treep = lmerge(tp->lt_left, tp->lt_right);
+	*treep = lmerge(tp->lt_left, tp->lt_right, context);
     
-    FREEMEM(sizeof (struct leftist));
+    FREEMEM(context,sizeof (struct leftist));
     FREE(tp);
     return(tup);
 }
@@ -169,14 +147,17 @@ gettuple(struct leftist **treep,
  *	Note:
  *		Currently never returns NULL BUG
  */
-int
-puttuple(struct leftist **treep, HeapTuple newtuple, int devnum)
+void
+puttuple(struct leftist **treep,
+	 HeapTuple newtuple,
+	 short devnum,
+	 LeftistContext context)
 {
     register struct	leftist	*new1;
     register struct	leftist	*tp;
     
     new1 = (struct leftist *) palloc((unsigned) sizeof (struct leftist));
-    USEMEM(sizeof (struct leftist));
+    USEMEM(context,sizeof (struct leftist));
     new1->lt_dist = 1;
     new1->lt_devnum = devnum;
     new1->lt_tuple = newtuple;
@@ -185,38 +166,11 @@ puttuple(struct leftist **treep, HeapTuple newtuple, int devnum)
     if ((tp = *treep) == NULL)
 	*treep = new1;
     else
-	*treep = linsert(tp, new1);
-    return(1);
+	*treep = linsert(tp, new1, context);
+    return;
 }
 
 
-/*
- *	dumptuples	- stores all the tuples in tree into file
- */
-void
-dumptuples(FILE *file)
-{
-    register struct	leftist	*tp;
-    register struct	leftist	*newp;
-    HeapTuple	tup;
-    
-    tp = Tuples;
-    while (tp != NULL) {
-	tup = tp->lt_tuple;
-	if (tp->lt_dist == 1)			/* lt_right == NULL */
-	    newp = tp->lt_left;
-	else
-	    newp = lmerge(tp->lt_left, tp->lt_right);
-	FREEMEM(sizeof (struct leftist));
-	FREE(tp);
-	PUTTUP(tup, file);
-	FREEMEM(tup->t_len);
-	FREE(tup);
-	tp = newp;
-    }
-    Tuples = NULL;
-}
-
 /*
  *	tuplecmp	- Compares two tuples with respect CmpList
  *
@@ -225,7 +179,7 @@ dumptuples(FILE *file)
  *	Assumtions:
  */
 int
-tuplecmp(HeapTuple ltup, HeapTuple rtup)
+tuplecmp(HeapTuple ltup, HeapTuple rtup, LeftistContext context)
 {
     register char	*lattr, *rattr;
     int		nkey = 0;
@@ -238,24 +192,27 @@ tuplecmp(HeapTuple ltup, HeapTuple rtup)
 	return(0);
     if (rtup == (HeapTuple)NULL)
 	return(1);
-    while (nkey < Nkeys && !result) {
+    while (nkey < context->nKeys && !result) {
 	lattr = heap_getattr(ltup, InvalidBuffer,
-			     Key[nkey].sk_attno, 
-			     RelationGetTupleDescriptor(SortRdesc),
-			     &isnull);
+			     context->scanKeys[nkey].sk_attno,
+			     context->tupDesc, &isnull);
 	if (isnull)
 	    return(0);
 	rattr = heap_getattr(rtup, InvalidBuffer,
-			     Key[nkey].sk_attno, 
-			     RelationGetTupleDescriptor(SortRdesc),
+			     context->scanKeys[nkey].sk_attno,
+			     context->tupDesc,
 			     &isnull);
 	if (isnull)
 	    return(1);
-	if (Key[nkey].sk_flags & SK_COMMUTE) {
-	    if (!(result = (long) (*Key[nkey].sk_func) (rattr, lattr)))
-		result = -(long) (*Key[nkey].sk_func) (lattr, rattr);
-	} else if (!(result = (long) (*Key[nkey].sk_func) (lattr, rattr)))
-	    result = -(long) (*Key[nkey].sk_func) (rattr, lattr);
+	if (context->scanKeys[nkey].sk_flags & SK_COMMUTE) {
+	    if (!(result =
+		  (long) (*context->scanKeys[nkey].sk_func) (rattr, lattr)))
+		result =
+		    -(long) (*context->scanKeys[nkey].sk_func) (lattr, rattr);
+	} else if (!(result =
+		     (long) (*context->scanKeys[nkey].sk_func) (lattr, rattr)))
+	    result =
+		-(long) (*context->scanKeys[nkey].sk_func) (rattr, lattr);
 	nkey++;
     }
     return (result == 1);
@@ -263,7 +220,7 @@ tuplecmp(HeapTuple ltup, HeapTuple rtup)
 
 #ifdef	EBUG
 void
-checktree(struct leftist *tree)
+checktree(struct leftist *tree, LeftistContext context)
 {
     int		lnodes;
     int		rnodes;
@@ -272,8 +229,8 @@ checktree(struct leftist *tree)
 	puts("Null tree.");
 	return;
     }
-    lnodes = checktreer(tree->lt_left, 1);
-    rnodes = checktreer(tree->lt_right, 1);
+    lnodes = checktreer(tree->lt_left, 1, context);
+    rnodes = checktreer(tree->lt_right, 1, context);
     if (lnodes < 0) {
 	lnodes = -lnodes;
 	puts("0:\tBad left side.");
@@ -297,24 +254,24 @@ checktree(struct leftist *tree)
     } else if (tree->lt_dist != 1+ tree->lt_right->lt_dist)
 	puts("0:\tDistance incorrect.");
     if (lnodes > 0)
-	if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple))
+	if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple, context))
 	    printf("%d:\tLeft child < parent.\n");
     if (rnodes > 0)
-	if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple))
+	if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple, context))
 	    printf("%d:\tRight child < parent.\n");
     printf("Tree has %d nodes\n", 1 + lnodes + rnodes);
 }
 
 int
-checktreer(struct leftist *tree, int level)
+checktreer(struct leftist *tree, int level, LeftistContext context)
 {
     int	lnodes, rnodes;
     int	error = 0;
     
     if (tree == NULL)
 	return(0);
-    lnodes = checktreer(tree->lt_left, level + 1);
-    rnodes = checktreer(tree->lt_right, level + 1);
+    lnodes = checktreer(tree->lt_left, level + 1, context);
+    rnodes = checktreer(tree->lt_right, level + 1, context);
     if (lnodes < 0) {
 	error = 1;
 	lnodes = -lnodes;
@@ -349,12 +306,12 @@ checktreer(struct leftist *tree, int level)
 	printf("%d:\tDistance incorrect.\n", level);
     }
     if (lnodes > 0)
-	if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple)) {
+	if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple, context)) {
 	    error = 1;
 	    printf("%d:\tLeft child < parent.\n");
 	}
     if (rnodes > 0)
-	if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple)) {
+	if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple, context)) {
 	    error = 1;
 	    printf("%d:\tRight child < parent.\n");
 	}
diff --git a/src/backend/utils/sort/psort.c b/src/backend/utils/sort/psort.c
index 7005666ce3f2bdcb0e4979b57f3326350610f7e4..5821905669ff13b4aca3f22787aa38a37e94ce0c 100644
--- a/src/backend/utils/sort/psort.c
+++ b/src/backend/utils/sort/psort.c
@@ -7,11 +7,25 @@
  *
  *
  * IDENTIFICATION
- *    $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.5 1997/07/24 20:18:07 momjian Exp $
+ *    $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.6 1997/08/06 03:41:55 momjian Exp $
  *
  * NOTES
- *	Sorts the first relation into the second relation.  The sort may
- * not be called twice simultaneously.
+ *      Sorts the first relation into the second relation.
+ *
+ *      The old psort.c's routines formed a temporary relation from the merged
+ * sort files. This version keeps the files around instead of generating the
+ * relation from them, and provides interface functions to the file so that
+ * you can grab tuples, mark a position in the file, restore a position in the
+ * file. You must now explicitly call an interface function to end the sort,
+ * psort_end, when you are done.
+ *      Now most of the global variables are stuck in the Sort nodes, and
+ * accessed from there (they are passed to all the psort routines) so that
+ * each sort running has its own separate state. This is facilitated by having
+ * the Sort nodes passed in to all the interface functions.
+ *      The one global variable that all the sorts still share is SortMemory.
+ *      You should now be allowed to run two or more psorts concurrently,
+ * so long as the memory they eat up is not greater than SORTMEM, the initial
+ * value of SortMemory.				        	-Rex 2.15.1995
  *
  *    Use the tape-splitting method (Knuth, Vol. III, pp281-86) in the future.
  *
@@ -21,7 +35,6 @@
  */
 #include <stdio.h>
 #include <math.h>
-#include <unistd.h>
 
 #include "postgres.h"
 
@@ -35,120 +48,150 @@
 #include "storage/buf.h"
 #include "storage/bufmgr.h"	/* for BLCKSZ */
 #include "utils/portal.h"	/* for {Start,End}PortalAllocMode */
+#include "utils/elog.h"
 #include "utils/rel.h"
 
-#include "utils/psort.h"
+#include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
+#include "executor/executor.h"
+
 #include "utils/lselect.h"
+#include "utils/psort.h"
 
 #include "storage/fd.h"
 
-#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
-#else
-# include <string.h>
-#endif
-
 #define	TEMPDIR	"./"
 
-int			Nkeys;
-ScanKey			Key;
-int			SortMemory;
-
-static	int		TapeRange;		/* number of tapes - 1 (T) */
-static	int		Level;			/* (l) */
-static	int		TotalDummy;		/* summation of tp_dummy */
-static	struct	tape	Tape[MAXTAPES];
-static	long		shortzero = 0;		/* used to delimit runs */
-static	struct	tuple	*LastTuple = NULL;	/* last output */
+extern 		int	SortMem;	/* defined as postgres option */
+static  	long	shortzero = 0;	/* used to delimit runs */
 
-static  int		BytesRead;		/* to keep track of # of IO */
-static  int		BytesWritten;
+/*
+ * old psort global variables
+ *
+ * (These are the global variables from the old psort. They are still used,
+ *  but are now accessed from Sort nodes using the PS macro. Note that while
+ *  these variables will be accessed by PS(node)->whatever, they will still
+ *  be called by their original names within the comments!      -Rex 2.10.1995)
+ *
+ * LeftistContextData   treeContext;
+ *
+ * static       int     TapeRange;		// number of tapes - 1 (T) //
+ * static       int     Level;			// (l) //
+ * static       int     TotalDummy;		// summation of tp_dummy //
+ * static struct tape   *Tape;
+ *
+ * static  	int	BytesRead;		// to keep track of # of IO //
+ * static  	int	BytesWritten;
+ *
+ * struct leftist       *Tuples;		// current tuples in memory //
+ *
+ * FILE		 	*psort_grab_file;       // this holds tuples grabbed
+ *						   from merged sort runs //
+ * long		 	psort_current;		// current file position //
+ * long		 	psort_saved;		// file position saved for
+ *						   mark and restore //
+ */
 
-Relation		SortRdesc;		/* current tuples in memory */
-struct	leftist		*Tuples;		/* current tuples in memory */
+/*
+ * PS - Macro to access and cast psortstate from a Sort node
+ */
+#define PS(N) ((Psortstate *)N->psortstate)
 
 /*
- *	psort		- polyphase merge sort entry point
+ *      psort_begin     - polyphase merge sort entry point. Sorts the subplan
+ *			  into a temporary file psort_grab_file. After
+ *			  this is called, calling the interface function
+ *			  psort_grabtuple iteratively will get you the sorted
+ *			  tuples. psort_end then finishes the sort off, after
+ *			  all the tuples have been grabbed.
+ *
+ *		          Allocates and initializes sort node's psort state.
  */
-void
-psort(Relation oldrel, Relation newrel, int nkeys, ScanKey key)
+bool
+psort_begin(Sort *node, int nkeys, ScanKey key)
 {
+    bool empty;	 /* to answer: is child node empty? */
+
+    node->psortstate = (struct Psortstate *)palloc(sizeof(struct Psortstate));
+    if (node->psortstate == NULL)
+	return false;
+
     AssertArg(nkeys >= 1);
     AssertArg(key[0].sk_attno != 0);
     AssertArg(key[0].sk_procedure != 0);
     
-    Nkeys = nkeys;
-    Key = key;
-    SortMemory = 0;
-    SortRdesc = oldrel;
-    BytesRead = 0;
-    BytesWritten = 0;
-    /* 
-     * may not be the best place.  
-     *
-     * Pass 0 for the "limit" as the argument is currently ignored.
-     * Previously, only one arg was passed. -mer 12 Nov. 1991
-     */
-    StartPortalAllocMode(StaticAllocMode, (Size)0);
-    initpsort();
-    initialrun(oldrel);
-    /* call finalrun(newrel, mergerun()) instead */
-    endpsort(newrel, mergeruns());
-    EndPortalAllocMode();
-    NDirectFileRead += (int)ceil((double)BytesRead / BLCKSZ);
-    NDirectFileWrite += (int)ceil((double)BytesWritten / BLCKSZ);
-}
+    PS(node)->BytesRead = 0;
+    PS(node)->BytesWritten = 0;
+    PS(node)->treeContext.tupDesc =
+	ExecGetTupType(outerPlan((Plan *)node));
+    PS(node)->treeContext.nKeys = nkeys;
+    PS(node)->treeContext.scanKeys = key;
+    PS(node)->treeContext.sortMem = SortMem;
 
-/*
- *	TAPENO		- number of tape in Tape
- */
+    PS(node)->Tuples = NULL;
+    PS(node)->tupcount = 0;
+    
+    PS(node)->using_tape_files = false;
+    PS(node)->memtuples = NULL;
+
+    initialrun(node, &empty);
+
+    if (empty)
+	return false;
+
+    if (PS(node)->using_tape_files)
+	PS(node)->psort_grab_file = mergeruns(node);
 
-#define	TAPENO(NODE)		(NODE - Tape)
-#define	TUPLENO(TUP)		((TUP == NULL) ? -1 : (int) TUP->t_iid)
+    PS(node)->psort_current = 0;
+    PS(node)->psort_saved = 0;
+
+    return true;
+}
 
 /*
- *	initpsort	- initializes the tapes
+ *	inittapes	- initializes the tapes
  *			- (polyphase merge Alg.D(D1)--Knuth, Vol.3, p.270)
  *	Returns:
  *		number of allocated tapes
  */
 void
-initpsort()
+inittapes(Sort *node)
 {
     register	int			i;
     register	struct	tape		*tp;
     
+    Assert(node != (Sort *) NULL);
+    Assert(PS(node) != (Psortstate *) NULL);
+
     /*
       ASSERT(ntapes >= 3 && ntapes <= MAXTAPES,
-      "initpsort: Invalid number of tapes to initialize.\n");
+      "inittapes: Invalid number of tapes to initialize.\n");
       */
     
-    tp = Tape;
+    tp = PS(node)->Tape;
     for (i = 0; i < MAXTAPES && (tp->tp_file = gettape()) != NULL; i++) {
 	tp->tp_dummy = 1;
 	tp->tp_fib = 1;
 	tp->tp_prev = tp - 1;
 	tp++;
     }
-    TapeRange = --tp - Tape;
+    PS(node)->TapeRange = --tp - PS(node)->Tape;
     tp->tp_dummy = 0;
     tp->tp_fib = 0;
-    Tape[0].tp_prev = tp;
-    
-    if (TapeRange <= 1)
-	elog(WARN, "initpsort: Could only allocate %d < 3 tapes\n",
-	     TapeRange + 1);
+    PS(node)->Tape[0].tp_prev = tp;
     
-    Level = 1;
-    TotalDummy = TapeRange;
+    if (PS(node)->TapeRange <= 1)
+	elog(WARN, "inittapes: Could only allocate %d < 3 tapes\n",
+	     PS(node)->TapeRange + 1);
     
-    SortMemory = SORTMEM;
-    LastTuple = NULL;
-    Tuples = NULL;
+    PS(node)->Level = 1;
+    PS(node)->TotalDummy = PS(node)->TapeRange;
+
+    PS(node)->using_tape_files = true;
 }
 
 /*
- *	resetpsort	- resets (frees) malloc'd memory for an aborted Xaction
+ *	resetpsort	- resets (pfrees) palloc'd memory for an aborted Xaction
  *
  *	Not implemented yet.
  */
@@ -170,16 +213,18 @@ resetpsort()
  *		LEN field must be a short; FP is a stream
  */
 
-#define	PUTTUP(TUP, FP)\
-    BytesWritten += (TUP)->t_len; \
-    fwrite((char *)TUP, (TUP)->t_len, 1, FP)
+
+#define	PUTTUP(NODE, TUP, FP) if (1) {\
+    ((Psortstate *)NODE->psortstate)->BytesWritten += (TUP)->t_len; \
+    fwrite((char *)TUP, (TUP)->t_len, 1, FP);} else
 #define	ENDRUN(FP)	fwrite((char *)&shortzero, sizeof (shortzero), 1, FP)
 #define	GETLEN(LEN, FP)	fread((char *)&(LEN), sizeof (shortzero), 1, FP)
 #define	ALLOCTUP(LEN)	((HeapTuple)palloc((unsigned)LEN))
-#define	GETTUP(TUP, LEN, FP)\
+#define	GETTUP(NODE, TUP, LEN, FP) if (1) {\
     IncrProcessed(); \
-    BytesRead += (LEN) - sizeof (shortzero); \
-    fread((char *)(TUP) + sizeof (shortzero), (LEN) - sizeof (shortzero), 1, FP)
+    ((Psortstate *)NODE->psortstate)->BytesRead += (LEN) - sizeof (shortzero); \
+    fread((char *)(TUP) + sizeof (shortzero), (LEN) - sizeof (shortzero), 1, FP);} \
+				else
 #define	SETTUPLEN(TUP, LEN)	(TUP)->t_len = LEN
     
     /*
@@ -188,9 +233,9 @@ resetpsort()
      *	FULLMEM		- 1 iff a tuple will fit
      */
     
-#define	USEMEM(AMT)	SortMemory -= (AMT)
-#define	FREEMEM(AMT)	SortMemory += (AMT)
-#define	LACKMEM()	(SortMemory <= BLCKSZ)		/* not accurate */
+#define	USEMEM(NODE,AMT)	PS(node)->treeContext.sortMem -= (AMT)
+#define	FREEMEM(NODE,AMT)	PS(node)->treeContext.sortMem += (AMT)
+#define	LACKMEM(NODE)		(PS(node)->treeContext.sortMem <= MAXBLCKSZ)	/* not accurate */
 #define	TRACEMEM(FUNC)
 #define	TRACEOUT(FUNC, TUP)
 
@@ -219,61 +264,66 @@ resetpsort()
  *		Also, perhaps allocate tapes when needed. Split into 2 funcs.
  */
 void
-initialrun(Relation rdesc)
+initialrun(Sort *node, bool *empty)
 {
     /*	register struct	tuple	*tup; */
     register struct	tape	*tp;
-    HeapScanDesc	sdesc;
     int		baseruns;		/* D:(a) */
-    int		morepasses;		/* EOF */
-    
-    sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 0,
-			   (ScanKey)NULL);
-    tp = Tape;
+    int		extrapasses;		/* EOF */
+
+    Assert(node != (Sort *) NULL);
+    Assert(PS(node) != (Psortstate *) NULL);
+
+    tp = PS(node)->Tape;
     
-    if ((bool)createrun(sdesc, tp->tp_file) != false)
-	morepasses = 0;
+    if ((bool)createrun(node, tp->tp_file, empty) != false) {
+	if (! PS(node)->using_tape_files)
+	    inittapes(node);
+	extrapasses = 0;
+    }
     else
-	morepasses = 1 + (Tuples != NULL); 	/* (T != N) ? 2 : 1 */
+	return;	/* if rows fit in memory, we never access tape stuff */
     
     for ( ; ; ) {
 	tp->tp_dummy--;
-	TotalDummy--;
+	PS(node)->TotalDummy--;
 	if (tp->tp_dummy < (tp + 1)->tp_dummy)
 	    tp++;
 	else if (tp->tp_dummy != 0)
-	    tp = Tape;
+	    tp = PS(node)->Tape;
 	else {
-	    Level++;
-	    baseruns = Tape[0].tp_fib;
-	    for (tp = Tape; tp - Tape < TapeRange; tp++) {
-		TotalDummy +=
+	    PS(node)->Level++;
+	    baseruns = PS(node)->Tape[0].tp_fib;
+	    for (tp = PS(node)->Tape;
+		 tp - PS(node)->Tape < PS(node)->TapeRange; tp++) {
+		PS(node)->TotalDummy +=
 		    (tp->tp_dummy = baseruns
 		     + (tp + 1)->tp_fib
 		     - tp->tp_fib);
 		tp->tp_fib = baseruns
 		    + (tp + 1)->tp_fib;
 	    }
-	    tp = Tape;			/* D4 */
+	    tp = PS(node)->Tape;		/* D4 */
 	}					/* D3 */
-	if (morepasses)
-	    if (--morepasses) {
-		dumptuples(tp->tp_file);
+	if (extrapasses)
+	    if (--extrapasses) {
+		dumptuples(node);
 		ENDRUN(tp->tp_file);
 		continue;
 	    } else
 		break;
-	if ((bool)createrun(sdesc, tp->tp_file) == false)
-	    morepasses = 1 + (Tuples != NULL);
+
+	if ((bool)createrun(node, tp->tp_file, empty) == false)
+	    extrapasses = 1 + (PS(node)->Tuples != NULL);
 	/* D2 */
     }
-    for (tp = Tape + TapeRange; tp >= Tape; tp--)
-	rewind(tp->tp_file);				/* D. */
-    heap_endscan(sdesc);
+    for (tp = PS(node)->Tape + PS(node)->TapeRange; tp >= PS(node)->Tape; tp--)
+	rewind(tp->tp_file);			    /* D. */
 }
 
 /*
- *	createrun	- places the next run on file
+ *      createrun       - places the next run on file, grabbing the tuples by
+ *			executing the subplan passed in
  *
  *	Uses:
  *		Tuples, which should contain any tuples for this run
@@ -283,7 +333,7 @@ initialrun(Relation rdesc)
  *		Tuples contains the tuples for the following run upon exit
  */
 bool
-createrun(HeapScanDesc sdesc, FILE *file)
+createrun(Sort *node, FILE *file, bool *empty)
 {
     register HeapTuple	lasttuple;
     register HeapTuple	btup, tup;
@@ -291,47 +341,74 @@ createrun(HeapScanDesc sdesc, FILE *file)
     Buffer	b;
     bool		foundeor;
     short		junk;
-    
+
+    int cr_tuples = 0; /* Count tuples grabbed from plannode */
+    TupleTableSlot *cr_slot;
+
+    Assert(node != (Sort *) NULL);
+    Assert(PS(node) != (Psortstate *) NULL);
+
     lasttuple = NULL;
     nextrun = NULL;
     foundeor = false;
     for ( ; ; ) {
-	while (LACKMEM() && Tuples != NULL) {
+	while (LACKMEM(node) && PS(node)->Tuples != NULL) {
 	    if (lasttuple != NULL) {
-		FREEMEM(lasttuple->t_len);
+		FREEMEM(node,lasttuple->t_len);
 		FREE(lasttuple);
 		TRACEMEM(createrun);
 	    }
-	    lasttuple = tup = gettuple(&Tuples, &junk);
-	    PUTTUP(tup, file);
+	    lasttuple = tup = gettuple(&PS(node)->Tuples, &junk,
+				       &PS(node)->treeContext);
+	    if (! PS(node)->using_tape_files)
+		inittapes(node);
+	    PUTTUP(node, tup, PS(node)->Tape->tp_file);
 	    TRACEOUT(createrun, tup);
 	}
-	if (LACKMEM())
+	if (LACKMEM(node))
 	    break;
-	btup = heap_getnext(sdesc, 0, &b);
-	if (!HeapTupleIsValid(btup)) {
+
+	/* About to call ExecProcNode, it can mess up the state if it
+	 * eventually calls another Sort node. So must stow it away here for
+	 * the meantime.					-Rex 2.2.1995
+	 */
+
+	cr_slot = ExecProcNode(outerPlan((Plan *)node), (Plan *)node);
+
+	if (TupIsNull(cr_slot)) {
 	    foundeor = true;
 	    break;
 	}
+	else {
+	    tup = tuplecopy(cr_slot->val);
+	    ExecClearTuple(cr_slot);
+	    PS(node)->tupcount++;
+	    cr_tuples++;
+	}
+
 	IncrProcessed();
-	tup = tuplecopy(btup, sdesc->rs_rd, b);
-	USEMEM(tup->t_len);
+	USEMEM(node,tup->t_len);
 	TRACEMEM(createrun);
-	if (lasttuple != NULL && tuplecmp(tup, lasttuple))
-	    puttuple(&nextrun, tup, 0);
+	if (lasttuple != NULL && tuplecmp(tup, lasttuple,
+					  &PS(node)->treeContext))
+	    puttuple(&nextrun, tup, 0, &PS(node)->treeContext);
 	else
-	    puttuple(&Tuples, tup, 0);
-	ReleaseBuffer(b);
+	    puttuple(&PS(node)->Tuples, tup, 0, &PS(node)->treeContext);
     }
     if (lasttuple != NULL) {
-	FREEMEM(lasttuple->t_len);
+	FREEMEM(node,lasttuple->t_len);
 	FREE(lasttuple);
 	TRACEMEM(createrun);
     }
-    dumptuples(file);
-    ENDRUN(file);
+    dumptuples(node);
+    if (PS(node)->using_tape_files)
+	ENDRUN(file);
     /* delimit the end of the run */
-    Tuples = nextrun;
+    PS(node)->Tuples = nextrun;
+
+    /* if we did not see any tuples, mark empty */
+    *empty = (cr_tuples > 0) ? false : true;
+
     return((bool)! foundeor); /* XXX - works iff bool is {0,1} */
 }
 
@@ -339,10 +416,10 @@ createrun(HeapScanDesc sdesc, FILE *file)
  *	tuplecopy	- see also tuple.c:palloctup()
  *
  *	This should eventually go there under that name?  And this will
- *	then use malloc directly (see version -r1.2).
+ *	then use palloc directly (see version -r1.2).
  */
 HeapTuple
-tuplecopy(HeapTuple tup, Relation rdesc, Buffer b)
+tuplecopy(HeapTuple tup)
 {
     HeapTuple	rettup;
     
@@ -362,18 +439,22 @@ tuplecopy(HeapTuple tup, Relation rdesc, Buffer b)
  *		file of tuples in order
  */
 FILE *
-mergeruns()
+mergeruns(Sort *node)
 {
-    register struct	tape	*tp;
-    
-    tp = Tape + TapeRange;
-    merge(tp);
+    register struct     tape    *tp;
+
+    Assert(node != (Sort *) NULL);
+    Assert(PS(node) != (Psortstate *) NULL);
+    Assert(PS(node)->using_tape_files == true);
+
+    tp = PS(node)->Tape + PS(node)->TapeRange;
+    merge(node, tp);
     rewind(tp->tp_file);
-    while (--Level != 0) {
+    while (--PS(node)->Level != 0) {
 	tp = tp->tp_prev;
 	rewind(tp->tp_file);
-	/*		resettape(tp->tp_file);		-not sufficient */
-	merge(tp);
+	/*	      resettape(tp->tp_file);	 -not sufficient */
+	merge(node, tp);
 	rewind(tp->tp_file);
     }
     return(tp->tp_file);
@@ -384,7 +465,7 @@ mergeruns()
  *			  (polyphase merge Alg.D(D5)--Knuth, Vol.3, p271)
  */
 void
-merge(struct tape *dest)
+merge(Sort *node, struct tape *dest)
 {
     register HeapTuple	tup;
     register struct	tape	*lasttp;	/* (TAPE[P]) */
@@ -396,6 +477,10 @@ merge(struct tape *dest)
     short		fromtape;
     long		tuplen;
     
+    Assert(node != (Sort *) NULL);
+    Assert(PS(node) != (Psortstate *) NULL);
+    Assert(PS(node)->using_tape_files == true);
+
     lasttp = dest->tp_prev;
     times = lasttp->tp_fib;
     for (tp = lasttp ; tp != dest; tp = tp->tp_prev)
@@ -403,95 +488,217 @@ merge(struct tape *dest)
     tp->tp_fib += times;
     /* Tape[].tp_fib (A[]) is set to proper exit values */
     
-    if (TotalDummy < TapeRange)		/* no complete dummy runs */
+    if (PS(node)->TotalDummy < PS(node)->TapeRange)/* no complete dummy runs */
 	outdummy = 0;
     else {
-	outdummy = TotalDummy;		/* a large positive number */
+	outdummy = PS(node)->TotalDummy;	/* a large positive number */
 	for (tp = lasttp; tp != dest; tp = tp->tp_prev)
 	    if (outdummy > tp->tp_dummy)
 		outdummy = tp->tp_dummy;
 	for (tp = lasttp; tp != dest; tp = tp->tp_prev)
 	    tp->tp_dummy -= outdummy;
 	tp->tp_dummy += outdummy;
-	TotalDummy -= outdummy * TapeRange;
+	PS(node)->TotalDummy -= outdummy * PS(node)->TapeRange;
 	/* do not add the outdummy runs yet */
 	times -= outdummy;
     }
     destfile = dest->tp_file;
-    while (times-- != 0) {			/* merge one run */
+    while (times-- != 0) {		      /* merge one run */
 	tuples = NULL;
-	if (TotalDummy == 0)
+	if (PS(node)->TotalDummy == 0)
 	    for (tp = dest->tp_prev; tp != dest; tp = tp->tp_prev) {
 		GETLEN(tuplen, tp->tp_file);
 		tup = ALLOCTUP(tuplen);
-		USEMEM(tuplen);
+		USEMEM(node,tuplen);
 		TRACEMEM(merge);
 		SETTUPLEN(tup, tuplen);
-		GETTUP(tup, tuplen, tp->tp_file);
-		puttuple(&tuples, tup, TAPENO(tp));
+		GETTUP(node, tup, tuplen, tp->tp_file);
+		puttuple(&tuples, tup, tp - PS(node)->Tape,
+			 &PS(node)->treeContext);
 	    }
 	else {
 	    for (tp = dest->tp_prev; tp != dest; tp = tp->tp_prev) {
 		if (tp->tp_dummy != 0) {
 		    tp->tp_dummy--;
-		    TotalDummy--;
+		    PS(node)->TotalDummy--;
 		} else {
 		    GETLEN(tuplen, tp->tp_file);
 		    tup = ALLOCTUP(tuplen);
-		    USEMEM(tuplen);
+		    USEMEM(node,tuplen);
 		    TRACEMEM(merge);
 		    SETTUPLEN(tup, tuplen);
-		    GETTUP(tup, tuplen, tp->tp_file);
-		    puttuple(&tuples, tup, TAPENO(tp));
+		    GETTUP(node, tup, tuplen, tp->tp_file);
+		    puttuple(&tuples, tup, tp - PS(node)->Tape,
+			     &PS(node)->treeContext);
 		}
 	    }
 	}
 	while (tuples != NULL) {
 	    /* possible optimization by using count in tuples */
-	    tup = gettuple(&tuples, &fromtape);
-	    PUTTUP(tup, destfile);
-	    FREEMEM(tup->t_len);
+	    tup = gettuple(&tuples, &fromtape, &PS(node)->treeContext);
+	    PUTTUP(node, tup, destfile);
+	    FREEMEM(node,tup->t_len);
 	    FREE(tup);
 	    TRACEMEM(merge);
-	    GETLEN(tuplen, Tape[fromtape].tp_file);
+	    GETLEN(tuplen, PS(node)->Tape[fromtape].tp_file);
 	    if (tuplen == 0)
 		;
 	    else {
 		tup = ALLOCTUP(tuplen);
-		USEMEM(tuplen);
+		USEMEM(node,tuplen);
 		TRACEMEM(merge);
 		SETTUPLEN(tup, tuplen);
-		GETTUP(tup, tuplen, Tape[fromtape].tp_file);
-		puttuple(&tuples, tup, fromtape);
+		GETTUP(node, tup, tuplen, PS(node)->Tape[fromtape].tp_file);
+		puttuple(&tuples, tup, fromtape, &PS(node)->treeContext);
 	    }
-	}				
+	} 
 	ENDRUN(destfile);
     }
-    TotalDummy += outdummy;
+    PS(node)->TotalDummy += outdummy;
 }
 
 /*
- *	endpsort	- creates the new relation and unlinks the tape files
+ * dumptuples	- stores all the tuples in tree into file
  */
 void
-endpsort(Relation rdesc, FILE *file)
+dumptuples(Sort *node)
 {
-    register struct	tape	*tp;
-    register HeapTuple	tup;
-    long		tuplen;
+    register struct	leftist	*tp;
+    register struct	leftist	*newp;
+    struct leftist **treep = &PS(node)->Tuples;
+    LeftistContext context = &PS(node)->treeContext;
+    HeapTuple	tup;
+    int memtupindex = 0;
+
+    if (! PS(node)->using_tape_files) {
+	Assert(PS(node)->memtuples == NULL);
+    	PS(node)->memtuples = palloc(PS(node)->tupcount * sizeof(HeapTuple));
+    }
     
-    if (! feof(file))
-	while (GETLEN(tuplen, file) && tuplen != 0) {
-	    tup = ALLOCTUP(tuplen);
-	    SortMemory += tuplen;
-	    SETTUPLEN(tup, tuplen);
-	    GETTUP(tup, tuplen, file);
-	    heap_insert(rdesc, tup);
+    tp = *treep;
+    while (tp != NULL) {
+	tup = tp->lt_tuple;
+	if (tp->lt_dist == 1)			/* lt_right == NULL */
+	    newp = tp->lt_left;
+	else
+	    newp = lmerge(tp->lt_left, tp->lt_right, context);
+	FREEMEM(node,sizeof (struct leftist));
+	FREE(tp);
+	if (PS(node)->using_tape_files) {
+	    PUTTUP(node, tup, PS(node)->Tape->tp_file);
+	    FREEMEM(node,tup->t_len);
 	    FREE(tup);
-	    SortMemory -= tuplen;
 	}
-    for (tp = Tape + TapeRange; tp >= Tape; tp--)
-	destroytape(tp->tp_file);
+	else
+	    PS(node)->memtuples[memtupindex++] = tup;
+
+	tp = newp;
+    }
+    *treep = NULL;
+}
+
+/*
+ *      psort_grabtuple - gets a tuple from the sorted file and returns it.
+ *			  If there are no tuples left, returns NULL.
+ *			  Should not call psort_end unless this has returned
+ *		          a NULL indicating the last tuple has been processed.
+ */
+HeapTuple
+psort_grabtuple(Sort *node)
+{
+    register HeapTuple  tup;
+    long		tuplen;
+
+    Assert(node != (Sort *) NULL);
+    Assert(PS(node) != (Psortstate *) NULL);
+
+    if (PS(node)->using_tape_files == true) {
+	if (!feof(PS(node)->psort_grab_file)) {
+	    if (GETLEN(tuplen, PS(node)->psort_grab_file) && tuplen != 0) {
+	    	tup = (HeapTuple)palloc((unsigned)tuplen);
+		SETTUPLEN(tup, tuplen);
+	    	GETTUP(node, tup, tuplen, PS(node)->psort_grab_file);
+
+	    	/* Update current merged sort file position */
+		PS(node)->psort_current += tuplen;
+
+	    	return tup;
+	    }
+	    else
+	    	return NULL;
+    	}
+    	else
+	    return NULL;
+    }
+    else {
+    	if (PS(node)->psort_current < PS(node)->tupcount)
+	    return PS(node)->memtuples[PS(node)->psort_current++];
+    	else
+	    return NULL;
+    }
+}
+
+/*
+ *      psort_markpos   - saves current position in the merged sort file
+ */
+void
+psort_markpos(Sort *node)
+{
+    Assert(node != (Sort *) NULL);
+    Assert(PS(node) != (Psortstate *) NULL);
+
+    PS(node)->psort_saved = PS(node)->psort_current;
+}
+
+/*
+ *      psort_restorepos- restores current position in merged sort file to
+ *			  last saved position
+ */
+void
+psort_restorepos(Sort *node)
+{
+    Assert(node != (Sort *) NULL);
+    Assert(PS(node) != (Psortstate *) NULL);
+
+    if (PS(node)->using_tape_files == true)
+	fseek(PS(node)->psort_grab_file, PS(node)->psort_saved, SEEK_SET);
+    PS(node)->psort_current = PS(node)->psort_saved;
+}
+
+/*
+ *      psort_end       - unlinks the tape files, and cleans up. Should not be
+ *			  called unless psort_grabtuple has returned a NULL.
+ */
+void
+psort_end(Sort *node)
+{
+    register struct     tape    *tp;
+
+    if (!node->cleaned) {
+	Assert(node != (Sort *) NULL);
+/* 	Assert(PS(node) != (Psortstate *) NULL); */
+
+	/*
+	 * I'm changing this because if we are sorting a relation
+	 * with no tuples, psortstate is NULL.
+	 */
+	if (PS(node) != (Psortstate *) NULL) {
+	    if (PS(node)->using_tape_files == true)
+		for (tp = PS(node)->Tape + PS(node)->TapeRange; tp >= PS(node)->Tape; tp--)
+		    destroytape(tp->tp_file);
+	    else if (PS(node)->memtuples)
+		pfree(PS(node)->memtuples);
+	    
+	    NDirectFileRead +=
+		(int)ceil((double)PS(node)->BytesRead / BLCKSZ);
+	    NDirectFileWrite +=
+		(int)ceil((double)PS(node)->BytesWritten / BLCKSZ);
+
+	    pfree((void *)node->psortstate);
+
+	    node->cleaned = TRUE;
+	}
+    }
 }
 
 /*
@@ -522,26 +729,34 @@ static char	Tempfile[MAXPGPATH] = TEMPDIR;
 FILE *
 gettape()
 {
-    register struct	tapelst	*tp;
-    FILE		*file;
-    static	int	tapeinit = 0;
+    register 	struct		tapelst	*tp;
+    FILE			*file;
+    static	int		tapeinit = 0;
+    char			*mktemp();
+    static	unsigned int	uniqueFileId = 0;
+    extern	int		errno;
+    char			uniqueName[MAXPGPATH];
     
     tp = (struct tapelst *)palloc((unsigned)sizeof (struct tapelst));
-    if (!tapeinit) {
-	Tempfile[sizeof (TEMPDIR) - 1] = '/';
-	memmove(Tempfile + sizeof(TEMPDIR), TAPEEXT, sizeof (TAPEEXT));
-	tapeinit = 1;
-    }
-    tp->tl_name = palloc((unsigned)sizeof(Tempfile));
+    
+    sprintf(uniqueName, "%spg_psort.%d.%d", TEMPDIR, getpid(), uniqueFileId);
+    uniqueFileId++;
+    
+    tapeinit = 1;
+    
+    tp->tl_name = palloc((unsigned)sizeof(uniqueName));
+    
     /*
-     * now, copy template with final null into malloc'd space
+     * now, copy template with final null into palloc'd space
      */
-    memmove(tp->tl_name, Tempfile, sizeof (TEMPDIR) + sizeof (TAPEEXT));
-    mktemp(tp->tl_name);
+    
+    memmove(tp->tl_name, uniqueName, strlen(uniqueName));
+    
     
     AllocateFile();
     file = fopen(tp->tl_name, "w+");
     if (file == NULL) {
+	elog(NOTICE, "psort: gettape: fopen returned error code %i", errno);
 	/* XXX this should not happen */
 	FreeFile();
 	FREE(tp->tl_name);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 3e01132faa303804477c0b9dadb6f530ca6566d2..ff01ff5a62e984a8473530a91732cc044a14d194 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execnodes.h,v 1.6 1996/11/04 08:52:54 scrappy Exp $
+ * $Id: execnodes.h,v 1.7 1997/08/06 03:42:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -605,7 +605,7 @@ typedef struct SortState {
     CommonScanState	csstate;	/* its first field is NodeTag */
     bool      		sort_Flag;
     ScanKey   		sort_Keys;
-    Relation  		sort_TempRelation;
+    bool		cleaned;
 } SortState;
 
 /* ----------------
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index b02a370facddb8bf64a8e64de0ff58f7e3955552..6e786c34f0e7d36022b75ab48fca53f1bb5cfca1 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plannodes.h,v 1.5 1996/11/05 08:18:44 scrappy Exp $
+ * $Id: plannodes.h,v 1.6 1997/08/06 03:42:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -265,6 +265,8 @@ typedef struct Sort {
     Oid			tempid;
     int			keycount;
     SortState		*sortstate;
+    void		*psortstate;
+    bool		cleaned;
 } Sort;
 
 /* ----------------
diff --git a/src/include/utils/lselect.h b/src/include/utils/lselect.h
index 7cb5f8d185ecdfe31817a89d90d65c56832ccc09..048ea932e28ce7747fb2a8943f908f4a8dec47e7 100644
--- a/src/include/utils/lselect.h
+++ b/src/include/utils/lselect.h
@@ -6,15 +6,15 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lselect.h,v 1.3 1996/11/04 11:51:19 scrappy Exp $
- *
+ * $Id: lselect.h,v 1.4 1997/08/06 03:42:07 momjian Exp $
+ * 
  *-------------------------------------------------------------------------
  */
 #ifndef	LSELECT_H
 #define	LSELECT_H
 
 #include <stdio.h>
-#include <access/htup.h>
+#include "access/htup.h"
 
 struct	leftist {
     short	lt_dist; 	/* distance to leaf/empty node */
@@ -24,17 +24,26 @@ struct	leftist {
     struct	leftist	*lt_right;
 };
 
-extern	struct	leftist	*Tuples;
+/* replaces global variables in lselect.c to make it reentrant */
+typedef struct {
+    TupleDesc tupDesc;
+    int nKeys;
+    ScanKey scanKeys;
+    int sortMem; /* needed for psort */
+} LeftistContextData;
+typedef LeftistContextData *LeftistContext;
 
-extern struct leftist *lmerge(struct leftist *pt, struct leftist *qt);
-extern HeapTuple gettuple(struct leftist **treep, short *devnum);
-extern int puttuple(struct leftist **treep, HeapTuple newtuple, int devnum);
-extern void dumptuples(FILE *file);
-extern int tuplecmp(HeapTuple ltup, HeapTuple rtup);
+extern struct leftist *lmerge(struct leftist *pt, struct leftist *qt,
+    LeftistContext context);
+extern HeapTuple gettuple(struct leftist **treep, short *devnum,
+    LeftistContext context);
+extern void puttuple(struct leftist **treep, HeapTuple newtuple, short devnum,
+    LeftistContext context);
+extern int tuplecmp(HeapTuple ltup, HeapTuple rtup, LeftistContext context);
 
 #ifdef EBUG
-extern void checktree(struct leftist *tree);
-extern int checktreer(struct leftist *tree, int level);
+extern void checktree(struct leftist *tree, LeftistContext context);
+extern int checktreer(struct leftist *tree, int level, LeftistContext context);
 #endif /* EBUG */
 
 #endif 	/* LSELECT_H */
diff --git a/src/include/utils/psort.h b/src/include/utils/psort.h
index 169c4bdc70fdf5b462705d763d25c4ae56392736..7ece609020337627266f769086790d388afcc78c 100644
--- a/src/include/utils/psort.h
+++ b/src/include/utils/psort.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: psort.h,v 1.3 1997/05/20 11:37:33 vadim Exp $
+ * $Id: psort.h,v 1.4 1997/08/06 03:42:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -14,11 +14,13 @@
 #define	PSORT_H
 
 #include <stdio.h>
-#include <access/relscan.h>
+#include "access/relscan.h"
+#include "utils/lselect.h"
+#include "nodes/plannodes.h"
 
 #define	SORTMEM		(1 << 18)		/* 1/4 M - any static memory */
 #define	MAXTAPES	7			/* 7--See Fig. 70, p273 */
-#define	TAPEEXT		"pg_psort.XXXXXX"	/* TEMPDIR/TAPEEXT */
+#define	TAPEEXTLEN	strlen("pg_psort.xxxxx.xxx")	/* TEMPDIR/TAPEEXT */
 #define	FREE(x)		pfree((char *) x)
 
 struct	tape {
@@ -35,13 +37,38 @@ struct	cmplist {
     struct	cmplist		*cp_next; /* next in chain */
 };
 
-extern	int		Nkeys;
-extern	ScanKey		key;
-extern	int		SortMemory;	/* free memory */
-extern	Relation	SortRdesc;
-extern	struct leftist	*Tuples;
+/* This structure preserves the state of psort between calls from different
+ * nodes to its interface functions. Basically, it includes all of the global
+ * variables in psort. In case you were wondering, pointers to these structures
+ * are included in Sort node structures.			-Rex 2.6.1995
+ */
+typedef struct Psortstate {
+    LeftistContextData treeContext;
+
+    int TapeRange;
+    int Level;
+    int TotalDummy;
+    struct tape Tape[MAXTAPES];
+
+    int BytesRead;
+    int BytesWritten;
+    int tupcount;
+
+    struct leftist *Tuples;
+
+    FILE *psort_grab_file;
+    long psort_current;	/* could be file offset, or array index */
+    long psort_saved;	/* could be file offset, or array index */
+    bool using_tape_files;
+
+    HeapTuple *memtuples;
+} Psortstate;
 
 #ifdef	EBUG
+#include <stdio.h>
+#include "utils/elog.h"
+#include "storage/buf.h"
+#include "storage/bufmgr.h"
 
 #define	PDEBUG(PROC, S1)\
 elog(DEBUG, "%s:%d>> PROC: %s.", __FILE__, __LINE__, S1)
@@ -69,15 +96,21 @@ if (1) CODE; else
 #endif
 
 /* psort.c */
-extern void psort(Relation oldrel, Relation newrel, int nkeys, ScanKey key);
-extern void initpsort(void);
+extern bool psort_begin(Sort *node, int nkeys, ScanKey key);
+extern void inittapes(Sort *node);
 extern void resetpsort(void);
-extern void initialrun(Relation rdesc);
-extern bool createrun(HeapScanDesc sdesc, FILE *file);
-extern HeapTuple tuplecopy(HeapTuple tup, Relation rdesc, Buffer b);
-extern FILE *mergeruns(void);
-extern void merge(struct tape *dest);
-extern void endpsort(Relation rdesc, FILE *file);
+extern void initialrun(Sort *node, bool *empty);
+extern bool createrun(Sort *node, FILE *file, bool *empty);
+extern HeapTuple tuplecopy(HeapTuple tup);
+extern FILE *mergeruns(Sort *node);
+extern void merge(Sort *node, struct tape *dest);
+
+extern void dumptuples(Sort *node);
+extern HeapTuple psort_grabtuple(Sort *node);
+extern void psort_markpos(Sort *node);
+extern void psort_restorepos(Sort *node);
+extern void psort_end(Sort *node);
+
 extern FILE *gettape(void);
 extern void resettape(FILE *file);
 extern void destroytape(FILE *file);
diff --git a/src/man/postgres.1 b/src/man/postgres.1
index 940e1822f9f46a44b6d11f2b354657d57b5e99a2..287e7347931ffbbdc6221cdb94f91c617c359c24 100644
--- a/src/man/postgres.1
+++ b/src/man/postgres.1
@@ -1,6 +1,6 @@
 .\" This is -*-nroff-*-
 .\" XXX standard disclaimer belongs here....
-.\" $Header: /cvsroot/pgsql/src/man/Attic/postgres.1,v 1.5 1997/01/26 15:32:20 scrappy Exp $
+.\" $Header: /cvsroot/pgsql/src/man/Attic/postgres.1,v 1.6 1997/08/06 03:42:18 momjian Exp $
 .TH POSTGRES95 UNIX 12/08/96 Postgres95 Postgres95
 .SH NAME
 postgres \(em the Postgres backend server
@@ -79,7 +79,10 @@ is the number of shared-memory buffers that the
 .IR "postmaster"
 has allocated for the backend server processes that it starts.  If the
 backend is running standalone, this specifies the number of buffers to
-allocate.  This value defaults to 64.
+allocate.  This value defaults to 64, and each buffer is 8k bytes.
+.TP
+.BR "-E"
+Echo all queries.
 .TP
 .BR "-F"
 Disable automatic fsync() call after each transaction.
@@ -89,15 +92,17 @@ while a transaction is in progress will probably cause data loss.
 .BR "-P" " filedes"
 .IR "filedes"
 specifies the file descriptor that corresponds to the socket (port) on
-which to communicate to the frontend process.  This option is 
+which to communicate to the frontend process.  This option is
 .BR not
 useful for interactive use.
 .TP
 .BR "-Q"
 Specifies \*(lqquiet\*(rq mode.
 .TP
-.BR "-E"
-Echo all queries.
+.BR "-S"
+Specifies the amount of memory to be used by internal sorts before using
+disk files for sorting.  This value is specified in 1k bytes, and
+defaults to 512.
 .TP
 .BR "-e"
 The
@@ -154,15 +159,6 @@ Turns off the locking system.
 .BR "-N"
 Disables use of newline as a query delimiter.
 .TP
-.BR "-S"
-Indicates that the transaction system can run with the assumption of
-stable main memory, thereby avoiding the necessary flushing of data
-and log pages to disk at the end of each transaction system.  This is
-only used for performance comparisons for stable vs. non-stable
-storage.  Do not use this in other cases, as recovery after a system
-crash may be impossible when this option is specified in the absence
-of stable main memory.
-.TP
 .BR "-b"
 Enables generation of bushy query plan trees (as opposed to left-deep
 query plans trees).  These query plans are not intended for actual
diff --git a/src/man/postmaster.1 b/src/man/postmaster.1
index 5b01b727020971a8480026881a34d60d300a67da..41e7b73bfd4933f8e7cd49f2e508a2c96cfcf909 100644
--- a/src/man/postmaster.1
+++ b/src/man/postmaster.1
@@ -1,6 +1,6 @@
 .\" This is -*-nroff-*-
 .\" XXX standard disclaimer belongs here....
-.\" $Header: /cvsroot/pgsql/src/man/Attic/postmaster.1,v 1.5 1997/02/19 01:31:30 momjian Exp $
+.\" $Header: /cvsroot/pgsql/src/man/Attic/postmaster.1,v 1.6 1997/08/06 03:42:21 momjian Exp $
 .TH POSTMASTER UNIX 11/05/95 PostgreSQL PostgreSQL
 .SH "NAME"
 postmaster \(em run the Postgres postmaster
@@ -60,7 +60,7 @@ understands the following command-line options:
 is the number of shared-memory buffers for the 
 .IR "postmaster"
 to allocate and manage for the backend server processes that it
-starts.  This value defaults to 64.
+starts.  This value defaults to 64, and each buffer is 8k bytes.
 .TP
 .BR "-D" " data_dir"
 Specifies the directory to use as the root of the tree of database