You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
postgres/src/backend/utils/mmgr/portalmem.c

276 lines
7.0 KiB

/*-------------------------------------------------------------------------
*
* portalmem.c
* backend portal memory context management stuff
*
* Portions Copyright (c) 1996-2002, 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.53 2003/03/11 19:40:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* NOTES
* A "Portal" is a structure used to keep track of cursor queries.
*
* When the backend sees a "declare cursor" query, it allocates a
* "PortalData" structure, plans the query and then stores the query
* in the portal without executing it. Later, when the backend
* sees a
* fetch 1 from FOO
* the system looks up the portal named "FOO" in the portal table,
* gets the planned query and then calls the executor with a count
* of 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". This means we have to be
* careful about memory management.
*
* I hope this makes things clearer to whoever reads this -cim 2/22/91
*/
#include "postgres.h"
#include "executor/executor.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/portal.h"
/*
* estimate of the maximum number of open portals a user would have,
* used in initially sizing the PortalHashTable in EnablePortalManager()
*/
#define PORTALS_PER_USER 64
/* ----------------
* Global state
* ----------------
*/
#define MAX_PORTALNAME_LEN NAMEDATALEN
typedef struct portalhashent
{
char portalname[MAX_PORTALNAME_LEN];
Portal portal;
} PortalHashEnt;
static HTAB *PortalHashTable = NULL;
#define PortalHashTableLookup(NAME, PORTAL) \
do { \
PortalHashEnt *hentry; char key[MAX_PORTALNAME_LEN]; \
\
MemSet(key, 0, MAX_PORTALNAME_LEN); \
snprintf(key, MAX_PORTALNAME_LEN - 1, "%s", NAME); \
hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
key, HASH_FIND, NULL); \
if (hentry) \
PORTAL = hentry->portal; \
else \
PORTAL = NULL; \
} while(0)
#define PortalHashTableInsert(PORTAL) \
do { \
PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
\
MemSet(key, 0, MAX_PORTALNAME_LEN); \
snprintf(key, MAX_PORTALNAME_LEN - 1, "%s", PORTAL->name); \
hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
key, HASH_ENTER, &found); \
if (hentry == NULL) \
elog(ERROR, "out of memory in PortalHashTable"); \
if (found) \
elog(WARNING, "trying to insert a portal name that exists."); \
hentry->portal = PORTAL; \
} while(0)
#define PortalHashTableDelete(PORTAL) \
do { \
PortalHashEnt *hentry; char key[MAX_PORTALNAME_LEN]; \
\
MemSet(key, 0, MAX_PORTALNAME_LEN); \
snprintf(key, MAX_PORTALNAME_LEN - 1, "%s", PORTAL->name); \
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)
static MemoryContext PortalMemory = NULL;
/* ----------------------------------------------------------------
* public portal interface functions
* ----------------------------------------------------------------
*/
/*
* EnablePortalManager
* Enables the portal management module at backend startup.
*/
void
EnablePortalManager(void)
{
HASHCTL ctl;
Assert(PortalMemory == NULL);
PortalMemory = AllocSetContextCreate(TopMemoryContext,
"PortalMemory",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
ctl.keysize = MAX_PORTALNAME_LEN;
ctl.entrysize = sizeof(PortalHashEnt);
/*
* use PORTALS_PER_USER, defined in utils/portal.h 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, or NULL if name not found.
*/
Portal
GetPortalByName(const char *name)
{
Portal portal;
if (PointerIsValid(name))
PortalHashTableLookup(name, portal);
else
portal = NULL;
return portal;
}
/*
* PortalSetQuery
* Attaches a "query" to portal.
*/
void
PortalSetQuery(Portal portal,
QueryDesc *queryDesc,
void (*cleanup) (Portal portal))
{
AssertArg(PortalIsValid(portal));
portal->queryDesc = queryDesc;
portal->cleanup = cleanup;
portal->backwardOK = ExecSupportsBackwardScan(queryDesc->plantree);
portal->atStart = true;
portal->atEnd = false; /* allow fetches */
portal->portalPos = 0;
portal->posOverflow = false;
}
/*
* CreatePortal
* Returns a new portal given a name.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if portal name is invalid.
* "WARNING" if portal name is in use (existing portal is returned!)
*/
Portal
CreatePortal(const char *name)
{
Portal portal;
AssertArg(PointerIsValid(name));
portal = GetPortalByName(name);
if (PortalIsValid(portal))
{
elog(WARNING, "CreatePortal: portal \"%s\" already exists", name);
return portal;
}
/* make new portal structure */
portal = (Portal) MemoryContextAlloc(PortalMemory, sizeof *portal);
/* initialize portal name */
portal->name = MemoryContextStrdup(PortalMemory, name);
/* initialize portal heap context */
portal->heap = AllocSetContextCreate(PortalMemory,
"PortalHeapMemory",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* initialize portal query */
portal->queryDesc = NULL;
portal->cleanup = NULL;
portal->backwardOK = false;
portal->atStart = true;
portal->atEnd = true; /* disallow fetches until query is set */
portal->portalPos = 0;
portal->posOverflow = false;
/* put portal in table */
PortalHashTableInsert(portal);
return portal;
}
/*
* PortalDrop
* Destroys portal.
*
* Exceptions:
* BadState if called when disabled.
* BadArg if portal is invalid.
*/
void
PortalDrop(Portal portal)
{
AssertArg(PortalIsValid(portal));
/* remove portal from hash table */
PortalHashTableDelete(portal);
/* reset portal */
if (PointerIsValid(portal->cleanup))
(*portal->cleanup) (portal);
/* release subsidiary storage */
MemoryContextDelete(PortalGetHeapMemory(portal));
/* release name and portal data (both are in PortalMemory) */
pfree(portal->name);
pfree(portal);
}
/*
* Destroy all portals created in the current transaction (ie, all of them).
*
* 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
AtEOXact_portals(void)
{
HASH_SEQ_STATUS status;
PortalHashEnt *hentry;
hash_seq_init(&status, PortalHashTable);
while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
PortalDrop(hentry->portal);
}