PostgreSQL Source Code  git master
portalcmds.h File Reference
#include "nodes/parsenodes.h"
#include "parser/parse_node.h"
#include "utils/portal.h"
Include dependency graph for portalcmds.h:
This graph shows which files directly or indirectly include this file:

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 43 of file portalcmds.c.

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(), linitial_node, list_length(), list_make1, MemoryContextSwitchTo(), NIL, DeclareCursorStmt::options, ParseState::p_sourcetext, pg_plan_query(), PlannedStmt::planTree, PORTAL_ONE_SELECT, PortalData::portalContext, PortalDefineQuery(), DeclareCursorStmt::portalname, PortalStart(), pstrdup(), DeclareCursorStmt::query, QueryRewrite(), RequireTransactionBlock(), PlannedStmt::rowMarks, and PortalData::strategy.

Referenced by standard_ProcessUtility().

45 {
46  Query *query = castNode(Query, cstmt->query);
47  List *rewritten;
48  PlannedStmt *plan;
49  Portal portal;
50  MemoryContext oldContext;
51  char *queryString;
52 
53  /*
54  * Disallow empty-string cursor name (conflicts with protocol-level
55  * unnamed portal).
56  */
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")));
61 
62  /*
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).
66  */
67  if (!(cstmt->options & CURSOR_OPT_HOLD))
68  RequireTransactionBlock(isTopLevel, "DECLARE CURSOR");
70  ereport(ERROR,
71  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
72  errmsg("cannot create a cursor WITH HOLD within security-restricted operation")));
73 
74  /*
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.
79  *
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.
85  */
86  rewritten = QueryRewrite((Query *) copyObject(query));
87 
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");
91 
92  query = linitial_node(Query, rewritten);
93 
94  if (query->commandType != CMD_SELECT)
95  elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
96 
97  /* Plan the query, applying the specified options */
98  plan = pg_plan_query(query, pstate->p_sourcetext, cstmt->options, params);
99 
100  /*
101  * Create a portal and copy the plan and query string into its memory.
102  */
103  portal = CreatePortal(cstmt->portalname, false, false);
104 
105  oldContext = MemoryContextSwitchTo(portal->portalContext);
106 
107  plan = copyObject(plan);
108 
109  queryString = pstrdup(pstate->p_sourcetext);
110 
111  PortalDefineQuery(portal,
112  NULL,
113  queryString,
114  CMDTAG_SELECT, /* cursor's query is always a SELECT */
115  list_make1(plan),
116  NULL);
117 
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  *----------
127  */
128  params = copyParamList(params);
129 
130  MemoryContextSwitchTo(oldContext);
131 
132  /*
133  * Set up options for portal.
134  *
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.
138  */
139  portal->cursorOptions = cstmt->options;
141  {
142  if (plan->rowMarks == NIL &&
144  portal->cursorOptions |= CURSOR_OPT_SCROLL;
145  else
147  }
148 
149  /*
150  * Start execution, inserting parameters if any.
151  */
152  PortalStart(portal, params, 0, GetActiveSnapshot());
153 
154  Assert(portal->strategy == PORTAL_ONE_SELECT);
155 
156  /*
157  * We're done; the query won't actually be run until PerformPortalFetch is
158  * called.
159  */
160 }
ParamListInfo copyParamList(ParamListInfo from)
Definition: params.c:78
#define NIL
Definition: pg_list.h:65
Portal CreatePortal(const char *name, bool allowDup, bool dupSilent)
Definition: portalmem.c:175
List * QueryRewrite(Query *parsetree)
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:430
#define castNode(_type_, nodeptr)
Definition: nodes.h:608
char * pstrdup(const char *in)
Definition: mcxt.c:1299
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2799
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:786
int errcode(int sqlerrcode)
Definition: elog.c:698
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, CommandTag commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:281
#define linitial_node(type, l)
Definition: pg_list.h:177
MemoryContext portalContext
Definition: portal.h:120
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2796
struct Plan * planTree
Definition: plannodes.h:64
#define list_make1(x1)
Definition: pg_list.h:206
#define ERROR
Definition: elog.h:46
PortalStrategy strategy
Definition: portal.h:145
const char * p_sourcetext
Definition: parse_node.h:181
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:515
List * rowMarks
Definition: plannodes.h:78
#define ereport(elevel,...)
Definition: elog.h:157
CmdType commandType
Definition: parsenodes.h:120
#define Assert(condition)
Definition: c.h:804
bool InSecurityRestrictedOperation(void)
Definition: miscinit.c:610
static int list_length(const List *l)
Definition: pg_list.h:149
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define elog(elevel,...)
Definition: elog.h:232
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2795
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:829
int cursorOptions
Definition: portal.h:146
#define copyObject(obj)
Definition: nodes.h:655
Definition: pg_list.h:50
void RequireTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3445

◆ PerformPortalClose()

void PerformPortalClose ( const char *  name)

Definition at line 220 of file portalcmds.c.

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

Referenced by standard_ProcessUtility().

221 {
222  Portal portal;
223 
224  /* NULL means CLOSE ALL */
225  if (name == NULL)
226  {
228  return;
229  }
230 
231  /*
232  * Disallow empty-string cursor name (conflicts with protocol-level
233  * unnamed portal).
234  */
235  if (name[0] == '\0')
236  ereport(ERROR,
237  (errcode(ERRCODE_INVALID_CURSOR_NAME),
238  errmsg("invalid cursor name: must not be empty")));
239 
240  /*
241  * get the portal from the portal name
242  */
243  portal = GetPortalByName(name);
244  if (!PortalIsValid(portal))
245  {
246  ereport(ERROR,
247  (errcode(ERRCODE_UNDEFINED_CURSOR),
248  errmsg("cursor \"%s\" does not exist", name)));
249  return; /* keep compiler happy */
250  }
251 
252  /*
253  * Note: PortalCleanup is called as a side-effect, if not already done.
254  */
255  PortalDrop(portal, false);
256 }
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
int errcode(int sqlerrcode)
Definition: elog.c:698
#define ERROR
Definition: elog.h:46
#define PortalIsValid(p)
Definition: portal.h:203
#define ereport(elevel,...)
Definition: elog.h:157
void PortalHashTableDeleteAll(void)
Definition: portalmem.c:603
const char * name
Definition: encode.c:515
int errmsg(const char *fmt,...)
Definition: elog.c:909
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:467

◆ PerformPortalFetch()

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

Definition at line 173 of file portalcmds.c.

References FetchStmt::direction, ereport, errcode(), errmsg(), ERROR, GetPortalByName(), FetchStmt::howMany, FetchStmt::ismove, None_Receiver, PortalIsValid, FetchStmt::portalname, PortalRunFetch(), and SetQueryCompletion().

Referenced by standard_ProcessUtility().

176 {
177  Portal portal;
178  uint64 nprocessed;
179 
180  /*
181  * Disallow empty-string cursor name (conflicts with protocol-level
182  * unnamed portal).
183  */
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")));
188 
189  /* get the portal from the portal name */
190  portal = GetPortalByName(stmt->portalname);
191  if (!PortalIsValid(portal))
192  {
193  ereport(ERROR,
194  (errcode(ERRCODE_UNDEFINED_CURSOR),
195  errmsg("cursor \"%s\" does not exist", stmt->portalname)));
196  return; /* keep compiler happy */
197  }
198 
199  /* Adjust dest if needed. MOVE wants destination DestNone */
200  if (stmt->ismove)
201  dest = None_Receiver;
202 
203  /* Do it */
204  nprocessed = PortalRunFetch(portal,
205  stmt->direction,
206  stmt->howMany,
207  dest);
208 
209  /* Return command status if wanted */
210  if (qc)
211  SetQueryCompletion(qc, stmt->ismove ? CMDTAG_MOVE : CMDTAG_FETCH,
212  nprocessed);
213 }
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1381
int errcode(int sqlerrcode)
Definition: elog.c:698
DestReceiver * None_Receiver
Definition: dest.c:96
#define ERROR
Definition: elog.h:46
char * portalname
Definition: parsenodes.h:2846
#define PortalIsValid(p)
Definition: portal.h:203
bool ismove
Definition: parsenodes.h:2847
long howMany
Definition: parsenodes.h:2845
#define ereport(elevel,...)
Definition: elog.h:157
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:36
int errmsg(const char *fmt,...)
Definition: elog.c:909
FetchDirection direction
Definition: parsenodes.h:2844

◆ PersistHoldablePortal()

void PersistHoldablePortal ( Portal  portal)

Definition at line 322 of file portalcmds.c.

References ActivePortal, Assert, PortalData::atEnd, CreateDestReceiver(), PortalData::createSubid, CreateTupleDescCopy(), CurrentResourceOwner, QueryDesc::dest, DestTuplestore, elog, ERROR, ExecutorEnd(), ExecutorFinish(), ExecutorRewind(), ExecutorRun(), ForwardScanDirection, FreeQueryDesc(), PortalData::holdContext, PortalData::holdSnapshot, PortalData::holdStore, InvalidSubTransactionId, MarkPortalActive(), MarkPortalFailed(), MemoryContextDeleteChildren(), MemoryContextSwitchTo(), 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().

323 {
324  QueryDesc *queryDesc = portal->queryDesc;
325  Portal saveActivePortal;
326  ResourceOwner saveResourceOwner;
327  MemoryContext savePortalContext;
328  MemoryContext oldcxt;
329 
330  /*
331  * If we're preserving a holdable portal, we had better be inside the
332  * transaction that originally created it.
333  */
335  Assert(queryDesc != NULL);
336 
337  /*
338  * Caller must have created the tuplestore already ... but not a snapshot.
339  */
340  Assert(portal->holdContext != NULL);
341  Assert(portal->holdStore != NULL);
342  Assert(portal->holdSnapshot == NULL);
343 
344  /*
345  * Before closing down the executor, we must copy the tupdesc into
346  * long-term memory, since it was created in executor memory.
347  */
348  oldcxt = MemoryContextSwitchTo(portal->holdContext);
349 
350  portal->tupDesc = CreateTupleDescCopy(portal->tupDesc);
351 
352  MemoryContextSwitchTo(oldcxt);
353 
354  /*
355  * Check for improper portal use, and mark portal active.
356  */
357  MarkPortalActive(portal);
358 
359  /*
360  * Set up global portal context pointers.
361  */
362  saveActivePortal = ActivePortal;
363  saveResourceOwner = CurrentResourceOwner;
364  savePortalContext = PortalContext;
365  PG_TRY();
366  {
367  ActivePortal = portal;
368  if (portal->resowner)
369  CurrentResourceOwner = portal->resowner;
370  PortalContext = portal->portalContext;
371 
373 
374  PushActiveSnapshot(queryDesc->snapshot);
375 
376  /*
377  * Rewind the executor: we need to store the entire result set in the
378  * tuplestore, so that subsequent backward FETCHs can be processed.
379  */
380  ExecutorRewind(queryDesc);
381 
382  /*
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.
386  */
387  queryDesc->dest = CreateDestReceiver(DestTuplestore);
389  portal->holdStore,
390  portal->holdContext,
391  true,
392  NULL,
393  NULL);
394 
395  /* Fetch the result set into the tuplestore */
396  ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
397 
398  queryDesc->dest->rDestroy(queryDesc->dest);
399  queryDesc->dest = NULL;
400 
401  /*
402  * Now shut down the inner executor.
403  */
404  portal->queryDesc = NULL; /* prevent double shutdown */
405  ExecutorFinish(queryDesc);
406  ExecutorEnd(queryDesc);
407  FreeQueryDesc(queryDesc);
408 
409  /*
410  * Set the position in the result set.
411  */
413 
414  if (portal->atEnd)
415  {
416  /*
417  * Just force the tuplestore forward to its end. The size of the
418  * skip request here is arbitrary.
419  */
420  while (tuplestore_skiptuples(portal->holdStore, 1000000, true))
421  /* continue */ ;
422  }
423  else
424  {
425  tuplestore_rescan(portal->holdStore);
426 
427  if (!tuplestore_skiptuples(portal->holdStore,
428  portal->portalPos,
429  true))
430  elog(ERROR, "unexpected end of tuple stream");
431  }
432  }
433  PG_CATCH();
434  {
435  /* Uncaught error while executing portal: mark it dead */
436  MarkPortalFailed(portal);
437 
438  /* Restore global vars and propagate error */
439  ActivePortal = saveActivePortal;
440  CurrentResourceOwner = saveResourceOwner;
441  PortalContext = savePortalContext;
442 
443  PG_RE_THROW();
444  }
445  PG_END_TRY();
446 
447  MemoryContextSwitchTo(oldcxt);
448 
449  /* Mark portal not active */
450  portal->status = PORTAL_READY;
451 
452  ActivePortal = saveActivePortal;
453  CurrentResourceOwner = saveResourceOwner;
454  PortalContext = savePortalContext;
455 
457 
458  /*
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.
463  */
465 }
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1233
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111
bool atEnd
Definition: portal.h:191
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
Portal ActivePortal
Definition: pquery.c:35
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast, TupleDesc target_tupdesc, const char *map_failure_msg)
void MarkPortalActive(Portal portal)
Definition: portalmem.c:394
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext holdContext
Definition: portal.h:169
void PopActiveSnapshot(void)
Definition: snapmgr.c:759
MemoryContext portalContext
Definition: portal.h:120
Snapshot snapshot
Definition: execdesc.h:39
MemoryContext PortalContext
Definition: mcxt.c:57
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:459
#define ERROR
Definition: elog.h:46
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:298
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:680
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
SubTransactionId createSubid
Definition: portal.h:131
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:399
QueryDesc * queryDesc
Definition: portal.h:156
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:263
void ExecutorRewind(QueryDesc *queryDesc)
Definition: execMain.c:525
TupleDesc tupDesc
Definition: portal.h:159
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:127
#define PG_CATCH()
Definition: elog.h:323
#define Assert(condition)
Definition: c.h:804
Snapshot holdSnapshot
Definition: portal.h:179
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:441
PortalStatus status
Definition: portal.h:150
#define PG_RE_THROW()
Definition: elog.h:354
bool tuplestore_skiptuples(Tuplestorestate *state, int64 ntuples, bool forward)
Definition: tuplestore.c:1135
#define InvalidSubTransactionId
Definition: c.h:593
DestReceiver * dest
Definition: execdesc.h:41
ResourceOwner resowner
Definition: portal.h:121
Tuplestorestate * holdStore
Definition: portal.h:168
#define elog(elevel,...)
Definition: elog.h:232
#define PG_TRY()
Definition: elog.h:313
#define PG_END_TRY()
Definition: elog.h:338
uint64 portalPos
Definition: portal.h:192

◆ PortalCleanup()

void PortalCleanup ( Portal  portal)

Definition at line 269 of file portalcmds.c.

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

Referenced by CreatePortal(), and PortalCleanup().

270 {
271  QueryDesc *queryDesc;
272 
273  /*
274  * sanity checks
275  */
276  AssertArg(PortalIsValid(portal));
277  AssertArg(portal->cleanup == PortalCleanup);
278 
279  /*
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.
283  */
284  queryDesc = portal->queryDesc;
285  if (queryDesc)
286  {
287  /*
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.
292  */
293  portal->queryDesc = NULL;
294 
295  if (portal->status != PORTAL_FAILED)
296  {
297  ResourceOwner saveResourceOwner;
298 
299  /* We must make the portal's resource owner current */
300  saveResourceOwner = CurrentResourceOwner;
301  if (portal->resowner)
302  CurrentResourceOwner = portal->resowner;
303 
304  ExecutorFinish(queryDesc);
305  ExecutorEnd(queryDesc);
306  FreeQueryDesc(queryDesc);
307 
308  CurrentResourceOwner = saveResourceOwner;
309  }
310  }
311 }
void(* cleanup)(Portal portal)
Definition: portal.h:122
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
void PortalCleanup(Portal portal)
Definition: portalcmds.c:269
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:459
#define AssertArg(condition)
Definition: c.h:806
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:399
QueryDesc * queryDesc
Definition: portal.h:156
#define PortalIsValid(p)
Definition: portal.h:203
PortalStatus status
Definition: portal.h:150
ResourceOwner resowner
Definition: portal.h:121