PostgreSQL Source Code  git master
portalcmds.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * portalcmds.c
4  * Utility commands affecting portals (that is, SQL cursor commands)
5  *
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).
10  *
11  *
12  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  *
16  * IDENTIFICATION
17  * src/backend/commands/portalcmds.c
18  *
19  *-------------------------------------------------------------------------
20  */
21 
22 #include "postgres.h"
23 
24 #include <limits.h>
25 
26 #include "access/xact.h"
27 #include "commands/portalcmds.h"
28 #include "executor/executor.h"
30 #include "rewrite/rewriteHandler.h"
31 #include "tcop/pquery.h"
32 #include "tcop/tcopprot.h"
33 #include "utils/memutils.h"
34 #include "utils/snapmgr.h"
35 
36 
37 /*
38  * PerformCursorOpen
39  * Execute SQL DECLARE CURSOR command.
40  */
41 void
43  bool isTopLevel)
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 }
156 
157 /*
158  * PerformPortalFetch
159  * Execute SQL FETCH or MOVE command.
160  *
161  * stmt: parsetree node for command
162  * dest: where to send results
163  * qc: where to store a command completion status data.
164  *
165  * qc may be NULL if caller doesn't want status data.
166  */
167 void
170  QueryCompletion *qc)
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 }
209 
210 /*
211  * PerformPortalClose
212  * Close a cursor.
213  */
214 void
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 }
252 
253 /*
254  * PortalCleanup
255  *
256  * Clean up a portal when it's dropped. This is the standard cleanup hook
257  * for portals.
258  *
259  * Note: if portal->status is PORTAL_FAILED, we are probably being called
260  * during error abort, and must be careful to avoid doing anything that
261  * is likely to fail again.
262  */
263 void
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 }
307 
308 /*
309  * PersistHoldablePortal
310  *
311  * Prepare the specified Portal for access outside of the current
312  * transaction. When this function returns, all future accesses to the
313  * portal must be done via the Tuplestore (not by invoking the
314  * executor).
315  */
316 void
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 
388  /* Fetch the result set into the tuplestore */
389  ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
390 
391  queryDesc->dest->rDestroy(queryDesc->dest);
392  queryDesc->dest = NULL;
393 
394  /*
395  * Now shut down the inner executor.
396  */
397  portal->queryDesc = NULL; /* prevent double shutdown */
398  ExecutorFinish(queryDesc);
399  ExecutorEnd(queryDesc);
400  FreeQueryDesc(queryDesc);
401 
402  /*
403  * Set the position in the result set.
404  */
406 
407  if (portal->atEnd)
408  {
409  /*
410  * Just force the tuplestore forward to its end. The size of the
411  * skip request here is arbitrary.
412  */
413  while (tuplestore_skiptuples(portal->holdStore, 1000000, true))
414  /* continue */ ;
415  }
416  else
417  {
418  tuplestore_rescan(portal->holdStore);
419 
420  if (!tuplestore_skiptuples(portal->holdStore,
421  portal->portalPos,
422  true))
423  elog(ERROR, "unexpected end of tuple stream");
424  }
425  }
426  PG_CATCH();
427  {
428  /* Uncaught error while executing portal: mark it dead */
429  MarkPortalFailed(portal);
430 
431  /* Restore global vars and propagate error */
432  ActivePortal = saveActivePortal;
433  CurrentResourceOwner = saveResourceOwner;
434  PortalContext = savePortalContext;
435 
436  PG_RE_THROW();
437  }
438  PG_END_TRY();
439 
440  MemoryContextSwitchTo(oldcxt);
441 
442  /* Mark portal not active */
443  portal->status = PORTAL_READY;
444 
445  ActivePortal = saveActivePortal;
446  CurrentResourceOwner = saveResourceOwner;
447  PortalContext = savePortalContext;
448 
450 
451  /*
452  * We can now release any subsidiary memory of the portal's context; we'll
453  * never use it again. The executor already dropped its context, but this
454  * will clean up anything that glommed onto the portal's context via
455  * PortalContext.
456  */
458 }
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1233
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
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
List * QueryRewrite(Query *parsetree)
void PerformPortalClose(const char *name)
Definition: portalcmds.c:215
bool atEnd
Definition: portal.h:191
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:430
void(* cleanup)(Portal portal)
Definition: portal.h:122
#define castNode(_type_, nodeptr)
Definition: nodes.h:598
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
Portal ActivePortal
Definition: pquery.c:35
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
ResourceOwner CurrentResourceOwner
Definition: resowner.c:142
char * pstrdup(const char *in)
Definition: mcxt.c:1186
void MarkPortalActive(Portal portal)
Definition: portalmem.c:394
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1368
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2710
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
int errcode(int sqlerrcode)
Definition: elog.c:610
MemoryContext holdContext
Definition: portal.h:169
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
void PortalCleanup(Portal portal)
Definition: portalcmds.c:264
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
DestReceiver * None_Receiver
Definition: dest.c:96
MemoryContext portalContext
Definition: portal.h:120
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2708
struct Plan * planTree
Definition: plannodes.h:64
Snapshot snapshot
Definition: execdesc.h:39
MemoryContext PortalContext
Definition: mcxt.c:53
#define list_make1(x1)
Definition: pg_list.h:227
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 PerformCursorOpen(ParseState *pstate, DeclareCursorStmt *cstmt, ParamListInfo params, bool isTopLevel)
Definition: portalcmds.c:42
void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest, QueryCompletion *qc)
Definition: portalcmds.c:168
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
PortalStrategy strategy
Definition: portal.h:145
const char * p_sourcetext
Definition: parse_node.h:179
char * portalname
Definition: parsenodes.h:2757
SubTransactionId createSubid
Definition: portal.h:131
#define AssertArg(condition)
Definition: c.h:740
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
QueryDesc * queryDesc
Definition: portal.h:156
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:256
#define PortalIsValid(p)
Definition: portal.h:203
void ExecutorRewind(QueryDesc *queryDesc)
Definition: execMain.c:528
bool ismove
Definition: parsenodes.h:2758
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:499
long howMany
Definition: parsenodes.h:2756
List * rowMarks
Definition: plannodes.h:84
TupleDesc tupDesc
Definition: portal.h:159
#define ereport(elevel,...)
Definition: elog.h:144
CmdType commandType
Definition: parsenodes.h:112
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:127
void PortalHashTableDeleteAll(void)
Definition: portalmem.c:603
#define PG_CATCH()
Definition: elog.h:305
#define Assert(condition)
Definition: c.h:738
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:36
static int list_length(const List *l)
Definition: pg_list.h:169
Snapshot holdSnapshot
Definition: portal.h:179
void PersistHoldablePortal(Portal portal)
Definition: portalcmds.c:317
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:519
const char * name
Definition: encode.c:555
DestReceiver * dest
Definition: execdesc.h:41
ResourceOwner resowner
Definition: portal.h:121
Tuplestorestate * holdStore
Definition: portal.h:168
int errmsg(const char *fmt,...)
Definition: elog.c:824
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:467
#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
#define PG_TRY()
Definition: elog.h:295
Definition: pg_list.h:50
#define PG_END_TRY()
Definition: elog.h:320
void RequireTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3416
FetchDirection direction
Definition: parsenodes.h:2755
uint64 portalPos
Definition: portal.h:192