PostgreSQL Source Code  git master
portalmem.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/portalcmds.h"
#include "miscadmin.h"
#include "storage/ipc.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
#include "utils/timestamp.h"
Include dependency graph for portalmem.c:

Go to the source code of this file.

Data Structures

struct  portalhashent
 

Macros

#define PORTALS_PER_USER   16
 
#define MAX_PORTALNAME_LEN   NAMEDATALEN
 
#define PortalHashTableLookup(NAME, PORTAL)
 
#define PortalHashTableInsert(PORTAL, NAME)
 
#define PortalHashTableDelete(PORTAL)
 

Typedefs

typedef struct portalhashent PortalHashEnt
 

Functions

void EnablePortalManager (void)
 
Portal GetPortalByName (const char *name)
 
PlannedStmtPortalGetPrimaryStmt (Portal portal)
 
Portal CreatePortal (const char *name, bool allowDup, bool dupSilent)
 
Portal CreateNewPortal (void)
 
void PortalDefineQuery (Portal portal, const char *prepStmtName, const char *sourceText, CommandTag commandTag, List *stmts, CachedPlan *cplan)
 
static void PortalReleaseCachedPlan (Portal portal)
 
void PortalCreateHoldStore (Portal portal)
 
void PinPortal (Portal portal)
 
void UnpinPortal (Portal portal)
 
void MarkPortalActive (Portal portal)
 
void MarkPortalDone (Portal portal)
 
void MarkPortalFailed (Portal portal)
 
void PortalDrop (Portal portal, bool isTopCommit)
 
void PortalHashTableDeleteAll (void)
 
static void HoldPortal (Portal portal)
 
bool PreCommit_Portals (bool isPrepare)
 
void AtAbort_Portals (void)
 
void AtCleanup_Portals (void)
 
void PortalErrorCleanup (void)
 
void AtSubCommit_Portals (SubTransactionId mySubid, SubTransactionId parentSubid, ResourceOwner parentXactOwner)
 
void AtSubAbort_Portals (SubTransactionId mySubid, SubTransactionId parentSubid, ResourceOwner myXactOwner, ResourceOwner parentXactOwner)
 
void AtSubCleanup_Portals (SubTransactionId mySubid)
 
Datum pg_cursor (PG_FUNCTION_ARGS)
 
bool ThereAreNoReadyPortals (void)
 
void HoldPinnedPortals (void)
 

Variables

static HTABPortalHashTable = NULL
 
static MemoryContext TopPortalContext = NULL
 

Macro Definition Documentation

◆ MAX_PORTALNAME_LEN

#define MAX_PORTALNAME_LEN   NAMEDATALEN

Definition at line 46 of file portalmem.c.

Referenced by CreateNewPortal(), and EnablePortalManager().

◆ PortalHashTableDelete

#define PortalHashTableDelete (   PORTAL)
Value:
do { \
PortalHashEnt *hentry; \
\
PORTAL->name, HASH_REMOVE, NULL); \
if (hentry == NULL) \
elog(WARNING, "trying to delete portal name that does not exist"); \
} while(0)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
#define WARNING
Definition: elog.h:40
static HTAB * PortalHashTable
Definition: portalmem.c:54

Definition at line 81 of file portalmem.c.

Referenced by PortalDrop().

◆ PortalHashTableInsert

#define PortalHashTableInsert (   PORTAL,
  NAME 
)
Value:
do { \
PortalHashEnt *hentry; bool found; \
\
(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)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
#define ERROR
Definition: elog.h:43
static HTAB * PortalHashTable
Definition: portalmem.c:54

Definition at line 68 of file portalmem.c.

Referenced by CreatePortal().

◆ PortalHashTableLookup

#define PortalHashTableLookup (   NAME,
  PORTAL 
)
Value:
do { \
PortalHashEnt *hentry; \
\
(NAME), HASH_FIND, NULL); \
if (hentry) \
PORTAL = hentry->portal; \
else \
PORTAL = NULL; \
} while(0)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
static HTAB * PortalHashTable
Definition: portalmem.c:54

Definition at line 56 of file portalmem.c.

Referenced by GetPortalByName().

◆ PORTALS_PER_USER

#define PORTALS_PER_USER   16

Definition at line 38 of file portalmem.c.

Referenced by EnablePortalManager().

Typedef Documentation

◆ PortalHashEnt

typedef struct portalhashent PortalHashEnt

Function Documentation

◆ AtAbort_Portals()

void AtAbort_Portals ( void  )

Definition at line 774 of file portalmem.c.

References PortalData::autoHeld, PortalData::cleanup, PortalData::createSubid, hash_seq_init(), hash_seq_search(), InvalidSubTransactionId, MarkPortalFailed(), MemoryContextDeleteChildren(), PointerIsValid, portalhashent::portal, PORTAL_ACTIVE, PORTAL_READY, PortalData::portalContext, PortalReleaseCachedPlan(), PortalData::resowner, shmem_exit_inprogress, status(), and PortalData::status.

Referenced by AbortOutOfAnyTransaction(), and AbortTransaction().

775 {
777  PortalHashEnt *hentry;
778 
779  hash_seq_init(&status, PortalHashTable);
780 
781  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
782  {
783  Portal portal = hentry->portal;
784 
785  /*
786  * When elog(FATAL) is progress, we need to set the active portal to
787  * failed, so that PortalCleanup() doesn't run the executor shutdown.
788  */
789  if (portal->status == PORTAL_ACTIVE && shmem_exit_inprogress)
790  MarkPortalFailed(portal);
791 
792  /*
793  * Do nothing else to cursors held over from a previous transaction.
794  */
795  if (portal->createSubid == InvalidSubTransactionId)
796  continue;
797 
798  /*
799  * Do nothing to auto-held cursors. This is similar to the case of a
800  * cursor from a previous transaction, but it could also be that the
801  * cursor was auto-held in this transaction, so it wants to live on.
802  */
803  if (portal->autoHeld)
804  continue;
805 
806  /*
807  * If it was created in the current transaction, we can't do normal
808  * shutdown on a READY portal either; it might refer to objects
809  * created in the failed transaction. See comments in
810  * AtSubAbort_Portals.
811  */
812  if (portal->status == PORTAL_READY)
813  MarkPortalFailed(portal);
814 
815  /*
816  * Allow portalcmds.c to clean up the state it knows about, if we
817  * haven't already.
818  */
819  if (PointerIsValid(portal->cleanup))
820  {
821  portal->cleanup(portal);
822  portal->cleanup = NULL;
823  }
824 
825  /* drop cached plan reference, if any */
826  PortalReleaseCachedPlan(portal);
827 
828  /*
829  * Any resources belonging to the portal will be released in the
830  * upcoming transaction-wide cleanup; they will be gone before we run
831  * PortalDrop.
832  */
833  portal->resowner = NULL;
834 
835  /*
836  * Although we can't delete the portal data structure proper, we can
837  * release any memory in subsidiary contexts, such as executor state.
838  * The cleanup hook was the last thing that might have needed data
839  * there. But leave active portals alone.
840  */
841  if (portal->status != PORTAL_ACTIVE)
843  }
844 }
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:309
bool autoHeld
Definition: portal.h:152
void(* cleanup)(Portal portal)
Definition: portal.h:122
MemoryContext portalContext
Definition: portal.h:120
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:257
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:441
PortalStatus status
Definition: portal.h:150
#define InvalidSubTransactionId
Definition: c.h:526
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
ResourceOwner resowner
Definition: portal.h:121
bool shmem_exit_inprogress
Definition: ipc.c:45
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define PointerIsValid(pointer)
Definition: c.h:639

◆ AtCleanup_Portals()

void AtCleanup_Portals ( void  )

Definition at line 851 of file portalmem.c.

References Assert, PortalData::autoHeld, PortalData::cleanup, PortalData::createSubid, elog, hash_seq_init(), hash_seq_search(), InvalidSubTransactionId, PortalData::name, PointerIsValid, portalhashent::portal, PORTAL_ACTIVE, PortalDrop(), PortalData::portalPinned, PortalData::resowner, status(), PortalData::status, and WARNING.

Referenced by CleanupTransaction().

852 {
854  PortalHashEnt *hentry;
855 
856  hash_seq_init(&status, PortalHashTable);
857 
858  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
859  {
860  Portal portal = hentry->portal;
861 
862  /*
863  * Do not touch active portals --- this can only happen in the case of
864  * a multi-transaction command.
865  */
866  if (portal->status == PORTAL_ACTIVE)
867  continue;
868 
869  /*
870  * Do nothing to cursors held over from a previous transaction or
871  * auto-held ones.
872  */
873  if (portal->createSubid == InvalidSubTransactionId || portal->autoHeld)
874  {
875  Assert(portal->status != PORTAL_ACTIVE);
876  Assert(portal->resowner == NULL);
877  continue;
878  }
879 
880  /*
881  * If a portal is still pinned, forcibly unpin it. PortalDrop will not
882  * let us drop the portal otherwise. Whoever pinned the portal was
883  * interrupted by the abort too and won't try to use it anymore.
884  */
885  if (portal->portalPinned)
886  portal->portalPinned = false;
887 
888  /*
889  * We had better not call any user-defined code during cleanup, so if
890  * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
891  */
892  if (PointerIsValid(portal->cleanup))
893  {
894  elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
895  portal->cleanup = NULL;
896  }
897 
898  /* Zap it. */
899  PortalDrop(portal, false);
900  }
901 }
bool autoHeld
Definition: portal.h:152
void(* cleanup)(Portal portal)
Definition: portal.h:122
const char * name
Definition: portal.h:118
bool portalPinned
Definition: portal.h:151
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
#define WARNING
Definition: elog.h:40
#define Assert(condition)
Definition: c.h:745
PortalStatus status
Definition: portal.h:150
#define InvalidSubTransactionId
Definition: c.h:526
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
ResourceOwner resowner
Definition: portal.h:121
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:467
#define elog(elevel,...)
Definition: elog.h:214
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define PointerIsValid(pointer)
Definition: c.h:639

◆ AtSubAbort_Portals()

void AtSubAbort_Portals ( SubTransactionId  mySubid,
SubTransactionId  parentSubid,
ResourceOwner  myXactOwner,
ResourceOwner  parentXactOwner 
)

Definition at line 970 of file portalmem.c.

References PortalData::activeSubid, PortalData::cleanup, PortalData::createSubid, hash_seq_init(), hash_seq_search(), MarkPortalFailed(), MemoryContextDeleteChildren(), PointerIsValid, portalhashent::portal, PORTAL_ACTIVE, PORTAL_FAILED, PORTAL_READY, PortalData::portalContext, PortalReleaseCachedPlan(), ResourceOwnerNewParent(), PortalData::resowner, status(), and PortalData::status.

Referenced by AbortOutOfAnyTransaction(), and AbortSubTransaction().

974 {
976  PortalHashEnt *hentry;
977 
978  hash_seq_init(&status, PortalHashTable);
979 
980  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
981  {
982  Portal portal = hentry->portal;
983 
984  /* Was it created in this subtransaction? */
985  if (portal->createSubid != mySubid)
986  {
987  /* No, but maybe it was used in this subtransaction? */
988  if (portal->activeSubid == mySubid)
989  {
990  /* Maintain activeSubid until the portal is removed */
991  portal->activeSubid = parentSubid;
992 
993  /*
994  * A MarkPortalActive() caller ran an upper-level portal in
995  * this subtransaction and left the portal ACTIVE. This can't
996  * happen, but force the portal into FAILED state for the same
997  * reasons discussed below.
998  *
999  * We assume we can get away without forcing upper-level READY
1000  * portals to fail, even if they were run and then suspended.
1001  * In theory a suspended upper-level portal could have
1002  * acquired some references to objects that are about to be
1003  * destroyed, but there should be sufficient defenses against
1004  * such cases: the portal's original query cannot contain such
1005  * references, and any references within, say, cached plans of
1006  * PL/pgSQL functions are not from active queries and should
1007  * be protected by revalidation logic.
1008  */
1009  if (portal->status == PORTAL_ACTIVE)
1010  MarkPortalFailed(portal);
1011 
1012  /*
1013  * Also, if we failed it during the current subtransaction
1014  * (either just above, or earlier), reattach its resource
1015  * owner to the current subtransaction's resource owner, so
1016  * that any resources it still holds will be released while
1017  * cleaning up this subtransaction. This prevents some corner
1018  * cases wherein we might get Asserts or worse while cleaning
1019  * up objects created during the current subtransaction
1020  * (because they're still referenced within this portal).
1021  */
1022  if (portal->status == PORTAL_FAILED && portal->resowner)
1023  {
1024  ResourceOwnerNewParent(portal->resowner, myXactOwner);
1025  portal->resowner = NULL;
1026  }
1027  }
1028  /* Done if it wasn't created in this subtransaction */
1029  continue;
1030  }
1031 
1032  /*
1033  * Force any live portals of my own subtransaction into FAILED state.
1034  * We have to do this because they might refer to objects created or
1035  * changed in the failed subtransaction, leading to crashes within
1036  * ExecutorEnd when portalcmds.c tries to close down the portal.
1037  * Currently, every MarkPortalActive() caller ensures it updates the
1038  * portal status again before relinquishing control, so ACTIVE can't
1039  * happen here. If it does happen, dispose the portal like existing
1040  * MarkPortalActive() callers would.
1041  */
1042  if (portal->status == PORTAL_READY ||
1043  portal->status == PORTAL_ACTIVE)
1044  MarkPortalFailed(portal);
1045 
1046  /*
1047  * Allow portalcmds.c to clean up the state it knows about, if we
1048  * haven't already.
1049  */
1050  if (PointerIsValid(portal->cleanup))
1051  {
1052  portal->cleanup(portal);
1053  portal->cleanup = NULL;
1054  }
1055 
1056  /* drop cached plan reference, if any */
1057  PortalReleaseCachedPlan(portal);
1058 
1059  /*
1060  * Any resources belonging to the portal will be released in the
1061  * upcoming transaction-wide cleanup; they will be gone before we run
1062  * PortalDrop.
1063  */
1064  portal->resowner = NULL;
1065 
1066  /*
1067  * Although we can't delete the portal data structure proper, we can
1068  * release any memory in subsidiary contexts, such as executor state.
1069  * The cleanup hook was the last thing that might have needed data
1070  * there.
1071  */
1073  }
1074 }
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:309
void(* cleanup)(Portal portal)
Definition: portal.h:122
MemoryContext portalContext
Definition: portal.h:120
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:257
SubTransactionId activeSubid
Definition: portal.h:132
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:441
PortalStatus status
Definition: portal.h:150
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:772
ResourceOwner resowner
Definition: portal.h:121
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define PointerIsValid(pointer)
Definition: c.h:639

◆ AtSubCleanup_Portals()

void AtSubCleanup_Portals ( SubTransactionId  mySubid)

Definition at line 1083 of file portalmem.c.

References PortalData::cleanup, PortalData::createSubid, elog, hash_seq_init(), hash_seq_search(), PortalData::name, PointerIsValid, portalhashent::portal, PortalDrop(), PortalData::portalPinned, status(), and WARNING.

Referenced by CleanupSubTransaction().

1084 {
1086  PortalHashEnt *hentry;
1087 
1088  hash_seq_init(&status, PortalHashTable);
1089 
1090  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1091  {
1092  Portal portal = hentry->portal;
1093 
1094  if (portal->createSubid != mySubid)
1095  continue;
1096 
1097  /*
1098  * If a portal is still pinned, forcibly unpin it. PortalDrop will not
1099  * let us drop the portal otherwise. Whoever pinned the portal was
1100  * interrupted by the abort too and won't try to use it anymore.
1101  */
1102  if (portal->portalPinned)
1103  portal->portalPinned = false;
1104 
1105  /*
1106  * We had better not call any user-defined code during cleanup, so if
1107  * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
1108  */
1109  if (PointerIsValid(portal->cleanup))
1110  {
1111  elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
1112  portal->cleanup = NULL;
1113  }
1114 
1115  /* Zap it. */
1116  PortalDrop(portal, false);
1117  }
1118 }
void(* cleanup)(Portal portal)
Definition: portal.h:122
const char * name
Definition: portal.h:118
bool portalPinned
Definition: portal.h:151
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
#define WARNING
Definition: elog.h:40
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:467
#define elog(elevel,...)
Definition: elog.h:214
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
#define PointerIsValid(pointer)
Definition: c.h:639

◆ AtSubCommit_Portals()

void AtSubCommit_Portals ( SubTransactionId  mySubid,
SubTransactionId  parentSubid,
ResourceOwner  parentXactOwner 
)

Definition at line 936 of file portalmem.c.

References PortalData::activeSubid, PortalData::createSubid, hash_seq_init(), hash_seq_search(), portalhashent::portal, ResourceOwnerNewParent(), PortalData::resowner, and status().

Referenced by CommitSubTransaction().

939 {
941  PortalHashEnt *hentry;
942 
943  hash_seq_init(&status, PortalHashTable);
944 
945  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
946  {
947  Portal portal = hentry->portal;
948 
949  if (portal->createSubid == mySubid)
950  {
951  portal->createSubid = parentSubid;
952  if (portal->resowner)
953  ResourceOwnerNewParent(portal->resowner, parentXactOwner);
954  }
955  if (portal->activeSubid == mySubid)
956  portal->activeSubid = parentSubid;
957  }
958 }
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
SubTransactionId activeSubid
Definition: portal.h:132
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:772
ResourceOwner resowner
Definition: portal.h:121
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ CreateNewPortal()

Portal CreateNewPortal ( void  )

Definition at line 234 of file portalmem.c.

References CreatePortal(), GetPortalByName(), MAX_PORTALNAME_LEN, portalhashent::portalname, and sprintf.

Referenced by ExecuteQuery(), and SPI_cursor_open_internal().

235 {
236  static unsigned int unnamed_portal_count = 0;
237 
238  char portalname[MAX_PORTALNAME_LEN];
239 
240  /* Select a nonconflicting name */
241  for (;;)
242  {
243  unnamed_portal_count++;
244  sprintf(portalname, "<unnamed portal %u>", unnamed_portal_count);
245  if (GetPortalByName(portalname) == NULL)
246  break;
247  }
248 
249  return CreatePortal(portalname, false, false);
250 }
Portal CreatePortal(const char *name, bool allowDup, bool dupSilent)
Definition: portalmem.c:175
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
#define sprintf
Definition: port.h:195
#define MAX_PORTALNAME_LEN
Definition: portalmem.c:46

◆ CreatePortal()

Portal CreatePortal ( const char *  name,
bool  allowDup,
bool  dupSilent 
)

Definition at line 175 of file portalmem.c.

References PortalData::activeSubid, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, AssertArg, PortalData::atEnd, PortalData::atStart, PortalData::cleanup, PortalData::createSubid, PortalData::creation_time, CURSOR_OPT_NO_SCROLL, PortalData::cursorOptions, CurTransactionResourceOwner, ereport, errcode(), errmsg(), ERROR, GetCurrentStatementStartTimestamp(), GetCurrentSubTransactionId(), GetPortalByName(), MemoryContextAllocZero(), MemoryContextSetIdentifier(), PortalData::name, PointerIsValid, portalhashent::portal, PORTAL_MULTI_QUERY, PORTAL_NEW, PortalCleanup(), PortalData::portalContext, 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().

176 {
177  Portal portal;
178 
180 
181  portal = GetPortalByName(name);
182  if (PortalIsValid(portal))
183  {
184  if (!allowDup)
185  ereport(ERROR,
186  (errcode(ERRCODE_DUPLICATE_CURSOR),
187  errmsg("cursor \"%s\" already exists", name)));
188  if (!dupSilent)
190  (errcode(ERRCODE_DUPLICATE_CURSOR),
191  errmsg("closing existing cursor \"%s\"",
192  name)));
193  PortalDrop(portal, false);
194  }
195 
196  /* make new portal structure */
197  portal = (Portal) MemoryContextAllocZero(TopPortalContext, sizeof *portal);
198 
199  /* initialize portal context; typically it won't store much */
201  "PortalContext",
203 
204  /* create a resource owner for the portal */
206  "Portal");
207 
208  /* initialize portal fields that don't start off zero */
209  portal->status = PORTAL_NEW;
210  portal->cleanup = PortalCleanup;
212  portal->activeSubid = portal->createSubid;
213  portal->strategy = PORTAL_MULTI_QUERY;
215  portal->atStart = true;
216  portal->atEnd = true; /* disallow fetches until query is set */
217  portal->visible = true;
219 
220  /* put portal in table (sets portal->name) */
221  PortalHashTableInsert(portal, name);
222 
223  /* for named portals reuse portal->name copy */
224  MemoryContextSetIdentifier(portal->portalContext, portal->name[0] ? portal->name : "<unnamed>");
225 
226  return portal;
227 }
#define AllocSetContextCreate
Definition: memutils.h:170
bool atEnd
Definition: portal.h:191
bool visible
Definition: portal.h:196
void(* cleanup)(Portal portal)
Definition: portal.h:122
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:143
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
int errcode(int sqlerrcode)
Definition: elog.c:610
void PortalCleanup(Portal portal)
Definition: portalcmds.c:264
MemoryContext portalContext
Definition: portal.h:120
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2710
static MemoryContext TopPortalContext
Definition: portalmem.c:91
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:43
struct PortalData * Portal
Definition: portal.h:113
PortalStrategy strategy
Definition: portal.h:145
SubTransactionId createSubid
Definition: portal.h:131
#define AssertArg(condition)
Definition: c.h:747
TimestampTz creation_time
Definition: portal.h:195
#define WARNING
Definition: elog.h:40
#define PortalIsValid(p)
Definition: portal.h:203
SubTransactionId activeSubid
Definition: portal.h:132
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:840
#define ereport(elevel,...)
Definition: elog.h:144
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:330
PortalStatus status
Definition: portal.h:150
const char * name
Definition: encode.c:561
ResourceOwner resowner
Definition: portal.h:121
bool atStart
Definition: portal.h:190
int errmsg(const char *fmt,...)
Definition: elog.c:824
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:467
int cursorOptions
Definition: portal.h:146
#define PortalHashTableInsert(PORTAL, NAME)
Definition: portalmem.c:68
#define PointerIsValid(pointer)
Definition: c.h:639
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:807
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:422

◆ EnablePortalManager()

void EnablePortalManager ( void  )

Definition at line 104 of file portalmem.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, HASHCTL::entrysize, hash_create(), HASH_ELEM, HASHCTL::keysize, MAX_PORTALNAME_LEN, PORTALS_PER_USER, and TopMemoryContext.

Referenced by InitPostgres().

105 {
106  HASHCTL ctl;
107 
108  Assert(TopPortalContext == NULL);
109 
111  "TopPortalContext",
113 
115  ctl.entrysize = sizeof(PortalHashEnt);
116 
117  /*
118  * use PORTALS_PER_USER as a guess of how many hash table entries to
119  * create, initially
120  */
122  &ctl, HASH_ELEM);
123 }
#define AllocSetContextCreate
Definition: memutils.h:170
#define HASH_ELEM
Definition: hsearch.h:85
#define PORTALS_PER_USER
Definition: portalmem.c:38
Size entrysize
Definition: hsearch.h:72
static MemoryContext TopPortalContext
Definition: portalmem.c:91
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
MemoryContext TopMemoryContext
Definition: mcxt.c:44
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
Size keysize
Definition: hsearch.h:71
struct portalhashent PortalHashEnt
#define Assert(condition)
Definition: c.h:745
#define MAX_PORTALNAME_LEN
Definition: portalmem.c:46
static HTAB * PortalHashTable
Definition: portalmem.c:54

◆ GetPortalByName()

Portal GetPortalByName ( const char *  name)

Definition at line 130 of file portalmem.c.

References PointerIsValid, portalhashent::portal, 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().

131 {
132  Portal portal;
133 
134  if (PointerIsValid(name))
135  PortalHashTableLookup(name, portal);
136  else
137  portal = NULL;
138 
139  return portal;
140 }
const char * name
Definition: encode.c:561
#define PortalHashTableLookup(NAME, PORTAL)
Definition: portalmem.c:56
#define PointerIsValid(pointer)
Definition: c.h:639

◆ HoldPinnedPortals()

void HoldPinnedPortals ( void  )

Definition at line 1245 of file portalmem.c.

References PortalData::autoHeld, elog, ereport, errcode(), errmsg(), ERROR, hash_seq_init(), hash_seq_search(), HoldPortal(), portalhashent::portal, PORTAL_ONE_SELECT, PORTAL_READY, PortalData::portalPinned, status(), PortalData::status, and PortalData::strategy.

Referenced by _SPI_commit(), and _SPI_rollback().

1246 {
1248  PortalHashEnt *hentry;
1249 
1250  hash_seq_init(&status, PortalHashTable);
1251 
1252  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1253  {
1254  Portal portal = hentry->portal;
1255 
1256  if (portal->portalPinned && !portal->autoHeld)
1257  {
1258  /*
1259  * Doing transaction control, especially abort, inside a cursor
1260  * loop that is not read-only, for example using UPDATE ...
1261  * RETURNING, has weird semantics issues. Also, this
1262  * implementation wouldn't work, because such portals cannot be
1263  * held. (The core grammar enforces that only SELECT statements
1264  * can drive a cursor, but for example PL/pgSQL does not restrict
1265  * it.)
1266  */
1267  if (portal->strategy != PORTAL_ONE_SELECT)
1268  ereport(ERROR,
1269  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
1270  errmsg("cannot perform transaction commands inside a cursor loop that is not read-only")));
1271 
1272  /* Verify it's in a suitable state to be held */
1273  if (portal->status != PORTAL_READY)
1274  elog(ERROR, "pinned portal is not ready to be auto-held");
1275 
1276  HoldPortal(portal);
1277  portal->autoHeld = true;
1278  }
1279  }
1280 }
bool autoHeld
Definition: portal.h:152
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
bool portalPinned
Definition: portal.h:151
PortalStrategy strategy
Definition: portal.h:145
Portal portal
Definition: portalmem.c:51
#define ereport(elevel,...)
Definition: elog.h:144
static void HoldPortal(Portal portal)
Definition: portalmem.c:632
PortalStatus status
Definition: portal.h:150
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ HoldPortal()

static void HoldPortal ( Portal  portal)
static

Definition at line 632 of file portalmem.c.

References PortalData::activeSubid, PortalData::createSubid, InvalidSubTransactionId, PersistHoldablePortal(), PortalCreateHoldStore(), PortalReleaseCachedPlan(), and PortalData::resowner.

Referenced by HoldPinnedPortals(), and PreCommit_Portals().

633 {
634  /*
635  * Note that PersistHoldablePortal() must release all resources used by
636  * the portal that are local to the creating transaction.
637  */
638  PortalCreateHoldStore(portal);
639  PersistHoldablePortal(portal);
640 
641  /* drop cached plan reference, if any */
642  PortalReleaseCachedPlan(portal);
643 
644  /*
645  * Any resources belonging to the portal will be released in the upcoming
646  * transaction-wide cleanup; the portal will no longer have its own
647  * resources.
648  */
649  portal->resowner = NULL;
650 
651  /*
652  * Having successfully exported the holdable cursor, mark it as not
653  * belonging to this transaction.
654  */
657 }
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:309
SubTransactionId createSubid
Definition: portal.h:131
SubTransactionId activeSubid
Definition: portal.h:132
void PersistHoldablePortal(Portal portal)
Definition: portalcmds.c:317
#define InvalidSubTransactionId
Definition: c.h:526
void PortalCreateHoldStore(Portal portal)
Definition: portalmem.c:330
ResourceOwner resowner
Definition: portal.h:121

◆ MarkPortalActive()

void MarkPortalActive ( Portal  portal)

Definition at line 394 of file portalmem.c.

References PortalData::activeSubid, ereport, errcode(), errmsg(), ERROR, GetCurrentSubTransactionId(), PortalData::name, PORTAL_ACTIVE, PORTAL_READY, and PortalData::status.

Referenced by PersistHoldablePortal(), PortalRun(), and PortalRunFetch().

395 {
396  /* For safety, this is a runtime test not just an Assert */
397  if (portal->status != PORTAL_READY)
398  ereport(ERROR,
399  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
400  errmsg("portal \"%s\" cannot be run", portal->name)));
401  /* Perform the state transition */
402  portal->status = PORTAL_ACTIVE;
404 }
int errcode(int sqlerrcode)
Definition: elog.c:610
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:43
SubTransactionId activeSubid
Definition: portal.h:132
#define ereport(elevel,...)
Definition: elog.h:144
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
PortalStatus status
Definition: portal.h:150
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ MarkPortalDone()

void MarkPortalDone ( Portal  portal)

Definition at line 413 of file portalmem.c.

References Assert, PortalData::cleanup, PointerIsValid, PORTAL_ACTIVE, PORTAL_DONE, and PortalData::status.

Referenced by PortalRun().

414 {
415  /* Perform the state transition */
416  Assert(portal->status == PORTAL_ACTIVE);
417  portal->status = PORTAL_DONE;
418 
419  /*
420  * Allow portalcmds.c to clean up the state it knows about. We might as
421  * well do that now, since the portal can't be executed any more.
422  *
423  * In some cases involving execution of a ROLLBACK command in an already
424  * aborted transaction, this is necessary, or we'd reach AtCleanup_Portals
425  * with the cleanup hook still unexecuted.
426  */
427  if (PointerIsValid(portal->cleanup))
428  {
429  portal->cleanup(portal);
430  portal->cleanup = NULL;
431  }
432 }
void(* cleanup)(Portal portal)
Definition: portal.h:122
#define Assert(condition)
Definition: c.h:745
PortalStatus status
Definition: portal.h:150
#define PointerIsValid(pointer)
Definition: c.h:639

◆ MarkPortalFailed()

void MarkPortalFailed ( Portal  portal)

Definition at line 441 of file portalmem.c.

References Assert, PortalData::cleanup, PointerIsValid, PORTAL_DONE, PORTAL_FAILED, and PortalData::status.

Referenced by AtAbort_Portals(), AtSubAbort_Portals(), PersistHoldablePortal(), PortalRun(), PortalRunFetch(), and PortalStart().

442 {
443  /* Perform the state transition */
444  Assert(portal->status != PORTAL_DONE);
445  portal->status = PORTAL_FAILED;
446 
447  /*
448  * Allow portalcmds.c to clean up the state it knows about. We might as
449  * well do that now, since the portal can't be executed any more.
450  *
451  * In some cases involving cleanup of an already aborted transaction, this
452  * is necessary, or we'd reach AtCleanup_Portals with the cleanup hook
453  * still unexecuted.
454  */
455  if (PointerIsValid(portal->cleanup))
456  {
457  portal->cleanup(portal);
458  portal->cleanup = NULL;
459  }
460 }
void(* cleanup)(Portal portal)
Definition: portal.h:122
#define Assert(condition)
Definition: c.h:745
PortalStatus status
Definition: portal.h:150
#define PointerIsValid(pointer)
Definition: c.h:639

◆ pg_cursor()

Datum pg_cursor ( PG_FUNCTION_ARGS  )

Definition at line 1122 of file portalmem.c.

References ReturnSetInfo::allowedModes, BoolGetDatum, 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, portalhashent::portal, ReturnSetInfo::returnMode, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SFRM_Materialize_Random, PortalData::sourceText, TimestampTzGetDatum, TupleDescInitEntry(), tuplestore_begin_heap(), tuplestore_donestoring, tuplestore_putvalues(), values, PortalData::visible, and work_mem.

1123 {
1124  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1125  TupleDesc tupdesc;
1126  Tuplestorestate *tupstore;
1127  MemoryContext per_query_ctx;
1128  MemoryContext oldcontext;
1129  HASH_SEQ_STATUS hash_seq;
1130  PortalHashEnt *hentry;
1131 
1132  /* check to see if caller supports us returning a tuplestore */
1133  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1134  ereport(ERROR,
1135  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1136  errmsg("set-valued function called in context that cannot accept a set")));
1137  if (!(rsinfo->allowedModes & SFRM_Materialize))
1138  ereport(ERROR,
1139  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1140  errmsg("materialize mode required, but it is not allowed in this context")));
1141 
1142  /* need to build tuplestore in query context */
1143  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1144  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1145 
1146  /*
1147  * build tupdesc for result tuples. This must match the definition of the
1148  * pg_cursors view in system_views.sql
1149  */
1150  tupdesc = CreateTemplateTupleDesc(6);
1151  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
1152  TEXTOID, -1, 0);
1153  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
1154  TEXTOID, -1, 0);
1155  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_holdable",
1156  BOOLOID, -1, 0);
1157  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_binary",
1158  BOOLOID, -1, 0);
1159  TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable",
1160  BOOLOID, -1, 0);
1161  TupleDescInitEntry(tupdesc, (AttrNumber) 6, "creation_time",
1162  TIMESTAMPTZOID, -1, 0);
1163 
1164  /*
1165  * We put all the tuples into a tuplestore in one scan of the hashtable.
1166  * This avoids any issue of the hashtable possibly changing between calls.
1167  */
1168  tupstore =
1170  false, work_mem);
1171 
1172  /* generate junk in short-term context */
1173  MemoryContextSwitchTo(oldcontext);
1174 
1175  hash_seq_init(&hash_seq, PortalHashTable);
1176  while ((hentry = hash_seq_search(&hash_seq)) != NULL)
1177  {
1178  Portal portal = hentry->portal;
1179  Datum values[6];
1180  bool nulls[6];
1181 
1182  /* report only "visible" entries */
1183  if (!portal->visible)
1184  continue;
1185 
1186  MemSet(nulls, 0, sizeof(nulls));
1187 
1188  values[0] = CStringGetTextDatum(portal->name);
1189  values[1] = CStringGetTextDatum(portal->sourceText);
1190  values[2] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_HOLD);
1191  values[3] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_BINARY);
1192  values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
1193  values[5] = TimestampTzGetDatum(portal->creation_time);
1194 
1195  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1196  }
1197 
1198  /* clean up and return the tuplestore */
1199  tuplestore_donestoring(tupstore);
1200 
1201  rsinfo->returnMode = SFRM_Materialize;
1202  rsinfo->setResult = tupstore;
1203  rsinfo->setDesc = tupdesc;
1204 
1205  return (Datum) 0;
1206 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
bool visible
Definition: portal.h:196
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
#define CURSOR_OPT_BINARY
Definition: parsenodes.h:2708
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2712
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
#define MemSet(start, val, len)
Definition: c.h:949
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:43
#define TimestampTzGetDatum(X)
Definition: timestamp.h:32
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
TimestampTz creation_time
Definition: portal.h:195
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
uintptr_t Datum
Definition: postgres.h:367
int work_mem
Definition: globals.c:121
const char * sourceText
Definition: portal.h:135
#define BoolGetDatum(X)
Definition: postgres.h:402
#define ereport(elevel,...)
Definition: elog.h:144
int allowedModes
Definition: execnodes.h:305
SetFunctionReturnMode returnMode
Definition: execnodes.h:307
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:233
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
Tuplestorestate * setResult
Definition: execnodes.h:310
static Datum values[MAXATTR]
Definition: bootstrap.c:165
ExprContext * econtext
Definition: execnodes.h:303
TupleDesc setDesc
Definition: execnodes.h:311
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2709
#define CStringGetTextDatum(s)
Definition: builtins.h:86
static HTAB * PortalHashTable
Definition: portalmem.c:54
int cursorOptions
Definition: portal.h:146
int16 AttrNumber
Definition: attnum.h:21

◆ PinPortal()

void PinPortal ( Portal  portal)

Definition at line 370 of file portalmem.c.

References elog, ERROR, and PortalData::portalPinned.

Referenced by exec_for_query(), plperl_spi_query(), plperl_spi_query_prepared(), PLy_cursor_plan(), and PLy_cursor_query().

371 {
372  if (portal->portalPinned)
373  elog(ERROR, "portal already pinned");
374 
375  portal->portalPinned = true;
376 }
#define ERROR
Definition: elog.h:43
bool portalPinned
Definition: portal.h:151
#define elog(elevel,...)
Definition: elog.h:214

◆ PortalCreateHoldStore()

void PortalCreateHoldStore ( Portal  portal)

Definition at line 330 of file portalmem.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CURSOR_OPT_SCROLL, PortalData::cursorOptions, PortalData::holdContext, PortalData::holdSnapshot, PortalData::holdStore, MemoryContextSwitchTo(), tuplestore_begin_heap(), and work_mem.

Referenced by FillPortalStore(), and HoldPortal().

331 {
332  MemoryContext oldcxt;
333 
334  Assert(portal->holdContext == NULL);
335  Assert(portal->holdStore == NULL);
336  Assert(portal->holdSnapshot == NULL);
337 
338  /*
339  * Create the memory context that is used for storage of the tuple set.
340  * Note this is NOT a child of the portal's portalContext.
341  */
342  portal->holdContext =
344  "PortalHoldContext",
346 
347  /*
348  * Create the tuple store, selecting cross-transaction temp files, and
349  * enabling random access only if cursor requires scrolling.
350  *
351  * XXX: Should maintenance_work_mem be used for the portal size?
352  */
353  oldcxt = MemoryContextSwitchTo(portal->holdContext);
354 
355  portal->holdStore =
357  true, work_mem);
358 
359  MemoryContextSwitchTo(oldcxt);
360 }
#define AllocSetContextCreate
Definition: memutils.h:170
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext holdContext
Definition: portal.h:169
static MemoryContext TopPortalContext
Definition: portalmem.c:91
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:121
#define Assert(condition)
Definition: c.h:745
Snapshot holdSnapshot
Definition: portal.h:179
Tuplestorestate * holdStore
Definition: portal.h:168
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2709
int cursorOptions
Definition: portal.h:146

◆ PortalDefineQuery()

void PortalDefineQuery ( Portal  portal,
const char *  prepStmtName,
const char *  sourceText,
CommandTag  commandTag,
List stmts,
CachedPlan cplan 
)

Definition at line 281 of file portalmem.c.

References AssertArg, AssertState, QueryCompletion::commandTag, PortalData::commandTag, PortalData::cplan, NIL, QueryCompletion::nprocessed, PORTAL_DEFINED, PORTAL_NEW, PortalIsValid, PortalData::prepStmtName, PortalData::qc, PortalData::sourceText, PortalData::status, and PortalData::stmts.

Referenced by exec_bind_message(), exec_simple_query(), ExecuteQuery(), PerformCursorOpen(), and SPI_cursor_open_internal().

287 {
288  AssertArg(PortalIsValid(portal));
289  AssertState(portal->status == PORTAL_NEW);
290 
291  AssertArg(sourceText != NULL);
292  AssertArg(commandTag != CMDTAG_UNKNOWN || stmts == NIL);
293 
294  portal->prepStmtName = prepStmtName;
295  portal->sourceText = sourceText;
296  portal->qc.commandTag = commandTag;
297  portal->qc.nprocessed = 0;
298  portal->commandTag = commandTag;
299  portal->stmts = stmts;
300  portal->cplan = cplan;
301  portal->status = PORTAL_DEFINED;
302 }
#define NIL
Definition: pg_list.h:65
#define AssertState(condition)
Definition: c.h:748
CommandTag commandTag
Definition: portal.h:136
CachedPlan * cplan
Definition: portal.h:139
List * stmts
Definition: portal.h:138
uint64 nprocessed
Definition: cmdtag.h:31
#define AssertArg(condition)
Definition: c.h:747
#define PortalIsValid(p)
Definition: portal.h:203
const char * sourceText
Definition: portal.h:135
CommandTag commandTag
Definition: cmdtag.h:30
QueryCompletion qc
Definition: portal.h:137
PortalStatus status
Definition: portal.h:150
const char * prepStmtName
Definition: portal.h:119

◆ PortalDrop()

void PortalDrop ( Portal  portal,
bool  isTopCommit 
)

Definition at line 467 of file portalmem.c.

References AssertArg, PortalData::cleanup, ereport, errcode(), errmsg(), ERROR, PortalData::holdContext, PortalData::holdSnapshot, PortalData::holdStore, MemoryContextDelete(), MemoryContextSwitchTo(), PortalData::name, pfree(), PointerIsValid, PORTAL_ACTIVE, PORTAL_FAILED, PortalData::portalContext, PortalHashTableDelete, PortalIsValid, PortalData::portalPinned, PortalReleaseCachedPlan(), RESOURCE_RELEASE_AFTER_LOCKS, RESOURCE_RELEASE_BEFORE_LOCKS, RESOURCE_RELEASE_LOCKS, ResourceOwnerDelete(), ResourceOwnerRelease(), PortalData::resowner, PortalData::status, tuplestore_end(), and UnregisterSnapshotFromOwner().

Referenced by AtCleanup_Portals(), AtSubCleanup_Portals(), CreatePortal(), exec_simple_query(), ExecuteQuery(), PerformPortalClose(), PortalErrorCleanup(), PortalHashTableDeleteAll(), PostgresMain(), PreCommit_Portals(), and SPI_cursor_close().

468 {
469  AssertArg(PortalIsValid(portal));
470 
471  /*
472  * Don't allow dropping a pinned portal, it's still needed by whoever
473  * pinned it.
474  */
475  if (portal->portalPinned)
476  ereport(ERROR,
477  (errcode(ERRCODE_INVALID_CURSOR_STATE),
478  errmsg("cannot drop pinned portal \"%s\"", portal->name)));
479 
480  /*
481  * Not sure if the PORTAL_ACTIVE case can validly happen or not...
482  */
483  if (portal->status == PORTAL_ACTIVE)
484  ereport(ERROR,
485  (errcode(ERRCODE_INVALID_CURSOR_STATE),
486  errmsg("cannot drop active portal \"%s\"", portal->name)));
487 
488  /*
489  * Allow portalcmds.c to clean up the state it knows about, in particular
490  * shutting down the executor if still active. This step potentially runs
491  * user-defined code so failure has to be expected. It's the cleanup
492  * hook's responsibility to not try to do that more than once, in the case
493  * that failure occurs and then we come back to drop the portal again
494  * during transaction abort.
495  *
496  * Note: in most paths of control, this will have been done already in
497  * MarkPortalDone or MarkPortalFailed. We're just making sure.
498  */
499  if (PointerIsValid(portal->cleanup))
500  {
501  portal->cleanup(portal);
502  portal->cleanup = NULL;
503  }
504 
505  /*
506  * Remove portal from hash table. Because we do this here, we will not
507  * come back to try to remove the portal again if there's any error in the
508  * subsequent steps. Better to leak a little memory than to get into an
509  * infinite error-recovery loop.
510  */
511  PortalHashTableDelete(portal);
512 
513  /* drop cached plan reference, if any */
514  PortalReleaseCachedPlan(portal);
515 
516  /*
517  * If portal has a snapshot protecting its data, release that. This needs
518  * a little care since the registration will be attached to the portal's
519  * resowner; if the portal failed, we will already have released the
520  * resowner (and the snapshot) during transaction abort.
521  */
522  if (portal->holdSnapshot)
523  {
524  if (portal->resowner)
526  portal->resowner);
527  portal->holdSnapshot = NULL;
528  }
529 
530  /*
531  * Release any resources still attached to the portal. There are several
532  * cases being covered here:
533  *
534  * Top transaction commit (indicated by isTopCommit): normally we should
535  * do nothing here and let the regular end-of-transaction resource
536  * releasing mechanism handle these resources too. However, if we have a
537  * FAILED portal (eg, a cursor that got an error), we'd better clean up
538  * its resources to avoid resource-leakage warning messages.
539  *
540  * Sub transaction commit: never comes here at all, since we don't kill
541  * any portals in AtSubCommit_Portals().
542  *
543  * Main or sub transaction abort: we will do nothing here because
544  * portal->resowner was already set NULL; the resources were already
545  * cleaned up in transaction abort.
546  *
547  * Ordinary portal drop: must release resources. However, if the portal
548  * is not FAILED then we do not release its locks. The locks become the
549  * responsibility of the transaction's ResourceOwner (since it is the
550  * parent of the portal's owner) and will be released when the transaction
551  * eventually ends.
552  */
553  if (portal->resowner &&
554  (!isTopCommit || portal->status == PORTAL_FAILED))
555  {
556  bool isCommit = (portal->status != PORTAL_FAILED);
557 
560  isCommit, false);
563  isCommit, false);
566  isCommit, false);
567  ResourceOwnerDelete(portal->resowner);
568  }
569  portal->resowner = NULL;
570 
571  /*
572  * Delete tuplestore if present. We should do this even under error
573  * conditions; since the tuplestore would have been using cross-
574  * transaction storage, its temp files need to be explicitly deleted.
575  */
576  if (portal->holdStore)
577  {
578  MemoryContext oldcontext;
579 
580  oldcontext = MemoryContextSwitchTo(portal->holdContext);
581  tuplestore_end(portal->holdStore);
582  MemoryContextSwitchTo(oldcontext);
583  portal->holdStore = NULL;
584  }
585 
586  /* delete tuplestore storage, if any */
587  if (portal->holdContext)
589 
590  /* release subsidiary storage */
592 
593  /* release portal struct (it's in TopPortalContext) */
594  pfree(portal);
595 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:212
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:309
void(* cleanup)(Portal portal)
Definition: portal.h:122
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:712
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
MemoryContext holdContext
Definition: portal.h:169
MemoryContext portalContext
Definition: portal.h:120
#define PortalHashTableDelete(PORTAL)
Definition: portalmem.c:81
void pfree(void *pointer)
Definition: mcxt.c:1057
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:43
bool portalPinned
Definition: portal.h:151
#define AssertArg(condition)
Definition: c.h:747
#define PortalIsValid(p)
Definition: portal.h:203
#define ereport(elevel,...)
Definition: elog.h:144
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:478
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:865
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
Snapshot holdSnapshot
Definition: portal.h:179
PortalStatus status
Definition: portal.h:150
ResourceOwner resowner
Definition: portal.h:121
Tuplestorestate * holdStore
Definition: portal.h:168
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define PointerIsValid(pointer)
Definition: c.h:639

◆ PortalErrorCleanup()

void PortalErrorCleanup ( void  )

Definition at line 910 of file portalmem.c.

References PortalData::autoHeld, hash_seq_init(), hash_seq_search(), portalhashent::portal, PortalDrop(), PortalData::portalPinned, and status().

Referenced by PostgresMain().

911 {
913  PortalHashEnt *hentry;
914 
915  hash_seq_init(&status, PortalHashTable);
916 
917  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
918  {
919  Portal portal = hentry->portal;
920 
921  if (portal->autoHeld)
922  {
923  portal->portalPinned = false;
924  PortalDrop(portal, false);
925  }
926  }
927 }
bool autoHeld
Definition: portal.h:152
bool portalPinned
Definition: portal.h:151
Portal portal
Definition: portalmem.c:51
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:467
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ PortalGetPrimaryStmt()

PlannedStmt* PortalGetPrimaryStmt ( Portal  portal)

Definition at line 151 of file portalmem.c.

References PlannedStmt::canSetTag, lfirst_node, and PortalData::stmts.

Referenced by FetchPortalTargetList(), and PortalStart().

152 {
153  ListCell *lc;
154 
155  foreach(lc, portal->stmts)
156  {
157  PlannedStmt *stmt = lfirst_node(PlannedStmt, lc);
158 
159  if (stmt->canSetTag)
160  return stmt;
161  }
162  return NULL;
163 }
List * stmts
Definition: portal.h:138
#define lfirst_node(type, lc)
Definition: pg_list.h:172
bool canSetTag
Definition: plannodes.h:54

◆ PortalHashTableDeleteAll()

void PortalHashTableDeleteAll ( void  )

Definition at line 603 of file portalmem.c.

References hash_seq_init(), hash_seq_search(), hash_seq_term(), portalhashent::portal, PORTAL_ACTIVE, PortalDrop(), status(), and PortalData::status.

Referenced by DiscardAll(), and PerformPortalClose().

604 {
606  PortalHashEnt *hentry;
607 
608  if (PortalHashTable == NULL)
609  return;
610 
611  hash_seq_init(&status, PortalHashTable);
612  while ((hentry = hash_seq_search(&status)) != NULL)
613  {
614  Portal portal = hentry->portal;
615 
616  /* Can't close the active portal (the one running the command) */
617  if (portal->status == PORTAL_ACTIVE)
618  continue;
619 
620  PortalDrop(portal, false);
621 
622  /* Restart the iteration in case that led to other drops */
623  hash_seq_term(&status);
624  hash_seq_init(&status, PortalHashTable);
625  }
626 }
Portal portal
Definition: portalmem.c:51
PortalStatus status
Definition: portal.h:150
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:467
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1477

◆ PortalReleaseCachedPlan()

static void PortalReleaseCachedPlan ( Portal  portal)
static

Definition at line 309 of file portalmem.c.

References PortalData::cplan, NIL, ReleaseCachedPlan(), and PortalData::stmts.

Referenced by AtAbort_Portals(), AtSubAbort_Portals(), HoldPortal(), and PortalDrop().

310 {
311  if (portal->cplan)
312  {
313  ReleaseCachedPlan(portal->cplan, false);
314  portal->cplan = NULL;
315 
316  /*
317  * We must also clear portal->stmts which is now a dangling reference
318  * to the cached plan's plan list. This protects any code that might
319  * try to examine the Portal later.
320  */
321  portal->stmts = NIL;
322  }
323 }
#define NIL
Definition: pg_list.h:65
CachedPlan * cplan
Definition: portal.h:139
List * stmts
Definition: portal.h:138
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1264

◆ PreCommit_Portals()

bool PreCommit_Portals ( bool  isPrepare)

Definition at line 672 of file portalmem.c.

References PortalData::autoHeld, PortalData::createSubid, CURSOR_OPT_HOLD, PortalData::cursorOptions, elog, ereport, errcode(), errmsg(), ERROR, hash_seq_init(), hash_seq_search(), hash_seq_term(), HoldPortal(), PortalData::holdSnapshot, InvalidSubTransactionId, portalhashent::portal, PORTAL_ACTIVE, PORTAL_READY, PortalDrop(), PortalData::portalPinned, PortalData::resowner, status(), PortalData::status, and UnregisterSnapshotFromOwner().

Referenced by CommitTransaction(), and PrepareTransaction().

673 {
674  bool result = false;
676  PortalHashEnt *hentry;
677 
678  hash_seq_init(&status, PortalHashTable);
679 
680  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
681  {
682  Portal portal = hentry->portal;
683 
684  /*
685  * There should be no pinned portals anymore. Complain if someone
686  * leaked one. Auto-held portals are allowed; we assume that whoever
687  * pinned them is managing them.
688  */
689  if (portal->portalPinned && !portal->autoHeld)
690  elog(ERROR, "cannot commit while a portal is pinned");
691 
692  /*
693  * Do not touch active portals --- this can only happen in the case of
694  * a multi-transaction utility command, such as VACUUM, or a commit in
695  * a procedure.
696  *
697  * Note however that any resource owner attached to such a portal is
698  * still going to go away, so don't leave a dangling pointer. Also
699  * unregister any snapshots held by the portal, mainly to avoid
700  * snapshot leak warnings from ResourceOwnerRelease().
701  */
702  if (portal->status == PORTAL_ACTIVE)
703  {
704  if (portal->holdSnapshot)
705  {
706  if (portal->resowner)
708  portal->resowner);
709  portal->holdSnapshot = NULL;
710  }
711  portal->resowner = NULL;
712  continue;
713  }
714 
715  /* Is it a holdable portal created in the current xact? */
716  if ((portal->cursorOptions & CURSOR_OPT_HOLD) &&
718  portal->status == PORTAL_READY)
719  {
720  /*
721  * We are exiting the transaction that created a holdable cursor.
722  * Instead of dropping the portal, prepare it for access by later
723  * transactions.
724  *
725  * However, if this is PREPARE TRANSACTION rather than COMMIT,
726  * refuse PREPARE, because the semantics seem pretty unclear.
727  */
728  if (isPrepare)
729  ereport(ERROR,
730  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
731  errmsg("cannot PREPARE a transaction that has created a cursor WITH HOLD")));
732 
733  HoldPortal(portal);
734 
735  /* Report we changed state */
736  result = true;
737  }
738  else if (portal->createSubid == InvalidSubTransactionId)
739  {
740  /*
741  * Do nothing to cursors held over from a previous transaction
742  * (including ones we just froze in a previous cycle of this loop)
743  */
744  continue;
745  }
746  else
747  {
748  /* Zap all non-holdable portals */
749  PortalDrop(portal, true);
750 
751  /* Report we changed state */
752  result = true;
753  }
754 
755  /*
756  * After either freezing or dropping a portal, we have to restart the
757  * iteration, because we could have invoked user-defined code that
758  * caused a drop of the next portal in the hash chain.
759  */
760  hash_seq_term(&status);
761  hash_seq_init(&status, PortalHashTable);
762  }
763 
764  return result;
765 }
bool autoHeld
Definition: portal.h:152
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2712
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
bool portalPinned
Definition: portal.h:151
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
#define ereport(elevel,...)
Definition: elog.h:144
static void HoldPortal(Portal portal)
Definition: portalmem.c:632
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:865
Snapshot holdSnapshot
Definition: portal.h:179
PortalStatus status
Definition: portal.h:150
#define InvalidSubTransactionId
Definition: c.h:526
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
ResourceOwner resowner
Definition: portal.h:121
int errmsg(const char *fmt,...)
Definition: elog.c:824
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:467
#define elog(elevel,...)
Definition: elog.h:214
static HTAB * PortalHashTable
Definition: portalmem.c:54
int cursorOptions
Definition: portal.h:146
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1477

◆ ThereAreNoReadyPortals()

bool ThereAreNoReadyPortals ( void  )

Definition at line 1209 of file portalmem.c.

References hash_seq_init(), hash_seq_search(), portalhashent::portal, PORTAL_READY, status(), and PortalData::status.

Referenced by CopyFrom().

1210 {
1212  PortalHashEnt *hentry;
1213 
1214  hash_seq_init(&status, PortalHashTable);
1215 
1216  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1217  {
1218  Portal portal = hentry->portal;
1219 
1220  if (portal->status == PORTAL_READY)
1221  return false;
1222  }
1223 
1224  return true;
1225 }
Portal portal
Definition: portalmem.c:51
PortalStatus status
Definition: portal.h:150
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ UnpinPortal()

void UnpinPortal ( Portal  portal)

Definition at line 379 of file portalmem.c.

References elog, ERROR, and PortalData::portalPinned.

Referenced by exec_for_query(), plperl_spi_cursor_close(), plperl_spi_fetchrow(), PLy_cursor_close(), and PLy_cursor_dealloc().

380 {
381  if (!portal->portalPinned)
382  elog(ERROR, "portal not pinned");
383 
384  portal->portalPinned = false;
385 }
#define ERROR
Definition: elog.h:43
bool portalPinned
Definition: portal.h:151
#define elog(elevel,...)
Definition: elog.h:214

Variable Documentation

◆ PortalHashTable

HTAB* PortalHashTable = NULL
static

Definition at line 54 of file portalmem.c.

◆ TopPortalContext

MemoryContext TopPortalContext = NULL
static

Definition at line 91 of file portalmem.c.