PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
portalcmds.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/xact.h"
#include "commands/portalcmds.h"
#include "executor/executor.h"
#include "executor/tstoreReceiver.h"
#include "miscadmin.h"
#include "nodes/queryjumble.h"
#include "parser/analyze.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
Include dependency graph for portalcmds.c:

Go to the source code of this file.

Functions

void PerformCursorOpen (ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo params, bool isTopLevel)
 
void PerformPortalFetch (FetchStmt *stmt, DestReceiver *dest, QueryCompletion *qc)
 
void PerformPortalClose (const char *name)
 
void PortalCleanup (Portal portal)
 
void PersistHoldablePortal (Portal portal)
 

Function Documentation

◆ PerformCursorOpen()

void PerformCursorOpen ( ParseState pstate,
DeclareCursorStmt cstmt,
ParamListInfo  params,
bool  isTopLevel 
)

Definition at line 45 of file portalcmds.c.

47{
48 Query *query = castNode(Query, cstmt->query);
49 JumbleState *jstate = NULL;
50 List *rewritten;
52 Portal portal;
53 MemoryContext oldContext;
54 char *queryString;
55
56 /*
57 * Disallow empty-string cursor name (conflicts with protocol-level
58 * unnamed portal).
59 */
60 if (!cstmt->portalname || cstmt->portalname[0] == '\0')
62 (errcode(ERRCODE_INVALID_CURSOR_NAME),
63 errmsg("invalid cursor name: must not be empty")));
64
65 /*
66 * If this is a non-holdable cursor, we require that this statement has
67 * been executed inside a transaction block (or else, it would have no
68 * user-visible effect).
69 */
70 if (!(cstmt->options & CURSOR_OPT_HOLD))
71 RequireTransactionBlock(isTopLevel, "DECLARE CURSOR");
74 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
75 errmsg("cannot create a cursor WITH HOLD within security-restricted operation")));
76
77 /* Query contained by DeclareCursor needs to be jumbled if requested */
78 if (IsQueryIdEnabled())
79 jstate = JumbleQuery(query);
80
82 (*post_parse_analyze_hook) (pstate, query, jstate);
83
84 /*
85 * Parse analysis was done already, but we still have to run the rule
86 * rewriter. We do not do AcquireRewriteLocks: we assume the query either
87 * came straight from the parser, or suitable locks were acquired by
88 * plancache.c.
89 */
90 rewritten = QueryRewrite(query);
91
92 /* SELECT should never rewrite to more or less than one query */
93 if (list_length(rewritten) != 1)
94 elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
95
96 query = linitial_node(Query, rewritten);
97
98 if (query->commandType != CMD_SELECT)
99 elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
100
101 /* Plan the query, applying the specified options */
102 plan = pg_plan_query(query, pstate->p_sourcetext, cstmt->options, params);
103
104 /*
105 * Create a portal and copy the plan and query string into its memory.
106 */
107 portal = CreatePortal(cstmt->portalname, false, false);
108
109 oldContext = MemoryContextSwitchTo(portal->portalContext);
110
112
113 queryString = pstrdup(pstate->p_sourcetext);
114
115 PortalDefineQuery(portal,
116 NULL,
117 queryString,
118 CMDTAG_SELECT, /* cursor's query is always a SELECT */
120 NULL);
121
122 /*----------
123 * Also copy the outer portal's parameter list into the inner portal's
124 * memory context. We want to pass down the parameter values in case we
125 * had a command like
126 * DECLARE c CURSOR FOR SELECT ... WHERE foo = $1
127 * This will have been parsed using the outer parameter set and the
128 * parameter value needs to be preserved for use when the cursor is
129 * executed.
130 *----------
131 */
132 params = copyParamList(params);
133
134 MemoryContextSwitchTo(oldContext);
135
136 /*
137 * Set up options for portal.
138 *
139 * If the user didn't specify a SCROLL type, allow or disallow scrolling
140 * based on whether it would require any additional runtime overhead to do
141 * so. Also, we disallow scrolling for FOR UPDATE cursors.
142 */
143 portal->cursorOptions = cstmt->options;
145 {
146 if (plan->rowMarks == NIL &&
149 else
151 }
152
153 /*
154 * Start execution, inserting parameters if any.
155 */
156 PortalStart(portal, params, 0, GetActiveSnapshot());
157
159
160 /*
161 * We're done; the query won't actually be run until PerformPortalFetch is
162 * called.
163 */
164}
#define Assert(condition)
Definition: c.h:812
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:510
char * pstrdup(const char *in)
Definition: mcxt.c:1696
bool InSecurityRestrictedOperation(void)
Definition: miscinit.c:687
#define copyObject(obj)
Definition: nodes.h:224
@ CMD_SELECT
Definition: nodes.h:265
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
ParamListInfo copyParamList(ParamListInfo from)
Definition: params.c:78
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:3308
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:3312
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:3309
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:59
static int list_length(const List *l)
Definition: pg_list.h:152
#define linitial_node(type, l)
Definition: pg_list.h:181
#define NIL
Definition: pg_list.h:68
#define list_make1(x1)
Definition: pg_list.h:212
#define plan(x)
Definition: pg_regress.c:161
@ PORTAL_ONE_SELECT
Definition: portal.h:91
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, CommandTag commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:282
Portal CreatePortal(const char *name, bool allowDup, bool dupSilent)
Definition: portalmem.c:175
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:881
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:433
static bool IsQueryIdEnabled(void)
Definition: queryjumble.h:77
JumbleState * JumbleQuery(Query *query)
List * QueryRewrite(Query *parsetree)
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:728
Definition: pg_list.h:54
MemoryContext portalContext
Definition: portal.h:120
int cursorOptions
Definition: portal.h:147
PortalStrategy strategy
Definition: portal.h:146
void RequireTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3708

References Assert, castNode, CMD_SELECT, Query::commandType, copyObject, copyParamList(), CreatePortal(), CURSOR_OPT_HOLD, CURSOR_OPT_NO_SCROLL, CURSOR_OPT_SCROLL, PortalData::cursorOptions, elog, ereport, errcode(), errmsg(), ERROR, ExecSupportsBackwardScan(), GetActiveSnapshot(), InSecurityRestrictedOperation(), IsQueryIdEnabled(), JumbleQuery(), linitial_node, list_length(), list_make1, MemoryContextSwitchTo(), NIL, DeclareCursorStmt::options, ParseState::p_sourcetext, pg_plan_query(), plan, PORTAL_ONE_SELECT, PortalData::portalContext, PortalDefineQuery(), DeclareCursorStmt::portalname, PortalStart(), post_parse_analyze_hook, pstrdup(), DeclareCursorStmt::query, QueryRewrite(), RequireTransactionBlock(), and PortalData::strategy.

Referenced by standard_ProcessUtility().

◆ PerformPortalClose()

void PerformPortalClose ( const char *  name)

Definition at line 224 of file portalcmds.c.

225{
226 Portal portal;
227
228 /* NULL means CLOSE ALL */
229 if (name == NULL)
230 {
232 return;
233 }
234
235 /*
236 * Disallow empty-string cursor name (conflicts with protocol-level
237 * unnamed portal).
238 */
239 if (name[0] == '\0')
241 (errcode(ERRCODE_INVALID_CURSOR_NAME),
242 errmsg("invalid cursor name: must not be empty")));
243
244 /*
245 * get the portal from the portal name
246 */
247 portal = GetPortalByName(name);
248 if (!PortalIsValid(portal))
249 {
251 (errcode(ERRCODE_UNDEFINED_CURSOR),
252 errmsg("cursor \"%s\" does not exist", name)));
253 return; /* keep compiler happy */
254 }
255
256 /*
257 * Note: PortalCleanup is called as a side-effect, if not already done.
258 */
259 PortalDrop(portal, false);
260}
#define PortalIsValid(p)
Definition: portal.h:211
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:468
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
void PortalHashTableDeleteAll(void)
Definition: portalmem.c:607
const char * name

References ereport, errcode(), errmsg(), ERROR, GetPortalByName(), name, PortalDrop(), PortalHashTableDeleteAll(), and PortalIsValid.

Referenced by standard_ProcessUtility().

◆ PerformPortalFetch()

void PerformPortalFetch ( FetchStmt stmt,
DestReceiver dest,
QueryCompletion qc 
)

Definition at line 177 of file portalcmds.c.

180{
181 Portal portal;
182 uint64 nprocessed;
183
184 /*
185 * Disallow empty-string cursor name (conflicts with protocol-level
186 * unnamed portal).
187 */
188 if (!stmt->portalname || stmt->portalname[0] == '\0')
190 (errcode(ERRCODE_INVALID_CURSOR_NAME),
191 errmsg("invalid cursor name: must not be empty")));
192
193 /* get the portal from the portal name */
194 portal = GetPortalByName(stmt->portalname);
195 if (!PortalIsValid(portal))
196 {
198 (errcode(ERRCODE_UNDEFINED_CURSOR),
199 errmsg("cursor \"%s\" does not exist", stmt->portalname)));
200 return; /* keep compiler happy */
201 }
202
203 /* Adjust dest if needed. MOVE wants destination DestNone */
204 if (stmt->ismove)
206
207 /* Do it */
208 nprocessed = PortalRunFetch(portal,
209 stmt->direction,
210 stmt->howMany,
211 dest);
212
213 /* Return command status if wanted */
214 if (qc)
215 SetQueryCompletion(qc, stmt->ismove ? CMDTAG_MOVE : CMDTAG_FETCH,
216 nprocessed);
217}
uint64_t uint64
Definition: c.h:486
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:37
DestReceiver * None_Receiver
Definition: dest.c:96
#define stmt
Definition: indent_codes.h:59
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1385

References generate_unaccent_rules::dest, ereport, errcode(), errmsg(), ERROR, GetPortalByName(), None_Receiver, PortalIsValid, PortalRunFetch(), SetQueryCompletion(), and stmt.

Referenced by standard_ProcessUtility().

◆ PersistHoldablePortal()

void PersistHoldablePortal ( Portal  portal)

Definition at line 326 of file portalcmds.c.

327{
328 QueryDesc *queryDesc = portal->queryDesc;
329 Portal saveActivePortal;
330 ResourceOwner saveResourceOwner;
331 MemoryContext savePortalContext;
332 MemoryContext oldcxt;
333
334 /*
335 * If we're preserving a holdable portal, we had better be inside the
336 * transaction that originally created it.
337 */
339 Assert(queryDesc != NULL);
340
341 /*
342 * Caller must have created the tuplestore already ... but not a snapshot.
343 */
344 Assert(portal->holdContext != NULL);
345 Assert(portal->holdStore != NULL);
346 Assert(portal->holdSnapshot == NULL);
347
348 /*
349 * Before closing down the executor, we must copy the tupdesc into
350 * long-term memory, since it was created in executor memory.
351 */
352 oldcxt = MemoryContextSwitchTo(portal->holdContext);
353
354 portal->tupDesc = CreateTupleDescCopy(portal->tupDesc);
355
356 MemoryContextSwitchTo(oldcxt);
357
358 /*
359 * Check for improper portal use, and mark portal active.
360 */
361 MarkPortalActive(portal);
362
363 /*
364 * Set up global portal context pointers.
365 */
366 saveActivePortal = ActivePortal;
367 saveResourceOwner = CurrentResourceOwner;
368 savePortalContext = PortalContext;
369 PG_TRY();
370 {
372
373 ActivePortal = portal;
374 if (portal->resowner)
377
379
380 PushActiveSnapshot(queryDesc->snapshot);
381
382 /*
383 * If the portal is marked scrollable, we need to store the entire
384 * result set in the tuplestore, so that subsequent backward FETCHs
385 * can be processed. Otherwise, store only the not-yet-fetched rows.
386 * (The latter is not only more efficient, but avoids semantic
387 * problems if the query's output isn't stable.)
388 *
389 * In the no-scroll case, tuple indexes in the tuplestore will not
390 * match the cursor's nominal position (portalPos). Currently this
391 * causes no difficulty because we only navigate in the tuplestore by
392 * relative position, except for the tuplestore_skiptuples call below
393 * and the tuplestore_rescan call in DoPortalRewind, both of which are
394 * disabled for no-scroll cursors. But someday we might need to track
395 * the offset between the holdStore and the cursor's nominal position
396 * explicitly.
397 */
398 if (portal->cursorOptions & CURSOR_OPT_SCROLL)
399 {
400 ExecutorRewind(queryDesc);
401 }
402 else
403 {
404 /*
405 * If we already reached end-of-query, set the direction to
406 * NoMovement to avoid trying to fetch any tuples. (This check
407 * exists because not all plan node types are robust about being
408 * called again if they've already returned NULL once.) We'll
409 * still set up an empty tuplestore, though, to keep this from
410 * being a special case later.
411 */
412 if (portal->atEnd)
413 direction = NoMovementScanDirection;
414 }
415
416 /*
417 * Change the destination to output to the tuplestore. Note we tell
418 * the tuplestore receiver to detoast all data passed through it; this
419 * makes it safe to not keep a snapshot associated with the data.
420 */
423 portal->holdStore,
424 portal->holdContext,
425 true,
426 NULL,
427 NULL);
428
429 /* Fetch the result set into the tuplestore */
430 ExecutorRun(queryDesc, direction, 0);
431
432 queryDesc->dest->rDestroy(queryDesc->dest);
433 queryDesc->dest = NULL;
434
435 /*
436 * Now shut down the inner executor.
437 */
438 portal->queryDesc = NULL; /* prevent double shutdown */
439 ExecutorFinish(queryDesc);
440 ExecutorEnd(queryDesc);
441 FreeQueryDesc(queryDesc);
442
443 /*
444 * Set the position in the result set.
445 */
447
448 if (portal->atEnd)
449 {
450 /*
451 * Just force the tuplestore forward to its end. The size of the
452 * skip request here is arbitrary.
453 */
454 while (tuplestore_skiptuples(portal->holdStore, 1000000, true))
455 /* continue */ ;
456 }
457 else
458 {
460
461 /*
462 * In the no-scroll case, the start of the tuplestore is exactly
463 * where we want to be, so no repositioning is wanted.
464 */
465 if (portal->cursorOptions & CURSOR_OPT_SCROLL)
466 {
467 if (!tuplestore_skiptuples(portal->holdStore,
468 portal->portalPos,
469 true))
470 elog(ERROR, "unexpected end of tuple stream");
471 }
472 }
473 }
474 PG_CATCH();
475 {
476 /* Uncaught error while executing portal: mark it dead */
477 MarkPortalFailed(portal);
478
479 /* Restore global vars and propagate error */
480 ActivePortal = saveActivePortal;
481 CurrentResourceOwner = saveResourceOwner;
482 PortalContext = savePortalContext;
483
484 PG_RE_THROW();
485 }
486 PG_END_TRY();
487
488 MemoryContextSwitchTo(oldcxt);
489
490 /* Mark portal not active */
491 portal->status = PORTAL_READY;
492
493 ActivePortal = saveActivePortal;
494 CurrentResourceOwner = saveResourceOwner;
495 PortalContext = savePortalContext;
496
498
499 /*
500 * We can now release any subsidiary memory of the portal's context; we'll
501 * never use it again. The executor already dropped its context, but this
502 * will clean up anything that glommed onto the portal's context via
503 * PortalContext.
504 */
506}
#define InvalidSubTransactionId
Definition: c.h:612
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
@ DestTuplestore
Definition: dest.h:93
#define PG_RE_THROW()
Definition: elog.h:412
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_CATCH(...)
Definition: elog.h:381
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:463
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:403
void ExecutorRewind(QueryDesc *queryDesc)
Definition: execMain.c:533
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:294
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:539
MemoryContext PortalContext
Definition: mcxt.c:158
@ PORTAL_READY
Definition: portal.h:107
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:442
void MarkPortalActive(Portal portal)
Definition: portalmem.c:395
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
Portal ActivePortal
Definition: pquery.c:35
ResourceOwner CurrentResourceOwner
Definition: resowner.c:165
ScanDirection
Definition: sdir.h:25
@ NoMovementScanDirection
Definition: sdir.h:27
@ ForwardScanDirection
Definition: sdir.h:28
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:610
void PopActiveSnapshot(void)
Definition: snapmgr.c:703
SubTransactionId createSubid
Definition: portal.h:131
uint64 portalPos
Definition: portal.h:200
QueryDesc * queryDesc
Definition: portal.h:156
bool atEnd
Definition: portal.h:199
ResourceOwner resowner
Definition: portal.h:121
MemoryContext holdContext
Definition: portal.h:177
Snapshot holdSnapshot
Definition: portal.h:187
TupleDesc tupDesc
Definition: portal.h:159
Tuplestorestate * holdStore
Definition: portal.h:176
PortalStatus status
Definition: portal.h:150
DestReceiver * dest
Definition: execdesc.h:41
Snapshot snapshot
Definition: execdesc.h:39
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:126
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast, TupleDesc target_tupdesc, const char *map_failure_msg)
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:235
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1285
bool tuplestore_skiptuples(Tuplestorestate *state, int64 ntuples, bool forward)
Definition: tuplestore.c:1187

References ActivePortal, Assert, PortalData::atEnd, CreateDestReceiver(), PortalData::createSubid, CreateTupleDescCopy(), CurrentResourceOwner, CURSOR_OPT_SCROLL, PortalData::cursorOptions, QueryDesc::dest, DestTuplestore, elog, ERROR, ExecutorEnd(), ExecutorFinish(), ExecutorRewind(), ExecutorRun(), ForwardScanDirection, FreeQueryDesc(), PortalData::holdContext, PortalData::holdSnapshot, PortalData::holdStore, InvalidSubTransactionId, MarkPortalActive(), MarkPortalFailed(), MemoryContextDeleteChildren(), MemoryContextSwitchTo(), NoMovementScanDirection, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PopActiveSnapshot(), PORTAL_READY, PortalContext, PortalData::portalContext, PortalData::portalPos, PushActiveSnapshot(), PortalData::queryDesc, _DestReceiver::rDestroy, PortalData::resowner, SetTuplestoreDestReceiverParams(), QueryDesc::snapshot, PortalData::status, PortalData::tupDesc, tuplestore_rescan(), and tuplestore_skiptuples().

Referenced by HoldPortal().

◆ PortalCleanup()

void PortalCleanup ( Portal  portal)

Definition at line 273 of file portalcmds.c.

274{
275 QueryDesc *queryDesc;
276
277 /*
278 * sanity checks
279 */
280 Assert(PortalIsValid(portal));
281 Assert(portal->cleanup == PortalCleanup);
282
283 /*
284 * Shut down executor, if still running. We skip this during error abort,
285 * since other mechanisms will take care of releasing executor resources,
286 * and we can't be sure that ExecutorEnd itself wouldn't fail.
287 */
288 queryDesc = portal->queryDesc;
289 if (queryDesc)
290 {
291 /*
292 * Reset the queryDesc before anything else. This prevents us from
293 * trying to shut down the executor twice, in case of an error below.
294 * The transaction abort mechanisms will take care of resource cleanup
295 * in such a case.
296 */
297 portal->queryDesc = NULL;
298
299 if (portal->status != PORTAL_FAILED)
300 {
301 ResourceOwner saveResourceOwner;
302
303 /* We must make the portal's resource owner current */
304 saveResourceOwner = CurrentResourceOwner;
305 if (portal->resowner)
307
308 ExecutorFinish(queryDesc);
309 ExecutorEnd(queryDesc);
310 FreeQueryDesc(queryDesc);
311
312 CurrentResourceOwner = saveResourceOwner;
313 }
314 }
315}
@ PORTAL_FAILED
Definition: portal.h:110
void PortalCleanup(Portal portal)
Definition: portalcmds.c:273
void(* cleanup)(Portal portal)
Definition: portal.h:122

References Assert, PortalData::cleanup, CurrentResourceOwner, ExecutorEnd(), ExecutorFinish(), FreeQueryDesc(), PORTAL_FAILED, PortalCleanup(), PortalIsValid, PortalData::queryDesc, PortalData::resowner, and PortalData::status.

Referenced by CreatePortal(), and PortalCleanup().