PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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 (DeclareCursorStmt *cstmt, ParamListInfo params, const char *queryString, 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

void PerformCursorOpen ( DeclareCursorStmt cstmt,
ParamListInfo  params,
const char *  queryString,
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, pg_plan_query(), PlannedStmt::planTree, PORTAL_ONE_SELECT, PortalDefineQuery(), PortalGetHeapMemory, DeclareCursorStmt::portalname, PortalStart(), pstrdup(), DeclareCursorStmt::query, QueryRewrite(), RequireTransactionChain(), 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 
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 }
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
List * QueryRewrite(Query *parsetree)
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:579
char * pstrdup(const char *in)
Definition: mcxt.c:1076
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2634
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:839
int errcode(int sqlerrcode)
Definition: elog.c:575
#define linitial_node(type, l)
Definition: pg_list.h:114
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2632
struct Plan * planTree
Definition: plannodes.h:61
#define list_make1(x1)
Definition: pg_list.h:139
#define ERROR
Definition: elog.h:43
PortalStrategy strategy
Definition: portal.h:143
#define ereport(elevel, rest)
Definition: elog.h:122
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:462
List * rowMarks
Definition: plannodes.h:86
CmdType commandType
Definition: parsenodes.h:110
void RequireTransactionChain(bool isTopLevel, const char *stmtType)
Definition: xact.c:3206
#define Assert(condition)
Definition: c.h:681
static int list_length(const List *l)
Definition: pg_list.h:89
#define PortalGetHeapMemory(portal)
Definition: portal.h:205
int errmsg(const char *fmt,...)
Definition: elog.c:797
#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:623
Definition: pg_list.h:45
PlannedStmt * pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:790
void PerformPortalClose ( const char *  name)

Definition at line 216 of file portalcmds.c.

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

Referenced by standard_ProcessUtility().

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 }
Portal GetPortalByName(const char *name)
Definition: portalmem.c:129
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define PortalIsValid(p)
Definition: portal.h:199
void PortalHashTableDeleteAll(void)
Definition: portalmem.c:591
const char * name
Definition: encode.c:521
int errmsg(const char *fmt,...)
Definition: elog.c:797
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:461
void PerformPortalFetch ( FetchStmt stmt,
DestReceiver dest,
char *  completionTag 
)

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

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 }
Portal GetPortalByName(const char *name)
Definition: portalmem.c:129
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1395
int errcode(int sqlerrcode)
Definition: elog.c:575
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
DestReceiver * None_Receiver
Definition: dest.c:91
#define ERROR
Definition: elog.h:43
char * portalname
Definition: parsenodes.h:2681
#define ereport(elevel, rest)
Definition: elog.h:122
#define PortalIsValid(p)
Definition: portal.h:199
bool ismove
Definition: parsenodes.h:2682
long howMany
Definition: parsenodes.h:2680
#define COMPLETION_TAG_BUFSIZE
Definition: dest.h:74
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define UINT64_FORMAT
Definition: c.h:301
FetchDirection direction
Definition: parsenodes.h:2679
void PersistHoldablePortal ( Portal  portal)

Definition at line 318 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, PortalGetHeapMemory, PortalGetQueryDesc, PortalData::portalPos, PushActiveSnapshot(), PortalData::queryDesc, _DestReceiver::rDestroy, PortalData::resowner, SetTuplestoreDestReceiverParams(), QueryDesc::snapshot, PortalData::status, PortalData::tupDesc, tuplestore_rescan(), and tuplestore_skiptuples().

Referenced by PreCommit_Portals().

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

Definition at line 265 of file portalcmds.c.

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

Referenced by CreatePortal(), and PortalCleanup().

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  if (portal->resowner)
298  CurrentResourceOwner = portal->resowner;
299 
300  ExecutorFinish(queryDesc);
301  ExecutorEnd(queryDesc);
302  FreeQueryDesc(queryDesc);
303 
304  CurrentResourceOwner = saveResourceOwner;
305  }
306  }
307 }
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
ResourceOwner CurrentResourceOwner
Definition: resowner.c:138
void PortalCleanup(Portal portal)
Definition: portalcmds.c:265
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:461
void(* cleanup)(Portal portal)
Definition: portal.h:121
#define AssertArg(condition)
Definition: c.h:683
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:401
QueryDesc * queryDesc
Definition: portal.h:152
#define PortalIsValid(p)
Definition: portal.h:199
PortalStatus status
Definition: portal.h:148
#define PortalGetQueryDesc(portal)
Definition: portal.h:204
ResourceOwner resowner
Definition: portal.h:120