PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
portal.h File Reference
#include "datatype/timestamp.h"
#include "executor/execdesc.h"
#include "tcop/cmdtag.h"
#include "utils/plancache.h"
#include "utils/resowner.h"
Include dependency graph for portal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  PortalData
 

Macros

#define PortalIsValid(p)   PointerIsValid(p)
 

Typedefs

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

Enumerations

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

Functions

void EnablePortalManager (void)
 
bool PreCommit_Portals (bool isPrepare)
 
void AtAbort_Portals (void)
 
void AtCleanup_Portals (void)
 
void PortalErrorCleanup (void)
 
void AtSubCommit_Portals (SubTransactionId mySubid, SubTransactionId parentSubid, 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, CachedPlanSource *plansource)
 
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)    PointerIsValid(p)

Definition at line 212 of file portal.h.

Typedef Documentation

◆ Portal

typedef struct PortalData* Portal

Definition at line 113 of file portal.h.

◆ PortalData

typedef struct PortalData PortalData

◆ PortalStatus

typedef enum PortalStatus PortalStatus

◆ PortalStrategy

Enumeration Type Documentation

◆ PortalStatus

Enumerator
PORTAL_NEW 
PORTAL_DEFINED 
PORTAL_READY 
PORTAL_ACTIVE 
PORTAL_DONE 
PORTAL_FAILED 

Definition at line 103 of file portal.h.

104{
105 PORTAL_NEW, /* freshly created */
106 PORTAL_DEFINED, /* PortalDefineQuery done */
107 PORTAL_READY, /* PortalStart complete, can run it */
108 PORTAL_ACTIVE, /* portal is running (can't delete it) */
109 PORTAL_DONE, /* portal is finished (don't re-run it) */
110 PORTAL_FAILED, /* portal got error (can't re-run it) */
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  )

Definition at line 783 of file portalmem.c.

784{
785 HASH_SEQ_STATUS status;
786 PortalHashEnt *hentry;
787
789
790 while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
791 {
792 Portal portal = hentry->portal;
793
794 /*
795 * When elog(FATAL) is progress, we need to set the active portal to
796 * failed, so that PortalCleanup() doesn't run the executor shutdown.
797 */
799 MarkPortalFailed(portal);
800
801 /*
802 * Do nothing else to cursors held over from a previous transaction.
803 */
805 continue;
806
807 /*
808 * Do nothing to auto-held cursors. This is similar to the case of a
809 * cursor from a previous transaction, but it could also be that the
810 * cursor was auto-held in this transaction, so it wants to live on.
811 */
812 if (portal->autoHeld)
813 continue;
814
815 /*
816 * If it was created in the current transaction, we can't do normal
817 * shutdown on a READY portal either; it might refer to objects
818 * created in the failed transaction. See comments in
819 * AtSubAbort_Portals.
820 */
821 if (portal->status == PORTAL_READY)
822 MarkPortalFailed(portal);
823
824 /*
825 * Allow portalcmds.c to clean up the state it knows about, if we
826 * haven't already.
827 */
828 if (PointerIsValid(portal->cleanup))
829 {
830 portal->cleanup(portal);
831 portal->cleanup = NULL;
832 }
833
834 /* drop cached plan reference, if any */
836
837 /*
838 * Any resources belonging to the portal will be released in the
839 * upcoming transaction-wide cleanup; they will be gone before we run
840 * PortalDrop.
841 */
842 portal->resowner = NULL;
843
844 /*
845 * Although we can't delete the portal data structure proper, we can
846 * release any memory in subsidiary contexts, such as executor state.
847 * The cleanup hook was the last thing that might have needed data
848 * there. But leave active portals alone.
849 */
850 if (portal->status != PORTAL_ACTIVE)
852 }
853}
#define InvalidSubTransactionId
Definition: c.h:629
#define PointerIsValid(pointer)
Definition: c.h:734
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:570
static HTAB * PortalHashTable
Definition: portalmem.c:54
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:444
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:312
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: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 860 of file portalmem.c.

861{
862 HASH_SEQ_STATUS status;
863 PortalHashEnt *hentry;
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 (PointerIsValid(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 WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:226
Assert(PointerIsAligned(start, uint64))
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:470
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, and WARNING.

Referenced by CleanupTransaction().

◆ AtSubAbort_Portals()

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

Definition at line 981 of file portalmem.c.

985{
986 HASH_SEQ_STATUS status;
987 PortalHashEnt *hentry;
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 {
1035 ResourceOwnerNewParent(portal->resowner, myXactOwner);
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 (PointerIsValid(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:914
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 1094 of file portalmem.c.

1095{
1096 HASH_SEQ_STATUS status;
1097 PortalHashEnt *hentry;
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 (PointerIsValid(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, 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 945 of file portalmem.c.

949{
950 HASH_SEQ_STATUS status;
951 PortalHashEnt *hentry;
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)
964 ResourceOwnerNewParent(portal->resowner, parentXactOwner);
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, 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:241
#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:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1290
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:643
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:190
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3377
struct PortalData * Portal
Definition: portal.h:113
#define PortalIsValid(p)
Definition: portal.h:212
void PortalCleanup(Portal portal)
Definition: portalcmds.c:274
#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:421
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:174
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:148
PortalStrategy strategy
Definition: portal.h:147
const char * name
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:791
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:929
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:879

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:165
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:180
struct portalhashent PortalHashEnt
#define PORTALS_PER_USER
Definition: portalmem.c:38
tree ctl
Definition: radixtree.h:1838

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

1259{
1260 HASH_SEQ_STATUS status;
1261 PortalHashEnt *hentry;
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;
1275 numPortalSnaps++;
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 {
1289 numActiveSnaps++;
1290 }
1291
1292 if (numPortalSnaps != numActiveSnaps)
1293 elog(ERROR, "portal snapshots (%d) did not account for all active snapshots (%d)",
1294 numPortalSnaps, numActiveSnaps);
1295}
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:799
void PopActiveSnapshot(void)
Definition: snapmgr.c:762
Snapshot portalSnapshot
Definition: portal.h:170

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

1210{
1211 HASH_SEQ_STATUS status;
1212 PortalHashEnt *hentry;
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,
1233 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
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:638

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

◆ MarkPortalActive()

void MarkPortalActive ( Portal  portal)

Definition at line 397 of file portalmem.c.

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

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

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

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

Referenced by PortalRun().

◆ MarkPortalFailed()

void MarkPortalFailed ( Portal  portal)

Definition at line 444 of file portalmem.c.

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

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

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

◆ PinPortal()

void PinPortal ( Portal  portal)

Definition at line 373 of file portalmem.c.

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

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

334{
335 MemoryContext oldcxt;
336
337 Assert(portal->holdContext == NULL);
338 Assert(portal->holdStore == NULL);
339 Assert(portal->holdSnapshot == NULL);
340
341 /*
342 * Create the memory context that is used for storage of the tuple set.
343 * Note this is NOT a child of the portal's portalContext.
344 */
345 portal->holdContext =
347 "PortalHoldContext",
349
350 /*
351 * Create the tuple store, selecting cross-transaction temp files, and
352 * enabling random access only if cursor requires scrolling.
353 *
354 * XXX: Should maintenance_work_mem be used for the portal size?
355 */
356 oldcxt = MemoryContextSwitchTo(portal->holdContext);
357
358 portal->holdStore =
360 true, work_mem);
361
362 MemoryContextSwitchTo(oldcxt);
363}
int work_mem
Definition: globals.c:132
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3376
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: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,
CachedPlanSource plansource 
)

Definition at line 282 of file portalmem.c.

289{
290 Assert(PortalIsValid(portal));
291 Assert(portal->status == PORTAL_NEW);
292
293 Assert(sourceText != NULL);
294 Assert(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->plansource = plansource;
304 portal->status = PORTAL_DEFINED;
305}
#define NIL
Definition: pg_list.h:68
CachedPlanSource * plansource
Definition: portal.h:141
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
uint64 nprocessed
Definition: cmdtag.h:32
CommandTag commandTag
Definition: cmdtag.h:31

References Assert(), QueryCompletion::commandTag, PortalData::commandTag, PortalData::cplan, NIL, QueryCompletion::nprocessed, PortalData::plansource, 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 470 of file portalmem.c.

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

920{
921 HASH_SEQ_STATUS status;
922 PortalHashEnt *hentry;
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, 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 609 of file portalmem.c.

610{
611 HASH_SEQ_STATUS status;
612 PortalHashEnt *hentry;
613
614 if (PortalHashTable == NULL)
615 return;
616
618 while ((hentry = hash_seq_search(&status)) != NULL)
619 {
620 Portal portal = hentry->portal;
621
622 /* Can't close the active portal (the one running the command) */
623 if (portal->status == PORTAL_ACTIVE)
624 continue;
625
626 PortalDrop(portal, false);
627
628 /* Restart the iteration in case that led to other drops */
629 hash_seq_term(&status);
631 }
632}
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().

◆ PreCommit_Portals()

bool PreCommit_Portals ( bool  isPrepare)

Definition at line 679 of file portalmem.c.

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

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

1174{
1175 HASH_SEQ_STATUS status;
1176 PortalHashEnt *hentry;
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 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 382 of file portalmem.c.

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

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