1 /*-------------------------------------------------------------------------
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
17 * src/backend/commands/portalcmds.c
19 *-------------------------------------------------------------------------
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"
40 * Execute SQL DECLARE CURSOR command.
43 PerformCursorOpen(ParseState
*pstate
, DeclareCursorStmt
*cstmt
, ParamListInfo params
,
46 Query
*query
= castNode(Query
, cstmt
->query
);
50 MemoryContext oldContext
;
54 * Disallow empty-string cursor name (conflicts with protocol-level
57 if (!cstmt
->portalname
|| cstmt
->portalname
[0] == '\0')
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())
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
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
,
114 CMDTAG_SELECT
, /* cursor's query is always a SELECT */
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
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
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
;
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
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.
173 PerformPortalFetch(FetchStmt
*stmt
,
181 * Disallow empty-string cursor name (conflicts with protocol-level
184 if (!stmt
->portalname
|| stmt
->portalname
[0] == '\0')
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
))
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 */
201 dest
= None_Receiver
;
204 nprocessed
= PortalRunFetch(portal
,
209 /* Return command status if wanted */
211 SetQueryCompletion(qc
, stmt
->ismove
? CMDTAG_MOVE
: CMDTAG_FETCH
,
220 PerformPortalClose(const char *name
)
224 /* NULL means CLOSE ALL */
227 PortalHashTableDeleteAll();
232 * Disallow empty-string cursor name (conflicts with protocol-level
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
))
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);
261 * Clean up a portal when it's dropped. This is the standard cleanup hook
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.
269 PortalCleanup(Portal portal
)
271 QueryDesc
*queryDesc
;
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
;
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
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
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
;
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
,
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
);
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))
425 tuplestore_rescan(portal
->holdStore
);
427 if (!tuplestore_skiptuples(portal
->holdStore
,
430 elog(ERROR
, "unexpected end of tuple stream");
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
;
447 MemoryContextSwitchTo(oldcxt
);
449 /* Mark portal not active */
450 portal
->status
= PORTAL_READY
;
452 ActivePortal
= saveActivePortal
;
453 CurrentResourceOwner
= saveResourceOwner
;
454 PortalContext
= savePortalContext
;
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
464 MemoryContextDeleteChildren(portal
->portalContext
);