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);