PostgreSQL Source Code  git master
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 "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 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, pstate->p_sourcetext, 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  CMDTAG_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:77
#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:598
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2710
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
int errcode(int sqlerrcode)
Definition: elog.c:610
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:198
MemoryContext portalContext
Definition: portal.h:120
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2708
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:145
const char * p_sourcetext
Definition: parse_node.h:179
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:499
List * rowMarks
Definition: plannodes.h:84
#define ereport(elevel,...)
Definition: elog.h:144
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:745
static int list_length(const List *l)
Definition: pg_list.h:169
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2707
PlannedStmt * pg_plan_query(Query *querytree, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:857
int cursorOptions
Definition: portal.h:146
#define copyObject(obj)
Definition: nodes.h:645
Definition: pg_list.h:50
void RequireTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3446

◆ PerformPortalClose()

void PerformPortalClose ( const char *  name)

Definition at line 215 of file portalcmds.c.

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

Referenced by standard_ProcessUtility().

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

◆ PerformPortalFetch()

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

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

171 {
172  Portal portal;
173  uint64 nprocessed;
174 
175  /*
176  * Disallow empty-string cursor name (conflicts with protocol-level
177  * unnamed portal).
178  */
179  if (!stmt->portalname || stmt->portalname[0] == '\0')
180  ereport(ERROR,
181  (errcode(ERRCODE_INVALID_CURSOR_NAME),
182  errmsg("invalid cursor name: must not be empty")));
183 
184  /* get the portal from the portal name */
185  portal = GetPortalByName(stmt->portalname);
186  if (!PortalIsValid(portal))
187  {
188  ereport(ERROR,
189  (errcode(ERRCODE_UNDEFINED_CURSOR),
190  errmsg("cursor \"%s\" does not exist", stmt->portalname)));
191  return; /* keep compiler happy */
192  }
193 
194  /* Adjust dest if needed. MOVE wants destination DestNone */
195  if (stmt->ismove)
196  dest = None_Receiver;
197 
198  /* Do it */
199  nprocessed = PortalRunFetch(portal,
200  stmt->direction,
201  stmt->howMany,
202  dest);
203 
204  /* Return command status if wanted */
205  if (qc)
206  SetQueryCompletion(qc, stmt->ismove ? CMDTAG_MOVE : CMDTAG_FETCH,
207  nprocessed);
208 }
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1370
int errcode(int sqlerrcode)
Definition: elog.c:610
DestReceiver * None_Receiver
Definition: dest.c:96
#define ERROR
Definition: elog.h:43
char * portalname
Definition: parsenodes.h:2757
#define PortalIsValid(p)
Definition: portal.h:203
bool ismove
Definition: parsenodes.h:2758
long howMany
Definition: parsenodes.h:2756
#define ereport(elevel,...)
Definition: elog.h:144
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:36
int errmsg(const char *fmt,...)
Definition: elog.c:824
FetchDirection direction
Definition: parsenodes.h:2755

◆ PersistHoldablePortal()

void PersistHoldablePortal ( Portal  portal)

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

318 {
319  QueryDesc *queryDesc = portal->queryDesc;
320  Portal saveActivePortal;
321  ResourceOwner saveResourceOwner;
322  MemoryContext savePortalContext;
323  MemoryContext oldcxt;
324 
325  /*
326  * If we're preserving a holdable portal, we had better be inside the
327  * transaction that originally created it.
328  */
330  Assert(queryDesc != NULL);
331 
332  /*
333  * Caller must have created the tuplestore already ... but not a snapshot.
334  */
335  Assert(portal->holdContext != NULL);
336  Assert(portal->holdStore != NULL);
337  Assert(portal->holdSnapshot == NULL);
338 
339  /*
340  * Before closing down the executor, we must copy the tupdesc into
341  * long-term memory, since it was created in executor memory.
342  */
343  oldcxt = MemoryContextSwitchTo(portal->holdContext);
344 
345  portal->tupDesc = CreateTupleDescCopy(portal->tupDesc);
346 
347  MemoryContextSwitchTo(oldcxt);
348 
349  /*
350  * Check for improper portal use, and mark portal active.
351  */
352  MarkPortalActive(portal);
353 
354  /*
355  * Set up global portal context pointers.
356  */
357  saveActivePortal = ActivePortal;
358  saveResourceOwner = CurrentResourceOwner;
359  savePortalContext = PortalContext;
360  PG_TRY();
361  {
362  ActivePortal = portal;
363  if (portal->resowner)
364  CurrentResourceOwner = portal->resowner;
365  PortalContext = portal->portalContext;
366 
368 
369  PushActiveSnapshot(queryDesc->snapshot);
370 
371  /*
372  * Rewind the executor: we need to store the entire result set in the
373  * tuplestore, so that subsequent backward FETCHs can be processed.
374  */
375  ExecutorRewind(queryDesc);
376 
377  /*
378  * Change the destination to output to the tuplestore. Note we tell
379  * the tuplestore receiver to detoast all data passed through it; this
380  * makes it safe to not keep a snapshot associated with the data.
381  */
382  queryDesc->dest = CreateDestReceiver(DestTuplestore);
384  portal->holdStore,
385  portal->holdContext,
386  true,
387  NULL,
388  NULL);
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:191
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
Portal ActivePortal
Definition: pquery.c:35
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
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:814
MemoryContext portalContext
Definition: portal.h:120
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:131
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
QueryDesc * queryDesc
Definition: portal.h:156
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:256
void ExecutorRewind(QueryDesc *queryDesc)
Definition: execMain.c:528
TupleDesc tupDesc
Definition: portal.h:159
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:127
#define PG_CATCH()
Definition: elog.h:305
#define Assert(condition)
Definition: c.h:745
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:336
bool tuplestore_skiptuples(Tuplestorestate *state, int64 ntuples, bool forward)
Definition: tuplestore.c:1135
#define InvalidSubTransactionId
Definition: c.h:526
DestReceiver * dest
Definition: execdesc.h:41
ResourceOwner resowner
Definition: portal.h:121
Tuplestorestate * holdStore
Definition: portal.h:168
#define elog(elevel,...)
Definition: elog.h:214
#define PG_TRY()
Definition: elog.h:295
#define PG_END_TRY()
Definition: elog.h:320
uint64 portalPos
Definition: portal.h:192

◆ PortalCleanup()

void PortalCleanup ( Portal  portal)

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

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