PostgreSQL Source Code  git master
portal.h File Reference
#include "datatype/timestamp.h"
#include "executor/execdesc.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, const char *commandTag, List *stmts, CachedPlan *cplan)
 
PlannedStmtPortalGetPrimaryStmt (Portal portal)
 
void PortalCreateHoldStore (Portal portal)
 
void PortalHashTableDeleteAll (void)
 
bool ThereAreNoReadyPortals (void)
 
void HoldPinnedPortals (void)
 

Macro Definition Documentation

◆ PortalIsValid

Typedef Documentation

◆ Portal

Definition at line 112 of file portal.h.

◆ PortalData

◆ PortalStatus

◆ PortalStrategy

Enumeration Type Documentation

◆ PortalStatus

Enumerator
PORTAL_NEW 
PORTAL_DEFINED 
PORTAL_READY 
PORTAL_ACTIVE 
PORTAL_DONE 
PORTAL_FAILED 

Definition at line 102 of file portal.h.

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

◆ PortalStrategy

Enumerator
PORTAL_ONE_SELECT 
PORTAL_ONE_RETURNING 
PORTAL_ONE_MOD_WITH 
PORTAL_UTIL_SELECT 
PORTAL_MULTI_QUERY 

Definition at line 88 of file portal.h.

Function Documentation

◆ AtAbort_Portals()

void AtAbort_Portals ( void  )

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

763 {
765  PortalHashEnt *hentry;
766 
767  hash_seq_init(&status, PortalHashTable);
768 
769  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
770  {
771  Portal portal = hentry->portal;
772 
773  /*
774  * When elog(FATAL) is progress, we need to set the active portal to
775  * failed, so that PortalCleanup() doesn't run the executor shutdown.
776  */
777  if (portal->status == PORTAL_ACTIVE && shmem_exit_inprogress)
778  MarkPortalFailed(portal);
779 
780  /*
781  * Do nothing else to cursors held over from a previous transaction.
782  */
783  if (portal->createSubid == InvalidSubTransactionId)
784  continue;
785 
786  /*
787  * Do nothing to auto-held cursors. This is similar to the case of a
788  * cursor from a previous transaction, but it could also be that the
789  * cursor was auto-held in this transaction, so it wants to live on.
790  */
791  if (portal->autoHeld)
792  continue;
793 
794  /*
795  * If it was created in the current transaction, we can't do normal
796  * shutdown on a READY portal either; it might refer to objects
797  * created in the failed transaction. See comments in
798  * AtSubAbort_Portals.
799  */
800  if (portal->status == PORTAL_READY)
801  MarkPortalFailed(portal);
802 
803  /*
804  * Allow portalcmds.c to clean up the state it knows about, if we
805  * haven't already.
806  */
807  if (PointerIsValid(portal->cleanup))
808  {
809  portal->cleanup(portal);
810  portal->cleanup = NULL;
811  }
812 
813  /* drop cached plan reference, if any */
814  PortalReleaseCachedPlan(portal);
815 
816  /*
817  * Any resources belonging to the portal will be released in the
818  * upcoming transaction-wide cleanup; they will be gone before we run
819  * PortalDrop.
820  */
821  portal->resowner = NULL;
822 
823  /*
824  * Although we can't delete the portal data structure proper, we can
825  * release any memory in subsidiary contexts, such as executor state.
826  * The cleanup hook was the last thing that might have needed data
827  * there. But leave active portals alone.
828  */
829  if (portal->status != PORTAL_ACTIVE)
831  }
832 }
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:307
bool autoHeld
Definition: portal.h:150
void(* cleanup)(Portal portal)
Definition: portal.h:121
MemoryContext portalContext
Definition: portal.h:119
SubTransactionId createSubid
Definition: portal.h:130
Portal portal
Definition: portalmem.c:51
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:256
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:439
PortalStatus status
Definition: portal.h:148
#define InvalidSubTransactionId
Definition: c.h:480
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
ResourceOwner resowner
Definition: portal.h:120
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:225
#define PointerIsValid(pointer)
Definition: c.h:593

◆ AtCleanup_Portals()

void AtCleanup_Portals ( void  )

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

840 {
842  PortalHashEnt *hentry;
843 
844  hash_seq_init(&status, PortalHashTable);
845 
846  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
847  {
848  Portal portal = hentry->portal;
849 
850  /*
851  * Do not touch active portals --- this can only happen in the case of
852  * a multi-transaction command.
853  */
854  if (portal->status == PORTAL_ACTIVE)
855  continue;
856 
857  /*
858  * Do nothing to cursors held over from a previous transaction or
859  * auto-held ones.
860  */
861  if (portal->createSubid == InvalidSubTransactionId || portal->autoHeld)
862  {
863  Assert(portal->status != PORTAL_ACTIVE);
864  Assert(portal->resowner == NULL);
865  continue;
866  }
867 
868  /*
869  * If a portal is still pinned, forcibly unpin it. PortalDrop will not
870  * let us drop the portal otherwise. Whoever pinned the portal was
871  * interrupted by the abort too and won't try to use it anymore.
872  */
873  if (portal->portalPinned)
874  portal->portalPinned = false;
875 
876  /*
877  * We had better not call any user-defined code during cleanup, so if
878  * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
879  */
880  if (PointerIsValid(portal->cleanup))
881  {
882  elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
883  portal->cleanup = NULL;
884  }
885 
886  /* Zap it. */
887  PortalDrop(portal, false);
888  }
889 }
bool autoHeld
Definition: portal.h:150
void(* cleanup)(Portal portal)
Definition: portal.h:121
const char * name
Definition: portal.h:117
bool portalPinned
Definition: portal.h:149
SubTransactionId createSubid
Definition: portal.h:130
Portal portal
Definition: portalmem.c:51
#define WARNING
Definition: elog.h:40
#define Assert(condition)
Definition: c.h:699
PortalStatus status
Definition: portal.h:148
#define InvalidSubTransactionId
Definition: c.h:480
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
ResourceOwner resowner
Definition: portal.h:120
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:465
static HTAB * PortalHashTable
Definition: portalmem.c:54
#define elog
Definition: elog.h:219
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
#define PointerIsValid(pointer)
Definition: c.h:593

◆ AtSubAbort_Portals()

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

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

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

◆ AtSubCleanup_Portals()

void AtSubCleanup_Portals ( SubTransactionId  mySubid)

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

1072 {
1074  PortalHashEnt *hentry;
1075 
1076  hash_seq_init(&status, PortalHashTable);
1077 
1078  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1079  {
1080  Portal portal = hentry->portal;
1081 
1082  if (portal->createSubid != mySubid)
1083  continue;
1084 
1085  /*
1086  * If a portal is still pinned, forcibly unpin it. PortalDrop will not
1087  * let us drop the portal otherwise. Whoever pinned the portal was
1088  * interrupted by the abort too and won't try to use it anymore.
1089  */
1090  if (portal->portalPinned)
1091  portal->portalPinned = false;
1092 
1093  /*
1094  * We had better not call any user-defined code during cleanup, so if
1095  * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
1096  */
1097  if (PointerIsValid(portal->cleanup))
1098  {
1099  elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
1100  portal->cleanup = NULL;
1101  }
1102 
1103  /* Zap it. */
1104  PortalDrop(portal, false);
1105  }
1106 }
void(* cleanup)(Portal portal)
Definition: portal.h:121
const char * name
Definition: portal.h:117
bool portalPinned
Definition: portal.h:149
SubTransactionId createSubid
Definition: portal.h:130
Portal portal
Definition: portalmem.c:51
#define WARNING
Definition: elog.h:40
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:465
static HTAB * PortalHashTable
Definition: portalmem.c:54
#define elog
Definition: elog.h:219
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
#define PointerIsValid(pointer)
Definition: c.h:593

◆ AtSubCommit_Portals()

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

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

927 {
929  PortalHashEnt *hentry;
930 
931  hash_seq_init(&status, PortalHashTable);
932 
933  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
934  {
935  Portal portal = hentry->portal;
936 
937  if (portal->createSubid == mySubid)
938  {
939  portal->createSubid = parentSubid;
940  if (portal->resowner)
941  ResourceOwnerNewParent(portal->resowner, parentXactOwner);
942  }
943  if (portal->activeSubid == mySubid)
944  portal->activeSubid = parentSubid;
945  }
946 }
SubTransactionId createSubid
Definition: portal.h:130
Portal portal
Definition: portalmem.c:51
SubTransactionId activeSubid
Definition: portal.h:131
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:744
ResourceOwner resowner
Definition: portal.h:120
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225

◆ CreateNewPortal()

Portal CreateNewPortal ( void  )

Definition at line 234 of file portalmem.c.

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

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 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  /* reuse portal->name copy */
225 
226  return portal;
227 }
bool atEnd
Definition: portal.h:189
bool visible
Definition: portal.h:194
void(* cleanup)(Portal portal)
Definition: portal.h:121
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:141
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
int errcode(int sqlerrcode)
Definition: elog.c:575
void PortalCleanup(Portal portal)
Definition: portalcmds.c:265
MemoryContext portalContext
Definition: portal.h:119
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2646
static MemoryContext TopPortalContext
Definition: portalmem.c:91
const char * name
Definition: portal.h:117
#define ERROR
Definition: elog.h:43
struct PortalData * Portal
Definition: portal.h:112
PortalStrategy strategy
Definition: portal.h:143
SubTransactionId createSubid
Definition: portal.h:130
#define ereport(elevel, rest)
Definition: elog.h:122
#define AssertArg(condition)
Definition: c.h:701
TimestampTz creation_time
Definition: portal.h:193
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
#define WARNING
Definition: elog.h:40
#define PortalIsValid(p)
Definition: portal.h:201
SubTransactionId activeSubid
Definition: portal.h:131
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:814
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:641
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:329
PortalStatus status
Definition: portal.h:148
const char * name
Definition: encode.c:521
ResourceOwner resowner
Definition: portal.h:120
bool atStart
Definition: portal.h:188
int errmsg(const char *fmt,...)
Definition: elog.c:797
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:465
int cursorOptions
Definition: portal.h:144
#define PortalHashTableInsert(PORTAL, NAME)
Definition: portalmem.c:68
#define PointerIsValid(pointer)
Definition: c.h:593
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:709
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:418

◆ EnablePortalManager()

void EnablePortalManager ( void  )

Definition at line 104 of file portalmem.c.

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

Referenced by InitPostgres().

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

◆ GetPortalByName()

Portal GetPortalByName ( const char *  name)

Definition at line 130 of file portalmem.c.

References PointerIsValid, portalhashent::portal, and PortalHashTableLookup.

Referenced by CreateNewPortal(), CreatePortal(), exec_describe_portal_message(), exec_execute_message(), exec_simple_query(), execCurrentOf(), FetchStatementTargetList(), PerformPortalClose(), PerformPortalFetch(), PLy_cursor_close(), PLy_cursor_dealloc(), PLy_cursor_fetch(), PLy_cursor_iternext(), PostgresMain(), SPI_cursor_find(), UtilityReturnsTuples(), and UtilityTupleDescriptor().

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

◆ HoldPinnedPortals()

void HoldPinnedPortals ( void  )

Definition at line 1228 of file portalmem.c.

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

Referenced by exec_stmt_commit(), exec_stmt_rollback(), plperl_spi_commit(), plperl_spi_rollback(), PLy_commit(), and PLy_rollback().

1229 {
1231  PortalHashEnt *hentry;
1232 
1233  hash_seq_init(&status, PortalHashTable);
1234 
1235  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1236  {
1237  Portal portal = hentry->portal;
1238 
1239  if (portal->portalPinned && !portal->autoHeld)
1240  {
1241  /*
1242  * Doing transaction control, especially abort, inside a cursor
1243  * loop that is not read-only, for example using UPDATE ...
1244  * RETURNING, has weird semantics issues. Also, this
1245  * implementation wouldn't work, because such portals cannot be
1246  * held. (The core grammar enforces that only SELECT statements
1247  * can drive a cursor, but for example PL/pgSQL does not restrict
1248  * it.)
1249  */
1250  if (portal->strategy != PORTAL_ONE_SELECT)
1251  ereport(ERROR,
1252  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
1253  errmsg("cannot perform transaction commands inside a cursor loop that is not read-only")));
1254 
1255  portal->autoHeld = true;
1256  HoldPortal(portal);
1257  }
1258  }
1259 }
bool autoHeld
Definition: portal.h:150
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
bool portalPinned
Definition: portal.h:149
PortalStrategy strategy
Definition: portal.h:143
#define ereport(elevel, rest)
Definition: elog.h:122
Portal portal
Definition: portalmem.c:51
static void HoldPortal(Portal portal)
Definition: portalmem.c:630
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
int errmsg(const char *fmt,...)
Definition: elog.c:797
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225

◆ MarkPortalActive()

void MarkPortalActive ( Portal  portal)

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

393 {
394  /* For safety, this is a runtime test not just an Assert */
395  if (portal->status != PORTAL_READY)
396  ereport(ERROR,
397  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
398  errmsg("portal \"%s\" cannot be run", portal->name)));
399  /* Perform the state transition */
400  portal->status = PORTAL_ACTIVE;
402 }
int errcode(int sqlerrcode)
Definition: elog.c:575
const char * name
Definition: portal.h:117
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
SubTransactionId activeSubid
Definition: portal.h:131
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:641
PortalStatus status
Definition: portal.h:148
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ MarkPortalDone()

void MarkPortalDone ( Portal  portal)

Definition at line 411 of file portalmem.c.

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

Referenced by PortalRun().

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

◆ MarkPortalFailed()

void MarkPortalFailed ( Portal  portal)

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

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

◆ PinPortal()

void PinPortal ( Portal  portal)

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

369 {
370  if (portal->portalPinned)
371  elog(ERROR, "portal already pinned");
372 
373  portal->portalPinned = true;
374 }
#define ERROR
Definition: elog.h:43
bool portalPinned
Definition: portal.h:149
#define elog
Definition: elog.h:219

◆ PortalCreateHoldStore()

void PortalCreateHoldStore ( Portal  portal)

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

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

◆ PortalDefineQuery()

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

Definition at line 281 of file portalmem.c.

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

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

287 {
288  AssertArg(PortalIsValid(portal));
289  AssertState(portal->status == PORTAL_NEW);
290 
291  AssertArg(sourceText != NULL);
292  AssertArg(commandTag != NULL || stmts == NIL);
293 
294  portal->prepStmtName = prepStmtName;
295  portal->sourceText = sourceText;
296  portal->commandTag = commandTag;
297  portal->stmts = stmts;
298  portal->cplan = cplan;
299  portal->status = PORTAL_DEFINED;
300 }
#define NIL
Definition: pg_list.h:69
#define AssertState(condition)
Definition: c.h:702
CachedPlan * cplan
Definition: portal.h:137
List * stmts
Definition: portal.h:136
const char * commandTag
Definition: portal.h:135
#define AssertArg(condition)
Definition: c.h:701
#define PortalIsValid(p)
Definition: portal.h:201
const char * sourceText
Definition: portal.h:134
PortalStatus status
Definition: portal.h:148
const char * prepStmtName
Definition: portal.h:118

◆ PortalDrop()

void PortalDrop ( Portal  portal,
bool  isTopCommit 
)

Definition at line 465 of file portalmem.c.

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

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

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

◆ PortalErrorCleanup()

void PortalErrorCleanup ( void  )

Definition at line 898 of file portalmem.c.

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

Referenced by PostgresMain().

899 {
901  PortalHashEnt *hentry;
902 
903  hash_seq_init(&status, PortalHashTable);
904 
905  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
906  {
907  Portal portal = hentry->portal;
908 
909  if (portal->autoHeld)
910  {
911  portal->portalPinned = false;
912  PortalDrop(portal, false);
913  }
914  }
915 }
bool autoHeld
Definition: portal.h:150
bool portalPinned
Definition: portal.h:149
Portal portal
Definition: portalmem.c:51
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:465
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225

◆ 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:136
#define lfirst_node(type, lc)
Definition: pg_list.h:109
bool canSetTag
Definition: plannodes.h:53

◆ PortalHashTableDeleteAll()

void PortalHashTableDeleteAll ( void  )

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

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

◆ PreCommit_Portals()

bool PreCommit_Portals ( bool  isPrepare)

Definition at line 670 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(), InvalidSubTransactionId, portalhashent::portal, PORTAL_ACTIVE, PORTAL_READY, PortalDrop(), PortalData::portalPinned, PortalData::resowner, status(), and PortalData::status.

Referenced by CommitTransaction(), and PrepareTransaction().

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

◆ ThereAreNoReadyPortals()

bool ThereAreNoReadyPortals ( void  )

Definition at line 1198 of file portalmem.c.

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

Referenced by CopyFrom().

1199 {
1201  PortalHashEnt *hentry;
1202 
1203  hash_seq_init(&status, PortalHashTable);
1204 
1205  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1206  {
1207  Portal portal = hentry->portal;
1208 
1209  if (portal->status == PORTAL_READY)
1210  return false;
1211  }
1212 
1213  return true;
1214 }
Portal portal
Definition: portalmem.c:51
PortalStatus status
Definition: portal.h:148
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225

◆ UnpinPortal()

void UnpinPortal ( Portal  portal)

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

378 {
379  if (!portal->portalPinned)
380  elog(ERROR, "portal not pinned");
381 
382  portal->portalPinned = false;
383 }
#define ERROR
Definition: elog.h:43
bool portalPinned
Definition: portal.h:149
#define elog
Definition: elog.h:219