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