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-2007, PostgreSQL Global Development Group
13 * Portions Copyright (c) 1994, Regents of the University of California
17 * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.63 2007/04/12 06:53:46 neilc Exp $
19 *-------------------------------------------------------------------------
26 #include "access/xact.h"
27 #include "commands/portalcmds.h"
28 #include "executor/executor.h"
29 #include "optimizer/planner.h"
30 #include "rewrite/rewriteHandler.h"
31 #include "tcop/pquery.h"
32 #include "tcop/tcopprot.h"
33 #include "utils/memutils.h"
38 * Execute SQL DECLARE CURSOR command.
41 PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params,
42 const char *queryString, bool isTopLevel)
50 MemoryContext oldContext;
53 * Disallow empty-string cursor name (conflicts with protocol-level
56 if (!stmt->portalname || stmt->portalname[0] == '\0')
58 (errcode(ERRCODE_INVALID_CURSOR_NAME),
59 errmsg("invalid cursor name: must not be empty")));
62 * If this is a non-holdable cursor, we require that this statement has
63 * been executed inside a transaction block (or else, it would have no
64 * user-visible effect).
66 if (!(stmt->options & CURSOR_OPT_HOLD))
67 RequireTransactionChain(isTopLevel, "DECLARE CURSOR");
70 * Don't allow both SCROLL and NO SCROLL to be specified
72 if ((stmt->options & CURSOR_OPT_SCROLL) &&
73 (stmt->options & CURSOR_OPT_NO_SCROLL))
75 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
76 errmsg("cannot specify both SCROLL and NO SCROLL")));
78 /* Convert parameter type data to the form parser wants */
79 getParamListTypes(params, ¶m_types, &num_params);
82 * Run parse analysis and rewrite. Note this also acquires sufficient
83 * locks on the source table(s).
85 * Because the parser and planner tend to scribble on their input, we
86 * make a preliminary copy of the source querytree. This prevents
87 * problems in the case that the DECLARE CURSOR is in a portal or plpgsql
88 * function and is executed repeatedly. (See also the same hack in
89 * COPY and PREPARE.) XXX FIXME someday.
91 rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query),
92 queryString, param_types, num_params);
94 /* We don't expect more or less than one result query */
95 if (list_length(rewritten) != 1 || !IsA(linitial(rewritten), Query))
96 elog(ERROR, "unexpected rewrite result");
97 query = (Query *) linitial(rewritten);
98 if (query->commandType != CMD_SELECT)
99 elog(ERROR, "unexpected rewrite result");
101 /* But we must explicitly disallow DECLARE CURSOR ... SELECT INTO */
104 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
105 errmsg("DECLARE CURSOR cannot specify INTO")));
107 if (query->rowMarks != NIL)
109 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
110 errmsg("DECLARE CURSOR ... FOR UPDATE/SHARE is not supported"),
111 errdetail("Cursors must be READ ONLY.")));
114 plan = planner(query, true, stmt->options, params);
117 * Create a portal and copy the plan into its memory context.
119 portal = CreatePortal(stmt->portalname, false, false);
121 oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
123 plan = copyObject(plan);
125 PortalDefineQuery(portal,
128 "SELECT", /* cursor's query is always a SELECT */
133 * Also copy the outer portal's parameter list into the inner portal's
134 * memory context. We want to pass down the parameter values in case we
136 * DECLARE c CURSOR FOR SELECT ... WHERE foo = $1
137 * This will have been parsed using the outer parameter set and the
138 * parameter value needs to be preserved for use when the cursor is
142 params = copyParamList(params);
144 MemoryContextSwitchTo(oldContext);
147 * Set up options for portal.
149 * If the user didn't specify a SCROLL type, allow or disallow scrolling
150 * based on whether it would require any additional runtime overhead to do
153 portal->cursorOptions = stmt->options;
154 if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
156 if (ExecSupportsBackwardScan(plan->planTree))
157 portal->cursorOptions |= CURSOR_OPT_SCROLL;
159 portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
163 * Start execution, inserting parameters if any.
165 PortalStart(portal, params, ActiveSnapshot);
167 Assert(portal->strategy == PORTAL_ONE_SELECT);
170 * We're done; the query won't actually be run until PerformPortalFetch is
177 * Execute SQL FETCH or MOVE command.
179 * stmt: parsetree node for command
180 * dest: where to send results
181 * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
182 * in which to store a command completion status string.
184 * completionTag may be NULL if caller doesn't want a status string.
187 PerformPortalFetch(FetchStmt *stmt,
195 * Disallow empty-string cursor name (conflicts with protocol-level
198 if (!stmt->portalname || stmt->portalname[0] == '\0')
200 (errcode(ERRCODE_INVALID_CURSOR_NAME),
201 errmsg("invalid cursor name: must not be empty")));
203 /* get the portal from the portal name */
204 portal = GetPortalByName(stmt->portalname);
205 if (!PortalIsValid(portal))
208 (errcode(ERRCODE_UNDEFINED_CURSOR),
209 errmsg("cursor \"%s\" does not exist", stmt->portalname)));
210 return; /* keep compiler happy */
213 /* Adjust dest if needed. MOVE wants destination DestNone */
215 dest = None_Receiver;
218 nprocessed = PortalRunFetch(portal,
223 /* Return command status if wanted */
225 snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld",
226 stmt->ismove ? "MOVE" : "FETCH",
235 PerformPortalClose(const char *name)
239 /* NULL means CLOSE ALL */
242 PortalHashTableDeleteAll();
247 * Disallow empty-string cursor name (conflicts with protocol-level
252 (errcode(ERRCODE_INVALID_CURSOR_NAME),
253 errmsg("invalid cursor name: must not be empty")));
256 * get the portal from the portal name
258 portal = GetPortalByName(name);
259 if (!PortalIsValid(portal))
262 (errcode(ERRCODE_UNDEFINED_CURSOR),
263 errmsg("cursor \"%s\" does not exist", name)));
264 return; /* keep compiler happy */
268 * Note: PortalCleanup is called as a side-effect
270 PortalDrop(portal, false);
276 * Clean up a portal when it's dropped. This is the standard cleanup hook
280 PortalCleanup(Portal portal)
282 QueryDesc *queryDesc;
287 AssertArg(PortalIsValid(portal));
288 AssertArg(portal->cleanup == PortalCleanup);
291 * Shut down executor, if still running. We skip this during error abort,
292 * since other mechanisms will take care of releasing executor resources,
293 * and we can't be sure that ExecutorEnd itself wouldn't fail.
295 queryDesc = PortalGetQueryDesc(portal);
298 portal->queryDesc = NULL;
299 if (portal->status != PORTAL_FAILED)
301 ResourceOwner saveResourceOwner;
303 /* We must make the portal's resource owner current */
304 saveResourceOwner = CurrentResourceOwner;
307 CurrentResourceOwner = portal->resowner;
308 /* we do not need AfterTriggerEndQuery() here */
309 ExecutorEnd(queryDesc);
313 /* Ensure CurrentResourceOwner is restored on error */
314 CurrentResourceOwner = saveResourceOwner;
318 CurrentResourceOwner = saveResourceOwner;
324 * PersistHoldablePortal
326 * Prepare the specified Portal for access outside of the current
327 * transaction. When this function returns, all future accesses to the
328 * portal must be done via the Tuplestore (not by invoking the
332 PersistHoldablePortal(Portal portal)
334 QueryDesc *queryDesc = PortalGetQueryDesc(portal);
335 Portal saveActivePortal;
336 Snapshot saveActiveSnapshot;
337 ResourceOwner saveResourceOwner;
338 MemoryContext savePortalContext;
339 MemoryContext oldcxt;
342 * If we're preserving a holdable portal, we had better be inside the
343 * transaction that originally created it.
345 Assert(portal->createSubid != InvalidSubTransactionId);
346 Assert(queryDesc != NULL);
349 * Caller must have created the tuplestore already.
351 Assert(portal->holdContext != NULL);
352 Assert(portal->holdStore != NULL);
355 * Before closing down the executor, we must copy the tupdesc into
356 * long-term memory, since it was created in executor memory.
358 oldcxt = MemoryContextSwitchTo(portal->holdContext);
360 portal->tupDesc = CreateTupleDescCopy(portal->tupDesc);
362 MemoryContextSwitchTo(oldcxt);
365 * Check for improper portal use, and mark portal active.
367 if (portal->status != PORTAL_READY)
369 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
370 errmsg("portal \"%s\" cannot be run", portal->name)));
371 portal->status = PORTAL_ACTIVE;
374 * Set up global portal context pointers.
376 saveActivePortal = ActivePortal;
377 saveActiveSnapshot = ActiveSnapshot;
378 saveResourceOwner = CurrentResourceOwner;
379 savePortalContext = PortalContext;
382 ActivePortal = portal;
383 ActiveSnapshot = queryDesc->snapshot;
384 CurrentResourceOwner = portal->resowner;
385 PortalContext = PortalGetHeapMemory(portal);
387 MemoryContextSwitchTo(PortalContext);
390 * Rewind the executor: we need to store the entire result set in the
391 * tuplestore, so that subsequent backward FETCHs can be processed.
393 ExecutorRewind(queryDesc);
395 /* Change the destination to output to the tuplestore */
396 queryDesc->dest = CreateDestReceiver(DestTuplestore, portal);
398 /* Fetch the result set into the tuplestore */
399 ExecutorRun(queryDesc, ForwardScanDirection, 0L);
401 (*queryDesc->dest->rDestroy) (queryDesc->dest);
402 queryDesc->dest = NULL;
405 * Now shut down the inner executor.
407 portal->queryDesc = NULL; /* prevent double shutdown */
408 /* we do not need AfterTriggerEndQuery() here */
409 ExecutorEnd(queryDesc);
412 * Set the position in the result set: ideally, this could be
413 * implemented by just skipping straight to the tuple # that we need
414 * to be at, but the tuplestore API doesn't support that. So we start
415 * at the beginning of the tuplestore and iterate through it until we
416 * reach where we need to be. FIXME someday? (Fortunately, the
417 * typical case is that we're supposed to be at or near the start
418 * of the result set, so this isn't as bad as it sounds.)
420 MemoryContextSwitchTo(portal->holdContext);
424 /* we can handle this case even if posOverflow */
425 while (tuplestore_advance(portal->holdStore, true))
432 if (portal->posOverflow) /* oops, cannot trust portalPos */
434 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
435 errmsg("could not reposition held cursor")));
437 tuplestore_rescan(portal->holdStore);
439 for (store_pos = 0; store_pos < portal->portalPos; store_pos++)
441 if (!tuplestore_advance(portal->holdStore, true))
442 elog(ERROR, "unexpected end of tuple stream");
448 /* Uncaught error while executing portal: mark it dead */
449 portal->status = PORTAL_FAILED;
451 /* Restore global vars and propagate error */
452 ActivePortal = saveActivePortal;
453 ActiveSnapshot = saveActiveSnapshot;
454 CurrentResourceOwner = saveResourceOwner;
455 PortalContext = savePortalContext;
461 MemoryContextSwitchTo(oldcxt);
463 /* Mark portal not active */
464 portal->status = PORTAL_READY;
466 ActivePortal = saveActivePortal;
467 ActiveSnapshot = saveActiveSnapshot;
468 CurrentResourceOwner = saveResourceOwner;
469 PortalContext = savePortalContext;
472 * We can now release any subsidiary memory of the portal's heap context;
473 * we'll never use it again. The executor already dropped its context,
474 * but this will clean up anything that glommed onto the portal's heap via
477 MemoryContextDeleteChildren(PortalGetHeapMemory(portal));