Simplify state managed by VACUUM.
[pgsql.git] / src / backend / commands / portalcmds.c
blob6f2397bd360e6cb2290fdf0acecbcfa7e588e2fb
1 /*-------------------------------------------------------------------------
3 * portalcmds.c
4 * Utility commands affecting portals (that is, SQL cursor commands)
6 * Note: see also tcop/pquery.c, which implements portal operations for
7 * the FE/BE protocol. This module uses pquery.c for some operations.
8 * And both modules depend on utils/mmgr/portalmem.c, which controls
9 * storage management for portals (but doesn't run any queries in them).
12 * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
13 * Portions Copyright (c) 1994, Regents of the University of California
16 * IDENTIFICATION
17 * src/backend/commands/portalcmds.c
19 *-------------------------------------------------------------------------
22 #include "postgres.h"
24 #include <limits.h>
26 #include "access/xact.h"
27 #include "commands/portalcmds.h"
28 #include "executor/executor.h"
29 #include "executor/tstoreReceiver.h"
30 #include "miscadmin.h"
31 #include "rewrite/rewriteHandler.h"
32 #include "tcop/pquery.h"
33 #include "tcop/tcopprot.h"
34 #include "utils/memutils.h"
35 #include "utils/snapmgr.h"
39 * PerformCursorOpen
40 * Execute SQL DECLARE CURSOR command.
42 void
43 PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo params,
44 bool isTopLevel)
46 Query *query = castNode(Query, cstmt->query);
47 List *rewritten;
48 PlannedStmt *plan;
49 Portal portal;
50 MemoryContext oldContext;
51 char *queryString;
54 * Disallow empty-string cursor name (conflicts with protocol-level
55 * unnamed portal).
57 if (!cstmt->portalname || cstmt->portalname[0] == '\0')
58 ereport(ERROR,
59 (errcode(ERRCODE_INVALID_CURSOR_NAME),
60 errmsg("invalid cursor name: must not be empty")));
63 * If this is a non-holdable cursor, we require that this statement has
64 * been executed inside a transaction block (or else, it would have no
65 * user-visible effect).
67 if (!(cstmt->options & CURSOR_OPT_HOLD))
68 RequireTransactionBlock(isTopLevel, "DECLARE CURSOR");
69 else if (InSecurityRestrictedOperation())
70 ereport(ERROR,
71 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
72 errmsg("cannot create a cursor WITH HOLD within security-restricted operation")));
75 * Parse analysis was done already, but we still have to run the rule
76 * rewriter. We do not do AcquireRewriteLocks: we assume the query either
77 * came straight from the parser, or suitable locks were acquired by
78 * plancache.c.
80 * Because the rewriter and planner tend to scribble on the input, we make
81 * a preliminary copy of the source querytree. This prevents problems in
82 * the case that the DECLARE CURSOR is in a portal or plpgsql function and
83 * is executed repeatedly. (See also the same hack in EXPLAIN and
84 * PREPARE.) XXX FIXME someday.
86 rewritten = QueryRewrite((Query *) copyObject(query));
88 /* SELECT should never rewrite to more or less than one query */
89 if (list_length(rewritten) != 1)
90 elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
92 query = linitial_node(Query, rewritten);
94 if (query->commandType != CMD_SELECT)
95 elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
97 /* Plan the query, applying the specified options */
98 plan = pg_plan_query(query, pstate->p_sourcetext, cstmt->options, params);
101 * Create a portal and copy the plan and query string into its memory.
103 portal = CreatePortal(cstmt->portalname, false, false);
105 oldContext = MemoryContextSwitchTo(portal->portalContext);
107 plan = copyObject(plan);
109 queryString = pstrdup(pstate->p_sourcetext);
111 PortalDefineQuery(portal,
112 NULL,
113 queryString,
114 CMDTAG_SELECT, /* cursor's query is always a SELECT */
115 list_make1(plan),
116 NULL);
118 /*----------
119 * Also copy the outer portal's parameter list into the inner portal's
120 * memory context. We want to pass down the parameter values in case we
121 * had a command like
122 * DECLARE c CURSOR FOR SELECT ... WHERE foo = $1
123 * This will have been parsed using the outer parameter set and the
124 * parameter value needs to be preserved for use when the cursor is
125 * executed.
126 *----------
128 params = copyParamList(params);
130 MemoryContextSwitchTo(oldContext);
133 * Set up options for portal.
135 * If the user didn't specify a SCROLL type, allow or disallow scrolling
136 * based on whether it would require any additional runtime overhead to do
137 * so. Also, we disallow scrolling for FOR UPDATE cursors.
139 portal->cursorOptions = cstmt->options;
140 if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
142 if (plan->rowMarks == NIL &&
143 ExecSupportsBackwardScan(plan->planTree))
144 portal->cursorOptions |= CURSOR_OPT_SCROLL;
145 else
146 portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
150 * Start execution, inserting parameters if any.
152 PortalStart(portal, params, 0, GetActiveSnapshot());
154 Assert(portal->strategy == PORTAL_ONE_SELECT);
157 * We're done; the query won't actually be run until PerformPortalFetch is
158 * called.
163 * PerformPortalFetch
164 * Execute SQL FETCH or MOVE command.
166 * stmt: parsetree node for command
167 * dest: where to send results
168 * qc: where to store a command completion status data.
170 * qc may be NULL if caller doesn't want status data.
172 void
173 PerformPortalFetch(FetchStmt *stmt,
174 DestReceiver *dest,
175 QueryCompletion *qc)
177 Portal portal;
178 uint64 nprocessed;
181 * Disallow empty-string cursor name (conflicts with protocol-level
182 * unnamed portal).
184 if (!stmt->portalname || stmt->portalname[0] == '\0')
185 ereport(ERROR,
186 (errcode(ERRCODE_INVALID_CURSOR_NAME),
187 errmsg("invalid cursor name: must not be empty")));
189 /* get the portal from the portal name */
190 portal = GetPortalByName(stmt->portalname);
191 if (!PortalIsValid(portal))
193 ereport(ERROR,
194 (errcode(ERRCODE_UNDEFINED_CURSOR),
195 errmsg("cursor \"%s\" does not exist", stmt->portalname)));
196 return; /* keep compiler happy */
199 /* Adjust dest if needed. MOVE wants destination DestNone */
200 if (stmt->ismove)
201 dest = None_Receiver;
203 /* Do it */
204 nprocessed = PortalRunFetch(portal,
205 stmt->direction,
206 stmt->howMany,
207 dest);
209 /* Return command status if wanted */
210 if (qc)
211 SetQueryCompletion(qc, stmt->ismove ? CMDTAG_MOVE : CMDTAG_FETCH,
212 nprocessed);
216 * PerformPortalClose
217 * Close a cursor.
219 void
220 PerformPortalClose(const char *name)
222 Portal portal;
224 /* NULL means CLOSE ALL */
225 if (name == NULL)
227 PortalHashTableDeleteAll();
228 return;
232 * Disallow empty-string cursor name (conflicts with protocol-level
233 * unnamed portal).
235 if (name[0] == '\0')
236 ereport(ERROR,
237 (errcode(ERRCODE_INVALID_CURSOR_NAME),
238 errmsg("invalid cursor name: must not be empty")));
241 * get the portal from the portal name
243 portal = GetPortalByName(name);
244 if (!PortalIsValid(portal))
246 ereport(ERROR,
247 (errcode(ERRCODE_UNDEFINED_CURSOR),
248 errmsg("cursor \"%s\" does not exist", name)));
249 return; /* keep compiler happy */
253 * Note: PortalCleanup is called as a side-effect, if not already done.
255 PortalDrop(portal, false);
259 * PortalCleanup
261 * Clean up a portal when it's dropped. This is the standard cleanup hook
262 * for portals.
264 * Note: if portal->status is PORTAL_FAILED, we are probably being called
265 * during error abort, and must be careful to avoid doing anything that
266 * is likely to fail again.
268 void
269 PortalCleanup(Portal portal)
271 QueryDesc *queryDesc;
274 * sanity checks
276 AssertArg(PortalIsValid(portal));
277 AssertArg(portal->cleanup == PortalCleanup);
280 * Shut down executor, if still running. We skip this during error abort,
281 * since other mechanisms will take care of releasing executor resources,
282 * and we can't be sure that ExecutorEnd itself wouldn't fail.
284 queryDesc = portal->queryDesc;
285 if (queryDesc)
288 * Reset the queryDesc before anything else. This prevents us from
289 * trying to shut down the executor twice, in case of an error below.
290 * The transaction abort mechanisms will take care of resource cleanup
291 * in such a case.
293 portal->queryDesc = NULL;
295 if (portal->status != PORTAL_FAILED)
297 ResourceOwner saveResourceOwner;
299 /* We must make the portal's resource owner current */
300 saveResourceOwner = CurrentResourceOwner;
301 if (portal->resowner)
302 CurrentResourceOwner = portal->resowner;
304 ExecutorFinish(queryDesc);
305 ExecutorEnd(queryDesc);
306 FreeQueryDesc(queryDesc);
308 CurrentResourceOwner = saveResourceOwner;
314 * PersistHoldablePortal
316 * Prepare the specified Portal for access outside of the current
317 * transaction. When this function returns, all future accesses to the
318 * portal must be done via the Tuplestore (not by invoking the
319 * executor).
321 void
322 PersistHoldablePortal(Portal portal)
324 QueryDesc *queryDesc = portal->queryDesc;
325 Portal saveActivePortal;
326 ResourceOwner saveResourceOwner;
327 MemoryContext savePortalContext;
328 MemoryContext oldcxt;
331 * If we're preserving a holdable portal, we had better be inside the
332 * transaction that originally created it.
334 Assert(portal->createSubid != InvalidSubTransactionId);
335 Assert(queryDesc != NULL);
338 * Caller must have created the tuplestore already ... but not a snapshot.
340 Assert(portal->holdContext != NULL);
341 Assert(portal->holdStore != NULL);
342 Assert(portal->holdSnapshot == NULL);
345 * Before closing down the executor, we must copy the tupdesc into
346 * long-term memory, since it was created in executor memory.
348 oldcxt = MemoryContextSwitchTo(portal->holdContext);
350 portal->tupDesc = CreateTupleDescCopy(portal->tupDesc);
352 MemoryContextSwitchTo(oldcxt);
355 * Check for improper portal use, and mark portal active.
357 MarkPortalActive(portal);
360 * Set up global portal context pointers.
362 saveActivePortal = ActivePortal;
363 saveResourceOwner = CurrentResourceOwner;
364 savePortalContext = PortalContext;
365 PG_TRY();
367 ActivePortal = portal;
368 if (portal->resowner)
369 CurrentResourceOwner = portal->resowner;
370 PortalContext = portal->portalContext;
372 MemoryContextSwitchTo(PortalContext);
374 PushActiveSnapshot(queryDesc->snapshot);
377 * Rewind the executor: we need to store the entire result set in the
378 * tuplestore, so that subsequent backward FETCHs can be processed.
380 ExecutorRewind(queryDesc);
383 * Change the destination to output to the tuplestore. Note we tell
384 * the tuplestore receiver to detoast all data passed through it; this
385 * makes it safe to not keep a snapshot associated with the data.
387 queryDesc->dest = CreateDestReceiver(DestTuplestore);
388 SetTuplestoreDestReceiverParams(queryDesc->dest,
389 portal->holdStore,
390 portal->holdContext,
391 true,
392 NULL,
393 NULL);
395 /* Fetch the result set into the tuplestore */
396 ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
398 queryDesc->dest->rDestroy(queryDesc->dest);
399 queryDesc->dest = NULL;
402 * Now shut down the inner executor.
404 portal->queryDesc = NULL; /* prevent double shutdown */
405 ExecutorFinish(queryDesc);
406 ExecutorEnd(queryDesc);
407 FreeQueryDesc(queryDesc);
410 * Set the position in the result set.
412 MemoryContextSwitchTo(portal->holdContext);
414 if (portal->atEnd)
417 * Just force the tuplestore forward to its end. The size of the
418 * skip request here is arbitrary.
420 while (tuplestore_skiptuples(portal->holdStore, 1000000, true))
421 /* continue */ ;
423 else
425 tuplestore_rescan(portal->holdStore);
427 if (!tuplestore_skiptuples(portal->holdStore,
428 portal->portalPos,
429 true))
430 elog(ERROR, "unexpected end of tuple stream");
433 PG_CATCH();
435 /* Uncaught error while executing portal: mark it dead */
436 MarkPortalFailed(portal);
438 /* Restore global vars and propagate error */
439 ActivePortal = saveActivePortal;
440 CurrentResourceOwner = saveResourceOwner;
441 PortalContext = savePortalContext;
443 PG_RE_THROW();
445 PG_END_TRY();
447 MemoryContextSwitchTo(oldcxt);
449 /* Mark portal not active */
450 portal->status = PORTAL_READY;
452 ActivePortal = saveActivePortal;
453 CurrentResourceOwner = saveResourceOwner;
454 PortalContext = savePortalContext;
456 PopActiveSnapshot();
459 * We can now release any subsidiary memory of the portal's context; we'll
460 * never use it again. The executor already dropped its context, but this
461 * will clean up anything that glommed onto the portal's context via
462 * PortalContext.
464 MemoryContextDeleteChildren(portal->portalContext);