]> granicus.if.org Git - postgresql/commitdiff
Clean up BeginCommand and related routines. BeginCommand and EndCommand
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 27 Feb 2002 19:36:13 +0000 (19:36 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 27 Feb 2002 19:36:13 +0000 (19:36 +0000)
are now both invoked once per received SQL command (raw parsetree) from
pg_exec_query_string.  BeginCommand is actually just an empty routine
at the moment --- all its former operations have been pushed into tuple
receiver setup routines in printtup.c.  This makes for a clean distinction
between BeginCommand/EndCommand (once per command) and the tuple receiver
setup/teardown routines (once per ExecutorRun call), whereas the old code
was quite ad hoc.  Along the way, clean up the calling conventions for
ExecutorRun a little bit.

15 files changed:
src/backend/access/common/printtup.c
src/backend/access/common/tupdesc.c
src/backend/commands/command.c
src/backend/executor/execMain.c
src/backend/executor/functions.c
src/backend/executor/spi.c
src/backend/tcop/dest.c
src/backend/tcop/postgres.c
src/backend/tcop/pquery.c
src/backend/utils/mmgr/portalmem.c
src/include/access/printtup.h
src/include/executor/execdefs.h
src/include/executor/execdesc.h
src/include/executor/executor.h
src/include/tcop/dest.h

index ea10330bf87bbddf54b479d82e39629fc9537b2c..95e79b9569b01337cde315a863346d29878c17d4 100644 (file)
@@ -1,15 +1,15 @@
 /*-------------------------------------------------------------------------
  *
  * printtup.c
- *       Routines to print out tuples to the destination (binary or non-binary
- *       portals, frontend/interactive backend, etc.).
+ *       Routines to print out tuples to the destination (both frontend
+ *       clients and interactive backends are supported here).
+ *
  *
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.60 2001/10/25 05:49:20 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.61 2002/02/27 19:34:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "access/heapam.h"
 #include "access/printtup.h"
 #include "catalog/pg_type.h"
+#include "libpq/libpq.h"
 #include "libpq/pqformat.h"
 #include "utils/syscache.h"
 
-static void printtup_setup(DestReceiver *self, TupleDesc typeinfo);
+static void printtup_setup(DestReceiver *self, int operation,
+                                                  const char *portalName, TupleDesc typeinfo);
 static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
 static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
 static void printtup_cleanup(DestReceiver *self);
@@ -97,17 +99,56 @@ printtup_create_DR(bool isBinary)
 }
 
 static void
-printtup_setup(DestReceiver *self, TupleDesc typeinfo)
+printtup_setup(DestReceiver *self, int operation,
+                          const char *portalName, TupleDesc typeinfo)
 {
+       /*
+        * Send portal name to frontend.
+        *
+        * If portal name not specified, use "blank" portal.
+        */
+       if (portalName == NULL)
+               portalName = "blank";
+
+       pq_puttextmessage('P', portalName);
+
+       /*
+        * if this is a retrieve, then we send back the tuple
+        * descriptor of the tuples.
+        */
+       if (operation == CMD_SELECT)
+       {
+               Form_pg_attribute *attrs = typeinfo->attrs;
+               int                     natts = typeinfo->natts;
+               int                     i;
+               StringInfoData buf;
+
+               pq_beginmessage(&buf);
+               pq_sendbyte(&buf, 'T'); /* tuple descriptor message type */
+               pq_sendint(&buf, natts, 2);     /* # of attrs in tuples */
+
+               for (i = 0; i < natts; ++i)
+               {
+                       pq_sendstring(&buf, NameStr(attrs[i]->attname));
+                       pq_sendint(&buf, (int) attrs[i]->atttypid,
+                                          sizeof(attrs[i]->atttypid));
+                       pq_sendint(&buf, attrs[i]->attlen,
+                                          sizeof(attrs[i]->attlen));
+                       if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
+                               pq_sendint(&buf, attrs[i]->atttypmod,
+                                                  sizeof(attrs[i]->atttypmod));
+               }
+               pq_endmessage(&buf);
+       }
+
        /* ----------------
         * We could set up the derived attr info at this time, but we postpone it
-        * until the first call of printtup, for 3 reasons:
+        * until the first call of printtup, for 2 reasons:
         * 1. We don't waste time (compared to the old way) if there are no
         *        tuples at all to output.
         * 2. Checking in printtup allows us to handle the case that the tuples
         *        change type midway through (although this probably can't happen in
         *        the current executor).
-        * 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-(
         * ----------------
         */
 }
@@ -267,12 +308,12 @@ printatt(unsigned attributeId,
  *             showatts
  * ----------------
  */
-void
-showatts(char *name, TupleDesc tupleDesc)
+static void
+showatts(const char *name, TupleDesc tupleDesc)
 {
-       int                     i;
        int                     natts = tupleDesc->natts;
        Form_pg_attribute *attinfo = tupleDesc->attrs;
+       int                     i;
 
        puts(name);
        for (i = 0; i < natts; ++i)
@@ -281,7 +322,24 @@ showatts(char *name, TupleDesc tupleDesc)
 }
 
 /* ----------------
- *             debugtup
+ *             debugSetup - prepare to print tuples for an interactive backend
+ * ----------------
+ */
+void
+debugSetup(DestReceiver *self, int operation,
+                  const char *portalName, TupleDesc typeinfo)
+{
+       /*
+        * show the return type of the tuples
+        */
+       if (portalName == NULL)
+               portalName = "blank";
+
+       showatts(portalName, typeinfo);
+}
+
+/* ----------------
+ *             debugtup - print one tuple for an interactive backend
  * ----------------
  */
 void
index 4b9d53df34766dc162e49085cf726a3b5c38a20a..81f996b8a03f05f52d55e889bba646bad721e6ca 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.76 2001/10/25 05:49:20 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.77 2002/02/27 19:34:11 tgl Exp $
  *
  * NOTES
  *       some of the executor utility code such as "ExecTypeFromTL" should be
@@ -432,7 +432,7 @@ TupleDescInitEntry(TupleDesc desc,
         *
         * (Why not just make the atttypid point to the OID type, instead of the
         * type the query returns?      Because the executor uses the atttypid to
-        * tell the front end what type will be returned (in BeginCommand),
+        * tell the front end what type will be returned,
         * and in the end the type returned will be the result of the query,
         * not an OID.)
         *
index 676caba22d583e345c0d2d17fb2d7aba812623c0..64554aa2da6695d8174e34af4cefa04bddafd1ba 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.155 2002/02/26 22:47:04 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.156 2002/02/27 19:34:38 tgl Exp $
  *
  * NOTES
  *       The PerformAddAttribute() code, like most of the relation
@@ -113,6 +113,7 @@ PerformPortalFetch(char *name,
        QueryDesc  *queryDesc;
        EState     *estate;
        MemoryContext oldcontext;
+       ScanDirection direction;
        CommandId       savedId;
        bool            temp_desc = false;
 
@@ -145,6 +146,9 @@ PerformPortalFetch(char *name,
         */
        oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
+       queryDesc = PortalGetQueryDesc(portal);
+       estate = PortalGetState(portal);
+
        /*
         * If the requested destination is not the same as the query's
         * original destination, make a temporary QueryDesc with the proper
@@ -156,9 +160,6 @@ PerformPortalFetch(char *name,
         * original dest.  This is necessary since a FETCH command will pass
         * dest = Remote, not knowing whether the cursor is binary or not.
         */
-       queryDesc = PortalGetQueryDesc(portal);
-       estate = PortalGetState(portal);
-
        if (dest != queryDesc->dest &&
                !(queryDesc->dest == RemoteInternal && dest == Remote))
        {
@@ -170,19 +171,6 @@ PerformPortalFetch(char *name,
                temp_desc = true;
        }
 
-       /*
-        * Tell the destination to prepare to receive some tuples.
-        */
-       BeginCommand(name,
-                                queryDesc->operation,
-                                PortalGetTupleDesc(portal),
-                                false,                 /* portal fetches don't end up in
-                                                                * relations */
-                                false,                 /* this is a portal fetch, not a "retrieve
-                                                                * portal" */
-                                NULL,                  /* not used */
-                                queryDesc->dest);
-
        /*
         * Restore the scanCommandId that was current when the cursor was
         * opened.  This ensures that we see the same tuples throughout the
@@ -194,47 +182,49 @@ PerformPortalFetch(char *name,
        /*
         * Determine which direction to go in, and check to see if we're
         * already at the end of the available tuples in that direction.  If
-        * so, do nothing.      (This check exists because not all plan node types
+        * so, set the direction to NoMovement to avoid trying to fetch any
+        * tuples.  (This check exists because not all plan node types
         * are robust about being called again if they've already returned
-        * NULL once.)  If it's OK to do the fetch, call the executor.  Then,
-        * update the atStart/atEnd state depending on the number of tuples
-        * that were retrieved.
+        * NULL once.)  Then call the executor (we must not skip this, because
+        * the destination needs to see a setup and shutdown even if no tuples
+        * are available).  Finally, update the atStart/atEnd state depending
+        * on the number of tuples that were retrieved.
         */
        if (forward)
        {
-               if (!portal->atEnd)
-               {
-                       ExecutorRun(queryDesc, estate, EXEC_FOR, (long) count);
+               if (portal->atEnd)
+                       direction = NoMovementScanDirection;
+               else
+                       direction = ForwardScanDirection;
 
-                       if (estate->es_processed > 0)
-                               portal->atStart = false;                /* OK to back up now */
-                       if (count <= 0 || (int) estate->es_processed < count)
-                               portal->atEnd = true;   /* we retrieved 'em all */
+               ExecutorRun(queryDesc, estate, direction, (long) count);
 
-                       if (completionTag)
-                               snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
-                                                (dest == None) ? "MOVE" : "FETCH",
-                                                estate->es_processed);
-               }
+               if (estate->es_processed > 0)
+                       portal->atStart = false; /* OK to back up now */
+               if (count <= 0 || (int) estate->es_processed < count)
+                       portal->atEnd = true;   /* we retrieved 'em all */
        }
        else
        {
-               if (!portal->atStart)
-               {
-                       ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count);
+               if (portal->atStart)
+                       direction = NoMovementScanDirection;
+               else
+                       direction = BackwardScanDirection;
 
-                       if (estate->es_processed > 0)
-                               portal->atEnd = false;  /* OK to go forward now */
-                       if (count <= 0 || (int) estate->es_processed < count)
-                               portal->atStart = true; /* we retrieved 'em all */
+               ExecutorRun(queryDesc, estate, direction, (long) count);
 
-                       if (completionTag)
-                               snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
-                                                (dest == None) ? "MOVE" : "FETCH",
-                                                estate->es_processed);
-               }
+               if (estate->es_processed > 0)
+                       portal->atEnd = false;  /* OK to go forward now */
+               if (count <= 0 || (int) estate->es_processed < count)
+                       portal->atStart = true; /* we retrieved 'em all */
        }
 
+       /* Return command status if wanted */
+       if (completionTag)
+               snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
+                                (dest == None) ? "MOVE" : "FETCH",
+                                estate->es_processed);
+
        /*
         * Restore outer command ID.
         */
index 6e1145ac7792177aa305c3978f912f3ce5e9498b..18b81849ac9ffcad8ffe5527acb40365de585ee6 100644 (file)
@@ -19,7 +19,7 @@
  *     query plan and ExecutorEnd() should always be called at the end of
  *     execution of a plan.
  *
- *     ExecutorRun accepts 'feature' and 'count' arguments that specify whether
+ *     ExecutorRun accepts direction and count arguments that specify whether
  *     the plan is to be executed forwards, backwards, and for how many tuples.
  *
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
@@ -27,7 +27,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.149 2001/10/25 05:49:27 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.150 2002/02/27 19:34:48 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,7 +88,7 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);
  *             query plan
  *
  *             returns a TupleDesc which describes the attributes of the tuples to
- *             be returned by the query.
+ *             be returned by the query.  (Same value is saved in queryDesc)
  *
  * NB: the CurrentMemoryContext when this is called must be the context
  * to be used as the per-query context for the query plan.     ExecutorRun()
@@ -137,6 +137,8 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
                                          queryDesc->plantree,
                                          estate);
 
+       queryDesc->tupDesc = result;
+
        return result;
 }
 
@@ -149,25 +151,23 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
  *
  *             ExecutorStart must have been called already.
  *
- *             the different features supported are:
- *                      EXEC_RUN:      retrieve all tuples in the forward direction
- *                      EXEC_FOR:      retrieve 'count' number of tuples in the forward dir
- *                      EXEC_BACK: retrieve 'count' number of tuples in the backward dir
- *                      EXEC_RETONE: return one tuple but don't 'retrieve' it
- *                                                used in postquel function processing
+ *             If direction is NoMovementScanDirection then nothing is done
+ *             except to start up/shut down the destination.  Otherwise,
+ *             we retrieve up to 'count' tuples in the specified direction.
  *
  *             Note: count = 0 is interpreted as "no limit".
  *
  * ----------------------------------------------------------------
  */
 TupleTableSlot *
-ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count)
+ExecutorRun(QueryDesc *queryDesc, EState *estate,
+                       ScanDirection direction, long count)
 {
        CmdType         operation;
        Plan       *plan;
-       TupleTableSlot *result;
        CommandDest dest;
        DestReceiver *destfunc;
+       TupleTableSlot *result;
 
        /*
         * sanity checks
@@ -181,69 +181,33 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count)
        operation = queryDesc->operation;
        plan = queryDesc->plantree;
        dest = queryDesc->dest;
-       destfunc = DestToFunction(dest);
-       estate->es_processed = 0;
-       estate->es_lastoid = InvalidOid;
 
        /*
-        * FIXME: the dest setup function ought to be handed the tuple desc
-        * for the tuples to be output, but I'm not quite sure how to get that
-        * info at this point.  For now, passing NULL is OK because no
-        * existing dest setup function actually uses the pointer.
+        * startup tuple receiver
         */
-       (*destfunc->setup) (destfunc, (TupleDesc) NULL);
-
-       switch (feature)
-       {
-               case EXEC_RUN:
-                       result = ExecutePlan(estate,
-                                                                plan,
-                                                                operation,
-                                                                count,
-                                                                ForwardScanDirection,
-                                                                destfunc);
-                       break;
-
-               case EXEC_FOR:
-                       result = ExecutePlan(estate,
-                                                                plan,
-                                                                operation,
-                                                                count,
-                                                                ForwardScanDirection,
-                                                                destfunc);
-                       break;
-
-                       /*
-                        * retrieve next n "backward" tuples
-                        */
-               case EXEC_BACK:
-                       result = ExecutePlan(estate,
-                                                                plan,
-                                                                operation,
-                                                                count,
-                                                                BackwardScanDirection,
-                                                                destfunc);
-                       break;
+       estate->es_processed = 0;
+       estate->es_lastoid = InvalidOid;
 
-                       /*
-                        * return one tuple but don't "retrieve" it. (this is used by
-                        * the rule manager..) -cim 9/14/89
-                        */
-               case EXEC_RETONE:
-                       result = ExecutePlan(estate,
-                                                                plan,
-                                                                operation,
-                                                                ONE_TUPLE,
-                                                                ForwardScanDirection,
-                                                                destfunc);
-                       break;
+       destfunc = DestToFunction(dest);
+       (*destfunc->setup) (destfunc, (int) operation,
+                                               queryDesc->portalName, queryDesc->tupDesc);
 
-               default:
-                       elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
-                       result = NULL;
-                       break;
-       }
+       /*
+        * run plan
+        */
+       if (direction == NoMovementScanDirection)
+               result = NULL;
+       else
+               result = ExecutePlan(estate,
+                                                        plan,
+                                                        operation,
+                                                        count,
+                                                        direction,
+                                                        destfunc);
 
+       /*
+        * shutdown receiver
+        */
        (*destfunc->cleanup) (destfunc);
 
        return result;
@@ -916,7 +880,7 @@ EndPlan(Plan *plan, EState *estate)
  *
  *             processes the query plan to retrieve 'numberTuples' tuples in the
  *             direction specified.
- *             Retrieves all tuples if tupleCount is 0
+ *             Retrieves all tuples if numberTuples is 0
  *
  *             result is either a slot containing the last tuple in the case
  *             of a RETRIEVE or NULL otherwise.
index c38b8077f520ce2d83ba0b7f8d2c6c8507c2595b..885d93a2afffd29a0fe6deaed55de083a33a7750 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.48 2002/02/26 22:47:05 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.49 2002/02/27 19:34:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -111,9 +111,8 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
 
                nextes->next = NULL;
                nextes->status = F_EXEC_START;
-               nextes->qd = CreateQueryDesc(queryTree,
-                                                                        planTree,
-                                                                        None);
+
+               nextes->qd = CreateQueryDesc(queryTree, planTree, None, NULL);
                estate = CreateExecutorState();
 
                if (nargs > 0)
@@ -268,7 +267,7 @@ postquel_start(execution_state *es)
 static TupleTableSlot *
 postquel_getnext(execution_state *es)
 {
-       int                     feature;
+       long    count;
 
        if (es->qd->operation == CMD_UTILITY)
        {
@@ -281,9 +280,10 @@ postquel_getnext(execution_state *es)
                return (TupleTableSlot *) NULL;
        }
 
-       feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
+       /* If it's not the last command, just run it to completion */
+       count = (LAST_POSTQUEL_COMMAND(es)) ? 1L : 0L;
 
-       return ExecutorRun(es->qd, es->estate, feature, 0L);
+       return ExecutorRun(es->qd, es->estate, ForwardScanDirection, count);
 }
 
 static void
index 05044d6cd39a123c39ef7b777e3717c872acd44c..c8c65b1cee43039a9734c8cb07535312b454e65a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.66 2002/02/26 22:47:05 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.67 2002/02/27 19:34:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -779,7 +779,7 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls)
        queryTree->isBinary = false;
 
        /* Create the QueryDesc object and the executor state */
-       queryDesc = CreateQueryDesc(queryTree, planTree, SPI);
+       queryDesc = CreateQueryDesc(queryTree, planTree, SPI, NULL);
        eState = CreateExecutorState();
 
        /* If the plan has parameters, put them into the executor state */
@@ -1023,7 +1023,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
                else if (plan == NULL)
                {
                        qdesc = CreateQueryDesc(queryTree, planTree,
-                                                                       islastquery ? SPI : None);
+                                                                       islastquery ? SPI : None, NULL);
                        state = CreateExecutorState();
                        res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
                        if (res < 0 || islastquery)
@@ -1033,7 +1033,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan)
                else
                {
                        qdesc = CreateQueryDesc(queryTree, planTree,
-                                                                       islastquery ? SPI : None);
+                                                                       islastquery ? SPI : None, NULL);
                        res = _SPI_pquery(qdesc, NULL, islastquery ? tcount : 0);
                        if (res < 0)
                                return res;
@@ -1094,7 +1094,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount)
                else
                {
                        qdesc = CreateQueryDesc(queryTree, planTree,
-                                                                       islastquery ? SPI : None);
+                                                                       islastquery ? SPI : None, NULL);
                        state = CreateExecutorState();
                        if (nargs > 0)
                        {
@@ -1132,7 +1132,6 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
        Query      *parseTree = queryDesc->parsetree;
        int                     operation = queryDesc->operation;
        CommandDest dest = queryDesc->dest;
-       TupleDesc       tupdesc;
        bool            isRetrieveIntoPortal = false;
        bool            isRetrieveIntoRelation = false;
        char       *intoName = NULL;
@@ -1174,11 +1173,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
 
        if (state == NULL)                      /* plan preparation */
                return res;
+
 #ifdef SPI_EXECUTOR_STATS
        if (ShowExecutorStats)
                ResetUsage();
 #endif
-       tupdesc = ExecutorStart(queryDesc, state);
+
+       ExecutorStart(queryDesc, state);
 
        /*
         * Don't work currently --- need to rearrange callers so that we
@@ -1188,7 +1189,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
        if (isRetrieveIntoPortal)
                elog(FATAL, "SPI_select: retrieve into portal not implemented");
 
-       ExecutorRun(queryDesc, state, EXEC_FOR, (long) tcount);
+       ExecutorRun(queryDesc, state, ForwardScanDirection, (long) tcount);
 
        _SPI_current->processed = state->es_processed;
        save_lastoid = state->es_lastoid;
@@ -1230,6 +1231,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
        QueryDesc  *querydesc;
        EState     *estate;
        MemoryContext oldcontext;
+       ScanDirection direction;
        CommandId       savedId;
        CommandDest olddest;
 
@@ -1268,29 +1270,35 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
        /* Run the executor like PerformPortalFetch and remember states */
        if (forward)
        {
-               if (!portal->atEnd)
-               {
-                       ExecutorRun(querydesc, estate, EXEC_FOR, (long) count);
-                       _SPI_current->processed = estate->es_processed;
-                       if (estate->es_processed > 0)
-                               portal->atStart = false;
-                       if (count <= 0 || (int) estate->es_processed < count)
-                               portal->atEnd = true;
-               }
+               if (portal->atEnd)
+                       direction = NoMovementScanDirection;
+               else
+                       direction = ForwardScanDirection;
+
+               ExecutorRun(querydesc, estate, direction, (long) count);
+
+               if (estate->es_processed > 0)
+                       portal->atStart = false; /* OK to back up now */
+               if (count <= 0 || (int) estate->es_processed < count)
+                       portal->atEnd = true;   /* we retrieved 'em all */
        }
        else
        {
-               if (!portal->atStart)
-               {
-                       ExecutorRun(querydesc, estate, EXEC_BACK, (long) count);
-                       _SPI_current->processed = estate->es_processed;
-                       if (estate->es_processed > 0)
-                               portal->atEnd = false;
-                       if (count <= 0 || estate->es_processed < count)
-                               portal->atStart = true;
-               }
+               if (portal->atStart)
+                       direction = NoMovementScanDirection;
+               else
+                       direction = BackwardScanDirection;
+
+               ExecutorRun(querydesc, estate, direction, (long) count);
+
+               if (estate->es_processed > 0)
+                       portal->atEnd = false;  /* OK to go forward now */
+               if (count <= 0 || (int) estate->es_processed < count)
+                       portal->atStart = true; /* we retrieved 'em all */
        }
 
+       _SPI_current->processed = estate->es_processed;
+
        /*
         * Restore outer command ID.
         */
index f055bc3137b251a1ef46cf8ba30524e66238b382..d56f032a02e16c7f177682e744720627fb808631 100644 (file)
@@ -1,22 +1,22 @@
 /*-------------------------------------------------------------------------
  *
  * dest.c
- *       support for various communication destinations - see include/tcop/dest.h
+ *       support for communication destinations
+ *
  *
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.47 2002/02/26 22:47:08 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.48 2002/02/27 19:35:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  *      INTERFACE ROUTINES
- *             BeginCommand - prepare destination for tuples of the given type
+ *             BeginCommand - initialize the destination at start of command
  *             DestToFunction - identify per-tuple processing routines
- *             EndCommand - tell destination that no more tuples will arrive
+ *             EndCommand - clean up the destination at end of command
  *             NullCommand - tell dest that an empty query string was recognized
  *             ReadyForQuery - tell dest that we are ready for a new query
  *
  *             These routines do the appropriate work before and after
  *             tuples are returned by a query to keep the backend and the
  *             "destination" portals synchronized.
- *
- *             There is a second level of initialization/cleanup performed by the
- *             setup/cleanup routines identified by DestToFunction.  This could
- *             probably be merged with the work done by BeginCommand/EndCommand,
- *             but as of right now BeginCommand/EndCommand are used in a rather
- *             unstructured way --- some places call Begin without End, some vice
- *             versa --- so I think I'll just leave 'em alone for now.  tgl 1/99.
- *
  */
 
 #include "postgres.h"
@@ -51,7 +43,8 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
 }
 
 static void
-donothingSetup(DestReceiver *self, TupleDesc typeinfo)
+donothingSetup(DestReceiver *self, int operation,
+                          const char *portalName, TupleDesc typeinfo)
 {
 }
 
@@ -68,97 +61,20 @@ static DestReceiver donothingDR = {
        donothingReceive, donothingSetup, donothingCleanup
 };
 static DestReceiver debugtupDR = {
-       debugtup, donothingSetup, donothingCleanup
+       debugtup, debugSetup, donothingCleanup
 };
 static DestReceiver spi_printtupDR = {
        spi_printtup, donothingSetup, donothingCleanup
 };
 
 /* ----------------
- *             BeginCommand - prepare destination for tuples of the given type
+ *             BeginCommand - initialize the destination at start of command
  * ----------------
  */
 void
-BeginCommand(char *pname,
-                        int operation,
-                        TupleDesc tupdesc,
-                        bool isIntoRel,
-                        bool isIntoPortal,
-                        char *tag,
-                        CommandDest dest)
+BeginCommand(const char *commandTag, CommandDest dest)
 {
-       Form_pg_attribute *attrs = tupdesc->attrs;
-       int                     natts = tupdesc->natts;
-       int                     i;
-
-       switch (dest)
-       {
-               case Remote:
-               case RemoteInternal:
-
-                       /*
-                        * if this is a "retrieve into portal" query, done because
-                        * nothing needs to be sent to the fe.
-                        */
-                       if (isIntoPortal)
-                               break;
-
-                       /*
-                        * if portal name not specified for remote query, use the
-                        * "blank" portal.
-                        */
-                       if (pname == NULL)
-                               pname = "blank";
-
-                       /*
-                        * send fe info on tuples we're about to send
-                        */
-                       pq_puttextmessage('P', pname);
-
-                       /*
-                        * if this is a retrieve, then we send back the tuple
-                        * descriptor of the tuples.  "retrieve into" is an exception
-                        * because no tuples are returned in that case.
-                        */
-                       if (operation == CMD_SELECT && !isIntoRel)
-                       {
-                               StringInfoData buf;
-
-                               pq_beginmessage(&buf);
-                               pq_sendbyte(&buf, 'T'); /* tuple descriptor message type */
-                               pq_sendint(&buf, natts, 2);             /* # of attributes in
-                                                                                                * tuples */
-
-                               for (i = 0; i < natts; ++i)
-                               {
-                                       pq_sendstring(&buf, NameStr(attrs[i]->attname));
-                                       pq_sendint(&buf, (int) attrs[i]->atttypid,
-                                                          sizeof(attrs[i]->atttypid));
-                                       pq_sendint(&buf, attrs[i]->attlen,
-                                                          sizeof(attrs[i]->attlen));
-                                       if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
-                                               pq_sendint(&buf, attrs[i]->atttypmod,
-                                                                  sizeof(attrs[i]->atttypmod));
-                               }
-                               pq_endmessage(&buf);
-                       }
-                       break;
-
-               case Debug:
-
-                       /*
-                        * show the return type of the tuples
-                        */
-                       if (pname == NULL)
-                               pname = "blank";
-
-                       showatts(pname, tupdesc);
-                       break;
-
-               case None:
-               default:
-                       break;
-       }
+       /* Nothing to do at present */
 }
 
 /* ----------------
@@ -183,19 +99,15 @@ DestToFunction(CommandDest dest)
                        return &spi_printtupDR;
 
                case None:
-               default:
                        return &donothingDR;
        }
 
-       /*
-        * never gets here, but DECstation lint appears to be stupid...
-        */
-
+       /* should never get here */
        return &donothingDR;
 }
 
 /* ----------------
- *             EndCommand - tell destination that query is complete
+ *             EndCommand - clean up the destination at end of command
  * ----------------
  */
 void
index 61fdf9c5acfd83ef17c6e8b15e9f0e9e248dedce..cfaaf556dd0180530208a5eb3cf1ccc81568d5eb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.248 2002/02/26 22:47:08 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.249 2002/02/27 19:35:12 tgl Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -645,6 +645,18 @@ pg_exec_query_string(char *query_string,           /* string to execute */
                /* Transaction control statements need some special handling */
                isTransactionStmt = IsA(parsetree, TransactionStmt);
 
+               /*
+                * First we set the command-completion tag to the main query
+                * (as opposed to each of the others that may be generated by
+                * analyze and rewrite).  Also set ps_status and do any special
+                * start-of-SQL-command processing needed by the destination.
+                */
+               commandTag = CreateCommandTag(parsetree);
+
+               set_ps_display(commandTag);
+
+               BeginCommand(commandTag, dest);
+
                /*
                 * If we are in an aborted transaction, ignore all commands except
                 * COMMIT/ABORT.  It is important that this test occur before we
@@ -707,18 +719,7 @@ pg_exec_query_string(char *query_string,           /* string to execute */
 
                /*
                 * OK to analyze and rewrite this query.
-                */
-                
-               /*
-                * First we set the command-completion tag to the main query
-                * (as opposed to each of the others that may be generated by
-                * analyze and rewrite).  Also set ps_status to the main query tag.
-                */
-               commandTag = CreateCommandTag(parsetree);
-
-               set_ps_display(commandTag);
-
-               /*
+                *
                 * Switch to appropriate context for constructing querytrees (again,
                 * these must outlive the execution context).
                 */
@@ -1688,7 +1689,7 @@ PostgresMain(int argc, char *argv[], const char *username)
        if (!IsUnderPostmaster)
        {
                puts("\nPOSTGRES backend interactive interface ");
-               puts("$Revision: 1.248 $ $Date: 2002/02/26 22:47:08 $\n");
+               puts("$Revision: 1.249 $ $Date: 2002/02/27 19:35:12 $\n");
        }
 
        /*
index 75b99c21fab6f4210dcfebd70684ed2db7c0c23c..80658a61d6b91e081797b7bdabc87e694550ed08 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.47 2002/02/26 22:47:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.48 2002/02/27 19:35:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,7 +30,8 @@
 QueryDesc *
 CreateQueryDesc(Query *parsetree,
                                Plan *plantree,
-                               CommandDest dest)
+                               CommandDest dest,
+                               const char *portalName)
 {
        QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
 
@@ -38,6 +39,9 @@ CreateQueryDesc(Query *parsetree,
        qd->parsetree = parsetree;      /* parse tree */
        qd->plantree = plantree;        /* plan */
        qd->dest = dest;                        /* output dest */
+       qd->portalName = portalName; /* name, if dest is a portal */
+       qd->tupDesc = NULL;                     /* until set by ExecutorStart */
+
        return qd;
 }
 
@@ -138,8 +142,7 @@ ProcessQuery(Query *parsetree,
                         char *completionTag)
 {
        int                     operation = parsetree->commandType;
-       bool            isRetrieveIntoPortal;
-       bool            isRetrieveIntoRelation;
+       bool            isRetrieveIntoPortal = false;
        char       *intoName = NULL;
        Portal          portal = NULL;
        MemoryContext oldContext = NULL;
@@ -148,31 +151,28 @@ ProcessQuery(Query *parsetree,
        TupleDesc       attinfo;
 
        /*
-        * initialize portal/into relation status
+        * Check for special-case destinations
         */
-       isRetrieveIntoPortal = false;
-       isRetrieveIntoRelation = false;
-
        if (operation == CMD_SELECT)
        {
                if (parsetree->isPortal)
                {
                        isRetrieveIntoPortal = true;
                        intoName = parsetree->into;
-                       if (parsetree->isBinary)
-                       {
-                               /*
-                                * For internal format portals, we change Remote
-                                * (externalized form) to RemoteInternal (internalized
-                                * form)
-                                */
+                       /* If binary portal, switch to alternate output format */
+                       if (dest == Remote && parsetree->isBinary)
                                dest = RemoteInternal;
-                       }
                }
                else if (parsetree->into != NULL)
                {
-                       /* select into table */
-                       isRetrieveIntoRelation = true;
+                       /*
+                        * SELECT INTO table (a/k/a CREATE AS ... SELECT).
+                        *
+                        * Override the normal communication destination; execMain.c
+                        * special-cases this case.  (Perhaps would be cleaner to
+                        * have an additional destination type?)
+                        */
+                       dest = None;
                }
        }
 
@@ -197,16 +197,7 @@ ProcessQuery(Query *parsetree,
        /*
         * Now we can create the QueryDesc object.
         */
-       queryDesc = CreateQueryDesc(parsetree, plan, dest);
-
-       /*
-        * When performing a retrieve into, we override the normal
-        * communication destination during the processing of the the query.
-        * This only affects the tuple-output function - the correct
-        * destination will still see the BeginCommand() call.
-        */
-       if (isRetrieveIntoRelation)
-               queryDesc->dest = None;
+       queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
 
        /*
         * create a default executor state.
@@ -218,18 +209,6 @@ ProcessQuery(Query *parsetree,
         */
        attinfo = ExecutorStart(queryDesc, state);
 
-       /*
-        * report the query's result type information back to the front end or
-        * to whatever destination we're dealing with.
-        */
-       BeginCommand(NULL,
-                                operation,
-                                attinfo,
-                                isRetrieveIntoRelation,
-                                isRetrieveIntoPortal,
-                                NULL,                  /* not used */
-                                dest);
-
        /*
         * If retrieve into portal, stop now; we do not run the plan until a
         * FETCH command is received.
@@ -256,7 +235,7 @@ ProcessQuery(Query *parsetree,
         * Now we get to the important call to ExecutorRun() where we actually
         * run the plan..
         */
-       ExecutorRun(queryDesc, state, EXEC_RUN, 0L);
+       ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
 
        /*
         * Build command completion status string, if caller wants one.
index 7682752922440ddcc85d4351ffdfe795c7024f72..7b04a0e036a1fa8819882ca17c43e85e571ffbee 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.45 2002/02/14 15:24:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.46 2002/02/27 19:35:35 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,8 +22,8 @@
  *             sees a
  *                             fetch 1 from FOO
  *             the system looks up the portal named "FOO" in the portal table,
- *             gets the planned query and then calls the executor with a feature of
- *             '(EXEC_FOR 1).  The executor then runs the query and returns a single
+ *             gets the planned query and then calls the executor with a count
+ *             of 1.  The executor then runs the query and returns a single
  *             tuple.  The problem is that we have to hold onto the state of the
  *             portal query until we see a "close".  This means we have to be
  *             careful about memory management.
index ff775eb2697159c852ec6e775661a9da1ff28e40..c1d8db17adbbc85611e71a31345c333bf850c57f 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: printtup.h,v 1.18 2001/11/05 17:46:31 momjian Exp $
+ * $Id: printtup.h,v 1.19 2002/02/27 19:35:40 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 extern DestReceiver *printtup_create_DR(bool isBinary);
 
-extern void showatts(char *name, TupleDesc attinfo);
+extern void debugSetup(DestReceiver *self, int operation,
+                                          const char *portalName, TupleDesc typeinfo);
 extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
-                DestReceiver *self);
+                                        DestReceiver *self);
 
 /* XXX this one is really in executor/spi.c */
 extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc,
index b6e7195771671e7a5f0828afdc8c0b4fea6f085e..bdb4dce13c6d6c11cb1393ed27ad4779e790d594 100644 (file)
@@ -7,30 +7,13 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execdefs.h,v 1.11 2001/11/05 17:46:33 momjian Exp $
+ * $Id: execdefs.h,v 1.12 2002/02/27 19:35:51 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef EXECDEFS_H
 #define EXECDEFS_H
 
-/* ----------------
- *             ExecutePlan() tuplecount definitions
- * ----------------
- */
-#define ALL_TUPLES                             0               /* return all tuples */
-#define ONE_TUPLE                              1               /* return only one tuple */
-
-/* ----------------
- *             constants used by ExecMain
- * ----------------
- */
-#define EXEC_RUN                                               3
-#define EXEC_FOR                                               4
-#define EXEC_BACK                                              5
-#define EXEC_RETONE                                            6
-#define EXEC_RESULT                                            7
-
 /* ----------------
  *             Merge Join states
  * ----------------
index 55bf52ed38ddee324b0c6e7d3b39fda7185661f5..87915e9c07e4572fe9dd60b147f078e09f5a59ad 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: execdesc.h,v 1.17 2001/11/05 17:46:33 momjian Exp $
+ * $Id: execdesc.h,v 1.18 2002/02/27 19:35:54 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -19,6 +19,7 @@
 #include "nodes/plannodes.h"
 #include "tcop/dest.h"
 
+
 /* ----------------
  *             query descriptor:
  *     a QueryDesc encapsulates everything that the executor
@@ -31,10 +32,14 @@ typedef struct QueryDesc
        Query      *parsetree;
        Plan       *plantree;
        CommandDest dest;                       /* the destination output of the execution */
+       const char *portalName;         /* name of portal, or NULL */
+
+       TupleDesc       tupDesc;                /* set by ExecutorStart */
 } QueryDesc;
 
 /* in pquery.c */
 extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
-                               CommandDest dest);
+                                                                 CommandDest dest, const char *portalName);
+
 
 #endif   /* EXECDESC_H  */
index c089a47731f0f7c0376666f0f6addb45081330c0..63bc10f79dcde17fb25258129feadc84352f2e77 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.62 2002/02/19 20:11:19 tgl Exp $
+ * $Id: executor.h,v 1.63 2002/02/27 19:35:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -50,7 +50,7 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
  */
 extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
 extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
-                       int feature, long count);
+                                                                  ScanDirection direction, long count);
 extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
 extern void ExecConstraints(char *caller, ResultRelInfo *resultRelInfo,
                                TupleTableSlot *slot, EState *estate);
index d5ac420ce6ed4968a669cb3564aee723fbe487cb..c96133759d5ef239af85365d487c0887ed1541ce 100644 (file)
@@ -1,11 +1,13 @@
 /*-------------------------------------------------------------------------
  *
  * dest.h
- *             Whenever the backend executes a query, the results
- *             have to go someplace.
+ *       support for communication destinations
+ *
+ * Whenever the backend executes a query, the results
+ * have to go someplace.
  *
  *       - stdout is the destination only when we are running a
- *             backend without a postmaster and are returning results
+ *             standalone backend (no postmaster) and are returning results
  *             back to an interactive user.
  *
  *       - a remote process is the destination when we are
  *             to the frontend via the functions in backend/libpq.
  *
  *       - None is the destination when the system executes
- *             a query internally.  This is not used now but it may be
- *             useful for the parallel optimiser/executor.
+ *             a query internally.  The results are discarded.
  *
  * dest.c defines three functions that implement destination management:
  *
- * BeginCommand: initialize the destination.
+ * BeginCommand: initialize the destination at start of command.
  * DestToFunction: return a pointer to a struct of destination-specific
  * receiver functions.
- * EndCommand: clean up the destination when output is complete.
+ * EndCommand: clean up the destination at end of command.
+ *
+ * BeginCommand/EndCommand are executed once per received SQL query.
+ *
+ * DestToFunction, and the receiver functions it links to, are executed
+ * each time we run the executor to produce tuples, which may occur
+ * multiple times per received query (eg, due to additional queries produced
+ * by rewrite rules).
  *
  * The DestReceiver object returned by DestToFunction may be a statically
  * allocated object (for destination types that require no local state)
  * by casting the DestReceiver* pointer passed to them.
  * The palloc'd object is pfree'd by the DestReceiver's cleanup function.
  *
- * XXX FIXME: the initialization and cleanup code that currently appears
- * in-line in BeginCommand and EndCommand probably should be moved out
- * to routines associated with each destination receiver type.
  *
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: dest.h,v 1.29 2002/02/26 22:47:11 tgl Exp $
+ * $Id: dest.h,v 1.30 2002/02/27 19:36:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -80,18 +85,17 @@ struct _DestReceiver
 {
        /* Called for each tuple to be output: */
        void            (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo,
-                                                                                        DestReceiver *self);
+                                                                DestReceiver *self);
        /* Initialization and teardown: */
-       void            (*setup) (DestReceiver *self, TupleDesc typeinfo);
+       void            (*setup) (DestReceiver *self, int operation,
+                                                 const char *portalName, TupleDesc typeinfo);
        void            (*cleanup) (DestReceiver *self);
        /* Private fields might appear beyond this point... */
 };
 
 /* The primary destination management functions */
 
-extern void BeginCommand(char *pname, int operation, TupleDesc attinfo,
-                        bool isIntoRel, bool isIntoPortal, char *tag,
-                        CommandDest dest);
+extern void BeginCommand(const char *commandTag, CommandDest dest);
 extern DestReceiver *DestToFunction(CommandDest dest);
 extern void EndCommand(const char *commandTag, CommandDest dest);