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)
 

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 774 of file portalmem.c.

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

Referenced by AbortOutOfAnyTransaction(), and AbortTransaction().

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

◆ AtCleanup_Portals()

void AtCleanup_Portals ( void  )

Definition at line 851 of file portalmem.c.

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

Referenced by CleanupTransaction().

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

◆ AtSubAbort_Portals()

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

Definition at line 970 of file portalmem.c.

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

Referenced by AbortOutOfAnyTransaction(), and AbortSubTransaction().

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

◆ AtSubCleanup_Portals()

void AtSubCleanup_Portals ( SubTransactionId  mySubid)

Definition at line 1083 of file portalmem.c.

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

Referenced by CleanupSubTransaction().

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

◆ AtSubCommit_Portals()

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

Definition at line 936 of file portalmem.c.

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

Referenced by CommitSubTransaction().

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

◆ CreateNewPortal()

Portal CreateNewPortal ( void  )

Definition at line 234 of file portalmem.c.

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

Referenced by ExecuteQuery(), and SPI_cursor_open_internal().

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

◆ CreatePortal()

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

Definition at line 175 of file portalmem.c.

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

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

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

◆ EnablePortalManager()

void EnablePortalManager ( void  )

Definition at line 104 of file portalmem.c.

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

Referenced by InitPostgres().

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

◆ GetPortalByName()

Portal GetPortalByName ( const char *  name)

Definition at line 130 of file portalmem.c.

References PointerIsValid, portalhashent::portal, and PortalHashTableLookup.

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

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

◆ HoldPinnedPortals()

void HoldPinnedPortals ( void  )

Definition at line 1245 of file portalmem.c.

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

Referenced by _SPI_commit(), and _SPI_rollback().

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

◆ MarkPortalActive()

void MarkPortalActive ( Portal  portal)

Definition at line 394 of file portalmem.c.

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

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

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

◆ MarkPortalDone()

void MarkPortalDone ( Portal  portal)

Definition at line 413 of file portalmem.c.

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

Referenced by PortalRun().

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

◆ MarkPortalFailed()

void MarkPortalFailed ( Portal  portal)

Definition at line 441 of file portalmem.c.

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

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

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

◆ PinPortal()

void PinPortal ( Portal  portal)

Definition at line 370 of file portalmem.c.

References elog, ERROR, and PortalData::portalPinned.

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

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

◆ PortalCreateHoldStore()

void PortalCreateHoldStore ( Portal  portal)

Definition at line 330 of file portalmem.c.

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

Referenced by FillPortalStore(), and HoldPortal().

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

◆ PortalDefineQuery()

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

Definition at line 281 of file portalmem.c.

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

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

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

◆ PortalDrop()

void PortalDrop ( Portal  portal,
bool  isTopCommit 
)

Definition at line 467 of file portalmem.c.

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

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

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

◆ PortalErrorCleanup()

void PortalErrorCleanup ( void  )

Definition at line 910 of file portalmem.c.

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

Referenced by PostgresMain().

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

◆ PortalGetPrimaryStmt()

PlannedStmt* PortalGetPrimaryStmt ( Portal  portal)

Definition at line 151 of file portalmem.c.

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

Referenced by FetchPortalTargetList(), and PortalStart().

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

◆ PortalHashTableDeleteAll()

void PortalHashTableDeleteAll ( void  )

Definition at line 603 of file portalmem.c.

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

Referenced by DiscardAll(), and PerformPortalClose().

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

◆ PreCommit_Portals()

bool PreCommit_Portals ( bool  isPrepare)

Definition at line 672 of file portalmem.c.

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

Referenced by CommitTransaction(), and PrepareTransaction().

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

◆ ThereAreNoReadyPortals()

bool ThereAreNoReadyPortals ( void  )

Definition at line 1209 of file portalmem.c.

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

Referenced by CopyFrom().

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

◆ UnpinPortal()

void UnpinPortal ( Portal  portal)

Definition at line 379 of file portalmem.c.

References elog, ERROR, and PortalData::portalPinned.

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

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