PostgreSQL Source Code  git master
portal.h File Reference
#include "datatype/timestamp.h"
#include "executor/execdesc.h"
#include "tcop/cmdtag.h"
#include "utils/plancache.h"
#include "utils/resowner.h"
Include dependency graph for portal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PortalData
 

Macros

#define PortalIsValid(p)   PointerIsValid(p)
 

Typedefs

typedef enum PortalStrategy PortalStrategy
 
typedef enum PortalStatus PortalStatus
 
typedef struct PortalDataPortal
 
typedef struct PortalData PortalData
 

Enumerations

enum  PortalStrategy {
  PORTAL_ONE_SELECT , PORTAL_ONE_RETURNING , PORTAL_ONE_MOD_WITH , PORTAL_UTIL_SELECT ,
  PORTAL_MULTI_QUERY
}
 
enum  PortalStatus {
  PORTAL_NEW , PORTAL_DEFINED , PORTAL_READY , PORTAL_ACTIVE ,
  PORTAL_DONE , PORTAL_FAILED
}
 

Functions

void EnablePortalManager (void)
 
bool PreCommit_Portals (bool isPrepare)
 
void AtAbort_Portals (void)
 
void AtCleanup_Portals (void)
 
void PortalErrorCleanup (void)
 
void AtSubCommit_Portals (SubTransactionId mySubid, SubTransactionId parentSubid, int parentLevel, ResourceOwner parentXactOwner)
 
void AtSubAbort_Portals (SubTransactionId mySubid, SubTransactionId parentSubid, ResourceOwner myXactOwner, ResourceOwner parentXactOwner)
 
void AtSubCleanup_Portals (SubTransactionId mySubid)
 
Portal CreatePortal (const char *name, bool allowDup, bool dupSilent)
 
Portal CreateNewPortal (void)
 
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)
 
Portal GetPortalByName (const char *name)
 
void PortalDefineQuery (Portal portal, const char *prepStmtName, const char *sourceText, CommandTag commandTag, List *stmts, CachedPlan *cplan)
 
PlannedStmtPortalGetPrimaryStmt (Portal portal)
 
void PortalCreateHoldStore (Portal portal)
 
void PortalHashTableDeleteAll (void)
 
bool ThereAreNoReadyPortals (void)
 
void HoldPinnedPortals (void)
 
void ForgetPortalSnapshots (void)
 

Macro Definition Documentation

◆ PortalIsValid

#define PortalIsValid (   p)    PointerIsValid(p)

Definition at line 212 of file portal.h.

Typedef Documentation

◆ Portal

typedef struct PortalData* Portal

Definition at line 113 of file portal.h.

◆ PortalData

typedef struct PortalData PortalData

◆ PortalStatus

typedef enum PortalStatus PortalStatus

◆ PortalStrategy

Enumeration Type Documentation

◆ PortalStatus

Enumerator
PORTAL_NEW 
PORTAL_DEFINED 
PORTAL_READY 
PORTAL_ACTIVE 
PORTAL_DONE 
PORTAL_FAILED 

Definition at line 103 of file portal.h.

104 {
105  PORTAL_NEW, /* freshly created */
106  PORTAL_DEFINED, /* PortalDefineQuery done */
107  PORTAL_READY, /* PortalStart complete, can run it */
108  PORTAL_ACTIVE, /* portal is running (can't delete it) */
109  PORTAL_DONE, /* portal is finished (don't re-run it) */
110  PORTAL_FAILED /* portal got error (can't re-run it) */
111 } PortalStatus;
PortalStatus
Definition: portal.h:104
@ PORTAL_FAILED
Definition: portal.h:110
@ PORTAL_NEW
Definition: portal.h:105
@ PORTAL_ACTIVE
Definition: portal.h:108
@ PORTAL_DONE
Definition: portal.h:109
@ PORTAL_READY
Definition: portal.h:107
@ PORTAL_DEFINED
Definition: portal.h:106

◆ PortalStrategy

Enumerator
PORTAL_ONE_SELECT 
PORTAL_ONE_RETURNING 
PORTAL_ONE_MOD_WITH 
PORTAL_UTIL_SELECT 
PORTAL_MULTI_QUERY 

Definition at line 89 of file portal.h.

90 {
PortalStrategy
Definition: portal.h:90
@ PORTAL_ONE_RETURNING
Definition: portal.h:92
@ PORTAL_MULTI_QUERY
Definition: portal.h:95
@ PORTAL_ONE_SELECT
Definition: portal.h:91
@ PORTAL_ONE_MOD_WITH
Definition: portal.h:93
@ PORTAL_UTIL_SELECT
Definition: portal.h:94

Function Documentation

◆ AtAbort_Portals()

void AtAbort_Portals ( void  )

Definition at line 782 of file portalmem.c.

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

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, PortalHashTable, PortalReleaseCachedPlan(), PortalData::resowner, shmem_exit_inprogress, and PortalData::status.

Referenced by AbortOutOfAnyTransaction(), and AbortTransaction().

◆ AtCleanup_Portals()

void AtCleanup_Portals ( void  )

Definition at line 859 of file portalmem.c.

860 {
861  HASH_SEQ_STATUS status;
862  PortalHashEnt *hentry;
863 
864  hash_seq_init(&status, PortalHashTable);
865 
866  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
867  {
868  Portal portal = hentry->portal;
869 
870  /*
871  * Do not touch active portals --- this can only happen in the case of
872  * a multi-transaction command.
873  */
874  if (portal->status == PORTAL_ACTIVE)
875  continue;
876 
877  /*
878  * Do nothing to cursors held over from a previous transaction or
879  * auto-held ones.
880  */
881  if (portal->createSubid == InvalidSubTransactionId || portal->autoHeld)
882  {
883  Assert(portal->status != PORTAL_ACTIVE);
884  Assert(portal->resowner == NULL);
885  continue;
886  }
887 
888  /*
889  * If a portal is still pinned, forcibly unpin it. PortalDrop will not
890  * let us drop the portal otherwise. Whoever pinned the portal was
891  * interrupted by the abort too and won't try to use it anymore.
892  */
893  if (portal->portalPinned)
894  portal->portalPinned = false;
895 
896  /*
897  * We had better not call any user-defined code during cleanup, so if
898  * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
899  */
900  if (PointerIsValid(portal->cleanup))
901  {
902  elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
903  portal->cleanup = NULL;
904  }
905 
906  /* Zap it. */
907  PortalDrop(portal, false);
908  }
909 }
#define WARNING
Definition: elog.h:36
Assert(fmt[strlen(fmt) - 1] !='\n')
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:469
bool portalPinned
Definition: portal.h:152
const char * name
Definition: portal.h:118

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

Referenced by CleanupTransaction().

◆ AtSubAbort_Portals()

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

Definition at line 980 of file portalmem.c.

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

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, PortalHashTable, PortalReleaseCachedPlan(), ResourceOwnerNewParent(), PortalData::resowner, and PortalData::status.

Referenced by AbortOutOfAnyTransaction(), and AbortSubTransaction().

◆ AtSubCleanup_Portals()

void AtSubCleanup_Portals ( SubTransactionId  mySubid)

Definition at line 1093 of file portalmem.c.

1094 {
1095  HASH_SEQ_STATUS status;
1096  PortalHashEnt *hentry;
1097 
1098  hash_seq_init(&status, PortalHashTable);
1099 
1100  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1101  {
1102  Portal portal = hentry->portal;
1103 
1104  if (portal->createSubid != mySubid)
1105  continue;
1106 
1107  /*
1108  * If a portal is still pinned, forcibly unpin it. PortalDrop will not
1109  * let us drop the portal otherwise. Whoever pinned the portal was
1110  * interrupted by the abort too and won't try to use it anymore.
1111  */
1112  if (portal->portalPinned)
1113  portal->portalPinned = false;
1114 
1115  /*
1116  * We had better not call any user-defined code during cleanup, so if
1117  * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
1118  */
1119  if (PointerIsValid(portal->cleanup))
1120  {
1121  elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
1122  portal->cleanup = NULL;
1123  }
1124 
1125  /* Zap it. */
1126  PortalDrop(portal, false);
1127  }
1128 }

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

Referenced by CleanupSubTransaction().

◆ AtSubCommit_Portals()

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

Definition at line 944 of file portalmem.c.

948 {
949  HASH_SEQ_STATUS status;
950  PortalHashEnt *hentry;
951 
952  hash_seq_init(&status, PortalHashTable);
953 
954  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
955  {
956  Portal portal = hentry->portal;
957 
958  if (portal->createSubid == mySubid)
959  {
960  portal->createSubid = parentSubid;
961  portal->createLevel = parentLevel;
962  if (portal->resowner)
963  ResourceOwnerNewParent(portal->resowner, parentXactOwner);
964  }
965  if (portal->activeSubid == mySubid)
966  portal->activeSubid = parentSubid;
967  }
968 }
int createLevel
Definition: portal.h:133

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

Referenced by CommitSubTransaction().

◆ CreateNewPortal()

Portal CreateNewPortal ( void  )

Definition at line 236 of file portalmem.c.

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

References CreatePortal(), GetPortalByName(), MAX_PORTALNAME_LEN, and sprintf.

Referenced by ExecuteQuery(), and SPI_cursor_open_internal().

◆ CreatePortal()

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

Definition at line 176 of file portalmem.c.

177 {
178  Portal portal;
179 
181 
182  portal = GetPortalByName(name);
183  if (PortalIsValid(portal))
184  {
185  if (!allowDup)
186  ereport(ERROR,
187  (errcode(ERRCODE_DUPLICATE_CURSOR),
188  errmsg("cursor \"%s\" already exists", name)));
189  if (!dupSilent)
191  (errcode(ERRCODE_DUPLICATE_CURSOR),
192  errmsg("closing existing cursor \"%s\"",
193  name)));
194  PortalDrop(portal, false);
195  }
196 
197  /* make new portal structure */
198  portal = (Portal) MemoryContextAllocZero(TopPortalContext, sizeof *portal);
199 
200  /* initialize portal context; typically it won't store much */
202  "PortalContext",
204 
205  /* create a resource owner for the portal */
207  "Portal");
208 
209  /* initialize portal fields that don't start off zero */
210  portal->status = PORTAL_NEW;
211  portal->cleanup = PortalCleanup;
213  portal->activeSubid = portal->createSubid;
215  portal->strategy = PORTAL_MULTI_QUERY;
217  portal->atStart = true;
218  portal->atEnd = true; /* disallow fetches until query is set */
219  portal->visible = true;
221 
222  /* put portal in table (sets portal->name) */
223  PortalHashTableInsert(portal, name);
224 
225  /* for named portals reuse portal->name copy */
226  MemoryContextSetIdentifier(portal->portalContext, portal->name[0] ? portal->name : "<unnamed>");
227 
228  return portal;
229 }
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1064
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:521
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3157
struct PortalData * Portal
Definition: portal.h:113
#define PortalIsValid(p)
Definition: portal.h:212
void PortalCleanup(Portal portal)
Definition: portalcmds.c:263
#define PortalHashTableInsert(PORTAL, NAME)
Definition: portalmem.c:69
static MemoryContext TopPortalContext
Definition: portalmem.c:92
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:429
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:148
bool atEnd
Definition: portal.h:200
bool atStart
Definition: portal.h:199
TimestampTz creation_time
Definition: portal.h:204
bool visible
Definition: portal.h:205
int cursorOptions
Definition: portal.h:147
PortalStrategy strategy
Definition: portal.h:146
const char * name
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:780
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:914
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:864

References PortalData::activeSubid, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert(), PortalData::atEnd, PortalData::atStart, PortalData::cleanup, PortalData::createLevel, PortalData::createSubid, PortalData::creation_time, CURSOR_OPT_NO_SCROLL, PortalData::cursorOptions, CurTransactionResourceOwner, ereport, errcode(), errmsg(), ERROR, GetCurrentStatementStartTimestamp(), GetCurrentSubTransactionId(), GetCurrentTransactionNestLevel(), GetPortalByName(), MemoryContextAllocZero(), MemoryContextSetIdentifier(), name, PortalData::name, PointerIsValid, PORTAL_MULTI_QUERY, PORTAL_NEW, PortalCleanup(), PortalData::portalContext, PortalDrop(), PortalHashTableInsert, PortalIsValid, ResourceOwnerCreate(), PortalData::resowner, PortalData::status, PortalData::strategy, TopPortalContext, PortalData::visible, and WARNING.

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

◆ EnablePortalManager()

void EnablePortalManager ( void  )

Definition at line 105 of file portalmem.c.

106 {
107  HASHCTL ctl;
108 
109  Assert(TopPortalContext == NULL);
110 
112  "TopPortalContext",
114 
116  ctl.entrysize = sizeof(PortalHashEnt);
117 
118  /*
119  * use PORTALS_PER_USER as a guess of how many hash table entries to
120  * create, initially
121  */
123  &ctl, HASH_ELEM | HASH_STRINGS);
124 }
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
#define HASH_STRINGS
Definition: hsearch.h:96
#define HASH_ELEM
Definition: hsearch.h:95
MemoryContext TopMemoryContext
Definition: mcxt.c:141
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
struct portalhashent PortalHashEnt
#define PORTALS_PER_USER
Definition: portalmem.c:39
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

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

Referenced by InitPostgres().

◆ ForgetPortalSnapshots()

void ForgetPortalSnapshots ( void  )

Definition at line 1254 of file portalmem.c.

1255 {
1256  HASH_SEQ_STATUS status;
1257  PortalHashEnt *hentry;
1258  int numPortalSnaps = 0;
1259  int numActiveSnaps = 0;
1260 
1261  /* First, scan PortalHashTable and clear portalSnapshot fields */
1262  hash_seq_init(&status, PortalHashTable);
1263 
1264  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1265  {
1266  Portal portal = hentry->portal;
1267 
1268  if (portal->portalSnapshot != NULL)
1269  {
1270  portal->portalSnapshot = NULL;
1271  numPortalSnaps++;
1272  }
1273  /* portal->holdSnapshot will be cleaned up in PreCommit_Portals */
1274  }
1275 
1276  /*
1277  * Now, pop all the active snapshots, which should be just those that were
1278  * portal snapshots. Ideally we'd drive this directly off the portal
1279  * scan, but there's no good way to visit the portals in the correct
1280  * order. So just cross-check after the fact.
1281  */
1282  while (ActiveSnapshotSet())
1283  {
1285  numActiveSnaps++;
1286  }
1287 
1288  if (numPortalSnaps != numActiveSnaps)
1289  elog(ERROR, "portal snapshots (%d) did not account for all active snapshots (%d)",
1290  numPortalSnaps, numActiveSnaps);
1291 }
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:763
void PopActiveSnapshot(void)
Definition: snapmgr.c:724
Snapshot portalSnapshot
Definition: portal.h:170

References ActiveSnapshotSet(), elog(), ERROR, hash_seq_init(), hash_seq_search(), PopActiveSnapshot(), portalhashent::portal, PortalHashTable, and PortalData::portalSnapshot.

Referenced by _SPI_commit(), and _SPI_rollback().

◆ GetPortalByName()

Portal GetPortalByName ( const char *  name)

◆ HoldPinnedPortals()

void HoldPinnedPortals ( void  )

Definition at line 1205 of file portalmem.c.

1206 {
1207  HASH_SEQ_STATUS status;
1208  PortalHashEnt *hentry;
1209 
1210  hash_seq_init(&status, PortalHashTable);
1211 
1212  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1213  {
1214  Portal portal = hentry->portal;
1215 
1216  if (portal->portalPinned && !portal->autoHeld)
1217  {
1218  /*
1219  * Doing transaction control, especially abort, inside a cursor
1220  * loop that is not read-only, for example using UPDATE ...
1221  * RETURNING, has weird semantics issues. Also, this
1222  * implementation wouldn't work, because such portals cannot be
1223  * held. (The core grammar enforces that only SELECT statements
1224  * can drive a cursor, but for example PL/pgSQL does not restrict
1225  * it.)
1226  */
1227  if (portal->strategy != PORTAL_ONE_SELECT)
1228  ereport(ERROR,
1229  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1230  errmsg("cannot perform transaction commands inside a cursor loop that is not read-only")));
1231 
1232  /* Verify it's in a suitable state to be held */
1233  if (portal->status != PORTAL_READY)
1234  elog(ERROR, "pinned portal is not ready to be auto-held");
1235 
1236  HoldPortal(portal);
1237  portal->autoHeld = true;
1238  }
1239  }
1240 }
static void HoldPortal(Portal portal)
Definition: portalmem.c:637

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

Referenced by _SPI_commit(), and _SPI_rollback().

◆ MarkPortalActive()

void MarkPortalActive ( Portal  portal)

Definition at line 396 of file portalmem.c.

397 {
398  /* For safety, this is a runtime test not just an Assert */
399  if (portal->status != PORTAL_READY)
400  ereport(ERROR,
401  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
402  errmsg("portal \"%s\" cannot be run", portal->name)));
403  /* Perform the state transition */
404  portal->status = PORTAL_ACTIVE;
406 }

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

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

◆ MarkPortalDone()

void MarkPortalDone ( Portal  portal)

Definition at line 415 of file portalmem.c.

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

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

Referenced by PortalRun().

◆ MarkPortalFailed()

void MarkPortalFailed ( Portal  portal)

Definition at line 443 of file portalmem.c.

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

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

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

◆ PinPortal()

void PinPortal ( Portal  portal)

Definition at line 372 of file portalmem.c.

373 {
374  if (portal->portalPinned)
375  elog(ERROR, "portal already pinned");
376 
377  portal->portalPinned = true;
378 }

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().

◆ PortalCreateHoldStore()

void PortalCreateHoldStore ( Portal  portal)

Definition at line 332 of file portalmem.c.

333 {
334  MemoryContext oldcxt;
335 
336  Assert(portal->holdContext == NULL);
337  Assert(portal->holdStore == NULL);
338  Assert(portal->holdSnapshot == NULL);
339 
340  /*
341  * Create the memory context that is used for storage of the tuple set.
342  * Note this is NOT a child of the portal's portalContext.
343  */
344  portal->holdContext =
346  "PortalHoldContext",
348 
349  /*
350  * Create the tuple store, selecting cross-transaction temp files, and
351  * enabling random access only if cursor requires scrolling.
352  *
353  * XXX: Should maintenance_work_mem be used for the portal size?
354  */
355  oldcxt = MemoryContextSwitchTo(portal->holdContext);
356 
357  portal->holdStore =
359  true, work_mem);
360 
361  MemoryContextSwitchTo(oldcxt);
362 }
int work_mem
Definition: globals.c:125
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3156
MemoryContext holdContext
Definition: portal.h:178
Snapshot holdSnapshot
Definition: portal.h:188
Tuplestorestate * holdStore
Definition: portal.h:177
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318

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

Referenced by FillPortalStore(), and HoldPortal().

◆ PortalDefineQuery()

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

Definition at line 283 of file portalmem.c.

289 {
290  Assert(PortalIsValid(portal));
291  Assert(portal->status == PORTAL_NEW);
292 
293  Assert(sourceText != NULL);
294  Assert(commandTag != CMDTAG_UNKNOWN || stmts == NIL);
295 
296  portal->prepStmtName = prepStmtName;
297  portal->sourceText = sourceText;
298  portal->qc.commandTag = commandTag;
299  portal->qc.nprocessed = 0;
300  portal->commandTag = commandTag;
301  portal->stmts = stmts;
302  portal->cplan = cplan;
303  portal->status = PORTAL_DEFINED;
304 }
#define NIL
Definition: pg_list.h:68
CommandTag commandTag
Definition: portal.h:137
const char * sourceText
Definition: portal.h:136
List * stmts
Definition: portal.h:139
QueryCompletion qc
Definition: portal.h:138
const char * prepStmtName
Definition: portal.h:119
CachedPlan * cplan
Definition: portal.h:140
uint64 nprocessed
Definition: cmdtag.h:33
CommandTag commandTag
Definition: cmdtag.h:32

References Assert(), 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().

◆ PortalDrop()

void PortalDrop ( Portal  portal,
bool  isTopCommit 
)

Definition at line 469 of file portalmem.c.

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

References Assert(), 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(), PortalData::portalSnapshot, 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().

◆ PortalErrorCleanup()

void PortalErrorCleanup ( void  )

Definition at line 918 of file portalmem.c.

919 {
920  HASH_SEQ_STATUS status;
921  PortalHashEnt *hentry;
922 
923  hash_seq_init(&status, PortalHashTable);
924 
925  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
926  {
927  Portal portal = hentry->portal;
928 
929  if (portal->autoHeld)
930  {
931  portal->portalPinned = false;
932  PortalDrop(portal, false);
933  }
934  }
935 }

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

Referenced by PostgresMain().

◆ PortalGetPrimaryStmt()

PlannedStmt* PortalGetPrimaryStmt ( Portal  portal)

Definition at line 152 of file portalmem.c.

153 {
154  ListCell *lc;
155 
156  foreach(lc, portal->stmts)
157  {
159 
160  if (stmt->canSetTag)
161  return stmt;
162  }
163  return NULL;
164 }
#define stmt
Definition: indent_codes.h:59
#define lfirst_node(type, lc)
Definition: pg_list.h:176

References lfirst_node, stmt, and PortalData::stmts.

Referenced by FetchPortalTargetList(), and PortalStart().

◆ PortalHashTableDeleteAll()

void PortalHashTableDeleteAll ( void  )

Definition at line 608 of file portalmem.c.

609 {
610  HASH_SEQ_STATUS status;
611  PortalHashEnt *hentry;
612 
613  if (PortalHashTable == NULL)
614  return;
615 
616  hash_seq_init(&status, PortalHashTable);
617  while ((hentry = hash_seq_search(&status)) != NULL)
618  {
619  Portal portal = hentry->portal;
620 
621  /* Can't close the active portal (the one running the command) */
622  if (portal->status == PORTAL_ACTIVE)
623  continue;
624 
625  PortalDrop(portal, false);
626 
627  /* Restart the iteration in case that led to other drops */
628  hash_seq_term(&status);
629  hash_seq_init(&status, PortalHashTable);
630  }
631 }
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1507

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

Referenced by DiscardAll(), and PerformPortalClose().

◆ PreCommit_Portals()

bool PreCommit_Portals ( bool  isPrepare)

Definition at line 678 of file portalmem.c.

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

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(), PortalHashTable, PortalData::portalPinned, PortalData::portalSnapshot, PortalData::resowner, PortalData::status, and UnregisterSnapshotFromOwner().

Referenced by CommitTransaction(), and PrepareTransaction().

◆ ThereAreNoReadyPortals()

bool ThereAreNoReadyPortals ( void  )

Definition at line 1169 of file portalmem.c.

1170 {
1171  HASH_SEQ_STATUS status;
1172  PortalHashEnt *hentry;
1173 
1174  hash_seq_init(&status, PortalHashTable);
1175 
1176  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1177  {
1178  Portal portal = hentry->portal;
1179 
1180  if (portal->status == PORTAL_READY)
1181  return false;
1182  }
1183 
1184  return true;
1185 }

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

Referenced by CopyFrom().

◆ UnpinPortal()

void UnpinPortal ( Portal  portal)

Definition at line 381 of file portalmem.c.

382 {
383  if (!portal->portalPinned)
384  elog(ERROR, "portal not pinned");
385 
386  portal->portalPinned = false;
387 }

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().