PostgreSQL Source Code  git master
portalmem.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/portalcmds.h"
#include "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.

Referenced by CreateNewPortal(), and EnablePortalManager().

◆ PortalHashTableDelete

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

Definition at line 81 of file portalmem.c.

Referenced by PortalDrop().

◆ 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)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
#define ERROR
Definition: elog.h:46
static HTAB * PortalHashTable
Definition: portalmem.c:54

Definition at line 68 of file portalmem.c.

Referenced by CreatePortal().

◆ PortalHashTableLookup

#define PortalHashTableLookup (   NAME,
  PORTAL 
)
Value:
do { \
PortalHashEnt *hentry; \
\
(NAME), HASH_FIND, NULL); \
if (hentry) \
PORTAL = hentry->portal; \
else \
PORTAL = NULL; \
} while(0)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static HTAB * PortalHashTable
Definition: portalmem.c:54

Definition at line 56 of file portalmem.c.

Referenced by GetPortalByName().

◆ PORTALS_PER_USER

#define PORTALS_PER_USER   16

Definition at line 38 of file portalmem.c.

Referenced by EnablePortalManager().

Typedef Documentation

◆ PortalHashEnt

typedef struct portalhashent PortalHashEnt

Function Documentation

◆ AtAbort_Portals()

void AtAbort_Portals ( void  )

Definition at line 781 of file portalmem.c.

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

Referenced by AbortOutOfAnyTransaction(), and AbortTransaction().

782 {
784  PortalHashEnt *hentry;
785 
786  hash_seq_init(&status, PortalHashTable);
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  */
796  if (portal->status == PORTAL_ACTIVE && shmem_exit_inprogress)
797  MarkPortalFailed(portal);
798 
799  /*
800  * Do nothing else to cursors held over from a previous transaction.
801  */
802  if (portal->createSubid == InvalidSubTransactionId)
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 */
833  PortalReleaseCachedPlan(portal);
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 }
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:310
bool autoHeld
Definition: portal.h:153
void(* cleanup)(Portal portal)
Definition: portal.h:122
MemoryContext portalContext
Definition: portal.h:120
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:263
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:442
PortalStatus status
Definition: portal.h:151
#define InvalidSubTransactionId
Definition: c.h:593
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
ResourceOwner resowner
Definition: portal.h:121
bool shmem_exit_inprogress
Definition: ipc.c:45
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
#define PointerIsValid(pointer)
Definition: c.h:698

◆ AtCleanup_Portals()

void AtCleanup_Portals ( void  )

Definition at line 858 of file portalmem.c.

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

Referenced by CleanupTransaction().

859 {
861  PortalHashEnt *hentry;
862 
863  hash_seq_init(&status, PortalHashTable);
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 }
bool autoHeld
Definition: portal.h:153
void(* cleanup)(Portal portal)
Definition: portal.h:122
const char * name
Definition: portal.h:118
bool portalPinned
Definition: portal.h:152
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
#define WARNING
Definition: elog.h:40
#define Assert(condition)
Definition: c.h:804
PortalStatus status
Definition: portal.h:151
#define InvalidSubTransactionId
Definition: c.h:593
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
ResourceOwner resowner
Definition: portal.h:121
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:468
#define elog(elevel,...)
Definition: elog.h:232
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
#define PointerIsValid(pointer)
Definition: c.h:698

◆ AtSubAbort_Portals()

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

Definition at line 979 of file portalmem.c.

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

Referenced by AbortOutOfAnyTransaction(), and AbortSubTransaction().

983 {
985  PortalHashEnt *hentry;
986 
987  hash_seq_init(&status, PortalHashTable);
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 */
1066  PortalReleaseCachedPlan(portal);
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 }
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:310
void(* cleanup)(Portal portal)
Definition: portal.h:122
MemoryContext portalContext
Definition: portal.h:120
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:263
SubTransactionId activeSubid
Definition: portal.h:132
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:442
PortalStatus status
Definition: portal.h:151
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:801
ResourceOwner resowner
Definition: portal.h:121
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
#define PointerIsValid(pointer)
Definition: c.h:698

◆ AtSubCleanup_Portals()

void AtSubCleanup_Portals ( SubTransactionId  mySubid)

Definition at line 1092 of file portalmem.c.

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

Referenced by CleanupSubTransaction().

1093 {
1095  PortalHashEnt *hentry;
1096 
1097  hash_seq_init(&status, PortalHashTable);
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 }
void(* cleanup)(Portal portal)
Definition: portal.h:122
const char * name
Definition: portal.h:118
bool portalPinned
Definition: portal.h:152
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
#define WARNING
Definition: elog.h:40
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:468
#define elog(elevel,...)
Definition: elog.h:232
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
#define PointerIsValid(pointer)
Definition: c.h:698

◆ AtSubCommit_Portals()

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

Definition at line 943 of file portalmem.c.

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

Referenced by CommitSubTransaction().

947 {
949  PortalHashEnt *hentry;
950 
951  hash_seq_init(&status, PortalHashTable);
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
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
SubTransactionId activeSubid
Definition: portal.h:132
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:801
ResourceOwner resowner
Definition: portal.h:121
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229

◆ CreateNewPortal()

Portal CreateNewPortal ( void  )

Definition at line 235 of file portalmem.c.

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

Referenced by ExecuteQuery(), and SPI_cursor_open_internal().

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 }
Portal CreatePortal(const char *name, bool allowDup, bool dupSilent)
Definition: portalmem.c:175
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
#define sprintf
Definition: port.h:219
#define MAX_PORTALNAME_LEN
Definition: portalmem.c:46

◆ CreatePortal()

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

Definition at line 175 of file portalmem.c.

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

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

176 {
177  Portal portal;
178 
180 
181  portal = GetPortalByName(name);
182  if (PortalIsValid(portal))
183  {
184  if (!allowDup)
185  ereport(ERROR,
186  (errcode(ERRCODE_DUPLICATE_CURSOR),
187  errmsg("cursor \"%s\" already exists", name)));
188  if (!dupSilent)
190  (errcode(ERRCODE_DUPLICATE_CURSOR),
191  errmsg("closing existing cursor \"%s\"",
192  name)));
193  PortalDrop(portal, false);
194  }
195 
196  /* make new portal structure */
197  portal = (Portal) MemoryContextAllocZero(TopPortalContext, sizeof *portal);
198 
199  /* initialize portal context; typically it won't store much */
201  "PortalContext",
203 
204  /* create a resource owner for the portal */
206  "Portal");
207 
208  /* initialize portal fields that don't start off zero */
209  portal->status = PORTAL_NEW;
210  portal->cleanup = PortalCleanup;
212  portal->activeSubid = portal->createSubid;
214  portal->strategy = PORTAL_MULTI_QUERY;
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) */
222  PortalHashTableInsert(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 createLevel
Definition: portal.h:133
#define AllocSetContextCreate
Definition: memutils.h:173
bool atEnd
Definition: portal.h:200
bool visible
Definition: portal.h:205
void(* cleanup)(Portal portal)
Definition: portal.h:122
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:147
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:205
int errcode(int sqlerrcode)
Definition: elog.c:698
void PortalCleanup(Portal portal)
Definition: portalcmds.c:263
MemoryContext portalContext
Definition: portal.h:120
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2820
static MemoryContext TopPortalContext
Definition: portalmem.c:91
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:46
struct PortalData * Portal
Definition: portal.h:113
PortalStrategy strategy
Definition: portal.h:146
SubTransactionId createSubid
Definition: portal.h:131
#define AssertArg(condition)
Definition: c.h:806
TimestampTz creation_time
Definition: portal.h:204
#define WARNING
Definition: elog.h:40
#define PortalIsValid(p)
Definition: portal.h:212
SubTransactionId activeSubid
Definition: portal.h:132
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
#define ereport(elevel,...)
Definition: elog.h:157
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:858
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:724
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:336
PortalStatus status
Definition: portal.h:151
const char * name
Definition: encode.c:561
ResourceOwner resowner
Definition: portal.h:121
bool atStart
Definition: portal.h:199
int errmsg(const char *fmt,...)
Definition: elog.c:909
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:468
int cursorOptions
Definition: portal.h:147
#define PortalHashTableInsert(PORTAL, NAME)
Definition: portalmem.c:68
#define PointerIsValid(pointer)
Definition: c.h:698
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:808
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:428

◆ EnablePortalManager()

void EnablePortalManager ( void  )

Definition at line 104 of file portalmem.c.

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

Referenced by InitPostgres().

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

◆ ForgetPortalSnapshots()

void ForgetPortalSnapshots ( void  )

Definition at line 1303 of file portalmem.c.

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

Referenced by _SPI_commit(), and _SPI_rollback().

1304 {
1306  PortalHashEnt *hentry;
1307  int numPortalSnaps = 0;
1308  int numActiveSnaps = 0;
1309 
1310  /* First, scan PortalHashTable and clear portalSnapshot fields */
1311  hash_seq_init(&status, PortalHashTable);
1312 
1313  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1314  {
1315  Portal portal = hentry->portal;
1316 
1317  if (portal->portalSnapshot != NULL)
1318  {
1319  portal->portalSnapshot = NULL;
1320  numPortalSnaps++;
1321  }
1322  /* portal->holdSnapshot will be cleaned up in PreCommit_Portals */
1323  }
1324 
1325  /*
1326  * Now, pop all the active snapshots, which should be just those that were
1327  * portal snapshots. Ideally we'd drive this directly off the portal
1328  * scan, but there's no good way to visit the portals in the correct
1329  * order. So just cross-check after the fact.
1330  */
1331  while (ActiveSnapshotSet())
1332  {
1334  numActiveSnaps++;
1335  }
1336 
1337  if (numPortalSnaps != numActiveSnaps)
1338  elog(ERROR, "portal snapshots (%d) did not account for all active snapshots (%d)",
1339  numPortalSnaps, numActiveSnaps);
1340 }
void PopActiveSnapshot(void)
Definition: snapmgr.c:774
#define ERROR
Definition: elog.h:46
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:813
Portal portal
Definition: portalmem.c:51
Snapshot portalSnapshot
Definition: portal.h:170
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
#define elog(elevel,...)
Definition: elog.h:232
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229

◆ GetPortalByName()

Portal GetPortalByName ( const char *  name)

Definition at line 130 of file portalmem.c.

References PointerIsValid, portalhashent::portal, and PortalHashTableLookup.

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

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

◆ HoldPinnedPortals()

void HoldPinnedPortals ( void  )

Definition at line 1254 of file portalmem.c.

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

Referenced by _SPI_commit(), and _SPI_rollback().

1255 {
1257  PortalHashEnt *hentry;
1258 
1259  hash_seq_init(&status, PortalHashTable);
1260 
1261  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1262  {
1263  Portal portal = hentry->portal;
1264 
1265  if (portal->portalPinned && !portal->autoHeld)
1266  {
1267  /*
1268  * Doing transaction control, especially abort, inside a cursor
1269  * loop that is not read-only, for example using UPDATE ...
1270  * RETURNING, has weird semantics issues. Also, this
1271  * implementation wouldn't work, because such portals cannot be
1272  * held. (The core grammar enforces that only SELECT statements
1273  * can drive a cursor, but for example PL/pgSQL does not restrict
1274  * it.)
1275  */
1276  if (portal->strategy != PORTAL_ONE_SELECT)
1277  ereport(ERROR,
1278  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
1279  errmsg("cannot perform transaction commands inside a cursor loop that is not read-only")));
1280 
1281  /* Verify it's in a suitable state to be held */
1282  if (portal->status != PORTAL_READY)
1283  elog(ERROR, "pinned portal is not ready to be auto-held");
1284 
1285  HoldPortal(portal);
1286  portal->autoHeld = true;
1287  }
1288  }
1289 }
bool autoHeld
Definition: portal.h:153
int errcode(int sqlerrcode)
Definition: elog.c:698
#define ERROR
Definition: elog.h:46
bool portalPinned
Definition: portal.h:152
PortalStrategy strategy
Definition: portal.h:146
Portal portal
Definition: portalmem.c:51
#define ereport(elevel,...)
Definition: elog.h:157
static void HoldPortal(Portal portal)
Definition: portalmem.c:636
PortalStatus status
Definition: portal.h:151
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229

◆ HoldPortal()

static void HoldPortal ( Portal  portal)
static

Definition at line 636 of file portalmem.c.

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

Referenced by HoldPinnedPortals(), and PreCommit_Portals().

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 */
646  PortalReleaseCachedPlan(portal);
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 }
int createLevel
Definition: portal.h:133
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:310
SubTransactionId createSubid
Definition: portal.h:131
SubTransactionId activeSubid
Definition: portal.h:132
void PersistHoldablePortal(Portal portal)
Definition: portalcmds.c:316
#define InvalidSubTransactionId
Definition: c.h:593
void PortalCreateHoldStore(Portal portal)
Definition: portalmem.c:331
ResourceOwner resowner
Definition: portal.h:121

◆ MarkPortalActive()

void MarkPortalActive ( Portal  portal)

Definition at line 395 of file portalmem.c.

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

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

396 {
397  /* For safety, this is a runtime test not just an Assert */
398  if (portal->status != PORTAL_READY)
399  ereport(ERROR,
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 }
int errcode(int sqlerrcode)
Definition: elog.c:698
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:46
SubTransactionId activeSubid
Definition: portal.h:132
#define ereport(elevel,...)
Definition: elog.h:157
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:724
PortalStatus status
Definition: portal.h:151
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ MarkPortalDone()

void MarkPortalDone ( Portal  portal)

Definition at line 414 of file portalmem.c.

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

Referenced by PortalRun().

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 }
void(* cleanup)(Portal portal)
Definition: portal.h:122
#define Assert(condition)
Definition: c.h:804
PortalStatus status
Definition: portal.h:151
#define PointerIsValid(pointer)
Definition: c.h:698

◆ MarkPortalFailed()

void MarkPortalFailed ( Portal  portal)

Definition at line 442 of file portalmem.c.

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

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

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 }
void(* cleanup)(Portal portal)
Definition: portal.h:122
#define Assert(condition)
Definition: c.h:804
PortalStatus status
Definition: portal.h:151
#define PointerIsValid(pointer)
Definition: c.h:698

◆ pg_cursor()

Datum pg_cursor ( PG_FUNCTION_ARGS  )

Definition at line 1131 of file portalmem.c.

References ReturnSetInfo::allowedModes, BoolGetDatum, CreateTemplateTupleDesc(), PortalData::creation_time, CStringGetTextDatum, CURSOR_OPT_BINARY, CURSOR_OPT_HOLD, CURSOR_OPT_SCROLL, PortalData::cursorOptions, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg(), ERROR, hash_seq_init(), hash_seq_search(), IsA, MemoryContextSwitchTo(), MemSet, PortalData::name, portalhashent::portal, ReturnSetInfo::returnMode, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SFRM_Materialize_Random, PortalData::sourceText, TimestampTzGetDatum, TupleDescInitEntry(), tuplestore_begin_heap(), tuplestore_donestoring, tuplestore_putvalues(), values, PortalData::visible, and work_mem.

1132 {
1133  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1134  TupleDesc tupdesc;
1135  Tuplestorestate *tupstore;
1136  MemoryContext per_query_ctx;
1137  MemoryContext oldcontext;
1138  HASH_SEQ_STATUS hash_seq;
1139  PortalHashEnt *hentry;
1140 
1141  /* check to see if caller supports us returning a tuplestore */
1142  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1143  ereport(ERROR,
1144  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1145  errmsg("set-valued function called in context that cannot accept a set")));
1146  if (!(rsinfo->allowedModes & SFRM_Materialize))
1147  ereport(ERROR,
1148  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1149  errmsg("materialize mode required, but it is not allowed in this context")));
1150 
1151  /* need to build tuplestore in query context */
1152  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1153  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1154 
1155  /*
1156  * build tupdesc for result tuples. This must match the definition of the
1157  * pg_cursors view in system_views.sql
1158  */
1159  tupdesc = CreateTemplateTupleDesc(6);
1160  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
1161  TEXTOID, -1, 0);
1162  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
1163  TEXTOID, -1, 0);
1164  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_holdable",
1165  BOOLOID, -1, 0);
1166  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_binary",
1167  BOOLOID, -1, 0);
1168  TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable",
1169  BOOLOID, -1, 0);
1170  TupleDescInitEntry(tupdesc, (AttrNumber) 6, "creation_time",
1171  TIMESTAMPTZOID, -1, 0);
1172 
1173  /*
1174  * We put all the tuples into a tuplestore in one scan of the hashtable.
1175  * This avoids any issue of the hashtable possibly changing between calls.
1176  */
1177  tupstore =
1179  false, work_mem);
1180 
1181  /* generate junk in short-term context */
1182  MemoryContextSwitchTo(oldcontext);
1183 
1184  hash_seq_init(&hash_seq, PortalHashTable);
1185  while ((hentry = hash_seq_search(&hash_seq)) != NULL)
1186  {
1187  Portal portal = hentry->portal;
1188  Datum values[6];
1189  bool nulls[6];
1190 
1191  /* report only "visible" entries */
1192  if (!portal->visible)
1193  continue;
1194 
1195  MemSet(nulls, 0, sizeof(nulls));
1196 
1197  values[0] = CStringGetTextDatum(portal->name);
1198  values[1] = CStringGetTextDatum(portal->sourceText);
1199  values[2] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_HOLD);
1200  values[3] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_BINARY);
1201  values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
1202  values[5] = TimestampTzGetDatum(portal->creation_time);
1203 
1204  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1205  }
1206 
1207  /* clean up and return the tuplestore */
1208  tuplestore_donestoring(tupstore);
1209 
1210  rsinfo->returnMode = SFRM_Materialize;
1211  rsinfo->setResult = tupstore;
1212  rsinfo->setDesc = tupdesc;
1213 
1214  return (Datum) 0;
1215 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define IsA(nodeptr, _type_)
Definition: nodes.h:588
bool visible
Definition: portal.h:205
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:45
#define CURSOR_OPT_BINARY
Definition: parsenodes.h:2818
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2823
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:698
#define MemSet(start, val, len)
Definition: c.h:1008
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:46
#define TimestampTzGetDatum(X)
Definition: timestamp.h:32
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:583
TimestampTz creation_time
Definition: portal.h:204
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
uintptr_t Datum
Definition: postgres.h:411
int work_mem
Definition: globals.c:124
const char * sourceText
Definition: portal.h:136
#define BoolGetDatum(X)
Definition: postgres.h:446
#define ereport(elevel,...)
Definition: elog.h:157
int allowedModes
Definition: execnodes.h:306
SetFunctionReturnMode returnMode
Definition: execnodes.h:308
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:234
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
Tuplestorestate * setResult
Definition: execnodes.h:311
static Datum values[MAXATTR]
Definition: bootstrap.c:156
ExprContext * econtext
Definition: execnodes.h:304
TupleDesc setDesc
Definition: execnodes.h:312
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2819
#define CStringGetTextDatum(s)
Definition: builtins.h:86
static HTAB * PortalHashTable
Definition: portalmem.c:54
int cursorOptions
Definition: portal.h:147
int16 AttrNumber
Definition: attnum.h:21

◆ PinPortal()

void PinPortal ( Portal  portal)

Definition at line 371 of file portalmem.c.

References elog, ERROR, and PortalData::portalPinned.

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

372 {
373  if (portal->portalPinned)
374  elog(ERROR, "portal already pinned");
375 
376  portal->portalPinned = true;
377 }
#define ERROR
Definition: elog.h:46
bool portalPinned
Definition: portal.h:152
#define elog(elevel,...)
Definition: elog.h:232

◆ PortalCreateHoldStore()

void PortalCreateHoldStore ( Portal  portal)

Definition at line 331 of file portalmem.c.

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

Referenced by FillPortalStore(), and HoldPortal().

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 }
#define AllocSetContextCreate
Definition: memutils.h:173
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext holdContext
Definition: portal.h:178
static MemoryContext TopPortalContext
Definition: portalmem.c:91
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:195
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int work_mem
Definition: globals.c:124
#define Assert(condition)
Definition: c.h:804
Snapshot holdSnapshot
Definition: portal.h:188
Tuplestorestate * holdStore
Definition: portal.h:177
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2819
int cursorOptions
Definition: portal.h:147

◆ 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.

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

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

288 {
289  AssertArg(PortalIsValid(portal));
290  AssertState(portal->status == PORTAL_NEW);
291 
292  AssertArg(sourceText != NULL);
293  AssertArg(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:65
#define AssertState(condition)
Definition: c.h:807
CommandTag commandTag
Definition: portal.h:137
CachedPlan * cplan
Definition: portal.h:140
List * stmts
Definition: portal.h:139
uint64 nprocessed
Definition: cmdtag.h:31
#define AssertArg(condition)
Definition: c.h:806
#define PortalIsValid(p)
Definition: portal.h:212
const char * sourceText
Definition: portal.h:136
CommandTag commandTag
Definition: cmdtag.h:30
QueryCompletion qc
Definition: portal.h:138
PortalStatus status
Definition: portal.h:151
const char * prepStmtName
Definition: portal.h:119

◆ PortalDrop()

void PortalDrop ( Portal  portal,
bool  isTopCommit 
)

Definition at line 468 of file portalmem.c.

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

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

469 {
470  AssertArg(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)
477  ereport(ERROR,
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)
485  ereport(ERROR,
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 */
518  PortalReleaseCachedPlan(portal);
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);
571  ResourceOwnerDelete(portal->resowner);
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 MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:310
void(* cleanup)(Portal portal)
Definition: portal.h:122
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:737
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:698
MemoryContext holdContext
Definition: portal.h:178
MemoryContext portalContext
Definition: portal.h:120
#define PortalHashTableDelete(PORTAL)
Definition: portalmem.c:81
void pfree(void *pointer)
Definition: mcxt.c:1169
const char * name
Definition: portal.h:118
#define ERROR
Definition: elog.h:46
bool portalPinned
Definition: portal.h:152
#define AssertArg(condition)
Definition: c.h:806
#define PortalIsValid(p)
Definition: portal.h:212
#define ereport(elevel,...)
Definition: elog.h:157
#define Assert(condition)
Definition: c.h:804
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:486
Snapshot portalSnapshot
Definition: portal.h:170
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:880
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
Snapshot holdSnapshot
Definition: portal.h:188
PortalStatus status
Definition: portal.h:151
ResourceOwner resowner
Definition: portal.h:121
Tuplestorestate * holdStore
Definition: portal.h:177
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define PointerIsValid(pointer)
Definition: c.h:698

◆ PortalErrorCleanup()

void PortalErrorCleanup ( void  )

Definition at line 917 of file portalmem.c.

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

Referenced by PostgresMain().

918 {
920  PortalHashEnt *hentry;
921 
922  hash_seq_init(&status, PortalHashTable);
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 }
bool autoHeld
Definition: portal.h:153
bool portalPinned
Definition: portal.h:152
Portal portal
Definition: portalmem.c:51
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:468
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229

◆ PortalGetPrimaryStmt()

PlannedStmt* PortalGetPrimaryStmt ( Portal  portal)

Definition at line 151 of file portalmem.c.

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

Referenced by FetchPortalTargetList(), and PortalStart().

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

◆ PortalHashTableDeleteAll()

void PortalHashTableDeleteAll ( void  )

Definition at line 607 of file portalmem.c.

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

Referenced by DiscardAll(), and PerformPortalClose().

608 {
610  PortalHashEnt *hentry;
611 
612  if (PortalHashTable == NULL)
613  return;
614 
615  hash_seq_init(&status, PortalHashTable);
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);
628  hash_seq_init(&status, PortalHashTable);
629  }
630 }
Portal portal
Definition: portalmem.c:51
PortalStatus status
Definition: portal.h:151
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:468
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1512

◆ PortalReleaseCachedPlan()

static void PortalReleaseCachedPlan ( Portal  portal)
static

Definition at line 310 of file portalmem.c.

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

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

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 }
#define NIL
Definition: pg_list.h:65
CachedPlan * cplan
Definition: portal.h:140
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1264
List * stmts
Definition: portal.h:139

◆ PreCommit_Portals()

bool PreCommit_Portals ( bool  isPrepare)

Definition at line 677 of file portalmem.c.

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

Referenced by CommitTransaction(), and PrepareTransaction().

678 {
679  bool result = false;
681  PortalHashEnt *hentry;
682 
683  hash_seq_init(&status, PortalHashTable);
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)
736  ereport(ERROR,
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);
768  hash_seq_init(&status, PortalHashTable);
769  }
770 
771  return result;
772 }
bool autoHeld
Definition: portal.h:153
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2823
int errcode(int sqlerrcode)
Definition: elog.c:698
#define ERROR
Definition: elog.h:46
bool portalPinned
Definition: portal.h:152
SubTransactionId createSubid
Definition: portal.h:131
Portal portal
Definition: portalmem.c:51
#define ereport(elevel,...)
Definition: elog.h:157
static void HoldPortal(Portal portal)
Definition: portalmem.c:636
Snapshot portalSnapshot
Definition: portal.h:170
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:880
Snapshot holdSnapshot
Definition: portal.h:188
PortalStatus status
Definition: portal.h:151
#define InvalidSubTransactionId
Definition: c.h:593
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
ResourceOwner resowner
Definition: portal.h:121
int errmsg(const char *fmt,...)
Definition: elog.c:909
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:468
#define elog(elevel,...)
Definition: elog.h:232
static HTAB * PortalHashTable
Definition: portalmem.c:54
int cursorOptions
Definition: portal.h:147
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1512

◆ ThereAreNoReadyPortals()

bool ThereAreNoReadyPortals ( void  )

Definition at line 1218 of file portalmem.c.

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

Referenced by CopyFrom().

1219 {
1221  PortalHashEnt *hentry;
1222 
1223  hash_seq_init(&status, PortalHashTable);
1224 
1225  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1226  {
1227  Portal portal = hentry->portal;
1228 
1229  if (portal->status == PORTAL_READY)
1230  return false;
1231  }
1232 
1233  return true;
1234 }
Portal portal
Definition: portalmem.c:51
PortalStatus status
Definition: portal.h:151
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
static HTAB * PortalHashTable
Definition: portalmem.c:54
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:229

◆ UnpinPortal()

void UnpinPortal ( Portal  portal)

Definition at line 380 of file portalmem.c.

References elog, ERROR, and PortalData::portalPinned.

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

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

Variable Documentation

◆ PortalHashTable

HTAB* PortalHashTable = NULL
static

Definition at line 54 of file portalmem.c.

◆ TopPortalContext

MemoryContext TopPortalContext = NULL
static

Definition at line 91 of file portalmem.c.