]> granicus.if.org Git - postgresql/blobdiff - src/include/utils/portal.h
Fix oversight in initial implementation of PORTAL_ONE_RETURNING mode: we
[postgresql] / src / include / utils / portal.h
index 390ee2116d5cedd2ad3541113f09ff479359ccd6..92cc55189ed67a556e4745e5386f12d61b7c4975 100644 (file)
  * portal.h
  *       POSTGRES portal definitions.
  *
+ * A portal is an abstraction which represents the execution state of
+ * a running or runnable query.  Portals support both SQL-level CURSORs
+ * and protocol-level portals.
  *
- * Copyright (c) 1994, Regents of the University of California
+ * Scrolling (nonsequential access) and suspension of execution are allowed
+ * only for portals that contain a single SELECT-type query.  We do not want
+ * to let the client suspend an update-type query partway through!     Because
+ * the query rewriter does not allow arbitrary ON SELECT rewrite rules,
+ * only queries that were originally update-type could produce multiple
+ * parse/plan trees; so the restriction to a single query is not a problem
+ * in practice.
  *
- * $Id: portal.h,v 1.14 1999/06/12 14:05:40 momjian Exp $
+ * For SQL cursors, we support three kinds of scroll behavior:
+ *
+ * (1) Neither NO SCROLL nor SCROLL was specified: to remain backward
+ *        compatible, we allow backward fetches here, unless it would
+ *        impose additional runtime overhead to do so.
+ *
+ * (2) NO SCROLL was specified: don't allow any backward fetches.
+ *
+ * (3) SCROLL was specified: allow all kinds of backward fetches, even
+ *        if we need to take a performance hit to do so.  (The planner sticks
+ *        a Materialize node atop the query plan if needed.)
+ *
+ * Case #1 is converted to #2 or #3 by looking at the query itself and
+ * determining if scrollability can be supported without additional
+ * overhead.
+ *
+ * Protocol-level portals have no nonsequential-fetch API and so the
+ * distinction doesn't matter for them.  They are always initialized
+ * to look like NO SCROLL cursors.
+ *
+ *
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.66 2006/08/14 22:57:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-/*
- * Note:
- *             A portal is an abstraction which represents the execution state of
- * a running query (or a fixed sequence of queries).  The "blank portal" is
- * a portal with an InvalidName.  This blank portal is in existance except
- * between calls to BlankPortalAssignName and GetPortalByName(NULL).
- *
- * Note:
- *             now that PQ calls can be made from within a backend, a portal
- *             may also be used to keep track of the tuples resulting
- *             from the execution of a query.  In this case, entryIndex
- */
 #ifndef PORTAL_H
 #define PORTAL_H
 
-#include <executor/execdesc.h>
-#include <lib/fstack.h>
-#include <nodes/memnodes.h>
-#include <utils/memutils.h>
+#include "executor/execdesc.h"
+#include "utils/resowner.h"
+#include "utils/timestamp.h"
 
-typedef struct PortalBlockData
+/*
+ * We have several execution strategies for Portals, depending on what
+ * query or queries are to be executed.  (Note: in all cases, a Portal
+ * executes just a single source-SQL query, and thus produces just a
+ * single result from the user's viewpoint.  However, the rule rewriter
+ * may expand the single source query to zero or many actual queries.)
+ *
+ * PORTAL_ONE_SELECT: the portal contains one single SELECT query.     We run
+ * the Executor incrementally as results are demanded. This strategy also
+ * supports holdable cursors (the Executor results can be dumped into a
+ * tuplestore for access after transaction completion).
+ *
+ * PORTAL_ONE_RETURNING: the portal contains a single INSERT/UPDATE/DELETE
+ * query with a RETURNING clause (plus possibly auxiliary queries added by
+ * rule rewriting).  On first execution, we run the portal to completion
+ * and dump the primary query's results into the portal tuplestore; the
+ * results are then returned to the client as demanded.  (We can't support
+ * suspension of the query partway through, because the AFTER TRIGGER code
+ * can't cope, and also because we don't want to risk failing to execute
+ * all the auxiliary queries.)
+ *
+ * PORTAL_UTIL_SELECT: the portal contains a utility statement that returns
+ * a SELECT-like result (for example, EXPLAIN or SHOW).  On first execution,
+ * we run the statement and dump its results into the portal tuplestore;
+ * the results are then returned to the client as demanded.
+ *
+ * PORTAL_MULTI_QUERY: all other cases.  Here, we do not support partial
+ * execution: the portal's queries will be run to completion on first call.
+ */
+typedef enum PortalStrategy
 {
-       AllocSetData setData;
-       FixedItemData itemData;
-} PortalBlockData;
+       PORTAL_ONE_SELECT,
+       PORTAL_ONE_RETURNING,
+       PORTAL_UTIL_SELECT,
+       PORTAL_MULTI_QUERY
+} PortalStrategy;
 
-typedef PortalBlockData *PortalBlock;
+/*
+ * A portal is always in one of these states.  It is possible to transit
+ * from ACTIVE back to READY if the query is not run to completion;
+ * otherwise we never back up in status.
+ */
+typedef enum PortalStatus
+{
+       PORTAL_NEW,                                     /* in process of creation */
+       PORTAL_READY,                           /* PortalStart complete, can run it */
+       PORTAL_ACTIVE,                          /* portal is running (can't delete it) */
+       PORTAL_DONE,                            /* portal is finished (don't re-run it) */
+       PORTAL_FAILED                           /* portal got error (can't re-run it) */
+} PortalStatus;
 
-typedef struct PortalD PortalD;
-typedef PortalD *Portal;
+/*
+ * Note: typedef Portal is declared in tcop/dest.h as
+ *             typedef struct PortalData *Portal;
+ */
 
-struct PortalD
+typedef struct PortalData
 {
-       char       *name;                       /* XXX PortalName */
-       struct PortalVariableMemoryData variable;
-       struct PortalHeapMemoryData heap;
-       QueryDesc  *queryDesc;
-       TupleDesc       attinfo;
-       EState     *state;
-       void            (*cleanup) (Portal);
-};
+       /* Bookkeeping data */
+       const char *name;                       /* portal's name */
+       const char *prepStmtName;       /* protocol prepare name */
+       MemoryContext heap;                     /* subsidiary memory for portal */
+       ResourceOwner resowner;         /* resources owned by portal */
+       void            (*cleanup) (Portal portal);             /* cleanup hook */
+       SubTransactionId createSubid;           /* the ID of the creating subxact */
+
+       /*
+        * if createSubid is InvalidSubTransactionId, the portal is held over from
+        * a previous transaction
+        */
+
+       /* The query or queries the portal will execute */
+       const char *sourceText;         /* text of query, if known (may be NULL) */
+       const char *commandTag;         /* command tag for original query */
+       List       *parseTrees;         /* parse tree(s) */
+       List       *planTrees;          /* plan tree(s) */
+       MemoryContext queryContext; /* where the above trees live */
+
+       /*
+        * Note: queryContext effectively identifies which prepared statement the
+        * portal depends on, if any.  The queryContext is *not* owned by the
+        * portal and is not to be deleted by portal destruction.  (But for a
+        * cursor it is the same as "heap", and that context is deleted by portal
+        * destruction.)
+        */
+       ParamListInfo portalParams; /* params to pass to query */
+
+       /* Features/options */
+       PortalStrategy strategy;        /* see above */
+       int                     cursorOptions;  /* DECLARE CURSOR option bits */
+
+       /* Status data */
+       PortalStatus status;            /* see above */
+
+       /* If not NULL, Executor is active; call ExecutorEnd eventually: */
+       QueryDesc  *queryDesc;          /* info needed for executor invocation */
+
+       /* If portal returns tuples, this is their tupdesc: */
+       TupleDesc       tupDesc;                /* descriptor for result tuples */
+       /* and these are the format codes to use for the columns: */
+       int16      *formats;            /* a format code for each column */
+
+       /*
+        * Where we store tuples for a held cursor or a PORTAL_ONE_RETURNING or
+        * PORTAL_UTIL_SELECT query.  (A cursor held past the end of its
+        * transaction no longer has any active executor state.)
+        */
+       Tuplestorestate *holdStore; /* store for holdable cursors */
+       MemoryContext holdContext;      /* memory containing holdStore */
+
+       /*
+        * atStart, atEnd and portalPos indicate the current cursor position.
+        * portalPos is zero before the first row, N after fetching N'th row of
+        * query.  After we run off the end, portalPos = # of rows in query, and
+        * atEnd is true.  If portalPos overflows, set posOverflow (this causes us
+        * to stop relying on its value for navigation).  Note that atStart
+        * implies portalPos == 0, but not the reverse (portalPos could have
+        * overflowed).
+        */
+       bool            atStart;
+       bool            atEnd;
+       bool            posOverflow;
+       long            portalPos;
+
+       /* Presentation data, primarily used by the pg_cursors system view */
+       TimestampTz     creation_time;  /* time at which this portal was defined */
+       bool            visible;                /* include this portal in pg_cursors? */
+} PortalData;
 
 /*
  * PortalIsValid
@@ -59,35 +186,40 @@ struct PortalD
 #define PortalIsValid(p) PointerIsValid(p)
 
 /*
- * Special portals (well, their names anyway)
+ * Access macros for Portal ... use these in preference to field access.
  */
-#define VACPNAME               "<vacuum>"
-
-extern bool PortalNameIsSpecial(char *pname);
-extern void AtEOXact_portals(void);
-extern void EnablePortalManager(bool on);
-extern Portal GetPortalByName(char *name);
-extern Portal BlankPortalAssignName(char *name);
-extern void PortalSetQuery(Portal portal, QueryDesc *queryDesc,
-                          TupleDesc attinfo, EState *state,
-                          void (*cleanup) (Portal portal));
-extern QueryDesc *PortalGetQueryDesc(Portal portal);
-extern EState *PortalGetState(Portal portal);
-extern Portal CreatePortal(char *name);
-extern void PortalDestroy(Portal *portalP);
-extern void StartPortalAllocMode(AllocMode mode, Size limit);
-extern void EndPortalAllocMode(void);
-extern PortalVariableMemory PortalGetVariableMemory(Portal portal);
-extern PortalHeapMemory PortalGetHeapMemory(Portal portal);
-
-#ifdef FREE_TUPLE_MEMORY
-bool   PortalHeapMemoryIsValid(MemoryContext context, Pointer pointer);
-#endif
-
-/* estimate of the maximum number of open portals a user would have,
- * used in initially sizing the PortalHashTable in     EnablePortalManager()
- */
-#define PORTALS_PER_USER          10
+#define PortalGetQueryDesc(portal)     ((portal)->queryDesc)
+#define PortalGetHeapMemory(portal) ((portal)->heap)
+#define PortalGetPrimaryQuery(portal) PortalListGetPrimaryQuery((portal)->parseTrees)
+
 
+/* Prototypes for functions in utils/mmgr/portalmem.c */
+extern void EnablePortalManager(void);
+extern bool CommitHoldablePortals(void);
+extern bool PrepareHoldablePortals(void);
+extern void AtCommit_Portals(void);
+extern void AtAbort_Portals(void);
+extern void AtCleanup_Portals(void);
+extern void AtSubCommit_Portals(SubTransactionId mySubid,
+                                       SubTransactionId parentSubid,
+                                       ResourceOwner parentXactOwner);
+extern void AtSubAbort_Portals(SubTransactionId mySubid,
+                                  SubTransactionId parentSubid,
+                                  ResourceOwner parentXactOwner);
+extern void AtSubCleanup_Portals(SubTransactionId mySubid);
+extern Portal CreatePortal(const char *name, bool allowDup, bool dupSilent);
+extern Portal CreateNewPortal(void);
+extern void PortalDrop(Portal portal, bool isTopCommit);
+extern void DropDependentPortals(MemoryContext queryContext);
+extern Portal GetPortalByName(const char *name);
+extern void PortalDefineQuery(Portal portal,
+                                 const char *prepStmtName,
+                                 const char *sourceText,
+                                 const char *commandTag,
+                                 List *parseTrees,
+                                 List *planTrees,
+                                 MemoryContext queryContext);
+extern Query *PortalListGetPrimaryQuery(List *parseTrees);
+extern void PortalCreateHoldStore(Portal portal);
 
-#endif  /* PORTAL_H */
+#endif   /* PORTAL_H */