PostgreSQL Source Code  git master
portalmem.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * portalmem.c
4  * backend portal memory management
5  *
6  * Portals are objects representing the execution state of a query.
7  * This module provides memory management services for portals, but it
8  * doesn't actually run the executor for them.
9  *
10  *
11  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
12  * Portions Copyright (c) 1994, Regents of the University of California
13  *
14  * IDENTIFICATION
15  * src/backend/utils/mmgr/portalmem.c
16  *
17  *-------------------------------------------------------------------------
18  */
19 #include "postgres.h"
20 
21 #include "access/xact.h"
22 #include "catalog/pg_type.h"
23 #include "commands/portalcmds.h"
24 #include "miscadmin.h"
25 #include "storage/ipc.h"
26 #include "utils/builtins.h"
27 #include "utils/memutils.h"
28 #include "utils/snapmgr.h"
29 #include "utils/timestamp.h"
30 
31 /*
32  * Estimate of the maximum number of open portals a user would have,
33  * used in initially sizing the PortalHashTable in EnablePortalManager().
34  * Since the hash table can expand, there's no need to make this overly
35  * generous, and keeping it small avoids unnecessary overhead in the
36  * hash_seq_search() calls executed during transaction end.
37  */
38 #define PORTALS_PER_USER 16
39 
40 
41 /* ----------------
42  * Global state
43  * ----------------
44  */
45 
46 #define MAX_PORTALNAME_LEN NAMEDATALEN
47 
48 typedef struct portalhashent
49 {
53 
54 static HTAB *PortalHashTable = NULL;
55 
56 #define PortalHashTableLookup(NAME, PORTAL) \
57 do { \
58  PortalHashEnt *hentry; \
59  \
60  hentry = (PortalHashEnt *) hash_search(PortalHashTable, \
61  (NAME), HASH_FIND, NULL); \
62  if (hentry) \
63  PORTAL = hentry->portal; \
64  else \
65  PORTAL = NULL; \
66 } while(0)
67 
68 #define PortalHashTableInsert(PORTAL, NAME) \
69 do { \
70  PortalHashEnt *hentry; bool found; \
71  \
72  hentry = (PortalHashEnt *) hash_search(PortalHashTable, \
73  (NAME), HASH_ENTER, &found); \
74  if (found) \
75  elog(ERROR, "duplicate portal name"); \
76  hentry->portal = PORTAL; \
77  /* To avoid duplicate storage, make PORTAL->name point to htab entry */ \
78  PORTAL->name = hentry->portalname; \
79 } while(0)
80 
81 #define PortalHashTableDelete(PORTAL) \
82 do { \
83  PortalHashEnt *hentry; \
84  \
85  hentry = (PortalHashEnt *) hash_search(PortalHashTable, \
86  PORTAL->name, HASH_REMOVE, NULL); \
87  if (hentry == NULL) \
88  elog(WARNING, "trying to delete portal name that does not exist"); \
89 } while(0)
90 
92 
93 
94 /* ----------------------------------------------------------------
95  * public portal interface functions
96  * ----------------------------------------------------------------
97  */
98 
99 /*
100  * EnablePortalManager
101  * Enables the portal management module at backend startup.
102  */
103 void
105 {
106  HASHCTL ctl;
107 
108  Assert(TopPortalContext == NULL);
109 
110  TopPortalContext = AllocSetContextCreate(TopMemoryContext,
111  "TopPortalContext",
113 
115  ctl.entrysize = sizeof(PortalHashEnt);
116 
117  /*
118  * use PORTALS_PER_USER as a guess of how many hash table entries to
119  * create, initially
120  */
121  PortalHashTable = hash_create("Portal hash", PORTALS_PER_USER,
122  &ctl, HASH_ELEM);
123 }
124 
125 /*
126  * GetPortalByName
127  * Returns a portal given a portal name, or NULL if name not found.
128  */
129 Portal
130 GetPortalByName(const char *name)
131 {
132  Portal portal;
133 
134  if (PointerIsValid(name))
135  PortalHashTableLookup(name, portal);
136  else
137  portal = NULL;
138 
139  return portal;
140 }
141 
142 /*
143  * PortalGetPrimaryStmt
144  * Get the "primary" stmt within a portal, ie, the one marked canSetTag.
145  *
146  * Returns NULL if no such stmt. If multiple PlannedStmt structs within the
147  * portal are marked canSetTag, returns the first one. Neither of these
148  * cases should occur in present usages of this function.
149  */
150 PlannedStmt *
152 {
153  ListCell *lc;
154 
155  foreach(lc, portal->stmts)
156  {
157  PlannedStmt *stmt = lfirst_node(PlannedStmt, lc);
158 
159  if (stmt->canSetTag)
160  return stmt;
161  }
162  return NULL;
163 }
164 
165 /*
166  * CreatePortal
167  * Returns a new portal given a name.
168  *
169  * allowDup: if true, automatically drop any pre-existing portal of the
170  * same name (if false, an error is raised).
171  *
172  * dupSilent: if true, don't even emit a WARNING.
173  */
174 Portal
175 CreatePortal(const char *name, bool allowDup, bool dupSilent)
176 {
177  Portal portal;
178 
179  AssertArg(PointerIsValid(name));
180 
181  portal = GetPortalByName(name);
182  if (PortalIsValid(portal))
183  {
184  if (!allowDup)
185  ereport(ERROR,
186  (errcode(ERRCODE_DUPLICATE_CURSOR),
187  errmsg("cursor \"%s\" already exists", name)));
188  if (!dupSilent)
190  (errcode(ERRCODE_DUPLICATE_CURSOR),
191  errmsg("closing existing cursor \"%s\"",
192  name)));
193  PortalDrop(portal, false);
194  }
195 
196  /* make new portal structure */
197  portal = (Portal) MemoryContextAllocZero(TopPortalContext, sizeof *portal);
198 
199  /* initialize portal context; typically it won't store much */
200  portal->portalContext = AllocSetContextCreate(TopPortalContext,
201  "PortalContext",
203 
204  /* create a resource owner for the portal */
206  "Portal");
207 
208  /* initialize portal fields that don't start off zero */
209  portal->status = PORTAL_NEW;
210  portal->cleanup = PortalCleanup;
212  portal->activeSubid = portal->createSubid;
213  portal->strategy = PORTAL_MULTI_QUERY;
215  portal->atStart = true;
216  portal->atEnd = true; /* disallow fetches until query is set */
217  portal->visible = true;
219 
220  /* put portal in table (sets portal->name) */
221  PortalHashTableInsert(portal, name);
222 
223  /* reuse portal->name copy */
225 
226  return portal;
227 }
228 
229 /*
230  * CreateNewPortal
231  * Create a new portal, assigning it a random nonconflicting name.
232  */
233 Portal
235 {
236  static unsigned int unnamed_portal_count = 0;
237 
239 
240  /* Select a nonconflicting name */
241  for (;;)
242  {
243  unnamed_portal_count++;
244  sprintf(portalname, "<unnamed portal %u>", unnamed_portal_count);
245  if (GetPortalByName(portalname) == NULL)
246  break;
247  }
248 
249  return CreatePortal(portalname, false, false);
250 }
251 
252 /*
253  * PortalDefineQuery
254  * A simple subroutine to establish a portal's query.
255  *
256  * Notes: as of PG 8.4, caller MUST supply a sourceText string; it is not
257  * allowed anymore to pass NULL. (If you really don't have source text,
258  * you can pass a constant string, perhaps "(query not available)".)
259  *
260  * commandTag shall be NULL if and only if the original query string
261  * (before rewriting) was an empty string. Also, the passed commandTag must
262  * be a pointer to a constant string, since it is not copied.
263  *
264  * If cplan is provided, then it is a cached plan containing the stmts, and
265  * the caller must have done GetCachedPlan(), causing a refcount increment.
266  * The refcount will be released when the portal is destroyed.
267  *
268  * If cplan is NULL, then it is the caller's responsibility to ensure that
269  * the passed plan trees have adequate lifetime. Typically this is done by
270  * copying them into the portal's context.
271  *
272  * The caller is also responsible for ensuring that the passed prepStmtName
273  * (if not NULL) and sourceText have adequate lifetime.
274  *
275  * NB: this function mustn't do much beyond storing the passed values; in
276  * particular don't do anything that risks elog(ERROR). If that were to
277  * happen here before storing the cplan reference, we'd leak the plancache
278  * refcount that the caller is trying to hand off to us.
279  */
280 void
282  const char *prepStmtName,
283  const char *sourceText,
284  const char *commandTag,
285  List *stmts,
286  CachedPlan *cplan)
287 {
288  AssertArg(PortalIsValid(portal));
289  AssertState(portal->status == PORTAL_NEW);
290 
291  AssertArg(sourceText != NULL);
292  AssertArg(commandTag != NULL || stmts == NIL);
293 
294  portal->prepStmtName = prepStmtName;
295  portal->sourceText = sourceText;
296  portal->commandTag = commandTag;
297  portal->stmts = stmts;
298  portal->cplan = cplan;
299  portal->status = PORTAL_DEFINED;
300 }
301 
302 /*
303  * PortalReleaseCachedPlan
304  * Release a portal's reference to its cached plan, if any.
305  */
306 static void
308 {
309  if (portal->cplan)
310  {
311  ReleaseCachedPlan(portal->cplan, false);
312  portal->cplan = NULL;
313 
314  /*
315  * We must also clear portal->stmts which is now a dangling reference
316  * to the cached plan's plan list. This protects any code that might
317  * try to examine the Portal later.
318  */
319  portal->stmts = NIL;
320  }
321 }
322 
323 /*
324  * PortalCreateHoldStore
325  * Create the tuplestore for a portal.
326  */
327 void
329 {
330  MemoryContext oldcxt;
331 
332  Assert(portal->holdContext == NULL);
333  Assert(portal->holdStore == NULL);
334  Assert(portal->holdSnapshot == NULL);
335 
336  /*
337  * Create the memory context that is used for storage of the tuple set.
338  * Note this is NOT a child of the portal's portalContext.
339  */
340  portal->holdContext =
341  AllocSetContextCreate(TopPortalContext,
342  "PortalHoldContext",
344 
345  /*
346  * Create the tuple store, selecting cross-transaction temp files, and
347  * enabling random access only if cursor requires scrolling.
348  *
349  * XXX: Should maintenance_work_mem be used for the portal size?
350  */
351  oldcxt = MemoryContextSwitchTo(portal->holdContext);
352 
353  portal->holdStore =
355  true, work_mem);
356 
357  MemoryContextSwitchTo(oldcxt);
358 }
359 
360 /*
361  * PinPortal
362  * Protect a portal from dropping.
363  *
364  * A pinned portal is still unpinned and dropped at transaction or
365  * subtransaction abort.
366  */
367 void
369 {
370  if (portal->portalPinned)
371  elog(ERROR, "portal already pinned");
372 
373  portal->portalPinned = true;
374 }
375 
376 void
378 {
379  if (!portal->portalPinned)
380  elog(ERROR, "portal not pinned");
381 
382  portal->portalPinned = false;
383 }
384 
385 /*
386  * MarkPortalActive
387  * Transition a portal from READY to ACTIVE state.
388  *
389  * NOTE: never set portal->status = PORTAL_ACTIVE directly; call this instead.
390  */
391 void
393 {
394  /* For safety, this is a runtime test not just an Assert */
395  if (portal->status != PORTAL_READY)
396  ereport(ERROR,
397  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
398  errmsg("portal \"%s\" cannot be run", portal->name)));
399  /* Perform the state transition */
400  portal->status = PORTAL_ACTIVE;
402 }
403 
404 /*
405  * MarkPortalDone
406  * Transition a portal from ACTIVE to DONE state.
407  *
408  * NOTE: never set portal->status = PORTAL_DONE directly; call this instead.
409  */
410 void
412 {
413  /* Perform the state transition */
414  Assert(portal->status == PORTAL_ACTIVE);
415  portal->status = PORTAL_DONE;
416 
417  /*
418  * Allow portalcmds.c to clean up the state it knows about. We might as
419  * well do that now, since the portal can't be executed any more.
420  *
421  * In some cases involving execution of a ROLLBACK command in an already
422  * aborted transaction, this is necessary, or we'd reach AtCleanup_Portals
423  * with the cleanup hook still unexecuted.
424  */
425  if (PointerIsValid(portal->cleanup))
426  {
427  portal->cleanup(portal);
428  portal->cleanup = NULL;
429  }
430 }
431 
432 /*
433  * MarkPortalFailed
434  * Transition a portal into FAILED state.
435  *
436  * NOTE: never set portal->status = PORTAL_FAILED directly; call this instead.
437  */
438 void
440 {
441  /* Perform the state transition */
442  Assert(portal->status != PORTAL_DONE);
443  portal->status = PORTAL_FAILED;
444 
445  /*
446  * Allow portalcmds.c to clean up the state it knows about. We might as
447  * well do that now, since the portal can't be executed any more.
448  *
449  * In some cases involving cleanup of an already aborted transaction, this
450  * is necessary, or we'd reach AtCleanup_Portals with the cleanup hook
451  * still unexecuted.
452  */
453  if (PointerIsValid(portal->cleanup))
454  {
455  portal->cleanup(portal);
456  portal->cleanup = NULL;
457  }
458 }
459 
460 /*
461  * PortalDrop
462  * Destroy the portal.
463  */
464 void
465 PortalDrop(Portal portal, bool isTopCommit)
466 {
467  AssertArg(PortalIsValid(portal));
468 
469  /*
470  * Don't allow dropping a pinned portal, it's still needed by whoever
471  * pinned it.
472  */
473  if (portal->portalPinned)
474  ereport(ERROR,
475  (errcode(ERRCODE_INVALID_CURSOR_STATE),
476  errmsg("cannot drop pinned portal \"%s\"", portal->name)));
477 
478  /*
479  * Not sure if the PORTAL_ACTIVE case can validly happen or not...
480  */
481  if (portal->status == PORTAL_ACTIVE)
482  ereport(ERROR,
483  (errcode(ERRCODE_INVALID_CURSOR_STATE),
484  errmsg("cannot drop active portal \"%s\"", portal->name)));
485 
486  /*
487  * Allow portalcmds.c to clean up the state it knows about, in particular
488  * shutting down the executor if still active. This step potentially runs
489  * user-defined code so failure has to be expected. It's the cleanup
490  * hook's responsibility to not try to do that more than once, in the case
491  * that failure occurs and then we come back to drop the portal again
492  * during transaction abort.
493  *
494  * Note: in most paths of control, this will have been done already in
495  * MarkPortalDone or MarkPortalFailed. We're just making sure.
496  */
497  if (PointerIsValid(portal->cleanup))
498  {
499  portal->cleanup(portal);
500  portal->cleanup = NULL;
501  }
502 
503  /*
504  * Remove portal from hash table. Because we do this here, we will not
505  * come back to try to remove the portal again if there's any error in the
506  * subsequent steps. Better to leak a little memory than to get into an
507  * infinite error-recovery loop.
508  */
509  PortalHashTableDelete(portal);
510 
511  /* drop cached plan reference, if any */
512  PortalReleaseCachedPlan(portal);
513 
514  /*
515  * If portal has a snapshot protecting its data, release that. This needs
516  * a little care since the registration will be attached to the portal's
517  * resowner; if the portal failed, we will already have released the
518  * resowner (and the snapshot) during transaction abort.
519  */
520  if (portal->holdSnapshot)
521  {
522  if (portal->resowner)
524  portal->resowner);
525  portal->holdSnapshot = NULL;
526  }
527 
528  /*
529  * Release any resources still attached to the portal. There are several
530  * cases being covered here:
531  *
532  * Top transaction commit (indicated by isTopCommit): normally we should
533  * do nothing here and let the regular end-of-transaction resource
534  * releasing mechanism handle these resources too. However, if we have a
535  * FAILED portal (eg, a cursor that got an error), we'd better clean up
536  * its resources to avoid resource-leakage warning messages.
537  *
538  * Sub transaction commit: never comes here at all, since we don't kill
539  * any portals in AtSubCommit_Portals().
540  *
541  * Main or sub transaction abort: we will do nothing here because
542  * portal->resowner was already set NULL; the resources were already
543  * cleaned up in transaction abort.
544  *
545  * Ordinary portal drop: must release resources. However, if the portal
546  * is not FAILED then we do not release its locks. The locks become the
547  * responsibility of the transaction's ResourceOwner (since it is the
548  * parent of the portal's owner) and will be released when the transaction
549  * eventually ends.
550  */
551  if (portal->resowner &&
552  (!isTopCommit || portal->status == PORTAL_FAILED))
553  {
554  bool isCommit = (portal->status != PORTAL_FAILED);
555 
558  isCommit, false);
561  isCommit, false);
564  isCommit, false);
565  ResourceOwnerDelete(portal->resowner);
566  }
567  portal->resowner = NULL;
568 
569  /*
570  * Delete tuplestore if present. We should do this even under error
571  * conditions; since the tuplestore would have been using cross-
572  * transaction storage, its temp files need to be explicitly deleted.
573  */
574  if (portal->holdStore)
575  {
576  MemoryContext oldcontext;
577 
578  oldcontext = MemoryContextSwitchTo(portal->holdContext);
579  tuplestore_end(portal->holdStore);
580  MemoryContextSwitchTo(oldcontext);
581  portal->holdStore = NULL;
582  }
583 
584  /* delete tuplestore storage, if any */
585  if (portal->holdContext)
587 
588  /* release subsidiary storage */
590 
591  /* release portal struct (it's in TopPortalContext) */
592  pfree(portal);
593 }
594 
595 /*
596  * Delete all declared cursors.
597  *
598  * Used by commands: CLOSE ALL, DISCARD ALL
599  */
600 void
602 {
604  PortalHashEnt *hentry;
605 
606  if (PortalHashTable == NULL)
607  return;
608 
609  hash_seq_init(&status, PortalHashTable);
610  while ((hentry = hash_seq_search(&status)) != NULL)
611  {
612  Portal portal = hentry->portal;
613 
614  /* Can't close the active portal (the one running the command) */
615  if (portal->status == PORTAL_ACTIVE)
616  continue;
617 
618  PortalDrop(portal, false);
619 
620  /* Restart the iteration in case that led to other drops */
621  hash_seq_term(&status);
622  hash_seq_init(&status, PortalHashTable);
623  }
624 }
625 
626 /*
627  * "Hold" a portal. Prepare it for access by later transactions.
628  */
629 static void
631 {
632  /*
633  * Note that PersistHoldablePortal() must release all resources used by
634  * the portal that are local to the creating transaction.
635  */
636  PortalCreateHoldStore(portal);
637  PersistHoldablePortal(portal);
638 
639  /* drop cached plan reference, if any */
640  PortalReleaseCachedPlan(portal);
641 
642  /*
643  * Any resources belonging to the portal will be released in the upcoming
644  * transaction-wide cleanup; the portal will no longer have its own
645  * resources.
646  */
647  portal->resowner = NULL;
648 
649  /*
650  * Having successfully exported the holdable cursor, mark it as not
651  * belonging to this transaction.
652  */
655 }
656 
657 /*
658  * Pre-commit processing for portals.
659  *
660  * Holdable cursors created in this transaction need to be converted to
661  * materialized form, since we are going to close down the executor and
662  * release locks. Non-holdable portals created in this transaction are
663  * simply removed. Portals remaining from prior transactions should be
664  * left untouched.
665  *
666  * Returns true if any portals changed state (possibly causing user-defined
667  * code to be run), false if not.
668  */
669 bool
670 PreCommit_Portals(bool isPrepare)
671 {
672  bool result = false;
674  PortalHashEnt *hentry;
675 
676  hash_seq_init(&status, PortalHashTable);
677 
678  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
679  {
680  Portal portal = hentry->portal;
681 
682  /*
683  * There should be no pinned portals anymore. Complain if someone
684  * leaked one. Auto-held portals are allowed; we assume that whoever
685  * pinned them is managing them.
686  */
687  if (portal->portalPinned && !portal->autoHeld)
688  elog(ERROR, "cannot commit while a portal is pinned");
689 
690  /*
691  * Do not touch active portals --- this can only happen in the case of
692  * a multi-transaction utility command, such as VACUUM.
693  *
694  * Note however that any resource owner attached to such a portal is
695  * still going to go away, so don't leave a dangling pointer.
696  */
697  if (portal->status == PORTAL_ACTIVE)
698  {
699  portal->resowner = NULL;
700  continue;
701  }
702 
703  /* Is it a holdable portal created in the current xact? */
704  if ((portal->cursorOptions & CURSOR_OPT_HOLD) &&
706  portal->status == PORTAL_READY)
707  {
708  /*
709  * We are exiting the transaction that created a holdable cursor.
710  * Instead of dropping the portal, prepare it for access by later
711  * transactions.
712  *
713  * However, if this is PREPARE TRANSACTION rather than COMMIT,
714  * refuse PREPARE, because the semantics seem pretty unclear.
715  */
716  if (isPrepare)
717  ereport(ERROR,
718  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
719  errmsg("cannot PREPARE a transaction that has created a cursor WITH HOLD")));
720 
721  HoldPortal(portal);
722 
723  /* Report we changed state */
724  result = true;
725  }
726  else if (portal->createSubid == InvalidSubTransactionId)
727  {
728  /*
729  * Do nothing to cursors held over from a previous transaction
730  * (including ones we just froze in a previous cycle of this loop)
731  */
732  continue;
733  }
734  else
735  {
736  /* Zap all non-holdable portals */
737  PortalDrop(portal, true);
738 
739  /* Report we changed state */
740  result = true;
741  }
742 
743  /*
744  * After either freezing or dropping a portal, we have to restart the
745  * iteration, because we could have invoked user-defined code that
746  * caused a drop of the next portal in the hash chain.
747  */
748  hash_seq_term(&status);
749  hash_seq_init(&status, PortalHashTable);
750  }
751 
752  return result;
753 }
754 
755 /*
756  * Abort processing for portals.
757  *
758  * At this point we run the cleanup hook if present, but we can't release the
759  * portal's memory until the cleanup call.
760  */
761 void
763 {
765  PortalHashEnt *hentry;
766 
767  hash_seq_init(&status, PortalHashTable);
768 
769  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
770  {
771  Portal portal = hentry->portal;
772 
773  /*
774  * When elog(FATAL) is progress, we need to set the active portal to
775  * failed, so that PortalCleanup() doesn't run the executor shutdown.
776  */
777  if (portal->status == PORTAL_ACTIVE && shmem_exit_inprogress)
778  MarkPortalFailed(portal);
779 
780  /*
781  * Do nothing else to cursors held over from a previous transaction.
782  */
783  if (portal->createSubid == InvalidSubTransactionId)
784  continue;
785 
786  /*
787  * Do nothing to auto-held cursors. This is similar to the case of a
788  * cursor from a previous transaction, but it could also be that the
789  * cursor was auto-held in this transaction, so it wants to live on.
790  */
791  if (portal->autoHeld)
792  continue;
793 
794  /*
795  * If it was created in the current transaction, we can't do normal
796  * shutdown on a READY portal either; it might refer to objects
797  * created in the failed transaction. See comments in
798  * AtSubAbort_Portals.
799  */
800  if (portal->status == PORTAL_READY)
801  MarkPortalFailed(portal);
802 
803  /*
804  * Allow portalcmds.c to clean up the state it knows about, if we
805  * haven't already.
806  */
807  if (PointerIsValid(portal->cleanup))
808  {
809  portal->cleanup(portal);
810  portal->cleanup = NULL;
811  }
812 
813  /* drop cached plan reference, if any */
814  PortalReleaseCachedPlan(portal);
815 
816  /*
817  * Any resources belonging to the portal will be released in the
818  * upcoming transaction-wide cleanup; they will be gone before we run
819  * PortalDrop.
820  */
821  portal->resowner = NULL;
822 
823  /*
824  * Although we can't delete the portal data structure proper, we can
825  * release any memory in subsidiary contexts, such as executor state.
826  * The cleanup hook was the last thing that might have needed data
827  * there. But leave active portals alone.
828  */
829  if (portal->status != PORTAL_ACTIVE)
831  }
832 }
833 
834 /*
835  * Post-abort cleanup for portals.
836  *
837  * Delete all portals not held over from prior transactions. */
838 void
840 {
842  PortalHashEnt *hentry;
843 
844  hash_seq_init(&status, PortalHashTable);
845 
846  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
847  {
848  Portal portal = hentry->portal;
849 
850  /*
851  * Do not touch active portals --- this can only happen in the case of
852  * a multi-transaction command.
853  */
854  if (portal->status == PORTAL_ACTIVE)
855  continue;
856 
857  /*
858  * Do nothing to cursors held over from a previous transaction or
859  * auto-held ones.
860  */
861  if (portal->createSubid == InvalidSubTransactionId || portal->autoHeld)
862  {
863  Assert(portal->status != PORTAL_ACTIVE);
864  Assert(portal->resowner == NULL);
865  continue;
866  }
867 
868  /*
869  * If a portal is still pinned, forcibly unpin it. PortalDrop will not
870  * let us drop the portal otherwise. Whoever pinned the portal was
871  * interrupted by the abort too and won't try to use it anymore.
872  */
873  if (portal->portalPinned)
874  portal->portalPinned = false;
875 
876  /*
877  * We had better not call any user-defined code during cleanup, so if
878  * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
879  */
880  if (PointerIsValid(portal->cleanup))
881  {
882  elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
883  portal->cleanup = NULL;
884  }
885 
886  /* Zap it. */
887  PortalDrop(portal, false);
888  }
889 }
890 
891 /*
892  * Portal-related cleanup when we return to the main loop on error.
893  *
894  * This is different from the cleanup at transaction abort. Auto-held portals
895  * are cleaned up on error but not on transaction abort.
896  */
897 void
899 {
901  PortalHashEnt *hentry;
902 
903  hash_seq_init(&status, PortalHashTable);
904 
905  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
906  {
907  Portal portal = hentry->portal;
908 
909  if (portal->autoHeld)
910  {
911  portal->portalPinned = false;
912  PortalDrop(portal, false);
913  }
914  }
915 }
916 
917 /*
918  * Pre-subcommit processing for portals.
919  *
920  * Reassign portals created or used in the current subtransaction to the
921  * parent subtransaction.
922  */
923 void
925  SubTransactionId parentSubid,
926  ResourceOwner parentXactOwner)
927 {
929  PortalHashEnt *hentry;
930 
931  hash_seq_init(&status, PortalHashTable);
932 
933  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
934  {
935  Portal portal = hentry->portal;
936 
937  if (portal->createSubid == mySubid)
938  {
939  portal->createSubid = parentSubid;
940  if (portal->resowner)
941  ResourceOwnerNewParent(portal->resowner, parentXactOwner);
942  }
943  if (portal->activeSubid == mySubid)
944  portal->activeSubid = parentSubid;
945  }
946 }
947 
948 /*
949  * Subtransaction abort handling for portals.
950  *
951  * Deactivate portals created or used during the failed subtransaction.
952  * Note that per AtSubCommit_Portals, this will catch portals created/used
953  * in descendants of the subtransaction too.
954  *
955  * We don't destroy any portals here; that's done in AtSubCleanup_Portals.
956  */
957 void
959  SubTransactionId parentSubid,
960  ResourceOwner myXactOwner,
961  ResourceOwner parentXactOwner)
962 {
964  PortalHashEnt *hentry;
965 
966  hash_seq_init(&status, PortalHashTable);
967 
968  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
969  {
970  Portal portal = hentry->portal;
971 
972  /* Was it created in this subtransaction? */
973  if (portal->createSubid != mySubid)
974  {
975  /* No, but maybe it was used in this subtransaction? */
976  if (portal->activeSubid == mySubid)
977  {
978  /* Maintain activeSubid until the portal is removed */
979  portal->activeSubid = parentSubid;
980 
981  /*
982  * A MarkPortalActive() caller ran an upper-level portal in
983  * this subtransaction and left the portal ACTIVE. This can't
984  * happen, but force the portal into FAILED state for the same
985  * reasons discussed below.
986  *
987  * We assume we can get away without forcing upper-level READY
988  * portals to fail, even if they were run and then suspended.
989  * In theory a suspended upper-level portal could have
990  * acquired some references to objects that are about to be
991  * destroyed, but there should be sufficient defenses against
992  * such cases: the portal's original query cannot contain such
993  * references, and any references within, say, cached plans of
994  * PL/pgSQL functions are not from active queries and should
995  * be protected by revalidation logic.
996  */
997  if (portal->status == PORTAL_ACTIVE)
998  MarkPortalFailed(portal);
999 
1000  /*
1001  * Also, if we failed it during the current subtransaction
1002  * (either just above, or earlier), reattach its resource
1003  * owner to the current subtransaction's resource owner, so
1004  * that any resources it still holds will be released while
1005  * cleaning up this subtransaction. This prevents some corner
1006  * cases wherein we might get Asserts or worse while cleaning
1007  * up objects created during the current subtransaction
1008  * (because they're still referenced within this portal).
1009  */
1010  if (portal->status == PORTAL_FAILED && portal->resowner)
1011  {
1012  ResourceOwnerNewParent(portal->resowner, myXactOwner);
1013  portal->resowner = NULL;
1014  }
1015  }
1016  /* Done if it wasn't created in this subtransaction */
1017  continue;
1018  }
1019 
1020  /*
1021  * Force any live portals of my own subtransaction into FAILED state.
1022  * We have to do this because they might refer to objects created or
1023  * changed in the failed subtransaction, leading to crashes within
1024  * ExecutorEnd when portalcmds.c tries to close down the portal.
1025  * Currently, every MarkPortalActive() caller ensures it updates the
1026  * portal status again before relinquishing control, so ACTIVE can't
1027  * happen here. If it does happen, dispose the portal like existing
1028  * MarkPortalActive() callers would.
1029  */
1030  if (portal->status == PORTAL_READY ||
1031  portal->status == PORTAL_ACTIVE)
1032  MarkPortalFailed(portal);
1033 
1034  /*
1035  * Allow portalcmds.c to clean up the state it knows about, if we
1036  * haven't already.
1037  */
1038  if (PointerIsValid(portal->cleanup))
1039  {
1040  portal->cleanup(portal);
1041  portal->cleanup = NULL;
1042  }
1043 
1044  /* drop cached plan reference, if any */
1045  PortalReleaseCachedPlan(portal);
1046 
1047  /*
1048  * Any resources belonging to the portal will be released in the
1049  * upcoming transaction-wide cleanup; they will be gone before we run
1050  * PortalDrop.
1051  */
1052  portal->resowner = NULL;
1053 
1054  /*
1055  * Although we can't delete the portal data structure proper, we can
1056  * release any memory in subsidiary contexts, such as executor state.
1057  * The cleanup hook was the last thing that might have needed data
1058  * there.
1059  */
1061  }
1062 }
1063 
1064 /*
1065  * Post-subabort cleanup for portals.
1066  *
1067  * Drop all portals created in the failed subtransaction (but note that
1068  * we will not drop any that were reassigned to the parent above).
1069  */
1070 void
1072 {
1074  PortalHashEnt *hentry;
1075 
1076  hash_seq_init(&status, PortalHashTable);
1077 
1078  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1079  {
1080  Portal portal = hentry->portal;
1081 
1082  if (portal->createSubid != mySubid)
1083  continue;
1084 
1085  /*
1086  * If a portal is still pinned, forcibly unpin it. PortalDrop will not
1087  * let us drop the portal otherwise. Whoever pinned the portal was
1088  * interrupted by the abort too and won't try to use it anymore.
1089  */
1090  if (portal->portalPinned)
1091  portal->portalPinned = false;
1092 
1093  /*
1094  * We had better not call any user-defined code during cleanup, so if
1095  * the cleanup hook hasn't been run yet, too bad; we'll just skip it.
1096  */
1097  if (PointerIsValid(portal->cleanup))
1098  {
1099  elog(WARNING, "skipping cleanup for portal \"%s\"", portal->name);
1100  portal->cleanup = NULL;
1101  }
1102 
1103  /* Zap it. */
1104  PortalDrop(portal, false);
1105  }
1106 }
1107 
1108 /* Find all available cursors */
1109 Datum
1111 {
1112  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1113  TupleDesc tupdesc;
1114  Tuplestorestate *tupstore;
1115  MemoryContext per_query_ctx;
1116  MemoryContext oldcontext;
1117  HASH_SEQ_STATUS hash_seq;
1118  PortalHashEnt *hentry;
1119 
1120  /* check to see if caller supports us returning a tuplestore */
1121  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1122  ereport(ERROR,
1123  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1124  errmsg("set-valued function called in context that cannot accept a set")));
1125  if (!(rsinfo->allowedModes & SFRM_Materialize))
1126  ereport(ERROR,
1127  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1128  errmsg("materialize mode required, but it is not " \
1129  "allowed in this context")));
1130 
1131  /* need to build tuplestore in query context */
1132  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1133  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1134 
1135  /*
1136  * build tupdesc for result tuples. This must match the definition of the
1137  * pg_cursors view in system_views.sql
1138  */
1139  tupdesc = CreateTemplateTupleDesc(6, false);
1140  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
1141  TEXTOID, -1, 0);
1142  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
1143  TEXTOID, -1, 0);
1144  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_holdable",
1145  BOOLOID, -1, 0);
1146  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_binary",
1147  BOOLOID, -1, 0);
1148  TupleDescInitEntry(tupdesc, (AttrNumber) 5, "is_scrollable",
1149  BOOLOID, -1, 0);
1150  TupleDescInitEntry(tupdesc, (AttrNumber) 6, "creation_time",
1151  TIMESTAMPTZOID, -1, 0);
1152 
1153  /*
1154  * We put all the tuples into a tuplestore in one scan of the hashtable.
1155  * This avoids any issue of the hashtable possibly changing between calls.
1156  */
1157  tupstore =
1159  false, work_mem);
1160 
1161  /* generate junk in short-term context */
1162  MemoryContextSwitchTo(oldcontext);
1163 
1164  hash_seq_init(&hash_seq, PortalHashTable);
1165  while ((hentry = hash_seq_search(&hash_seq)) != NULL)
1166  {
1167  Portal portal = hentry->portal;
1168  Datum values[6];
1169  bool nulls[6];
1170 
1171  /* report only "visible" entries */
1172  if (!portal->visible)
1173  continue;
1174 
1175  MemSet(nulls, 0, sizeof(nulls));
1176 
1177  values[0] = CStringGetTextDatum(portal->name);
1178  values[1] = CStringGetTextDatum(portal->sourceText);
1179  values[2] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_HOLD);
1180  values[3] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_BINARY);
1181  values[4] = BoolGetDatum(portal->cursorOptions & CURSOR_OPT_SCROLL);
1182  values[5] = TimestampTzGetDatum(portal->creation_time);
1183 
1184  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1185  }
1186 
1187  /* clean up and return the tuplestore */
1188  tuplestore_donestoring(tupstore);
1189 
1190  rsinfo->returnMode = SFRM_Materialize;
1191  rsinfo->setResult = tupstore;
1192  rsinfo->setDesc = tupdesc;
1193 
1194  return (Datum) 0;
1195 }
1196 
1197 bool
1199 {
1201  PortalHashEnt *hentry;
1202 
1203  hash_seq_init(&status, PortalHashTable);
1204 
1205  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1206  {
1207  Portal portal = hentry->portal;
1208 
1209  if (portal->status == PORTAL_READY)
1210  return false;
1211  }
1212 
1213  return true;
1214 }
1215 
1216 /*
1217  * Hold all pinned portals.
1218  *
1219  * A procedural language implementation that uses pinned portals for its
1220  * internally generated cursors can call this in its COMMIT command to convert
1221  * those cursors to held cursors, so that they survive the transaction end.
1222  * We mark those portals as "auto-held" so that exception exit knows to clean
1223  * them up. (In normal, non-exception code paths, the PL needs to clean those
1224  * portals itself, since transaction end won't do it anymore, but that should
1225  * be normal practice anyway.)
1226  */
1227 void
1229 {
1231  PortalHashEnt *hentry;
1232 
1233  hash_seq_init(&status, PortalHashTable);
1234 
1235  while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
1236  {
1237  Portal portal = hentry->portal;
1238 
1239  if (portal->portalPinned && !portal->autoHeld)
1240  {
1241  /*
1242  * Doing transaction control, especially abort, inside a cursor
1243  * loop that is not read-only, for example using UPDATE ...
1244  * RETURNING, has weird semantics issues. Also, this
1245  * implementation wouldn't work, because such portals cannot be
1246  * held. (The core grammar enforces that only SELECT statements
1247  * can drive a cursor, but for example PL/pgSQL does not restrict
1248  * it.)
1249  */
1250  if (portal->strategy != PORTAL_ONE_SELECT)
1251  ereport(ERROR,
1252  (errcode(ERRCODE_INVALID_TRANSACTION_TERMINATION),
1253  errmsg("cannot perform transaction commands inside a cursor loop that is not read-only")));
1254 
1255  portal->autoHeld = true;
1256  HoldPortal(portal);
1257  }
1258  }
1259 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
void UnpinPortal(Portal portal)
Definition: portalmem.c:377
#define NIL
Definition: pg_list.h:69
Portal CreatePortal(const char *name, bool allowDup, bool dupSilent)
Definition: portalmem.c:175
#define IsA(nodeptr, _type_)
Definition: nodes.h:567
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static void PortalReleaseCachedPlan(Portal portal)
Definition: portalmem.c:307
#define AssertState(condition)
Definition: c.h:702
Portal CreateNewPortal(void)
Definition: portalmem.c:234
bool atEnd
Definition: portal.h:189
#define HASH_ELEM
Definition: hsearch.h:87
bool visible
Definition: portal.h:194
bool autoHeld
Definition: portal.h:150
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, const char *commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:281
void(* cleanup)(Portal portal)
Definition: portal.h:121
#define PORTALS_PER_USER
Definition: portalmem.c:38
Portal GetPortalByName(const char *name)
Definition: portalmem.c:130
#define CURSOR_OPT_BINARY
Definition: parsenodes.h:2644
ResourceOwner CurTransactionResourceOwner
Definition: resowner.c:141
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
void MarkPortalActive(Portal portal)
Definition: portalmem.c:392
#define CURSOR_OPT_HOLD
Definition: parsenodes.h:2648
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
void ResourceOwnerDelete(ResourceOwner owner)
Definition: resowner.c:684
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Size entrysize
Definition: hsearch.h:73
CachedPlan * cplan
Definition: portal.h:137
int errcode(int sqlerrcode)
Definition: elog.c:575
Datum pg_cursor(PG_FUNCTION_ARGS)
Definition: portalmem.c:1110
#define MemSet(start, val, len)
Definition: c.h:908
MemoryContext holdContext
Definition: portal.h:167
uint32 SubTransactionId
Definition: c.h:478
void PortalCleanup(Portal portal)
Definition: portalcmds.c:265
List * stmts
Definition: portal.h:136
MemoryContext portalContext
Definition: portal.h:119
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2646
void AtCleanup_Portals(void)
Definition: portalmem.c:839
void AtAbort_Portals(void)
Definition: portalmem.c:762
Definition: dynahash.c:208
#define PortalHashTableDelete(PORTAL)
Definition: portalmem.c:81
static MemoryContext TopPortalContext
Definition: portalmem.c:91
void pfree(void *pointer)
Definition: mcxt.c:1031
const char * name
Definition: portal.h:117
PlannedStmt * PortalGetPrimaryStmt(Portal portal)
Definition: portalmem.c:151
bool ThereAreNoReadyPortals(void)
Definition: portalmem.c:1198
#define ERROR
Definition: elog.h:43
#define TimestampTzGetDatum(X)
Definition: timestamp.h:32
const char * commandTag
Definition: portal.h:135
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
#define lfirst_node(type, lc)
Definition: pg_list.h:109
void MarkPortalDone(Portal portal)
Definition: portalmem.c:411
struct PortalData * Portal
Definition: portal.h:112
void PinPortal(Portal portal)
Definition: portalmem.c:368
bool portalPinned
Definition: portal.h:149
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1258
void PortalErrorCleanup(void)
Definition: portalmem.c:898
PortalStrategy strategy
Definition: portal.h:143
void AtSubCleanup_Portals(SubTransactionId mySubid)
Definition: portalmem.c:1071
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:600
SubTransactionId createSubid
Definition: portal.h:130
#define ereport(elevel, rest)
Definition: elog.h:122
#define AssertArg(condition)
Definition: c.h:701
MemoryContext TopMemoryContext
Definition: mcxt.c:44
Portal portal
Definition: portalmem.c:51
TimestampTz creation_time
Definition: portal.h:193
char portalname[MAX_PORTALNAME_LEN]
Definition: portalmem.c:50
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
#define WARNING
Definition: elog.h:40
void MemoryContextDeleteChildren(MemoryContext context)
Definition: mcxt.c:256
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
#define PortalIsValid(p)
Definition: portal.h:201
bool canSetTag
Definition: plannodes.h:54
uintptr_t Datum
Definition: postgres.h:367
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
SubTransactionId activeSubid
Definition: portal.h:131
Size keysize
Definition: hsearch.h:72
int work_mem
Definition: globals.c:120
const char * sourceText
Definition: portal.h:134
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:814
void EnablePortalManager(void)
Definition: portalmem.c:104
#define BoolGetDatum(X)
Definition: postgres.h:387
int allowedModes
Definition: execnodes.h:297
void PortalHashTableDeleteAll(void)
Definition: portalmem.c:601
SetFunctionReturnMode returnMode
Definition: execnodes.h:299
struct portalhashent PortalHashEnt
#define Assert(condition)
Definition: c.h:699
void ResourceOwnerRelease(ResourceOwner owner, ResourceReleasePhase phase, bool isCommit, bool isTopLevel)
Definition: resowner.c:474
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:641
static void HoldPortal(Portal portal)
Definition: portalmem.c:630
void AtSubAbort_Portals(SubTransactionId mySubid, SubTransactionId parentSubid, ResourceOwner myXactOwner, ResourceOwner parentXactOwner)
Definition: portalmem.c:958
void UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
Definition: snapmgr.c:918
void tuplestore_end(Tuplestorestate *state)
Definition: tuplestore.c:453
Snapshot holdSnapshot
Definition: portal.h:177
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
Definition: mcxt.c:329
void PersistHoldablePortal(Portal portal)
Definition: portalcmds.c:318
void MarkPortalFailed(Portal portal)
Definition: portalmem.c:439
PortalStatus status
Definition: portal.h:148
#define InvalidSubTransactionId
Definition: c.h:480
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:225
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:45
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
void PortalCreateHoldStore(Portal portal)
Definition: portalmem.c:328
const char * name
Definition: encode.c:521
bool PreCommit_Portals(bool isPrepare)
Definition: portalmem.c:670
Tuplestorestate * setResult
Definition: execnodes.h:302
void ResourceOwnerNewParent(ResourceOwner owner, ResourceOwner newparent)
Definition: resowner.c:744
static Datum values[MAXATTR]
Definition: bootstrap.c:164
ResourceOwner resowner
Definition: portal.h:120
ExprContext * econtext
Definition: execnodes.h:295
bool atStart
Definition: portal.h:188
#define MAX_PORTALNAME_LEN
Definition: portalmem.c:46
TupleDesc setDesc
Definition: execnodes.h:303
bool shmem_exit_inprogress
Definition: ipc.c:45
Tuplestorestate * holdStore
Definition: portal.h:166
int errmsg(const char *fmt,...)
Definition: elog.c:797
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:465
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2645
#define CStringGetTextDatum(s)
Definition: builtins.h:95
void HoldPinnedPortals(void)
Definition: portalmem.c:1228
static HTAB * PortalHashTable
Definition: portalmem.c:54
#define PG_FUNCTION_ARGS
Definition: fmgr.h:163
#define elog
Definition: elog.h:219
int cursorOptions
Definition: portal.h:144
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225
#define PortalHashTableLookup(NAME, PORTAL)
Definition: portalmem.c:56
#define PortalHashTableInsert(PORTAL, NAME)
Definition: portalmem.c:68
Definition: pg_list.h:45
#define PointerIsValid(pointer)
Definition: c.h:593
int16 AttrNumber
Definition: attnum.h:21
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1465
void AtSubCommit_Portals(SubTransactionId mySubid, SubTransactionId parentSubid, ResourceOwner parentXactOwner)
Definition: portalmem.c:924
const char * prepStmtName
Definition: portal.h:118
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:709
ResourceOwner ResourceOwnerCreate(ResourceOwner parent, const char *name)
Definition: resowner.c:418