#include "postgres.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/portalcmds.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
Go to the source code of this file.
#define MAX_PORTALNAME_LEN NAMEDATALEN |
Definition at line 44 of file portalmem.c.
#define PortalHashTableDelete | ( | PORTAL | ) |
do { \ PortalHashEnt *hentry; \ \ hentry = (PortalHashEnt *) hash_search(PortalHashTable, \ PORTAL->name, HASH_REMOVE, NULL); \ if (hentry == NULL) \ elog(WARNING, "trying to delete portal name that does not exist"); \ } while(0)
Definition at line 79 of file portalmem.c.
Referenced by PortalDrop().
#define PortalHashTableInsert | ( | PORTAL, | ||
NAME | ||||
) |
do { \ PortalHashEnt *hentry; bool found; \ \ hentry = (PortalHashEnt *) hash_search(PortalHashTable, \ (NAME), HASH_ENTER, &found); \ 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)
Definition at line 66 of file portalmem.c.
Referenced by CreatePortal().
#define PortalHashTableLookup | ( | NAME, | ||
PORTAL | ||||
) |
do { \ PortalHashEnt *hentry; \ \ hentry = (PortalHashEnt *) hash_search(PortalHashTable, \ (NAME), HASH_FIND, NULL); \ if (hentry) \ PORTAL = hentry->portal; \ else \ PORTAL = NULL; \ } while(0)
Definition at line 54 of file portalmem.c.
Referenced by GetPortalByName().
#define PORTALS_PER_USER 16 |
Definition at line 36 of file portalmem.c.
Referenced by EnablePortalManager().
typedef struct portalhashent PortalHashEnt |
void AtAbort_Portals | ( | void | ) |
Definition at line 736 of file portalmem.c.
References PortalData::cleanup, PortalData::createSubid, hash_seq_init(), hash_seq_search(), InvalidSubTransactionId, MarkPortalFailed(), MemoryContextDeleteChildren(), NULL, PointerIsValid, portalhashent::portal, PORTAL_ACTIVE, PORTAL_READY, PortalGetHeapMemory, PortalReleaseCachedPlan(), PortalData::resowner, and PortalData::status.
Referenced by AbortTransaction().
{ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; /* Any portal that was actually running has to be considered broken */ if (portal->status == PORTAL_ACTIVE) MarkPortalFailed(portal); /* * Do nothing else to cursors held over from a previous transaction. */ if (portal->createSubid == InvalidSubTransactionId) continue; /* * If it was created in the current transaction, we can't do normal * shutdown on a READY portal either; it might refer to objects * created in the failed transaction. See comments in * AtSubAbort_Portals. */ if (portal->status == PORTAL_READY) MarkPortalFailed(portal); /* * Allow portalcmds.c to clean up the state it knows about, if we * haven't already. */ if (PointerIsValid(portal->cleanup)) { (*portal->cleanup) (portal); portal->cleanup = NULL; } /* drop cached plan reference, if any */ PortalReleaseCachedPlan(portal); /* * Any resources belonging to the portal will be released in the * upcoming transaction-wide cleanup; they will be gone before we run * PortalDrop. */ portal->resowner = NULL; /* * Although we can't delete the portal data structure proper, we can * release any memory in subsidiary contexts, such as executor state. * The cleanup hook was the last thing that might have needed data * there. */ MemoryContextDeleteChildren(PortalGetHeapMemory(portal)); } }
void AtCleanup_Portals | ( | void | ) |
Definition at line 801 of file portalmem.c.
References Assert, PortalData::cleanup, PortalData::createSubid, hash_seq_init(), hash_seq_search(), InvalidSubTransactionId, NULL, portalhashent::portal, PORTAL_ACTIVE, PortalDrop(), PortalData::portalPinned, PortalData::resowner, and PortalData::status.
Referenced by CleanupTransaction().
{ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; /* Do nothing to cursors held over from a previous transaction */ if (portal->createSubid == InvalidSubTransactionId) { Assert(portal->status != PORTAL_ACTIVE); Assert(portal->resowner == NULL); continue; } /* * If a portal is still pinned, forcibly unpin it. PortalDrop will not * let us drop the portal otherwise. Whoever pinned the portal was * interrupted by the abort too and won't try to use it anymore. */ if (portal->portalPinned) portal->portalPinned = false; /* We had better not be calling any user-defined code here */ Assert(portal->cleanup == NULL); /* Zap it. */ PortalDrop(portal, false); } }
void AtSubAbort_Portals | ( | SubTransactionId | mySubid, | |
SubTransactionId | parentSubid, | |||
ResourceOwner | parentXactOwner | |||
) |
Definition at line 875 of file portalmem.c.
References PortalData::cleanup, PortalData::createSubid, hash_seq_init(), hash_seq_search(), MarkPortalFailed(), MemoryContextDeleteChildren(), NULL, PointerIsValid, portalhashent::portal, PORTAL_ACTIVE, PORTAL_READY, PortalGetHeapMemory, PortalReleaseCachedPlan(), PortalData::resowner, and PortalData::status.
Referenced by AbortSubTransaction().
{ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->createSubid != mySubid) continue; /* * Force any live portals of my own subtransaction into FAILED state. * We have to do this because they might refer to objects created or * changed in the failed subtransaction, leading to crashes if * execution is resumed, or even if we just try to run ExecutorEnd. * (Note we do NOT do this to upper-level portals, since they cannot * have such references and hence may be able to continue.) */ if (portal->status == PORTAL_READY || portal->status == PORTAL_ACTIVE) MarkPortalFailed(portal); /* * Allow portalcmds.c to clean up the state it knows about, if we * haven't already. */ if (PointerIsValid(portal->cleanup)) { (*portal->cleanup) (portal); portal->cleanup = NULL; } /* drop cached plan reference, if any */ PortalReleaseCachedPlan(portal); /* * Any resources belonging to the portal will be released in the * upcoming transaction-wide cleanup; they will be gone before we run * PortalDrop. */ portal->resowner = NULL; /* * Although we can't delete the portal data structure proper, we can * release any memory in subsidiary contexts, such as executor state. * The cleanup hook was the last thing that might have needed data * there. */ MemoryContextDeleteChildren(PortalGetHeapMemory(portal)); } }
void AtSubCleanup_Portals | ( | SubTransactionId | mySubid | ) |
Definition at line 940 of file portalmem.c.
References Assert, PortalData::cleanup, PortalData::createSubid, hash_seq_init(), hash_seq_search(), NULL, portalhashent::portal, PortalDrop(), and PortalData::portalPinned.
Referenced by CleanupSubTransaction().
{ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->createSubid != mySubid) continue; /* * If a portal is still pinned, forcibly unpin it. PortalDrop will not * let us drop the portal otherwise. Whoever pinned the portal was * interrupted by the abort too and won't try to use it anymore. */ if (portal->portalPinned) portal->portalPinned = false; /* We had better not be calling any user-defined code here */ Assert(portal->cleanup == NULL); /* Zap it. */ PortalDrop(portal, false); } }
void AtSubCommit_Portals | ( | SubTransactionId | mySubid, | |
SubTransactionId | parentSubid, | |||
ResourceOwner | parentXactOwner | |||
) |
Definition at line 843 of file portalmem.c.
References PortalData::createSubid, hash_seq_init(), hash_seq_search(), NULL, portalhashent::portal, ResourceOwnerNewParent(), and PortalData::resowner.
Referenced by CommitSubTransaction().
{ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->createSubid == mySubid) { portal->createSubid = parentSubid; if (portal->resowner) ResourceOwnerNewParent(portal->resowner, parentXactOwner); } } }
Portal CreateNewPortal | ( | void | ) |
Definition at line 253 of file portalmem.c.
References CreatePortal(), GetPortalByName(), and NULL.
Referenced by ExecuteQuery(), and SPI_cursor_open_internal().
{ static unsigned int unnamed_portal_count = 0; char portalname[MAX_PORTALNAME_LEN]; /* Select a nonconflicting name */ for (;;) { unnamed_portal_count++; sprintf(portalname, "<unnamed portal %u>", unnamed_portal_count); if (GetPortalByName(portalname) == NULL) break; } return CreatePortal(portalname, false, false); }
Definition at line 196 of file portalmem.c.
References ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), AssertArg, PortalData::atEnd, PortalData::atStart, PortalData::cleanup, PortalData::createSubid, PortalData::creation_time, PortalData::cursorOptions, CurTransactionResourceOwner, ereport, errcode(), errmsg(), ERROR, GetCurrentStatementStartTimestamp(), GetCurrentSubTransactionId(), GetPortalByName(), PortalData::heap, MemoryContextAllocZero(), PointerIsValid, PortalDrop(), PortalHashTableInsert, PortalIsValid, ResourceOwnerCreate(), PortalData::resowner, PortalData::status, PortalData::strategy, PortalData::visible, and WARNING.
Referenced by CreateNewPortal(), exec_bind_message(), exec_simple_query(), PerformCursorOpen(), and SPI_cursor_open_internal().
{ Portal portal; AssertArg(PointerIsValid(name)); portal = GetPortalByName(name); if (PortalIsValid(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); } /* make new portal structure */ portal = (Portal) MemoryContextAllocZero(PortalMemory, sizeof *portal); /* initialize portal heap context; typically it won't store much */ portal->heap = AllocSetContextCreate(PortalMemory, "PortalHeapMemory", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); /* create a resource owner for the portal */ portal->resowner = ResourceOwnerCreate(CurTransactionResourceOwner, "Portal"); /* initialize portal fields that don't start off zero */ portal->status = PORTAL_NEW; portal->cleanup = PortalCleanup; portal->createSubid = GetCurrentSubTransactionId(); portal->strategy = PORTAL_MULTI_QUERY; portal->cursorOptions = CURSOR_OPT_NO_SCROLL; portal->atStart = true; portal->atEnd = true; /* disallow fetches until query is set */ portal->visible = true; portal->creation_time = GetCurrentStatementStartTimestamp(); /* put portal in table (sets portal->name) */ PortalHashTableInsert(portal, name); return portal; }
void EnablePortalManager | ( | void | ) |
Definition at line 102 of file portalmem.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, HASHCTL::entrysize, hash_create(), HASH_ELEM, HASHCTL::keysize, NULL, PORTALS_PER_USER, and TopMemoryContext.
Referenced by InitPostgres().
{ 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 as a guess of how many hash table entries to * create, initially */ PortalHashTable = hash_create("Portal hash", PORTALS_PER_USER, &ctl, HASH_ELEM); }
Portal GetPortalByName | ( | const char * | name | ) |
Definition at line 130 of file portalmem.c.
References PointerIsValid, and PortalHashTableLookup.
Referenced by CreateNewPortal(), CreatePortal(), exec_describe_portal_message(), exec_execute_message(), exec_simple_query(), execCurrentOf(), FetchStatementTargetList(), PerformPortalClose(), PerformPortalFetch(), PLy_cursor_close(), PLy_cursor_dealloc(), PLy_cursor_fetch(), PLy_cursor_iternext(), PostgresMain(), SPI_cursor_find(), UtilityReturnsTuples(), and UtilityTupleDescriptor().
{ Portal portal; if (PointerIsValid(name)) PortalHashTableLookup(name, portal); else portal = NULL; return portal; }
void MarkPortalDone | ( | Portal | portal | ) |
Definition at line 412 of file portalmem.c.
References Assert, PortalData::cleanup, PointerIsValid, PORTAL_ACTIVE, and PortalData::status.
Referenced by PortalRun().
{ /* Perform the state transition */ Assert(portal->status == PORTAL_ACTIVE); portal->status = PORTAL_DONE; /* * Allow portalcmds.c to clean up the state it knows about. We might as * well do that now, since the portal can't be executed any more. * * In some cases involving execution of a ROLLBACK command in an already * aborted transaction, this prevents an assertion failure caused by * reaching AtCleanup_Portals with the cleanup hook still unexecuted. */ if (PointerIsValid(portal->cleanup)) { (*portal->cleanup) (portal); portal->cleanup = NULL; } }
void MarkPortalFailed | ( | Portal | portal | ) |
Definition at line 440 of file portalmem.c.
References Assert, PortalData::cleanup, PointerIsValid, PORTAL_DONE, and PortalData::status.
Referenced by AtAbort_Portals(), AtSubAbort_Portals(), PersistHoldablePortal(), PortalRun(), PortalRunFetch(), and PortalStart().
{ /* Perform the state transition */ Assert(portal->status != PORTAL_DONE); portal->status = PORTAL_FAILED; /* * Allow portalcmds.c to clean up the state it knows about. We might as * well do that now, since the portal can't be executed any more. * * In some cases involving cleanup of an already aborted transaction, this * prevents an assertion failure caused by reaching AtCleanup_Portals with * the cleanup hook still unexecuted. */ if (PointerIsValid(portal->cleanup)) { (*portal->cleanup) (portal); portal->cleanup = NULL; } }
Datum pg_cursor | ( | PG_FUNCTION_ARGS | ) |
Definition at line 972 of file portalmem.c.
References ReturnSetInfo::allowedModes, BoolGetDatum, BOOLOID, CreateTemplateTupleDesc(), PortalData::creation_time, CStringGetTextDatum, CURSOR_OPT_BINARY, CURSOR_OPT_HOLD, CURSOR_OPT_SCROLL, PortalData::cursorOptions, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg(), ERROR, hash_seq_init(), hash_seq_search(), IsA, MemoryContextSwitchTo(), MemSet, PortalData::name, NULL, ReturnSetInfo::returnMode, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SFRM_Materialize_Random, PortalData::sourceText, TEXTOID, TimestampTzGetDatum, TIMESTAMPTZOID, TupleDescInitEntry(), tuplestore_begin_heap(), tuplestore_donestoring, tuplestore_putvalues(), values, PortalData::visible, and work_mem.
{ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; HASH_SEQ_STATUS hash_seq; PortalHashEnt *hentry; /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); /* need to build tuplestore in query context */ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); /* * build tupdesc for result tuples. This must match the definition of the * pg_cursors view in system_views.sql */ tupdesc = CreateTemplateTupleDesc(6, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_holdable", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_binary", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable", BOOLOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "creation_time", TIMESTAMPTZOID, -1, 0); /* * We put all the tuples into a tuplestore in one scan of the hashtable. * This avoids any issue of the hashtable possibly changing between calls. */ tupstore = tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, false, work_mem); /* generate junk in short-term context */ MemoryContextSwitchTo(oldcontext); hash_seq_init(&hash_seq, PortalHashTable); while ((hentry = hash_seq_search(&hash_seq)) != NULL) { Portal portal = hentry->portal; Datum values[6]; bool nulls[6]; /* report only "visible" entries */ if (!portal->visible) continue; MemSet(nulls, 0, sizeof(nulls)); values[0] = CStringGetTextDatum(portal->name); values[1] = CStringGetTextDatum(portal->sourceText); values[2] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_HOLD); values[3] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_BINARY); values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL); values[5] = TimestampTzGetDatum(portal->creation_time); tuplestore_putvalues(tupstore, tupdesc, values, nulls); } /* clean up and return the tuplestore */ tuplestore_donestoring(tupstore); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; rsinfo->setDesc = tupdesc; return (Datum) 0; }
void PinPortal | ( | Portal | portal | ) |
Definition at line 388 of file portalmem.c.
References elog, ERROR, and PortalData::portalPinned.
Referenced by exec_for_query().
{ if (portal->portalPinned) elog(ERROR, "portal already pinned"); portal->portalPinned = true; }
void PortalCreateHoldStore | ( | Portal | portal | ) |
Definition at line 347 of file portalmem.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, CURSOR_OPT_SCROLL, PortalData::cursorOptions, PortalData::holdContext, PortalData::holdStore, MemoryContextSwitchTo(), NULL, tuplestore_begin_heap(), and work_mem.
Referenced by FillPortalStore(), and PreCommit_Portals().
{ MemoryContext oldcxt; Assert(portal->holdContext == NULL); Assert(portal->holdStore == NULL); /* * 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, "PortalHoldContext", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); /* * Create the tuple store, selecting cross-transaction temp files, and * enabling random access only if cursor requires scrolling. * * XXX: Should maintenance_work_mem be used for the portal size? */ oldcxt = MemoryContextSwitchTo(portal->holdContext); portal->holdStore = tuplestore_begin_heap(portal->cursorOptions & CURSOR_OPT_SCROLL, true, work_mem); MemoryContextSwitchTo(oldcxt); }
void PortalDefineQuery | ( | Portal | portal, | |
const char * | prepStmtName, | |||
const char * | sourceText, | |||
const char * | commandTag, | |||
List * | stmts, | |||
CachedPlan * | cplan | |||
) |
Definition at line 300 of file portalmem.c.
References AssertArg, AssertState, PortalData::commandTag, PortalData::cplan, NIL, NULL, PORTAL_NEW, PortalIsValid, PortalData::prepStmtName, PortalData::sourceText, PortalData::status, and PortalData::stmts.
Referenced by exec_bind_message(), exec_simple_query(), ExecuteQuery(), PerformCursorOpen(), and SPI_cursor_open_internal().
{ AssertArg(PortalIsValid(portal)); AssertState(portal->status == PORTAL_NEW); AssertArg(sourceText != NULL); AssertArg(commandTag != NULL || stmts == NIL); portal->prepStmtName = prepStmtName; portal->sourceText = sourceText; portal->commandTag = commandTag; portal->stmts = stmts; portal->cplan = cplan; portal->status = PORTAL_DEFINED; }
Definition at line 466 of file portalmem.c.
References AssertArg, PortalData::cleanup, ereport, errcode(), errmsg(), ERROR, PortalData::holdContext, PortalData::holdStore, MemoryContextDelete(), MemoryContextSwitchTo(), PortalData::name, pfree(), PointerIsValid, PORTAL_ACTIVE, PORTAL_FAILED, PortalGetHeapMemory, PortalHashTableDelete, PortalIsValid, PortalData::portalPinned, PortalReleaseCachedPlan(), RESOURCE_RELEASE_AFTER_LOCKS, RESOURCE_RELEASE_BEFORE_LOCKS, RESOURCE_RELEASE_LOCKS, ResourceOwnerDelete(), ResourceOwnerRelease(), PortalData::resowner, PortalData::status, and tuplestore_end().
Referenced by AtCleanup_Portals(), AtSubCleanup_Portals(), CreatePortal(), exec_simple_query(), ExecuteQuery(), PerformPortalClose(), PortalHashTableDeleteAll(), PostgresMain(), PreCommit_Portals(), and SPI_cursor_close().
{ AssertArg(PortalIsValid(portal)); /* * Don't allow dropping a pinned portal, it's still needed by whoever * pinned it. Not sure if the PORTAL_ACTIVE case can validly happen or * not... */ if (portal->portalPinned || portal->status == PORTAL_ACTIVE) ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_STATE), errmsg("cannot drop active portal \"%s\"", portal->name))); /* * Allow portalcmds.c to clean up the state it knows about, in particular * shutting down the executor if still active. This step potentially runs * user-defined code so failure has to be expected. It's the cleanup * hook's responsibility to not try to do that more than once, in the case * that failure occurs and then we come back to drop the portal again * during transaction abort. * * Note: in most paths of control, this will have been done already in * MarkPortalDone or MarkPortalFailed. We're just making sure. */ if (PointerIsValid(portal->cleanup)) { (*portal->cleanup) (portal); portal->cleanup = NULL; } /* * Remove portal from hash table. Because we do this here, 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); /* drop cached plan reference, if any */ PortalReleaseCachedPlan(portal); /* * Release any resources still attached to the portal. There are several * cases being covered here: * * Top transaction commit (indicated by isTopCommit): normally we should * do nothing here and let the regular end-of-transaction resource * releasing mechanism handle these resources too. However, if we have a * FAILED portal (eg, a cursor that got an error), we'd better clean up * its resources to avoid resource-leakage warning messages. * * Sub transaction commit: never comes here at all, since we don't kill * any portals in AtSubCommit_Portals(). * * Main or sub transaction abort: we will do nothing here because * portal->resowner was already set NULL; the resources were already * cleaned up in transaction abort. * * Ordinary portal drop: must release resources. However, if the portal * is not FAILED then we do not release its locks. The locks become the * responsibility of the transaction's ResourceOwner (since it is the * parent of the portal's owner) and will be released when the transaction * eventually ends. */ if (portal->resowner && (!isTopCommit || portal->status == PORTAL_FAILED)) { bool isCommit = (portal->status != PORTAL_FAILED); ResourceOwnerRelease(portal->resowner, RESOURCE_RELEASE_BEFORE_LOCKS, isCommit, false); ResourceOwnerRelease(portal->resowner, RESOURCE_RELEASE_LOCKS, isCommit, false); ResourceOwnerRelease(portal->resowner, RESOURCE_RELEASE_AFTER_LOCKS, isCommit, false); ResourceOwnerDelete(portal->resowner); } portal->resowner = NULL; /* * 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; } /* delete tuplestore storage, if any */ if (portal->holdContext) MemoryContextDelete(portal->holdContext); /* release subsidiary storage */ MemoryContextDelete(PortalGetHeapMemory(portal)); /* release portal struct (it's in PortalMemory) */ pfree(portal); }
void PortalHashTableDeleteAll | ( | void | ) |
Definition at line 582 of file portalmem.c.
References hash_seq_init(), hash_seq_search(), hash_seq_term(), NULL, portalhashent::portal, PORTAL_ACTIVE, PortalDrop(), and PortalData::status.
Referenced by DiscardAll(), and PerformPortalClose().
{ HASH_SEQ_STATUS status; PortalHashEnt *hentry; if (PortalHashTable == NULL) return; hash_seq_init(&status, PortalHashTable); while ((hentry = hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; /* Can't close the active portal (the one running the command) */ if (portal->status == PORTAL_ACTIVE) continue; PortalDrop(portal, false); /* Restart the iteration in case that led to other drops */ hash_seq_term(&status); hash_seq_init(&status, PortalHashTable); } }
Definition at line 158 of file portalmem.c.
References IsA, lfirst, and list_length().
Referenced by CachedPlanGetTargetList(), and PlanCacheComputeResultDesc().
{ ListCell *lc; foreach(lc, stmts) { Node *stmt = (Node *) lfirst(lc); if (IsA(stmt, PlannedStmt)) { if (((PlannedStmt *) stmt)->canSetTag) return stmt; } else if (IsA(stmt, Query)) { if (((Query *) stmt)->canSetTag) return stmt; } else { /* Utility stmts are assumed canSetTag if they're the only stmt */ if (list_length(stmts) == 1) return stmt; } } return NULL; }
static void PortalReleaseCachedPlan | ( | Portal | portal | ) | [static] |
Definition at line 326 of file portalmem.c.
References PortalData::cplan, ReleaseCachedPlan(), and PortalData::stmts.
Referenced by AtAbort_Portals(), AtSubAbort_Portals(), PortalDrop(), and PreCommit_Portals().
{ if (portal->cplan) { ReleaseCachedPlan(portal->cplan, false); portal->cplan = NULL; /* * We must also clear portal->stmts which is now a dangling reference * to the cached plan's plan list. This protects any code that might * try to examine the Portal later. */ portal->stmts = NIL; } }
Definition at line 621 of file portalmem.c.
References PortalData::createSubid, CURSOR_OPT_HOLD, PortalData::cursorOptions, elog, ereport, errcode(), errmsg(), ERROR, hash_seq_init(), hash_seq_search(), hash_seq_term(), InvalidSubTransactionId, NULL, PersistHoldablePortal(), portalhashent::portal, PORTAL_ACTIVE, PORTAL_READY, PortalCreateHoldStore(), PortalDrop(), PortalData::portalPinned, PortalReleaseCachedPlan(), PortalData::resowner, and PortalData::status.
Referenced by CommitTransaction(), and PrepareTransaction().
{ bool result = false; HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; /* * There should be no pinned portals anymore. Complain if someone * leaked one. */ if (portal->portalPinned) elog(ERROR, "cannot commit while a portal is pinned"); /* * Do not touch active portals --- this can only happen in the case of * a multi-transaction utility command, such as VACUUM. * * Note however that any resource owner attached to such a portal is * still going to go away, so don't leave a dangling pointer. */ if (portal->status == PORTAL_ACTIVE) { portal->resowner = NULL; continue; } /* Is it a holdable portal created in the current xact? */ if ((portal->cursorOptions & CURSOR_OPT_HOLD) && portal->createSubid != InvalidSubTransactionId && portal->status == PORTAL_READY) { /* * We are exiting the transaction that created a holdable cursor. * Instead of dropping the portal, prepare it for access by later * transactions. * * However, if this is PREPARE TRANSACTION rather than COMMIT, * refuse PREPARE, because the semantics seem pretty unclear. */ if (isPrepare) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot PREPARE a transaction that has created a cursor WITH HOLD"))); /* * Note that PersistHoldablePortal() must release all resources * used by the portal that are local to the creating transaction. */ PortalCreateHoldStore(portal); PersistHoldablePortal(portal); /* drop cached plan reference, if any */ PortalReleaseCachedPlan(portal); /* * Any resources belonging to the portal will be released in the * upcoming transaction-wide cleanup; the portal will no longer * have its own resources. */ portal->resowner = NULL; /* * Having successfully exported the holdable cursor, mark it as * not belonging to this transaction. */ portal->createSubid = InvalidSubTransactionId; /* Report we changed state */ result = true; } else if (portal->createSubid == InvalidSubTransactionId) { /* * Do nothing to cursors held over from a previous transaction * (including ones we just froze in a previous cycle of this loop) */ continue; } else { /* Zap all non-holdable portals */ PortalDrop(portal, true); /* Report we changed state */ result = true; } /* * After either freezing or dropping a portal, we have to restart the * iteration, because we could have invoked user-defined code that * caused a drop of the next portal in the hash chain. */ hash_seq_term(&status); hash_seq_init(&status, PortalHashTable); } return result; }
bool ThereAreNoReadyPortals | ( | void | ) |
Definition at line 1060 of file portalmem.c.
References hash_seq_init(), hash_seq_search(), NULL, portalhashent::portal, PORTAL_READY, and PortalData::status.
Referenced by CopyFrom().
{ HASH_SEQ_STATUS status; PortalHashEnt *hentry; hash_seq_init(&status, PortalHashTable); while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL) { Portal portal = hentry->portal; if (portal->status == PORTAL_READY) return false; } return true; }
void UnpinPortal | ( | Portal | portal | ) |
Definition at line 397 of file portalmem.c.
References elog, ERROR, and PortalData::portalPinned.
Referenced by exec_for_query().
{ if (!portal->portalPinned) elog(ERROR, "portal not pinned"); portal->portalPinned = false; }
HTAB* PortalHashTable = NULL [static] |
Definition at line 52 of file portalmem.c.
MemoryContext PortalMemory = NULL [static] |
Definition at line 89 of file portalmem.c.