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, char *completionTag)
 
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 42 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(), 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().

44 {
45  Query *query = castNode(Query, cstmt->query);
46  List *rewritten;
47  PlannedStmt *plan;
48  Portal portal;
49  MemoryContext oldContext;
50  char *queryString;
51 
52  /*
53  * Disallow empty-string cursor name (conflicts with protocol-level
54  * unnamed portal).
55  */
56  if (!cstmt->portalname || cstmt->portalname[0] == '\0')
57  ereport(ERROR,
58  (errcode(ERRCODE_INVALID_CURSOR_NAME),
59  errmsg("invalid cursor name: must not be empty")));
60 
61  /*
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).
65  */
66  if (!(cstmt->options & CURSOR_OPT_HOLD))
67  RequireTransactionBlock(isTopLevel, "DECLARE CURSOR");
68 
69  /*
70  * Parse analysis was done already, but we still have to run the rule
71  * rewriter. We do not do AcquireRewriteLocks: we assume the query either
72  * came straight from the parser, or suitable locks were acquired by
73  * plancache.c.
74  *
75  * Because the rewriter and planner tend to scribble on the input, we make
76  * a preliminary copy of the source querytree. This prevents problems in
77  * the case that the DECLARE CURSOR is in a portal or plpgsql function and
78  * is executed repeatedly. (See also the same hack in EXPLAIN and
79  * PREPARE.) XXX FIXME someday.
80  */
81  rewritten = QueryRewrite((Query *) copyObject(query));
82 
83  /* SELECT should never rewrite to more or less than one query */
84  if (list_length(rewritten) != 1)
85  elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
86 
87  query = linitial_node(Query, rewritten);
88 
89  if (query->commandType != CMD_SELECT)
90  elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
91 
92  /* Plan the query, applying the specified options */
93  plan = pg_plan_query(query, cstmt->options, params);
94 
95  /*
96  * Create a portal and copy the plan and query string into its memory.
97  */
98  portal = CreatePortal(cstmt->portalname, false, false);
99 
100  oldContext = MemoryContextSwitchTo(portal->portalContext);
101 
102  plan = copyObject(plan);
103 
104  queryString = pstrdup(pstate->p_sourcetext);
105 
106  PortalDefineQuery(portal,
107  NULL,
108  queryString,
109  "SELECT", /* cursor's query is always a SELECT */
110  list_make1(plan),
111  NULL);
112 
113  /*----------
114  * Also copy the outer portal's parameter list into the inner portal's
115  * memory context. We want to pass down the parameter values in case we
116  * had a command like
117  * DECLARE c CURSOR FOR SELECT ... WHERE foo = $1
118  * This will have been parsed using the outer parameter set and the
119  * parameter value needs to be preserved for use when the cursor is
120  * executed.
121  *----------
122  */
123  params = copyParamList(params);
124 
125  MemoryContextSwitchTo(oldContext);
126 
127  /*
128  * Set up options for portal.
129  *
130  * If the user didn't specify a SCROLL type, allow or disallow scrolling
131  * based on whether it would require any additional runtime overhead to do
132  * so. Also, we disallow scrolling for FOR UPDATE cursors.
133  */
134  portal->cursorOptions = cstmt->options;
136  {
137  if (plan->rowMarks == NIL &&
139  portal->cursorOptions |= CURSOR_OPT_SCROLL;
140  else
142  }
143 
144  /*
145  * Start execution, inserting parameters if any.
146  */
147  PortalStart(portal, params, 0, GetActiveSnapshot());
148 
149  Assert(portal->strategy == PORTAL_ONE_SELECT);
150 
151  /*
152  * We're done; the query won't actually be run until PerformPortalFetch is
153  * called.
154  */
155 }
ParamListInfo copyParamList(ParamListInfo from)
Definition: params.c:69
#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:443
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, const char *commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:281
#define castNode(_type_, nodeptr)
Definition: nodes.h:594
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2707
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
int errcode(int sqlerrcode)
Definition: elog.c:608
#define linitial_node(type, l)
Definition: pg_list.h:198
MemoryContext portalContext
Definition: portal.h:119
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2705
struct Plan * planTree
Definition: plannodes.h:64
#define list_make1(x1)
Definition: pg_list.h:227
#define ERROR
Definition: elog.h:43
PortalStrategy strategy
Definition: portal.h:143
const char * p_sourcetext
Definition: parse_node.h:179
#define ereport(elevel, rest)
Definition: elog.h:141
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:494
List * rowMarks
Definition: plannodes.h:84
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:739
static int list_length(const List *l)
Definition: pg_list.h:169
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2704
int cursorOptions
Definition: portal.h:144
#define copyObject(obj)
Definition: nodes.h:641
Definition: pg_list.h:50
void RequireTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3397
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:857

◆ PerformPortalClose()

void PerformPortalClose ( const char *  name)

Definition at line 217 of file portalcmds.c.

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

Referenced by standard_ProcessUtility().

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

◆ PerformPortalFetch()

void PerformPortalFetch ( FetchStmt stmt,
DestReceiver dest,
char *  completionTag 
)

Definition at line 169 of file portalcmds.c.

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

Referenced by standard_ProcessUtility().

172 {
173  Portal portal;
174  uint64 nprocessed;
175 
176  /*
177  * Disallow empty-string cursor name (conflicts with protocol-level
178  * unnamed portal).
179  */
180  if (!stmt->portalname || stmt->portalname[0] == '\0')
181  ereport(ERROR,
182  (errcode(ERRCODE_INVALID_CURSOR_NAME),
183  errmsg("invalid cursor name: must not be empty")));
184 
185  /* get the portal from the portal name */
186  portal = GetPortalByName(stmt->portalname);
187  if (!PortalIsValid(portal))
188  {
189  ereport(ERROR,
190  (errcode(ERRCODE_UNDEFINED_CURSOR),
191  errmsg("cursor \"%s\" does not exist", stmt->portalname)));
192  return; /* keep compiler happy */
193  }
194 
195  /* Adjust dest if needed. MOVE wants destination DestNone */
196  if (stmt->ismove)
197  dest = None_Receiver;
198 
199  /* Do it */
200  nprocessed = PortalRunFetch(portal,
201  stmt->direction,
202  stmt->howMany,
203  dest);
204 
205  /* Return command status if wanted */
206  if (completionTag)
207  snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s " UINT64_FORMAT,
208  stmt->ismove ? "MOVE" : "FETCH",
209  nprocessed);
210 }
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1392
int errcode(int sqlerrcode)
Definition: elog.c:608
DestReceiver * None_Receiver
Definition: dest.c:96
#define ERROR
Definition: elog.h:43
char * portalname
Definition: parsenodes.h:2754
#define ereport(elevel, rest)
Definition: elog.h:141
#define PortalIsValid(p)
Definition: portal.h:201
bool ismove
Definition: parsenodes.h:2755
long howMany
Definition: parsenodes.h:2753
#define COMPLETION_TAG_BUFSIZE
Definition: dest.h:74
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define snprintf
Definition: port.h:192
#define UINT64_FORMAT
Definition: c.h:402
FetchDirection direction
Definition: parsenodes.h:2752

◆ PersistHoldablePortal()

void PersistHoldablePortal ( Portal  portal)

Definition at line 319 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().

320 {
321  QueryDesc *queryDesc = portal->queryDesc;
322  Portal saveActivePortal;
323  ResourceOwner saveResourceOwner;
324  MemoryContext savePortalContext;
325  MemoryContext oldcxt;
326 
327  /*
328  * If we're preserving a holdable portal, we had better be inside the
329  * transaction that originally created it.
330  */
332  Assert(queryDesc != NULL);
333 
334  /*
335  * Caller must have created the tuplestore already ... but not a snapshot.
336  */
337  Assert(portal->holdContext != NULL);
338  Assert(portal->holdStore != NULL);
339  Assert(portal->holdSnapshot == NULL);
340 
341  /*
342  * Before closing down the executor, we must copy the tupdesc into
343  * long-term memory, since it was created in executor memory.
344  */
345  oldcxt = MemoryContextSwitchTo(portal->holdContext);
346 
347  portal->tupDesc = CreateTupleDescCopy(portal->tupDesc);
348 
349  MemoryContextSwitchTo(oldcxt);
350 
351  /*
352  * Check for improper portal use, and mark portal active.
353  */
354  MarkPortalActive(portal);
355 
356  /*
357  * Set up global portal context pointers.
358  */
359  saveActivePortal = ActivePortal;
360  saveResourceOwner = CurrentResourceOwner;
361  savePortalContext = PortalContext;
362  PG_TRY();
363  {
364  ActivePortal = portal;
365  if (portal->resowner)
366  CurrentResourceOwner = portal->resowner;
367  PortalContext = portal->portalContext;
368 
370 
371  PushActiveSnapshot(queryDesc->snapshot);
372 
373  /*
374  * Rewind the executor: we need to store the entire result set in the
375  * tuplestore, so that subsequent backward FETCHs can be processed.
376  */
377  ExecutorRewind(queryDesc);
378 
379  /*
380  * Change the destination to output to the tuplestore. Note we tell
381  * the tuplestore receiver to detoast all data passed through it; this
382  * makes it safe to not keep a snapshot associated with the data.
383  */
384  queryDesc->dest = CreateDestReceiver(DestTuplestore);
386  portal->holdStore,
387  portal->holdContext,
388  true);
389 
390  /* Fetch the result set into the tuplestore */
391  ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
392 
393  queryDesc->dest->rDestroy(queryDesc->dest);
394  queryDesc->dest = NULL;
395 
396  /*
397  * Now shut down the inner executor.
398  */
399  portal->queryDesc = NULL; /* prevent double shutdown */
400  ExecutorFinish(queryDesc);
401  ExecutorEnd(queryDesc);
402  FreeQueryDesc(queryDesc);
403 
404  /*
405  * Set the position in the result set.
406  */
408 
409  if (portal->atEnd)
410  {
411  /*
412  * Just force the tuplestore forward to its end. The size of the
413  * skip request here is arbitrary.
414  */
415  while (tuplestore_skiptuples(portal->holdStore, 1000000, true))
416  /* continue */ ;
417  }
418  else
419  {
420  tuplestore_rescan(portal->holdStore);
421 
422  if (!tuplestore_skiptuples(portal->holdStore,
423  portal->portalPos,
424  true))
425  elog(ERROR, "unexpected end of tuple stream");
426  }
427  }
428  PG_CATCH();
429  {
430  /* Uncaught error while executing portal: mark it dead */
431  MarkPortalFailed(portal);
432 
433  /* Restore global vars and propagate error */
434  ActivePortal = saveActivePortal;
435  CurrentResourceOwner = saveResourceOwner;
436  PortalContext = savePortalContext;
437 
438  PG_RE_THROW();
439  }
440  PG_END_TRY();
441 
442  MemoryContextSwitchTo(oldcxt);
443 
444  /* Mark portal not active */
445  portal->status = PORTAL_READY;
446 
447  ActivePortal = saveActivePortal;
448  CurrentResourceOwner = saveResourceOwner;
449  PortalContext = savePortalContext;
450 
452 
453  /*
454  * We can now release any subsidiary memory of the portal's context; we'll
455  * never use it again. The executor already dropped its context, but this
456  * will clean up anything that glommed onto the portal's context via
457  * PortalContext.
458  */
460 }
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1233
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
bool atEnd
Definition: portal.h:189
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
Portal ActivePortal
Definition: pquery.c:35
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
void MarkPortalActive(Portal portal)
Definition: portalmem.c:392
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
MemoryContext holdContext
Definition: portal.h:167
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
MemoryContext portalContext
Definition: portal.h:119
Snapshot snapshot
Definition: execdesc.h:39
MemoryContext PortalContext
Definition: mcxt.c:53
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:462
#define ERROR
Definition: elog.h:43
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:301
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
SubTransactionId createSubid
Definition: portal.h:130
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
QueryDesc * queryDesc
Definition: portal.h:154
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:256
void ExecutorRewind(QueryDesc *queryDesc)
Definition: execMain.c:528
TupleDesc tupDesc
Definition: portal.h:157
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:126
#define PG_CATCH()
Definition: elog.h:332
#define Assert(condition)
Definition: c.h:739
Snapshot holdSnapshot
Definition: portal.h:177
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:439
PortalStatus status
Definition: portal.h:148
#define PG_RE_THROW()
Definition: elog.h:363
bool tuplestore_skiptuples(Tuplestorestate *state, int64 ntuples, bool forward)
Definition: tuplestore.c:1135
#define InvalidSubTransactionId
Definition: c.h:520
DestReceiver * dest
Definition: execdesc.h:41
ResourceOwner resowner
Definition: portal.h:120
Tuplestorestate * holdStore
Definition: portal.h:166
#define elog(elevel,...)
Definition: elog.h:228
#define PG_TRY()
Definition: elog.h:322
#define PG_END_TRY()
Definition: elog.h:347
uint64 portalPos
Definition: portal.h:190

◆ PortalCleanup()

void PortalCleanup ( Portal  portal)

Definition at line 266 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().

267 {
268  QueryDesc *queryDesc;
269 
270  /*
271  * sanity checks
272  */
273  AssertArg(PortalIsValid(portal));
274  AssertArg(portal->cleanup == PortalCleanup);
275 
276  /*
277  * Shut down executor, if still running. We skip this during error abort,
278  * since other mechanisms will take care of releasing executor resources,
279  * and we can't be sure that ExecutorEnd itself wouldn't fail.
280  */
281  queryDesc = portal->queryDesc;
282  if (queryDesc)
283  {
284  /*
285  * Reset the queryDesc before anything else. This prevents us from
286  * trying to shut down the executor twice, in case of an error below.
287  * The transaction abort mechanisms will take care of resource cleanup
288  * in such a case.
289  */
290  portal->queryDesc = NULL;
291 
292  if (portal->status != PORTAL_FAILED)
293  {
294  ResourceOwner saveResourceOwner;
295 
296  /* We must make the portal's resource owner current */
297  saveResourceOwner = CurrentResourceOwner;
298  if (portal->resowner)
299  CurrentResourceOwner = portal->resowner;
300 
301  ExecutorFinish(queryDesc);
302  ExecutorEnd(queryDesc);
303  FreeQueryDesc(queryDesc);
304 
305  CurrentResourceOwner = saveResourceOwner;
306  }
307  }
308 }
void(* cleanup)(Portal portal)
Definition: portal.h:121
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
void PortalCleanup(Portal portal)
Definition: portalcmds.c:266
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:462
#define AssertArg(condition)
Definition: c.h:741
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
QueryDesc * queryDesc
Definition: portal.h:154
#define PortalIsValid(p)
Definition: portal.h:201
PortalStatus status
Definition: portal.h:148
ResourceOwner resowner
Definition: portal.h:120