1 /*------------------------------------------------------------------------- 2 * 3 * portal.h 4 * POSTGRES portal definitions. 5 * 6 * A portal is an abstraction which represents the execution state of 7 * a running or runnable query. Portals support both SQL-level CURSORs 8 * and protocol-level portals. 9 * 10 * Scrolling (nonsequential access) and suspension of execution are allowed 11 * only for portals that contain a single SELECT-type query. We do not want 12 * to let the client suspend an update-type query partway through! Because 13 * the query rewriter does not allow arbitrary ON SELECT rewrite rules, 14 * only queries that were originally update-type could produce multiple 15 * plan trees; so the restriction to a single query is not a problem 16 * in practice. 17 * 18 * For SQL cursors, we support three kinds of scroll behavior: 19 * 20 * (1) Neither NO SCROLL nor SCROLL was specified: to remain backward 21 * compatible, we allow backward fetches here, unless it would 22 * impose additional runtime overhead to do so. 23 * 24 * (2) NO SCROLL was specified: don't allow any backward fetches. 25 * 26 * (3) SCROLL was specified: allow all kinds of backward fetches, even 27 * if we need to take a performance hit to do so. (The planner sticks 28 * a Materialize node atop the query plan if needed.) 29 * 30 * Case #1 is converted to #2 or #3 by looking at the query itself and 31 * determining if scrollability can be supported without additional 32 * overhead. 33 * 34 * Protocol-level portals have no nonsequential-fetch API and so the 35 * distinction doesn't matter for them. They are always initialized 36 * to look like NO SCROLL cursors. 37 * 38 * 39 * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group 40 * Portions Copyright (c) 1994, Regents of the University of California 41 * 42 * src/include/utils/portal.h 43 * 44 *------------------------------------------------------------------------- 45 */ 46 #ifndef PORTAL_H 47 #define PORTAL_H 48 49 #include "datatype/timestamp.h" 50 #include "executor/execdesc.h" 51 #include "tcop/cmdtag.h" 52 #include "utils/plancache.h" 53 #include "utils/resowner.h" 54 55 /* 56 * We have several execution strategies for Portals, depending on what 57 * query or queries are to be executed. (Note: in all cases, a Portal 58 * executes just a single source-SQL query, and thus produces just a 59 * single result from the user's viewpoint. However, the rule rewriter 60 * may expand the single source query to zero or many actual queries.) 61 * 62 * PORTAL_ONE_SELECT: the portal contains one single SELECT query. We run 63 * the Executor incrementally as results are demanded. This strategy also 64 * supports holdable cursors (the Executor results can be dumped into a 65 * tuplestore for access after transaction completion). 66 * 67 * PORTAL_ONE_RETURNING: the portal contains a single INSERT/UPDATE/DELETE 68 * query with a RETURNING clause (plus possibly auxiliary queries added by 69 * rule rewriting). On first execution, we run the portal to completion 70 * and dump the primary query's results into the portal tuplestore; the 71 * results are then returned to the client as demanded. (We can't support 72 * suspension of the query partway through, because the AFTER TRIGGER code 73 * can't cope, and also because we don't want to risk failing to execute 74 * all the auxiliary queries.) 75 * 76 * PORTAL_ONE_MOD_WITH: the portal contains one single SELECT query, but 77 * it has data-modifying CTEs. This is currently treated the same as the 78 * PORTAL_ONE_RETURNING case because of the possibility of needing to fire 79 * triggers. It may act more like PORTAL_ONE_SELECT in future. 80 * 81 * PORTAL_UTIL_SELECT: the portal contains a utility statement that returns 82 * a SELECT-like result (for example, EXPLAIN or SHOW). On first execution, 83 * we run the statement and dump its results into the portal tuplestore; 84 * the results are then returned to the client as demanded. 85 * 86 * PORTAL_MULTI_QUERY: all other cases. Here, we do not support partial 87 * execution: the portal's queries will be run to completion on first call. 88 */ 89 typedef enum PortalStrategy 90 { 91 PORTAL_ONE_SELECT, 92 PORTAL_ONE_RETURNING, 93 PORTAL_ONE_MOD_WITH, 94 PORTAL_UTIL_SELECT, 95 PORTAL_MULTI_QUERY 96 } PortalStrategy; 97 98 /* 99 * A portal is always in one of these states. It is possible to transit 100 * from ACTIVE back to READY if the query is not run to completion; 101 * otherwise we never back up in status. 102 */ 103 typedef enum PortalStatus 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) */ 111 } PortalStatus; 112 113 typedef struct PortalData *Portal; 114 115 typedef struct PortalData 116 { 117 /* Bookkeeping data */ 118 const char *name; /* portal's name */ 119 const char *prepStmtName; /* source prepared statement (NULL if none) */ 120 MemoryContext portalContext; /* subsidiary memory for portal */ 121 ResourceOwner resowner; /* resources owned by portal */ 122 void (*cleanup) (Portal portal); /* cleanup hook */ 123 124 /* 125 * State data for remembering which subtransaction(s) the portal was 126 * created or used in. If the portal is held over from a previous 127 * transaction, both subxids are InvalidSubTransactionId. Otherwise, 128 * createSubid is the creating subxact and activeSubid is the last subxact 129 * in which we ran the portal. 130 */ 131 SubTransactionId createSubid; /* the creating subxact */ 132 SubTransactionId activeSubid; /* the last subxact with activity */ 133 134 /* The query or queries the portal will execute */ 135 const char *sourceText; /* text of query (as of 8.4, never NULL) */ 136 CommandTag commandTag; /* command tag for original query */ 137 QueryCompletion qc; /* command completion data for executed query */ 138 List *stmts; /* list of PlannedStmts */ 139 CachedPlan *cplan; /* CachedPlan, if stmts are from one */ 140 141 ParamListInfo portalParams; /* params to pass to query */ 142 QueryEnvironment *queryEnv; /* environment for query */ 143 144 /* Features/options */ 145 PortalStrategy strategy; /* see above */ 146 int cursorOptions; /* DECLARE CURSOR option bits */ 147 bool run_once; /* portal will only be run once */ 148 149 /* Status data */ 150 PortalStatus status; /* see above */ 151 bool portalPinned; /* a pinned portal can't be dropped */ 152 bool autoHeld; /* was automatically converted from pinned to 153 * held (see HoldPinnedPortals()) */ 154 155 /* If not NULL, Executor is active; call ExecutorEnd eventually: */ 156 QueryDesc *queryDesc; /* info needed for executor invocation */ 157 158 /* If portal returns tuples, this is their tupdesc: */ 159 TupleDesc tupDesc; /* descriptor for result tuples */ 160 /* and these are the format codes to use for the columns: */ 161 int16 *formats; /* a format code for each column */ 162 163 /* 164 * Outermost ActiveSnapshot for execution of the portal's queries. For 165 * all but a few utility commands, we require such a snapshot to exist. 166 * This ensures that TOAST references in query results can be detoasted, 167 * and helps to reduce thrashing of the process's exposed xmin. 168 */ 169 Snapshot portalSnapshot; /* active snapshot, or NULL if none */ 170 171 /* 172 * Where we store tuples for a held cursor or a PORTAL_ONE_RETURNING or 173 * PORTAL_UTIL_SELECT query. (A cursor held past the end of its 174 * transaction no longer has any active executor state.) 175 */ 176 Tuplestorestate *holdStore; /* store for holdable cursors */ 177 MemoryContext holdContext; /* memory containing holdStore */ 178 179 /* 180 * Snapshot under which tuples in the holdStore were read. We must keep a 181 * reference to this snapshot if there is any possibility that the tuples 182 * contain TOAST references, because releasing the snapshot could allow 183 * recently-dead rows to be vacuumed away, along with any toast data 184 * belonging to them. In the case of a held cursor, we avoid needing to 185 * keep such a snapshot by forcibly detoasting the data. 186 */ 187 Snapshot holdSnapshot; /* registered snapshot, or NULL if none */ 188 189 /* 190 * atStart, atEnd and portalPos indicate the current cursor position. 191 * portalPos is zero before the first row, N after fetching N'th row of 192 * query. After we run off the end, portalPos = # of rows in query, and 193 * atEnd is true. Note that atStart implies portalPos == 0, but not the 194 * reverse: we might have backed up only as far as the first row, not to 195 * the start. Also note that various code inspects atStart and atEnd, but 196 * only the portal movement routines should touch portalPos. 197 */ 198 bool atStart; 199 bool atEnd; 200 uint64 portalPos; 201 202 /* Presentation data, primarily used by the pg_cursors system view */ 203 TimestampTz creation_time; /* time at which this portal was defined */ 204 bool visible; /* include this portal in pg_cursors? */ 205 206 /* Stuff added at the end to avoid ABI break in stable branches: */ 207 int createLevel; /* creating subxact's nesting level */ 208 } PortalData; 209 210 /* 211 * PortalIsValid 212 * True iff portal is valid. 213 */ 214 #define PortalIsValid(p) PointerIsValid(p) 215 216 217 /* Prototypes for functions in utils/mmgr/portalmem.c */ 218 extern void EnablePortalManager(void); 219 extern bool PreCommit_Portals(bool isPrepare); 220 extern void AtAbort_Portals(void); 221 extern void AtCleanup_Portals(void); 222 extern void PortalErrorCleanup(void); 223 extern void AtSubCommit_Portals(SubTransactionId mySubid, 224 SubTransactionId parentSubid, 225 int parentLevel, 226 ResourceOwner parentXactOwner); 227 extern void AtSubAbort_Portals(SubTransactionId mySubid, 228 SubTransactionId parentSubid, 229 ResourceOwner myXactOwner, 230 ResourceOwner parentXactOwner); 231 extern void AtSubCleanup_Portals(SubTransactionId mySubid); 232 extern Portal CreatePortal(const char *name, bool allowDup, bool dupSilent); 233 extern Portal CreateNewPortal(void); 234 extern void PinPortal(Portal portal); 235 extern void UnpinPortal(Portal portal); 236 extern void MarkPortalActive(Portal portal); 237 extern void MarkPortalDone(Portal portal); 238 extern void MarkPortalFailed(Portal portal); 239 extern void PortalDrop(Portal portal, bool isTopCommit); 240 extern Portal GetPortalByName(const char *name); 241 extern void PortalDefineQuery(Portal portal, 242 const char *prepStmtName, 243 const char *sourceText, 244 CommandTag commandTag, 245 List *stmts, 246 CachedPlan *cplan); 247 extern PlannedStmt *PortalGetPrimaryStmt(Portal portal); 248 extern void PortalCreateHoldStore(Portal portal); 249 extern void PortalHashTableDeleteAll(void); 250 extern bool ThereAreNoReadyPortals(void); 251 extern void HoldPinnedPortals(void); 252 extern void ForgetPortalSnapshots(void); 253 254 #endif /* PORTAL_H */ 255