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, 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

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:103

◆ 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.

Function Documentation

◆ AtAbort_Portals()

void AtAbort_Portals ( void  )

Definition at line 779 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().

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

◆ AtCleanup_Portals()

void AtCleanup_Portals ( void  )

Definition at line 856 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().

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

◆ AtSubAbort_Portals()

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

Definition at line 975 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().

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

◆ AtSubCleanup_Portals()

void AtSubCleanup_Portals ( SubTransactionId  mySubid)

Definition at line 1088 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().

1089 {
1091  PortalHashEnt *hentry;
1092 
1093  hash_seq_init(&status, PortalHashTable);
1094 
1095  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1096  {
1097  Portal portal = hentry->portal;
1098 
1099  if (portal->createSubid != mySubid)
1100  continue;
1101 
1102  /*
1103  * If a portal is still pinned, forcibly unpin it. PortalDrop will not
1104  * let us drop the portal otherwise. Whoever pinned the portal was
1105  * interrupted by the abort too and won't try to use it anymore.
1106  */
1107  if (portal->portalPinned)
1108  portal->portalPinned = false;
1109 
1110  /*
1111  * We had better not call any user-defined code during cleanup, so if
1112  * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
1113  */
1114  if (PointerIsValid(portal->cleanup))
1115  {
1116  elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
1117  portal->cleanup = NULL;
1118  }
1119 
1120  /* Zap it. */
1121  PortalDrop(portal, false);
1122  }
1123 }
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:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:467
#define elog(elevel,...)
Definition: elog.h:232
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:698

◆ AtSubCommit_Portals()

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

Definition at line 941 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().

944 {
946  PortalHashEnt *hentry;
947 
948  hash_seq_init(&status, PortalHashTable);
949 
950  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
951  {
952  Portal portal = hentry->portal;
953 
954  if (portal->createSubid == mySubid)
955  {
956  portal->createSubid = parentSubid;
957  if (portal->resowner)
958  ResourceOwnerNewParent(portal->resowner, parentXactOwner);
959  }
960  if (portal->activeSubid == mySubid)
961  portal->activeSubid = parentSubid;
962  }
963 }
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:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:801
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:218
#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:173
bool atEnd
Definition: portal.h:199
bool visible
Definition: portal.h:204
void(* cleanup)(Portal portal)
Definition: portal.h:122
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:147
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:205
int errcode(int sqlerrcode)
Definition: elog.c:698
void PortalCleanup(Portal portal)
Definition: portalcmds.c:263
MemoryContext portalContext
Definition: portal.h:120
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2820
static MemoryContext TopPortalContext
Definition: portalmem.c:91
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:46
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:806
TimestampTz creation_time
Definition: portal.h:203
#define WARNING
Definition: elog.h:40
#define PortalIsValid(p)
Definition: portal.h:211
SubTransactionId activeSubid
Definition: portal.h:132
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
#define ereport(elevel,...)
Definition: elog.h:157
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:336
PortalStatus status
Definition: portal.h:150
const char * name
Definition: encode.c:561
ResourceOwner resowner
Definition: portal.h:121
bool atStart
Definition: portal.h:198
int errmsg(const char *fmt,...)
Definition: elog.c:909
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:698
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:807
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:428

◆ EnablePortalManager()

void EnablePortalManager ( void  )

Definition at line 104 of file portalmem.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, HASHCTL::entrysize, hash_create(), HASH_ELEM, HASH_STRINGS, 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 | HASH_STRINGS);
123 }
#define AllocSetContextCreate
Definition: memutils.h:173
#define HASH_ELEM
Definition: hsearch.h:95
#define PORTALS_PER_USER
Definition: portalmem.c:38
Size entrysize
Definition: hsearch.h:76
static MemoryContext TopPortalContext
Definition: portalmem.c:91
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
MemoryContext TopMemoryContext
Definition: mcxt.c:48
Size keysize
Definition: hsearch.h:75
struct portalhashent PortalHashEnt
#define Assert(condition)
Definition: c.h:804
#define MAX_PORTALNAME_LEN
Definition: portalmem.c:46
static HTAB * PortalHashTable
Definition: portalmem.c:54
#define HASH_STRINGS
Definition: hsearch.h:96

◆ ForgetPortalSnapshots()

void ForgetPortalSnapshots ( void  )

Definition at line 1299 of file portalmem.c.

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

Referenced by _SPI_commit(), and _SPI_rollback().

1300 {
1302  PortalHashEnt *hentry;
1303  int numPortalSnaps = 0;
1304  int numActiveSnaps = 0;
1305 
1306  /* First, scan PortalHashTable and clear portalSnapshot fields */
1307  hash_seq_init(&status, PortalHashTable);
1308 
1309  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1310  {
1311  Portal portal = hentry->portal;
1312 
1313  if (portal->portalSnapshot != NULL)
1314  {
1315  portal->portalSnapshot = NULL;
1316  numPortalSnaps++;
1317  }
1318  /* portal->holdSnapshot will be cleaned up in PreCommit_Portals */
1319  }
1320 
1321  /*
1322  * Now, pop all the active snapshots, which should be just those that were
1323  * portal snapshots. Ideally we'd drive this directly off the portal
1324  * scan, but there's no good way to visit the portals in the correct
1325  * order. So just cross-check after the fact.
1326  */
1327  while (ActiveSnapshotSet())
1328  {
1330  numActiveSnaps++;
1331  }
1332 
1333  if (numPortalSnaps != numActiveSnaps)
1334  elog(ERROR, "portal snapshots (%d) did not account for all active snapshots (%d)",
1335  numPortalSnaps, numActiveSnaps);
1336 }
void PopActiveSnapshot(void)
Definition: snapmgr.c:759
#define ERROR
Definition: elog.h:46
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:798
Portal portal
Definition: portalmem.c:51
Snapshot portalSnapshot
Definition: portal.h:169
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
#define elog(elevel,...)
Definition: elog.h:232
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ 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:698

◆ HoldPinnedPortals()

void HoldPinnedPortals ( void  )

Definition at line 1250 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().

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

◆ 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:698
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:46
SubTransactionId activeSubid
Definition: portal.h:132
#define ereport(elevel,...)
Definition: elog.h:157
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:723
PortalStatus status
Definition: portal.h:150
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ 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:804
PortalStatus status
Definition: portal.h:150
#define PointerIsValid(pointer)
Definition: c.h:698

◆ 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:804
PortalStatus status
Definition: portal.h:150
#define PointerIsValid(pointer)
Definition: c.h:698

◆ 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:46
bool portalPinned
Definition: portal.h:151
#define elog(elevel,...)
Definition: elog.h:232

◆ 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:173
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext holdContext
Definition: portal.h:177
static MemoryContext TopPortalContext
Definition: portalmem.c:91
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:124
#define Assert(condition)
Definition: c.h:804
Snapshot holdSnapshot
Definition: portal.h:187
Tuplestorestate * holdStore
Definition: portal.h:176
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2819
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:807
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:806
#define PortalIsValid(p)
Definition: portal.h:211
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 Assert, 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(), 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().

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  /* There shouldn't be an active snapshot anymore, except after error */
506  Assert(portal->portalSnapshot == NULL || !isTopCommit);
507 
508  /*
509  * Remove portal from hash table. Because we do this here, we will not
510  * come back to try to remove the portal again if there's any error in the
511  * subsequent steps. Better to leak a little memory than to get into an
512  * infinite error-recovery loop.
513  */
514  PortalHashTableDelete(portal);
515 
516  /* drop cached plan reference, if any */
517  PortalReleaseCachedPlan(portal);
518 
519  /*
520  * If portal has a snapshot protecting its data, release that. This needs
521  * a little care since the registration will be attached to the portal's
522  * resowner; if the portal failed, we will already have released the
523  * resowner (and the snapshot) during transaction abort.
524  */
525  if (portal->holdSnapshot)
526  {
527  if (portal->resowner)
529  portal->resowner);
530  portal->holdSnapshot = NULL;
531  }
532 
533  /*
534  * Release any resources still attached to the portal. There are several
535  * cases being covered here:
536  *
537  * Top transaction commit (indicated by isTopCommit): normally we should
538  * do nothing here and let the regular end-of-transaction resource
539  * releasing mechanism handle these resources too. However, if we have a
540  * FAILED portal (eg, a cursor that got an error), we'd better clean up
541  * its resources to avoid resource-leakage warning messages.
542  *
543  * Sub transaction commit: never comes here at all, since we don't kill
544  * any portals in AtSubCommit_Portals().
545  *
546  * Main or sub transaction abort: we will do nothing here because
547  * portal->resowner was already set NULL; the resources were already
548  * cleaned up in transaction abort.
549  *
550  * Ordinary portal drop: must release resources. However, if the portal
551  * is not FAILED then we do not release its locks. The locks become the
552  * responsibility of the transaction's ResourceOwner (since it is the
553  * parent of the portal's owner) and will be released when the transaction
554  * eventually ends.
555  */
556  if (portal->resowner &&
557  (!isTopCommit || portal->status == PORTAL_FAILED))
558  {
559  bool isCommit = (portal->status != PORTAL_FAILED);
560 
563  isCommit, false);
566  isCommit, false);
569  isCommit, false);
570  ResourceOwnerDelete(portal->resowner);
571  }
572  portal->resowner = NULL;
573 
574  /*
575  * Delete tuplestore if present. We should do this even under error
576  * conditions; since the tuplestore would have been using cross-
577  * transaction storage, its temp files need to be explicitly deleted.
578  */
579  if (portal->holdStore)
580  {
581  MemoryContext oldcontext;
582 
583  oldcontext = MemoryContextSwitchTo(portal->holdContext);
584  tuplestore_end(portal->holdStore);
585  MemoryContextSwitchTo(oldcontext);
586  portal->holdStore = NULL;
587  }
588 
589  /* delete tuplestore storage, if any */
590  if (portal->holdContext)
592 
593  /* release subsidiary storage */
595 
596  /* release portal struct (it's in TopPortalContext) */
597  pfree(portal);
598 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:309
void(* cleanup)(Portal portal)
Definition: portal.h:122
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:737
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:698
MemoryContext holdContext
Definition: portal.h:177
MemoryContext portalContext
Definition: portal.h:120
#define PortalHashTableDelete(PORTAL)
Definition: portalmem.c:81
void pfree(void *pointer)
Definition: mcxt.c:1169
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:46
bool portalPinned
Definition: portal.h:151
#define AssertArg(condition)
Definition: c.h:806
#define PortalIsValid(p)
Definition: portal.h:211
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:486
Snapshot portalSnapshot
Definition: portal.h:169
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:865
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
Snapshot holdSnapshot
Definition: portal.h:187
PortalStatus status
Definition: portal.h:150
ResourceOwner resowner
Definition: portal.h:121
Tuplestorestate * holdStore
Definition: portal.h:176
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define PointerIsValid(pointer)
Definition: c.h:698

◆ PortalErrorCleanup()

void PortalErrorCleanup ( void  )

Definition at line 915 of file portalmem.c.

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

Referenced by PostgresMain().

916 {
918  PortalHashEnt *hentry;
919 
920  hash_seq_init(&status, PortalHashTable);
921 
922  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
923  {
924  Portal portal = hentry->portal;
925 
926  if (portal->autoHeld)
927  {
928  portal->portalPinned = false;
929  PortalDrop(portal, false);
930  }
931  }
932 }
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:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
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 606 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().

607 {
609  PortalHashEnt *hentry;
610 
611  if (PortalHashTable == NULL)
612  return;
613 
614  hash_seq_init(&status, PortalHashTable);
615  while ((hentry = hash_seq_search(&status)) != NULL)
616  {
617  Portal portal = hentry->portal;
618 
619  /* Can't close the active portal (the one running the command) */
620  if (portal->status == PORTAL_ACTIVE)
621  continue;
622 
623  PortalDrop(portal, false);
624 
625  /* Restart the iteration in case that led to other drops */
626  hash_seq_term(&status);
627  hash_seq_init(&status, PortalHashTable);
628  }
629 }
Portal portal
Definition: portalmem.c:51
PortalStatus status
Definition: portal.h:150
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
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:1512

◆ PreCommit_Portals()

bool PreCommit_Portals ( bool  isPrepare)

Definition at line 675 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::portalSnapshot, PortalData::resowner, status(), PortalData::status, and UnregisterSnapshotFromOwner().

Referenced by CommitTransaction(), and PrepareTransaction().

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

◆ ThereAreNoReadyPortals()

bool ThereAreNoReadyPortals ( void  )

Definition at line 1214 of file portalmem.c.

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

Referenced by CopyFrom().

1215 {
1217  PortalHashEnt *hentry;
1218 
1219  hash_seq_init(&status, PortalHashTable);
1220 
1221  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1222  {
1223  Portal portal = hentry->portal;
1224 
1225  if (portal->status == PORTAL_READY)
1226  return false;
1227  }
1228 
1229  return true;
1230 }
Portal portal
Definition: portalmem.c:51
PortalStatus status
Definition: portal.h:150
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
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:46
bool portalPinned
Definition: portal.h:151
#define elog(elevel,...)
Definition: elog.h:232