PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
portalmem.c File Reference
#include "postgres.h"
#include "access/xact.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 46 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:955
#define WARNING
Definition: elog.h:36
@ HASH_REMOVE
Definition: hsearch.h:115
static HTAB * PortalHashTable
Definition: portalmem.c:54

Definition at line 81 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:39
@ HASH_ENTER
Definition: hsearch.h:114

Definition at line 68 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 56 of file portalmem.c.

◆ PORTALS_PER_USER

#define PORTALS_PER_USER   16

Definition at line 38 of file portalmem.c.

Typedef Documentation

◆ PortalHashEnt

typedef struct portalhashent PortalHashEnt

Function Documentation

◆ AtAbort_Portals()

void AtAbort_Portals ( void  )

Definition at line 781 of file portalmem.c.

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

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

Referenced by AbortOutOfAnyTransaction(), and AbortTransaction().

◆ AtCleanup_Portals()

void AtCleanup_Portals ( void  )

Definition at line 858 of file portalmem.c.

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

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

Referenced by CleanupTransaction().

◆ AtSubAbort_Portals()

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

Definition at line 979 of file portalmem.c.

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

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

Referenced by AbortOutOfAnyTransaction(), and AbortSubTransaction().

◆ AtSubCleanup_Portals()

void AtSubCleanup_Portals ( SubTransactionId  mySubid)

Definition at line 1092 of file portalmem.c.

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

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

Referenced by CleanupSubTransaction().

◆ AtSubCommit_Portals()

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

Definition at line 943 of file portalmem.c.

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

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

Referenced by CommitSubTransaction().

◆ CreateNewPortal()

Portal CreateNewPortal ( void  )

Definition at line 235 of file portalmem.c.

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

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

176{
177 Portal portal;
178
180
181 portal = GetPortalByName(name);
182 if (PortalIsValid(portal))
183 {
184 if (!allowDup)
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;
216 portal->atStart = true;
217 portal->atEnd = true; /* disallow fetches until query is set */
218 portal->visible = true;
220
221 /* put portal in table (sets portal->name) */
223
224 /* for named portals reuse portal->name copy */
225 MemoryContextSetIdentifier(portal->portalContext, portal->name[0] ? portal->name : "<unnamed>");
226
227 return portal;
228}
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1215
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:612
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3309
@ 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:211
void PortalCleanup(Portal portal)
Definition: portalcmds.c:273
#define PortalHashTableInsert(PORTAL, NAME)
Definition: portalmem.c:68
static MemoryContext TopPortalContext
Definition: portalmem.c:91
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:413
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:166
bool atEnd
Definition: portal.h:199
bool atStart
Definition: portal.h:198
TimestampTz creation_time
Definition: portal.h:203
bool visible
Definition: portal.h:204
int cursorOptions
Definition: portal.h:147
PortalStrategy strategy
Definition: portal.h:146
const char * name
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:790
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:928
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:878

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

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

◆ EnablePortalManager()

void EnablePortalManager ( void  )

Definition at line 104 of file portalmem.c.

105{
106 HASHCTL ctl;
107
108 Assert(TopPortalContext == NULL);
109
111 "TopPortalContext",
113
114 ctl.keysize = MAX_PORTALNAME_LEN;
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 */
123}
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
#define HASH_STRINGS
Definition: hsearch.h:96
#define HASH_ELEM
Definition: hsearch.h:95
MemoryContext TopMemoryContext
Definition: mcxt.c:149
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
struct portalhashent PortalHashEnt
#define PORTALS_PER_USER
Definition: portalmem.c:38
tree ctl
Definition: radixtree.h:1855

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, ctl, hash_create(), HASH_ELEM, HASH_STRINGS, 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{
1258 HASH_SEQ_STATUS status;
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:740
void PopActiveSnapshot(void)
Definition: snapmgr.c:703
Snapshot portalSnapshot
Definition: portal.h:169

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

Referenced by _SPI_commit(), and _SPI_rollback().

◆ GetPortalByName()

◆ HoldPinnedPortals()

void HoldPinnedPortals ( void  )

Definition at line 1207 of file portalmem.c.

1208{
1209 HASH_SEQ_STATUS status;
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:636

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

Referenced by _SPI_commit(), and _SPI_rollback().

◆ HoldPortal()

static void HoldPortal ( Portal  portal)
static

Definition at line 636 of file portalmem.c.

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

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

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

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

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

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

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

1132{
1133 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1134 HASH_SEQ_STATUS hash_seq;
1135 PortalHashEnt *hentry;
1136
1137 /*
1138 * We put all the tuples into a tuplestore in one scan of the hashtable.
1139 * This avoids any issue of the hashtable possibly changing between calls.
1140 */
1141 InitMaterializedSRF(fcinfo, 0);
1142
1143 hash_seq_init(&hash_seq, PortalHashTable);
1144 while ((hentry = hash_seq_search(&hash_seq)) != NULL)
1145 {
1146 Portal portal = hentry->portal;
1147 Datum values[6];
1148 bool nulls[6] = {0};
1149
1150 /* report only "visible" entries */
1151 if (!portal->visible)
1152 continue;
1153 /* also ignore it if PortalDefineQuery hasn't been called yet */
1154 if (!portal->sourceText)
1155 continue;
1156
1157 values[0] = CStringGetTextDatum(portal->name);
1163
1164 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1165 }
1166
1167 return (Datum) 0;
1168}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3308
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:3312
#define CURSOR_OPT_BINARY
Definition: parsenodes.h:3307
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
const char * sourceText
Definition: portal.h:136
TupleDesc setDesc
Definition: execnodes.h:343
Tuplestorestate * setResult
Definition: execnodes.h:342
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
static Datum TimestampTzGetDatum(TimestampTz X)
Definition: timestamp.h:52

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

◆ PinPortal()

void PinPortal ( Portal  portal)

Definition at line 371 of file portalmem.c.

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

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

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

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

288{
289 Assert(PortalIsValid(portal));
290 Assert(portal->status == PORTAL_NEW);
291
292 Assert(sourceText != NULL);
293 Assert(commandTag != CMDTAG_UNKNOWN || stmts == NIL);
294
295 portal->prepStmtName = prepStmtName;
296 portal->sourceText = sourceText;
297 portal->qc.commandTag = commandTag;
298 portal->qc.nprocessed = 0;
299 portal->commandTag = commandTag;
300 portal->stmts = stmts;
301 portal->cplan = cplan;
302 portal->status = PORTAL_DEFINED;
303}
#define NIL
Definition: pg_list.h:68
@ 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:32
CommandTag commandTag
Definition: cmdtag.h:31

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

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

◆ PortalDrop()

void PortalDrop ( Portal  portal,
bool  isTopCommit 
)

Definition at line 468 of file portalmem.c.

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

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

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

◆ PortalErrorCleanup()

void PortalErrorCleanup ( void  )

Definition at line 917 of file portalmem.c.

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

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

Referenced by PostgresMain().

◆ PortalGetPrimaryStmt()

PlannedStmt * PortalGetPrimaryStmt ( Portal  portal)

Definition at line 151 of file portalmem.c.

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

References lfirst_node, stmt, and PortalData::stmts.

Referenced by FetchPortalTargetList(), and PortalStart().

◆ PortalHashTableDeleteAll()

void PortalHashTableDeleteAll ( void  )

Definition at line 607 of file portalmem.c.

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

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

Referenced by DiscardAll(), and PerformPortalClose().

◆ PortalReleaseCachedPlan()

static void PortalReleaseCachedPlan ( Portal  portal)
static

Definition at line 310 of file portalmem.c.

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

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

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

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

Referenced by CommitTransaction(), and PrepareTransaction().

◆ ThereAreNoReadyPortals()

bool ThereAreNoReadyPortals ( void  )

Definition at line 1171 of file portalmem.c.

1172{
1173 HASH_SEQ_STATUS status;
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, and PortalData::status.

Referenced by CopyFrom().

◆ UnpinPortal()

void UnpinPortal ( Portal  portal)

Definition at line 380 of file portalmem.c.

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

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

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