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

Go to the source code of this file.

Data Structures

struct  portalhashent
 

Macros

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

Typedefs

typedef struct portalhashent PortalHashEnt
 

Functions

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

Variables

static HTABPortalHashTable = NULL
 
static MemoryContext TopPortalContext = NULL
 

Macro Definition Documentation

◆ MAX_PORTALNAME_LEN

#define MAX_PORTALNAME_LEN   NAMEDATALEN

Definition at line 47 of file portalmem.c.

◆ PortalHashTableDelete

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

Definition at line 82 of file portalmem.c.

◆ PortalHashTableInsert

#define PortalHashTableInsert (   PORTAL,
  NAME 
)
Value:
do { \
PortalHashEnt *hentry; bool found; \
\
(NAME), HASH_ENTER, &found); \
if (found) \
elog(ERROR, "duplicate portal name"); \
hentry->portal = PORTAL; \
/* To avoid duplicate storage, make PORTAL->name point to htab entry */ \
PORTAL->name = hentry->portalname; \
} while(0)
#define ERROR
Definition: elog.h:33
@ HASH_ENTER
Definition: hsearch.h:114

Definition at line 69 of file portalmem.c.

◆ PortalHashTableLookup

#define PortalHashTableLookup (   NAME,
  PORTAL 
)
Value:
do { \
PortalHashEnt *hentry; \
\
(NAME), HASH_FIND, NULL); \
if (hentry) \
PORTAL = hentry->portal; \
else \
PORTAL = NULL; \
} while(0)
@ HASH_FIND
Definition: hsearch.h:113

Definition at line 57 of file portalmem.c.

◆ PORTALS_PER_USER

#define PORTALS_PER_USER   16

Definition at line 39 of file portalmem.c.

Typedef Documentation

◆ PortalHashEnt

typedef struct portalhashent PortalHashEnt

Function Documentation

◆ AtAbort_Portals()

void AtAbort_Portals ( void  )

Definition at line 782 of file portalmem.c.

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

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

Referenced by AbortOutOfAnyTransaction(), and AbortTransaction().

◆ AtCleanup_Portals()

void AtCleanup_Portals ( void  )

Definition at line 859 of file portalmem.c.

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

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

Referenced by CleanupTransaction().

◆ AtSubAbort_Portals()

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

Definition at line 980 of file portalmem.c.

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

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

Referenced by AbortOutOfAnyTransaction(), and AbortSubTransaction().

◆ AtSubCleanup_Portals()

void AtSubCleanup_Portals ( SubTransactionId  mySubid)

Definition at line 1093 of file portalmem.c.

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

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

Referenced by CleanupSubTransaction().

◆ AtSubCommit_Portals()

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

Definition at line 944 of file portalmem.c.

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

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

Referenced by CommitSubTransaction().

◆ CreateNewPortal()

Portal CreateNewPortal ( void  )

Definition at line 236 of file portalmem.c.

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

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

Referenced by ExecuteQuery(), and SPI_cursor_open_internal().

◆ CreatePortal()

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

Definition at line 176 of file portalmem.c.

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

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

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

◆ EnablePortalManager()

void EnablePortalManager ( void  )

Definition at line 105 of file portalmem.c.

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

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

Referenced by InitPostgres().

◆ ForgetPortalSnapshots()

void ForgetPortalSnapshots ( void  )

Definition at line 1256 of file portalmem.c.

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

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

Referenced by _SPI_commit(), and _SPI_rollback().

◆ GetPortalByName()

Portal GetPortalByName ( const char *  name)

◆ HoldPinnedPortals()

void HoldPinnedPortals ( void  )

Definition at line 1207 of file portalmem.c.

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

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

Referenced by _SPI_commit(), and _SPI_rollback().

◆ HoldPortal()

static void HoldPortal ( Portal  portal)
static

Definition at line 637 of file portalmem.c.

638 {
639  /*
640  * Note that PersistHoldablePortal() must release all resources used by
641  * the portal that are local to the creating transaction.
642  */
643  PortalCreateHoldStore(portal);
644  PersistHoldablePortal(portal);
645 
646  /* drop cached plan reference, if any */
647  PortalReleaseCachedPlan(portal);
648 
649  /*
650  * Any resources belonging to the portal will be released in the upcoming
651  * transaction-wide cleanup; the portal will no longer have its own
652  * resources.
653  */
654  portal->resowner = NULL;
655 
656  /*
657  * Having successfully exported the holdable cursor, mark it as not
658  * belonging to this transaction.
659  */
662  portal->createLevel = 0;
663 }
void PersistHoldablePortal(Portal portal)
Definition: portalcmds.c:316
void PortalCreateHoldStore(Portal portal)
Definition: portalmem.c:332

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

Referenced by HoldPinnedPortals(), and PreCommit_Portals().

◆ MarkPortalActive()

void MarkPortalActive ( Portal  portal)

Definition at line 396 of file portalmem.c.

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

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

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

◆ MarkPortalDone()

void MarkPortalDone ( Portal  portal)

Definition at line 415 of file portalmem.c.

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

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

Referenced by PortalRun().

◆ MarkPortalFailed()

void MarkPortalFailed ( Portal  portal)

Definition at line 443 of file portalmem.c.

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

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

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

◆ pg_cursor()

Datum pg_cursor ( PG_FUNCTION_ARGS  )

Definition at line 1132 of file portalmem.c.

1133 {
1134  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1135  HASH_SEQ_STATUS hash_seq;
1136  PortalHashEnt *hentry;
1137 
1138  /*
1139  * We put all the tuples into a tuplestore in one scan of the hashtable.
1140  * This avoids any issue of the hashtable possibly changing between calls.
1141  */
1142  SetSingleFuncCall(fcinfo, 0);
1143 
1144  hash_seq_init(&hash_seq, PortalHashTable);
1145  while ((hentry = hash_seq_search(&hash_seq)) != NULL)
1146  {
1147  Portal portal = hentry->portal;
1148  Datum values[6];
1149  bool nulls[6];
1150 
1151  /* report only "visible" entries */
1152  if (!portal->visible)
1153  continue;
1154 
1155  MemSet(nulls, 0, sizeof(nulls));
1156 
1157  values[0] = CStringGetTextDatum(portal->name);
1158  values[1] = CStringGetTextDatum(portal->sourceText);
1163 
1164  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1165  }
1166 
1167  return (Datum) 0;
1168 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:85
#define MemSet(start, val, len)
Definition: c.h:1008
void SetSingleFuncCall(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3168
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:3172
#define CURSOR_OPT_BINARY
Definition: parsenodes.h:3167
uintptr_t Datum
Definition: postgres.h:411
#define BoolGetDatum(X)
Definition: postgres.h:446
const char * sourceText
Definition: portal.h:136
TupleDesc setDesc
Definition: execnodes.h:317
Tuplestorestate * setResult
Definition: execnodes.h:316
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define TimestampTzGetDatum(X)
Definition: timestamp.h:32

References BoolGetDatum, PortalData::creation_time, CStringGetTextDatum, CURSOR_OPT_BINARY, CURSOR_OPT_HOLD, CURSOR_OPT_SCROLL, PortalData::cursorOptions, hash_seq_init(), hash_seq_search(), MemSet, PortalData::name, PortalHashTable, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SetSingleFuncCall(), PortalData::sourceText, TimestampTzGetDatum, tuplestore_putvalues(), values, and PortalData::visible.

◆ PinPortal()

void PinPortal ( Portal  portal)

Definition at line 372 of file portalmem.c.

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

References elog, ERROR, and PortalData::portalPinned.

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

◆ PortalCreateHoldStore()

void PortalCreateHoldStore ( Portal  portal)

Definition at line 332 of file portalmem.c.

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

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

Referenced by FillPortalStore(), and HoldPortal().

◆ PortalDefineQuery()

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

Definition at line 283 of file portalmem.c.

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

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

◆ PortalDrop()

void PortalDrop ( Portal  portal,
bool  isTopCommit 
)

Definition at line 469 of file portalmem.c.

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

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

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

◆ PortalErrorCleanup()

void PortalErrorCleanup ( void  )

Definition at line 918 of file portalmem.c.

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

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

Referenced by PostgresMain().

◆ PortalGetPrimaryStmt()

PlannedStmt* PortalGetPrimaryStmt ( Portal  portal)

Definition at line 152 of file portalmem.c.

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

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

Referenced by FetchPortalTargetList(), and PortalStart().

◆ PortalHashTableDeleteAll()

void PortalHashTableDeleteAll ( void  )

Definition at line 608 of file portalmem.c.

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

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

Referenced by DiscardAll(), and PerformPortalClose().

◆ PortalReleaseCachedPlan()

static void PortalReleaseCachedPlan ( Portal  portal)
static

Definition at line 311 of file portalmem.c.

312 {
313  if (portal->cplan)
314  {
315  ReleaseCachedPlan(portal->cplan, NULL);
316  portal->cplan = NULL;
317 
318  /*
319  * We must also clear portal->stmts which is now a dangling reference
320  * to the cached plan's plan list. This protects any code that might
321  * try to examine the Portal later.
322  */
323  portal->stmts = NIL;
324  }
325 }
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1264

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

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

◆ PreCommit_Portals()

bool PreCommit_Portals ( bool  isPrepare)

Definition at line 678 of file portalmem.c.

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

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

Referenced by CommitTransaction(), and PrepareTransaction().

◆ ThereAreNoReadyPortals()

bool ThereAreNoReadyPortals ( void  )

Definition at line 1171 of file portalmem.c.

1172 {
1174  PortalHashEnt *hentry;
1175 
1177 
1178  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1179  {
1180  Portal portal = hentry->portal;
1181 
1182  if (portal->status == PORTAL_READY)
1183  return false;
1184  }
1185 
1186  return true;
1187 }

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

Referenced by CopyFrom().

◆ UnpinPortal()

void UnpinPortal ( Portal  portal)

Definition at line 381 of file portalmem.c.

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

References elog, ERROR, and PortalData::portalPinned.

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

Variable Documentation

◆ PortalHashTable

◆ TopPortalContext

MemoryContext TopPortalContext = NULL
static

Definition at line 92 of file portalmem.c.

Referenced by CreatePortal(), EnablePortalManager(), and PortalCreateHoldStore().