PostgreSQL Source Code git master
Loading...
Searching...
No Matches
portal.h File Reference
#include "datatype/timestamp.h"
#include "executor/execdesc.h"
#include "tcop/cmdtag.h"
#include "utils/plancache.h"
#include "utils/resowner.h"
Include dependency graph for portal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PortalData
 

Macros

#define PortalIsValid(p)   ((p) != NULL)
 

Typedefs

typedef enum PortalStrategy PortalStrategy
 
typedef enum PortalStatus PortalStatus
 
typedef struct PortalDataPortal
 
typedef struct PortalData PortalData
 

Enumerations

enum  PortalStrategy {
  PORTAL_ONE_SELECT , PORTAL_ONE_RETURNING , PORTAL_ONE_MOD_WITH , PORTAL_UTIL_SELECT ,
  PORTAL_MULTI_QUERY
}
 
enum  PortalStatus {
  PORTAL_NEW , PORTAL_DEFINED , PORTAL_READY , PORTAL_ACTIVE ,
  PORTAL_DONE , PORTAL_FAILED
}
 

Functions

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

Macro Definition Documentation

◆ PortalIsValid

#define PortalIsValid (   p)    ((p) != NULL)

Definition at line 211 of file portal.h.

Typedef Documentation

◆ Portal

Definition at line 113 of file portal.h.

◆ PortalData

◆ PortalStatus

◆ PortalStrategy

Enumeration Type Documentation

◆ PortalStatus

Enumerator
PORTAL_NEW 
PORTAL_DEFINED 
PORTAL_READY 
PORTAL_ACTIVE 
PORTAL_DONE 
PORTAL_FAILED 

Definition at line 103 of file portal.h.

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

◆ PortalStrategy

Enumerator
PORTAL_ONE_SELECT 
PORTAL_ONE_RETURNING 
PORTAL_ONE_MOD_WITH 
PORTAL_UTIL_SELECT 
PORTAL_MULTI_QUERY 

Definition at line 89 of file portal.h.

90{
PortalStrategy
Definition portal.h:90
@ PORTAL_ONE_RETURNING
Definition portal.h:92
@ PORTAL_MULTI_QUERY
Definition portal.h:95
@ PORTAL_ONE_SELECT
Definition portal.h:91
@ PORTAL_ONE_MOD_WITH
Definition portal.h:93
@ PORTAL_UTIL_SELECT
Definition portal.h:94

Function Documentation

◆ AtAbort_Portals()

void AtAbort_Portals ( void  )
extern

Definition at line 782 of file portalmem.c.

783{
784 HASH_SEQ_STATUS status;
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 */
798 MarkPortalFailed(portal);
799
800 /*
801 * Do nothing else to cursors held over from a previous transaction.
802 */
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 (portal->cleanup)
828 {
829 portal->cleanup(portal);
830 portal->cleanup = NULL;
831 }
832
833 /* drop cached plan reference, if any */
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:744
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1415
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1380
bool shmem_exit_inprogress
Definition ipc.c:46
void MemoryContextDeleteChildren(MemoryContext context)
Definition mcxt.c:555
static HTAB * PortalHashTable
Definition portalmem.c:56
void MarkPortalFailed(Portal portal)
Definition portalmem.c:443
static void PortalReleaseCachedPlan(Portal portal)
Definition portalmem.c:311
static int fb(int x)
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

References PortalData::autoHeld, PortalData::cleanup, PortalData::createSubid, fb(), hash_seq_init(), hash_seq_search(), InvalidSubTransactionId, MarkPortalFailed(), MemoryContextDeleteChildren(), 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  )
extern

Definition at line 860 of file portalmem.c.

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

References Assert, PortalData::autoHeld, PortalData::cleanup, PortalData::createSubid, elog, fb(), hash_seq_init(), hash_seq_search(), InvalidSubTransactionId, PortalData::name, 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 
)
extern

Definition at line 981 of file portalmem.c.

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

References PortalData::activeSubid, PortalData::cleanup, PortalData::createSubid, fb(), hash_seq_init(), hash_seq_search(), MarkPortalFailed(), MemoryContextDeleteChildren(), 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)
extern

Definition at line 1094 of file portalmem.c.

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

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

Referenced by CleanupSubTransaction().

◆ AtSubCommit_Portals()

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

Definition at line 945 of file portalmem.c.

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

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

Referenced by CommitSubTransaction().

◆ CreateNewPortal()

Portal CreateNewPortal ( void  )
extern

Definition at line 237 of file portalmem.c.

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

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

Referenced by ExecuteQuery(), and SPI_cursor_open_internal().

◆ CreatePortal()

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

Definition at line 177 of file portalmem.c.

178{
179 Portal portal;
180
181 Assert(name);
182
183 portal = GetPortalByName(name);
184 if (PortalIsValid(portal))
185 {
186 if (!allowDup)
189 errmsg("cursor \"%s\" already exists", name)));
190 if (!dupSilent)
193 errmsg("closing existing cursor \"%s\"",
194 name)));
195 PortalDrop(portal, false);
196 }
197
198 /* make new portal structure */
199 portal = (Portal) MemoryContextAllocZero(TopPortalContext, sizeof *portal);
200
201 /* initialize portal context; typically it won't store much */
203 "PortalContext",
205
206 /* create a resource owner for the portal */
208 "Portal");
209
210 /* initialize portal fields that don't start off zero */
211 portal->status = PORTAL_NEW;
212 portal->cleanup = PortalCleanup;
214 portal->activeSubid = portal->createSubid;
218 portal->atStart = true;
219 portal->atEnd = true; /* disallow fetches until query is set */
220 portal->visible = true;
222
223 /* put portal in table (sets portal->name) */
225
226 /* for named portals reuse portal->name copy */
227 MemoryContextSetIdentifier(portal->portalContext, portal->name[0] ? portal->name : "<unnamed>");
228
229 return portal;
230}
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition mcxt.c:661
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
static char * errmsg
#define CURSOR_OPT_NO_SCROLL
struct PortalData * Portal
Definition portal.h:113
#define PortalIsValid(p)
Definition portal.h:211
void PortalCleanup(Portal portal)
Definition portalcmds.c:274
#define PortalHashTableInsert(PORTAL, NAME)
Definition portalmem.c:70
static MemoryContext TopPortalContext
Definition portalmem.c:93
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition resowner.c:418
ResourceOwner CurTransactionResourceOwner
Definition resowner.c:174
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:793
int GetCurrentTransactionNestLevel(void)
Definition xact.c:931
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition xact.c:881

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, fb(), GetCurrentStatementStartTimestamp(), GetCurrentSubTransactionId(), GetCurrentTransactionNestLevel(), GetPortalByName(), MemoryContextAllocZero(), MemoryContextSetIdentifier(), name, PortalData::name, 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  )
extern

Definition at line 106 of file portalmem.c.

107{
108 HASHCTL ctl;
109
111
113 "TopPortalContext",
115
116 ctl.keysize = MAX_PORTALNAME_LEN;
117 ctl.entrysize = sizeof(PortalHashEnt);
118
119 /*
120 * use PORTALS_PER_USER as a guess of how many hash table entries to
121 * create, initially
122 */
125}
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
#define HASH_STRINGS
Definition hsearch.h:96
#define HASH_ELEM
Definition hsearch.h:95
MemoryContext TopMemoryContext
Definition mcxt.c:166
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
struct portalhashent PortalHashEnt
#define PORTALS_PER_USER
Definition portalmem.c:40
tree ctl
Definition radixtree.h:1838

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, ctl, fb(), hash_create(), HASH_ELEM, HASH_STRINGS, MAX_PORTALNAME_LEN, PortalHashTable, PORTALS_PER_USER, TopMemoryContext, and TopPortalContext.

Referenced by InitPostgres().

◆ ForgetPortalSnapshots()

void ForgetPortalSnapshots ( void  )
extern

Definition at line 1258 of file portalmem.c.

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

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

Referenced by _SPI_commit(), and _SPI_rollback().

◆ GetPortalByName()

◆ HoldPinnedPortals()

void HoldPinnedPortals ( void  )
extern

Definition at line 1209 of file portalmem.c.

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

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

Referenced by _SPI_commit(), and _SPI_rollback().

◆ MarkPortalActive()

void MarkPortalActive ( Portal  portal)
extern

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)
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, fb(), GetCurrentSubTransactionId(), PortalData::name, PORTAL_ACTIVE, PORTAL_READY, and PortalData::status.

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

◆ MarkPortalDone()

void MarkPortalDone ( Portal  portal)
extern

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 (portal->cleanup)
430 {
431 portal->cleanup(portal);
432 portal->cleanup = NULL;
433 }
434}

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

Referenced by PortalRun().

◆ MarkPortalFailed()

void MarkPortalFailed ( Portal  portal)
extern

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 (portal->cleanup)
458 {
459 portal->cleanup(portal);
460 portal->cleanup = NULL;
461 }
462}

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

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

◆ PinPortal()

void PinPortal ( Portal  portal)
extern

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)
extern

Definition at line 332 of file portalmem.c.

333{
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 */
356
357 portal->holdStore =
359 true, work_mem);
360
362}
int work_mem
Definition globals.c:131
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define CURSOR_OPT_SCROLL
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:331

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, CURSOR_OPT_SCROLL, PortalData::cursorOptions, fb(), 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 
)
extern

Definition at line 284 of file portalmem.c.

290{
291 Assert(PortalIsValid(portal));
292 Assert(portal->status == PORTAL_NEW);
293
294 Assert(sourceText != NULL);
295 Assert(commandTag != CMDTAG_UNKNOWN || stmts == NIL);
296
297 portal->prepStmtName = prepStmtName;
298 portal->sourceText = sourceText;
299 portal->commandTag = commandTag;
300 SetQueryCompletion(&portal->qc, commandTag, 0);
301 portal->stmts = stmts;
302 portal->cplan = cplan;
303 portal->status = PORTAL_DEFINED;
304}
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition cmdtag.h:37
#define NIL
Definition pg_list.h:68
CommandTag commandTag
Definition portal.h:137
const char * sourceText
Definition portal.h:136
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

References Assert, PortalData::commandTag, PortalData::cplan, fb(), NIL, PORTAL_DEFINED, PORTAL_NEW, PortalIsValid, PortalData::prepStmtName, PortalData::qc, SetQueryCompletion(), 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 
)
extern

Definition at line 469 of file portalmem.c.

470{
471 Assert(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)
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)
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 (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 */
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);
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:1616
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define PortalHashTableDelete(PORTAL)
Definition portalmem.c:83
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition resowner.c:655
void ResourceOwnerDelete(ResourceOwner owner)
Definition resowner.c:868
@ 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:879
void tuplestore_end(Tuplestorestate *state)
Definition tuplestore.c:493

References Assert, PortalData::cleanup, ereport, errcode(), errmsg, ERROR, fb(), PortalData::holdContext, PortalData::holdSnapshot, PortalData::holdStore, MemoryContextDelete(), MemoryContextSwitchTo(), PortalData::name, pfree(), 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  )
extern

Definition at line 919 of file portalmem.c.

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

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

Referenced by PostgresMain().

◆ PortalGetPrimaryStmt()

PlannedStmt * PortalGetPrimaryStmt ( Portal  portal)
extern

Definition at line 153 of file portalmem.c.

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

References fb(), lfirst_node, stmt, and PortalData::stmts.

Referenced by FetchPortalTargetList(), and PortalStart().

◆ PortalHashTableDeleteAll()

void PortalHashTableDeleteAll ( void  )
extern

Definition at line 608 of file portalmem.c.

609{
610 HASH_SEQ_STATUS status;
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 */
628 hash_seq_term(&status);
630 }
631}
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition dynahash.c:1509

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

Referenced by DiscardAll(), and PerformPortalClose().

◆ PreCommit_Portals()

bool PreCommit_Portals ( bool  isPrepare)
extern

Definition at line 678 of file portalmem.c.

679{
680 bool result = false;
681 HASH_SEQ_STATUS status;
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)
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 */
768 hash_seq_term(&status);
770 }
771
772 return result;
773}
#define CURSOR_OPT_HOLD

References PortalData::autoHeld, PortalData::createSubid, CURSOR_OPT_HOLD, PortalData::cursorOptions, elog, ereport, errcode(), errmsg, ERROR, fb(), hash_seq_init(), hash_seq_search(), hash_seq_term(), HoldPortal(), PortalData::holdSnapshot, InvalidSubTransactionId, 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  )
extern

Definition at line 1173 of file portalmem.c.

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

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

Referenced by CopyFrom().

◆ UnpinPortal()

void UnpinPortal ( Portal  portal)
extern

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