]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/mmgr/portalmem.c
Rename SortMem and VacuumMem to work_mem and maintenance_work_mem.
[postgresql] / src / backend / utils / mmgr / portalmem.c
index b56690320f000278be766e0dede102cd3635ff07..f6b72481fb9b772720ce012920d99f2f623651b6 100644 (file)
 /*-------------------------------------------------------------------------
  *
- * portalmem.c--
- *       backend portal memory context management stuff
+ * portalmem.c
+ *       backend portal memory management
  *
- * Copyright (c) 1994, Regents of the University of California
+ * Portals are objects representing the execution state of a query.
+ * This module provides memory management services for portals, but it
+ * doesn't actually run the executor for them.
  *
  *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.8 1997/09/08 21:49:31 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.64 2004/02/03 17:34:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-/*
- * NOTES
- *             Do not confuse "Portal" with "PortalEntry" (or "PortalBuffer").
- *             When a PQexec() routine is run, the resulting tuples
- *             find their way into a "PortalEntry".  The contents of the resulting
- *             "PortalEntry" can then be inspected by other PQxxx functions.
- *
- *             A "Portal" is a structure used to keep track of queries of the
- *             form:
- *                             retrieve portal FOO ( blah... ) where blah...
- *
- *             When the backend sees a "retrieve portal" query, it allocates
- *             a "PortalD" structure, plans the query and then stores the query
- *             in the portal without executing it.  Later, when the backend
- *             sees a
- *                             fetch 1 into FOO
- *
- *             the system looks up the portal named "FOO" in the portal table,
- *             gets the planned query and then calls the executor with a feature of
- *             '(EXEC_FOR 1).  The executor then runs the query and returns a single
- *             tuple.  The problem is that we have to hold onto the state of the
- *             portal query until we see a "close p".  This means we have to be
- *             careful about memory management.
- *
- *             Having said all that, here is what a PortalD currently looks like:
- *
- * struct PortalD {
- *             char*                                                   name;
- *             classObj(PortalVariableMemory)  variable;
- *             classObj(PortalHeapMemory)              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 <stdio.h>                             /* for sprintf() */
-#include <string.h>                            /* for strlen, strncpy */
-
 #include "postgres.h"
 
-#include "lib/hasht.h"
-#include "utils/module.h"
-#include "utils/excid.h"               /* for Unimplemented */
-#include "utils/mcxt.h"
+#include "miscadmin.h"
+#include "commands/portalcmds.h"
+#include "executor/executor.h"
 #include "utils/hsearch.h"
-
-#include "nodes/memnodes.h"
-#include "nodes/nodes.h"
-#include "nodes/pg_list.h"
-#include "nodes/execnodes.h"   /* for EState */
-
+#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 void PortalResetHeapMemory(Portal portal);
-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
- * ----------------
+/*
+ * estimate of the maximum number of open portals a user would have,
+ * used in initially sizing the PortalHashTable in EnablePortalManager()
  */
-#undef ALLOCFREE_ERROR_ABORT
+#define PORTALS_PER_USER          64
+
 
 /* ----------------
  *             Global state
  * ----------------
  */
 
-static int     PortalManagerEnableCount = 0;
-
-#define MAX_PORTALNAME_LEN             64              /* XXX LONGALIGNable value */
+#define MAX_PORTALNAME_LEN             NAMEDATALEN
 
 typedef struct portalhashent
 {
@@ -120,892 +45,469 @@ typedef struct portalhashent
        Portal          portal;
 } PortalHashEnt;
 
-#define PortalManagerEnabled   (PortalManagerEnableCount >= 1)
-
 static HTAB *PortalHashTable = NULL;
 
 #define PortalHashTableLookup(NAME, PORTAL) \
-       {       PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
-               memset(key, 0, MAX_PORTALNAME_LEN); \
-               sprintf(key, "%s", NAME); \
-               hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
-                                                                                        key, HASH_FIND, &found); \
-               if (hentry == NULL) \
-                       elog(FATAL, "error in PortalHashTable"); \
-               if (found) \
-                       PORTAL = hentry->portal; \
-               else \
-                       PORTAL = NULL; \
-       }
-#define PortalHashTableInsert(PORTAL) \
-       {       PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
-               memset(key, 0, MAX_PORTALNAME_LEN); \
-               sprintf(key, "%s", PORTAL->name); \
-               hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
-                                                                                        key, HASH_ENTER, &found); \
-               if (hentry == NULL) \
-                       elog(FATAL, "error in PortalHashTable"); \
-               if (found) \
-                       elog(NOTICE, "trying to insert a portal name that exists."); \
-               hentry->portal = PORTAL; \
-       }
-#define PortalHashTableDelete(PORTAL) \
-       {       PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
-               memset(key, 0, MAX_PORTALNAME_LEN); \
-               sprintf(key, "%s", PORTAL->name); \
-               hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
-                                                                                        key, HASH_REMOVE, &found); \
-               if (hentry == NULL) \
-                       elog(FATAL, "error in PortalHashTable"); \
-               if (!found) \
-                       elog(NOTICE, "trying to delete portal name that does not exist."); \
-       }
-
-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 (form("%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));
-}
+do { \
+       PortalHashEnt *hentry; char key[MAX_PORTALNAME_LEN]; \
+       \
+       MemSet(key, 0, MAX_PORTALNAME_LEN); \
+       StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \
+       hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
+                                                                                key, HASH_FIND, NULL); \
+       if (hentry) \
+               PORTAL = hentry->portal; \
+       else \
+               PORTAL = NULL; \
+} while(0)
+
+#define PortalHashTableInsert(PORTAL, NAME) \
+do { \
+       PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
+       \
+       MemSet(key, 0, MAX_PORTALNAME_LEN); \
+       StrNCpy(key, NAME, MAX_PORTALNAME_LEN); \
+       hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
+                                                                                key, HASH_ENTER, &found); \
+       if (hentry == NULL) \
+               ereport(ERROR, \
+                               (errcode(ERRCODE_OUT_OF_MEMORY), \
+                                errmsg("out of memory"))); \
+       if (found) \
+               elog(ERROR, "duplicate portal name"); \
+       hentry->portal = PORTAL; \
+       /* To avoid duplicate storage, make PORTAL->name point to htab entry */ \
+       PORTAL->name = hentry->portalname; \
+} while(0)
 
-/* ----------------
- *             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%x 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 (form("%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 */
-};
-
-
-/* ----------------------------------------------------------------
- *                               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;
-       return false;
-}
-
-/*
- * This routine is used to collect all portals created in this xaction
- * and then destroy them.  There is a little trickiness required as a
- * result of the dynamic hashing interface to getting every hash entry
- * sequentially.  Its use of static variables requires that we get every
- * entry *before* we destroy anything (destroying updates the hashtable
- * and screws up the sequential walk of the table). -mer 17 Aug 1992
- */
-static void
-CollectNamedPortals(Portal *portalP, int destroy)
-{
-       static Portal *portalList = (Portal *) NULL;
-       static int      listIndex = 0;
-       static int      maxIndex = 9;
-
-       if (portalList == (Portal *) NULL)
-               portalList = (Portal *) malloc(10 * sizeof(Portal));
-
-       if (destroy != 0)
-       {
-               int                     i;
-
-               for (i = 0; i < listIndex; i++)
-                       PortalDestroy(&portalList[i]);
-               listIndex = 0;
-       }
-       else
-       {
-               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)
-               {
-                       portalList = (Portal *)
-                               realloc(portalList, (maxIndex + 11) * sizeof(Portal));
-                       maxIndex += 10;
-               }
-       }
-       return;
-}
-
-void
-AtEOXact_portals()
-{
-       HashTableWalk(PortalHashTable, CollectNamedPortals, 0);
-       CollectNamedPortals(NULL, 1);
-}
-
-/* ----------------
- *             PortalDump
- * ----------------
- */
-#ifdef NOT_USED
-static void
-PortalDump(Portal *thisP)
-{
-       /* XXX state/argument checking here */
-
-       PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
-       PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
-}
-
-#endif
-
-/* ----------------
- *             DumpPortals
- * ----------------
- */
-#ifdef NOT_USED
-static void
-DumpPortals()
-{
-       /* XXX state checking here */
+#define PortalHashTableDelete(PORTAL) \
+do { \
+       PortalHashEnt *hentry; char key[MAX_PORTALNAME_LEN]; \
+       \
+       MemSet(key, 0, MAX_PORTALNAME_LEN); \
+       StrNCpy(key, PORTAL->name, MAX_PORTALNAME_LEN); \
+       hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
+                                                                                key, HASH_REMOVE, NULL); \
+       if (hentry == NULL) \
+               elog(WARNING, "trying to delete portal name that does not exist"); \
+} while(0)
 
-       HashTableWalk(PortalHashTable, PortalDump, 0);
-}
+static MemoryContext PortalMemory = NULL;
 
-#endif
 
 /* ----------------------------------------------------------------
  *                                public portal interface functions
  * ----------------------------------------------------------------
  */
+
 /*
- * EnablePortalManager --
- *             Enables/disables the portal management module.
+ * EnablePortalManager
+ *             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;
+       Assert(PortalMemory == NULL);
 
-       if (on)
-       {                                                       /* initialize */
-               EnableMemoryContext(true);
+       PortalMemory = AllocSetContextCreate(TopMemoryContext,
+                                                                                "PortalMemory",
+                                                                                ALLOCSET_DEFAULT_MINSIZE,
+                                                                                ALLOCSET_DEFAULT_INITSIZE,
+                                                                                ALLOCSET_DEFAULT_MAXSIZE);
 
-               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))
-               {
-                       PortalDestroy(&BlankPortal);
-                       MemoryContextFree((MemoryContext) PortalMemory,
-                                                         (Pointer) BlankPortal);
-                       BlankPortal = NULL;
-               }
+       ctl.keysize = MAX_PORTALNAME_LEN;
+       ctl.entrysize = sizeof(PortalHashEnt);
 
-               /*
-                * Each portal must free its non-memory resources specially.
-                */
-               HashTableWalk(PortalHashTable, PortalDestroy, 0);
-               hash_destroy(PortalHashTable);
-               PortalHashTable = NULL;
-
-               GlobalMemoryDestroy(PortalMemory);
-               PortalMemory = NULL;
-
-               EnableMemoryContext(true);
-       }
-
-       processing = false;
+       /*
+        * use PORTALS_PER_USER as a guess of how many hash table entries to
+        * create, initially
+        */
+       PortalHashTable = hash_create("Portal hash", PORTALS_PER_USER,
+                                                                 &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.
+ * GetPortalByName
+ *             Returns a portal given a portal name, or NULL if name not found.
  */
 Portal
-GetPortalByName(char *name)
+GetPortalByName(const char *name)
 {
        Portal          portal;
 
-       AssertState(PortalManagerEnabled);
-
        if (PointerIsValid(name))
-       {
                PortalHashTableLookup(name, portal);
-       }
        else
-       {
-               if (!PortalIsValid(BlankPortal))
-                       CreateNewBlankPortal();
-               portal = BlankPortal;
-       }
+               portal = NULL;
 
-       return (portal);
+       return portal;
 }
 
 /*
- * BlankPortalAssignName --
- *             Returns former blank portal as portal with given name.
+ * CreatePortal
+ *             Returns a new portal given a name.
  *
- * Side effect:
- *             All references to the former blank portal become incorrect.
+ * allowDup: if true, automatically drop any pre-existing portal of the
+ * same name (if false, an error is raised).
  *
- * 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.
+ * dupSilent: if true, don't even emit a WARNING.
  */
 Portal
-BlankPortalAssignName(char *name)              /* XXX PortalName */
+CreatePortal(const char *name, bool allowDup, bool dupSilent)
 {
        Portal          portal;
-       uint16          length;
 
-       AssertState(PortalManagerEnabled);
-       AssertState(PortalIsValid(BlankPortal));
-       AssertArg(PointerIsValid(name));        /* XXX PortalName */
+       AssertArg(PointerIsValid(name));
 
        portal = GetPortalByName(name);
        if (PortalIsValid(portal))
        {
-               elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
-               return (portal);
+               if (!allowDup)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DUPLICATE_CURSOR),
+                                        errmsg("cursor \"%s\" already exists", name)));
+               if (!dupSilent)
+                       ereport(WARNING,
+                                       (errcode(ERRCODE_DUPLICATE_CURSOR),
+                                        errmsg("closing existing cursor \"%s\"",
+                                                       name)));
+               PortalDrop(portal, false);
        }
 
-       /*
-        * remove blank portal
-        */
-       portal = BlankPortal;
-       BlankPortal = NULL;
+       /* make new portal structure */
+       portal = (Portal) MemoryContextAllocZero(PortalMemory, sizeof *portal);
 
-       /*
-        * initialize portal name
-        */
-       length = 1 + strlen(name);
-       portal->name = (char *)
-               MemoryContextAlloc((MemoryContext) &portal->variable, length);
+       /* initialize portal heap context; typically it won't store much */
+       portal->heap = AllocSetContextCreate(PortalMemory,
+                                                                                "PortalHeapMemory",
+                                                                                ALLOCSET_SMALL_MINSIZE,
+                                                                                ALLOCSET_SMALL_INITSIZE,
+                                                                                ALLOCSET_SMALL_MAXSIZE);
 
-       strncpy(portal->name, name, length);
+       /* initialize portal fields that don't start off zero */
+       portal->cleanup = PortalCleanup;
+       portal->createXact = GetCurrentTransactionId();
+       portal->strategy = PORTAL_MULTI_QUERY;
+       portal->cursorOptions = CURSOR_OPT_NO_SCROLL;
+       portal->atStart = true;
+       portal->atEnd = true;           /* disallow fetches until query is set */
 
-       /*
-        * put portal in table
-        */
-       PortalHashTableInsert(portal);
+       /* put portal in table (sets portal->name) */
+       PortalHashTableInsert(portal, name);
 
-       return (portal);
+       return portal;
 }
 
 /*
- * PortalSetQuery --
- *             Attaches a "query" to portal.
- *
- * Exceptions:
- *             BadState if called when disabled.
- *             BadArg if portal is invalid.
- *             BadArg if queryDesc is "invalid."
- *             BadArg if state is "invalid."
+ * CreateNewPortal
+ *             Create a new portal, assigning it a random nonconflicting name.
  */
-void
-PortalSetQuery(Portal portal,
-                          QueryDesc *queryDesc,
-                          TupleDesc attinfo,
-                          EState *state,
-                          void (*cleanup) (Portal portal))
+Portal
+CreateNewPortal(void)
 {
-       AssertState(PortalManagerEnabled);
-       AssertArg(PortalIsValid(portal));
-       AssertArg(IsA((Node *) state, EState));
+       static unsigned int unnamed_portal_count = 0;
 
-       portal->queryDesc = queryDesc;
-       portal->state = state;
-       portal->attinfo = attinfo;
-       portal->cleanup = cleanup;
-}
+       char            portalname[MAX_PORTALNAME_LEN];
 
-/*
- * PortalGetQueryDesc --
- *             Returns query attached to portal.
- *
- * Exceptions:
- *             BadState if called when disabled.
- *             BadArg if portal is invalid.
- */
-QueryDesc  *
-PortalGetQueryDesc(Portal portal)
-{
-       AssertState(PortalManagerEnabled);
-       AssertArg(PortalIsValid(portal));
+       /* Select a nonconflicting name */
+       for (;;)
+       {
+               unnamed_portal_count++;
+               sprintf(portalname, "<unnamed portal %u>", unnamed_portal_count);
+               if (GetPortalByName(portalname) == NULL)
+                       break;
+       }
 
-       return (portal->queryDesc);
+       return CreatePortal(portalname, false, false);
 }
 
 /*
- * PortalGetState --
- *             Returns state attached to portal.
+ * PortalDefineQuery
+ *             A simple subroutine to establish a portal's query.
  *
- * Exceptions:
- *             BadState if called when disabled.
- *             BadArg if portal is invalid.
+ * Notes: commandTag shall be NULL if and only if the original query string
+ * (before rewriting) was an empty string.     Also, the passed commandTag must
+ * be a pointer to a constant string, since it is not copied.  The caller is
+ * responsible for ensuring that the passed sourceText (if any), parse and
+ * plan trees have adequate lifetime.  Also, queryContext must accurately
+ * describe the location of the parse and plan trees.
  */
-EState    *
-PortalGetState(Portal portal)
+void
+PortalDefineQuery(Portal portal,
+                                 const char *sourceText,
+                                 const char *commandTag,
+                                 List *parseTrees,
+                                 List *planTrees,
+                                 MemoryContext queryContext)
 {
-       AssertState(PortalManagerEnabled);
        AssertArg(PortalIsValid(portal));
+       AssertState(portal->queryContext == NULL);      /* else defined already */
+
+       Assert(length(parseTrees) == length(planTrees));
+
+       Assert(commandTag != NULL || parseTrees == NIL);
 
-       return (portal->state);
+       portal->sourceText = sourceText;
+       portal->commandTag = commandTag;
+       portal->parseTrees = parseTrees;
+       portal->planTrees = planTrees;
+       portal->queryContext = queryContext;
 }
 
 /*
- * 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.
+ * PortalCreateHoldStore
+ *             Create the tuplestore for a portal.
  */
-Portal
-CreatePortal(char *name)               /* XXX PortalName */
+void
+PortalCreateHoldStore(Portal portal)
 {
-       Portal          portal;
-       uint16          length;
+       MemoryContext oldcxt;
 
-       AssertState(PortalManagerEnabled);
-       AssertArg(PointerIsValid(name));        /* XXX PortalName */
+       Assert(portal->holdContext == NULL);
+       Assert(portal->holdStore == NULL);
 
-       portal = GetPortalByName(name);
-       if (PortalIsValid(portal))
-       {
-               elog(NOTICE, "CreatePortal: portal %s already exists", name);
-               return (portal);
-       }
+       /*
+        * Create the memory context that is used for storage of the tuple
+        * set. Note this is NOT a child of the portal's heap memory.
+        */
+       portal->holdContext =
+               AllocSetContextCreate(PortalMemory,
+                                                         "PortalHeapMemory",
+                                                         ALLOCSET_DEFAULT_MINSIZE,
+                                                         ALLOCSET_DEFAULT_INITSIZE,
+                                                         ALLOCSET_DEFAULT_MAXSIZE);
 
-       /* 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;
-
-       /* initialize portal name */
-       length = 1 + strlen(name);
-       portal->name = (char *)
-               MemoryContextAlloc((MemoryContext) &portal->variable, length);
-       strncpy(portal->name, name, length);
-
-       /* 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);
+       /* Create the tuple store, selecting cross-transaction temp files. */
+       oldcxt = MemoryContextSwitchTo(portal->holdContext);
+
+       /* XXX: Should maintenance_work_mem be used for the portal size? */
+       portal->holdStore = tuplestore_begin_heap(true, true, work_mem);
+
+       MemoryContextSwitchTo(oldcxt);
 }
 
 /*
- * PortalDestroy --
- *             Destroys portal.
+ * PortalDrop
+ *             Destroy the portal.
  *
- * Exceptions:
- *             BadState if called when disabled.
- *             BadArg if portal is invalid.
+ *             isError: if true, we are destroying portals at the end of a failed
+ *             transaction.  (This causes PortalCleanup to skip unneeded steps.)
  */
 void
-PortalDestroy(Portal *portalP)
+PortalDrop(Portal portal, bool isError)
 {
-       Portal          portal = *portalP;
-
-       AssertState(PortalManagerEnabled);
        AssertArg(PortalIsValid(portal));
 
-       /* remove portal from table if not blank portal */
-       if (portal != BlankPortal)
-               PortalHashTableDelete(portal);
+       /* Not sure if this case can validly happen or not... */
+       if (portal->portalActive)
+               elog(ERROR, "cannot drop active portal");
+
+       /*
+        * Remove portal from hash table.  Because we do this first, we will
+        * not come back to try to remove the portal again if there's any
+        * error in the subsequent steps.  Better to leak a little memory than
+        * to get into an infinite error-recovery loop.
+        */
+       PortalHashTableDelete(portal);
 
-       /* reset portal */
+       /* let portalcmds.c clean up the state it knows about */
        if (PointerIsValid(portal->cleanup))
-               (*portal->cleanup) (portal);
+               (*portal->cleanup) (portal, isError);
+
+       /*
+        * Delete tuplestore if present.  We should do this even under error
+        * conditions; since the tuplestore would have been using cross-
+        * transaction storage, its temp files need to be explicitly deleted.
+        */
+       if (portal->holdStore)
+       {
+               MemoryContext oldcontext;
+
+               oldcontext = MemoryContextSwitchTo(portal->holdContext);
+               tuplestore_end(portal->holdStore);
+               MemoryContextSwitchTo(oldcontext);
+               portal->holdStore = NULL;
+       }
 
-       PortalResetHeapMemory(portal);
-       MemoryContextFree((MemoryContext) &portal->variable,
-                                         (Pointer) portal->name);
-       AllocSetReset(&portal->variable.setData);       /* XXX log */
+       /* delete tuplestore storage, if any */
+       if (portal->holdContext)
+               MemoryContextDelete(portal->holdContext);
 
-       if (portal != BlankPortal)
-               MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
+       /* release subsidiary storage */
+       MemoryContextDelete(PortalGetHeapMemory(portal));
+
+       /* release portal struct (it's in PortalMemory) */
+       pfree(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.
+/*
+ * DropDependentPortals
+ *             Drop any portals using the specified context as queryContext.
  *
- * Exceptions:
- *             BadState if called when disabled.
- *             BadState if called when not in PortalHeapMemory context.
- *             BadArg if mode is invalid.
- * ----------------
+ * This is normally used to make sure we can safely drop a prepared statement.
  */
-static void
-PortalResetHeapMemory(Portal portal)
+void
+DropDependentPortals(MemoryContext queryContext)
 {
-       PortalHeapMemory context;
-       MemoryContext currentContext;
+       HASH_SEQ_STATUS status;
+       PortalHashEnt *hentry;
 
-       context = PortalGetHeapMemory(portal);
+       hash_seq_init(&status, PortalHashTable);
 
-       if (PointerIsValid(context->block))
+       while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
        {
-               /* save present context */
-               currentContext = MemoryContextSwitchTo((MemoryContext) context);
-
-               do
-               {
-                       EndPortalAllocMode();
-               } while (PointerIsValid(context->block));
+               Portal          portal = hentry->portal;
 
-               /* restore context */
-               MemoryContextSwitchTo(currentContext);
+               if (portal->queryContext == queryContext)
+                       PortalDrop(portal, false);
        }
 }
 
+
 /*
- * StartPortalAllocMode --
- *             Starts a new block of portal heap allocation using mode and limit;
- *             the current block is disabled until EndPortalAllocMode is called.
+ * Pre-commit processing for portals.
  *
- * Note:
- *             Note blocks may be stacked and restored arbitarily.
- *             The semantics of mode and limit are described in aset.h.
+ * Any holdable cursors created in this transaction need to be converted to
+ * materialized form, since we are going to close down the executor and
+ * release locks.  Remove all other portals created in this transaction.
+ * Portals remaining from prior transactions should be left untouched.
  *
- * Exceptions:
- *             BadState if called when disabled.
- *             BadState if called when not in PortalHeapMemory context.
- *             BadArg if mode is invalid.
+ * XXX This assumes that portals can be deleted in a random order, ie,
+ * no portal has a reference to any other (at least not one that will be
+ * exercised during deletion). I think this is okay at the moment, but
+ * we've had bugs of that ilk in the past.  Keep a close eye on cursor
+ * references...
  */
 void
-StartPortalAllocMode(AllocMode mode, Size limit)
+AtCommit_Portals(void)
 {
-       PortalHeapMemory context;
-
-       AssertState(PortalManagerEnabled);
-       AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
-       /* AssertArg(AllocModeIsValid); */
+       HASH_SEQ_STATUS status;
+       PortalHashEnt *hentry;
+       TransactionId xact = GetCurrentTransactionId();
 
-       context = (PortalHeapMemory) CurrentMemoryContext;
+       hash_seq_init(&status, PortalHashTable);
 
-       /* 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));
+       while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
+       {
+               Portal          portal = hentry->portal;
 
-       /* XXX careful, context->block has never been stacked => bad state */
+               /*
+                * Do not touch active portals --- this can only happen in the
+                * case of a multi-transaction utility command, such as VACUUM.
+                */
+               if (portal->portalActive)
+                       continue;
 
-       AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
+               if (portal->cursorOptions & CURSOR_OPT_HOLD)
+               {
+                       /*
+                        * Do nothing to cursors held over from a previous
+                        * transaction.
+                        */
+                       if (portal->createXact != xact)
+                               continue;
+
+                       /*
+                        * We are exiting the transaction that created a holdable
+                        * cursor.      Instead of dropping the portal, prepare it for
+                        * access by later transactions.
+                        *
+                        * Note that PersistHoldablePortal() must release all resources
+                        * used by the portal that are local to the creating
+                        * transaction.
+                        */
+                       PortalCreateHoldStore(portal);
+                       PersistHoldablePortal(portal);
+               }
+               else
+               {
+                       /* Zap all non-holdable portals */
+                       PortalDrop(portal, false);
+               }
+       }
 }
 
 /*
- * EndPortalAllocMode --
- *             Ends current block of portal heap allocation; previous block is
- *             reenabled.
+ * Abort processing for portals.
  *
- * Note:
- *             Note blocks may be stacked and restored arbitarily.
+ * At this point we reset the "active" flags and run the cleanup hook if
+ * present, but we can't release memory until the cleanup call.
  *
- * Exceptions:
- *             BadState if called when disabled.
- *             BadState if called when not in PortalHeapMemory context.
+ * The reason we need to reset active is so that we can replace the unnamed
+ * portal, else we'll fail to execute ROLLBACK when it arrives.  Also, we
+ * want to run the cleanup hook now to be certain it knows that we had an
+ * error abort and not successful conclusion.
  */
 void
-EndPortalAllocMode()
+AtAbort_Portals(void)
 {
-       PortalHeapMemory context;
+       HASH_SEQ_STATUS status;
+       PortalHashEnt *hentry;
+       TransactionId xact = GetCurrentTransactionId();
 
-       AssertState(PortalManagerEnabled);
-       AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
+       hash_seq_init(&status, PortalHashTable);
 
-       context = (PortalHeapMemory) CurrentMemoryContext;
-       AssertState(PointerIsValid(context->block));            /* XXX Trap(...) */
+       while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
+       {
+               Portal          portal = hentry->portal;
 
-       /* free current mode */
-       AllocSetReset(&HEAPMEMBLOCK(context)->setData);
-       MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
-                                         context->block);
+               portal->portalActive = false;
 
-       /* restore previous mode */
-       context->block = FixedStackPop(&context->stackData);
-}
+               /*
+                * Do nothing else to cursors held over from a previous
+                * transaction. (This test must include checking CURSOR_OPT_HOLD,
+                * else we will fail to clean up a VACUUM portal if it fails after
+                * its first sub-transaction.)
+                */
+               if (portal->createXact != xact &&
+                       (portal->cursorOptions & CURSOR_OPT_HOLD))
+                       continue;
 
-/*
- * 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);
+               /* let portalcmds.c clean up the state it knows about */
+               if (PointerIsValid(portal->cleanup))
+               {
+                       (*portal->cleanup) (portal, true);
+                       portal->cleanup = NULL;
+               }
+       }
 }
 
 /*
- * PortalGetHeapMemory --
- *             Returns heap memory context for a given portal.
+ * Post-abort cleanup for portals.
  *
- * Exceptions:
- *             BadState if called when disabled.
- *             BadArg if portal is invalid.
+ * Delete all portals not held over from prior transactions.
  */
-PortalHeapMemory
-PortalGetHeapMemory(Portal portal)
+void
+AtCleanup_Portals(void)
 {
-       return (&portal->heap);
-}
+       HASH_SEQ_STATUS status;
+       PortalHashEnt *hentry;
+       TransactionId xact = GetCurrentTransactionId();
 
-/*
- * 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)));
-}
+       hash_seq_init(&status, PortalHashTable);
 
-/*
- * 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)));
-}
+       while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
+       {
+               Portal          portal = hentry->portal;
 
-/*
- * 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)));
-}
+               /*
+                * Let's just make sure no one's active...
+                */
+               portal->portalActive = false;
 
-#endif
+               /*
+                * Do nothing else to cursors held over from a previous
+                * transaction. (This test must include checking CURSOR_OPT_HOLD,
+                * else we will fail to clean up a VACUUM portal if it fails after
+                * its first sub-transaction.)
+                */
+               if (portal->createXact != xact &&
+                       (portal->cursorOptions & CURSOR_OPT_HOLD))
+                       continue;
 
-/*
- * 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)));
+               /* Else zap it with prejudice. */
+               PortalDrop(portal, true);
+       }
 }