PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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  const char *queryString, bool isTopLevel)
44 {
45  Query *query = castNode(Query, cstmt->query);
46  List *rewritten;
47  PlannedStmt *plan;
48  Portal portal;
49  MemoryContext oldContext;
50 
51  /*
52  * Disallow empty-string cursor name (conflicts with protocol-level
53  * unnamed portal).
54  */
55  if (!cstmt->portalname || cstmt->portalname[0] == '\0')
56  ereport(ERROR,
57  (errcode(ERRCODE_INVALID_CURSOR_NAME),
58  errmsg("invalid cursor name: must not be empty")));
59 
60  /*
61  * If this is a non-holdable cursor, we require that this statement has
62  * been executed inside a transaction block (or else, it would have no
63  * user-visible effect).
64  */
65  if (!(cstmt->options & CURSOR_OPT_HOLD))
66  RequireTransactionChain(isTopLevel, "DECLARE CURSOR");
67 
68  /*
69  * Parse analysis was done already, but we still have to run the rule
70  * rewriter. We do not do AcquireRewriteLocks: we assume the query either
71  * came straight from the parser, or suitable locks were acquired by
72  * plancache.c.
73  *
74  * Because the rewriter and planner tend to scribble on the input, we make
75  * a preliminary copy of the source querytree. This prevents problems in
76  * the case that the DECLARE CURSOR is in a portal or plpgsql function and
77  * is executed repeatedly. (See also the same hack in EXPLAIN and
78  * PREPARE.) XXX FIXME someday.
79  */
80  rewritten = QueryRewrite((Query *) copyObject(query));
81 
82  /* SELECT should never rewrite to more or less than one query */
83  if (list_length(rewritten) != 1)
84  elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
85 
86  query = linitial_node(Query, rewritten);
87 
88  if (query->commandType != CMD_SELECT)
89  elog(ERROR, "non-SELECT statement in DECLARE CURSOR");
90 
91  /* Plan the query, applying the specified options */
92  plan = pg_plan_query(query, cstmt->options, params);
93 
94  /*
95  * Create a portal and copy the plan and queryString into its memory.
96  */
97  portal = CreatePortal(cstmt->portalname, false, false);
98 
99  oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
100 
101  plan = copyObject(plan);
102 
103  queryString = pstrdup(queryString);
104 
105  PortalDefineQuery(portal,
106  NULL,
107  queryString,
108  "SELECT", /* cursor's query is always a SELECT */
109  list_make1(plan),
110  NULL);
111 
112  /*----------
113  * Also copy the outer portal's parameter list into the inner portal's
114  * memory context. We want to pass down the parameter values in case we
115  * had a command like
116  * DECLARE c CURSOR FOR SELECT ... WHERE foo = $1
117  * This will have been parsed using the outer parameter set and the
118  * parameter value needs to be preserved for use when the cursor is
119  * executed.
120  *----------
121  */
122  params = copyParamList(params);
123 
124  MemoryContextSwitchTo(oldContext);
125 
126  /*
127  * Set up options for portal.
128  *
129  * If the user didn't specify a SCROLL type, allow or disallow scrolling
130  * based on whether it would require any additional runtime overhead to do
131  * so. Also, we disallow scrolling for FOR UPDATE cursors.
132  */
133  portal->cursorOptions = cstmt->options;
135  {
136  if (plan->rowMarks == NIL &&
138  portal->cursorOptions |= CURSOR_OPT_SCROLL;
139  else
141  }
142 
143  /*
144  * Start execution, inserting parameters if any.
145  */
146  PortalStart(portal, params, 0, GetActiveSnapshot());
147 
148  Assert(portal->strategy == PORTAL_ONE_SELECT);
149 
150  /*
151  * We're done; the query won't actually be run until PerformPortalFetch is
152  * called.
153  */
154 }
155 
156 /*
157  * PerformPortalFetch
158  * Execute SQL FETCH or MOVE command.
159  *
160  * stmt: parsetree node for command
161  * dest: where to send results
162  * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
163  * in which to store a command completion status string.
164  *
165  * completionTag may be NULL if caller doesn't want a status string.
166  */
167 void
169  DestReceiver *dest,
170  char *completionTag)
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 (completionTag)
206  snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s " UINT64_FORMAT,
207  stmt->ismove ? "MOVE" : "FETCH",
208  nprocessed);
209 }
210 
211 /*
212  * PerformPortalClose
213  * Close a cursor.
214  */
215 void
217 {
218  Portal portal;
219 
220  /* NULL means CLOSE ALL */
221  if (name == NULL)
222  {
224  return;
225  }
226 
227  /*
228  * Disallow empty-string cursor name (conflicts with protocol-level
229  * unnamed portal).
230  */
231  if (name[0] == '\0')
232  ereport(ERROR,
233  (errcode(ERRCODE_INVALID_CURSOR_NAME),
234  errmsg("invalid cursor name: must not be empty")));
235 
236  /*
237  * get the portal from the portal name
238  */
239  portal = GetPortalByName(name);
240  if (!PortalIsValid(portal))
241  {
242  ereport(ERROR,
243  (errcode(ERRCODE_UNDEFINED_CURSOR),
244  errmsg("cursor \"%s\" does not exist", name)));
245  return; /* keep compiler happy */
246  }
247 
248  /*
249  * Note: PortalCleanup is called as a side-effect, if not already done.
250  */
251  PortalDrop(portal, false);
252 }
253 
254 /*
255  * PortalCleanup
256  *
257  * Clean up a portal when it's dropped. This is the standard cleanup hook
258  * for portals.
259  *
260  * Note: if portal->status is PORTAL_FAILED, we are probably being called
261  * during error abort, and must be careful to avoid doing anything that
262  * is likely to fail again.
263  */
264 void
266 {
267  QueryDesc *queryDesc;
268 
269  /*
270  * sanity checks
271  */
272  AssertArg(PortalIsValid(portal));
273  AssertArg(portal->cleanup == PortalCleanup);
274 
275  /*
276  * Shut down executor, if still running. We skip this during error abort,
277  * since other mechanisms will take care of releasing executor resources,
278  * and we can't be sure that ExecutorEnd itself wouldn't fail.
279  */
280  queryDesc = PortalGetQueryDesc(portal);
281  if (queryDesc)
282  {
283  /*
284  * Reset the queryDesc before anything else. This prevents us from
285  * trying to shut down the executor twice, in case of an error below.
286  * The transaction abort mechanisms will take care of resource cleanup
287  * in such a case.
288  */
289  portal->queryDesc = NULL;
290 
291  if (portal->status != PORTAL_FAILED)
292  {
293  ResourceOwner saveResourceOwner;
294 
295  /* We must make the portal's resource owner current */
296  saveResourceOwner = CurrentResourceOwner;
297  PG_TRY();
298  {
299  if (portal->resowner)
300  CurrentResourceOwner = portal->resowner;
301  ExecutorFinish(queryDesc);
302  ExecutorEnd(queryDesc);
303  FreeQueryDesc(queryDesc);
304  }
305  PG_CATCH();
306  {
307  /* Ensure CurrentResourceOwner is restored on error */
308  CurrentResourceOwner = saveResourceOwner;
309  PG_RE_THROW();
310  }
311  PG_END_TRY();
312  CurrentResourceOwner = saveResourceOwner;
313  }
314  }
315 }
316 
317 /*
318  * PersistHoldablePortal
319  *
320  * Prepare the specified Portal for access outside of the current
321  * transaction. When this function returns, all future accesses to the
322  * portal must be done via the Tuplestore (not by invoking the
323  * executor).
324  */
325 void
327 {
328  QueryDesc *queryDesc = PortalGetQueryDesc(portal);
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  {
371  ActivePortal = portal;
372  if (portal->resowner)
373  CurrentResourceOwner = portal->resowner;
375 
377 
378  PushActiveSnapshot(queryDesc->snapshot);
379 
380  /*
381  * Rewind the executor: we need to store the entire result set in the
382  * tuplestore, so that subsequent backward FETCHs can be processed.
383  */
384  ExecutorRewind(queryDesc);
385 
386  /*
387  * Change the destination to output to the tuplestore. Note we tell
388  * the tuplestore receiver to detoast all data passed through it; this
389  * makes it safe to not keep a snapshot associated with the data.
390  */
391  queryDesc->dest = CreateDestReceiver(DestTuplestore);
393  portal->holdStore,
394  portal->holdContext,
395  true);
396 
397  /* Fetch the result set into the tuplestore */
398  ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
399 
400  queryDesc->dest->rDestroy(queryDesc->dest);
401  queryDesc->dest = NULL;
402 
403  /*
404  * Now shut down the inner executor.
405  */
406  portal->queryDesc = NULL; /* prevent double shutdown */
407  ExecutorFinish(queryDesc);
408  ExecutorEnd(queryDesc);
409  FreeQueryDesc(queryDesc);
410 
411  /*
412  * Set the position in the result set.
413  */
415 
416  if (portal->atEnd)
417  {
418  /*
419  * Just force the tuplestore forward to its end. The size of the
420  * skip request here is arbitrary.
421  */
422  while (tuplestore_skiptuples(portal->holdStore, 1000000, true))
423  /* continue */ ;
424  }
425  else
426  {
427  tuplestore_rescan(portal->holdStore);
428 
429  if (!tuplestore_skiptuples(portal->holdStore,
430  portal->portalPos,
431  true))
432  elog(ERROR, "unexpected end of tuple stream");
433  }
434  }
435  PG_CATCH();
436  {
437  /* Uncaught error while executing portal: mark it dead */
438  MarkPortalFailed(portal);
439 
440  /* Restore global vars and propagate error */
441  ActivePortal = saveActivePortal;
442  CurrentResourceOwner = saveResourceOwner;
443  PortalContext = savePortalContext;
444 
445  PG_RE_THROW();
446  }
447  PG_END_TRY();
448 
449  MemoryContextSwitchTo(oldcxt);
450 
451  /* Mark portal not active */
452  portal->status = PORTAL_READY;
453 
454  ActivePortal = saveActivePortal;
455  CurrentResourceOwner = saveResourceOwner;
456  PortalContext = savePortalContext;
457 
459 
460  /*
461  * We can now release any subsidiary memory of the portal's heap context;
462  * we'll never use it again. The executor already dropped its context,
463  * but this will clean up anything that glommed onto the portal's heap via
464  * PortalContext.
465  */
467 }
void tuplestore_rescan(Tuplestorestate *state)
Definition: tuplestore.c:1233
ParamListInfo copyParamList(ParamListInfo from)
Definition: params.c:36
#define NIL
Definition: pg_list.h:69
Portal CreatePortal(const char *name, bool allowDup, bool dupSilent)
Definition: portalmem.c:174
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:102
void(* rDestroy)(DestReceiver *self)
Definition: dest.h:126
List * QueryRewrite(Query *parsetree)
void PerformPortalClose(const char *name)
Definition: portalcmds.c:216
bool atEnd
Definition: portal.h:187
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:445
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, const char *commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:277
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
Portal ActivePortal
Definition: pquery.c:35
Portal GetPortalByName(const char *name)
Definition: portalmem.c:129
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
char * pstrdup(const char *in)
Definition: mcxt.c:1076
void MarkPortalActive(Portal portal)
Definition: portalmem.c:388
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1395
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2634
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:839
int errcode(int sqlerrcode)
Definition: elog.c:575
void PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params, const char *queryString, bool isTopLevel)
Definition: portalcmds.c:42
MemoryContext holdContext
Definition: portal.h:165
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
void PortalCleanup(Portal portal)
Definition: portalcmds.c:265
#define linitial_node(type, l)
Definition: pg_list.h:114
DestReceiver * None_Receiver
Definition: dest.c:91
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2632
struct Plan * planTree
Definition: plannodes.h:61
Snapshot snapshot
Definition: execdesc.h:39
MemoryContext PortalContext
Definition: mcxt.c:52
#define list_make1(x1)
Definition: pg_list.h:139
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:461
#define ERROR
Definition: elog.h:43
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:299
void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest, char *completionTag)
Definition: portalcmds.c:168
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:109
PortalStrategy strategy
Definition: portal.h:143
char * portalname
Definition: parsenodes.h:2681
SubTransactionId createSubid
Definition: portal.h:130
#define ereport(elevel, rest)
Definition: elog.h:122
void(* cleanup)(Portal portal)
Definition: portal.h:121
#define AssertArg(condition)
Definition: c.h:666
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:401
QueryDesc * queryDesc
Definition: portal.h:152
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:236
#define PortalIsValid(p)
Definition: portal.h:199
void ExecutorRewind(QueryDesc *queryDesc)
Definition: execMain.c:527
bool ismove
Definition: parsenodes.h:2682
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:462
long howMany
Definition: parsenodes.h:2680
List * rowMarks
Definition: plannodes.h:86
TupleDesc tupDesc
Definition: portal.h:155
CmdType commandType
Definition: parsenodes.h:110
void RequireTransactionChain(bool isTopLevel, const char *stmtType)
Definition: xact.c:3214
void PortalHashTableDeleteAll(void)
Definition: portalmem.c:591
#define PG_CATCH()
Definition: elog.h:293
#define COMPLETION_TAG_BUFSIZE
Definition: dest.h:74
#define Assert(condition)
Definition: c.h:664
static int list_length(const List *l)
Definition: pg_list.h:89
#define PortalGetHeapMemory(portal)
Definition: portal.h:205
Snapshot holdSnapshot
Definition: portal.h:175
void PersistHoldablePortal(Portal portal)
Definition: portalcmds.c:326
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:435
PortalStatus status
Definition: portal.h:148
#define PG_RE_THROW()
Definition: elog.h:314
bool tuplestore_skiptuples(Tuplestorestate *state, int64 ntuples, bool forward)
Definition: tuplestore.c:1135
#define InvalidSubTransactionId
Definition: c.h:397
const char * name
Definition: encode.c:521
#define PortalGetQueryDesc(portal)
Definition: portal.h:204
DestReceiver * dest
Definition: execdesc.h:41
ResourceOwner resowner
Definition: portal.h:120
Tuplestorestate * holdStore
Definition: portal.h:164
int errmsg(const char *fmt,...)
Definition: elog.c:797
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:461
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2631
#define elog
Definition: elog.h:219
int cursorOptions
Definition: portal.h:144
#define copyObject(obj)
Definition: nodes.h:622
#define PG_TRY()
Definition: elog.h:284
Definition: pg_list.h:45
#define UINT64_FORMAT
Definition: c.h:301
#define PG_END_TRY()
Definition: elog.h:300
FetchDirection direction
Definition: parsenodes.h:2679
uint64 portalPos
Definition: portal.h:188
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:786