From 1aebc3618a0be13451918581ad390ad9a3518702 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 28 Jun 2000 03:33:33 +0000
Subject: [PATCH] First phase of memory management rewrite (see
 backend/utils/mmgr/README for details).  It doesn't really do that much yet,
 since there are no short-term memory contexts in the executor, but the
 infrastructure is in place and long-term contexts are handled reasonably.  A
 few long- standing bugs have been fixed, such as 'VACUUM; anything' in a
 single query string crashing.  Also, out-of-memory is now considered a
 recoverable ERROR, not FATAL. Eliminate a large amount of crufty, now-dead
 code in and around memory management. Fix problem with holding off SIGTRAP,
 SIGSEGV, etc in postmaster and backend startup.

---
 doc/src/sgml/geqo.sgml                     |  18 +-
 doc/src/sgml/ref/declare.sgml              |   9 +-
 src/backend/Makefile                       |   4 +-
 src/backend/access/heap/heapam.c           |   5 +-
 src/backend/access/transam/xact.c          | 238 ++++---
 src/backend/bootstrap/bootstrap.c          |  40 +-
 src/backend/catalog/heap.c                 |  32 +-
 src/backend/catalog/index.c                |  18 +-
 src/backend/catalog/pg_proc.c              |   5 +-
 src/backend/commands/command.c             |  66 +-
 src/backend/commands/indexcmds.c           |  35 +-
 src/backend/commands/trigger.c             |  39 +-
 src/backend/commands/user.c                |   4 +-
 src/backend/commands/vacuum.c              | 110 +--
 src/backend/executor/functions.c           |   6 +-
 src/backend/executor/nodeAgg.c             |  10 +-
 src/backend/executor/nodeHash.c            |  50 +-
 src/backend/executor/spi.c                 | 166 ++---
 src/backend/lib/Makefile                   |   4 +-
 src/backend/lib/fstack.c                   | 145 ----
 src/backend/lib/stringinfo.c               |  15 +-
 src/backend/libpq/be-fsstubs.c             |  41 +-
 src/backend/libpq/be-pqexec.c              |   6 +-
 src/backend/libpq/pqsignal.c               |  40 +-
 src/backend/optimizer/geqo/geqo_eval.c     |  67 +-
 src/backend/optimizer/geqo/geqo_main.c     |   5 +-
 src/backend/postmaster/postmaster.c        |  46 +-
 src/backend/rewrite/rewriteDefine.c        | 113 +--
 src/backend/rewrite/rewriteSupport.c       |  10 +-
 src/backend/storage/ipc/shmem.c            |  47 +-
 src/backend/storage/large_object/inv_api.c |   4 +-
 src/backend/storage/lmgr/lock.c            |  33 +-
 src/backend/storage/lmgr/proc.c            |  12 +-
 src/backend/storage/smgr/md.c              |  46 +-
 src/backend/tcop/postgres.c                | 240 ++++---
 src/backend/tcop/pquery.c                  | 178 ++---
 src/backend/utils/cache/catcache.c         |  91 ++-
 src/backend/utils/cache/relcache.c         |  25 +-
 src/backend/utils/cache/temprel.c          |   8 +-
 src/backend/utils/error/elog.c             |  61 +-
 src/backend/utils/fmgr/dfmgr.c             |   4 +-
 src/backend/utils/hash/dynahash.c          |  54 +-
 src/backend/utils/init/Makefile            |   5 +-
 src/backend/utils/init/enbl.c              |  47 --
 src/backend/utils/init/postinit.c          |  23 +-
 src/backend/utils/mb/conv.c                |  29 +-
 src/backend/utils/mmgr/Makefile            |   4 +-
 src/backend/utils/mmgr/README              | 379 ++++++++++
 src/backend/utils/mmgr/aset.c              | 365 +++++++---
 src/backend/utils/mmgr/mcxt.c              | 760 ++++++++++-----------
 src/backend/utils/mmgr/oset.c              | 165 -----
 src/backend/utils/mmgr/palloc.c            |  41 --
 src/backend/utils/mmgr/portalmem.c         | 741 ++------------------
 src/include/commands/command.h             |   3 +-
 src/include/executor/hashjoin.h            |  24 +-
 src/include/executor/spi.h                 |   3 +-
 src/include/executor/spi_priv.h            |   5 +-
 src/include/lib/fstack.h                   | 115 ----
 src/include/libpq/pqsignal.h               |  16 +-
 src/include/miscadmin.h                    |   7 +-
 src/include/nodes/memnodes.h               | 112 ++-
 src/include/nodes/nodes.h                  |   7 +-
 src/include/optimizer/geqo.h               |   3 +-
 src/include/postgres.h                     |   3 +-
 src/include/storage/shmem.h                |   7 +-
 src/include/tcop/pquery.h                  |  19 +-
 src/include/tcop/tcopprot.h                |   9 +-
 src/include/utils/catcache.h               |   6 +-
 src/include/utils/hsearch.h                |   7 +-
 src/include/utils/mcxt.h                   |  60 --
 src/include/utils/memutils.h               | 252 ++-----
 src/include/utils/module.h                 |  26 -
 src/include/utils/palloc.h                 |  79 ++-
 src/include/utils/portal.h                 |  55 +-
 74 files changed, 2278 insertions(+), 3249 deletions(-)
 delete mode 100644 src/backend/lib/fstack.c
 delete mode 100644 src/backend/utils/init/enbl.c
 create mode 100644 src/backend/utils/mmgr/README
 delete mode 100644 src/backend/utils/mmgr/oset.c
 delete mode 100644 src/backend/utils/mmgr/palloc.c
 delete mode 100644 src/include/lib/fstack.h
 delete mode 100644 src/include/utils/mcxt.h
 delete mode 100644 src/include/utils/module.h

diff --git a/doc/src/sgml/geqo.sgml b/doc/src/sgml/geqo.sgml
index fd6d58aca0..4f2f80e97a 100644
--- a/doc/src/sgml/geqo.sgml
+++ b/doc/src/sgml/geqo.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/geqo.sgml,v 1.9 2000/03/31 03:27:40 thomas Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/geqo.sgml,v 1.10 2000/06/28 03:30:53 tgl Exp $
 Genetic Optimizer
 -->
 
@@ -228,22 +228,6 @@ Improved cost size approximation of query plans since no longer
 <Sect2>
 <Title>Basic Improvements</Title>
 
-<Sect3>
-<Title>Improve freeing of memory when query is already processed</Title>
-
-<Para>
-With large <Command>join</Command> queries the computing time spent for the genetic query
-optimization seems to be a mere <Emphasis>fraction</Emphasis> of the time
- <ProductName>Postgres</ProductName>
-needs for freeing memory via routine <Function>MemoryContextFree</Function>,
-file <FileName>backend/utils/mmgr/mcxt.c</FileName>.
-Debugging showed that it get stucked in a loop of routine
-<Function>OrderedElemPop</Function>, file <FileName>backend/utils/mmgr/oset.c</FileName>.
-The same problems arise with long queries when using the normal
-<ProductName>Postgres</ProductName> query optimization algorithm.
-</para>
-</sect3>
-
 <Sect3>
 <Title>Improve genetic algorithm parameter settings</Title>
 
diff --git a/doc/src/sgml/ref/declare.sgml b/doc/src/sgml/ref/declare.sgml
index c3c8b52680..803949a1ea 100644
--- a/doc/src/sgml/ref/declare.sgml
+++ b/doc/src/sgml/ref/declare.sgml
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/declare.sgml,v 1.8 1999/12/30 22:58:10 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/declare.sgml,v 1.9 2000/06/28 03:30:54 tgl Exp $
 Postgres documentation
 -->
 
@@ -153,12 +153,13 @@ SELECT
 
      <varlistentry>
       <term><computeroutput>
-NOTICE
-BlankPortalAssignName: portal "<replaceable class="parameter">cursorname</replaceable>" already exists
+NOTICE:  Closing pre-existing portal "<replaceable class="parameter">cursorname</replaceable>"
        </computeroutput></term>
       <listitem>
        <para>
-	This error occurs if <replaceable class="parameter">cursorname</replaceable> is already declared.
+	This message is reported if the same cursor name was already declared
+	in the current transaction block.  The previous definition is
+	discarded.
        </para>
       </listitem>
      </varlistentry>
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 37a4a7bae9..ab691cef46 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -34,7 +34,7 @@
 #
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.55 2000/06/17 00:09:34 petere Exp $
+#    $Header: /cvsroot/pgsql/src/backend/Makefile,v 1.56 2000/06/28 03:30:57 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -237,8 +237,6 @@ install-headers: prebuildheaders $(SRCDIR)/include/config.h
           $(HEADERDIR)/utils/fmgroids.h
 	$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/palloc.h \
           $(HEADERDIR)/utils/palloc.h
-	$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/utils/mcxt.h \
-          $(HEADERDIR)/utils/mcxt.h
 	$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/access/attnum.h \
           $(HEADERDIR)/access/attnum.h
 	$(INSTALL) $(INSTLOPTS) $(SRCDIR)/include/executor/spi.h \
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index aacef2a66a..7ca83587a4 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.71 2000/06/15 04:09:34 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.72 2000/06/28 03:31:04 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -1230,10 +1230,7 @@ heap_insert(Relation relation, HeapTuple tup)
 	 * ----------------
 	 */
 	if (!OidIsValid(tup->t_data->t_oid))
-	{
 		tup->t_data->t_oid = newoid();
-		LastOidProcessed = tup->t_data->t_oid;
-	}
 	else
 		CheckMaxObjectId(tup->t_data->t_oid);
 
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index d6551cc9c9..bc8f968571 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.67 2000/06/18 22:43:51 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.68 2000/06/28 03:31:05 tgl Exp $
  *
  * NOTES
  *		Transaction aborts can now occur two ways:
@@ -18,14 +18,14 @@
  *
  *		These two cases used to be treated identically, but now
  *		we need to distinguish them.  Why?	consider the following
- *		two situatuons:
+ *		two situations:
  *
  *				case 1							case 2
  *				------							------
  *		1) user types BEGIN				1) user types BEGIN
  *		2) user does something			2) user does something
  *		3) user does not like what		3) system aborts for some reason
- *		   she shes and types ABORT
+ *		   she sees and types ABORT
  *
  *		In case 1, we want to abort the transaction and return to the
  *		default state.	In case 2, there may be more commands coming
@@ -42,6 +42,15 @@
  *		* AbortTransactionBlock() leaves us in TBLOCK_ABORT and
  *		* UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
  *
+ *		Low-level transaction abort handling is divided into two phases:
+ *		* AbortTransaction() executes as soon as we realize the transaction
+ *		  has failed.  It should release all shared resources (locks etc)
+ *		  so that we do not delay other backends unnecessarily.
+ *		* CleanupTransaction() executes when we finally see a user COMMIT
+ *		  or ROLLBACK command; it cleans things up and gets us out of
+ *		  the transaction internally.  In particular, we mustn't destroy
+ *		  TransactionCommandContext until this point.
+ *
  *	 NOTES
  *		This file is an attempt at a redesign of the upper layer
  *		of the V1 transaction system which was too poorly thought
@@ -70,7 +79,7 @@
  *				StartTransaction
  *				CommitTransaction
  *				AbortTransaction
- *				UserAbortTransaction
+ *				CleanupTransaction
  *
  *		are provided to do the lower level work like recording
  *		the transaction status in the log and doing memory cleanup.
@@ -151,13 +160,15 @@
 #include "commands/async.h"
 #include "commands/sequence.h"
 #include "commands/trigger.h"
+#include "executor/spi.h"
 #include "libpq/be-fsstubs.h"
 #include "storage/proc.h"
 #include "storage/sinval.h"
-#include "utils/temprel.h"
 #include "utils/inval.h"
+#include "utils/memutils.h"
 #include "utils/portal.h"
 #include "utils/relcache.h"
+#include "utils/temprel.h"
 
 extern bool SharedBufferChanged;
 
@@ -165,6 +176,7 @@ static void AbortTransaction(void);
 static void AtAbort_Cache(void);
 static void AtAbort_Locks(void);
 static void AtAbort_Memory(void);
+static void AtCleanup_Memory(void);
 static void AtCommit_Cache(void);
 static void AtCommit_LocalCache(void);
 static void AtCommit_Locks(void);
@@ -172,6 +184,7 @@ static void AtCommit_Memory(void);
 static void AtStart_Cache(void);
 static void AtStart_Locks(void);
 static void AtStart_Memory(void);
+static void CleanupTransaction(void);
 static void CommitTransaction(void);
 static void RecordTransactionAbort(void);
 static void RecordTransactionCommit(void);
@@ -243,7 +256,7 @@ bool		AMI_OVERRIDE = false;
 
 /* --------------------------------
  *		TranactionFlushEnabled()
- *		SetTranactionFlushEnabled()
+ *		SetTransactionFlushEnabled()
  *
  *		These are used to test and set the "TransactionFlushState"
  *		varable.  If this variable is true (the default), then
@@ -580,22 +593,35 @@ AtStart_Locks()
 static void
 AtStart_Memory()
 {
-	Portal		portal;
-	MemoryContext portalContext;
+	/* ----------------
+	 *	We shouldn't have any transaction contexts already.
+	 * ----------------
+	 */
+	Assert(TopTransactionContext == NULL);
+	Assert(TransactionCommandContext == NULL);
 
 	/* ----------------
-	 *	get the blank portal and its memory context
+	 *	Create a toplevel context for the transaction.
 	 * ----------------
 	 */
-	portal = GetPortalByName(NULL);
-	portalContext = (MemoryContext) PortalGetHeapMemory(portal);
+	TopTransactionContext =
+		AllocSetContextCreate(TopMemoryContext,
+							  "TopTransactionContext",
+							  ALLOCSET_DEFAULT_MINSIZE,
+							  ALLOCSET_DEFAULT_INITSIZE,
+							  ALLOCSET_DEFAULT_MAXSIZE);
 
 	/* ----------------
-	 *	tell system to allocate in the blank portal context
+	 *	Create a statement-level context and make it active.
 	 * ----------------
 	 */
-	MemoryContextSwitchTo(portalContext);
-	StartPortalAllocMode(DefaultAllocMode, 0);
+	TransactionCommandContext =
+		AllocSetContextCreate(TopTransactionContext,
+							  "TransactionCommandContext",
+							  ALLOCSET_DEFAULT_MINSIZE,
+							  ALLOCSET_DEFAULT_INITSIZE,
+							  ALLOCSET_DEFAULT_MAXSIZE);
+	MemoryContextSwitchTo(TransactionCommandContext);
 }
 
 
@@ -711,22 +737,21 @@ AtCommit_Locks()
 static void
 AtCommit_Memory()
 {
-	Portal		portal;
-
 	/* ----------------
-	 *	Release all heap memory in the blank portal.
+	 *	Now that we're "out" of a transaction, have the
+	 *	system allocate things in the top memory context instead
+	 *	of per-transaction contexts.
 	 * ----------------
 	 */
-	portal = GetPortalByName(NULL);
-	PortalResetHeapMemory(portal);
+	MemoryContextSwitchTo(TopMemoryContext);
 
 	/* ----------------
-	 *	Now that we're "out" of a transaction, have the
-	 *	system allocate things in the top memory context instead
-	 *	of the blank portal memory context.
+	 *	Release all transaction-local memory.
 	 * ----------------
 	 */
-	MemoryContextSwitchTo(TopMemoryContext);
+	MemoryContextDelete(TopTransactionContext);
+	TopTransactionContext = NULL;
+	TransactionCommandContext = NULL;
 }
 
 /* ----------------------------------------------------------------
@@ -798,24 +823,52 @@ AtAbort_Locks()
 static void
 AtAbort_Memory()
 {
-	Portal		portal;
+	/* ----------------
+	 *	Make sure we are in a valid context (not a child of
+	 *	TransactionCommandContext...)
+	 * ----------------
+	 */
+	MemoryContextSwitchTo(TransactionCommandContext);
 
 	/* ----------------
-	 *	Release all heap memory in the blank portal.
+	 *	We do not want to destroy transaction contexts yet,
+	 *	but it should be OK to delete any command-local memory.
 	 * ----------------
 	 */
-	portal = GetPortalByName(NULL);
-	PortalResetHeapMemory(portal);
+	MemoryContextResetAndDeleteChildren(TransactionCommandContext);
+}
+
+
+/* ----------------------------------------------------------------
+ *						CleanupTransaction stuff
+ * ----------------------------------------------------------------
+ */
 
+/* --------------------------------
+ *		AtCleanup_Memory
+ * --------------------------------
+ */
+static void
+AtCleanup_Memory()
+{
 	/* ----------------
 	 *	Now that we're "out" of a transaction, have the
 	 *	system allocate things in the top memory context instead
-	 *	of the blank portal memory context.
+	 *	of per-transaction contexts.
 	 * ----------------
 	 */
 	MemoryContextSwitchTo(TopMemoryContext);
+
+	/* ----------------
+	 *	Release all transaction-local memory.
+	 * ----------------
+	 */
+	MemoryContextDelete(TopTransactionContext);
+	TopTransactionContext = NULL;
+	TransactionCommandContext = NULL;
 }
 
+
 /* ----------------------------------------------------------------
  *						interface routines
  * ----------------------------------------------------------------
@@ -854,6 +907,7 @@ StartTransaction()
 	s->state = TRANS_START;
 
 	SetReindexProcessing(false);
+
 	/* ----------------
 	 *	generate a new transaction id
 	 * ----------------
@@ -874,9 +928,9 @@ StartTransaction()
 	 *	initialize the various transaction subsystems
 	 * ----------------
 	 */
+	AtStart_Memory();
 	AtStart_Cache();
 	AtStart_Locks();
-	AtStart_Memory();
 
 	/* ----------------
 	 *	Tell the trigger manager to we're starting a transaction
@@ -974,20 +1028,21 @@ CommitTransaction()
 	}
 
 	RelationPurgeLocalRelation(true);
+	AtEOXact_SPI();
 	AtEOXact_nbtree();
 	AtCommit_Cache();
 	AtCommit_Locks();
 	AtCommit_Memory();
 	AtEOXact_Files();
 
+	SharedBufferChanged = false; /* safest place to do it */
+
 	/* ----------------
 	 *	done with commit processing, set current transaction
 	 *	state back to default
 	 * ----------------
 	 */
 	s->state = TRANS_DEFAULT;
-	SharedBufferChanged = false;/* safest place to do it */
-
 }
 
 /* --------------------------------
@@ -1018,7 +1073,7 @@ AbortTransaction()
 		return;
 
 	if (s->state != TRANS_INPROGRESS)
-		elog(NOTICE, "AbortTransaction and not in in-progress state ");
+		elog(NOTICE, "AbortTransaction and not in in-progress state");
 
 	/* ----------------
 	 *	Tell the trigger manager that this transaction is about to be
@@ -1043,24 +1098,56 @@ AbortTransaction()
 	AtAbort_Notify();
 	CloseSequences();
 	AtEOXact_portals();
-	if (CommonSpecialPortalIsOpen())
-		CommonSpecialPortalClose();
 	RecordTransactionAbort();
 	RelationPurgeLocalRelation(false);
 	invalidate_temp_relations();
+	AtEOXact_SPI();
 	AtEOXact_nbtree();
 	AtAbort_Cache();
 	AtAbort_Locks();
 	AtAbort_Memory();
 	AtEOXact_Files();
 
+	SharedBufferChanged = false; /* safest place to do it */
+
+	/* ----------------
+	 *	State remains TRANS_ABORT until CleanupTransaction().
+	 * ----------------
+	 */
+}
+
+/* --------------------------------
+ *		CleanupTransaction
+ *
+ * --------------------------------
+ */
+static void
+CleanupTransaction()
+{
+	TransactionState s = CurrentTransactionState;
+
+	if (s->state == TRANS_DISABLED)
+		return;
+
+	/* ----------------
+	 *	State should still be TRANS_ABORT from AbortTransaction().
+	 * ----------------
+	 */
+	if (s->state != TRANS_ABORT)
+		elog(FATAL, "CleanupTransaction and not in abort state");
+
+	/* ----------------
+	 *	do abort cleanup processing
+	 * ----------------
+	 */
+	AtCleanup_Memory();
+
 	/* ----------------
 	 *	done with abort processing, set current transaction
 	 *	state back to default
 	 * ----------------
 	 */
 	s->state = TRANS_DEFAULT;
-	SharedBufferChanged = false;/* safest place to do it */
 }
 
 /* --------------------------------
@@ -1133,7 +1220,7 @@ StartTransactionCommand()
 			/* ----------------
 			 *		This means we somehow aborted and the last call to
 			 *		CommitTransactionCommand() didn't clear the state so
-			 *		we remain in the ENDABORT state and mabey next time
+			 *		we remain in the ENDABORT state and maybe next time
 			 *		we get to CommitTransactionCommand() the state will
 			 *		get reset to default.
 			 * ----------------
@@ -1142,6 +1229,13 @@ StartTransactionCommand()
 			elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
 			break;
 	}
+
+	/*
+	 * We must switch to TransactionCommandContext before returning.
+	 * This is already done if we called StartTransaction, otherwise not.
+	 */
+	Assert(TransactionCommandContext != NULL);
+	MemoryContextSwitchTo(TransactionCommandContext);
 }
 
 /* --------------------------------
@@ -1181,28 +1275,25 @@ CommitTransactionCommand()
 			 *		command counter and return.  Someday we may free resources
 			 *		local to the command.
 			 *
-			 *		That someday is today, at least for memory allocated by
-			 *		command in the BlankPortal' HeapMemory context.
+			 *		That someday is today, at least for memory allocated in
+			 *		TransactionCommandContext.
 			 *				- vadim 03/25/97
 			 * ----------------
 			 */
 		case TBLOCK_INPROGRESS:
 			CommandCounterIncrement();
-#ifdef TBL_FREE_CMD_MEMORY
-			EndPortalAllocMode();
-			StartPortalAllocMode(DefaultAllocMode, 0);
-#endif
+			MemoryContextResetAndDeleteChildren(TransactionCommandContext);
 			break;
 
 			/* ----------------
 			 *		This is the case when we just got the "END TRANSACTION"
-			 *		statement, so we go back to the default state and
-			 *		commit the transaction.
+			 *		statement, so we commit the transaction and go back to
+			 *		the default state.
 			 * ----------------
 			 */
 		case TBLOCK_END:
-			s->blockState = TBLOCK_DEFAULT;
 			CommitTransaction();
+			s->blockState = TBLOCK_DEFAULT;
 			break;
 
 			/* ----------------
@@ -1218,10 +1309,11 @@ CommitTransactionCommand()
 			/* ----------------
 			 *		Here we were in an aborted transaction block which
 			 *		just processed the "END TRANSACTION" command from the
-			 *		user, so now we return the to default state.
+			 *		user, so clean up and return to the default state.
 			 * ----------------
 			 */
 		case TBLOCK_ENDABORT:
+			CleanupTransaction();
 			s->blockState = TBLOCK_DEFAULT;
 			break;
 	}
@@ -1240,11 +1332,12 @@ AbortCurrentTransaction()
 	{
 			/* ----------------
 			 *		if we aren't in a transaction block, we
-			 *		just do our usual abort transaction.
+			 *		just do the basic abort & cleanup transaction.
 			 * ----------------
 			 */
 		case TBLOCK_DEFAULT:
 			AbortTransaction();
+			CleanupTransaction();
 			break;
 
 			/* ----------------
@@ -1257,6 +1350,7 @@ AbortCurrentTransaction()
 		case TBLOCK_BEGIN:
 			s->blockState = TBLOCK_ABORT;
 			AbortTransaction();
+			/* CleanupTransaction happens when we exit TBLOCK_ABORT */
 			break;
 
 			/* ----------------
@@ -1269,6 +1363,7 @@ AbortCurrentTransaction()
 		case TBLOCK_INPROGRESS:
 			s->blockState = TBLOCK_ABORT;
 			AbortTransaction();
+			/* CleanupTransaction happens when we exit TBLOCK_ABORT */
 			break;
 
 			/* ----------------
@@ -1281,6 +1376,7 @@ AbortCurrentTransaction()
 		case TBLOCK_END:
 			s->blockState = TBLOCK_DEFAULT;
 			AbortTransaction();
+			CleanupTransaction();
 			break;
 
 			/* ----------------
@@ -1297,10 +1393,11 @@ AbortCurrentTransaction()
 			 *		Here we were in an aborted transaction block which
 			 *		just processed the "END TRANSACTION" command but somehow
 			 *		aborted again.. since we must have done the abort
-			 *		processing, we return to the default state.
+			 *		processing, we clean up and return to the default state.
 			 * ----------------
 			 */
 		case TBLOCK_ENDABORT:
+			CleanupTransaction();
 			s->blockState = TBLOCK_DEFAULT;
 			break;
 	}
@@ -1394,13 +1491,14 @@ EndTransactionBlock(void)
 	}
 
 	/* ----------------
-	 *	We should not get here, but if we do, we go to the ENDABORT
-	 *	state after printing a warning.  The upcoming call to
+	 *	here, the user issued COMMIT when not inside a transaction.
+	 *	Issue a notice and go to abort state.  The upcoming call to
 	 *	CommitTransactionCommand() will then put us back into the
 	 *	default state.
 	 * ----------------
 	 */
 	elog(NOTICE, "COMMIT: no transaction in progress");
+	AbortTransaction();
 	s->blockState = TBLOCK_ENDABORT;
 }
 
@@ -1427,29 +1525,23 @@ AbortTransactionBlock(void)
 		 *	here we were inside a transaction block something
 		 *	screwed up inside the system so we enter the abort state,
 		 *	do the abort processing and then return.
-		 *	We remain in the abort state until we see the upcoming
+		 *	We remain in the abort state until we see an
 		 *	END TRANSACTION command.
 		 * ----------------
 		 */
 		s->blockState = TBLOCK_ABORT;
-
-		/* ----------------
-		 *	do abort processing and return
-		 * ----------------
-		 */
 		AbortTransaction();
 		return;
 	}
 
 	/* ----------------
-	 *	this case should not be possible, because it would mean
-	 *	the user entered an "abort" from outside a transaction block.
-	 *	So we print an error message, abort the transaction and
-	 *	enter the "ENDABORT" state so we will end up in the default
-	 *	state after the upcoming CommitTransactionCommand().
+	 *	here, the user issued ABORT when not inside a transaction.
+	 *	Issue a notice and go to abort state.  The upcoming call to
+	 *	CommitTransactionCommand() will then put us back into the
+	 *	default state.
 	 * ----------------
 	 */
-	elog(NOTICE, "AbortTransactionBlock and not in in-progress state");
+	elog(NOTICE, "ROLLBACK: no transaction in progress");
 	AbortTransaction();
 	s->blockState = TBLOCK_ENDABORT;
 }
@@ -1495,27 +1587,16 @@ UserAbortTransactionBlock()
 		 * ----------------
 		 */
 		s->blockState = TBLOCK_ABORT;
-
-		/* ----------------
-		 *	do abort processing
-		 * ----------------
-		 */
 		AbortTransaction();
-
-		/* ----------------
-		 *	change to the end abort state and return
-		 * ----------------
-		 */
 		s->blockState = TBLOCK_ENDABORT;
 		return;
 	}
 
 	/* ----------------
-	 *	this case should not be possible, because it would mean
-	 *	the user entered a "rollback" from outside a transaction block.
-	 *	So we print an error message, abort the transaction and
-	 *	enter the "ENDABORT" state so we will end up in the default
-	 *	state after the upcoming CommitTransactionCommand().
+	 *	here, the user issued ABORT when not inside a transaction.
+	 *	Issue a notice and go to abort state.  The upcoming call to
+	 *	CommitTransactionCommand() will then put us back into the
+	 *	default state.
 	 * ----------------
 	 */
 	elog(NOTICE, "ROLLBACK: no transaction in progress");
@@ -1540,7 +1621,10 @@ AbortOutOfAnyTransaction()
 	 * Get out of any low-level transaction
 	 */
 	if (s->state != TRANS_DEFAULT)
+	{
 		AbortTransaction();
+		CleanupTransaction();
+	}
 
 	/*
 	 * Now reset the high-level state
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index b49d5ef8bf..54d4ab8139 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.87 2000/06/22 22:31:17 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.88 2000/06/28 03:31:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,14 +34,14 @@
 #include "miscadmin.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
+#include "utils/exc.h"
 #include "utils/fmgroids.h"
 #include "utils/guc.h"
 #include "utils/lsyscache.h"
-#include "utils/portal.h"
+
 
 #define ALLOC(t, c)		((t *) calloc((unsigned)(c), sizeof(t)))
 
-extern void BaseInit(void);
 extern void StartupXLOG(void);
 extern void ShutdownXLOG(void);
 extern void BootStrapXLOG(void);
@@ -144,8 +144,8 @@ static Datum values[MAXATTR];	/* corresponding attribute values */
 int			numattr;			/* number of attributes for cur. rel */
 
 int			DebugMode;
-static GlobalMemory nogc = (GlobalMemory) NULL; /* special no-gc mem
-												 * context */
+
+static MemoryContext nogc = NULL; /* special no-gc mem context */
 
 extern int	optind;
 extern char *optarg;
@@ -240,6 +240,17 @@ BootstrapMain(int argc, char *argv[])
 
 	MyProcPid = getpid();
 
+	/*
+	 * Fire up essential subsystems: error and memory management
+	 *
+	 * If we are running under the postmaster, this is done already.
+	 */
+	if (!IsUnderPostmaster)
+	{
+		EnableExceptionHandling(true);
+		MemoryContextInit();
+	}
+
 	/* ----------------
 	 *	process command arguments
 	 * ----------------
@@ -428,7 +439,6 @@ boot_openrel(char *relname)
 
 	if (Typ == (struct typmap **) NULL)
 	{
-		StartPortalAllocMode(DefaultAllocMode, 0);
 		rel = heap_openr(TypeRelationName, NoLock);
 		Assert(rel);
 		scan = heap_beginscan(rel, 0, SnapshotNow, 0, (ScanKey) NULL);
@@ -445,13 +455,13 @@ boot_openrel(char *relname)
 		while (HeapTupleIsValid(tup = heap_getnext(scan, 0)))
 		{
 			(*app)->am_oid = tup->t_data->t_oid;
-			memmove((char *) &(*app++)->am_typ,
-					(char *) GETSTRUCT(tup),
-					sizeof((*app)->am_typ));
+			memcpy((char *) &(*app)->am_typ,
+				   (char *) GETSTRUCT(tup),
+				   sizeof((*app)->am_typ));
+			app++;
 		}
 		heap_endscan(scan);
 		heap_close(rel, NoLock);
-		EndPortalAllocMode();
 	}
 
 	if (reldesc != NULL)
@@ -1088,10 +1098,14 @@ index_register(char *heap,
 	 * them later.
 	 */
 
-	if (nogc == (GlobalMemory) NULL)
-		nogc = CreateGlobalMemory("BootstrapNoGC");
+	if (nogc == NULL)
+		nogc = AllocSetContextCreate((MemoryContext) NULL,
+									 "BootstrapNoGC",
+									 ALLOCSET_DEFAULT_MINSIZE,
+									 ALLOCSET_DEFAULT_INITSIZE,
+									 ALLOCSET_DEFAULT_MAXSIZE);
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) nogc);
+	oldcxt = MemoryContextSwitchTo(nogc);
 
 	newind = (IndexList *) palloc(sizeof(IndexList));
 	newind->il_heap = pstrdup(heap);
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 7aeec8adb0..9ba935f716 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.133 2000/06/18 22:43:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.134 2000/06/28 03:31:22 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -188,38 +188,27 @@ heap_create(char *relname,
 			 relname);
 	}
 
-	/* ----------------
-	 *	switch to the cache context so that we don't lose
-	 *	allocations at the end of this transaction, I guess.
-	 *	-cim 6/14/90
-	 * ----------------
-	 */
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
-
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
-
 	/* ----------------
 	 *	real ugly stuff to assign the proper relid in the relation
 	 *	descriptor follows.
 	 * ----------------
 	 */
-	if (relname && !strcmp(RelationRelationName, relname))
+	if (relname && strcmp(RelationRelationName, relname) == 0)
 	{
 		relid = RelOid_pg_class;
 		nailme = true;
 	}
-	else if (relname && !strcmp(AttributeRelationName, relname))
+	else if (relname && strcmp(AttributeRelationName, relname) == 0)
 	{
 		relid = RelOid_pg_attribute;
 		nailme = true;
 	}
-	else if (relname && !strcmp(ProcedureRelationName, relname))
+	else if (relname && strcmp(ProcedureRelationName, relname) == 0)
 	{
 		relid = RelOid_pg_proc;
 		nailme = true;
 	}
-	else if (relname && !strcmp(TypeRelationName, relname))
+	else if (relname && strcmp(TypeRelationName, relname) == 0)
 	{
 		relid = RelOid_pg_type;
 		nailme = true;
@@ -234,6 +223,15 @@ heap_create(char *relname,
 				 (int) MyProcPid, uniqueId++);
 	}
 
+	/* ----------------
+	 *	switch to the cache context to create the relcache entry.
+	 * ----------------
+	 */
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
+
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
+
 	/* ----------------
 	 *	allocate a new relation descriptor.
 	 * ----------------
@@ -287,6 +285,8 @@ heap_create(char *relname,
 
 	/* ----------------
 	 *	have the storage manager create the relation.
+	 *
+	 * XXX shouldn't we switch out of CacheMemoryContext for that?
 	 * ----------------
 	 */
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 5b8e005c5f..c737618996 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.119 2000/06/18 22:43:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.120 2000/06/28 03:31:23 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -442,10 +442,10 @@ ConstructIndexReldesc(Relation indexRelation, Oid amoid)
 	 *	  context changes
 	 * ----------------
 	 */
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	indexRelation->rd_am = AccessMethodObjectIdGetForm(amoid);
 
@@ -904,16 +904,16 @@ InitIndexStrategy(int numatts,
 	 *	it will be lost at the end of the transaction.
 	 * ----------------
 	 */
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
 
-	strategy = (IndexStrategy)
-		MemoryContextAlloc((MemoryContext) CacheCxt, strsize);
+	strategy = (IndexStrategy) MemoryContextAlloc(CacheMemoryContext,
+												  strsize);
 
 	if (amsupport > 0)
 	{
 		strsize = numatts * (amsupport * sizeof(RegProcedure));
-		support = (RegProcedure *) MemoryContextAlloc((MemoryContext) CacheCxt,
+		support = (RegProcedure *) MemoryContextAlloc(CacheMemoryContext,
 													  strsize);
 	}
 	else
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 836790c82a..e6091f6f63 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.44 2000/06/14 04:53:44 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.45 2000/06/28 03:31:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -217,8 +217,7 @@ ProcedureCreate(char *procedureName,
 
 	if (languageObjectId == SQLlanguageId)
 	{
-		querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount,
-											  FALSE);
+		querytree_list = pg_parse_and_rewrite(prosrc, typev, parameterCount);
 		/* typecheck return value */
 		pg_checkretval(typeObjectId, querytree_list);
 	}
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 5644afc46c..d0bd89fdfd 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -8,13 +8,9 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.80 2000/06/15 04:09:45 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.81 2000/06/28 03:31:28 tgl Exp $
  *
  * NOTES
- *	  The PortalExecutorHeapMemory crap needs to be eliminated
- *	  by designing a better executor / portal processing memory
- *	  interface.
- *
  *	  The PerformAddAttribute() code, like most of the relation
  *	  manipulating code in the commands/ directory, should go
  *	  someplace closer to the lib/catalog code.
@@ -40,13 +36,6 @@
 #include "parser/parse.h"
 #endif	 /* _DROP_COLUMN_HACK__ */
 
-/* ----------------
- *		PortalExecutorHeapMemory stuff
- *
- *		This is where the XXXSuperDuperHacky code was. -cim 3/15/90
- * ----------------
- */
-MemoryContext PortalExecutorHeapMemory = NULL;
 
 /* --------------------------------
  *		PortalCleanup
@@ -55,7 +44,7 @@ MemoryContext PortalExecutorHeapMemory = NULL;
 void
 PortalCleanup(Portal portal)
 {
-	MemoryContext context;
+	MemoryContext oldcontext;
 
 	/* ----------------
 	 *	sanity checks
@@ -68,8 +57,7 @@ PortalCleanup(Portal portal)
 	 *	set proper portal-executor context before calling ExecMain.
 	 * ----------------
 	 */
-	context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
-	PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
+	oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
 	/* ----------------
 	 *	tell the executor to shutdown the query
@@ -81,8 +69,7 @@ PortalCleanup(Portal portal)
 	 *	switch back to previous context
 	 * ----------------
 	 */
-	MemoryContextSwitchTo(context);
-	PortalExecutorHeapMemory = (MemoryContext) NULL;
+	MemoryContextSwitchTo(oldcontext);
 }
 
 /* --------------------------------
@@ -99,7 +86,7 @@ PerformPortalFetch(char *name,
 	Portal		portal;
 	int			feature;
 	QueryDesc  *queryDesc;
-	MemoryContext context;
+	MemoryContext oldcontext;
 	Const		limcount;
 
 	/* ----------------
@@ -108,7 +95,7 @@ PerformPortalFetch(char *name,
 	 */
 	if (name == NULL)
 	{
-		elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
+		elog(NOTICE, "PerformPortalFetch: missing portal name");
 		return;
 	}
 
@@ -120,12 +107,11 @@ PerformPortalFetch(char *name,
 	limcount.type = T_Const;
 	limcount.consttype = INT4OID;
 	limcount.constlen = sizeof(int4);
-	limcount.constvalue = (Datum) count;
-	limcount.constisnull = FALSE;
-	limcount.constbyval = TRUE;
-	limcount.constisset = FALSE;
-	limcount.constiscast = FALSE;
-
+	limcount.constvalue = Int32GetDatum(count);
+	limcount.constisnull = false;
+	limcount.constbyval = true;
+	limcount.constisset = false;
+	limcount.constiscast = false;
 
 	/* ----------------
 	 *	get the portal from the portal name
@@ -143,9 +129,7 @@ PerformPortalFetch(char *name,
 	 *	switch into the portal context
 	 * ----------------
 	 */
-	context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
-
-	AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
+	oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
 	/* ----------------
 	 *	setup "feature" to tell the executor what direction and
@@ -174,8 +158,7 @@ PerformPortalFetch(char *name,
 
 	BeginCommand(name,
 				 queryDesc->operation,
-				 portal->attinfo,		/* QueryDescGetTypeInfo(queryDesc),
-										 * */
+				 portal->attinfo, /* QueryDescGetTypeInfo(queryDesc) */
 				 false,			/* portal fetches don't end up in
 								 * relations */
 				 false,			/* this is a portal fetch, not a "retrieve
@@ -187,27 +170,23 @@ PerformPortalFetch(char *name,
 	 *	execute the portal fetch operation
 	 * ----------------
 	 */
-	PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
-
 	ExecutorRun(queryDesc, PortalGetState(portal), feature,
 				(Node *) NULL, (Node *) &limcount);
 
 	if (dest == None)			/* MOVE */
 		pfree(queryDesc);
 
+	/* ----------------
+	 * Switch back to old context.
+	 * ----------------
+	 */
+	MemoryContextSwitchTo(oldcontext);
+
 	/* ----------------
 	 * Note: the "end-of-command" tag is returned by higher-level
 	 *		 utility code
-	 *
-	 * Return blank portal for now.
-	 * Otherwise, this named portal will be cleaned.
-	 * Note: portals will only be supported within a BEGIN...END
-	 * block in the near future.  Later, someone will fix it to
-	 * do what is possible across transaction boundries.
 	 * ----------------
 	 */
-	MemoryContextSwitchTo(
-			 (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
 }
 
 /* --------------------------------
@@ -225,15 +204,10 @@ PerformPortalClose(char *name, CommandDest dest)
 	 */
 	if (name == NULL)
 	{
-		elog(NOTICE, "PerformPortalClose: blank portal unsupported");
+		elog(NOTICE, "PerformPortalClose: missing portal name");
 		return;
 	}
 
-	if (PortalNameIsSpecial(name))
-		elog(ERROR,
-			 "The portal name \"%s\" is reserved for internal use",
-			 name);
-
 	/* ----------------
 	 *	get the portal from the portal name
 	 * ----------------
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index e5896b304c..bb45f01f67 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.31 2000/06/17 23:41:36 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.32 2000/06/28 03:31:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,7 +39,6 @@
 #include "utils/fmgroids.h"
 #include "utils/syscache.h"
 #include "miscadmin.h"			/* ReindexDatabase() */
-#include "utils/portal.h"		/* ReindexDatabase() */
 #include "catalog/catalog.h"	/* ReindexDatabase() */
 
 #define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args != NIL)
@@ -764,7 +763,6 @@ ReindexTable(const char *name, bool force)
  *		"ERROR" if table nonexistent.
  *		...
  */
-extern Oid	MyDatabaseId;
 void
 ReindexDatabase(const char *dbname, bool force, bool all)
 {
@@ -780,7 +778,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
 	Oid			db_id;
 	char	   *username;
 	ScanKeyData scankey;
-	PortalVariableMemory pmem;
+	MemoryContext private_context;
 	MemoryContext old;
 	int			relcnt,
 				relalc,
@@ -808,16 +806,34 @@ ReindexDatabase(const char *dbname, bool force, bool all)
 	db_id = dbtuple->t_data->t_oid;
 	db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
 	heap_endscan(scan);
+	heap_close(relation, NoLock);
+
 	if (user_id != db_owner && !superuser)
 		elog(ERROR, "REINDEX DATABASE: Permission denied.");
 
 	if (db_id != MyDatabaseId)
 		elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
 
-	heap_close(relation, NoLock);
+	/*
+	 * We cannot run inside a user transaction block; if we were
+	 * inside a transaction, then our commit- and
+	 * start-transaction-command calls would not have the intended effect!
+	 */
+	if (IsTransactionBlock())
+		elog(ERROR, "REINDEX DATABASE cannot run inside a BEGIN/END block");
+
+	/*
+	 * Create a memory context that will survive forced transaction commits
+	 * we do below.  Since it is a child of QueryContext, it will go away
+	 * eventually even if we suffer an error; there's no need for special
+	 * abort cleanup logic.
+	 */
+	private_context = AllocSetContextCreate(QueryContext,
+											"ReindexDatabase",
+											ALLOCSET_DEFAULT_MINSIZE,
+											ALLOCSET_DEFAULT_INITSIZE,
+											ALLOCSET_DEFAULT_MAXSIZE);
 
-	CommonSpecialPortalOpen();
-	pmem = CommonSpecialPortalGetMemory();
 	relationRelation = heap_openr(RelationRelationName, AccessShareLock);
 	scan = heap_beginscan(relationRelation, false, SnapshotNow, 0, NULL);
 	relcnt = relalc = 0;
@@ -832,7 +848,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
 		}
 		if (((Form_pg_class) GETSTRUCT(tuple))->relkind == RELKIND_RELATION)
 		{
-			old = MemoryContextSwitchTo((MemoryContext) pmem);
+			old = MemoryContextSwitchTo(private_context);
 			if (relcnt == 0)
 			{
 				relalc = oncealc;
@@ -859,6 +875,7 @@ ReindexDatabase(const char *dbname, bool force, bool all)
 			elog(NOTICE, "relation %d was reindexed", relids[i]);
 		CommitTransactionCommand();
 	}
-	CommonSpecialPortalClose();
 	StartTransactionCommand();
+
+	MemoryContextDelete(private_context);
 }
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 62d88caf39..fbb5a694b8 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.69 2000/06/08 22:37:01 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.70 2000/06/28 03:31:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1029,8 +1029,8 @@ ltrmark:;
  * end.
  * ----------
  */
-static GlobalMemory deftrig_gcxt = NULL;
-static GlobalMemory deftrig_cxt = NULL;
+static MemoryContext deftrig_gcxt = NULL;
+static MemoryContext deftrig_cxt = NULL;
 
 /* ----------
  * Global data that tells which triggers are actually in
@@ -1104,7 +1104,7 @@ deferredTriggerCheckState(Oid tgoid, int32 itemstate)
 	 * as the current and return that.
 	 * ----------
 	 */
-	oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+	oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
 	trigstate = (DeferredTriggerStatus)
 		palloc(sizeof(DeferredTriggerStatusData));
@@ -1366,7 +1366,12 @@ deferredTriggerInvokeEvents(bool immediate_only)
 int
 DeferredTriggerInit(void)
 {
-	deftrig_gcxt = CreateGlobalMemory("DeferredTriggerSession");
+	deftrig_gcxt = AllocSetContextCreate(TopMemoryContext,
+										 "DeferredTriggerSession",
+										 ALLOCSET_DEFAULT_MINSIZE,
+										 ALLOCSET_DEFAULT_INITSIZE,
+										 ALLOCSET_DEFAULT_MAXSIZE);
+
 	return 0;
 }
 
@@ -1395,8 +1400,12 @@ DeferredTriggerBeginXact(void)
 	 * from the per session context to here.
 	 * ----------
 	 */
-	deftrig_cxt = CreateGlobalMemory("DeferredTriggerXact");
-	oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+	deftrig_cxt = AllocSetContextCreate(TopTransactionContext,
+										"DeferredTriggerXact",
+										ALLOCSET_DEFAULT_MINSIZE,
+										ALLOCSET_DEFAULT_INITSIZE,
+										ALLOCSET_DEFAULT_MAXSIZE);
+	oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
 	deftrig_all_isset = deftrig_dfl_all_isset;
 	deftrig_all_isdeferred = deftrig_dfl_all_isdeferred;
@@ -1461,7 +1470,7 @@ DeferredTriggerEndXact(void)
 
 	deferredTriggerInvokeEvents(false);
 
-	GlobalMemoryDestroy(deftrig_cxt);
+	MemoryContextDelete(deftrig_cxt);
 	deftrig_cxt = NULL;
 }
 
@@ -1484,7 +1493,7 @@ DeferredTriggerAbortXact(void)
 	if (deftrig_cxt == NULL)
 		return;
 
-	GlobalMemoryDestroy(deftrig_cxt);
+	MemoryContextDelete(deftrig_cxt);
 	deftrig_cxt = NULL;
 }
 
@@ -1521,7 +1530,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
 			 * ... outside of a transaction block
 			 * ----------
 			 */
-			oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
+			oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
 
 			/* ----------
 			 * Drop all information about individual trigger states per
@@ -1555,7 +1564,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
 			 * ... inside of a transaction block
 			 * ----------
 			 */
-			oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+			oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
 			/* ----------
 			 * Drop all information about individual trigger states per
@@ -1701,7 +1710,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
 		 * states of individual triggers on session level.
 		 * ----------
 		 */
-		oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_gcxt);
+		oldcxt = MemoryContextSwitchTo(deftrig_gcxt);
 
 		foreach(l, loid)
 		{
@@ -1739,7 +1748,7 @@ DeferredTriggerSetState(ConstraintsSetStmt *stmt)
 		 * states of individual triggers on transaction level.
 		 * ----------
 		 */
-		oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+		oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
 		foreach(l, loid)
 		{
@@ -1827,7 +1836,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
 	 * Create a new event
 	 * ----------
 	 */
-	oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+	oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 
 	ntriggers = rel->trigdesc->n_after_row[event];
 	triggers = rel->trigdesc->tg_after_row[event];
@@ -2022,7 +2031,7 @@ DeferredTriggerSaveEvent(Relation rel, int event,
 	 * Anything's fine up to here. Add the new event to the queue.
 	 * ----------
 	 */
-	oldcxt = MemoryContextSwitchTo((MemoryContext) deftrig_cxt);
+	oldcxt = MemoryContextSwitchTo(deftrig_cxt);
 	deferredTriggerAddEvent(new_event);
 	MemoryContextSwitchTo(oldcxt);
 
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 859cb31eda..9bb36311cc 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -1,12 +1,12 @@
 /*-------------------------------------------------------------------------
  *
  * user.c
- *	  use pg_exec_query to create a new user in the catalog
+ *	  Commands for manipulating users and groups.
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.61 2000/06/25 14:24:59 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/user.c,v 1.62 2000/06/28 03:31:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 5eed27387a..01ed68b3b7 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.160 2000/06/17 21:48:43 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.161 2000/06/28 03:31:28 tgl Exp $
  *
 
  *-------------------------------------------------------------------------
@@ -35,7 +35,6 @@
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/inval.h"
-#include "utils/portal.h"
 #include "utils/relcache.h"
 #include "utils/syscache.h"
 #include "utils/temprel.h"
@@ -48,9 +47,7 @@
 #endif
 
 
-bool		CommonSpecialPortalInUse = false;
-
-static Portal vac_portal;
+static MemoryContext vac_context = NULL;
 
 static int	MESSAGE_LEVEL;		/* message level */
 
@@ -82,14 +79,13 @@ static int	vac_cmp_offno(const void *left, const void *right);
 static int	vac_cmp_vtlinks(const void *left, const void *right);
 static bool enough_space(VacPage vacpage, Size len);
 static char *show_rusage(struct rusage * ru0);
-/* CommonSpecialPortal function at the bottom */
+
 
 void
 vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
 {
 	NameData	VacRel;
 	Name		VacRelName;
-	PortalVariableMemory pmem;
 	MemoryContext old;
 	List	   *le;
 	List	   *anal_cols2 = NIL;
@@ -114,8 +110,18 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
 	else
 		MESSAGE_LEVEL = DEBUG;
 
-	/* Create special portal for cross-transaction storage */
-	CommonSpecialPortalOpen();
+	/*
+	 * Create special memory context for cross-transaction storage.
+	 *
+	 * Since it is a child of QueryContext, it will go away eventually
+	 * even if we suffer an error; there's no need for special abort
+	 * cleanup logic.
+	 */
+	vac_context = AllocSetContextCreate(QueryContext,
+										"Vacuum",
+										ALLOCSET_DEFAULT_MINSIZE,
+										ALLOCSET_DEFAULT_INITSIZE,
+										ALLOCSET_DEFAULT_MAXSIZE);
 
 	/* vacrel gets de-allocated on xact commit, so copy it to safe storage */
 	if (vacrel)
@@ -127,8 +133,7 @@ vacuum(char *vacrel, bool verbose, bool analyze, List *anal_cols)
 		VacRelName = NULL;
 
 	/* must also copy the column list, if any, to safe storage */
-	pmem = CommonSpecialPortalGetMemory();
-	old = MemoryContextSwitchTo((MemoryContext) pmem);
+	old = MemoryContextSwitchTo(vac_context);
 	foreach(le, anal_cols)
 	{
 		char	   *col = (char *) lfirst(le);
@@ -198,11 +203,16 @@ vacuum_shutdown()
 	 */
 	unlink(RELCACHE_INIT_FILENAME);
 
-	/* Clean up working storage */
-	CommonSpecialPortalClose();
-
 	/* matches the CommitTransaction in PostgresMain() */
 	StartTransactionCommand();
+
+	/*
+	 * Clean up working storage --- note we must do this after
+	 * StartTransactionCommand, else we might be trying to delete
+	 * the active context!
+	 */
+	MemoryContextDelete(vac_context);
+	vac_context = NULL;
 }
 
 /*
@@ -239,8 +249,6 @@ getrels(NameData *VacRelP)
 	TupleDesc	tupdesc;
 	HeapScanDesc scan;
 	HeapTuple	tuple;
-	PortalVariableMemory portalmem;
-	MemoryContext old;
 	VRelList	vrl,
 				cur;
 	Datum		d;
@@ -276,7 +284,6 @@ getrels(NameData *VacRelP)
 							   F_CHAREQ, CharGetDatum('r'));
 	}
 
-	portalmem = CommonSpecialPortalGetMemory();
 	vrl = cur = (VRelList) NULL;
 
 	rel = heap_openr(RelationRelationName, AccessShareLock);
@@ -302,25 +309,26 @@ getrels(NameData *VacRelP)
 		}
 
 		/* get a relation list entry for this guy */
-		old = MemoryContextSwitchTo((MemoryContext) portalmem);
 		if (vrl == (VRelList) NULL)
-			vrl = cur = (VRelList) palloc(sizeof(VRelListData));
+			vrl = cur = (VRelList)
+				MemoryContextAlloc(vac_context, sizeof(VRelListData));
 		else
 		{
-			cur->vrl_next = (VRelList) palloc(sizeof(VRelListData));
+			cur->vrl_next = (VRelList)
+				MemoryContextAlloc(vac_context, sizeof(VRelListData));
 			cur = cur->vrl_next;
 		}
-		MemoryContextSwitchTo(old);
 
 		cur->vrl_relid = tuple->t_data->t_oid;
 		cur->vrl_next = (VRelList) NULL;
 	}
-	if (found == false)
-		elog(NOTICE, "Vacuum: table not found");
 
 	heap_endscan(scan);
 	heap_close(rel, AccessShareLock);
 
+	if (!found)
+		elog(NOTICE, "Vacuum: table not found");
+
 	CommitTransactionCommand();
 
 	return vrl;
@@ -2275,62 +2283,6 @@ vac_cmp_vtlinks(const void *left, const void *right)
 
 }
 
-/*
- * This routines handle a special cross-transaction portal.
- * However it is automatically closed in case of abort.
- */
-void
-CommonSpecialPortalOpen(void)
-{
-	char	   *pname;
-
-
-	if (CommonSpecialPortalInUse)
-		elog(ERROR, "CommonSpecialPortal is in use");
-
-	/*
-	 * Create a portal for safe memory across transactions. We need to
-	 * palloc the name space for it because our hash function expects the
-	 * name to be on a longword boundary.  CreatePortal copies the name to
-	 * safe storage for us.
-	 */
-	pname = pstrdup(VACPNAME);
-	vac_portal = CreatePortal(pname);
-	pfree(pname);
-
-	/*
-	 * Set flag to indicate that vac_portal must be removed after an error.
-	 * This global variable is checked in the transaction manager on xact
-	 * abort, and the routine CommonSpecialPortalClose() is called if
-	 * necessary.
-	 */
-	CommonSpecialPortalInUse = true;
-}
-
-void
-CommonSpecialPortalClose(void)
-{
-	/* Clear flag first, to avoid recursion if PortalDrop elog's */
-	CommonSpecialPortalInUse = false;
-
-	/*
-	 * Release our portal for cross-transaction memory.
-	 */
-	PortalDrop(&vac_portal);
-}
-
-PortalVariableMemory
-CommonSpecialPortalGetMemory(void)
-{
-	return PortalGetVariableMemory(vac_portal);
-}
-
-bool
-CommonSpecialPortalIsOpen(void)
-{
-	return CommonSpecialPortalInUse;
-}
-
 
 static void
 get_indices(Relation relation, int *nindices, Relation **Irel)
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index ee5fabf170..6d8d93a47f 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.34 2000/05/28 17:55:55 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.35 2000/06/28 03:31:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -87,8 +87,8 @@ init_execution_state(FunctionCachePtr fcache)
 	nextes = newes;
 	preves = (execution_state *) NULL;
 
-	queryTree_list = pg_parse_and_rewrite(fcache->src, fcache->argOidVect,
-										  nargs, FALSE);
+	queryTree_list = pg_parse_and_rewrite(fcache->src,
+										  fcache->argOidVect, nargs);
 
 	foreach(qtl_item, queryTree_list)
 	{
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index c9d6299f49..0289cf45bd 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -32,7 +32,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.67 2000/06/15 03:32:09 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.68 2000/06/28 03:31:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -265,7 +265,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
 			else
 				newVal = FunctionCallInvoke(&fcinfo);
 			if (!peraggstate->transtype1ByVal && !peraggstate->value1IsNull)
-				pfree(peraggstate->value1);
+				pfree(DatumGetPointer(peraggstate->value1));
 			peraggstate->value1 = newVal;
 			peraggstate->value1IsNull = fcinfo.isnull;
 		}
@@ -288,7 +288,7 @@ advance_transition_functions(AggStatePerAgg peraggstate,
 		else
 			newVal = FunctionCallInvoke(&fcinfo);
 		if (!peraggstate->transtype2ByVal && !peraggstate->value2IsNull)
-			pfree(peraggstate->value2);
+			pfree(DatumGetPointer(peraggstate->value2));
 		peraggstate->value2 = newVal;
 		peraggstate->value2IsNull = fcinfo.isnull;
 	}
@@ -424,12 +424,12 @@ finalize_aggregate(AggStatePerAgg peraggstate,
 	if (OidIsValid(peraggstate->xfn1_oid) &&
 		!peraggstate->value1IsNull &&
 		!peraggstate->transtype1ByVal)
-		pfree(peraggstate->value1);
+		pfree(DatumGetPointer(peraggstate->value1));
 
 	if (OidIsValid(peraggstate->xfn2_oid) &&
 		!peraggstate->value2IsNull &&
 		!peraggstate->transtype2ByVal)
-		pfree(peraggstate->value2);
+		pfree(DatumGetPointer(peraggstate->value2));
 }
 
 /* ---------------------------------------
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index b662883803..34b0a269a5 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -7,14 +7,14 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- *	$Id: nodeHash.c,v 1.47 2000/06/15 04:09:52 momjian Exp $
+ *	$Id: nodeHash.c,v 1.48 2000/06/28 03:31:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * INTERFACE ROUTINES
  *		ExecHash		- generate an in-memory hash table of the relation
- *		ExecInitHash	- initialize node and subnodes..
+ *		ExecInitHash	- initialize node and subnodes
  *		ExecEndHash		- shutdown node and subnodes
  *
  */
@@ -23,11 +23,12 @@
 #include <math.h>
 
 #include "postgres.h"
+
 #include "executor/execdebug.h"
 #include "executor/nodeHash.h"
 #include "executor/nodeHashjoin.h"
 #include "miscadmin.h"
-#include "utils/portal.h"
+
 
 static int	hashFunc(Datum key, int len, bool byVal);
 
@@ -235,8 +236,6 @@ ExecHashTableCreate(Hash *node)
 	int			totalbuckets;
 	int			bucketsize;
 	int			i;
-	Portal		myPortal;
-	char		myPortalName[64];
 	MemoryContext oldcxt;
 
 	/* ----------------
@@ -348,23 +347,21 @@ ExecHashTableCreate(Hash *node)
 	hashtable->outerBatchSize = NULL;
 
 	/* ----------------
-	 *	Create a named portal in which to keep the hashtable working storage.
-	 *	Each hashjoin must have its own portal, so be wary of name conflicts.
+	 *	Create temporary memory contexts in which to keep the hashtable
+	 *	working storage.  See notes in executor/hashjoin.h.
 	 * ----------------
 	 */
-	i = 0;
-	do
-	{
-		i++;
-		sprintf(myPortalName, "<hashtable %d>", i);
-		myPortal = GetPortalByName(myPortalName);
-	} while (PortalIsValid(myPortal));
-	myPortal = CreatePortal(myPortalName);
-	Assert(PortalIsValid(myPortal));
-	hashtable->myPortal = (void *) myPortal;	/* kluge for circular
-												 * includes */
-	hashtable->hashCxt = (MemoryContext) PortalGetVariableMemory(myPortal);
-	hashtable->batchCxt = (MemoryContext) PortalGetHeapMemory(myPortal);
+	hashtable->hashCxt = AllocSetContextCreate(TransactionCommandContext,
+											   "HashTableContext",
+											   ALLOCSET_DEFAULT_MINSIZE,
+											   ALLOCSET_DEFAULT_INITSIZE,
+											   ALLOCSET_DEFAULT_MAXSIZE);
+
+	hashtable->batchCxt = AllocSetContextCreate(hashtable->hashCxt,
+												"HashBatchContext",
+												ALLOCSET_DEFAULT_MINSIZE,
+												ALLOCSET_DEFAULT_INITSIZE,
+												ALLOCSET_DEFAULT_MAXSIZE);
 
 	/* Allocate data that will live for the life of the hashjoin */
 
@@ -395,11 +392,10 @@ ExecHashTableCreate(Hash *node)
 	}
 
 	/*
-	 * Prepare portal for the first-scan space allocations; allocate the
+	 * Prepare context for the first-scan space allocations; allocate the
 	 * hashbucket array therein, and set each bucket "empty".
 	 */
 	MemoryContextSwitchTo(hashtable->batchCxt);
-	StartPortalAllocMode(DefaultAllocMode, 0);
 
 	hashtable->buckets = (HashJoinTuple *)
 		palloc(nbuckets * sizeof(HashJoinTuple));
@@ -435,9 +431,8 @@ ExecHashTableDestroy(HashJoinTable hashtable)
 			BufFileClose(hashtable->outerBatchFile[i]);
 	}
 
-	/* Destroy the portal to release all working memory */
-	/* cast here is a kluge for circular includes... */
-	PortalDrop((Portal *) &hashtable->myPortal);
+	/* Release working memory (batchCxt is a child, so it goes away too) */
+	MemoryContextDelete(hashtable->hashCxt);
 
 	/* And drop the control block */
 	pfree(hashtable);
@@ -676,11 +671,10 @@ ExecHashTableReset(HashJoinTable hashtable, long ntuples)
 
 	/*
 	 * Release all the hash buckets and tuples acquired in the prior pass,
-	 * and reinitialize the portal for a new pass.
+	 * and reinitialize the context for a new pass.
 	 */
+	MemoryContextReset(hashtable->batchCxt);
 	oldcxt = MemoryContextSwitchTo(hashtable->batchCxt);
-	EndPortalAllocMode();
-	StartPortalAllocMode(DefaultAllocMode, 0);
 
 	/*
 	 * We still use the same number of physical buckets as in the first
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index ac86695ee1..1ab6ae67d5 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -3,21 +3,20 @@
  * spi.c
  *				Server Programming Interface
  *
- * $Id: spi.c,v 1.46 2000/05/30 04:24:45 tgl Exp $
+ * $Id: spi.c,v 1.47 2000/06/28 03:31:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "executor/spi_priv.h"
 #include "access/printtup.h"
 
-static Portal _SPI_portal = (Portal) NULL;
 static _SPI_connection *_SPI_stack = NULL;
 static _SPI_connection *_SPI_current = NULL;
 static int	_SPI_connected = -1;
 static int	_SPI_curid = -1;
 
 DLLIMPORT uint32 SPI_processed = 0;
-DLLIMPORT SPITupleTable *SPI_tuptable;
+DLLIMPORT SPITupleTable *SPI_tuptable = NULL;
 DLLIMPORT int SPI_result;
 
 static int	_SPI_execute(char *src, int tcount, _SPI_plan *plan);
@@ -46,28 +45,6 @@ extern void ShowUsage(void);
 int
 SPI_connect()
 {
-	char		pname[64];
-	PortalVariableMemory pvmem;
-
-	/*
-	 * It's possible on startup and after commit/abort. In future we'll
-	 * catch commit/abort in some way...
-	 */
-	strcpy(pname, "<SPI manager>");
-	_SPI_portal = GetPortalByName(pname);
-	if (!PortalIsValid(_SPI_portal))
-	{
-		if (_SPI_stack != NULL) /* there was abort */
-			free(_SPI_stack);
-		_SPI_current = _SPI_stack = NULL;
-		_SPI_connected = _SPI_curid = -1;
-		SPI_processed = 0;
-		SPI_tuptable = NULL;
-		_SPI_portal = CreatePortal(pname);
-		if (!PortalIsValid(_SPI_portal))
-			elog(FATAL, "SPI_connect: global initialization failed");
-	}
-
 	/*
 	 * When procedure called by Executor _SPI_curid expected to be equal
 	 * to _SPI_connected
@@ -99,15 +76,19 @@ SPI_connect()
 	_SPI_current->processed = 0;
 	_SPI_current->tuptable = NULL;
 
-	/* Create Portal for this procedure ... */
-	snprintf(pname, 64, "<SPI %d>", _SPI_connected);
-	_SPI_current->portal = CreatePortal(pname);
-	if (!PortalIsValid(_SPI_current->portal))
-		elog(FATAL, "SPI_connect: initialization failed");
-
-	/* ... and switch to Portal' Variable memory - procedure' context */
-	pvmem = PortalGetVariableMemory(_SPI_current->portal);
-	_SPI_current->savedcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
+	/* Create memory contexts for this procedure */
+	_SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
+												  "SPI Proc",
+												  ALLOCSET_DEFAULT_MINSIZE,
+												  ALLOCSET_DEFAULT_INITSIZE,
+												  ALLOCSET_DEFAULT_MAXSIZE);
+	_SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
+												  "SPI Exec",
+												  ALLOCSET_DEFAULT_MINSIZE,
+												  ALLOCSET_DEFAULT_INITSIZE,
+												  ALLOCSET_DEFAULT_MAXSIZE);
+	/* ... and switch to procedure's context */
+	_SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
 
 	_SPI_current->savedId = GetScanCommandId();
 	SetScanCommandId(GetCurrentCommandId());
@@ -127,7 +108,10 @@ SPI_finish()
 
 	/* Restore memory context as it was before procedure call */
 	MemoryContextSwitchTo(_SPI_current->savedcxt);
-	PortalDrop(&(_SPI_current->portal));
+
+	/* Release memory used in procedure call */
+	MemoryContextDelete(_SPI_current->execCxt);
+	MemoryContextDelete(_SPI_current->procCxt);
 
 	SetScanCommandId(_SPI_current->savedId);
 
@@ -142,6 +126,7 @@ SPI_finish()
 	{
 		free(_SPI_stack);
 		_SPI_stack = NULL;
+		_SPI_current = NULL;
 	}
 	else
 	{
@@ -154,6 +139,25 @@ SPI_finish()
 
 }
 
+/*
+ * Clean up SPI state at transaction commit or abort (we don't care which).
+ */
+void
+AtEOXact_SPI(void)
+{
+	/*
+	 * Note that memory contexts belonging to SPI stack entries will be
+	 * freed automatically, so we can ignore them here.  We just need to
+	 * restore our static variables to initial state.
+	 */
+	if (_SPI_stack != NULL)		/* there was abort */
+		free(_SPI_stack);
+	_SPI_current = _SPI_stack = NULL;
+	_SPI_connected = _SPI_curid = -1;
+	SPI_processed = 0;
+	SPI_tuptable = NULL;
+}
+
 void
 SPI_push(void)
 {
@@ -508,61 +512,22 @@ SPI_palloc(Size size)
 void *
 SPI_repalloc(void *pointer, Size size)
 {
-	MemoryContext oldcxt = NULL;
-
-	if (_SPI_curid + 1 == _SPI_connected)		/* connected */
-	{
-		if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
-			elog(FATAL, "SPI: stack corrupted");
-		oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
-	}
-
-	pointer = repalloc(pointer, size);
-
-	if (oldcxt)
-		MemoryContextSwitchTo(oldcxt);
-
-	return pointer;
+	/* No longer need to worry which context chunk was in... */
+	return repalloc(pointer, size);
 }
 
 void
 SPI_pfree(void *pointer)
 {
-	MemoryContext oldcxt = NULL;
-
-	if (_SPI_curid + 1 == _SPI_connected)		/* connected */
-	{
-		if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
-			elog(FATAL, "SPI: stack corrupted");
-		oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
-	}
-
+	/* No longer need to worry which context chunk was in... */
 	pfree(pointer);
-
-	if (oldcxt)
-		MemoryContextSwitchTo(oldcxt);
-
-	return;
 }
 
 void
 SPI_freetuple(HeapTuple tuple)
 {
-	MemoryContext oldcxt = NULL;
-
-	if (_SPI_curid + 1 == _SPI_connected)		/* connected */
-	{
-		if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
-			elog(FATAL, "SPI: stack corrupted");
-		oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
-	}
-
+	/* No longer need to worry which context tuple was in... */
 	heap_freetuple(tuple);
-
-	if (oldcxt)
-		MemoryContextSwitchTo(oldcxt);
-
-	return;
 }
 
 /* =================== private functions =================== */
@@ -647,7 +612,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
 		argtypes = plan->argtypes;
 	}
 
-	queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs, FALSE);
+	queryTree_list = pg_parse_and_rewrite(src, argtypes, nargs);
 
 	_SPI_current->qtlist = queryTree_list;
 
@@ -790,7 +755,6 @@ static int
 _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
 {
 	Query	   *parseTree = queryDesc->parsetree;
-	Plan	   *plan = queryDesc->plantree;
 	int			operation = queryDesc->operation;
 	CommandDest dest = queryDesc->dest;
 	TupleDesc	tupdesc;
@@ -875,16 +839,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
 #endif
 	tupdesc = ExecutorStart(queryDesc, state);
 
-	/* Don't work currently */
+	/* Don't work currently --- need to rearrange callers so that
+	 * we prepare the portal before doing CreateExecutorState() etc.
+	 * See pquery.c for the correct order of operations.
+	 */
 	if (isRetrieveIntoPortal)
 	{
-		ProcessPortal(intoName,
-					  parseTree,
-					  plan,
-					  state,
-					  tupdesc,
-					  None);
-		return SPI_OK_CURSOR;
+		elog(FATAL, "SPI_select: retrieve into portal not implemented");
 	}
 
 	ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
@@ -920,27 +881,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
 static MemoryContext
 _SPI_execmem()
 {
-	MemoryContext oldcxt;
-	PortalHeapMemory phmem;
-
-	phmem = PortalGetHeapMemory(_SPI_current->portal);
-	oldcxt = MemoryContextSwitchTo((MemoryContext) phmem);
-
-	return oldcxt;
-
+	return MemoryContextSwitchTo(_SPI_current->execCxt);
 }
 
 static MemoryContext
 _SPI_procmem()
 {
-	MemoryContext oldcxt;
-	PortalVariableMemory pvmem;
-
-	pvmem = PortalGetVariableMemory(_SPI_current->portal);
-	oldcxt = MemoryContextSwitchTo((MemoryContext) pvmem);
-
-	return oldcxt;
-
+	return MemoryContextSwitchTo(_SPI_current->procCxt);
 }
 
 /*
@@ -959,7 +906,6 @@ _SPI_begin_call(bool execmem)
 	if (execmem)				/* switch to the Executor memory context */
 	{
 		_SPI_execmem();
-		StartPortalAllocMode(DefaultAllocMode, 0);
 	}
 
 	return 0;
@@ -977,9 +923,10 @@ _SPI_end_call(bool procmem)
 	_SPI_current->qtlist = NULL;
 
 	if (procmem)				/* switch to the procedure memory context */
-	{							/* but free Executor memory before */
-		EndPortalAllocMode();
+	{
 		_SPI_procmem();
+		/* and free Executor memory */
+		MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
 	}
 
 	return 0;
@@ -1016,8 +963,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
 	MemoryContext oldcxt = NULL;
 
 	if (location == _SPI_CPLAN_PROCXT)
-		oldcxt = MemoryContextSwitchTo((MemoryContext)
-						  PortalGetVariableMemory(_SPI_current->portal));
+		oldcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
 	else if (location == _SPI_CPLAN_TOPCXT)
 		oldcxt = MemoryContextSwitchTo(TopMemoryContext);
 
@@ -1033,7 +979,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
 	else
 		newplan->argtypes = NULL;
 
-	if (location != _SPI_CPLAN_CURCXT)
+	if (oldcxt != NULL)
 		MemoryContextSwitchTo(oldcxt);
 
 	return newplan;
diff --git a/src/backend/lib/Makefile b/src/backend/lib/Makefile
index 6b8a9d7202..428935f255 100644
--- a/src/backend/lib/Makefile
+++ b/src/backend/lib/Makefile
@@ -4,14 +4,14 @@
 #    Makefile for lib (miscellaneous stuff)
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.13 2000/05/29 05:44:45 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/lib/Makefile,v 1.14 2000/06/28 03:31:34 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
 SRCDIR = ../..
 include ../../Makefile.global
 
-OBJS = bit.o fstack.o hasht.o lispsort.o stringinfo.o dllist.o
+OBJS = bit.o hasht.o lispsort.o stringinfo.o dllist.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/lib/fstack.c b/src/backend/lib/fstack.c
deleted file mode 100644
index 9552909bc0..0000000000
--- a/src/backend/lib/fstack.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * fstack.c
- *	  Fixed format stack definitions.
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/lib/Attic/fstack.c,v 1.14 2000/01/26 05:56:26 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-#include "lib/fstack.h"
-
-/*
- * Internal function definitions
- */
-
-/*
- * FixedItemIsValid
- *		True iff item is valid.
- */
-#define FixedItemIsValid(item)	PointerIsValid(item)
-
-/*
- * FixedStackGetItemBase
- *		Returns base of enclosing structure.
- */
-#define FixedStackGetItemBase(stack, item) \
-		((Pointer)((char *)(item) - (stack)->offset))
-
-/*
- * FixedStackGetItem
- *		Returns item of given pointer to enclosing structure.
- */
-#define FixedStackGetItem(stack, pointer) \
-		((FixedItem)((char *)(pointer) + (stack)->offset))
-
-#define FixedStackIsValid(stack) ((bool)PointerIsValid(stack))
-
-/*
- * External functions
- */
-
-void
-FixedStackInit(FixedStack stack, Offset offset)
-{
-	AssertArg(PointerIsValid(stack));
-
-	stack->top = NULL;
-	stack->offset = offset;
-}
-
-Pointer
-FixedStackPop(FixedStack stack)
-{
-	Pointer		pointer;
-
-	AssertArg(FixedStackIsValid(stack));
-
-	if (!PointerIsValid(stack->top))
-		return NULL;
-
-	pointer = FixedStackGetItemBase(stack, stack->top);
-	stack->top = stack->top->next;
-
-	return pointer;
-}
-
-void
-FixedStackPush(FixedStack stack, Pointer pointer)
-{
-	FixedItem	item = FixedStackGetItem(stack, pointer);
-
-	AssertArg(FixedStackIsValid(stack));
-	AssertArg(PointerIsValid(pointer));
-
-	item->next = stack->top;
-	stack->top = item;
-}
-
-#ifdef USE_ASSERT_CHECKING
-/*
- * FixedStackContains
- *		True iff ordered stack contains given element.
- *
- * Note:
- *		This is inefficient.  It is intended for debugging use only.
- *
- * Exceptions:
- *		BadArg if stack is invalid.
- *		BadArg if pointer is invalid.
- */
-static bool
-FixedStackContains(FixedStack stack, Pointer pointer)
-{
-	FixedItem	next;
-	FixedItem	item;
-
-	AssertArg(FixedStackIsValid(stack));
-	AssertArg(PointerIsValid(pointer));
-
-	item = FixedStackGetItem(stack, pointer);
-
-	for (next = stack->top; FixedItemIsValid(next); next = next->next)
-	{
-		if (next == item)
-			return true;
-	}
-	return false;
-}
-
-#endif
-
-Pointer
-FixedStackGetTop(FixedStack stack)
-{
-	AssertArg(FixedStackIsValid(stack));
-
-	if (!PointerIsValid(stack->top))
-		return NULL;
-
-	return FixedStackGetItemBase(stack, stack->top);
-}
-
-Pointer
-FixedStackGetNext(FixedStack stack, Pointer pointer)
-{
-	FixedItem	item;
-
-	/* AssertArg(FixedStackIsValid(stack)); */
-	/* AssertArg(PointerIsValid(pointer)); */
-	AssertArg(FixedStackContains(stack, pointer));
-
-	item = FixedStackGetItem(stack, pointer)->next;
-
-	if (!PointerIsValid(item))
-		return NULL;
-
-	return FixedStackGetItemBase(stack, item);
-}
diff --git a/src/backend/lib/stringinfo.c b/src/backend/lib/stringinfo.c
index 4f2df74684..379cd79502 100644
--- a/src/backend/lib/stringinfo.c
+++ b/src/backend/lib/stringinfo.c
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *	  $Id: stringinfo.c,v 1.25 2000/04/12 17:15:11 momjian Exp $
+ *	  $Id: stringinfo.c,v 1.26 2000/06/28 03:31:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,8 +29,6 @@ makeStringInfo(void)
 	StringInfo	res;
 
 	res = (StringInfo) palloc(sizeof(StringInfoData));
-	if (res == NULL)
-		elog(ERROR, "makeStringInfo: Out of memory");
 
 	initStringInfo(res);
 
@@ -49,9 +47,6 @@ initStringInfo(StringInfo str)
 	int			size = 256;		/* initial default buffer size */
 
 	str->data = (char *) palloc(size);
-	if (str->data == NULL)
-		elog(ERROR,
-			 "initStringInfo: Out of memory (%d bytes requested)", size);
 	str->maxlen = size;
 	str->len = 0;
 	str->data[0] = '\0';
@@ -62,6 +57,11 @@ initStringInfo(StringInfo str)
  *
  * Internal routine: make sure there is enough space for 'needed' more bytes
  * ('needed' does not include the terminating null).
+ *
+ * NB: because we use repalloc() to enlarge the buffer, the string buffer
+ * will remain allocated in the same memory context that was current when
+ * initStringInfo was called, even if another context is now current.
+ * This is the desired and indeed critical behavior!
  */
 static void
 enlargeStringInfo(StringInfo str, int needed)
@@ -83,9 +83,6 @@ enlargeStringInfo(StringInfo str, int needed)
 		newlen = 2 * newlen;
 
 	str->data = (char *) repalloc(str->data, newlen);
-	if (str->data == NULL)
-		elog(ERROR,
-		"enlargeStringInfo: Out of memory (%d bytes requested)", newlen);
 
 	str->maxlen = newlen;
 }
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index a12ae3a8a8..75f6562a8f 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.46 2000/06/09 01:11:06 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.47 2000/06/28 03:31:41 tgl Exp $
  *
  * NOTES
  *	  This should be moved to a more appropriate place.  It is here
@@ -16,7 +16,7 @@
  *
  *	  Builtin functions for open/close/read/write operations on large objects.
  *
- *	  These functions operate in a private GlobalMemoryContext, which means
+ *	  These functions operate in a private MemoryContext, which means
  *	  that large object descriptors hang around until we destroy the context.
  *	  That happens in lo_commit().	It'd be possible to prolong the lifetime
  *	  of the context so that LO FDs are good across transactions (for example,
@@ -24,8 +24,10 @@
  *	  But we'd need additional state in order to do the right thing at the
  *	  end of an aborted transaction.  FDs opened during an aborted xact would
  *	  still need to be closed, since they might not be pointing at valid
- *	  relations at all.  For now, we'll stick with the existing documented
- *	  semantics of LO FDs: they're only good within a transaction.
+ *	  relations at all.  Locking semantics are also an interesting problem
+ *	  if LOs stay open across transactions.  For now, we'll stick with the
+ *	  existing documented semantics of LO FDs: they're only good within a
+ *	  transaction.
  *
  *-------------------------------------------------------------------------
  */
@@ -56,7 +58,7 @@
  */
 static LargeObjectDesc *cookies[MAX_LOBJ_FDS];
 
-static GlobalMemory fscxt = NULL;
+static MemoryContext fscxt = NULL;
 
 
 static int	newLOfd(LargeObjectDesc *lobjCookie);
@@ -80,8 +82,13 @@ lo_open(PG_FUNCTION_ARGS)
 #endif
 
 	if (fscxt == NULL)
-		fscxt = CreateGlobalMemory("Filesystem");
-	currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+		fscxt = AllocSetContextCreate(TopMemoryContext,
+									  "Filesystem",
+									  ALLOCSET_DEFAULT_MINSIZE,
+									  ALLOCSET_DEFAULT_INITSIZE,
+									  ALLOCSET_DEFAULT_MAXSIZE);
+
+	currentContext = MemoryContextSwitchTo(fscxt);
 
 	lobjDesc = inv_open(lobjId, mode);
 
@@ -128,7 +135,7 @@ lo_close(PG_FUNCTION_ARGS)
 #endif
 
 	Assert(fscxt != NULL);
-	currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+	currentContext = MemoryContextSwitchTo(fscxt);
 
 	inv_close(cookies[fd]);
 
@@ -166,7 +173,7 @@ lo_read(int fd, char *buf, int len)
 	}
 
 	Assert(fscxt != NULL);
-	currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+	currentContext = MemoryContextSwitchTo(fscxt);
 
 	status = inv_read(cookies[fd], buf, len);
 
@@ -193,7 +200,7 @@ lo_write(int fd, char *buf, int len)
 	}
 
 	Assert(fscxt != NULL);
-	currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+	currentContext = MemoryContextSwitchTo(fscxt);
 
 	status = inv_write(cookies[fd], buf, len);
 
@@ -224,7 +231,7 @@ lo_lseek(PG_FUNCTION_ARGS)
 	}
 
 	Assert(fscxt != NULL);
-	currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+	currentContext = MemoryContextSwitchTo(fscxt);
 
 	status = inv_seek(cookies[fd], offset, whence);
 
@@ -242,9 +249,13 @@ lo_creat(PG_FUNCTION_ARGS)
 	Oid			lobjId;
 
 	if (fscxt == NULL)
-		fscxt = CreateGlobalMemory("Filesystem");
+		fscxt = AllocSetContextCreate(TopMemoryContext,
+									  "Filesystem",
+									  ALLOCSET_DEFAULT_MINSIZE,
+									  ALLOCSET_DEFAULT_INITSIZE,
+									  ALLOCSET_DEFAULT_MAXSIZE);
 
-	currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+	currentContext = MemoryContextSwitchTo(fscxt);
 
 	lobjDesc = inv_create(mode);
 
@@ -493,7 +504,7 @@ lo_commit(bool isCommit)
 	if (fscxt == NULL)
 		return;					/* no LO operations in this xact */
 
-	currentContext = MemoryContextSwitchTo((MemoryContext) fscxt);
+	currentContext = MemoryContextSwitchTo(fscxt);
 
 	/*
 	 * Clean out still-open index scans (not necessary if aborting) and
@@ -512,7 +523,7 @@ lo_commit(bool isCommit)
 	MemoryContextSwitchTo(currentContext);
 
 	/* Release the LO memory context to prevent permanent memory leaks. */
-	GlobalMemoryDestroy(fscxt);
+	MemoryContextDelete(fscxt);
 	fscxt = NULL;
 }
 
diff --git a/src/backend/libpq/be-pqexec.c b/src/backend/libpq/be-pqexec.c
index 42d48281e0..c76889a7a7 100644
--- a/src/backend/libpq/be-pqexec.c
+++ b/src/backend/libpq/be-pqexec.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.32 2000/05/28 17:55:56 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.33 2000/06/28 03:31:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -135,9 +135,11 @@ PQexec(char *query)
 	/* ----------------
 	 *	pg_exec_query_dest will put the query results in a portal which will
 	 *	end up on the top of the portal stack.
+	 *
+	 * XXX memory context manipulation needs thought here.
 	 * ----------------
 	 */
-	pg_exec_query_dest(query, Local, FALSE);
+	pg_exec_query_dest(query, Local, CurrentMemoryContext);
 
 	/* ----------------
 	 *	pop the portal off the portal stack and return the
diff --git a/src/backend/libpq/pqsignal.c b/src/backend/libpq/pqsignal.c
index 04ebd7dd57..4648fe455f 100644
--- a/src/backend/libpq/pqsignal.c
+++ b/src/backend/libpq/pqsignal.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.15 2000/06/11 11:39:50 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/libpq/pqsignal.c,v 1.16 2000/06/28 03:31:41 tgl Exp $
  *
  * NOTES
  *		This shouldn't be in libpq, but the monitor and some other
@@ -44,6 +44,44 @@
 
 #include "libpq/pqsignal.h"
 
+
+/*
+ * Initialize BlockSig and UnBlockSig.
+ *
+ * BlockSig is the set of signals to block when we are trying to block
+ * signals.  This includes all signals we normally expect to get, but NOT
+ * signals that should never be turned off.
+ *
+ * UnBlockSig is the set of signals to block when we don't want to block
+ * signals (is this ever nonzero??)
+ */
+void
+pqinitmask(void)
+{
+#ifdef HAVE_SIGPROCMASK
+	sigemptyset(&UnBlockSig);
+	sigfillset(&BlockSig);
+	sigdelset(&BlockSig, SIGABRT);
+	sigdelset(&BlockSig, SIGILL);
+	sigdelset(&BlockSig, SIGSEGV);
+	sigdelset(&BlockSig, SIGBUS);
+	sigdelset(&BlockSig, SIGTRAP);
+	sigdelset(&BlockSig, SIGCONT);
+	sigdelset(&BlockSig, SIGSYS);
+#else
+	UnBlockSig = 0;
+	BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) |
+		sigmask(SIGTERM) | sigmask(SIGALRM) |
+		sigmask(SIGINT) | sigmask(SIGUSR1) |
+		sigmask(SIGUSR2) | sigmask(SIGCHLD) |
+		sigmask(SIGWINCH) | sigmask(SIGFPE);
+#endif
+}
+
+
+/*
+ * Set up a signal handler
+ */
 pqsigfunc
 pqsignal(int signo, pqsigfunc func)
 {
diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c
index f3e009f5d1..fa46fac6c8 100644
--- a/src/backend/optimizer/geqo/geqo_eval.c
+++ b/src/backend/optimizer/geqo/geqo_eval.c
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: geqo_eval.c,v 1.50 2000/05/30 00:49:46 momjian Exp $
+ * $Id: geqo_eval.c,v 1.51 2000/06/28 03:31:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,9 +19,9 @@
    =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
  */
 
-#include <math.h>
-
 #include "postgres.h"
+
+#include <math.h>
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
 #else
@@ -33,41 +33,8 @@
 #include "optimizer/geqo.h"
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
-#include "utils/portal.h"
-
-
-/*
- * Variables set by geqo_eval_startup for use within a single GEQO run
- */
-static MemoryContext geqo_eval_context;
-
-/*
- * geqo_eval_startup:
- *	 Must be called during geqo_main startup (before geqo_eval may be called)
- *
- * The main thing we need to do here is prepare a private memory context for
- * allocation of temp storage used while constructing a path in geqo_eval().
- * Since geqo_eval() will be called many times, we can't afford to let all
- * that memory go unreclaimed until end of statement.  We use a special
- * named portal to hold the context, so that it will be freed even if
- * we abort via elog(ERROR).  The working data is allocated in the portal's
- * heap memory context.
- */
-void
-geqo_eval_startup(void)
-{
-#define GEQO_PORTAL_NAME	"<geqo workspace>"
-	Portal		geqo_portal = GetPortalByName(GEQO_PORTAL_NAME);
-
-	if (!PortalIsValid(geqo_portal))
-	{
-		/* First time through (within current transaction, that is) */
-		geqo_portal = CreatePortal(GEQO_PORTAL_NAME);
-		Assert(PortalIsValid(geqo_portal));
-	}
+#include "utils/memutils.h"
 
-	geqo_eval_context = (MemoryContext) PortalGetHeapMemory(geqo_portal);
-}
 
 /*
  * geqo_eval
@@ -77,20 +44,30 @@ geqo_eval_startup(void)
 Cost
 geqo_eval(Query *root, Gene *tour, int num_gene)
 {
+	MemoryContext mycontext;
 	MemoryContext oldcxt;
 	RelOptInfo *joinrel;
 	Cost		fitness;
 	List	   *savelist;
 
-	/* preserve root->join_rel_list, which gimme_tree changes */
-	savelist = root->join_rel_list;
-
 	/*
-	 * create a temporary allocation context for the path construction
-	 * work
+	 * Create a private memory context that will hold all temp storage
+	 * allocated inside gimme_tree().
+	 *
+	 * Since geqo_eval() will be called many times, we can't afford to let
+	 * all that memory go unreclaimed until end of statement.  Note we make
+	 * the temp context a child of TransactionCommandContext, so that
+	 * it will be freed even if we abort via elog(ERROR).
 	 */
-	oldcxt = MemoryContextSwitchTo(geqo_eval_context);
-	StartPortalAllocMode(DefaultAllocMode, 0);
+	mycontext = AllocSetContextCreate(TransactionCommandContext,
+									  "GEQO",
+									  ALLOCSET_DEFAULT_MINSIZE,
+									  ALLOCSET_DEFAULT_INITSIZE,
+									  ALLOCSET_DEFAULT_MAXSIZE);
+	oldcxt = MemoryContextSwitchTo(mycontext);
+
+	/* preserve root->join_rel_list, which gimme_tree changes */
+	savelist = root->join_rel_list;
 
 	/* construct the best path for the given combination of relations */
 	joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
@@ -107,8 +84,8 @@ geqo_eval(Query *root, Gene *tour, int num_gene)
 	root->join_rel_list = savelist;
 
 	/* release all the memory acquired within gimme_tree */
-	EndPortalAllocMode();
 	MemoryContextSwitchTo(oldcxt);
+	MemoryContextDelete(mycontext);
 
 	return fitness;
 }
diff --git a/src/backend/optimizer/geqo/geqo_main.c b/src/backend/optimizer/geqo/geqo_main.c
index b00e9823bd..4f2f63572c 100644
--- a/src/backend/optimizer/geqo/geqo_main.c
+++ b/src/backend/optimizer/geqo/geqo_main.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: geqo_main.c,v 1.21 2000/05/31 00:28:19 petere Exp $
+ * $Id: geqo_main.c,v 1.22 2000/06/28 03:31:45 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -110,9 +110,6 @@ geqo(Query *root)
     else
         srandom(time(NULL));
 
-/* initialize plan evaluator */
-	geqo_eval_startup();
-
 /* allocate genetic pool memory */
 	pool = alloc_pool(pool_size, number_of_rels);
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index f712d7cfec..135b6d5950 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.149 2000/06/22 22:31:20 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.150 2000/06/28 03:31:52 tgl Exp $
  *
  * NOTES
  *
@@ -378,15 +378,38 @@ PostmasterMain(int argc, char *argv[])
 	 */
 	umask((mode_t) 0077);
 
-	ResetAllOptions();
-
 	MyProcPid = getpid();
+
+	/*
+	 * Fire up essential subsystems: error and memory management
+	 */
+	EnableExceptionHandling(true);
+	MemoryContextInit();
+
+	/*
+	 * By default, palloc() requests in the postmaster will be allocated
+	 * in the PostmasterContext, which is space that can be recycled by
+	 * backends.  Allocated data that needs to be available to backends
+	 * should be allocated in TopMemoryContext.
+	 */
+	PostmasterContext = AllocSetContextCreate(TopMemoryContext,
+											  "Postmaster",
+											  ALLOCSET_DEFAULT_MINSIZE,
+											  ALLOCSET_DEFAULT_INITSIZE,
+											  ALLOCSET_DEFAULT_MAXSIZE);
+	MemoryContextSwitchTo(PostmasterContext);
+
+	/*
+	 * Options setup
+	 */
 	if (getenv("PGDATA"))
 		DataDir = strdup(getenv("PGDATA")); /* default value */
 
 	if (getenv("PGPORT"))
 		PostPortName = atoi(getenv("PGPORT"));
 
+	ResetAllOptions();
+
 	/*
 	 * First we must scan for a -D argument to get the data dir. Then
 	 * read the config file. Finally, scan all the other arguments.
@@ -600,7 +623,6 @@ PostmasterMain(int argc, char *argv[])
 	}
 #endif
 	/* set up shared memory and semaphores */
-	EnableMemoryContext(TRUE);
 	reset_shared(PostPortName);
 
 	/*
@@ -662,7 +684,7 @@ PostmasterMain(int argc, char *argv[])
 	/*
 	 * Set up signal handlers for the postmaster process.
 	 */
-	PG_INITMASK();
+	pqinitmask();
 	PG_SETMASK(&BlockSig);
 
 	pqsignal(SIGHUP, SIGHUP_handler);	/* reread config file and have children do same */
@@ -1867,6 +1889,7 @@ DoBackend(Port *port)
 	/* Save port etc. for ps status */
 	MyProcPort = port;
 
+	/* Reset MyProcPid to new backend's pid */
 	MyProcPid = getpid();
 
 	/*
@@ -1946,6 +1969,19 @@ DoBackend(Port *port)
 
 	av[ac] = (char *) NULL;
 
+	/*
+	 * Release postmaster's working memory context so that backend can
+	 * recycle the space.  Note we couldn't do it earlier than here,
+	 * because port pointer is pointing into that space!  But now we
+	 * have copied all the interesting info into safe local storage.
+	 */
+	MemoryContextSwitchTo(TopMemoryContext);
+	MemoryContextDelete(PostmasterContext);
+	PostmasterContext = NULL;
+
+	/*
+	 * Debug: print arguments being passed to backend
+	 */
 	if (DebugLvl > 1)
 	{
 		fprintf(stderr, "%s child[%d]: starting with (",
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 40ebf3e02c..08351fe669 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.46 2000/06/15 04:09:58 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.47 2000/06/28 03:31:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,51 +16,20 @@
 #include "postgres.h"
 
 #include "access/heapam.h"
-#include "lib/stringinfo.h"
+#include "utils/builtins.h"
+#include "catalog/catname.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_rewrite.h"
 #include "parser/parse_relation.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteSupport.h"
-#include "tcop/tcopprot.h"
 
-Oid			LastOidProcessed = InvalidOid;
-
-
-/*
- * Convert given string to a suitably quoted string constant,
- * and append it to the StringInfo buffer.
- * XXX Any MULTIBYTE considerations here?
- */
-static void
-quoteString(StringInfo buf, char *source)
-{
-	char	   *current;
-
-	appendStringInfoChar(buf, '\'');
-	for (current = source; *current; current++)
-	{
-		char		ch = *current;
-
-		if (ch == '\'' || ch == '\\')
-		{
-			appendStringInfoChar(buf, '\\');
-			appendStringInfoChar(buf, ch);
-		}
-		else if (ch >= 0 && ch < ' ')
-			appendStringInfo(buf, "\\%03o", (int) ch);
-		else
-			appendStringInfoChar(buf, ch);
-	}
-	appendStringInfoChar(buf, '\'');
-}
 
 /*
  * InsertRule -
  *	  takes the arguments and inserts them as attributes into the system
  *	  relation "pg_rewrite"
  *
- *		MODS :	changes the value of LastOidProcessed as a side
- *				effect of inserting the rule tuple
- *
  *		ARGS :	rulname			-		name of the rule
  *				evtype			-		one of RETRIEVE,REPLACE,DELETE,APPEND
  *				evobj			-		name of relation
@@ -78,11 +47,17 @@ InsertRule(char *rulname,
 		   bool evinstead,
 		   char *actiontree)
 {
-	StringInfoData rulebuf;
 	Relation	eventrel;
 	Oid			eventrel_oid;
 	AttrNumber	evslot_index;
-	char	   *is_instead = "f";
+	int			i;
+	Datum		values[Natts_pg_rewrite];
+	char		nulls[Natts_pg_rewrite];
+	NameData	rname;
+	Relation	pg_rewrite_desc;
+	TupleDesc	tupDesc;
+	HeapTuple	tup;
+	Oid			rewriteObjectId;
 
 	eventrel = heap_openr(evobj, AccessShareLock);
 	eventrel_oid = RelationGetRelid(eventrel);
@@ -96,9 +71,6 @@ InsertRule(char *rulname,
 		evslot_index = attnameAttNum(eventrel, evslot);
 	heap_close(eventrel, AccessShareLock);
 
-	if (evinstead)
-		is_instead = "t";
-
 	if (evqual == NULL)
 		evqual = "<>";
 
@@ -106,23 +78,54 @@ InsertRule(char *rulname,
 		elog(ERROR, "Attempt to insert rule '%s' failed: already exists",
 			 rulname);
 
-	initStringInfo(&rulebuf);
-	appendStringInfo(&rulebuf,
-					 "INSERT INTO pg_rewrite (rulename, ev_type, ev_class, ev_attr, ev_action, ev_qual, is_instead) VALUES (");
-	quoteString(&rulebuf, rulname);
-	appendStringInfo(&rulebuf, ", %d::char, %u::oid, %d::int2, ",
-					 evtype, eventrel_oid, evslot_index);
-	quoteString(&rulebuf, actiontree);
-	appendStringInfo(&rulebuf, "::text, ");
-	quoteString(&rulebuf, evqual);
-	appendStringInfo(&rulebuf, "::text, '%s'::bool);",
-					 is_instead);
+	/* ----------------
+	 *	Set up *nulls and *values arrays
+	 * ----------------
+	 */
+	MemSet(nulls, ' ', sizeof(nulls));
+
+	i = 0;
+	namestrcpy(&rname, rulname);
+	values[i++] = NameGetDatum(&rname);
+	values[i++] = CharGetDatum(evtype + '0');
+	values[i++] = ObjectIdGetDatum(eventrel_oid);
+	values[i++] = Int16GetDatum(evslot_index);
+	values[i++] = BoolGetDatum(evinstead);
+	values[i++] = PointerGetDatum(lztextin(evqual));
+	values[i++] = PointerGetDatum(lztextin(actiontree));
+
+	/* ----------------
+	 *	create a new pg_rewrite tuple
+	 * ----------------
+	 */
+	pg_rewrite_desc = heap_openr(RewriteRelationName, RowExclusiveLock);
+
+	tupDesc = pg_rewrite_desc->rd_att;
+
+	tup = heap_formtuple(tupDesc,
+						 values,
+						 nulls);
+
+	heap_insert(pg_rewrite_desc, tup);
+
+	rewriteObjectId = tup->t_data->t_oid;
+
+	if (RelationGetForm(pg_rewrite_desc)->relhasindex)
+	{
+		Relation	idescs[Num_pg_rewrite_indices];
+
+		CatalogOpenIndices(Num_pg_rewrite_indices, Name_pg_rewrite_indices,
+						   idescs);
+		CatalogIndexInsert(idescs, Num_pg_rewrite_indices, pg_rewrite_desc,
+						   tup);
+		CatalogCloseIndices(Num_pg_rewrite_indices, idescs);
+	}
 
-	pg_exec_query_dest(rulebuf.data, None, true);
+	heap_freetuple(tup);
 
-	pfree(rulebuf.data);
+	heap_close(pg_rewrite_desc, RowExclusiveLock);
 
-	return LastOidProcessed;
+	return rewriteObjectId;
 }
 
 /*
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index 9a5f486241..113e0b73c5 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.41 2000/01/26 05:56:50 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.42 2000/06/28 03:31:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,7 +136,7 @@ prs2_addToRelation(Oid relid,
 	 * create an in memory RewriteRule data structure which is cached by
 	 * every Relation descriptor. (see utils/cache/relcache.c)
 	 */
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 	thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
 	if (qual != NULL)
 		qual = copyObject(qual);
@@ -159,7 +159,7 @@ prs2_addToRelation(Oid relid,
 	if (relation->rd_rules == NULL)
 	{
 
-		oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+		oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 		rulelock = (RuleLock *) palloc(sizeof(RuleLock));
 		rulelock->numLocks = 1;
 		rulelock->rules = (RewriteRule **) palloc(sizeof(RewriteRule *));
@@ -181,7 +181,7 @@ prs2_addToRelation(Oid relid,
 		rulelock = relation->rd_rules;
 		numlock = rulelock->numLocks;
 		/* expand, for safety reasons */
-		oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+		oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 		rulelock->rules = (RewriteRule **) repalloc(rulelock->rules,
 								  sizeof(RewriteRule *) * (numlock + 1));
 		MemoryContextSwitchTo(oldcxt);
@@ -212,7 +212,7 @@ prs2_deleteFromRelation(Oid relid, Oid ruleId)
 			break;
 	}
 	Assert(i < numlock);
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 	pfree(rulelock->rules[i]);
 	MemoryContextSwitchTo(oldcxt);
 	if (numlock == 1)
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 8b7ad3874b..4c590a2774 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.51 2000/05/30 00:49:52 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.52 2000/06/28 03:31:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -262,29 +262,23 @@ InitShmem(unsigned int key, unsigned int size)
 }
 
 /*
- * ShmemAlloc -- allocate word-aligned byte string from
- *		shared memory
+ * ShmemAlloc -- allocate max-aligned byte string from shared memory
  *
  * Assumes ShmemLock and ShmemFreeStart are initialized.
  * Returns: real pointer to memory or NULL if we are out
  *		of space.  Has to return a real pointer in order
- *		to be compatable with malloc().
+ *		to be compatible with malloc().
  */
-long *
-ShmemAlloc(unsigned long size)
+void *
+ShmemAlloc(Size size)
 {
 	unsigned long tmpFree;
-	long	   *newSpace;
+	void	   *newSpace;
 
 	/*
-	 * ensure space is word aligned.
-	 *
-	 * Word-alignment is not good enough. We have to be more conservative:
-	 * doubles need 8-byte alignment. (We probably only need this on RISC
-	 * platforms but this is not a big waste of space.) - ay 12/94
+	 * ensure all space is adequately aligned.
 	 */
-	if (size % sizeof(double))
-		size += sizeof(double) - (size % sizeof(double));
+	size = MAXALIGN(size);
 
 	Assert(*ShmemFreeStart);
 
@@ -293,7 +287,7 @@ ShmemAlloc(unsigned long size)
 	tmpFree = *ShmemFreeStart + size;
 	if (tmpFree <= ShmemSize)
 	{
-		newSpace = (long *) MAKE_PTR(*ShmemFreeStart);
+		newSpace = (void *) MAKE_PTR(*ShmemFreeStart);
 		*ShmemFreeStart += size;
 	}
 	else
@@ -302,7 +296,8 @@ ShmemAlloc(unsigned long size)
 	SpinRelease(ShmemLock);
 
 	if (!newSpace)
-		elog(NOTICE, "ShmemAlloc: out of memory ");
+		elog(NOTICE, "ShmemAlloc: out of memory");
+
 	return newSpace;
 }
 
@@ -336,7 +331,7 @@ ShmemInitHash(char *name,		/* table string name for shmem index */
 			  int hash_flags)	/* info about infoP */
 {
 	bool		found;
-	long	   *location;
+	void	   *location;
 
 	/*
 	 * Hash tables allocated in shared memory have a fixed directory; it
@@ -478,12 +473,12 @@ ShmemPIDDestroy(int pid)
  *		the object is already in the shmem index (hence, already
  *		initialized).
  */
-long *
-ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
+void *
+ShmemInitStruct(char *name, Size size, bool *foundPtr)
 {
 	ShmemIndexEnt *result,
 				item;
-	long	   *structPtr;
+	void	   *structPtr;
 
 	strncpy(item.key, name, SHMEM_INDEX_KEYSIZE);
 	item.location = BAD_LOCATION;
@@ -498,27 +493,27 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
 #endif
 
 		/*
-		 * If the shmem index doesnt exist, we fake it.
+		 * If the shmem index doesn't exist, we fake it.
 		 *
 		 * If we are creating the first shmem index, then let shmemalloc()
 		 * allocate the space for a new HTAB.  Otherwise, find the old one
 		 * and return that.  Notice that the ShmemIndexLock is held until
 		 * the shmem index has been completely initialized.
 		 */
-		Assert(!strcmp(name, strname));
+		Assert(strcmp(name, strname) == 0);
 		if (ShmemBootstrap)
 		{
 			/* in POSTMASTER/Single process */
 
 			*foundPtr = FALSE;
-			return (long *) ShmemAlloc(size);
+			return ShmemAlloc(size);
 		}
 		else
 		{
 			Assert(ShmemIndexOffset);
 
 			*foundPtr = TRUE;
-			return (long *) MAKE_PTR(*ShmemIndexOffset);
+			return (void *) MAKE_PTR(*ShmemIndexOffset);
 		}
 
 
@@ -554,12 +549,12 @@ ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
 			/* let caller print its message too */
 			return NULL;
 		}
-		structPtr = (long *) MAKE_PTR(result->location);
+		structPtr = (void *) MAKE_PTR(result->location);
 	}
 	else
 	{
 		/* It isn't in the table yet. allocate and initialize it */
-		structPtr = ShmemAlloc((long) size);
+		structPtr = ShmemAlloc(size);
 		if (!structPtr)
 		{
 			/* out of memory */
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index 474f2616aa..5ca3b7e826 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.71 2000/06/17 23:41:39 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.72 2000/06/28 03:32:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1090,7 +1090,7 @@ inv_newtuple(LargeObjectDesc *obj_desc,
 
 	ntup->t_len = tupsize;
 	ItemPointerSet(&ntup->t_self, BufferGetBlockNumber(buffer), off);
-	LastOidProcessed = ntup->t_data->t_oid = newoid();
+	ntup->t_data->t_oid = newoid();
 	TransactionIdStore(GetCurrentTransactionId(), &(ntup->t_data->t_xmin));
 	ntup->t_data->t_cmin = GetCurrentCommandId();
 	StoreInvalidTransactionId(&(ntup->t_data->t_xmax));
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index d18739497b..12a8372c7c 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.69 2000/06/04 01:44:32 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.70 2000/06/28 03:32:07 tgl Exp $
  *
  * NOTES
  *	  Outside modules can create a lock table and acquire/release
@@ -225,6 +225,11 @@ LockMethodInit(LOCKMETHODTABLE *lockMethodTable,
  *		has its name stored in the shmem index at its creation.  It
  *		is wasteful, in this case, but not much space is involved.
  *
+ * NOTE: data structures allocated here are allocated permanently, using
+ * TopMemoryContext and shared memory.  We don't ever release them anyway,
+ * and in normal multi-backend operation the lock table structures set up
+ * by the postmaster are inherited by each backend, so they must be in
+ * TopMemoryContext.
  */
 LOCKMETHOD
 LockMethodTableInit(char *tabName,
@@ -246,22 +251,13 @@ LockMethodTableInit(char *tabName,
 		return INVALID_LOCKMETHOD;
 	}
 
-	/* allocate a string for the shmem index table lookup */
-	shmemName = (char *) palloc((unsigned) (strlen(tabName) + 32));
-	if (!shmemName)
-	{
-		elog(NOTICE, "LockMethodTableInit: couldn't malloc string %s \n", tabName);
-		return INVALID_LOCKMETHOD;
-	}
+	/* Allocate a string for the shmem index table lookups. */
+	/* This is just temp space in this routine, so palloc is OK. */
+	shmemName = (char *) palloc(strlen(tabName) + 32);
 
-	/* each lock table has a non-shared header */
-	lockMethodTable = (LOCKMETHODTABLE *) palloc((unsigned) sizeof(LOCKMETHODTABLE));
-	if (!lockMethodTable)
-	{
-		elog(NOTICE, "LockMethodTableInit: couldn't malloc lock table %s\n", tabName);
-		pfree(shmemName);
-		return INVALID_LOCKMETHOD;
-	}
+	/* each lock table has a non-shared, permanent header */
+	lockMethodTable = (LOCKMETHODTABLE *)
+		MemoryContextAlloc(TopMemoryContext, sizeof(LOCKMETHODTABLE));
 
 	/* ------------------------
 	 * find/acquire the spinlock for the table
@@ -269,7 +265,6 @@ LockMethodTableInit(char *tabName,
 	 */
 	SpinAcquire(LockMgrLock);
 
-
 	/* -----------------------
 	 * allocate a control structure from shared memory or attach to it
 	 * if it already exists.
@@ -277,7 +272,7 @@ LockMethodTableInit(char *tabName,
 	 */
 	sprintf(shmemName, "%s (ctl)", tabName);
 	lockMethodTable->ctl = (LOCKMETHODCTL *)
-		ShmemInitStruct(shmemName, (unsigned) sizeof(LOCKMETHODCTL), &found);
+		ShmemInitStruct(shmemName, sizeof(LOCKMETHODCTL), &found);
 
 	if (!lockMethodTable->ctl)
 	{
@@ -910,7 +905,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode)
 	LOCK_PRINT("WaitOnLock: sleeping on lock", lock, lockmode);
 
 	old_status = pstrdup(get_ps_display());
-	new_status = palloc(strlen(get_ps_display()) + 10);
+	new_status = (char *) palloc(strlen(get_ps_display()) + 10);
 	strcpy(new_status, get_ps_display());
 	strcat(new_status, " waiting");
 	set_ps_display(new_status);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index ed41e43727..de2b406f87 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,7 @@
  *		This is so that we can support more backends. (system-wide semaphore
  *		sets run out pretty fast.)				  -ay 4/95
  *
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.75 2000/06/15 04:10:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.76 2000/06/28 03:32:07 tgl Exp $
  */
 #include <sys/time.h>
 #include <unistd.h>
@@ -119,7 +119,7 @@ InitProcGlobal(IPCKey key, int maxBackends)
 
 	/* attach to the free list */
 	ProcGlobal = (PROC_HDR *)
-		ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
+		ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
 
 	/* --------------------
 	 * We're the first - initialize.
@@ -185,7 +185,7 @@ InitProcess(IPCKey key)
 
 	/* attach to the free list */
 	ProcGlobal = (PROC_HDR *)
-		ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
+		ShmemInitStruct("Proc Header", sizeof(PROC_HDR), &found);
 	if (!found)
 	{
 		/* this should not happen. InitProcGlobal() is called before this. */
@@ -218,7 +218,7 @@ InitProcess(IPCKey key)
 		 * cleanup dead processes).
 		 */
 
-		MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
+		MyProc = (PROC *) ShmemAlloc(sizeof(PROC));
 		if (!MyProc)
 		{
 			SpinRelease(ProcStructLock);
@@ -458,7 +458,7 @@ ProcQueueAlloc(char *name)
 {
 	bool		found;
 	PROC_QUEUE *queue = (PROC_QUEUE *)
-	ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
+		ShmemInitStruct(name, sizeof(PROC_QUEUE), &found);
 
 	if (!queue)
 		return NULL;
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 19433ae29a..de51e703f8 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.71 2000/06/19 23:37:08 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.72 2000/06/28 03:32:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -94,19 +94,15 @@ static BlockNumber _mdnblocks(File file, Size blcksz);
 int
 mdinit()
 {
-	MemoryContext oldcxt;
 	int			i;
 
-	MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
-	if (MdCxt == (MemoryContext) NULL)
-		return SM_FAIL;
-
-	oldcxt = MemoryContextSwitchTo(MdCxt);
-	Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
-	MemoryContextSwitchTo(oldcxt);
+	MdCxt = AllocSetContextCreate(TopMemoryContext,
+								  "MdSmgr",
+								  ALLOCSET_DEFAULT_MINSIZE,
+								  ALLOCSET_DEFAULT_INITSIZE,
+								  ALLOCSET_DEFAULT_MAXSIZE);
 
-	if (Md_fdvec == (MdfdVec *) NULL)
-		return SM_FAIL;
+	Md_fdvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
 
 	MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
 
@@ -208,7 +204,6 @@ mdunlink(Relation reln)
 	int			nblocks;
 	int			fd;
 	MdfdVec    *v;
-	MemoryContext oldcxt;
 
 	/*
 	 * If the relation is already unlinked,we have nothing to do any more.
@@ -238,7 +233,6 @@ mdunlink(Relation reln)
 
 	Md_fdvec[fd].mdfd_flags = (uint16) 0;
 
-	oldcxt = MemoryContextSwitchTo(MdCxt);
 #ifndef LET_OS_MANAGE_FILESIZE
 	for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
 	{
@@ -256,7 +250,6 @@ mdunlink(Relation reln)
 	FileTruncate(v->mdfd_vfd, 0);
 	FileUnlink(v->mdfd_vfd);
 #endif
-	MemoryContextSwitchTo(oldcxt);
 
 	_fdvec_free(fd);
 
@@ -400,9 +393,7 @@ static void
 mdclose_fd(int fd)
 {
 	MdfdVec    *v;
-	MemoryContext oldcxt;
 
-	oldcxt = MemoryContextSwitchTo(MdCxt);
 #ifndef LET_OS_MANAGE_FILESIZE
 	for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
 	{
@@ -446,7 +437,6 @@ mdclose_fd(int fd)
 		}
 	}
 #endif
-	MemoryContextSwitchTo(oldcxt);
 
 	_fdvec_free(fd);
 }
@@ -751,11 +741,8 @@ mdtruncate(Relation reln, int nblocks)
 	int			curnblk;
 	int			fd;
 	MdfdVec    *v;
-
 #ifndef LET_OS_MANAGE_FILESIZE
-	MemoryContext oldcxt;
 	int			priorblocks;
-
 #endif
 
 	/*
@@ -772,7 +759,6 @@ mdtruncate(Relation reln, int nblocks)
 	v = &Md_fdvec[fd];
 
 #ifndef LET_OS_MANAGE_FILESIZE
-	oldcxt = MemoryContextSwitchTo(MdCxt);
 	priorblocks = 0;
 	while (v != (MdfdVec *) NULL)
 	{
@@ -825,7 +811,6 @@ mdtruncate(Relation reln, int nblocks)
 		}
 		priorblocks += RELSEG_SIZE;
 	}
-	MemoryContextSwitchTo(oldcxt);
 #else
 	if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
 		return -1;
@@ -833,8 +818,7 @@ mdtruncate(Relation reln, int nblocks)
 #endif
 
 	return nblocks;
-
-}	/* mdtruncate */
+}
 
 /*
  *	mdcommit() -- Commit a transaction.
@@ -907,7 +891,6 @@ _fdvec_alloc()
 	MdfdVec    *nvec;
 	int			fdvec,
 				i;
-	MemoryContext oldcxt;
 
 	if (Md_Free >= 0)			/* get from free list */
 	{
@@ -930,15 +913,11 @@ _fdvec_alloc()
 
 	Nfds *= 2;
 
-	oldcxt = MemoryContextSwitchTo(MdCxt);
-
-	nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
+	nvec = (MdfdVec *) MemoryContextAlloc(MdCxt, Nfds * sizeof(MdfdVec));
 	MemSet(nvec, 0, Nfds * sizeof(MdfdVec));
-	memmove(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
+	memcpy(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
 	pfree(Md_fdvec);
 
-	MemoryContextSwitchTo(oldcxt);
-
 	Md_fdvec = nvec;
 
 	/* Set new free list */
@@ -976,7 +955,6 @@ _fdvec_free(int fdvec)
 static MdfdVec *
 _mdfd_openseg(Relation reln, int segno, int oflags)
 {
-	MemoryContext oldcxt;
 	MdfdVec    *v;
 	int			fd;
 	char	   *path,
@@ -1003,9 +981,7 @@ _mdfd_openseg(Relation reln, int segno, int oflags)
 		return (MdfdVec *) NULL;
 
 	/* allocate an mdfdvec entry for it */
-	oldcxt = MemoryContextSwitchTo(MdCxt);
-	v = (MdfdVec *) palloc(sizeof(MdfdVec));
-	MemoryContextSwitchTo(oldcxt);
+	v = (MdfdVec *) MemoryContextAlloc(MdCxt, sizeof(MdfdVec));
 
 	/* fill the entry */
 	v->mdfd_vfd = fd;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 9209b6509f..e018114a5d 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.161 2000/06/22 22:31:20 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.162 2000/06/28 03:32:18 tgl Exp $
  *
  * NOTES
  *	  this is the "main" module of the postgres backend and
@@ -79,7 +79,6 @@ bool Log_connections = false;
 CommandDest whereToSendOutput = Debug;
 
 
-extern void BaseInit(void);
 extern void StartupXLOG(void);
 extern void ShutdownXLOG(void);
 
@@ -88,10 +87,8 @@ extern void HandleDeadLock(SIGNAL_ARGS);
 extern char XLogDir[];
 extern char ControlFilePath[];
 
-extern int	lockingOff;
-extern int	NBuffers;
+static bool	dontExecute = false;
 
-int			dontExecute = 0;
 static bool IsEmptyQuery = false;
 
 /* note: these declarations had better match tcopprot.h */
@@ -101,8 +98,6 @@ bool		Warn_restart_ready = false;
 bool		InError = false;
 bool		ExitAfterAbort = false;
 
-extern int	NBuffers;
-
 static bool EchoQuery = false;	/* default don't echo */
 char		pg_pathname[MAXPGPATH];
 FILE	   *StatFp = NULL;
@@ -133,7 +128,6 @@ int			XfuncMode = 0;
 static int	InteractiveBackend(StringInfo inBuf);
 static int	SocketBackend(StringInfo inBuf);
 static int	ReadCommand(StringInfo inBuf);
-static void pg_exec_query(char *query_string);
 static void SigHupHandler(SIGNAL_ARGS);
 static void FloatExceptionHandler(SIGNAL_ARGS);
 static void quickdie(SIGNAL_ARGS);
@@ -331,19 +325,12 @@ SocketBackend(StringInfo inBuf)
 static int
 ReadCommand(StringInfo inBuf)
 {
-	MemoryContext oldcontext;
 	int			result;
 
-	/*
-	 * Make sure any expansion of inBuf happens in permanent memory
-	 * context, so that we can keep using it for future command cycles.
-	 */
-	oldcontext = MemoryContextSwitchTo(TopMemoryContext);
 	if (IsUnderPostmaster)
 		result = SocketBackend(inBuf);
 	else
 		result = InteractiveBackend(inBuf);
-	MemoryContextSwitchTo(oldcontext);
 	return result;
 }
 
@@ -355,10 +342,9 @@ ReadCommand(StringInfo inBuf)
  * multiple queries and/or the rewriter might expand one query to several.
  */
 List *
-pg_parse_and_rewrite(char *query_string,		/* string to execute */
-					 Oid *typev,/* argument types */
-					 int nargs, /* number of arguments */
-					 bool aclOverride)
+pg_parse_and_rewrite(char *query_string,	/* string to execute */
+					 Oid *typev,			/* parameter types */
+					 int nargs)				/* number of parameters */
 {
 	List	   *querytree_list;
 	List	   *querytree_list_item;
@@ -422,30 +408,6 @@ pg_parse_and_rewrite(char *query_string,		/* string to execute */
 
 	querytree_list = new_list;
 
-	/* ----------------
-	 *	(3) If ACL override is requested, mark queries for no ACL check.
-	 * ----------------
-	 */
-	if (aclOverride)
-	{
-		foreach(querytree_list_item, querytree_list)
-		{
-			List	   *l;
-
-			querytree = (Query *) lfirst(querytree_list_item);
-
-			if (querytree->commandType == CMD_UTILITY)
-				continue;
-
-			foreach(l, querytree->rtable)
-			{
-				RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
-
-				rte->skipAcl = TRUE;
-			}
-		}
-	}
-
 	if (Debug_print_rewritten)
 	{
 		if (Debug_pretty_print)
@@ -516,63 +478,66 @@ pg_plan_query(Query *querytree)
 
 
 /* ----------------------------------------------------------------
- *		pg_exec_query()
+ *		pg_exec_query_dest()
  *
  *		Takes a querystring, runs the parser/utilities or
- *		parser/planner/executor over it as necessary
- *		Begin Transaction Should have been called before this
- *		and CommitTransaction After this is called
- *		This is strictly because we do not allow for nested xactions.
+ *		parser/planner/executor over it as necessary.
+ *
+ * Assumptions:
+ *
+ * Caller is responsible for calling StartTransactionCommand() beforehand
+ * and CommitTransactionCommand() afterwards (if successful).
+ *
+ * The CurrentMemoryContext at entry references a context that is
+ * appropriate for execution of individual queries (typically this will be
+ * TransactionCommandContext).  Note that this routine resets that context
+ * after each individual query, so don't store anything there that
+ * must outlive the call!
  *
- *		NON-OBVIOUS-RESTRICTIONS
- *		this function _MUST_ allocate a new "parsetree" each time,
- *		since it may be stored in a named portal and should not
- *		change its value.
+ * parse_context references a context suitable for holding the
+ * parse/rewrite trees (typically this will be QueryContext).
+ * This context must be longer-lived than the CurrentMemoryContext!
+ * In fact, if the query string might contain BEGIN/COMMIT commands,
+ * parse_context had better outlive TopTransactionContext!
+ *
+ * We could have hard-wired knowledge about QueryContext and
+ * TransactionCommandContext into this routine, but it seems better
+ * not to, in case callers from outside this module need to use some
+ * other contexts.
  *
  * ----------------------------------------------------------------
  */
 
-static void
-pg_exec_query(char *query_string)
-{
-	pg_exec_query_dest(query_string, whereToSendOutput, FALSE);
-}
-
-#ifdef NOT_USED
-void
-pg_exec_query_acl_override(char *query_string)
-{
-	pg_exec_query_dest(query_string, whereToSendOutput, TRUE);
-}
-#endif
-
 void
 pg_exec_query_dest(char *query_string,	/* string to execute */
 				   CommandDest dest,	/* where results should go */
-				   bool aclOverride)	/* to give utility commands power
-										 * of superusers */
+				   MemoryContext parse_context)	/* context for parsetrees */
 {
-	List	   *querytree_list;
+	MemoryContext oldcontext;
+	List	   *querytree_list,
+			   *querytree_item;
 
-	/* parse and rewrite the queries */
-	querytree_list = pg_parse_and_rewrite(query_string, NULL, 0,
-										  aclOverride);
+	/*
+	 * Switch to appropriate context for constructing parsetrees.
+	 */
+	oldcontext = MemoryContextSwitchTo(parse_context);
 
 	/*
-	 * NOTE: we do not use "foreach" here because we want to be sure the
-	 * list pointer has been advanced before the query is executed. We
-	 * need to do that because VACUUM has a nasty little habit of doing
-	 * CommitTransactionCommand at startup, and that will release the
-	 * memory holding our parse list :-(.  This needs a better solution
-	 * --- currently, the code will crash if someone submits "vacuum;
-	 * something-else" in a single query string.  But memory allocation
-	 * needs redesigned anyway, so this will have to do for now.
+	 * Parse and rewrite the query or queries.
 	 */
-	while (querytree_list)
-	{
-		Query	   *querytree = (Query *) lfirst(querytree_list);
+	querytree_list = pg_parse_and_rewrite(query_string, NULL, 0);
 
-		querytree_list = lnext(querytree_list);
+	/*
+	 * Switch back to execution context for planning and execution.
+	 */
+	MemoryContextSwitchTo(oldcontext);
+
+	/*
+	 * Run through the query or queries and execute each one.
+	 */
+	foreach(querytree_item, querytree_list)
+	{
+		Query	   *querytree = (Query *) lfirst(querytree_item);
 
 		/* if we got a cancel signal in parsing or prior command, quit */
 		if (QueryCancel)
@@ -636,9 +601,17 @@ pg_exec_query_dest(char *query_string,	/* string to execute */
 			if (Show_executor_stats)
 				ResetUsage();
 
-			if (DebugLvl > 1)
-				elog(DEBUG, "ProcessQuery");
-			ProcessQuery(querytree, plan, dest);
+			if (dontExecute)
+			{
+				/* don't execute it, just show the query plan */
+				print_plan(plan, querytree);
+			}
+			else
+			{
+				if (DebugLvl > 1)
+					elog(DEBUG, "ProcessQuery");
+				ProcessQuery(querytree, plan, dest);
+			}
 
 			if (Show_executor_stats)
 			{
@@ -652,8 +625,15 @@ pg_exec_query_dest(char *query_string,	/* string to execute */
 		 * between queries so that the effects of early queries are
 		 * visible to subsequent ones.
 		 */
-
 		CommandCounterIncrement();
+		/*
+		 * Also, clear the execution context to recover temporary
+		 * memory used by the query.  NOTE: if query string contains
+		 * BEGIN/COMMIT transaction commands, execution context may
+		 * now be different from what we were originally passed;
+		 * so be careful to clear current context not "oldcontext".
+		 */
+		MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
 	}
 }
 
@@ -821,6 +801,17 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 	extern char *optarg;
 	extern int	DebugLvl;
 
+	/*
+	 * Fire up essential subsystems: error and memory management
+	 *
+	 * If we are running under the postmaster, this is done already.
+	 */
+	if (!IsUnderPostmaster)
+	{
+		EnableExceptionHandling(true);
+		MemoryContextInit();
+	}
+
 	/*
 	 * Set default values for command-line options.
 	 */
@@ -973,7 +964,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 				break;
 
 			case 'i':
-				dontExecute = 1;
+				dontExecute = true;
 				break;
 
 			case 'L':
@@ -1182,11 +1173,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 	 *
 	 * Note that postmaster already blocked ALL signals to make us happy.
 	 */
-	if (!IsUnderPostmaster)
-	{
-		PG_INITMASK();
-		PG_SETMASK(&BlockSig);
-	}
+	pqinitmask();
 
 #ifdef HAVE_SIGPROCMASK
 	sigdelset(&BlockSig, SIGUSR1);
@@ -1194,6 +1181,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 	BlockSig &= ~(sigmask(SIGUSR1));
 #endif
 
+	PG_SETMASK(&BlockSig);		/* block everything except SIGUSR1 */
+
 	pqsignal(SIGHUP, SigHupHandler);	/* set flag to read config file */
 	pqsignal(SIGINT, QueryCancelHandler);		/* cancel current query */
 	pqsignal(SIGQUIT, handle_warn);		/* handle error */
@@ -1215,8 +1204,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 	pqsignal(SIGTTOU, SIG_DFL);
 	pqsignal(SIGCONT, SIG_DFL);
 
-	PG_SETMASK(&BlockSig);		/* block everything except SIGUSR1 */
-
 	/*
 	 * Get user name (needed now in case it is the default database name)
 	 * and check command line validity
@@ -1360,13 +1347,6 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 
 	on_shmem_exit(remove_all_temp_relations, NULL);
 
-	{
-		MemoryContext oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-
-		parser_input = makeStringInfo();		/* initialize input buffer */
-		MemoryContextSwitchTo(oldcontext);
-	}
-
 	/*
 	 * Send this backend's cancellation info to the frontend.
 	 */
@@ -1386,7 +1366,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 	if (!IsUnderPostmaster)
 	{
 		puts("\nPOSTGRES backend interactive interface ");
-		puts("$Revision: 1.161 $ $Date: 2000/06/22 22:31:20 $\n");
+		puts("$Revision: 1.162 $ $Date: 2000/06/28 03:32:18 $\n");
 	}
 
 	/*
@@ -1397,6 +1377,20 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 
 	SetProcessingMode(NormalProcessing);
 
+	/*
+	 * Create the memory context we will use in the main loop.
+	 *
+	 * QueryContext is reset once per iteration of the main loop,
+	 * ie, upon completion of processing of each supplied query string.
+	 * It can therefore be used for any data that should live just as
+	 * long as the query string --- parse trees, for example.
+	 */
+	QueryContext = AllocSetContextCreate(TopMemoryContext,
+										 "QueryContext",
+										 ALLOCSET_DEFAULT_MINSIZE,
+										 ALLOCSET_DEFAULT_INITSIZE,
+										 ALLOCSET_DEFAULT_MAXSIZE);
+
 	/*
 	 * POSTGRES main processing loop begins here
 	 *
@@ -1406,18 +1400,30 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 
 	if (sigsetjmp(Warn_restart, 1) != 0)
 	{
-		/* Make sure we are in a valid memory context */
-		MemoryContextSwitchTo(TopMemoryContext);
+		/*
+		 * Make sure we are in a valid memory context during recovery.
+		 *
+		 * We use ErrorContext in hopes that it will have some free space
+		 * even if we're otherwise up against it...
+		 */
+		MemoryContextSwitchTo(ErrorContext);
 
 		if (DebugLvl >= 1)
 			elog(DEBUG, "AbortCurrentTransaction");
 		AbortCurrentTransaction();
-		InError = false;
+
 		if (ExitAfterAbort)
 		{
 			ProcReleaseLocks(); /* Just to be sure... */
 			proc_exit(0);
 		}
+		/*
+		 * If we recovered successfully, return to normal top-level context
+		 * and clear ErrorContext for next time.
+		 */
+		MemoryContextSwitchTo(TopMemoryContext);
+		MemoryContextResetAndDeleteChildren(ErrorContext);
+		InError = false;
 	}
 
 	Warn_restart_ready = true;	/* we can now handle elog(ERROR) */
@@ -1430,7 +1436,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 
 	for (;;)
 	{
-		set_ps_display("idle");
+		/*
+		 * Release storage left over from prior query cycle, and
+		 * create a new query input buffer in the cleared QueryContext.
+		 */
+		MemoryContextSwitchTo(QueryContext);
+		MemoryContextResetAndDeleteChildren(QueryContext);
+
+		parser_input = makeStringInfo();
 
 		/* XXX this could be moved after ReadCommand below to get more
 		 * sensical behaviour */
@@ -1462,6 +1475,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 		 *	 (3) read a command (loop blocks here)
 		 * ----------------
 		 */
+		set_ps_display("idle");
+
 		firstchar = ReadCommand(parser_input);
 
 		QueryCancel = false;	/* forget any earlier CANCEL signal */
@@ -1528,7 +1543,9 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 						elog(DEBUG, "StartTransactionCommand");
 					StartTransactionCommand();
 
-					pg_exec_query(parser_input->data);
+					pg_exec_query_dest(parser_input->data,
+									   whereToSendOutput,
+									   QueryContext);
 
 					/*
 					 * Invoke IMMEDIATE constraint triggers
@@ -1566,7 +1583,8 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 		 *	 (6) commit the current transaction
 		 *
 		 *	 Note: if we had an empty input buffer, then we didn't
-		 *	 call pg_exec_query, so we don't bother to commit this transaction.
+		 *	 call pg_exec_query_dest, so we don't bother to commit
+		 *	 this transaction.
 		 * ----------------
 		 */
 		if (!IsEmptyQuery)
@@ -1578,7 +1596,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
 #ifdef SHOW_MEMORY_STATS
 			/* print global-context stats at each commit for leak tracking */
 			if (ShowStats)
-				GlobalMemoryStats();
+				MemoryContextStats(TopMemoryContext);
 #endif
 		}
 		else
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index b26923b6f1..9e52930e20 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.34 2000/06/12 03:40:40 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.35 2000/06/28 03:32:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,8 +22,6 @@
 #include "utils/ps_status.h"
 
 static char *CreateOperationTag(int operationType);
-static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset,
-				 Node *limcount);
 
 
 /* ----------------------------------------------------------------
@@ -115,7 +113,7 @@ CreateOperationTag(int operationType)
 		default:
 			elog(DEBUG, "CreateOperationTag: unknown operation type %d",
 				 operationType);
-			tag = NULL;
+			tag = "???";
 			break;
 	}
 
@@ -123,31 +121,18 @@ CreateOperationTag(int operationType)
 }
 
 /* ----------------
- *		ProcessPortal
+ *		PreparePortal
  * ----------------
  */
-
-void
-ProcessPortal(char *portalName,
-			  Query *parseTree,
-			  Plan *plan,
-			  EState *state,
-			  TupleDesc attinfo,
-			  CommandDest dest)
+Portal
+PreparePortal(char *portalName)
 {
 	Portal		portal;
-	MemoryContext portalContext;
 
 	/* ----------------
-	 *	 Check for reserved or already-in-use portal name.
+	 *	 Check for already-in-use portal name.
 	 * ----------------
 	 */
-
-	if (PortalNameIsSpecial(portalName))
-		elog(ERROR,
-			 "The portal name \"%s\" is reserved for internal use",
-			 portalName);
-
 	portal = GetPortalByName(portalName);
 	if (PortalIsValid(portal))
 	{
@@ -158,70 +143,39 @@ ProcessPortal(char *portalName,
 	}
 
 	/* ----------------
-	 *	 Convert the current blank portal into the user-specified
-	 *	 portal and initialize the state and query descriptor.
-	 *
-	 *	 Since the parsetree has been created in the current blank portal,
-	 *	 we don't have to do any work to copy it into the user-named portal.
+	 *	 Create the new portal and make its memory context active.
 	 * ----------------
 	 */
+	portal = CreatePortal(portalName);
 
-	portal = BlankPortalAssignName(portalName);
-
-	PortalSetQuery(portal,
-				   CreateQueryDesc(parseTree, plan, dest),
-				   attinfo,
-				   state,
-				   PortalCleanup);
+	MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
-	/* ----------------
-	 *	Now create a new blank portal and switch to it.
-	 *	Otherwise, the new named portal will be cleaned at statement end.
-	 *
-	 *	Note: portals will only be supported within a BEGIN...END
-	 *	block in the near future.  Later, someone will fix it to
-	 *	do what is possible across transaction boundries. -hirohama
-	 * ----------------
-	 */
-	portalContext = (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL));
-
-	MemoryContextSwitchTo(portalContext);
-
-	StartPortalAllocMode(DefaultAllocMode, 0);
+	return portal;
 }
 
 
 /* ----------------------------------------------------------------
- *		ProcessQueryDesc
+ *		ProcessQuery
  *
- *		Read the comments for ProcessQuery() below...
+ *		Execute a plan, the non-parallel version
  * ----------------------------------------------------------------
  */
-static void
-ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
+void
+ProcessQuery(Query *parsetree,
+			 Plan *plan,
+			 CommandDest dest)
 {
-	Query	   *parseTree;
-	Plan	   *plan;
-	int			operation;
-	char	   *tag = NULL;
-	EState	   *state;
-	TupleDesc	attinfo;
-
+	int			operation = parsetree->commandType;
+	char	   *tag;
 	bool		isRetrieveIntoPortal;
 	bool		isRetrieveIntoRelation;
+	Portal		portal = NULL;
 	char	   *intoName = NULL;
-	CommandDest dest;
-
-	/* ----------------
-	 *	get info from the query desc
-	 * ----------------
-	 */
-	parseTree = queryDesc->parsetree;
-	plan = queryDesc->plantree;
+	QueryDesc  *queryDesc;
+	EState	   *state;
+	TupleDesc	attinfo;
 
-	operation = queryDesc->operation;
 	set_ps_display(tag = CreateOperationTag(operation));
-	dest = queryDesc->dest;
 
 	/* ----------------
 	 *	initialize portal/into relation status
@@ -232,11 +186,11 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
 
 	if (operation == CMD_SELECT)
 	{
-		if (parseTree->isPortal)
+		if (parsetree->isPortal)
 		{
 			isRetrieveIntoPortal = true;
-			intoName = parseTree->into;
-			if (parseTree->isBinary)
+			intoName = parsetree->into;
+			if (parsetree->isBinary)
 			{
 
 				/*
@@ -244,19 +198,38 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
 				 * (externalized form) to RemoteInternal (internalized
 				 * form)
 				 */
-				dest = queryDesc->dest = RemoteInternal;
+				dest = RemoteInternal;
 			}
 		}
-		else if (parseTree->into != NULL)
+		else if (parsetree->into != NULL)
 		{
 			/* select into table */
 			isRetrieveIntoRelation = true;
 		}
+	}
 
+	/* ----------------
+	 *	If retrieving into a portal, set up the portal and copy
+	 *	the parsetree and plan into its memory context.
+	 * ----------------
+	 */
+	if (isRetrieveIntoPortal)
+	{
+		portal = PreparePortal(intoName);
+		/* CurrentMemoryContext is now pointing to portal's context */
+		parsetree = copyObject(parsetree);
+		plan = copyObject(plan);
 	}
 
 	/* ----------------
-	 *	when performing a retrieve into, we override the normal
+	 *	Now we can create the QueryDesc object (this is also in
+	 *	the portal context, if portal retrieve).
+	 * ----------------
+	 */
+	queryDesc = CreateQueryDesc(parsetree, plan, dest);
+
+	/* ----------------
+	 *	When performing a retrieve into, we override the normal
 	 *	communication destination during the processing of the
 	 *	the query.	This only affects the tuple-output function
 	 *	- the correct destination will still see BeginCommand()
@@ -293,26 +266,19 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
 				 dest);
 
 	/* ----------------
-	 *	Named portals do not do a "fetch all" initially, so now
-	 *	we return since ExecMain has been called with EXEC_START
-	 *	to initialize the query plan.
-	 *
-	 *	Note: ProcessPortal transforms the current "blank" portal
-	 *		  into a named portal and creates a new blank portal so
-	 *		  everything we allocated in the current "blank" memory
-	 *		  context will be preserved across queries.  -cim 2/22/91
+	 *	If retrieve into portal, stop now; we do not run the plan
+	 *	until a FETCH command is received.
 	 * ----------------
 	 */
 	if (isRetrieveIntoPortal)
 	{
-		PortalExecutorHeapMemory = NULL;
+		PortalSetQuery(portal,
+					   queryDesc,
+					   attinfo,
+					   state,
+					   PortalCleanup);
 
-		ProcessPortal(intoName,
-					  parseTree,
-					  plan,
-					  state,
-					  attinfo,
-					  dest);
+		MemoryContextSwitchTo(TransactionCommandContext);
 
 		EndCommand(tag, dest);
 		return;
@@ -323,14 +289,14 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
 	 *	 actually run the plan..
 	 * ----------------
 	 */
-	ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount);
+	ExecutorRun(queryDesc, state, EXEC_RUN,
+				parsetree->limitOffset, parsetree->limitCount);
 
 	/* save infos for EndCommand */
 	UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
 
 	/* ----------------
-	 *	 now, we close down all the scans and free allocated resources...
-	 * with ExecutorEnd()
+	 *	 Now, we close down all the scans and free allocated resources.
 	 * ----------------
 	 */
 	ExecutorEnd(queryDesc, state);
@@ -341,31 +307,3 @@ ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount)
 	 */
 	EndCommand(tag, dest);
 }
-
-/* ----------------------------------------------------------------
- *		ProcessQuery
- *
- *		Execute a plan, the non-parallel version
- * ----------------------------------------------------------------
- */
-
-void
-ProcessQuery(Query *parsetree,
-			 Plan *plan,
-			 CommandDest dest)
-{
-	QueryDesc  *queryDesc;
-	extern int	dontExecute;	/* from postgres.c */
-	extern void print_plan(Plan *p, Query *parsetree);	/* from print.c */
-
-	queryDesc = CreateQueryDesc(parsetree, plan, dest);
-
-	if (dontExecute)
-	{
-		/* don't execute it, just show the query plan */
-		print_plan(plan, parsetree);
-	}
-	else
-		ProcessQueryDesc(queryDesc, parsetree->limitOffset,
-						 parsetree->limitCount);
-}
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index a1c2d5b7bb..d673000678 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.67 2000/06/19 03:54:31 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.68 2000/06/28 03:32:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -60,10 +60,6 @@ static Datum cc_hashname(PG_FUNCTION_ARGS);
 
 static CatCache *Caches = NULL; /* head of list of caches */
 
-GlobalMemory CacheCxt;			/* context in which caches are allocated */
-
-/* CacheCxt is global because relcache uses it too. */
-
 
 /* ----------------
  *		EQPROC is used in CatalogCacheInitializeCache to find the equality
@@ -135,6 +131,28 @@ cc_hashname(PG_FUNCTION_ARGS)
 }
 
 
+/*
+ * Standard routine for creating cache context if it doesn't exist yet
+ *
+ * There are a lot of places (probably far more than necessary) that check
+ * whether CacheMemoryContext exists yet and want to create it if not.
+ * We centralize knowledge of exactly how to create it here.
+ */
+void
+CreateCacheMemoryContext(void)
+{
+	/* Purely for paranoia, check that context doesn't exist;
+	 * caller probably did so already.
+	 */
+	if (!CacheMemoryContext)
+		CacheMemoryContext = AllocSetContextCreate(TopMemoryContext,
+												   "CacheMemoryContext",
+												   ALLOCSET_DEFAULT_MINSIZE,
+												   ALLOCSET_DEFAULT_INITSIZE,
+												   ALLOCSET_DEFAULT_MAXSIZE);
+}
+
+
 /* --------------------------------
  *		CatalogCacheInitializeCache
  * --------------------------------
@@ -183,9 +201,10 @@ CatalogCacheInitializeCache(CatCache * cache,
 	 *	do not vanish at the end of a transaction
 	 * ----------------
 	 */
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
+
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/* ----------------
 	 *	If no relation was passed we must open it to get access to
@@ -415,7 +434,7 @@ CatalogCacheComputeTupleHashIndex(CatCache * cacheInOutP,
 /* --------------------------------
  *		CatCacheRemoveCTup
  *
- *		NB: assumes caller has switched to CacheCxt
+ *		NB: assumes caller has switched to CacheMemoryContext
  * --------------------------------
  */
 static void
@@ -477,9 +496,10 @@ CatalogCacheIdInvalidate(int cacheId,	/* XXX */
 	 *	switch to the cache context for our memory allocations
 	 * ----------------
 	 */
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
+
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/* ----------------
 	 *	inspect every cache that could contain the tuple
@@ -552,10 +572,10 @@ ResetSystemCache()
 	 *	do not vanish at the end of a transaction
 	 * ----------------
 	 */
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/* ----------------
 	 *	here we purge the contents of all the caches
@@ -681,10 +701,10 @@ InitSysCache(char *relname,
 	 *	do not vanish at the end of a transaction
 	 * ----------------
 	 */
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/* ----------------
 	 *	allocate a new cache structure
@@ -839,14 +859,14 @@ SearchSelfReferences(CatCache * cache)
 			HeapScanDesc sd;
 			MemoryContext oldcxt;
 
-			if (!CacheCxt)
-				CacheCxt = CreateGlobalMemory("Cache");
 			rel = heap_open(cache->relationId, AccessShareLock);
 			sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
 			ntp = heap_getnext(sd, 0);
 			if (!HeapTupleIsValid(ntp))
 				elog(ERROR, "SearchSelfReferences: tuple not found");
-			oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+			if (!CacheMemoryContext)
+				CreateCacheMemoryContext();
+			oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 			indexSelfTuple = heap_copytuple(ntp);
 			MemoryContextSwitchTo(oldcxt);
 			heap_endscan(sd);
@@ -868,14 +888,14 @@ SearchSelfReferences(CatCache * cache)
 			HeapScanDesc sd;
 			MemoryContext oldcxt;
 
-			if (!CacheCxt)
-				CacheCxt = CreateGlobalMemory("Cache");
 			rel = heap_open(cache->relationId, AccessShareLock);
 			sd = heap_beginscan(rel, false, SnapshotNow, 1, cache->cc_skey);
 			ntp = heap_getnext(sd, 0);
 			if (!HeapTupleIsValid(ntp))
 				elog(ERROR, "SearchSelfReferences: tuple not found");
-			oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+			if (!CacheMemoryContext)
+				CreateCacheMemoryContext();
+			oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 			operatorSelfTuple[lookup_oid - MIN_OIDCMP] = heap_copytuple(ntp);
 			MemoryContextSwitchTo(oldcxt);
 			heap_endscan(sd);
@@ -908,7 +928,6 @@ SearchSysCache(CatCache * cache,
 	CatCTup    *nct2;
 	Dlelem	   *elt;
 	HeapTuple	ntp = NULL;
-
 	Relation	relation;
 	MemoryContext oldcxt;
 
@@ -1020,10 +1039,10 @@ SearchSysCache(CatCache * cache,
 	 * ----------------
 	 */
 
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/* ----------------
 	 *	Scan the relation to find the tuple.  If there's an index, and
@@ -1060,12 +1079,13 @@ SearchSysCache(CatCache * cache,
 		 */
 		if (HeapTupleIsValid(indextp))
 		{
-			MemoryContextSwitchTo((MemoryContext) CacheCxt);
+			MemoryContextSwitchTo(CacheMemoryContext);
 			ntp = heap_copytuple(indextp);
+			/* this switch is probably not needed anymore: */
 			MemoryContextSwitchTo(oldcxt);
 			heap_freetuple(indextp);
 		}
-		MemoryContextSwitchTo((MemoryContext) CacheCxt);
+		MemoryContextSwitchTo(CacheMemoryContext);
 	}
 	else
 	{
@@ -1084,7 +1104,7 @@ SearchSysCache(CatCache * cache,
 
 		ntp = heap_getnext(sd, 0);
 
-		MemoryContextSwitchTo((MemoryContext) CacheCxt);
+		MemoryContextSwitchTo(CacheMemoryContext);
 
 		if (HeapTupleIsValid(ntp))
 		{
@@ -1097,7 +1117,7 @@ SearchSysCache(CatCache * cache,
 
 		heap_endscan(sd);
 
-		MemoryContextSwitchTo((MemoryContext) CacheCxt);
+		MemoryContextSwitchTo(CacheMemoryContext);
 	}
 
 	cache->busy = false;
@@ -1205,9 +1225,10 @@ RelationInvalidateCatalogCacheTuple(Relation relation,
 	 *	switch to the cache memory context
 	 * ----------------
 	 */
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
+
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/* ----------------
 	 *	for each cache
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index a063534c0d..b0ee20fce9 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.103 2000/06/19 23:40:48 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.104 2000/06/28 03:32:24 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -917,10 +917,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
 	/* ----------------
 	 *	allocate storage for the relation descriptor,
 	 *	initialize relation->rd_rel and get the access method id.
-	 *	The storage is allocated in memory context CacheCxt.
+	 *	The storage is allocated in memory context CacheMemoryContext.
 	 * ----------------
 	 */
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 	relation = AllocateRelationDesc(oldrelation, natts, relp);
 	relam = relation->rd_rel->relam;
 
@@ -1383,7 +1383,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
 	if (relation->rd_isnailed)
 		return;
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/*
 	 * Remove relation from hash tables
@@ -1574,7 +1574,7 @@ RelationForgetRelation(Oid rid)
 			List	   *curr;
 			List	   *prev = NIL;
 
-			oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+			oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 			foreach(curr, newlyCreatedRelns)
 			{
@@ -1731,10 +1731,7 @@ RelationRegisterRelation(Relation relation)
 {
 	MemoryContext oldcxt;
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
-
-	if (oldcxt != (MemoryContext) CacheCxt)
-		elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	RelationInitLockInfo(relation);
 
@@ -1769,7 +1766,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
 	if (newlyCreatedRelns == NULL)
 		return;
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	while (newlyCreatedRelns)
 	{
@@ -1822,10 +1819,10 @@ RelationInitialize(void)
 	 *	switch to cache memory context
 	 * ----------------
 	 */
-	if (!CacheCxt)
-		CacheCxt = CreateGlobalMemory("Cache");
+	if (!CacheMemoryContext)
+		CreateCacheMemoryContext();
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	/* ----------------
 	 *	create global caches
@@ -2186,7 +2183,7 @@ RelationGetIndexList(Relation relation)
 	heap_close(indrel, AccessShareLock);
 
 	/* Now save a copy of the completed list in the relcache entry. */
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 	relation->rd_indexlist = listCopy(result);
 	relation->rd_indexfound = true;
 	MemoryContextSwitchTo(oldcxt);
diff --git a/src/backend/utils/cache/temprel.c b/src/backend/utils/cache/temprel.c
index d09e35336e..20c94ac57b 100644
--- a/src/backend/utils/cache/temprel.c
+++ b/src/backend/utils/cache/temprel.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.24 2000/06/20 06:41:12 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/temprel.c,v 1.25 2000/06/28 03:32:25 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -67,7 +67,7 @@ create_temp_relation(const char *relname, HeapTuple pg_class_tuple)
 	MemoryContext oldcxt;
 	TempTable  *temp_rel;
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	temp_rel = (TempTable *) palloc(sizeof(TempTable));
 	temp_rel->user_relname = (char *) palloc(NAMEDATALEN);
@@ -135,7 +135,7 @@ remove_temp_relation(Oid relid)
 	List	   *l,
 			   *prev;
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	prev = NIL;
 	l = temp_rels;
@@ -185,7 +185,7 @@ invalidate_temp_relations(void)
 	List	   *l,
 			   *prev;
 
-	oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+	oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
 
 	prev = NIL;
 	l = temp_rels;
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index 5b05b81a18..da8d80763a 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.60 2000/06/04 15:06:29 petere Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.61 2000/06/28 03:32:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,7 +27,7 @@
 #include <sys/time.h>
 #include <ctype.h>
 #ifdef ENABLE_SYSLOG
-# include <syslog.h>
+#include <syslog.h>
 #endif
 
 #include "libpq/libpq.h"
@@ -89,10 +89,9 @@ static int	ElogDebugIndentLevel = 0;
  *--------------------
  */
 void
-elog(int lev, const char *fmt,...)
+elog(int lev, const char *fmt, ...)
 {
 	va_list		ap;
-
 	/*
 	 * The expanded format and final output message are dynamically
 	 * allocated if necessary, but not if they fit in the "reasonable
@@ -101,12 +100,21 @@ elog(int lev, const char *fmt,...)
 	 * working (since memory-clobber errors often take out malloc first).
 	 * Don't make these buffers unreasonably large though, on pain of
 	 * having to chase a bug with no error message.
+	 *
+	 * Note that we use malloc() not palloc() because we want to retain
+	 * control if we run out of memory.  palloc() would recursively call
+	 * elog(ERROR), which would be all right except if we are working on a
+	 * FATAL or REALLYFATAL error.  We'd lose track of the fatal condition
+	 * and report a mere ERROR to outer loop, which would be a Bad Thing.
+	 * So, we substitute an appropriate message in-place, without downgrading
+	 * the level if it's above ERROR.
 	 */
 	char		fmt_fixedbuf[128];
 	char		msg_fixedbuf[256];
 	char	   *fmt_buf = fmt_fixedbuf;
 	char	   *msg_buf = msg_fixedbuf;
-
+	/* this buffer is only used for strange values of lev: */
+	char		prefix_buf[32];
 	/* this buffer is only used if errno has a bogus value: */
 	char		errorstr_buf[32];
 	const char *errorstr;
@@ -115,7 +123,6 @@ elog(int lev, const char *fmt,...)
 	char	   *bp;
 	int			indent = 0;
 	int			space_needed;
-
 	int			len;
 	/* size of the prefix needed for timestamp and pid, if enabled */
 	size_t      timestamp_size;
@@ -123,6 +130,15 @@ elog(int lev, const char *fmt,...)
 	if (lev <= DEBUG && Debugfile < 0)
 		return;					/* ignore debug msgs if noplace to send */
 
+	/* save errno string for %m */
+	if (errno < sys_nerr && errno >= 0)
+		errorstr = strerror(errno);
+	else
+	{
+		sprintf(errorstr_buf, "error %d", errno);
+		errorstr = errorstr_buf;
+	}
+
 	if (lev == ERROR || lev == FATAL)
 	{
 		/* this is probably redundant... */
@@ -156,21 +172,11 @@ elog(int lev, const char *fmt,...)
 			prefix = "ERROR:  ";
 			break;
 		default:
-			/* temporarily use msg buf for prefix */
-			sprintf(msg_fixedbuf, "FATAL %d:  ", lev);
-			prefix = msg_fixedbuf;
+			sprintf(prefix_buf, "FATAL %d:  ", lev);
+			prefix = prefix_buf;
 			break;
 	}
 
-	/* get errno string for %m */
-	if (errno < sys_nerr && errno >= 0)
-		errorstr = strerror(errno);
-	else
-	{
-		sprintf(errorstr_buf, "error %d", errno);
-		errorstr = errorstr_buf;
-	}
-
 	timestamp_size = 0;
 	if (Log_timestamp)
 		timestamp_size += TIMESTAMP_SIZE;
@@ -190,9 +196,13 @@ elog(int lev, const char *fmt,...)
 		fmt_buf = (char *) malloc(space_needed);
 		if (fmt_buf == NULL)
 		{
-			/* We're up against it, convert to fatal out-of-memory error */
+			/* We're up against it, convert to out-of-memory error */
 			fmt_buf = fmt_fixedbuf;
-			lev = REALLYFATAL;
+			if (lev < FATAL)
+			{
+				lev = ERROR;
+				prefix = "ERROR:  ";
+			}
 			fmt = "elog: out of memory";		/* this must fit in
 												 * fmt_fixedbuf! */
 		}
@@ -281,15 +291,20 @@ elog(int lev, const char *fmt,...)
 		msg_buf = (char *) malloc(space_needed);
 		if (msg_buf == NULL)
 		{
-			/* We're up against it, convert to fatal out-of-memory error */
+			/* We're up against it, convert to out-of-memory error */
 			msg_buf = msg_fixedbuf;
-			lev = REALLYFATAL;
+			if (lev < FATAL)
+			{
+				lev = ERROR;
+				prefix = "ERROR:  ";
+			}
 			msg_buf[0] = '\0';
 			if (Log_timestamp)
 				strcat(msg_buf, print_timestamp());
 			if (Log_pid)
 				strcat(msg_buf, print_pid());
-			strcat(msg_buf, "FATAL:  elog: out of memory");
+			strcat(msg_buf, prefix);
+			strcat(msg_buf, "elog: out of memory");
 			break;
 		}
 	}
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index ca9b01a8c4..baa89be7bb 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.42 2000/06/15 04:10:29 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.43 2000/06/28 03:32:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -134,7 +134,7 @@ load_external_function(char *filename, char *funcname)
 		file_scanner = (DynamicFileList *)
 			malloc(sizeof(DynamicFileList) + strlen(filename));
 		if (file_scanner == NULL)
-			elog(FATAL, "Out of memory in load_external_function");
+			elog(ERROR, "Out of memory in load_external_function");
 
 		MemSet((char *) file_scanner, 0, sizeof(DynamicFileList));
 		strcpy(file_scanner->filename, filename);
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index 93707fcba9..9646a7c550 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.31 2000/04/12 17:16:00 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.32 2000/06/28 03:32:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -56,8 +56,7 @@
 /*
  * Private function prototypes
  */
-static long *DynaHashAlloc(unsigned int size);
-static void DynaHashFree(Pointer ptr);
+static void *DynaHashAlloc(Size size);
 static uint32 call_hash(HTAB *hashp, char *k);
 static SEG_OFFSET seg_alloc(HTAB *hashp);
 static int	bucket_alloc(HTAB *hashp);
@@ -66,9 +65,7 @@ static int	expand_table(HTAB *hashp);
 static int	hdefault(HTAB *hashp);
 static int	init_htab(HTAB *hashp, int nelem);
 
-typedef long *((*dhalloc_ptr) ());
 
-#ifndef FRONTEND
 /* ----------------
  * memory allocation routines
  *
@@ -84,34 +81,24 @@ typedef long *((*dhalloc_ptr) ());
  *	   do the latter -cim 1/19/91
  * ----------------
  */
-GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
+static MemoryContext DynaHashCxt = NULL;
 
-static long *
-DynaHashAlloc(unsigned int size)
+static void *
+DynaHashAlloc(Size size)
 {
 	if (!DynaHashCxt)
-		DynaHashCxt = CreateGlobalMemory("DynaHash");
+		DynaHashCxt = AllocSetContextCreate(TopMemoryContext,
+											"DynaHash",
+											ALLOCSET_DEFAULT_MINSIZE,
+											ALLOCSET_DEFAULT_INITSIZE,
+											ALLOCSET_DEFAULT_MAXSIZE);
 
-	return (long *)
-		MemoryContextAlloc((MemoryContext) DynaHashCxt, size);
-}
-
-static void
-DynaHashFree(Pointer ptr)
-{
-	MemoryContextFree((MemoryContext) DynaHashCxt, ptr);
+	return MemoryContextAlloc(DynaHashCxt, size);
 }
 
 #define MEM_ALLOC		DynaHashAlloc
-#define MEM_FREE		DynaHashFree
-
-#else							/* FRONTEND */
-
-#define MEM_ALLOC		palloc
 #define MEM_FREE		pfree
 
-#endif	 /* FRONTEND */
-
 
 /*
  * pointer access macros.  Shared memory implementation cannot
@@ -147,7 +134,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
 	HTAB	   *hashp;
 
 
-	hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
+	hashp = (HTAB *) MEM_ALLOC(sizeof(HTAB));
 	MemSet(hashp, 0, sizeof(HTAB));
 
 	if (flags & HASH_FUNCTION)
@@ -181,7 +168,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
 		/* setup hash table defaults */
 
 		hashp->hctl = NULL;
-		hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
+		hashp->alloc = MEM_ALLOC;
 		hashp->dir = NULL;
 		hashp->segbase = NULL;
 
@@ -189,7 +176,7 @@ hash_create(int nelem, HASHCTL *info, int flags)
 
 	if (!hashp->hctl)
 	{
-		hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR));
+		hashp->hctl = (HHDR *) hashp->alloc(sizeof(HHDR));
 		if (!hashp->hctl)
 			return 0;
 	}
@@ -318,7 +305,8 @@ init_htab(HTAB *hashp, int nelem)
 	/* Allocate a directory */
 	if (!(hashp->dir))
 	{
-		hashp->dir = (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
+		hashp->dir = (SEG_OFFSET *)
+			hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
 		if (!hashp->dir)
 			return -1;
 	}
@@ -445,7 +433,7 @@ hash_destroy(HTAB *hashp)
 		/* cannot destroy a shared memory hash table */
 		Assert(!hashp->segbase);
 		/* allocation method must be one we know how to free, too */
-		Assert(hashp->alloc == (dhalloc_ptr) MEM_ALLOC);
+		Assert(hashp->alloc == MEM_ALLOC);
 
 		hash_stats("destroy", hashp);
 
@@ -885,7 +873,7 @@ dir_realloc(HTAB *hashp)
 	new_dirsize = new_dsize * sizeof(SEG_OFFSET);
 
 	old_p = (char *) hashp->dir;
-	p = (char *) hashp->alloc((unsigned long) new_dirsize);
+	p = (char *) hashp->alloc((Size) new_dirsize);
 
 	if (p != NULL)
 	{
@@ -906,8 +894,7 @@ seg_alloc(HTAB *hashp)
 	SEGMENT		segp;
 	SEG_OFFSET	segOffset;
 
-	segp = (SEGMENT) hashp->alloc((unsigned long)
-							  sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
+	segp = (SEGMENT) hashp->alloc(sizeof(BUCKET_INDEX) * hashp->hctl->ssize);
 
 	if (!segp)
 		return 0;
@@ -937,8 +924,7 @@ bucket_alloc(HTAB *hashp)
 	/* make sure its aligned correctly */
 	bucketSize = MAXALIGN(bucketSize);
 
-	tmpBucket = (ELEMENT *)
-		hashp->alloc((unsigned long) BUCKET_ALLOC_INCR * bucketSize);
+	tmpBucket = (ELEMENT *) hashp->alloc(BUCKET_ALLOC_INCR * bucketSize);
 
 	if (!tmpBucket)
 		return 0;
diff --git a/src/backend/utils/init/Makefile b/src/backend/utils/init/Makefile
index 60ee275c64..9e3e3e9d42 100644
--- a/src/backend/utils/init/Makefile
+++ b/src/backend/utils/init/Makefile
@@ -4,14 +4,14 @@
 #    Makefile for utils/init
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.13 2000/05/29 05:45:32 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/utils/init/Makefile,v 1.14 2000/06/28 03:32:43 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
 SRCDIR = ../../..
 include ../../../Makefile.global
 
-OBJS = enbl.o findbe.o globals.o miscinit.o postinit.o
+OBJS = findbe.o globals.o miscinit.o postinit.o
 
 all: SUBSYS.o
 
@@ -27,4 +27,3 @@ clean:
 ifeq (depend,$(wildcard depend))
 include depend
 endif
-
diff --git a/src/backend/utils/init/enbl.c b/src/backend/utils/init/enbl.c
deleted file mode 100644
index 137653e31a..0000000000
--- a/src/backend/utils/init/enbl.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * enbl.c
- *	  POSTGRES module enable and disable support code.
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/enbl.c,v 1.10 2000/01/26 05:57:26 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-#include "utils/module.h"
-
-/*
- * BypassEnable
- *		False iff enable/disable processing is required given on and "*countP."
- *
- * Note:
- *		As a side-effect, *countP is modified.	It should be 0 initially.
- *
- * Exceptions:
- *		BadState if called with pointer to value 0 and false.
- *		BadArg if "countP" is invalid pointer.
- *		BadArg if on is invalid.
- */
-bool
-BypassEnable(int *enableCountInOutP, bool on)
-{
-	AssertArg(PointerIsValid(enableCountInOutP));
-	AssertArg(BoolIsValid(on));
-
-	if (on)
-	{
-		*enableCountInOutP += 1;
-		return (bool) (*enableCountInOutP >= 2);
-	}
-
-	Assert(*enableCountInOutP >= 1);
-
-	*enableCountInOutP -= 1;
-
-	return (bool) (*enableCountInOutP >= 1);
-}
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 51cab6f0e8..f2a5864666 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.59 2000/05/30 00:49:56 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.60 2000/06/28 03:32:43 tgl Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -40,8 +40,6 @@
 #include "mb/pg_wchar.h"
 #endif
 
-void		BaseInit(void);
-
 static void ReverifyMyDatabase(const char *name);
 static void InitCommunication(void);
 
@@ -222,8 +220,6 @@ InitCommunication()
  *		Be very careful with the order of calls in the InitPostgres function.
  * --------------------------------
  */
-extern int	NBuffers;
-
 int			lockingOff = 0;		/* backend -L switch */
 
 /*
@@ -405,21 +401,6 @@ InitPostgres(const char *dbname)
 void
 BaseInit(void)
 {
-
-	/*
-	 * Turn on the exception handler. Note: we cannot use elog, Assert,
-	 * AssertState, etc. until after exception handling is on.
-	 */
-	EnableExceptionHandling(true);
-
-	/*
-	 * Memory system initialization - we may call palloc after
-	 * EnableMemoryContext()).	Note that EnableMemoryContext() must
-	 * happen before EnablePortalManager().
-	 */
-	EnableMemoryContext(true);	/* initializes the "top context" */
-	EnablePortalManager(true);	/* memory for portal/transaction stuff */
-
 	/*
 	 * Attach to shared memory and semaphores, and initialize our
 	 * input/output/debugging file descriptors.
@@ -427,4 +408,6 @@ BaseInit(void)
 	InitCommunication();
 	DebugFileOpen();
 	smgrinit();
+
+	EnablePortalManager();		/* memory for portal/transaction stuff */
 }
diff --git a/src/backend/utils/mb/conv.c b/src/backend/utils/mb/conv.c
index 7ee42f0e33..af7f5623b5 100644
--- a/src/backend/utils/mb/conv.c
+++ b/src/backend/utils/mb/conv.c
@@ -6,7 +6,7 @@
  * WIN1250 client encoding support contributed by Pavel Behal
  * SJIS UDC (NEC selection IBM kanji) support contributed by Eiji Tokuya
  *
- * $Id: conv.c,v 1.15 2000/05/20 13:12:26 ishii Exp $
+ * $Id: conv.c,v 1.16 2000/06/28 03:32:45 tgl Exp $
  *
  *
  */
@@ -1521,7 +1521,8 @@ pg_encoding_conv_tbl pg_conv_tbl[] = {
 };
 
 #ifdef DEBUGMAIN
-#include "utils/mcxt.h"
+#include "postgres.h"
+#include "utils/memutils.h"
 /*
  *	testing for sjis2mic() and mic2sjis()
  */
@@ -1565,21 +1566,23 @@ main()
 void
 elog(int lev, const char *fmt,...)
 {
-};
+}
+
 MemoryContext CurrentMemoryContext;
-Pointer
+
+void *
 MemoryContextAlloc(MemoryContext context, Size size)
 {
-};
-Pointer
-MemoryContextRealloc(MemoryContext context,
-					 Pointer pointer,
-					 Size size)
-{
-};
+}
+
 void
-MemoryContextFree(MemoryContext context, Pointer pointer)
+pfree(void *pointer)
 {
-};
+}
+
+void *
+repalloc(void *pointer, Size size)
+{
+}
 
 #endif
diff --git a/src/backend/utils/mmgr/Makefile b/src/backend/utils/mmgr/Makefile
index 4769817222..371f976781 100644
--- a/src/backend/utils/mmgr/Makefile
+++ b/src/backend/utils/mmgr/Makefile
@@ -4,14 +4,14 @@
 #    Makefile for utils/mmgr
 #
 # IDENTIFICATION
-#    $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.8 2000/05/29 05:45:40 tgl Exp $
+#    $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Makefile,v 1.9 2000/06/28 03:32:50 tgl Exp $
 #
 #-------------------------------------------------------------------------
 
 SRCDIR = ../../..
 include ../../../Makefile.global
 
-OBJS = aset.o mcxt.o palloc.o portalmem.o oset.o
+OBJS = aset.o mcxt.o portalmem.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/utils/mmgr/README b/src/backend/utils/mmgr/README
new file mode 100644
index 0000000000..1b82d6398c
--- /dev/null
+++ b/src/backend/utils/mmgr/README
@@ -0,0 +1,379 @@
+Proposal for memory allocation fixes, take 2		21-Jun-2000
+--------------------------------------------
+
+We know that Postgres has serious problems with memory leakage during
+large queries that process a lot of pass-by-reference data.  There is
+no provision for recycling memory until end of query.  This needs to be
+fixed, even more so with the advent of TOAST which will allow very large
+chunks of data to be passed around in the system.  So, here is a proposal.
+
+
+Background
+----------
+
+We already do most of our memory allocation in "memory contexts", which
+are usually AllocSets as implemented by backend/utils/mmgr/aset.c.  What
+we need to do is create more contexts and define proper rules about when
+they can be freed.
+
+The basic operations on a memory context are:
+
+* create a context
+
+* allocate a chunk of memory within a context (equivalent of standard
+  C library's malloc())
+
+* delete a context (including freeing all the memory allocated therein)
+
+* reset a context (free all memory allocated in the context, but not the
+  context object itself)
+
+Given a chunk of memory previously allocated from a context, one can
+free it or reallocate it larger or smaller (corresponding to standard
+library's free() and realloc() routines).  These operations return memory
+to or get more memory from the same context the chunk was originally
+allocated in.
+
+At all times there is a "current" context denoted by the
+CurrentMemoryContext global variable.  The backend macro palloc()
+implicitly allocates space in that context.  The MemoryContextSwitchTo()
+operation selects a new current context (and returns the previous context,
+so that the caller can restore the previous context before exiting).
+
+The main advantage of memory contexts over plain use of malloc/free is
+that the entire contents of a memory context can be freed easily, without
+having to request freeing of each individual chunk within it.  This is
+both faster and more reliable than per-chunk bookkeeping.  We already use
+this fact to clean up at transaction end: by resetting all the active
+contexts, we reclaim all memory.  What we need are additional contexts
+that can be reset or deleted at strategic times within a query, such as
+after each tuple.
+
+
+pfree/repalloc no longer depend on CurrentMemoryContext
+-------------------------------------------------------
+
+In this proposal, pfree() and repalloc() can be applied to any chunk
+whether it belongs to CurrentMemoryContext or not --- the chunk's owning
+context will be invoked to handle the operation, regardless.  This is a
+change from the old requirement that CurrentMemoryContext must be set
+to the same context the memory was allocated from before one can use
+pfree() or repalloc().  The old coding requirement is obviously fairly
+error-prone, and will become more so the more context-switching we do;
+so I think it's essential to use CurrentMemoryContext only for palloc.
+We can avoid needing it for pfree/repalloc by putting restrictions on
+context managers as discussed below.
+
+We could even consider getting rid of CurrentMemoryContext entirely,
+instead requiring the target memory context for allocation to be specified
+explicitly.  But I think that would be too much notational overhead ---
+we'd have to pass an apppropriate memory context to called routines in
+many places.  For example, the copyObject routines would need to be passed
+a context, as would function execution routines that return a
+pass-by-reference datatype.  And what of routines that temporarily
+allocate space internally, but don't return it to their caller?  We
+certainly don't want to clutter every call in the system with "here is
+a context to use for any temporary memory allocation you might want to
+do".  So there'd still need to be a global variable specifying a suitable
+temporary-allocation context.  That might as well be CurrentMemoryContext.
+
+
+Additions to the memory-context mechanism
+-----------------------------------------
+
+If we are going to have more contexts, we need more mechanism for keeping
+track of them; else we risk leaking whole contexts under error conditions.
+
+We can do this by creating trees of "parent" and "child" contexts.  When
+creating a memory context, the new context can be specified to be a child
+of some existing context.  A context can have many children, but only one
+parent.  In this way the contexts form a forest (not necessarily a single
+tree, since there could be more than one top-level context).
+
+We then say that resetting or deleting any particular context resets or
+deletes all its direct and indirect children as well.  This feature allows
+us to manage a lot of contexts without fear that some will be leaked; we
+only need to keep track of one top-level context that we are going to
+delete at transaction end, and make sure that any shorter-lived contexts
+we create are descendants of that context.  Since the tree can have
+multiple levels, we can deal easily with nested lifetimes of storage,
+such as per-transaction, per-statement, per-scan, per-tuple.  Storage
+lifetimes that only partially overlap can be handled by allocating
+from different trees of the context forest (there are some examples
+in the next section).
+
+For convenience we will also want operations like "reset/delete all
+children of a given context, but don't reset or delete that context
+itself".
+
+
+Top-level contexts
+------------------
+
+There will be several top-level contexts --- these contexts have no parent
+and will be referenced by global variables.  At any instant the system may
+contain many additional contexts, but all other contexts should be direct
+or indirect children of one of the top-level contexts to ensure they are
+not leaked in event of an error.  I presently envision these top-level
+contexts:
+
+TopMemoryContext --- allocating here is essentially the same as "malloc",
+because this context will never be reset or deleted.  This is for stuff
+that should live forever, or for stuff that you know you will delete
+at the appropriate time.  An example is fd.c's tables of open files,
+as well as the context management nodes for memory contexts themselves.
+Avoid allocating stuff here unless really necessary, and especially
+avoid running with CurrentMemoryContext pointing here.
+
+PostmasterContext --- this is the postmaster's normal working context.
+After a backend is spawned, it can delete PostmasterContext to free its
+copy of memory the postmaster was using that it doesn't need.  (Anything
+that has to be passed from postmaster to backends will be passed in
+TopMemoryContext.  The postmaster will probably have only TopMemoryContext,
+PostmasterContext, and possibly ErrorContext --- the remaining top-level
+contexts will be set up in each backend during startup.)
+
+CacheMemoryContext --- permanent storage for relcache, catcache, and
+related modules.  This will never be reset or deleted, either, so it's
+not truly necessary to distinguish it from TopMemoryContext.  But it
+seems worthwhile to maintain the distinction for debugging purposes.
+(Note: CacheMemoryContext may well have child-contexts with shorter
+lifespans.  For example, a child context seems like the best place to
+keep the subsidiary storage associated with a relcache entry; that way
+we can free rule parsetrees and so forth easily, without having to depend
+on constructing a reliable version of freeObject().)
+
+QueryContext --- this is where the storage holding a received query string
+is kept, as well as storage that should live as long as the query string,
+notably the parsetree constructed from it.  This context will be reset at
+the top of each cycle of the outer loop of PostgresMain, thereby freeing
+the old query and parsetree.  We must keep this separate from
+TopTransactionContext because a query string might need to live either a
+longer or shorter time than a transaction, depending on whether it
+contains begin/end commands or not.  (This'll also fix the nasty bug that
+"vacuum; anything else" crashes if submitted as a single query string,
+because vacuum's xact commit frees the memory holding the parsetree...)
+
+TopTransactionContext --- this holds everything that lives until end of
+transaction (longer than one statement within a transaction!).  An example
+of what has to be here is the list of pending NOTIFY messages to be sent
+at xact commit.  This context will be reset, and all its children deleted,
+at conclusion of each transaction cycle.  Note: presently I envision that
+this context will NOT be cleared immediately upon error; its contents
+will survive anyway until the transaction block is exited by
+COMMIT/ROLLBACK.  This seems appropriate since we want to move in the
+direction of allowing a transaction to continue processing after an error.
+
+TransactionCommandContext --- this is really a child of
+TopTransactionContext, not a top-level context, but we'll probably store a
+link to it in a global variable anyway for convenience.  All the memory
+allocated during planning and execution lives here or in a child context.
+This context is deleted at statement completion, whether normal completion
+or error abort.
+
+ErrorContext --- this permanent context will be switched into
+for error recovery processing, and then reset on completion of recovery.
+We'll arrange to have, say, 8K of memory available in it at all times.
+In this way, we can ensure that some memory is available for error
+recovery even if the backend has run out of memory otherwise.  This should
+allow out-of-memory to be treated as a normal ERROR condition, not a FATAL
+error.
+
+If we ever implement nested transactions, there may need to be some
+additional levels of transaction-local contexts between
+TopTransactionContext and TransactionCommandContext, but that's beyond
+the scope of this proposal.
+
+
+Transient contexts during execution
+-----------------------------------
+
+The planner will probably have a transient context in which it stores
+pathnodes; this will allow it to release the bulk of its temporary space
+usage (which can be a lot, for large joins) at completion of planning.
+The completed plan tree will be in TransactionCommandContext.
+
+The executor will have contexts with lifetime similar to plan nodes
+(I'm not sure at the moment whether there's need for one such context
+per plan level, or whether a single context is sufficient).  These
+contexts will hold plan-node-local execution state and related items.
+There will also be a context on each plan level that is reset at the start
+of each tuple processing cycle.  This per-tuple context will be the normal
+CurrentMemoryContext during evaluation of expressions and so forth.  By
+resetting it, we reclaim transient memory that was used during processing
+of the prior tuple.  That should be enough to solve the problem of running
+out of memory on large queries.  We must have a per-tuple context in each
+plan node, and we must reset it at the start of a tuple cycle rather than
+the end, so that each plan node can use results of expression evaluation
+as part of the tuple it returns to its parent node.
+
+By resetting the per-tuple context, we will be able to free memory after
+each tuple is processed, rather than only after the whole plan is
+processed.  This should solve our memory leakage problems pretty well;
+yet we do not need to add very much new bookkeeping logic to do it.
+In particular, we do *not* need to try to keep track of individual values
+palloc'd during expression evaluation.
+
+Note we assume that resetting a context is a cheap operation.  This is
+true already, and we can make it even more true with a little bit of
+tuning in aset.c.
+
+There will be some special cases, such as aggregate functions.  nodeAgg.c
+needs to remember the results of evaluation of aggregate transition
+functions from one tuple cycle to the next, so it can't just discard
+all per-tuple state in each cycle.  The easiest way to handle this seems
+to be to have two per-tuple contexts in an aggregate node, and to
+ping-pong between them, so that at each tuple one is the active allocation
+context and the other holds any results allocated by the prior cycle's
+transition function.
+
+Executor routines that switch the active CurrentMemoryContext may need
+to copy data into their caller's current memory context before returning.
+I think there will be relatively little need for that, because of the
+convention of resetting the per-tuple context at the *start* of an
+execution cycle rather than at its end.  With that rule, an execution
+node can return a tuple that is palloc'd in its per-tuple context, and
+the tuple will remain good until the node is called for another tuple
+or told to end execution.  This is pretty much the same state of affairs
+that exists now, since a scan node can return a direct pointer to a tuple
+in a disk buffer that is only guaranteed to remain good that long.
+
+A more common reason for copying data will be to transfer a result from
+per-tuple context to per-run context; for example, a Unique node will
+save the last distinct tuple value in its per-run context, requiring a
+copy step.  (Actually, Unique could use the same trick with two per-tuple
+contexts as described above for Agg, but there will probably be other
+cases where doing an extra copy step is the right thing.)
+
+Another interesting special case is VACUUM, which needs to allocate
+working space that will survive its forced transaction commits, yet
+be released on error.  Currently it does that through a "portal",
+which is essentially a child context of TopMemoryContext.  While that
+way still works, it's ugly since xact abort needs special processing
+to delete the portal.  Better would be to use a context that's a child
+of QueryContext and hence is certain to go away as part of normal
+processing.  (Eventually we might have an even better solution from
+nested transactions, but this'll do fine for now.)
+
+
+Mechanisms to allow multiple types of contexts
+----------------------------------------------
+
+We may want several different types of memory contexts with different
+allocation policies but similar external behavior.  To handle this,
+memory allocation functions will be accessed via function pointers,
+and we will require all context types to obey the conventions given here.
+(This is not very far different from the existing code.)
+
+A memory context will be represented by an object like
+
+typedef struct MemoryContextData
+{
+    NodeTag        type;           /* identifies exact kind of context */
+    MemoryContextMethods methods;
+    MemoryContextData *parent;     /* NULL if no parent (toplevel context) */
+    MemoryContextData *firstchild; /* head of linked list of children */
+    MemoryContextData *nextchild;  /* next child of same parent */
+    char          *name;           /* context name (just for debugging) */
+} MemoryContextData, *MemoryContext;
+
+This is essentially an abstract superclass, and the "methods" pointer is
+its virtual function table.  Specific memory context types will use
+derived structs having these fields as their first fields.  All the
+contexts of a specific type will have methods pointers that point to the
+same static table of function pointers, which will look like
+
+typedef struct MemoryContextMethodsData
+{
+    Pointer     (*alloc) (MemoryContext c, Size size);
+    void        (*free_p) (Pointer chunk);
+    Pointer     (*realloc) (Pointer chunk, Size newsize);
+    void        (*reset) (MemoryContext c);
+    void        (*delete) (MemoryContext c);
+} MemoryContextMethodsData, *MemoryContextMethods;
+
+Alloc, reset, and delete requests will take a MemoryContext pointer
+as parameter, so they'll have no trouble finding the method pointer
+to call.  Free and realloc are trickier.  To make those work, we will
+require all memory context types to produce allocated chunks that
+are immediately preceded by a standard chunk header, which has the
+layout
+
+typedef struct StandardChunkHeader
+{
+    MemoryContext mycontext;         /* Link to owning context object */
+    Size          size;              /* Allocated size of chunk */
+};
+
+It turns out that the existing aset.c memory context type does this
+already, and probably any other kind of context would need to have the
+same data available to support realloc, so this is not really creating
+any additional overhead.  (Note that if a context type needs more per-
+allocated-chunk information than this, it can make an additional
+nonstandard header that precedes the standard header.  So we're not
+constraining context-type designers very much.)
+
+Given this, the pfree routine will look something like
+
+    StandardChunkHeader * header = 
+        (StandardChunkHeader *) ((char *) p - sizeof(StandardChunkHeader));
+
+    (*header->mycontext->methods->free_p) (p);
+
+We could do it as a macro, but the macro would have to evaluate its
+argument twice, which seems like a bad idea (the current pfree macro
+does not do that).  This is already saving two levels of function call
+compared to the existing code, so I think we're doing fine without
+squeezing out that last little bit ...
+
+
+More control over aset.c behavior
+---------------------------------
+
+Currently, aset.c allocates an 8K block upon the first allocation in
+a context, and doubles that size for each successive block request.
+That's good behavior for a context that might hold *lots* of data, and
+the overhead wasn't bad when we had only a few contexts in existence.
+With dozens if not hundreds of smaller contexts in the system, we will
+want to be able to fine-tune things a little better.
+
+The creator of a context will be able to specify an initial block size
+and a maximum block size.  Selecting smaller values will prevent wastage
+of space in contexts that aren't expected to hold very much (an example is
+the relcache's per-relation contexts).
+
+Also, it will be possible to specify a minimum context size.  If this
+value is greater than zero then a block of that size will be grabbed
+immediately upon context creation, and cleared but not released during
+context resets.  This feature is needed for ErrorContext (see above).
+It is also useful for per-tuple contexts, which will be reset frequently
+and typically will not allocate very much space per tuple cycle.  We can
+save a lot of unnecessary malloc traffic if these contexts hang onto one
+allocation block rather than releasing and reacquiring the block on
+each tuple cycle.
+
+
+Other notes
+-----------
+
+The original version of this proposal suggested that functions returning
+pass-by-reference datatypes should be required to return a value freshly
+palloc'd in their caller's memory context, never a pointer to an input
+value.  I've abandoned that notion since it clearly is prone to error.
+In the current proposal, it is possible to discover which context a
+chunk of memory is allocated in (by checking the required standard chunk
+header), so nodeAgg can determine whether or not it's safe to reset
+its working context; it doesn't have to rely on the transition function
+to do what it's expecting.
+
+It might be that the executor per-run contexts described above should
+be tied directly to executor "EState" nodes, that is, one context per
+EState.  I'm not real clear on the lifespan of EStates or the situations
+where we have just one or more than one, so I'm not sure.  Comments?
+
+It would probably be possible to adapt the existing "portal" memory
+management mechanism to do what we need.  I am instead proposing setting
+up a totally new mechanism, because the portal code strikes me as
+extremely crufty and unwieldy.  It may be that we can eventually remove
+portals entirely, or perhaps reimplement them with this mechanism
+underneath.
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 574b98697d..e0244ade78 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -3,12 +3,15 @@
  * aset.c
  *	  Allocation set definitions.
  *
+ * AllocSet is our standard implementation of the abstract MemoryContext
+ * type.
+ *
+ *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.27 2000/05/21 02:23:29 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.28 2000/06/28 03:32:50 tgl Exp $
  *
  * NOTE:
  *	This is a new (Feb. 05, 1999) implementation of the allocation set
@@ -30,15 +33,68 @@
  *	AllocSetReset() under the old way.
  *-------------------------------------------------------------------------
  */
+
 #include "postgres.h"
+
 #include "utils/memutils.h"
 
 
-#undef AllocSetReset
-#undef malloc
-#undef free
-#undef realloc
+/*
+ * AllocSetContext is defined in nodes/memnodes.h.
+ */
+typedef AllocSetContext *AllocSet;
+
+/*
+ * AllocPointer
+ *		Aligned pointer which may be a member of an allocation set.
+ */
+typedef void *AllocPointer;
+
+/*
+ * AllocBlock
+ *		An AllocBlock is the unit of memory that is obtained by aset.c
+ *		from malloc().	It contains one or more AllocChunks, which are
+ *		the units requested by palloc() and freed by pfree().  AllocChunks
+ *		cannot be returned to malloc() individually, instead they are put
+ *		on freelists by pfree() and re-used by the next palloc() that has
+ *		a matching request size.
+ *
+ *		AllocBlockData is the header data for a block --- the usable space
+ *		within the block begins at the next alignment boundary.
+ */
+typedef struct AllocBlockData
+{
+	AllocSet	aset;			/* aset that owns this block */
+	AllocBlock	next;			/* next block in aset's blocks list */
+	char	   *freeptr;		/* start of free space in this block */
+	char	   *endptr;			/* end of space in this block */
+} AllocBlockData;
+
+/*
+ * AllocChunk
+ *		The prefix of each piece of memory in an AllocBlock
+ *
+ * NB: this MUST match StandardChunkHeader as defined by utils/memutils.h.
+ */
+typedef struct AllocChunkData
+{
+	/* aset is the owning aset if allocated, or the freelist link if free */
+	void	   *aset;
+	/* size is always the size of the usable space in the chunk */
+	Size		size;
+} AllocChunkData;
 
+/*
+ * AllocPointerIsValid
+ *		True iff pointer is valid allocation pointer.
+ */
+#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
+
+/*
+ * AllocSetIsValid
+ *		True iff set is valid allocation set.
+ */
+#define AllocSetIsValid(set) PointerIsValid(set)
 
 /*--------------------
  * Chunk freelist k holds chunks of size 1 << (k + ALLOC_MINBITS),
@@ -59,9 +115,9 @@
 /* Size of largest chunk that we use a fixed size for */
 
 /*--------------------
- * The first block allocated for an allocset has size ALLOC_MIN_BLOCK_SIZE.
+ * The first block allocated for an allocset has size initBlockSize.
  * Each time we have to allocate another block, we double the block size
- * (if possible, and without exceeding ALLOC_MAX_BLOCK_SIZE), so as to reduce
+ * (if possible, and without exceeding maxBlockSize), so as to reduce
  * the bookkeeping load on malloc().
  *
  * Blocks allocated to hold oversize chunks do not follow this rule, however;
@@ -74,20 +130,21 @@
  * AllocSetAlloc has discretion whether to put the request into an existing
  * block or make a single-chunk block.
  *
- * We must have ALLOC_MIN_BLOCK_SIZE > ALLOC_SMALLCHUNK_LIMIT and
+ * We must have initBlockSize > ALLOC_SMALLCHUNK_LIMIT and
  * ALLOC_BIGCHUNK_LIMIT > ALLOC_SMALLCHUNK_LIMIT.
  *--------------------
  */
 
-#define ALLOC_MIN_BLOCK_SIZE	(8 * 1024)
-#define ALLOC_MAX_BLOCK_SIZE	(8 * 1024 * 1024)
-
 #define ALLOC_BIGCHUNK_LIMIT	(64 * 1024)
 /* Chunks >= ALLOC_BIGCHUNK_LIMIT are immediately free()d by pfree() */
 
 #define ALLOC_BLOCKHDRSZ	MAXALIGN(sizeof(AllocBlockData))
 #define ALLOC_CHUNKHDRSZ	MAXALIGN(sizeof(AllocChunkData))
 
+/* Min safe value of allocation block size */
+#define ALLOC_MIN_BLOCK_SIZE  \
+	(ALLOC_SMALLCHUNK_LIMIT + ALLOC_CHUNKHDRSZ + ALLOC_BLOCKHDRSZ)
+
 #define AllocPointerGetChunk(ptr)	\
 					((AllocChunk)(((char *)(ptr)) - ALLOC_CHUNKHDRSZ))
 #define AllocChunkGetPointer(chk)	\
@@ -95,6 +152,29 @@
 #define AllocPointerGetAset(ptr)	((AllocSet)(AllocPointerGetChunk(ptr)->aset))
 #define AllocPointerGetSize(ptr)	(AllocPointerGetChunk(ptr)->size)
 
+/*
+ * These functions implement the MemoryContext API for AllocSet contexts.
+ */
+static void *AllocSetAlloc(MemoryContext context, Size size);
+static void AllocSetFree(MemoryContext context, void *pointer);
+static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
+static void AllocSetInit(MemoryContext context);
+static void AllocSetReset(MemoryContext context);
+static void AllocSetDelete(MemoryContext context);
+static void AllocSetStats(MemoryContext context);
+
+/*
+ * This is the virtual function table for AllocSet contexts.
+ */
+static MemoryContextMethods AllocSetMethods = {
+	AllocSetAlloc,
+	AllocSetFree,
+	AllocSetRealloc,
+	AllocSetInit,
+	AllocSetReset,
+	AllocSetDelete,
+	AllocSetStats
+};
 
 
 /* ----------
@@ -127,92 +207,182 @@ AllocSetFreeIndex(Size size)
  * Public routines
  */
 
+
 /*
- * AllocSetInit
- *		Initializes given allocation set.
- *
- * Note:
- *		The semantics of the mode are explained above.	Limit is ignored
- *		for dynamic and static modes.
+ * AllocSetContextCreate
+ *		Create a new AllocSet context.
  *
- * Exceptions:
- *		BadArg if set is invalid pointer.
- *		BadArg if mode is invalid.
+ * parent: parent context, or NULL if top-level context
+ * name: name of context (for debugging --- string will be copied)
+ * minContextSize: minimum context size
+ * initBlockSize: initial allocation block size
+ * maxBlockSize: maximum allocation block size
  */
-void
-AllocSetInit(AllocSet set, AllocMode mode, Size limit)
+MemoryContext
+AllocSetContextCreate(MemoryContext parent,
+					  const char *name,
+					  Size minContextSize,
+					  Size initBlockSize,
+					  Size maxBlockSize)
 {
-	AssertArg(PointerIsValid(set));
-	AssertArg((int) DynamicAllocMode <= (int) mode);
-	AssertArg((int) mode <= (int) BoundedAllocMode);
+	AllocSet	context;
+
+	/* Do the type-independent part of context creation */
+	context = (AllocSet) MemoryContextCreate(T_AllocSetContext,
+											 sizeof(AllocSetContext),
+											 &AllocSetMethods,
+											 parent,
+											 name);
+	/*
+	 * Make sure alloc parameters are safe, and save them
+	 */
+	initBlockSize = MAXALIGN(initBlockSize);
+	if (initBlockSize < ALLOC_MIN_BLOCK_SIZE)
+		initBlockSize = ALLOC_MIN_BLOCK_SIZE;
+	maxBlockSize = MAXALIGN(maxBlockSize);
+	if (maxBlockSize < initBlockSize)
+		maxBlockSize = initBlockSize;
+	context->initBlockSize = initBlockSize;
+	context->maxBlockSize = maxBlockSize;
 
 	/*
-	 * XXX mode is currently ignored and treated as DynamicAllocMode. XXX
-	 * limit is also ignored.  This affects this whole file.
+	 * Grab always-allocated space, if requested
 	 */
+	if (minContextSize > ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)
+	{
+		Size		blksize = MAXALIGN(minContextSize);
+		AllocBlock	block;
 
-	memset(set, 0, sizeof(AllocSetData));
+		block = (AllocBlock) malloc(blksize);
+		if (block == NULL)
+			elog(ERROR, "Memory exhausted in AllocSetContextCreate()");
+		block->aset = context;
+		block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
+		block->endptr = ((char *) block) + blksize;
+		block->next = context->blocks;
+		context->blocks = block;
+		/* Mark block as not to be released at reset time */
+		context->keeper = block;
+	}
+
+	return (MemoryContext) context;
 }
 
+/*
+ * AllocSetInit
+ *		Context-type-specific initialization routine.
+ *
+ * This is called by MemoryContextCreate() after setting up the
+ * generic MemoryContext fields and before linking the new context
+ * into the context tree.  We must do whatever is needed to make the
+ * new context minimally valid for deletion.  We must *not* risk
+ * failure --- thus, for example, allocating more memory is not cool.
+ * (AllocSetContextCreate can allocate memory when it gets control
+ * back, however.)
+ */
+static void
+AllocSetInit(MemoryContext context)
+{
+	/*
+	 * Since MemoryContextCreate already zeroed the context node,
+	 * we don't have to do anything here: it's already OK.
+	 */
+}
 
 /*
  * AllocSetReset
  *		Frees all memory which is allocated in the given set.
  *
- * Exceptions:
- *		BadArg if set is invalid.
+ * Actually, this routine has some discretion about what to do.
+ * It should mark all allocated chunks freed, but it need not
+ * necessarily give back all the resources the set owns.  Our
+ * actual implementation is that we hang on to any "keeper"
+ * block specified for the set.
  */
-void
-AllocSetReset(AllocSet set)
+static void
+AllocSetReset(MemoryContext context)
 {
+	AllocSet	set = (AllocSet) context;
 	AllocBlock	block = set->blocks;
-	AllocBlock	next;
 
 	AssertArg(AllocSetIsValid(set));
 
 	while (block != NULL)
 	{
-		next = block->next;
+		AllocBlock	next = block->next;
+
+		if (block == set->keeper)
+		{
+			/* Reset the block, but don't return it to malloc */
+			block->next = NULL;
+			block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
 #ifdef CLOBBER_FREED_MEMORY
-		/* Wipe freed memory for debugging purposes */
-		memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+			/* Wipe freed memory for debugging purposes */
+			memset(block->freeptr, 0x7F,
+				   ((char *) block->endptr) - ((char *) block->freeptr));
 #endif
-		free(block);
+		}
+		else
+		{
+			/* Normal case, release the block */
+#ifdef CLOBBER_FREED_MEMORY
+			/* Wipe freed memory for debugging purposes */
+			memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+#endif
+			free(block);
+		}
 		block = next;
 	}
 
-	memset(set, 0, sizeof(AllocSetData));
+	/* Now blocks list is either empty or just the keeper block */
+	set->blocks = set->keeper;
+	/* Clear chunk freelists in any case */
+	MemSet(set->freelist, 0, sizeof(set->freelist));
 }
 
 /*
- * AllocSetContains
- *		True iff allocation set contains given allocation element.
+ * AllocSetDelete
+ *		Frees all memory which is allocated in the given set,
+ *		in preparation for deletion of the set.
  *
- * Exceptions:
- *		BadArg if set is invalid.
- *		BadArg if pointer is invalid.
+ * Unlike AllocSetReset, this *must* free all resources of the set.
+ * But note we are not responsible for deleting the context node itself.
  */
-bool
-AllocSetContains(AllocSet set, AllocPointer pointer)
+static void
+AllocSetDelete(MemoryContext context)
 {
+	AllocSet	set = (AllocSet) context;
+	AllocBlock	block = set->blocks;
+
 	AssertArg(AllocSetIsValid(set));
-	AssertArg(AllocPointerIsValid(pointer));
 
-	return (AllocPointerGetAset(pointer) == set);
+	while (block != NULL)
+	{
+		AllocBlock	next = block->next;
+
+#ifdef CLOBBER_FREED_MEMORY
+		/* Wipe freed memory for debugging purposes */
+		memset(block, 0x7F, ((char *) block->endptr) - ((char *) block));
+#endif
+		free(block);
+		block = next;
+	}
+
+	/* Make it look empty, just in case... */
+	set->blocks = NULL;
+	MemSet(set->freelist, 0, sizeof(set->freelist));
+	set->keeper = NULL;
 }
 
 /*
  * AllocSetAlloc
  *		Returns pointer to allocated memory of given size; memory is added
  *		to the set.
- *
- * Exceptions:
- *		BadArg if set is invalid.
- *		MemoryExhausted if allocation fails.
  */
-AllocPointer
-AllocSetAlloc(AllocSet set, Size size)
+static void *
+AllocSetAlloc(MemoryContext context, Size size)
 {
+	AllocSet	set = (AllocSet) context;
 	AllocBlock	block;
 	AllocChunk	chunk;
 	AllocChunk	priorfree = NULL;
@@ -225,7 +395,6 @@ AllocSetAlloc(AllocSet set, Size size)
 	/*
 	 * Lookup in the corresponding free list if there is a free chunk we
 	 * could reuse
-	 *
 	 */
 	fidx = AllocSetFreeIndex(size);
 	for (chunk = set->freelist[fidx]; chunk; chunk = (AllocChunk) chunk->aset)
@@ -238,7 +407,6 @@ AllocSetAlloc(AllocSet set, Size size)
 	/*
 	 * If one is found, remove it from the free list, make it again a
 	 * member of the alloc set and return its data address.
-	 *
 	 */
 	if (chunk != NULL)
 	{
@@ -284,7 +452,7 @@ AllocSetAlloc(AllocSet set, Size size)
 		blksize = chunk_size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
 		block = (AllocBlock) malloc(blksize);
 		if (block == NULL)
-			elog(FATAL, "Memory exhausted in AllocSetAlloc()");
+			elog(ERROR, "Memory exhausted in AllocSetAlloc()");
 		block->aset = set;
 		block->freeptr = block->endptr = ((char *) block) + blksize;
 
@@ -317,7 +485,7 @@ AllocSetAlloc(AllocSet set, Size size)
 	{
 		if (set->blocks == NULL)
 		{
-			blksize = ALLOC_MIN_BLOCK_SIZE;
+			blksize = set->initBlockSize;
 			block = (AllocBlock) malloc(blksize);
 		}
 		else
@@ -327,15 +495,18 @@ AllocSetAlloc(AllocSet set, Size size)
 
 			/*
 			 * Special case: if very first allocation was for a large
-			 * chunk, could have a funny-sized top block.  Do something
-			 * reasonable.
+			 * chunk (or we have a small "keeper" block), could have an
+			 * undersized top block.  Do something reasonable.
 			 */
-			if (blksize < ALLOC_MIN_BLOCK_SIZE)
-				blksize = ALLOC_MIN_BLOCK_SIZE;
-			/* Crank it up, but not past max */
-			blksize <<= 1;
-			if (blksize > ALLOC_MAX_BLOCK_SIZE)
-				blksize = ALLOC_MAX_BLOCK_SIZE;
+			if (blksize < set->initBlockSize)
+				blksize = set->initBlockSize;
+			else
+			{
+				/* Crank it up, but not past max */
+				blksize <<= 1;
+				if (blksize > set->maxBlockSize)
+					blksize = set->maxBlockSize;
+			}
 			/* Try to allocate it */
 			block = (AllocBlock) malloc(blksize);
 
@@ -352,7 +523,7 @@ AllocSetAlloc(AllocSet set, Size size)
 		}
 
 		if (block == NULL)
-			elog(FATAL, "Memory exhausted in AllocSetAlloc()");
+			elog(ERROR, "Memory exhausted in AllocSetAlloc()");
 		block->aset = set;
 		block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
 		block->endptr = ((char *) block) + blksize;
@@ -376,22 +547,12 @@ AllocSetAlloc(AllocSet set, Size size)
 /*
  * AllocSetFree
  *		Frees allocated memory; memory is removed from the set.
- *
- * Exceptions:
- *		BadArg if set is invalid.
- *		BadArg if pointer is invalid.
- *		BadArg if pointer is not member of set.
  */
-void
-AllocSetFree(AllocSet set, AllocPointer pointer)
+static void
+AllocSetFree(MemoryContext context, void *pointer)
 {
-	AllocChunk	chunk;
-
-	/* AssertArg(AllocSetIsValid(set)); */
-	/* AssertArg(AllocPointerIsValid(pointer)); */
-	AssertArg(AllocSetContains(set, pointer));
-
-	chunk = AllocPointerGetChunk(pointer);
+	AllocSet	set = (AllocSet) context;
+	AllocChunk	chunk = AllocPointerGetChunk(pointer);
 
 #ifdef CLOBBER_FREED_MEMORY
 	/* Wipe freed memory for debugging purposes */
@@ -446,24 +607,15 @@ AllocSetFree(AllocSet set, AllocPointer pointer)
  *		Returns new pointer to allocated memory of given size; this memory
  *		is added to the set.  Memory associated with given pointer is copied
  *		into the new memory, and the old memory is freed.
- *
- * Exceptions:
- *		BadArg if set is invalid.
- *		BadArg if pointer is invalid.
- *		BadArg if pointer is not member of set.
- *		MemoryExhausted if allocation fails.
  */
-AllocPointer
-AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
+static void *
+AllocSetRealloc(MemoryContext context, void *pointer, Size size)
 {
+	AllocSet	set = (AllocSet) context;
 	Size		oldsize;
 
-	/* AssertArg(AllocSetIsValid(set)); */
-	/* AssertArg(AllocPointerIsValid(pointer)); */
-	AssertArg(AllocSetContains(set, pointer));
-
 	/*
-	 * Chunk sizes are aligned to power of 2 on AllocSetAlloc(). Maybe the
+	 * Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the
 	 * allocated area already is >= the new size.  (In particular, we
 	 * always fall out here if the requested size is a decrease.)
 	 */
@@ -503,7 +655,7 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
 		blksize = size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
 		block = (AllocBlock) realloc(block, blksize);
 		if (block == NULL)
-			elog(FATAL, "Memory exhausted in AllocSetReAlloc()");
+			elog(ERROR, "Memory exhausted in AllocSetReAlloc()");
 		block->freeptr = block->endptr = ((char *) block) + blksize;
 
 		/* Update pointers since block has likely been moved */
@@ -520,35 +672,26 @@ AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
 		/* Normal small-chunk case: just do it by brute force. */
 
 		/* allocate new chunk */
-		AllocPointer newPointer = AllocSetAlloc(set, size);
+		AllocPointer newPointer = AllocSetAlloc((MemoryContext) set, size);
 
 		/* transfer existing data (certain to fit) */
 		memcpy(newPointer, pointer, oldsize);
 
 		/* free old chunk */
-		AllocSetFree(set, pointer);
+		AllocSetFree((MemoryContext) set, pointer);
 
 		return newPointer;
 	}
 }
 
-/*
- * AllocSetDump
- *		Displays allocated set.
- */
-void
-AllocSetDump(AllocSet set)
-{
-	elog(DEBUG, "Currently unable to dump AllocSet");
-}
-
 /*
  * AllocSetStats
  *		Displays stats about memory consumption of an allocset.
  */
-void
-AllocSetStats(AllocSet set, const char *ident)
+static void
+AllocSetStats(MemoryContext context)
 {
+	AllocSet	set = (AllocSet) context;
 	long		nblocks = 0;
 	long		nchunks = 0;
 	long		totalspace = 0;
@@ -557,8 +700,6 @@ AllocSetStats(AllocSet set, const char *ident)
 	AllocChunk	chunk;
 	int			fidx;
 
-	AssertArg(AllocSetIsValid(set));
-
 	for (block = set->blocks; block != NULL; block = block->next)
 	{
 		nblocks++;
@@ -576,6 +717,6 @@ AllocSetStats(AllocSet set, const char *ident)
 	}
 	fprintf(stderr,
 			"%s: %ld total in %ld blocks; %ld free (%ld chunks); %ld used\n",
-			ident, totalspace, nblocks, freespace, nchunks,
+			set->header.name, totalspace, nblocks, freespace, nchunks,
 			totalspace - freespace);
 }
diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 5a3be6700e..71877c4e62 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -1,14 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * mcxt.c
- *	  POSTGRES memory context code.
+ *	  POSTGRES memory context management code.
+ *
+ * This module handles context management operations that are independent
+ * of the particular kind of context being operated on.  It calls
+ * context-type-specific operations via the function pointers in a
+ * context's MemoryContextMethods struct.
+ *
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.21 2000/05/21 02:23:29 tgl Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.22 2000/06/28 03:32:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,41 +23,8 @@
 
 #include "nodes/memnodes.h"
 #include "utils/excid.h"
-#include "utils/module.h"
-
-
-
-#undef MemoryContextAlloc
-#undef MemoryContextFree
-#undef malloc
-#undef free
-
-/*
- * Global State
- */
-static int	MemoryContextEnableCount = 0;
-
-#define MemoryContextEnabled	(MemoryContextEnableCount > 0)
+#include "utils/memutils.h"
 
-static OrderedSetData ActiveGlobalMemorySetData;		/* uninitialized */
-
-#define ActiveGlobalMemorySet	(&ActiveGlobalMemorySetData)
-
-/*
- * description of allocated memory representation goes here
- */
-
-#define PSIZE(PTR)		(*((int32 *)(PTR) - 1))
-#define PSIZEALL(PTR)	(*((int32 *)(PTR) - 1) + sizeof (int32))
-#define PSIZESKIP(PTR)	((char *)((int32 *)(PTR) + 1))
-#define PSIZEFIND(PTR)	((char *)((int32 *)(PTR) - 1))
-#define PSIZESPACE(LEN) ((LEN) + sizeof (int32))
-
-/*
- * AllocSizeIsValid
- *		True iff 0 < size and size <= MaxAllocSize.
- */
-#define AllocSizeIsValid(size)	(0 < (size) && (size) <= MaxAllocSize)
 
 /*****************************************************************************
  *	  GLOBAL MEMORY															 *
@@ -59,478 +32,451 @@ static OrderedSetData ActiveGlobalMemorySetData;		/* uninitialized */
 
 /*
  * CurrentMemoryContext
- *		Memory context for general global allocations.
+ *		Default memory context for allocations.
  */
 DLLIMPORT MemoryContext CurrentMemoryContext = NULL;
 
-/*****************************************************************************
- *	  PRIVATE DEFINITIONS													 *
- *****************************************************************************/
-
-static Pointer GlobalMemoryAlloc(GlobalMemory this, Size size);
-static void GlobalMemoryFree(GlobalMemory this, Pointer pointer);
-static Pointer GlobalMemoryRealloc(GlobalMemory this, Pointer pointer,
-					Size size);
-static char *GlobalMemoryGetName(GlobalMemory this);
-static void GlobalMemoryDump(GlobalMemory this);
-
-#ifdef NOT_USED
-static void DumpGlobalMemories(void);
-
-#endif
-
 /*
- * Global Memory Methods
+ * Standard top-level contexts
  */
+MemoryContext TopMemoryContext = NULL;
+MemoryContext ErrorContext = NULL;
+MemoryContext PostmasterContext = NULL;
+MemoryContext CacheMemoryContext = NULL;
+MemoryContext QueryContext = NULL;
+MemoryContext TopTransactionContext = NULL;
+MemoryContext TransactionCommandContext = NULL;
 
-static struct MemoryContextMethodsData GlobalContextMethodsData = {
-	GlobalMemoryAlloc,			/* Pointer (*)(this, uint32)  palloc */
-	GlobalMemoryFree,			/* void (*)(this, Pointer)	  pfree */
-	GlobalMemoryRealloc,		/* Pointer (*)(this, Pointer) repalloc */
-	GlobalMemoryGetName,		/* char* (*)(this)			  getName */
-	GlobalMemoryDump			/* void (*)(this)			  dump */
-};
 
-/*
- * Note:
- *		TopGlobalMemory is handled specially because of bootstrapping.
- */
-/* extern bool EqualGlobalMemory(); */
+/*****************************************************************************
+ *	  EXPORTED ROUTINES														 *
+ *****************************************************************************/
 
-static struct GlobalMemoryData TopGlobalMemoryData = {
-	T_GlobalMemory,				/* NodeTag				tag		  */
-	&GlobalContextMethodsData,	/* ContextMethods		method	  */
-	{NULL, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}},
-	/* free AllocSet   */
-	"TopGlobal",				/* char* name	   */
-	{0}							/* uninitialized OrderedElemData elemD */
-};
 
 /*
- * TopMemoryContext
- *		Memory context for general global allocations.
+ * MemoryContextInit
+ *		Start up the memory-context subsystem.
  *
- * Note:
- *		Don't use this memory context for random allocations.  If you
- *		allocate something here, you are expected to clean it up when
- *		appropriate.
- */
-MemoryContext TopMemoryContext = (MemoryContext) &TopGlobalMemoryData;
-
-
-
-
-/*
- * Module State
- */
-
-/*
- * EnableMemoryContext
- *		Enables/disables memory management and global contexts.
+ * This must be called before creating contexts or allocating memory in
+ * contexts.  TopMemoryContext and ErrorContext are initialized here;
+ * other contexts must be created afterwards.
  *
- * Note:
- *		This must be called before creating contexts or allocating memory.
- *		This must be called before other contexts are created.
+ * In normal multi-backend operation, this is called once during
+ * postmaster startup, and not at all by individual backend startup
+ * (since the backends inherit an already-initialized context subsystem
+ * by virtue of being forked off the postmaster).
  *
- * Exceptions:
- *		BadArg if on is invalid.
- *		BadState if on is false when disabled.
+ * In a standalone backend this must be called during backend startup.
  */
 void
-EnableMemoryContext(bool on)
+MemoryContextInit(void)
 {
-	static bool processing = false;
-
-	AssertState(!processing);
-	AssertArg(BoolIsValid(on));
-
-	if (BypassEnable(&MemoryContextEnableCount, on))
-		return;
-
-	processing = true;
-
-	if (on)
-	{							/* initialize */
-		/* initialize TopGlobalMemoryData.setData */
-		AllocSetInit(&TopGlobalMemoryData.setData, DynamicAllocMode,
-					 (Size) 0);
-
-		/* make TopGlobalMemoryData member of ActiveGlobalMemorySet */
-		OrderedSetInit(ActiveGlobalMemorySet,
-					   offsetof(struct GlobalMemoryData, elemData));
-		OrderedElemPushInto(&TopGlobalMemoryData.elemData,
-							ActiveGlobalMemorySet);
-
-		/* initialize CurrentMemoryContext */
-		CurrentMemoryContext = TopMemoryContext;
-
-	}
-	else
-	{							/* cleanup */
-		GlobalMemory context;
-
-		/* walk the list of allocations */
-		while (PointerIsValid(context = (GlobalMemory)
-							  OrderedSetGetHead(ActiveGlobalMemorySet)))
-		{
-
-			if (context == &TopGlobalMemoryData)
-			{
-				/* don't free it and clean it last */
-				OrderedElemPop(&TopGlobalMemoryData.elemData);
-			}
-			else
-				GlobalMemoryDestroy(context);
-			/* what is needed for the top? */
-		}
-
-		/*
-		 * Freeing memory here should be safe as this is called only after
-		 * all modules which allocate in TopMemoryContext have been
-		 * disabled.
-		 */
-
-		/* step through remaining allocations and log */
-		/* AllocSetStep(...); */
-
-		/* deallocate whatever is left */
-		AllocSetReset(&TopGlobalMemoryData.setData);
-	}
-
-	processing = false;
+	AssertState(TopMemoryContext == NULL);
+	/*
+	 * Initialize TopMemoryContext as an AllocSetContext with slow
+	 * growth rate --- we don't really expect much to be allocated in it.
+	 *
+	 * (There is special-case code in MemoryContextCreate() for this call.)
+	 */
+	TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
+											 "TopMemoryContext",
+											 8 * 1024,
+											 8 * 1024,
+											 8 * 1024);
+	/*
+	 * Not having any other place to point CurrentMemoryContext,
+	 * make it point to TopMemoryContext.  Caller should change this soon!
+	 */
+	CurrentMemoryContext = TopMemoryContext;
+	/*
+	 * Initialize ErrorContext as an AllocSetContext with slow
+	 * growth rate --- we don't really expect much to be allocated in it.
+	 * More to the point, require it to contain at least 8K at all times.
+	 * This is the only case where retained memory in a context is
+	 * *essential* --- we want to be sure ErrorContext still has some
+	 * memory even if we've run out elsewhere!
+	 */
+	ErrorContext = AllocSetContextCreate(TopMemoryContext,
+										 "ErrorContext",
+										 8 * 1024,
+										 8 * 1024,
+										 8 * 1024);
 }
 
 /*
- * MemoryContextAlloc
- *		Returns pointer to aligned allocated memory in the given context.
- *
- * Note:
- *		none
+ * MemoryContextReset
+ *		Release all space allocated within a context and its descendants,
+ *		but don't delete the contexts themselves.
  *
- * Exceptions:
- *		BadState if called before InitMemoryManager.
- *		BadArg if context is invalid or if size is 0.
- *		BadAllocSize if size is larger than MaxAllocSize.
+ * The type-specific reset routine handles the context itself, but we
+ * have to do the recursion for the children.
  */
-Pointer
-MemoryContextAlloc(MemoryContext context, Size size)
+void
+MemoryContextReset(MemoryContext context)
 {
-	AssertState(MemoryContextEnabled);
-	AssertArg(MemoryContextIsValid(context));
-
-	LogTrap(!AllocSizeIsValid(size), BadAllocSize,
-			("size=%d [0x%x]", size, size));
-
-	return context->method->alloc(context, size);
+	MemoryContextResetChildren(context);
+	(*context->methods->reset) (context);
 }
 
 /*
- * MemoryContextFree
- *		Frees allocated memory referenced by pointer in the given context.
- *
- * Note:
- *		none
- *
- * Exceptions:
- *		???
- *		BadArgumentsErr if firstTime is true for subsequent calls.
+ * MemoryContextResetChildren
+ *		Release all space allocated within a context's descendants,
+ *		but don't delete the contexts themselves.  The named context
+ *		itself is not touched.
  */
 void
-MemoryContextFree(MemoryContext context, Pointer pointer)
+MemoryContextResetChildren(MemoryContext context)
 {
-	AssertState(MemoryContextEnabled);
-	AssertArg(MemoryContextIsValid(context));
-	AssertArg(PointerIsValid(pointer));
+	MemoryContext	child;
 
-	context->method->free_p(context, pointer);
+	for (child = context->firstchild; child != NULL; child = child->nextchild)
+	{
+		MemoryContextReset(child);
+	}
 }
 
 /*
- * MemoryContextRelloc
- *		Returns pointer to aligned allocated memory in the given context.
+ * MemoryContextDelete
+ *		Delete a context and its descendants, and release all space
+ *		allocated therein.
  *
- * Note:
- *		none
- *
- * Exceptions:
- *		???
- *		BadArgumentsErr if firstTime is true for subsequent calls.
+ * The type-specific delete routine removes all subsidiary storage
+ * for the context, but we have to delete the context node itself,
+ * as well as recurse to get the children.  We must also delink the
+ * node from its parent, if it has one.
  */
-Pointer
-MemoryContextRealloc(MemoryContext context,
-					 Pointer pointer,
-					 Size size)
+void
+MemoryContextDelete(MemoryContext context)
 {
-	AssertState(MemoryContextEnabled);
-	AssertArg(MemoryContextIsValid(context));
-	AssertArg(PointerIsValid(pointer));
+	/* We had better not be deleting TopMemoryContext ... */
+	Assert(context != TopMemoryContext);
+	/* And not CurrentMemoryContext, either */
+	Assert(context != CurrentMemoryContext);
+
+	MemoryContextDeleteChildren(context);
+	/*
+	 * We delink the context from its parent before deleting it,
+	 * so that if there's an error we won't have deleted/busted
+	 * contexts still attached to the context tree.  Better a leak
+	 * than a crash.
+	 */
+	if (context->parent)
+	{
+		MemoryContext	parent = context->parent;
 
-	LogTrap(!AllocSizeIsValid(size), BadAllocSize,
-			("size=%d [0x%x]", size, size));
+		if (context == parent->firstchild)
+		{
+			parent->firstchild = context->nextchild;
+		}
+		else
+		{
+			MemoryContext	child;
 
-	return context->method->realloc(context, pointer, size);
+			for (child = parent->firstchild; child; child = child->nextchild)
+			{
+				if (context == child->nextchild)
+				{
+					child->nextchild = context->nextchild;
+					break;
+				}
+			}
+		}
+	}
+	(*context->methods->delete) (context);
+	pfree(context);
 }
 
 /*
- * MemoryContextGetName
- *		Returns pointer to aligned allocated memory in the given context.
- *
- * Note:
- *		none
- *
- * Exceptions:
- *		???
- *		BadArgumentsErr if firstTime is true for subsequent calls.
+ * MemoryContextDeleteChildren
+ *		Delete all the descendants of the named context and release all
+ *		space allocated therein.  The named context itself is not touched.
  */
-#ifdef NOT_USED
-char *
-MemoryContextGetName(MemoryContext context)
+void
+MemoryContextDeleteChildren(MemoryContext context)
 {
-	AssertState(MemoryContextEnabled);
-	AssertArg(MemoryContextIsValid(context));
-
-	return context->method->getName(context);
+	/*
+	 * MemoryContextDelete will delink the child from me,
+	 * so just iterate as long as there is a child.
+	 */
+	while (context->firstchild != NULL)
+	{
+		MemoryContextDelete(context->firstchild);
+	}
 }
 
-#endif
-
 /*
- * PointerGetAllocSize
- *		Returns size of aligned allocated memory given pointer to it.
+ * MemoryContextResetAndDeleteChildren
+ *		Release all space allocated within a context and delete all
+ *		its descendants.
  *
- * Note:
- *		none
- *
- * Exceptions:
- *		???
- *		BadArgumentsErr if firstTime is true for subsequent calls.
+ * This is a common combination case where we want to preserve the
+ * specific context but get rid of absolutely everything under it.
  */
-#ifdef NOT_USED
-Size
-PointerGetAllocSize(Pointer pointer)
+void
+MemoryContextResetAndDeleteChildren(MemoryContext context)
 {
-	AssertState(MemoryContextEnabled);
-	AssertArg(PointerIsValid(pointer));
-
-	return PSIZE(pointer);
+	MemoryContextDeleteChildren(context);
+	(*context->methods->reset) (context);
 }
 
-#endif
-
 /*
- * MemoryContextSwitchTo
- *		Returns the current context; installs the given context.
+ * MemoryContextStats
+ *		Print statistics about the named context and all its descendants.
  *
- * Note:
- *		none
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadArg if context is invalid.
+ * This is just a debugging utility, so it's not fancy.  The statistics
+ * are merely sent to stderr.
  */
-MemoryContext
-MemoryContextSwitchTo(MemoryContext context)
+void
+MemoryContextStats(MemoryContext context)
 {
-	MemoryContext old;
+	MemoryContext	child;
 
-	AssertState(MemoryContextEnabled);
-	AssertArg(MemoryContextIsValid(context));
-
-	old = CurrentMemoryContext;
-	CurrentMemoryContext = context;
-	return old;
+	(*context->methods->stats) (context);
+	for (child = context->firstchild; child != NULL; child = child->nextchild)
+	{
+		MemoryContextStats(child);
+	}
 }
 
 /*
- * External Functions
- */
-/*
- * CreateGlobalMemory
- *		Returns new global memory context.
- *
- * Note:
- *		Assumes name is static.
+ * MemoryContextContains
+ *		Detect whether an allocated chunk of memory belongs to a given
+ *		context or not.
  *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadState if called outside TopMemoryContext (TopGlobalMemory).
- *		BadArg if name is invalid.
+ * Caution: this test is reliable as long as 'pointer' does point to
+ * a chunk of memory allocated from *some* context.  If 'pointer' points
+ * at memory obtained in some other way, there is a small chance of a
+ * false-positive result, since the bits right before it might look like
+ * a valid chunk header by chance.
  */
-GlobalMemory
-CreateGlobalMemory(char *name)	/* XXX MemoryContextName */
+bool
+MemoryContextContains(MemoryContext context, void *pointer)
 {
-	GlobalMemory context;
-	MemoryContext savecxt;
-
-	AssertState(MemoryContextEnabled);
-
-	savecxt = MemoryContextSwitchTo(TopMemoryContext);
-
-	context = (GlobalMemory) newNode(sizeof(struct GlobalMemoryData), T_GlobalMemory);
-	context->method = &GlobalContextMethodsData;
-	context->name = name;		/* assumes name is static */
-	AllocSetInit(&context->setData, DynamicAllocMode, (Size) 0);
-
-	/* link the context */
-	OrderedElemPushInto(&context->elemData, ActiveGlobalMemorySet);
-
-	MemoryContextSwitchTo(savecxt);
-	return context;
+	StandardChunkHeader	   *header;
+
+	/*
+	 * Try to detect bogus pointers handed to us, poorly though we can.
+	 * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
+	 * an allocated chunk.
+	 */
+	if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
+		return false;
+	/*
+	 * OK, it's probably safe to look at the chunk header.
+	 */
+	header = (StandardChunkHeader *)
+		((char *) pointer - STANDARDCHUNKHEADERSIZE);
+	/*
+	 * If the context link doesn't match then we certainly have a
+	 * non-member chunk.  Also check for a reasonable-looking size
+	 * as extra guard against being fooled by bogus pointers.
+	 */
+	if (header->context == context && AllocSizeIsValid(header->size))
+		return true;
+	return false;
 }
 
-/*
- * GlobalMemoryDestroy
- *		Destroys given global memory context.
+/*--------------------
+ * MemoryContextCreate
+ *		Context-type-independent part of context creation.
+ *
+ * This is only intended to be called by context-type-specific
+ * context creation routines, not by the unwashed masses.
+ *
+ * The context creation procedure is a little bit tricky because
+ * we want to be sure that we don't leave the context tree invalid
+ * in case of failure (such as insufficient memory to allocate the
+ * context node itself).  The procedure goes like this:
+ *	1.	Context-type-specific routine first calls MemoryContextCreate(),
+ *		passing the appropriate tag/size/methods values (the methods
+ *		pointer will ordinarily point to statically allocated data).
+ *		The parent and name parameters usually come from the caller.
+ *	2.	MemoryContextCreate() attempts to allocate the context node,
+ *		plus space for the name.  If this fails we can elog() with no
+ *		damage done.
+ *	3.	We fill in all of the type-independent MemoryContext fields.
+ *	4.	We call the type-specific init routine (using the methods pointer).
+ *		The init routine is required to make the node minimally valid
+ *		with zero chance of failure --- it can't allocate more memory,
+ *		for example.
+ *	5.	Now we have a minimally valid node that can behave correctly
+ *		when told to reset or delete itself.  We link the node to its
+ *		parent (if any), making the node part of the context tree.
+ *	6.	We return to the context-type-specific routine, which finishes
+ *		up type-specific initialization.  This routine can now do things
+ *		that might fail (like allocate more memory), so long as it's
+ *		sure the node is left in a state that delete will handle.
+ *
+ * This protocol doesn't prevent us from leaking memory if step 6 fails
+ * during creation of a top-level context, since there's no parent link
+ * in that case.  However, if you run out of memory while you're building
+ * a top-level context, you might as well go home anyway...
  *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadState if called outside TopMemoryContext (TopGlobalMemory).
- *		BadArg if context is invalid GlobalMemory.
- *		BadArg if context is TopMemoryContext (TopGlobalMemory).
+ * Normally, the context node and the name are allocated from
+ * TopMemoryContext (NOT from the parent context, since the node must
+ * survive resets of its parent context!).  However, this routine is itself
+ * used to create TopMemoryContext!  If we see that TopMemoryContext is NULL,
+ * we assume we are creating TopMemoryContext and use malloc() to allocate
+ * the node.
+ *
+ * Note that the name field of a MemoryContext does not point to
+ * separately-allocated storage, so it should not be freed at context
+ * deletion.
+ *--------------------
  */
-void
-GlobalMemoryDestroy(GlobalMemory context)
+MemoryContext
+MemoryContextCreate(NodeTag tag, Size size,
+					MemoryContextMethods *methods,
+					MemoryContext parent,
+					const char *name)
 {
-	AssertState(MemoryContextEnabled);
-	AssertArg(IsA(context, GlobalMemory));
-	AssertArg(context != &TopGlobalMemoryData);
+	MemoryContext	node;
+	Size			needed = size + strlen(name) + 1;
 
-	AllocSetReset(&context->setData);
-
-	/* unlink and delete the context */
-	OrderedElemPop(&context->elemData);
-	MemoryContextFree(TopMemoryContext, (Pointer) context);
-}
+	/* Get space for node and name */
+	if (TopMemoryContext != NULL)
+	{
+		/* Normal case: allocate the node in TopMemoryContext */
+		node = (MemoryContext) MemoryContextAlloc(TopMemoryContext,
+												  needed);
+	}
+	else
+	{
+		/* Special case for startup: use good ol' malloc */
+		node = (MemoryContext) malloc(needed);
+		Assert(node != NULL);
+	}
 
-/*****************************************************************************
- *	  PRIVATE																 *
- *****************************************************************************/
+	/* Initialize the node as best we can */
+	MemSet(node, 0, size);
+	node->type = tag;
+	node->methods = methods;
+	node->parent = NULL;		/* for the moment */
+	node->firstchild = NULL;
+	node->nextchild = NULL;
+	node->name = ((char *) node) + size;
+	strcpy(node->name, name);
+
+	/* Type-specific routine finishes any other essential initialization */
+	(*node->methods->init) (node);
+
+	/* OK to link node to parent (if any) */
+	if (parent)
+	{
+		node->parent = parent;
+		node->nextchild = parent->firstchild;
+		parent->firstchild = node;
+	}
 
-/*
- * GlobalMemoryAlloc
- *		Returns pointer to aligned space in the global context.
- *
- * Exceptions:
- *		ExhaustedMemory if allocation fails.
- */
-static Pointer
-GlobalMemoryAlloc(GlobalMemory this, Size size)
-{
-	return AllocSetAlloc(&this->setData, size);
+	/* Return to type-specific creation routine to finish up */
+	return node;
 }
 
 /*
- * GlobalMemoryFree
- *		Frees allocated memory in the global context.
+ * MemoryContextAlloc
+ *		Allocate space within the specified context.
  *
- * Exceptions:
- *		BadContextErr if current context is not the global context.
- *		BadArgumentsErr if pointer is invalid.
+ * This could be turned into a macro, but we'd have to import
+ * nodes/memnodes.h into postgres.h which seems a bad idea.
  */
-static void
-GlobalMemoryFree(GlobalMemory this,
-				 Pointer pointer)
+void *
+MemoryContextAlloc(MemoryContext context, Size size)
 {
-	AllocSetFree(&this->setData, pointer);
-}
+	AssertArg(MemoryContextIsValid(context));
 
-/*
- * GlobalMemoryRealloc
- *		Returns pointer to aligned space in the global context.
- *
- * Note:
- *		Memory associated with the pointer is freed before return.
- *
- * Exceptions:
- *		BadContextErr if current context is not the global context.
- *		BadArgumentsErr if pointer is invalid.
- *		NoMoreMemoryErr if allocation fails.
- */
-static Pointer
-GlobalMemoryRealloc(GlobalMemory this,
-					Pointer pointer,
-					Size size)
-{
-	return AllocSetRealloc(&this->setData, pointer, size);
+	LogTrap(!AllocSizeIsValid(size), BadAllocSize,
+			("size=%d [0x%x]", size, size));
+
+	return (*context->methods->alloc) (context, size);
 }
 
 /*
- * GlobalMemoryGetName
- *		Returns name string for context.
- *
- * Exceptions:
- *		???
+ * pfree
+ *		Release an allocated chunk.
  */
-static char *
-GlobalMemoryGetName(GlobalMemory this)
+void
+pfree(void *pointer)
 {
-	return this->name;
+	StandardChunkHeader	   *header;
+
+	/*
+	 * Try to detect bogus pointers handed to us, poorly though we can.
+	 * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
+	 * an allocated chunk.
+	 */
+	Assert(pointer != NULL);
+	Assert(pointer == (void *) MAXALIGN(pointer));
+	/*
+	 * OK, it's probably safe to look at the chunk header.
+	 */
+	header = (StandardChunkHeader *)
+		((char *) pointer - STANDARDCHUNKHEADERSIZE);
+
+	AssertArg(MemoryContextIsValid(header->context));
+
+    (*header->context->methods->free_p) (header->context, pointer);
 }
 
 /*
- * GlobalMemoryDump
- *		Dumps global memory context for debugging.
+ * repalloc
  *
- * Exceptions:
- *		???
  */
-static void
-GlobalMemoryDump(GlobalMemory this)
+void *
+repalloc(void *pointer, Size size)
 {
-	GlobalMemory context;
-
-	printf("--\n%s:\n", GlobalMemoryGetName(this));
+	StandardChunkHeader	   *header;
+
+	/*
+	 * Try to detect bogus pointers handed to us, poorly though we can.
+	 * Presumably, a pointer that isn't MAXALIGNED isn't pointing at
+	 * an allocated chunk.
+	 */
+	Assert(pointer != NULL);
+	Assert(pointer == (void *) MAXALIGN(pointer));
+	/*
+	 * OK, it's probably safe to look at the chunk header.
+	 */
+	header = (StandardChunkHeader *)
+		((char *) pointer - STANDARDCHUNKHEADERSIZE);
+
+	AssertArg(MemoryContextIsValid(header->context));
 
-	context = (GlobalMemory) OrderedElemGetPredecessor(&this->elemData);
-	if (PointerIsValid(context))
-		printf("\tpredecessor=%s\n", GlobalMemoryGetName(context));
-
-	context = (GlobalMemory) OrderedElemGetSuccessor(&this->elemData);
-	if (PointerIsValid(context))
-		printf("\tsucessor=%s\n", GlobalMemoryGetName(context));
+	LogTrap(!AllocSizeIsValid(size), BadAllocSize,
+			("size=%d [0x%x]", size, size));
 
-	AllocSetDump(&this->setData);
+    return (*header->context->methods->realloc) (header->context,
+												 pointer, size);
 }
 
 /*
- * DumpGlobalMemories
- *		Dumps all global memory contexts for debugging.
- *
- * Exceptions:
- *		???
+ * MemoryContextSwitchTo
+ *		Returns the current context; installs the given context.
  */
-#ifdef NOT_USED
-static void
-DumpGlobalMemories()
+MemoryContext
+MemoryContextSwitchTo(MemoryContext context)
 {
-	GlobalMemory context;
-
-	context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
+	MemoryContext old;
 
-	while (PointerIsValid(context))
-	{
-		GlobalMemoryDump(context);
+	AssertArg(MemoryContextIsValid(context));
 
-		context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
-	}
+	old = CurrentMemoryContext;
+	CurrentMemoryContext = context;
+	return old;
 }
 
-#endif
-
 /*
- * GlobalMemoryStats
- *		Displays stats about memory consumption of all global contexts.
+ * MemoryContextStrdup
+ *		Like strdup(), but allocate from the specified context
  */
-void
-GlobalMemoryStats(void)
+char *
+MemoryContextStrdup(MemoryContext context, const char *string)
 {
-	GlobalMemory context;
+	char	   *nstr;
+	Size		len = strlen(string) + 1;
 
-	context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
+	nstr = (char *) MemoryContextAlloc(context, len);
 
-	while (PointerIsValid(context))
-	{
-		AllocSetStats(&context->setData, GlobalMemoryGetName(context));
-		context = (GlobalMemory) OrderedElemGetSuccessor(&context->elemData);
-	}
+	memcpy(nstr, string, len);
+
+	return nstr;
 }
diff --git a/src/backend/utils/mmgr/oset.c b/src/backend/utils/mmgr/oset.c
deleted file mode 100644
index 86487ab07d..0000000000
--- a/src/backend/utils/mmgr/oset.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * oset.c
- *	  Fixed format ordered set definitions.
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/oset.c,v 1.17 2000/04/12 17:16:10 momjian Exp $
- *
- * NOTE
- *	  XXX This is a preliminary implementation which lacks fail-fast
- *	  XXX validity checking of arguments.
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "utils/memutils.h"
-
-static Pointer OrderedElemGetBase(OrderedElem elem);
-static void OrderedElemPush(OrderedElem elem);
-static void OrderedElemPushHead(OrderedElem elem);
-
-/*
- * OrderedElemGetBase
- *		Returns base of enclosing structure.
- */
-static Pointer
-OrderedElemGetBase(OrderedElem elem)
-{
-	if (elem == (OrderedElem) NULL)
-		return (Pointer) NULL;
-
-	return (Pointer) ((char *) (elem) - (elem)->set->offset);
-}
-
-/*
- * OrderedSetInit
- */
-void
-OrderedSetInit(OrderedSet set, Offset offset)
-{
-	set->head = (OrderedElem) &set->dummy;
-	set->dummy = NULL;
-	set->tail = (OrderedElem) &set->head;
-	set->offset = offset;
-}
-
-/*
- * OrderedSetContains
- *		True iff ordered set contains given element.
- */
-#ifdef NOT_USED
-bool
-OrderedSetContains(OrderedSet set, OrderedElem elem)
-{
-	return (bool) (elem->set == set && (elem->next || elem->prev));
-}
-
-#endif
-
-/*
- * OrderedSetGetHead
- */
-Pointer
-OrderedSetGetHead(OrderedSet set)
-{
-	OrderedElem elem;
-
-	elem = set->head;
-	if (elem->next)
-		return OrderedElemGetBase(elem);
-	return NULL;
-}
-
-/*
- * OrderedSetGetTail
- */
-#ifdef NOT_USED
-Pointer
-OrderedSetGetTail(OrderedSet set)
-{
-	OrderedElem elem;
-
-	elem = set->tail;
-	if (elem->prev)
-		return OrderedElemGetBase(elem);
-	return NULL;
-}
-
-#endif
-
-/*
- * OrderedElemGetPredecessor
- */
-Pointer
-OrderedElemGetPredecessor(OrderedElem elem)
-{
-	elem = elem->prev;
-	if (elem->prev)
-		return OrderedElemGetBase(elem);
-	return NULL;
-}
-
-/*
- * OrderedElemGetSuccessor
- */
-Pointer
-OrderedElemGetSuccessor(OrderedElem elem)
-{
-	elem = elem->next;
-	if (elem->next)
-		return OrderedElemGetBase(elem);
-	return NULL;
-}
-
-/*
- * OrderedElemPop
- */
-void
-OrderedElemPop(OrderedElem elem)
-{
-	elem->next->prev = elem->prev;
-	elem->prev->next = elem->next;
-	/* assignments used only for error detection */
-	elem->next = NULL;
-	elem->prev = NULL;
-}
-
-/*
- * OrderedElemPushInto
- */
-void
-OrderedElemPushInto(OrderedElem elem, OrderedSet set)
-{
-	elem->set = set;
-	/* mark as unattached */
-	elem->next = NULL;
-	elem->prev = NULL;
-	OrderedElemPush(elem);
-}
-
-/*
- * OrderedElemPush
- */
-static void
-OrderedElemPush(OrderedElem elem)
-{
-	OrderedElemPushHead(elem);
-}
-
-/*
- * OrderedElemPushHead
- */
-static void
-OrderedElemPushHead(OrderedElem elem)
-{
-	elem->next = elem->set->head;
-	elem->prev = (OrderedElem) &elem->set->head;
-	elem->next->prev = elem;
-	elem->prev->next = elem;
-}
diff --git a/src/backend/utils/mmgr/palloc.c b/src/backend/utils/mmgr/palloc.c
deleted file mode 100644
index e714225be9..0000000000
--- a/src/backend/utils/mmgr/palloc.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * palloc.c
- *	  POSTGRES memory allocator code.
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.18 2000/05/30 00:49:57 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-
-
-#include "postgres.h"
-
-
-
-/* ----------------------------------------------------------------
- *		User library functions
- * ----------------------------------------------------------------
- */
-
-/* ----------
- * palloc(), pfree() and repalloc() are now macros in palloc.h
- * ----------
- */
-
-char *
-pstrdup(const char *string)
-{
-	char	   *nstr;
-	int			len;
-
-	nstr = palloc(len = strlen(string) + 1);
-	memcpy(nstr, string, len);
-
-	return nstr;
-}
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 71e94b7096..21aeb0a8a5 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.36 2000/04/12 17:16:10 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.37 2000/06/28 03:32:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,67 +40,28 @@
  *
  * struct PortalD {
  *		char*							name;
- *		classObj(PortalVariableMemory)	variable;
- *		classObj(PortalHeapMemory)		heap;
+ *		classObj(MemoryContext)			heap;
  *		List							queryDesc;
  *		EState							state;
  *		void							(*cleanup) ARGS((Portal portal));
  * };
  *
  *		I hope this makes things clearer to whoever reads this -cim 2/22/91
- *
- *		Here is an old comment taken from nodes/memnodes.h
- *
- * MemoryContext
- *		A logical context in which memory allocations occur.
- *
- * The types of memory contexts can be thought of as members of the
- * following inheritance hierarchy with properties summarized below.
- *
- *						Node
- *						|
- *				MemoryContext___
- *				/				\
- *		GlobalMemory	PortalMemoryContext
- *						/				\
- *		PortalVariableMemory	PortalHeapMemory
- *
- *						Flushed at		Flushed at		Checkpoints
- *						Transaction		Portal
- *						Commit			Close
- *
- * GlobalMemory					n				n				n
- * PortalVariableMemory			n				y				n
- * PortalHeapMemory				y				y				y *
- *
  */
 
 #include "postgres.h"
 
 #include "lib/hasht.h"
-#include "utils/module.h"
+#include "utils/memutils.h"
 #include "utils/portal.h"
 
 static void CollectNamedPortals(Portal *portalP, int destroy);
-static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
-static PortalVariableMemory PortalHeapMemoryGetVariableMemory(PortalHeapMemory context);
-static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
-
-/* ----------------
- *		ALLOCFREE_ERROR_ABORT
- *		define this if you want a core dump when you try to
- *		free memory already freed -cim 2/9/91
- * ----------------
- */
-#undef ALLOCFREE_ERROR_ABORT
 
 /* ----------------
  *		Global state
  * ----------------
  */
 
-static int	PortalManagerEnableCount = 0;
-
 #define MAX_PORTALNAME_LEN		64		/* XXX LONGALIGNable value */
 
 typedef struct portalhashent
@@ -109,8 +70,6 @@ typedef struct portalhashent
 	Portal		portal;
 } PortalHashEnt;
 
-#define PortalManagerEnabled	(PortalManagerEnableCount >= 1)
-
 static HTAB *PortalHashTable = NULL;
 
 #define PortalHashTableLookup(NAME, PORTAL) \
@@ -158,263 +117,13 @@ do { \
 		elog(NOTICE, "trying to delete portal name that does not exist."); \
 } while(0)
 
-static GlobalMemory PortalMemory = NULL;
-static char PortalMemoryName[] = "Portal";
-
-static Portal BlankPortal = NULL;
-
-/* ----------------
- *		Internal class definitions
- * ----------------
- */
-typedef struct HeapMemoryBlockData
-{
-	AllocSetData setData;
-	FixedItemData itemData;
-} HeapMemoryBlockData;
-
-typedef HeapMemoryBlockData *HeapMemoryBlock;
-
-#define HEAPMEMBLOCK(context) \
-	((HeapMemoryBlock)(context)->block)
-
-/* ----------------------------------------------------------------
- *				  Variable and heap memory methods
- * ----------------------------------------------------------------
- */
-/* ----------------
- *		PortalVariableMemoryAlloc
- * ----------------
- */
-static Pointer
-PortalVariableMemoryAlloc(PortalVariableMemory this,
-						  Size size)
-{
-	return AllocSetAlloc(&this->setData, size);
-}
-
-/* ----------------
- *		PortalVariableMemoryFree
- * ----------------
- */
-static void
-PortalVariableMemoryFree(PortalVariableMemory this,
-						 Pointer pointer)
-{
-	AllocSetFree(&this->setData, pointer);
-}
-
-/* ----------------
- *		PortalVariableMemoryRealloc
- * ----------------
- */
-static Pointer
-PortalVariableMemoryRealloc(PortalVariableMemory this,
-							Pointer pointer,
-							Size size)
-{
-	return AllocSetRealloc(&this->setData, pointer, size);
-}
-
-/* ----------------
- *		PortalVariableMemoryGetName
- * ----------------
- */
-static char *
-PortalVariableMemoryGetName(PortalVariableMemory this)
-{
-	return vararg_format("%s-var", PortalVariableMemoryGetPortal(this)->name);
-}
-
-/* ----------------
- *		PortalVariableMemoryDump
- * ----------------
- */
-static void
-PortalVariableMemoryDump(PortalVariableMemory this)
-{
-	printf("--\n%s:\n", PortalVariableMemoryGetName(this));
-
-	AllocSetDump(&this->setData);		/* XXX is this the right interface */
-}
-
-/* ----------------
- *		PortalHeapMemoryAlloc
- * ----------------
- */
-static Pointer
-PortalHeapMemoryAlloc(PortalHeapMemory this,
-					  Size size)
-{
-	HeapMemoryBlock block = HEAPMEMBLOCK(this);
-
-	AssertState(PointerIsValid(block));
-
-	return AllocSetAlloc(&block->setData, size);
-}
-
-/* ----------------
- *		PortalHeapMemoryFree
- * ----------------
- */
-static void
-PortalHeapMemoryFree(PortalHeapMemory this,
-					 Pointer pointer)
-{
-	HeapMemoryBlock block = HEAPMEMBLOCK(this);
-
-	AssertState(PointerIsValid(block));
-
-	if (AllocSetContains(&block->setData, pointer))
-		AllocSetFree(&block->setData, pointer);
-	else
-	{
-		elog(NOTICE,
-			 "PortalHeapMemoryFree: 0x%p not in alloc set!",
-			 pointer);
-#ifdef ALLOCFREE_ERROR_ABORT
-		Assert(AllocSetContains(&block->setData, pointer));
-#endif	 /* ALLOCFREE_ERROR_ABORT */
-	}
-}
-
-/* ----------------
- *		PortalHeapMemoryRealloc
- * ----------------
- */
-static Pointer
-PortalHeapMemoryRealloc(PortalHeapMemory this,
-						Pointer pointer,
-						Size size)
-{
-	HeapMemoryBlock block = HEAPMEMBLOCK(this);
-
-	AssertState(PointerIsValid(block));
-
-	return AllocSetRealloc(&block->setData, pointer, size);
-}
-
-/* ----------------
- *		PortalHeapMemoryGetName
- * ----------------
- */
-static char *
-PortalHeapMemoryGetName(PortalHeapMemory this)
-{
-	return vararg_format("%s-heap", PortalHeapMemoryGetPortal(this)->name);
-}
-
-/* ----------------
- *		PortalHeapMemoryDump
- * ----------------
- */
-static void
-PortalHeapMemoryDump(PortalHeapMemory this)
-{
-	HeapMemoryBlock block;
-
-	printf("--\n%s:\n", PortalHeapMemoryGetName(this));
-
-	/* XXX is this the right interface */
-	if (PointerIsValid(this->block))
-		AllocSetDump(&HEAPMEMBLOCK(this)->setData);
-
-	/* dump the stack too */
-	for (block = (HeapMemoryBlock) FixedStackGetTop(&this->stackData);
-		 PointerIsValid(block);
-		 block = (HeapMemoryBlock)
-		 FixedStackGetNext(&this->stackData, (Pointer) block))
-	{
-
-		printf("--\n");
-		AllocSetDump(&block->setData);
-	}
-}
-
-/* ----------------------------------------------------------------
- *				variable / heap context method tables
- * ----------------------------------------------------------------
- */
-static struct MemoryContextMethodsData PortalVariableContextMethodsData = {
-	PortalVariableMemoryAlloc,	/* Pointer (*)(this, uint32)	palloc */
-	PortalVariableMemoryFree,	/* void (*)(this, Pointer)		pfree */
-	PortalVariableMemoryRealloc,/* Pointer (*)(this, Pointer)	repalloc */
-	PortalVariableMemoryGetName,/* char* (*)(this)				getName */
-	PortalVariableMemoryDump	/* void (*)(this)				dump */
-};
-
-static struct MemoryContextMethodsData PortalHeapContextMethodsData = {
-	PortalHeapMemoryAlloc,		/* Pointer (*)(this, uint32)	palloc */
-	PortalHeapMemoryFree,		/* void (*)(this, Pointer)		pfree */
-	PortalHeapMemoryRealloc,	/* Pointer (*)(this, Pointer)	repalloc */
-	PortalHeapMemoryGetName,	/* char* (*)(this)				getName */
-	PortalHeapMemoryDump		/* void (*)(this)				dump */
-};
+static MemoryContext PortalMemory = NULL;
 
 
 /* ----------------------------------------------------------------
  *				  private internal support routines
  * ----------------------------------------------------------------
  */
-/* ----------------
- *		CreateNewBlankPortal
- * ----------------
- */
-static void
-CreateNewBlankPortal()
-{
-	Portal		portal;
-
-	AssertState(!PortalIsValid(BlankPortal));
-
-	/*
-	 * make new portal structure
-	 */
-	portal = (Portal)
-		MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
-
-	/*
-	 * initialize portal variable context
-	 */
-	NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
-	AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
-	portal->variable.method = &PortalVariableContextMethodsData;
-
-	/*
-	 * initialize portal heap context
-	 */
-	NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
-	portal->heap.block = NULL;
-	FixedStackInit(&portal->heap.stackData,
-				   offsetof(HeapMemoryBlockData, itemData));
-	portal->heap.method = &PortalHeapContextMethodsData;
-
-	/*
-	 * set bogus portal name
-	 */
-	portal->name = "** Blank Portal **";
-
-	/* initialize portal query */
-	portal->queryDesc = NULL;
-	portal->attinfo = NULL;
-	portal->state = NULL;
-	portal->cleanup = NULL;
-
-	/*
-	 * install blank portal
-	 */
-	BlankPortal = portal;
-}
-
-bool
-PortalNameIsSpecial(char *pname)
-{
-	if (strcmp(pname, VACPNAME) == 0)
-		return true;
-	if (strcmp(pname, TRUNCPNAME) == 0)
-		return true;
-	return false;
-}
 
 /*
  * This routine is used to collect all portals created in this xaction
@@ -447,12 +156,6 @@ CollectNamedPortals(Portal *portalP, int destroy)
 		Assert(portalP);
 		Assert(*portalP);
 
-		/*
-		 * Don't delete special portals, up to portal creator to do this
-		 */
-		if (PortalNameIsSpecial((*portalP)->name))
-			return;
-
 		portalList[listIndex] = *portalP;
 		listIndex++;
 		if (listIndex == maxIndex)
@@ -472,179 +175,50 @@ AtEOXact_portals()
 	CollectNamedPortals(NULL, 1);
 }
 
-/* ----------------
- *		PortalDump
- * ----------------
- */
-#ifdef NOT_USED
-static void
-PortalDump(Portal *thisP, int dummy)
-{
-	/* XXX state/argument checking here */
-
-	PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
-	PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
-}
-
-#endif
-
-/* ----------------
- *		DumpPortals
- * ----------------
- */
-#ifdef NOT_USED
-static void
-DumpPortals()
-{
-	/* XXX state checking here */
-
-	HashTableWalk(PortalHashTable, (HashtFunc) PortalDump, 0);
-}
-
-#endif
-
 /* ----------------------------------------------------------------
  *				   public portal interface functions
  * ----------------------------------------------------------------
  */
 /*
  * EnablePortalManager
- *		Enables/disables the portal management module.
+ *		Enables the portal management module at backend startup.
  */
 void
-EnablePortalManager(bool on)
+EnablePortalManager(void)
 {
-	static bool processing = false;
 	HASHCTL		ctl;
 
-	AssertState(!processing);
-	AssertArg(BoolIsValid(on));
-
-	if (BypassEnable(&PortalManagerEnableCount, on))
-		return;
-
-	processing = true;
-
-	if (on)
-	{							/* initialize */
-		EnableMemoryContext(true);
-
-		PortalMemory = CreateGlobalMemory(PortalMemoryName);
-
-		ctl.keysize = MAX_PORTALNAME_LEN;
-		ctl.datasize = sizeof(Portal);
-
-		/*
-		 * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
-		 * how many hash table entries to create, initially
-		 */
-		PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
-
-		CreateNewBlankPortal();
-
-	}
-	else
-	{							/* cleanup */
-		if (PortalIsValid(BlankPortal))
-		{
-			PortalDrop(&BlankPortal);
-			MemoryContextFree((MemoryContext) PortalMemory,
-							  (Pointer) BlankPortal);
-			BlankPortal = NULL;
-		}
-
-		/*
-		 * Each portal must free its non-memory resources specially.
-		 */
-		HashTableWalk(PortalHashTable, (HashtFunc) PortalDrop, 0);
-		hash_destroy(PortalHashTable);
-		PortalHashTable = NULL;
+	Assert(PortalMemory == NULL);
 
-		GlobalMemoryDestroy(PortalMemory);
-		PortalMemory = NULL;
+	PortalMemory = AllocSetContextCreate(TopMemoryContext,
+										 "PortalMemory",
+										 ALLOCSET_DEFAULT_MINSIZE,
+										 ALLOCSET_DEFAULT_INITSIZE,
+										 ALLOCSET_DEFAULT_MAXSIZE);
 
-		EnableMemoryContext(true);
-	}
+	ctl.keysize = MAX_PORTALNAME_LEN;
+	ctl.datasize = sizeof(Portal);
 
-	processing = false;
+	/*
+	 * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
+	 * how many hash table entries to create, initially
+	 */
+	PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
 }
 
 /*
  * GetPortalByName
- *		Returns a portal given a portal name; returns blank portal given
- * NULL; returns invalid portal if portal not found.
- *
- * Exceptions:
- *		BadState if called when disabled.
+ *		Returns a portal given a portal name, or NULL if name not found.
  */
 Portal
 GetPortalByName(char *name)
 {
 	Portal		portal;
 
-	AssertState(PortalManagerEnabled);
-
 	if (PointerIsValid(name))
 		PortalHashTableLookup(name, portal);
 	else
-	{
-		if (!PortalIsValid(BlankPortal))
-			CreateNewBlankPortal();
-		portal = BlankPortal;
-	}
-
-	return portal;
-}
-
-/*
- * BlankPortalAssignName
- *		Returns former blank portal as portal with given name.
- *
- * Side effect:
- *		All references to the former blank portal become incorrect.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadState if called without an intervening call to GetPortalByName(NULL).
- *		BadArg if portal name is invalid.
- *		"WARN" if portal name is in use.
- */
-Portal
-BlankPortalAssignName(char *name)		/* XXX PortalName */
-{
-	Portal		portal;
-	uint16		length;
-
-	AssertState(PortalManagerEnabled);
-	AssertState(PortalIsValid(BlankPortal));
-	AssertArg(PointerIsValid(name));	/* XXX PortalName */
-
-	portal = GetPortalByName(name);
-	if (PortalIsValid(portal))
-	{
-		elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
-		return portal;
-	}
-
-	/*
-	 * remove blank portal
-	 */
-	portal = BlankPortal;
-	BlankPortal = NULL;
-
-	/*
-	 * initialize portal name
-	 */
-	length = 1 + strlen(name);
-	portal->name = (char *)
-		MemoryContextAlloc((MemoryContext) &portal->variable, length);
-
-	strncpy(portal->name, name, length);
-
-	/*
-	 * put portal in table
-	 */
-	PortalHashTableInsert(portal);
+		portal = NULL;
 
 	return portal;
 }
@@ -666,7 +240,6 @@ PortalSetQuery(Portal portal,
 			   EState *state,
 			   void (*cleanup) (Portal portal))
 {
-	AssertState(PortalManagerEnabled);
 	AssertArg(PortalIsValid(portal));
 	AssertArg(IsA((Node *) state, EState));
 
@@ -687,7 +260,6 @@ PortalSetQuery(Portal portal,
 QueryDesc  *
 PortalGetQueryDesc(Portal portal)
 {
-	AssertState(PortalManagerEnabled);
 	AssertArg(PortalIsValid(portal));
 
 	return portal->queryDesc;
@@ -704,7 +276,6 @@ PortalGetQueryDesc(Portal portal)
 EState *
 PortalGetState(Portal portal)
 {
-	AssertState(PortalManagerEnabled);
 	AssertArg(PortalIsValid(portal));
 
 	return portal->state;
@@ -714,63 +285,48 @@ PortalGetState(Portal portal)
  * CreatePortal
  *		Returns a new portal given a name.
  *
- * Note:
- *		This is expected to be of very limited usability.  See instead,
- * BlankPortalAssignName.
- *
  * Exceptions:
  *		BadState if called when disabled.
  *		BadArg if portal name is invalid.
- *		"WARN" if portal name is in use.
+ *		"NOTICE" if portal name is in use (existing portal is returned!)
  */
 Portal
-CreatePortal(char *name)		/* XXX PortalName */
+CreatePortal(char *name)
 {
 	Portal		portal;
-	uint16		length;
 
-	AssertState(PortalManagerEnabled);
-	AssertArg(PointerIsValid(name));	/* XXX PortalName */
+	AssertArg(PointerIsValid(name));
 
 	portal = GetPortalByName(name);
 	if (PortalIsValid(portal))
 	{
-		elog(NOTICE, "CreatePortal: portal %s already exists", name);
+		elog(NOTICE, "CreatePortal: portal \"%s\" already exists", name);
 		return portal;
 	}
 
 	/* make new portal structure */
-	portal = (Portal)
-		MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
+	portal = (Portal) MemoryContextAlloc(PortalMemory, sizeof *portal);
 
-	/* initialize portal variable context */
-	NodeSetTag((Node *) &portal->variable, T_PortalVariableMemory);
-	AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
-	portal->variable.method = &PortalVariableContextMethodsData;
+	/* initialize portal name */
+	portal->name = MemoryContextStrdup(PortalMemory, name);
 
 	/* initialize portal heap context */
-	NodeSetTag((Node *) &portal->heap, T_PortalHeapMemory);
-	portal->heap.block = NULL;
-	FixedStackInit(&portal->heap.stackData,
-				   offsetof(HeapMemoryBlockData, itemData));
-	portal->heap.method = &PortalHeapContextMethodsData;
-
-	/* initialize portal name */
-	length = 1 + strlen(name);
-	portal->name = (char *)
-		MemoryContextAlloc((MemoryContext) &portal->variable, length);
-	strncpy(portal->name, name, length);
+	portal->heap = AllocSetContextCreate(PortalMemory,
+										 "PortalHeapMemory",
+										 ALLOCSET_DEFAULT_MINSIZE,
+										 ALLOCSET_DEFAULT_INITSIZE,
+										 ALLOCSET_DEFAULT_MAXSIZE);
 
 	/* initialize portal query */
 	portal->queryDesc = NULL;
 	portal->attinfo = NULL;
 	portal->state = NULL;
+
 	portal->cleanup = NULL;
 
 	/* put portal in table */
 	PortalHashTableInsert(portal);
 
-	/* Trap(PointerIsValid(name), Unimplemented); */
 	return portal;
 }
 
@@ -787,240 +343,29 @@ PortalDrop(Portal *portalP)
 {
 	Portal		portal = *portalP;
 
-	AssertState(PortalManagerEnabled);
 	AssertArg(PortalIsValid(portal));
 
-	/* remove portal from table if not blank portal */
-	if (portal != BlankPortal)
-		PortalHashTableDelete(portal);
+	/* remove portal from hash table */
+	PortalHashTableDelete(portal);
 
 	/* reset portal */
 	if (PointerIsValid(portal->cleanup))
 		(*portal->cleanup) (portal);
 
-	PortalResetHeapMemory(portal);
-	MemoryContextFree((MemoryContext) &portal->variable,
-					  (Pointer) portal->name);
-	AllocSetReset(&portal->variable.setData);	/* XXX log */
-
-	/*
-	 * In the case of a transaction abort it is possible that we get
-	 * called while one of the memory contexts of the portal we're
-	 * destroying is the current memory context.
-	 *
-	 * Don't know how to handle that cleanly because it is required to be in
-	 * that context right now. This portal struct remains allocated in the
-	 * PortalMemory context until backend dies.
-	 *
-	 * Not happy with that, but it's better to loose some bytes of memory
-	 * than to have the backend dump core.
-	 *
-	 * --- Feb. 04, 1999 Jan Wieck
-	 */
-	if (CurrentMemoryContext == (MemoryContext) PortalGetHeapMemory(portal))
-		return;
-	if (CurrentMemoryContext == (MemoryContext) PortalGetVariableMemory(portal))
-		return;
-
-	if (portal != BlankPortal)
-		MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
-}
-
-/* ----------------
- *		PortalResetHeapMemory
- *				Resets portal's heap memory context.
- *
- * Someday, Reset, Start, and End can be optimized by keeping a global
- * portal module stack of free HeapMemoryBlock's.  This will make Start
- * and End be fast.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadState if called when not in PortalHeapMemory context.
- *		BadArg if mode is invalid.
- * ----------------
- */
-void
-PortalResetHeapMemory(Portal portal)
-{
-	PortalHeapMemory context;
-	MemoryContext currentContext;
-
-	context = PortalGetHeapMemory(portal);
-
-	if (PointerIsValid(context->block))
-	{
-		/* save present context */
-		currentContext = MemoryContextSwitchTo((MemoryContext) context);
-
-		do
-		{
-			EndPortalAllocMode();
-		} while (PointerIsValid(context->block));
-
-		/* restore context */
-		MemoryContextSwitchTo(currentContext);
-	}
-}
-
-/*
- * StartPortalAllocMode
- *		Starts a new block of portal heap allocation using mode and limit;
- *		the current block is disabled until EndPortalAllocMode is called.
- *
- * Note:
- *		Note blocks may be stacked and restored arbitarily.
- *		The semantics of mode and limit are described in aset.h.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadState if called when not in PortalHeapMemory context.
- *		BadArg if mode is invalid.
- */
-void
-StartPortalAllocMode(AllocMode mode, Size limit)
-{
-	PortalHeapMemory context;
-
-	AssertState(PortalManagerEnabled);
-	AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
-	/* AssertArg(AllocModeIsValid); */
-
-	context = (PortalHeapMemory) CurrentMemoryContext;
-
-	/* stack current mode */
-	if (PointerIsValid(context->block))
-		FixedStackPush(&context->stackData, context->block);
-
-	/* allocate and initialize new block */
-	context->block = MemoryContextAlloc(
-			  (MemoryContext) PortalHeapMemoryGetVariableMemory(context),
-										sizeof(HeapMemoryBlockData));
-
-	/* XXX careful, context->block has never been stacked => bad state */
-
-	AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
-}
-
-/*
- * EndPortalAllocMode
- *		Ends current block of portal heap allocation; previous block is
- *		reenabled.
- *
- * Note:
- *		Note blocks may be stacked and restored arbitarily.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadState if called when not in PortalHeapMemory context.
- */
-void
-EndPortalAllocMode()
-{
-	PortalHeapMemory context;
+	/* release subsidiary storage */
+	MemoryContextDelete(PortalGetHeapMemory(portal));
 
-	AssertState(PortalManagerEnabled);
-	AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
-
-	context = (PortalHeapMemory) CurrentMemoryContext;
-	AssertState(PointerIsValid(context->block));		/* XXX Trap(...) */
-
-	/* free current mode */
-	AllocSetReset(&HEAPMEMBLOCK(context)->setData);
-	MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
-					  context->block);
-
-	/* restore previous mode */
-	context->block = FixedStackPop(&context->stackData);
-}
-
-/*
- * PortalGetVariableMemory
- *		Returns variable memory context for a given portal.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadArg if portal is invalid.
- */
-PortalVariableMemory
-PortalGetVariableMemory(Portal portal)
-{
-	return &portal->variable;
+	/* release name and portal data (both are in PortalMemory) */
+	pfree(portal->name);
+	pfree(portal);
 }
 
 /*
  * PortalGetHeapMemory
  *		Returns heap memory context for a given portal.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadArg if portal is invalid.
  */
-PortalHeapMemory
+MemoryContext
 PortalGetHeapMemory(Portal portal)
 {
-	return &portal->heap;
-}
-
-/*
- * PortalVariableMemoryGetPortal
- *		Returns portal containing given variable memory context.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadArg if context is invalid.
- */
-static Portal
-PortalVariableMemoryGetPortal(PortalVariableMemory context)
-{
-	return (Portal) ((char *) context - offsetof(PortalD, variable));
-}
-
-/*
- * PortalHeapMemoryGetPortal
- *		Returns portal containing given heap memory context.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadArg if context is invalid.
- */
-static Portal
-PortalHeapMemoryGetPortal(PortalHeapMemory context)
-{
-	return (Portal) ((char *) context - offsetof(PortalD, heap));
-}
-
-/*
- * PortalVariableMemoryGetHeapMemory
- *		Returns heap memory context associated with given variable memory.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadArg if context is invalid.
- */
-#ifdef NOT_USED
-PortalHeapMemory
-PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
-{
-	return ((PortalHeapMemory) ((char *) context
-								- offsetof(PortalD, variable)
-								+offsetof(PortalD, heap)));
-}
-
-#endif
-
-/*
- * PortalHeapMemoryGetVariableMemory
- *		Returns variable memory context associated with given heap memory.
- *
- * Exceptions:
- *		BadState if called when disabled.
- *		BadArg if context is invalid.
- */
-static PortalVariableMemory
-PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
-{
-	return ((PortalVariableMemory) ((char *) context
-									- offsetof(PortalD, heap)
-									+offsetof(PortalD, variable)));
+	return portal->heap;
 }
diff --git a/src/include/commands/command.h b/src/include/commands/command.h
index b68ec2de5d..8cb31889fa 100644
--- a/src/include/commands/command.h
+++ b/src/include/commands/command.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: command.h,v 1.18 2000/04/12 17:16:31 momjian Exp $
+ * $Id: command.h,v 1.19 2000/06/28 03:32:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,7 +16,6 @@
 
 #include "utils/portal.h"
 
-extern MemoryContext PortalExecutorHeapMemory;
 
 /*
  * PerformPortalFetch
diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h
index 6b505cecdf..285bb314d3 100644
--- a/src/include/executor/hashjoin.h
+++ b/src/include/executor/hashjoin.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: hashjoin.h,v 1.16 2000/01/26 05:58:05 momjian Exp $
+ * $Id: hashjoin.h,v 1.17 2000/06/28 03:33:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,20 +22,19 @@
  *
  * Each active hashjoin has a HashJoinTable control block which is
  * palloc'd in the executor's context.	All other storage needed for
- * the hashjoin is kept in a private "named portal", one for each hashjoin.
+ * the hashjoin is kept in private memory contexts, two for each hashjoin.
  * This makes it easy and fast to release the storage when we don't need it
  * anymore.
  *
- * The portal manager guarantees that portals will be discarded at end of
- * transaction, so we have no problem with a memory leak if the join is
+ * The contexts are made children of TransactionCommandContext, ensuring
+ * that they will be discarded at end of statement even if the join is
  * aborted early by an error.  (Likewise, any temporary files we make will
  * be cleaned up by the virtual file manager in event of an error.)
  *
  * Storage that should live through the entire join is allocated from the
- * portal's "variable context", while storage that is only wanted for the
- * current batch is allocated in the portal's "heap context".  By popping
- * the portal's heap at the end of a batch, we free all the per-batch storage
- * reliably and without tedium.
+ * "hashCxt", while storage that is only wanted for the current batch is
+ * allocated in the "batchCxt".  By resetting the batchCxt at the end of
+ * each batch, we free all the per-batch storage reliably and without tedium.
  * ----------------------------------------------------------------
  */
 
@@ -80,15 +79,6 @@ typedef struct HashTableData
 	 * to hash buckets and output.
 	 */
 
-	/*
-	 * Ugly kluge: myPortal ought to be declared as type Portal (ie,
-	 * PortalD*) but if we try to include utils/portal.h here, we end up
-	 * with a circular dependency of include files!  Until the various
-	 * node.h files are restructured in a cleaner way, we have to fake it.
-	 * The most reliable fake seems to be to declare myPortal as void *
-	 * and then cast it to the right things in nodeHash.c.
-	 */
-	void	   *myPortal;		/* where to keep working storage */
 	MemoryContext hashCxt;		/* context for whole-hash-join storage */
 	MemoryContext batchCxt;		/* context for this-batch-only storage */
 } HashTableData;
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index 1c1e75876d..2db0c5d577 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -28,7 +28,6 @@
 #include "utils/fcache.h"
 #include "utils/datum.h"
 #include "utils/syscache.h"
-#include "utils/portal.h"
 #include "utils/builtins.h"
 #include "catalog/pg_language.h"
 #include "access/heapam.h"
@@ -95,4 +94,6 @@ extern void *SPI_repalloc(void *pointer, Size size);
 extern void SPI_pfree(void *pointer);
 extern void SPI_freetuple(HeapTuple pointer);
 
+extern void AtEOXact_SPI(void);
+
 #endif	 /* SPI_H */
diff --git a/src/include/executor/spi_priv.h b/src/include/executor/spi_priv.h
index 916d7141d2..00b28a5803 100644
--- a/src/include/executor/spi_priv.h
+++ b/src/include/executor/spi_priv.h
@@ -3,7 +3,7 @@
  * spi.c
  *				Server Programming Interface private declarations
  *
- * $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.6 1999/07/15 15:21:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/include/executor/spi_priv.h,v 1.7 2000/06/28 03:33:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,8 @@ typedef struct
 	List	   *qtlist;
 	uint32		processed;		/* by Executor */
 	SPITupleTable *tuptable;
-	Portal		portal;			/* portal per procedure */
+	MemoryContext procCxt;		/* procedure context */
+	MemoryContext execCxt;		/* executor context */
 	MemoryContext savedcxt;
 	CommandId	savedId;
 } _SPI_connection;
diff --git a/src/include/lib/fstack.h b/src/include/lib/fstack.h
deleted file mode 100644
index d639a224fc..0000000000
--- a/src/include/lib/fstack.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * fstack.h
- *	  Fixed format stack definitions.
- *
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: fstack.h,v 1.9 2000/01/26 05:58:09 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-/*
- * Note:
- *		Fixed format stacks assist in the construction of FIFO stacks of
- *		fixed format structures.  Structures which are to be stackable
- *		should contain a FixedItemData component.  A stack is initilized
- *		with the offset of the FixedItemData component of the structure
- *		it will hold.  By doing so, push and pop operations are simplified
- *		for the callers.  All references to stackable items are pointers
- *		to the base of the structure instead of pointers to the
- *		FixedItemData component.
- *
- */
-#ifndef FSTACK_H
-#define FSTACK_H
-
-
-/*
- * FixedItem
- *		Fixed format stackable item chain component.
- *
- * Note:
- *		Structures must contain one FixedItemData component per stack in
- *		which it will be an item.
- */
-typedef struct FixedItemData FixedItemData;
-typedef FixedItemData *FixedItem;
-
-struct FixedItemData
-{
-	FixedItem	next;			/* next item or NULL */
-};
-
-/*
- * FixedStack
- *		Fixed format stack.
- */
-typedef struct FixedStackData
-{
-	FixedItem	top;			/* Top item on the stack or NULL */
-	Offset		offset;			/* Offset from struct base to item */
-	/* this could be signed short int! */
-} FixedStackData;
-
-typedef FixedStackData *FixedStack;
-
-/*
- * FixedStackInit
- *		Iniitializes stack for structures with given fixed component offset.
- *
- * Exceptions:
- *		BadArg if stack is invalid pointer.
- */
-extern void FixedStackInit(FixedStack stack, Offset offset);
-
-/*
- * FixedStackPop
- *		Returns pointer to top structure on stack or NULL if empty stack.
- *
- * Exceptions:
- *		BadArg if stack is invalid.
- */
-Pointer		FixedStackPop(FixedStack stack);
-
-/*
- * FixedStackPush
- *		Places structure associated with pointer onto top of stack.
- *
- * Exceptions:
- *		BadArg if stack is invalid.
- *		BadArg if pointer is invalid.
- */
-extern void FixedStackPush(FixedStack stack, Pointer pointer);
-
-/*
- * FixedStackGetTop
- *		Returns pointer to top structure of a stack.  This item is not poped.
- *
- * Note:
- *		This is not part of the normal stack interface.  It is intended for
- *		 debugging use only.
- *
- * Exceptions:
- *		BadArg if stack is invalid.
- */
-extern Pointer FixedStackGetTop(FixedStack stack);
-
-/*
- * FixedStackGetNext
- *		Returns pointer to next structure after pointer of a stack.
- *
- * Note:
- *		This is not part of the normal stack interface.  It is intended for
- *		 debugging use only.
- *
- * Exceptions:
- *		BadArg if stack is invalid.
- *		BadArg if pointer is invalid.
- *		BadArg if stack does not contain pointer.
- */
-extern Pointer FixedStackGetNext(FixedStack stack, Pointer pointer);
-
-#endif	 /* FSTACK_H */
diff --git a/src/include/libpq/pqsignal.h b/src/include/libpq/pqsignal.h
index 4ee039c0fe..4a81af04eb 100644
--- a/src/include/libpq/pqsignal.h
+++ b/src/include/libpq/pqsignal.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pqsignal.h,v 1.13 2000/06/15 00:52:11 momjian Exp $
+ * $Id: pqsignal.h,v 1.14 2000/06/28 03:33:14 tgl Exp $
  *
  * NOTES
  *	  This shouldn't be in libpq, but the monitor and some other
@@ -24,28 +24,18 @@
 extern sigset_t UnBlockSig,
 			BlockSig;
 
-#define PG_INITMASK()	( \
-							sigemptyset(&UnBlockSig), \
-							sigfillset(&BlockSig) \
-						)
 #define PG_SETMASK(mask)	sigprocmask(SIG_SETMASK, mask, NULL)
 #else
 extern int	UnBlockSig,
 			BlockSig;
 
-#define PG_INITMASK()	( \
-							UnBlockSig = 0, \
-							BlockSig = sigmask(SIGHUP) | sigmask(SIGQUIT) | \
-										sigmask(SIGTERM) | sigmask(SIGALRM) | \
-										sigmask(SIGINT) | sigmask(SIGUSR1) | \
-										sigmask(SIGUSR2) | sigmask(SIGCHLD) | \
-										sigmask(SIGWINCH) | sigmask(SIGFPE) \
-						)
 #define PG_SETMASK(mask)	sigsetmask(*((int*)(mask)))
 #endif
 
 typedef void (*pqsigfunc) (int);
 
+extern void pqinitmask(void);
+
 extern pqsigfunc pqsignal(int signo, pqsigfunc func);
 
 #endif	 /* PQSIGNAL_H */
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index b3aa67250f..e6b8309aac 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: miscadmin.h,v 1.60 2000/06/15 00:52:04 momjian Exp $
+ * $Id: miscadmin.h,v 1.61 2000/06/28 03:32:56 tgl Exp $
  *
  * NOTES
  *	  some of the information in this file will be moved to
@@ -105,8 +105,6 @@ extern bool enableFsync;
 extern bool allowSystemTableMods;
 extern int	SortMem;
 
-extern Oid	LastOidProcessed;	/* for query rewrite */
-
 /* a few postmaster startup options are exported here so the
    configuration file processor has access to them */
 
@@ -189,9 +187,10 @@ typedef int16 ExitStatus;
 
 /* in utils/init/postinit.c */
 
-extern bool PostgresIsInitialized;
+extern int	lockingOff;
 
 extern void InitPostgres(const char *dbname);
+extern void BaseInit(void);
 
 /* one of the ways to get out of here */
 #define ExitPostgres(status) proc_exec(status)
diff --git a/src/include/nodes/memnodes.h b/src/include/nodes/memnodes.h
index 08ba967318..abc38e5c60 100644
--- a/src/include/nodes/memnodes.h
+++ b/src/include/nodes/memnodes.h
@@ -7,100 +7,88 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: memnodes.h,v 1.16 2000/01/26 05:58:16 momjian Exp $
+ * $Id: memnodes.h,v 1.17 2000/06/28 03:33:15 tgl Exp $
  *
- * XXX the typedefs in this file are different from the other ???nodes.h;
- *	  they are pointers to structures instead of the structures themselves.
- *	  If you're wondering, this is plain laziness. I don't want to touch
- *	  the memory context code which should be revamped altogether some day.
- *														- ay 10/94
  *-------------------------------------------------------------------------
  */
 #ifndef MEMNODES_H
 #define MEMNODES_H
 
-#include "lib/fstack.h"
 #include "nodes/nodes.h"
-#include "utils/memutils.h"
 
 /*
  * MemoryContext
  *		A logical context in which memory allocations occur.
  *
- * The types of memory contexts can be thought of as members of the
- * following inheritance hierarchy with properties summarized below.
+ * MemoryContext itself is an abstract type that can have multiple
+ * implementations, though for now we have only AllocSetContext.
+ * The function pointers in MemoryContextMethods define one specific
+ * implementation of MemoryContext --- they are a virtual function table
+ * in C++ terms.
  *
- *						Node
- *						|
- *				MemoryContext___
- *				/				\
- *		GlobalMemory	PortalMemoryContext
- *						/				\
- *		PortalVariableMemory	PortalHeapMemory
+ * Node types that are actual implementations of memory contexts must
+ * begin with the same fields as MemoryContext.
  *
- *						Flushed at		Flushed at		Checkpoints
- *						Transaction		Portal
- *						Commit			Close
- *
- * GlobalMemory					n				n				n
- * PortalVariableMemory			n				y				n
- * PortalHeapMemory				y				y				y
+ * Note: for largely historical reasons, typedef MemoryContext is a pointer
+ * to the context struct rather than the struct type itself.
  */
 
-typedef struct MemoryContextMethodsData
+typedef struct MemoryContextMethods
 {
-	Pointer		(*alloc) ();
-	void		(*free_p) ();	/* need to use free as a #define, so can't
-								 * use free */
-	Pointer		(*realloc) ();
-	char	   *(*getName) ();
-	void		(*dump) ();
-}		   *MemoryContextMethods;
+	void	   *(*alloc) (MemoryContext context, Size size);
+	/* call this free_p in case someone #define's free() */
+	void		(*free_p) (MemoryContext context, void *pointer);
+	void	   *(*realloc) (MemoryContext context, void *pointer, Size size);
+	void		(*init) (MemoryContext context);
+	void		(*reset) (MemoryContext context);
+	void		(*delete) (MemoryContext context);
+	void		(*stats) (MemoryContext context);
+} MemoryContextMethods;
+
 
 typedef struct MemoryContextData
 {
-	NodeTag		type;
-	MemoryContextMethods method;
+	NodeTag		type;				/* identifies exact kind of context */
+	MemoryContextMethods *methods;	/* virtual function table */
+	MemoryContext parent;			/* NULL if no parent (toplevel context) */
+	MemoryContext firstchild;		/* head of linked list of children */
+	MemoryContext nextchild;		/* next child of same parent */
+	char	   *name;				/* context name (just for debugging) */
 } MemoryContextData;
 
-/* utils/mcxt.h contains typedef struct MemoryContextData *MemoryContext */
+/* utils/palloc.h contains typedef struct MemoryContextData *MemoryContext */
 
-/* think about doing this right some time but we'll have explicit fields
-   for now -ay 10/94 */
-typedef struct GlobalMemoryData
-{
-	NodeTag		type;
-	MemoryContextMethods method;
-	AllocSetData setData;
-	char	   *name;
-	OrderedElemData elemData;
-} GlobalMemoryData;
 
-/* utils/mcxt.h contains typedef struct GlobalMemoryData *GlobalMemory */
-
-typedef struct MemoryContextData *PortalMemoryContext;
+/*
+ * AllocSetContext is our standard implementation of MemoryContext.
+ */
+typedef struct AllocBlockData *AllocBlock; /* internal to aset.c */
+typedef struct AllocChunkData *AllocChunk;
 
-typedef struct PortalVariableMemoryData
+typedef struct AllocSetContext
 {
-	NodeTag		type;
-	MemoryContextMethods method;
-	AllocSetData setData;
-}		   *PortalVariableMemory;
+	MemoryContextData header;		/* Standard memory-context fields */
+	/* Info about storage allocated in this context: */
+	AllocBlock	blocks;				/* head of list of blocks in this set */
+#define ALLOCSET_NUM_FREELISTS	8
+	AllocChunk	freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
+	/* Allocation parameters for this context: */
+	Size		initBlockSize;		/* initial block size */
+	Size		maxBlockSize;		/* maximum block size */
+	AllocBlock	keeper;				/* if not NULL, keep this block
+									 * over resets */
+} AllocSetContext;
 
-typedef struct PortalHeapMemoryData
-{
-	NodeTag		type;
-	MemoryContextMethods method;
-	Pointer		block;
-	FixedStackData stackData;
-}		   *PortalHeapMemory;
 
 /*
  * MemoryContextIsValid
  *		True iff memory context is valid.
+ *
+ * Add new context types to the set accepted by this macro.
  */
 #define MemoryContextIsValid(context) \
-	(IsA(context,MemoryContext) || IsA(context,GlobalMemory) || \
-	 IsA(context,PortalVariableMemory) || IsA(context,PortalHeapMemory))
+	((context) != NULL && \
+	 (IsA((context), AllocSetContext)))
+
 
 #endif	 /* MEMNODES_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 3be4831778..481f613688 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.69 2000/06/18 22:44:31 tgl Exp $
+ * $Id: nodes.h,v 1.70 2000/06/28 03:33:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -122,10 +122,7 @@ typedef enum NodeTag
 	 *---------------------
 	 */
 	T_MemoryContext = 400,
-	T_GlobalMemory,
-	T_PortalMemoryContext,
-	T_PortalVariableMemory,
-	T_PortalHeapMemory,
+	T_AllocSetContext,
 
 	/*---------------------
 	 * TAGS FOR VALUE NODES (pg_list.h)
diff --git a/src/include/optimizer/geqo.h b/src/include/optimizer/geqo.h
index bf65771529..1c6182f8d5 100644
--- a/src/include/optimizer/geqo.h
+++ b/src/include/optimizer/geqo.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: geqo.h,v 1.19 2000/05/31 00:28:38 petere Exp $
+ * $Id: geqo.h,v 1.20 2000/06/28 03:33:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,7 +65,6 @@ extern int          Geqo_random_seed; /* or negative to use current time */
 extern RelOptInfo *geqo(Query *root);
 
 /* routines in geqo_eval.c */
-extern void geqo_eval_startup(void);
 extern Cost geqo_eval(Query *root, Gene *tour, int num_gene);
 extern RelOptInfo *gimme_tree(Query *root, Gene *tour, int rel_count,
 		   int num_gene, RelOptInfo *old_rel);
diff --git a/src/include/postgres.h b/src/include/postgres.h
index 0f26b7978a..a4a7fda110 100644
--- a/src/include/postgres.h
+++ b/src/include/postgres.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1995, Regents of the University of California
  *
- * $Id: postgres.h,v 1.41 2000/06/13 07:35:24 tgl Exp $
+ * $Id: postgres.h,v 1.42 2000/06/28 03:32:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,7 +39,6 @@
 #include "postgres_ext.h"
 #include "c.h"
 #include "utils/elog.h"
-#include "utils/mcxt.h"
 #include "utils/palloc.h"
 
 /* ----------------------------------------------------------------
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 85eb424777..35545f9519 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: shmem.h,v 1.22 2000/01/26 05:58:33 momjian Exp $
+ * $Id: shmem.h,v 1.23 2000/06/28 03:33:27 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,14 +63,13 @@ typedef struct SHM_QUEUE
 extern void ShmemIndexReset(void);
 extern void ShmemCreate(unsigned int key, unsigned int size);
 extern int	InitShmem(unsigned int key, unsigned int size);
-extern long *ShmemAlloc(unsigned long size);
+extern void *ShmemAlloc(Size size);
 extern int	ShmemIsValid(unsigned long addr);
 extern HTAB *ShmemInitHash(char *name, long init_size, long max_size,
 			  HASHCTL *infoP, int hash_flags);
 extern bool ShmemPIDLookup(int pid, SHMEM_OFFSET *locationPtr);
 extern SHMEM_OFFSET ShmemPIDDestroy(int pid);
-extern long *ShmemInitStruct(char *name, unsigned long size,
-				bool *foundPtr);
+extern void *ShmemInitStruct(char *name, Size size, bool *foundPtr);
 
 
 typedef int TableID;
diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h
index 0dd1900a21..1bc5da9a33 100644
--- a/src/include/tcop/pquery.h
+++ b/src/include/tcop/pquery.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pquery.h,v 1.14 2000/01/26 05:58:35 momjian Exp $
+ * $Id: pquery.h,v 1.15 2000/06/28 03:33:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,20 +15,13 @@
 #define PQUERY_H
 
 #include "executor/execdesc.h"
+#include "utils/portal.h"
 
-/* moved to execdesc.h
-extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
-								  CommandDest dest);
-
-*/
-extern EState *CreateExecutorState(void);
 
+extern void ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
 
-extern void ProcessPortal(char *portalName, Query *parseTree,
-			  Plan *plan, EState *state, TupleDesc attinfo,
-			  CommandDest dest);
+extern EState *CreateExecutorState(void);
 
-extern void
-			ProcessQuery(Query *parsetree, Plan *plan, CommandDest dest);
+extern Portal PreparePortal(char *portalName);
 
-#endif	 /* pqueryIncluded */
+#endif	 /* PQUERY_H */
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 6f7bdd6e4e..cde0f5655a 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tcopprot.h,v 1.30 2000/06/15 03:33:04 momjian Exp $
+ * $Id: tcopprot.h,v 1.31 2000/06/28 03:33:28 tgl Exp $
  *
  * OLD COMMENTS
  *	  This file was created so that other c files could get the two
@@ -33,12 +33,11 @@ extern bool ShowPortNumber;
 #ifndef BOOTSTRAP_INCLUDE
 
 extern List *pg_parse_and_rewrite(char *query_string,
-					 Oid *typev, int nargs,
-					 bool aclOverride);
+								  Oid *typev, int nargs);
 extern Plan *pg_plan_query(Query *querytree);
 extern void pg_exec_query_dest(char *query_string,
-				   CommandDest dest,
-				   bool aclOverride);
+							   CommandDest dest,
+							   MemoryContext parse_context);
 
 #endif	 /* BOOTSTRAP_INCLUDE */
 
diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h
index b8e4ce71d7..cba400bc00 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catcache.h,v 1.24 2000/06/17 04:56:29 tgl Exp $
+ * $Id: catcache.h,v 1.25 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,8 +75,10 @@ typedef struct catcache
 
 #define InvalidCatalogCacheId	(-1)
 
-extern GlobalMemory CacheCxt;
+/* this extern duplicates utils/memutils.h... */
+extern MemoryContext CacheMemoryContext;
 
+extern void CreateCacheMemoryContext(void);
 extern void CatalogCacheIdInvalidate(int cacheId, Index hashIndex,
 						 ItemPointer pointer);
 extern void ResetSystemCache(void);
diff --git a/src/include/utils/hsearch.h b/src/include/utils/hsearch.h
index ef243da145..6d857175c9 100644
--- a/src/include/utils/hsearch.h
+++ b/src/include/utils/hsearch.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: hsearch.h,v 1.15 2000/04/12 17:16:55 momjian Exp $
+ * $Id: hsearch.h,v 1.16 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -84,8 +84,7 @@ typedef struct htab
 	char	   *segbase;		/* segment base address for calculating
 								 * pointer values */
 	SEG_OFFSET *dir;			/* 'directory' of segm starts */
-	long	   *(*alloc) ();	/* memory allocator (long * for alignment
-								 * reasons) */
+	void	   *(*alloc) (Size);	/* memory allocator */
 } HTAB;
 
 typedef struct hashctl
@@ -99,7 +98,7 @@ typedef struct hashctl
 	long		max_dsize;		/* limit to dsize if directory size is
 								 * limited */
 	long	   *segbase;		/* base for calculating bucket + seg ptrs */
-	long	   *(*alloc) ();	/* memory allocation function */
+	void	   *(*alloc) (Size);	/* memory allocation function */
 	long	   *dir;			/* directory if allocated already */
 	long	   *hctl;			/* location of header information in shd
 								 * mem */
diff --git a/src/include/utils/mcxt.h b/src/include/utils/mcxt.h
deleted file mode 100644
index 7b867d8664..0000000000
--- a/src/include/utils/mcxt.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * mcxt.h
- *	  POSTGRES memory context definitions.
- *
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: mcxt.h,v 1.17 2000/05/21 02:23:28 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef MCXT_H
-#define MCXT_H
-
-/* These types are declared in nodes/memnodes.h, but most users of memory
- * allocation should just treat them as abstract types, so we do not provide
- * the struct contents here.
- */
-
-typedef struct MemoryContextData *MemoryContext;
-typedef struct GlobalMemoryData *GlobalMemory;
-
-
-extern DLLIMPORT MemoryContext CurrentMemoryContext;
-extern MemoryContext TopMemoryContext;
-
-
-/*
- * MaxAllocSize
- *		Arbitrary limit on size of allocations.
- *
- * Note:
- *		There is no guarantee that allocations smaller than MaxAllocSize
- *		will succeed.  Allocation requests larger than MaxAllocSize will
- *		be summarily denied.
- *
- *		This value should not be referenced except in one place in the code.
- *
- * XXX This should be defined in a file of tunable constants.
- */
-#define MaxAllocSize	(0xfffffff)		/* 16G - 1 */
-
-/*
- * prototypes for functions in mcxt.c
- */
-extern void EnableMemoryContext(bool on);
-extern Pointer MemoryContextAlloc(MemoryContext context, Size size);
-extern Pointer MemoryContextRealloc(MemoryContext context,
-					 Pointer pointer,
-					 Size size);
-extern void MemoryContextFree(MemoryContext context, Pointer pointer);
-extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
-extern GlobalMemory CreateGlobalMemory(char *name);
-extern void GlobalMemoryDestroy(GlobalMemory context);
-extern void GlobalMemoryStats(void);
-
-
-#endif	 /* MCXT_H */
diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h
index 3e6ad2e53d..cbabdbf275 100644
--- a/src/include/utils/memutils.h
+++ b/src/include/utils/memutils.h
@@ -1,230 +1,114 @@
 /*-------------------------------------------------------------------------
  *
  * memutils.h
- *	  this file contains general memory alignment, allocation
- *	  and manipulation stuff that used to be spread out
- *	  between the following files:
- *
- *		align.h							alignment macros
- *		aset.h							memory allocation set stuff
- *		oset.h							  (used by aset.h)
+ *	  This file contains declarations for memory allocation utility
+ *	  functions.  These are functions that are not quite widely used
+ *	  enough to justify going in utils/palloc.h, but are still part
+ *	  of the API of the memory management subsystem.
  *
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: memutils.h,v 1.35 2000/05/21 02:23:28 tgl Exp $
+ * $Id: memutils.h,v 1.36 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef MEMUTILS_H
 #define MEMUTILS_H
 
-/* ----------------
- * Alignment macros: align a length or address appropriately for a given type.
- *
- * There used to be some incredibly crufty platform-dependent hackery here,
- * but now we rely on the configure script to get the info for us. Much nicer.
- *
- * NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
- * That case seems extremely unlikely to occur in practice, however.
- * ----------------
- */
+#include "nodes/memnodes.h"
 
-#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
-
-#define SHORTALIGN(LEN)			TYPEALIGN(ALIGNOF_SHORT, (LEN))
-#define INTALIGN(LEN)			TYPEALIGN(ALIGNOF_INT, (LEN))
-#define LONGALIGN(LEN)			TYPEALIGN(ALIGNOF_LONG, (LEN))
-#define DOUBLEALIGN(LEN)		TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
-#define MAXALIGN(LEN)			TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
-
-/*****************************************************************************
- *	  oset.h --			Fixed format ordered set definitions.				 *
- *****************************************************************************/
-/* Note:
- *		Fixed format ordered sets are <EXPLAIN>.
- *		XXX This is a preliminary version.	Work is needed to explain
- *		XXX semantics of the external definitions.	Otherwise, the
- *		XXX functional interface should not change.
- *
- */
-
-typedef struct OrderedElemData OrderedElemData;
-typedef OrderedElemData *OrderedElem;
 
-typedef struct OrderedSetData OrderedSetData;
-typedef OrderedSetData *OrderedSet;
-
-struct OrderedElemData
-{
-	OrderedElem next;			/* Next elem or &this->set->dummy		*/
-	OrderedElem prev;			/* Previous elem or &this->set->head	*/
-	OrderedSet	set;			/* Parent set							*/
-};
-
-struct OrderedSetData
-{
-	OrderedElem head;			/* First elem or &this->dummy			*/
-	OrderedElem dummy;			/* (hack) Terminator == NULL			*/
-	OrderedElem tail;			/* Last elem or &this->head				*/
-	Offset		offset;			/* Offset from struct base to elem		*/
-	/* this could be signed short int! */
-};
-
-extern void OrderedSetInit(OrderedSet set, Offset offset);
-extern Pointer OrderedSetGetHead(OrderedSet set);
-extern Pointer OrderedElemGetPredecessor(OrderedElem elem);
-extern Pointer OrderedElemGetSuccessor(OrderedElem elem);
-extern void OrderedElemPop(OrderedElem elem);
-extern void OrderedElemPushInto(OrderedElem elem, OrderedSet Set);
-
-/*****************************************************************************
- *	  aset.h --			Allocation set definitions.							 *
- *****************************************************************************/
 /*
- * Description:
- *		An allocation set is a set containing allocated elements.  When
- *		an allocation is requested for a set, memory is allocated and a
- *		pointer is returned.  Subsequently, this memory may be freed or
- *		reallocated.  In addition, an allocation set may be reset which
- *		will cause all memory allocated within it to be freed.
- *
- *		XXX The following material about allocation modes is all OUT OF DATE.
- *		aset.c currently implements only one allocation strategy,
- *		DynamicAllocMode, and that's the only one anyone ever requests anyway.
- *		If we ever did have more strategies, the new ones might or might
- *		not look like what is described here...
- *
- *		Allocations may occur in four different modes.	The mode of
- *		allocation does not affect the behavior of allocations except in
- *		terms of performance.  The allocation mode is set at the time of
- *		set initialization.  Once the mode is chosen, it cannot be changed
- *		unless the set is reinitialized.
- *
- *		"Dynamic" mode forces all allocations to occur in a heap.  This
- *		is a good mode to use when small memory segments are allocated
- *		and freed very frequently.	This is a good choice when allocation
- *		characteristics are unknown.  This is the default mode.
- *
- *		"Static" mode attempts to allocate space as efficiently as possible
- *		without regard to freeing memory.  This mode should be chosen only
- *		when it is known that many allocations will occur but that very
- *		little of the allocated memory will be explicitly freed.
- *
- *		"Tunable" mode is a hybrid of dynamic and static modes.  The
- *		tunable mode will use static mode allocation except when the
- *		allocation request exceeds a size limit supplied at the time of set
- *		initialization.  "Big" objects are allocated using dynamic mode.
- *
- *		"Bounded" mode attempts to allocate space efficiently given a limit
- *		on space consumed by the allocation set.  This restriction can be
- *		considered a "soft" restriction, because memory segments will
- *		continue to be returned after the limit is exceeded.  The limit is
- *		specified at the time of set initialization like for tunable mode.
+ * MaxAllocSize
+ *		Arbitrary limit on size of allocations.
  *
  * Note:
- *		Allocation sets are not automatically reset on a system reset.
- *		Higher level code is responsible for cleaning up.
+ *		There is no guarantee that allocations smaller than MaxAllocSize
+ *		will succeed.  Allocation requests larger than MaxAllocSize will
+ *		be summarily denied.
  *
- *		There may be other modes in the future.
+ * XXX This should be defined in a file of tunable constants.
  */
+#define MaxAllocSize	((Size) 0xfffffff)		/* 16G - 1 */
 
-/*
- * AllocPointer
- *		Aligned pointer which may be a member of an allocation set.
- */
-typedef Pointer AllocPointer;
+#define AllocSizeIsValid(size)	(0 < (size) && (size) <= MaxAllocSize)
 
 /*
- * AllocMode
- *		Mode of allocation for an allocation set.
- *
- * Note:
- *		See above for a description of the various modes.
+ * All chunks allocated by any memory context manager are required to be
+ * preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE.
+ * A currently-allocated chunk must contain a backpointer to its owning
+ * context as well as the allocated size of the chunk.  The backpointer is
+ * used by pfree() and repalloc() to find the context to call.  The allocated
+ * size is not absolutely essential, but it's expected to be needed by any
+ * reasonable implementation.
  */
-typedef enum AllocMode
+typedef struct StandardChunkHeader
 {
-	DynamicAllocMode,			/* always dynamically allocate */
-	StaticAllocMode,			/* always "statically" allocate */
-	TunableAllocMode,			/* allocations are "tuned" */
-	BoundedAllocMode			/* allocations bounded to fixed usage */
-} AllocMode;
+	MemoryContext context;			/* owning context */
+	Size size;						/* size of data space allocated in chunk */
+} StandardChunkHeader;
 
-#define DefaultAllocMode		DynamicAllocMode
+#define STANDARDCHUNKHEADERSIZE  MAXALIGN(sizeof(StandardChunkHeader))
 
-typedef struct AllocSetData *AllocSet;
-typedef struct AllocBlockData *AllocBlock;
-typedef struct AllocChunkData *AllocChunk;
-
-/*
- * AllocSet
- *		Allocation set.
- */
-typedef struct AllocSetData
-{
-	AllocBlock	blocks;			/* head of list of blocks in this set */
-#define ALLOCSET_NUM_FREELISTS	8
-	AllocChunk	freelist[ALLOCSET_NUM_FREELISTS];		/* free chunk lists */
-	/* Note: this will change in the future to support other modes */
-} AllocSetData;
 
 /*
- * AllocBlock
- *		An AllocBlock is the unit of memory that is obtained by aset.c
- *		from malloc().	It contains one or more AllocChunks, which are
- *		the units requested by palloc() and freed by pfree().  AllocChunks
- *		cannot be returned to malloc() individually, instead they are put
- *		on freelists by pfree() and re-used by the next palloc() that has
- *		a matching request size.
+ * Standard top-level memory contexts.
  *
- *		AllocBlockData is the header data for a block --- the usable space
- *		within the block begins at the next alignment boundary.
+ * Only TopMemoryContext and ErrorContext are initialized by
+ * MemoryContextInit() itself.
  */
-typedef struct AllocBlockData
-{
-	AllocSet	aset;			/* aset that owns this block */
-	AllocBlock	next;			/* next block in aset's blocks list */
-	char	   *freeptr;		/* start of free space in this block */
-	char	   *endptr;			/* end of space in this block */
-} AllocBlockData;
+extern MemoryContext TopMemoryContext;
+extern MemoryContext ErrorContext;
+extern MemoryContext PostmasterContext;
+extern MemoryContext CacheMemoryContext;
+extern MemoryContext QueryContext;
+extern MemoryContext TopTransactionContext;
+extern MemoryContext TransactionCommandContext;
 
-/*
- * AllocChunk
- *		The prefix of each piece of memory in an AllocBlock
- */
-typedef struct AllocChunkData
-{
-	/* aset is the owning aset if allocated, or the freelist link if free */
-	void	   *aset;
-	/* size is always the size of the usable space in the chunk */
-	Size		size;
-} AllocChunkData;
 
 /*
- * AllocPointerIsValid
- *		True iff pointer is valid allocation pointer.
+ * Memory-context-type-independent functions in mcxt.c
  */
-#define AllocPointerIsValid(pointer) PointerIsValid(pointer)
+extern void MemoryContextInit(void);
+extern void MemoryContextReset(MemoryContext context);
+extern void MemoryContextDelete(MemoryContext context);
+extern void MemoryContextResetChildren(MemoryContext context);
+extern void MemoryContextDeleteChildren(MemoryContext context);
+extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
+extern void MemoryContextStats(MemoryContext context);
+extern bool MemoryContextContains(MemoryContext context, void *pointer);
 
 /*
- * AllocSetIsValid
- *		True iff set is valid allocation set.
+ * This routine handles the context-type-independent part of memory
+ * context creation.  It's intended to be called from context-type-
+ * specific creation routines, and noplace else.
  */
-#define AllocSetIsValid(set) PointerIsValid(set)
+extern MemoryContext MemoryContextCreate(NodeTag tag, Size size,
+										 MemoryContextMethods *methods,
+										 MemoryContext parent,
+										 const char *name);
 
-extern void AllocSetInit(AllocSet set, AllocMode mode, Size limit);
 
-extern void AllocSetReset(AllocSet set);
+/*
+ * Memory-context-type-specific functions
+ */
 
-extern bool AllocSetContains(AllocSet set, AllocPointer pointer);
-extern AllocPointer AllocSetAlloc(AllocSet set, Size size);
-extern void AllocSetFree(AllocSet set, AllocPointer pointer);
-extern AllocPointer AllocSetRealloc(AllocSet set, AllocPointer pointer,
-				Size size);
+/* aset.c */
+extern MemoryContext AllocSetContextCreate(MemoryContext parent,
+										   const char *name,
+										   Size minContextSize,
+										   Size initBlockSize,
+										   Size maxBlockSize);
 
-extern void AllocSetDump(AllocSet set);
-extern void AllocSetStats(AllocSet set, const char *ident);
+/*
+ * Recommended default alloc parameters, suitable for "ordinary" contexts
+ * that might hold quite a lot of data.
+ */
+#define ALLOCSET_DEFAULT_MINSIZE   (8 * 1024)
+#define ALLOCSET_DEFAULT_INITSIZE  (8 * 1024)
+#define ALLOCSET_DEFAULT_MAXSIZE   (8 * 1024 * 1024)
 
 
 #endif	 /* MEMUTILS_H */
diff --git a/src/include/utils/module.h b/src/include/utils/module.h
deleted file mode 100644
index e7e45580ac..0000000000
--- a/src/include/utils/module.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * module.h
- *	  this file contains general "module" stuff  that used to be
- *	  spread out between the following files:
- *
- *		enbl.h					module enable stuff
- *		trace.h					module trace stuff (now gone)
- *
- *
- * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: module.h,v 1.6 2000/01/26 05:58:38 momjian Exp $
- *
- *-------------------------------------------------------------------------
- */
-#ifndef MODULE_H
-#define MODULE_H
-
-/*
- * prototypes for functions in init/enbl.c
- */
-extern bool BypassEnable(int *enableCountInOutP, bool on);
-
-#endif	 /* MODULE_H */
diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h
index 0ec6caabbb..4bfdedff7e 100644
--- a/src/include/utils/palloc.h
+++ b/src/include/utils/palloc.h
@@ -3,36 +3,85 @@
  * palloc.h
  *	  POSTGRES memory allocator definitions.
  *
+ * This file contains the basic memory allocation interface that is
+ * needed by almost every backend module.  It is included directly by
+ * postgres.h, so the definitions here are automatically available
+ * everywhere.  Keep it lean!
+ *
+ * Memory allocation occurs within "contexts".  Every chunk obtained from
+ * palloc()/MemoryContextAlloc() is allocated within a specific context.
+ * The entire contents of a context can be freed easily and quickly by
+ * resetting or deleting the context --- this is both faster and less
+ * prone to memory-leakage bugs than releasing chunks individually.
+ * We organize contexts into context trees to allow fine-grain control
+ * over chunk lifetime while preserving the certainty that we will free
+ * everything that should be freed.  See utils/mmgr/README for more info.
+ *
  *
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: palloc.h,v 1.12 2000/01/26 05:58:38 momjian Exp $
+ * $Id: palloc.h,v 1.13 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef PALLOC_H
 #define PALLOC_H
 
-#ifdef PALLOC_IS_MALLOC
+/*
+ * Type MemoryContextData is declared in nodes/memnodes.h.  Most users
+ * of memory allocation should just treat it as an abstract type, so we
+ * do not provide the struct contents here.
+ */
+typedef struct MemoryContextData *MemoryContext;
+
+/*
+ * CurrentMemoryContext is the default allocation context for palloc().
+ * We declare it here so that palloc() can be a macro.  Avoid accessing it
+ * directly!  Instead, use MemoryContextSwitchTo() to change the setting.
+ */
+extern DLLIMPORT MemoryContext CurrentMemoryContext;
+
+/*
+ * Fundamental memory-allocation operations (more are in utils/memutils.h)
+ */
+extern void *MemoryContextAlloc(MemoryContext context, Size size);
+
+#define palloc(sz)  MemoryContextAlloc(CurrentMemoryContext, (sz))
 
-#define palloc(s)	  malloc(s)
-#define pfree(p)	  free(p)
-#define repalloc(p,s) realloc((p),(s))
+extern void pfree(void *pointer);
 
-#else							/* ! PALLOC_IS_MALLOC */
+extern void *repalloc(void *pointer, Size size);
 
-/* ----------
- * In the case we use memory contexts, use macro's for palloc() etc.
- * ----------
+extern MemoryContext MemoryContextSwitchTo(MemoryContext context);
+
+/*
+ * These are like standard strdup() except the copied string is
+ * allocated in a context, not with malloc().
+ */
+extern char *MemoryContextStrdup(MemoryContext context, const char *string);
+
+#define pstrdup(str)  MemoryContextStrdup(CurrentMemoryContext, (str))
+
+
+/* ----------------
+ * Alignment macros: align a length or address appropriately for a given type.
+ *
+ * There used to be some incredibly crufty platform-dependent hackery here,
+ * but now we rely on the configure script to get the info for us. Much nicer.
+ *
+ * NOTE: TYPEALIGN will not work if ALIGNVAL is not a power of 2.
+ * That case seems extremely unlikely to occur in practice, however.
+ * ----------------
  */
-#define palloc(s)	  ((void *)MemoryContextAlloc(CurrentMemoryContext,(Size)(s)))
-#define pfree(p)	  MemoryContextFree(CurrentMemoryContext,(Pointer)(p))
-#define repalloc(p,s) ((void *)MemoryContextRealloc(CurrentMemoryContext,(Pointer)(p),(Size)(s)))
 
-#endif	 /* PALLOC_IS_MALLOC */
+#define TYPEALIGN(ALIGNVAL,LEN) (((long)(LEN) + (ALIGNVAL-1)) & ~(ALIGNVAL-1))
+
+#define SHORTALIGN(LEN)			TYPEALIGN(ALIGNOF_SHORT, (LEN))
+#define INTALIGN(LEN)			TYPEALIGN(ALIGNOF_INT, (LEN))
+#define LONGALIGN(LEN)			TYPEALIGN(ALIGNOF_LONG, (LEN))
+#define DOUBLEALIGN(LEN)		TYPEALIGN(ALIGNOF_DOUBLE, (LEN))
+#define MAXALIGN(LEN)			TYPEALIGN(MAXIMUM_ALIGNOF, (LEN))
 
-/* like strdup except uses palloc */
-extern char *pstrdup(const char *pointer);
 
 #endif	 /* PALLOC_H */
diff --git a/src/include/utils/portal.h b/src/include/utils/portal.h
index 406fcc6af2..bb240fe599 100644
--- a/src/include/utils/portal.h
+++ b/src/include/utils/portal.h
@@ -7,16 +7,14 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: portal.h,v 1.23 2000/04/12 17:16:55 momjian Exp $
+ * $Id: portal.h,v 1.24 2000/06/28 03:33:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * Note:
  *		A portal is an abstraction which represents the execution state of
- * a running query (or a fixed sequence of queries).  The "blank portal" is
- * a portal with an InvalidName.  This blank portal is in existance except
- * between calls to BlankPortalAssignName and GetPortalByName(NULL).
+ * a running query (or a fixed sequence of queries).
  *
  * Note:
  *		now that PQ calls can be made from within a backend, a portal
@@ -29,27 +27,18 @@
 #include "executor/execdesc.h"
 #include "nodes/memnodes.h"
 
-typedef struct PortalBlockData
-{
-	AllocSetData setData;
-	FixedItemData itemData;
-} PortalBlockData;
-
-typedef PortalBlockData *PortalBlock;
 
-typedef struct PortalD PortalD;
-typedef PortalD *Portal;
+typedef struct PortalD *Portal;
 
-struct PortalD
+typedef struct PortalD
 {
-	char	   *name;			/* XXX PortalName */
-	struct PortalVariableMemoryData variable;
-	struct PortalHeapMemoryData heap;
-	QueryDesc  *queryDesc;
+	char	   *name;			/* Portal's name */
+	MemoryContext heap;			/* subsidiary memory */
+	QueryDesc  *queryDesc;		/* Info about query associated with portal */
 	TupleDesc	attinfo;
 	EState	   *state;
-	void		(*cleanup) (Portal);
-};
+	void		(*cleanup) (Portal); /* Cleanup routine (optional) */
+} PortalD;
 
 /*
  * PortalIsValid
@@ -57,36 +46,20 @@ struct PortalD
  */
 #define PortalIsValid(p) PointerIsValid(p)
 
-/*
- * Special portals (well, their names anyway)
- */
-#define VACPNAME		"<vacuum>"
-#define TRUNCPNAME				"<truncate>"
-
-extern bool PortalNameIsSpecial(char *pname);
+extern void EnablePortalManager(void);
 extern void AtEOXact_portals(void);
-extern void EnablePortalManager(bool on);
+extern Portal CreatePortal(char *name);
+extern void PortalDrop(Portal *portalP);
 extern Portal GetPortalByName(char *name);
-extern Portal BlankPortalAssignName(char *name);
 extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
 			   TupleDesc attinfo, EState *state,
 			   void (*cleanup) (Portal portal));
 extern QueryDesc *PortalGetQueryDesc(Portal portal);
 extern EState *PortalGetState(Portal portal);
-extern Portal CreatePortal(char *name);
-extern void PortalDrop(Portal *portalP);
-extern void StartPortalAllocMode(AllocMode mode, Size limit);
-extern void EndPortalAllocMode(void);
-extern void PortalResetHeapMemory(Portal portal);
-extern PortalVariableMemory PortalGetVariableMemory(Portal portal);
-extern PortalHeapMemory PortalGetHeapMemory(Portal portal);
-extern void CommonSpecialPortalOpen(void);
-extern void CommonSpecialPortalClose(void);
-extern PortalVariableMemory CommonSpecialPortalGetMemory(void);
-extern bool CommonSpecialPortalIsOpen(void);
+extern MemoryContext PortalGetHeapMemory(Portal portal);
 
 /* estimate of the maximum number of open portals a user would have,
- * used in initially sizing the PortalHashTable in	EnablePortalManager()
+ * used in initially sizing the PortalHashTable in EnablePortalManager()
  */
 #define PORTALS_PER_USER	   10
 
-- 
2.40.0