]> granicus.if.org Git - postgresql/commitdiff
Another SELECT speedup: extract OIDs of column print functions
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 27 Jan 1999 00:36:28 +0000 (00:36 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 27 Jan 1999 00:36:28 +0000 (00:36 +0000)
only once per SELECT, not once per tuple.  10% here, 10% there,
pretty soon you're talking about real speedups ...

src/backend/access/common/printtup.c
src/backend/executor/execMain.c
src/backend/executor/spi.c
src/backend/libpq/be-dumpdata.c
src/backend/nodes/print.c
src/backend/tcop/dest.c
src/include/access/printtup.h
src/include/libpq/libpq.h
src/include/tcop/dest.h

index fdf4ca8621222ff4216cd34aa3a3d30f1166eff2..91273e4933f3c3364621a3fcd36e617f6ec6f78b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.39 1999/01/24 22:50:58 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.40 1999/01/27 00:36:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include <mb/pg_wchar.h>
 #endif
 
+static void printtup_setup(DestReceiver* self, TupleDesc typeinfo);
+static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self);
+static void printtup_cleanup(DestReceiver* self);
+
 /* ----------------------------------------------------------------
  *             printtup / debugtup support
  * ----------------------------------------------------------------
@@ -64,13 +68,89 @@ getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem)
        return 0;
 }
 
+/* ----------------
+ *             Private state for a printtup destination object
+ * ----------------
+ */
+typedef struct {                               /* Per-attribute information */
+       Oid                     typoutput;              /* Oid for the attribute's type output fn */
+       Oid                     typelem;                /* typelem value to pass to the output fn */
+       /* more soon... */
+} PrinttupAttrInfo;
+
+typedef struct {
+       DestReceiver            pub;            /* publicly-known function pointers */
+       TupleDesc                       attrinfo;       /* The attr info we are set up for */
+       int                                     nattrs;
+       PrinttupAttrInfo   *myinfo;             /* Cached info about each attr */
+} DR_printtup;
+
+/* ----------------
+ *             Initialize: create a DestReceiver for printtup
+ * ----------------
+ */
+DestReceiver*
+printtup_create_DR()
+{
+       DR_printtup* self = (DR_printtup*) palloc(sizeof(DR_printtup));
+
+       self->pub.receiveTuple = printtup;
+       self->pub.setup = printtup_setup;
+       self->pub.cleanup = printtup_cleanup;
+
+       self->attrinfo = NULL;
+       self->nattrs = 0;
+       self->myinfo = NULL;
+
+       return (DestReceiver*) self;
+}
+
+static void
+printtup_setup(DestReceiver* self, TupleDesc typeinfo)
+{
+       /* ----------------
+        * We could set up the derived attr info at this time, but we postpone it
+        * until the first call of printtup, for 3 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 :-(
+        * ----------------
+        */
+}
+
+static void
+printtup_prepare_info(DR_printtup* myState, TupleDesc typeinfo, int numAttrs)
+{
+       int i;
+
+       if (myState->myinfo)
+               pfree(myState->myinfo); /* get rid of any old data */
+       myState->myinfo = NULL;
+       myState->attrinfo = typeinfo;
+       myState->nattrs = numAttrs;
+       if (numAttrs <= 0)
+               return;
+       myState->myinfo = (PrinttupAttrInfo*)
+               palloc(numAttrs * sizeof(PrinttupAttrInfo));
+       for (i = 0; i < numAttrs; i++)
+       {
+               PrinttupAttrInfo* thisState = myState->myinfo + i;
+               getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
+                                                 &thisState->typoutput, &thisState->typelem);
+       }
+}
+
 /* ----------------
  *             printtup
  * ----------------
  */
-void
-printtup(HeapTuple tuple, TupleDesc typeinfo)
+static void
+printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
 {
+       DR_printtup *myState = (DR_printtup*) self;
        int                     i,
                                j,
                                k,
@@ -78,12 +158,15 @@ printtup(HeapTuple tuple, TupleDesc typeinfo)
        char       *outputstr;
        Datum           attr;
        bool            isnull;
-       Oid                     typoutput,
-                               typelem;
 #ifdef MULTIBYTE
        unsigned char *p;
 #endif
 
+       /* Set or update my derived attribute info, if needed */
+       if (myState->attrinfo != typeinfo ||
+               myState->nattrs != tuple->t_data->t_natts)
+               printtup_prepare_info(myState, typeinfo, tuple->t_data->t_natts);
+
        /* ----------------
         *      tell the frontend to expect new tuple data (in ASCII style)
         * ----------------
@@ -120,10 +203,11 @@ printtup(HeapTuple tuple, TupleDesc typeinfo)
                attr = heap_getattr(tuple, i + 1, typeinfo, &isnull);
                if (isnull)
                        continue;
-               if (getTypeOutAndElem((Oid) typeinfo->attrs[i]->atttypid,
-                                                         &typoutput, &typelem))
+               if (OidIsValid(myState->myinfo[i].typoutput))
                {
-                       outputstr = fmgr(typoutput, attr, typelem,
+                       outputstr = fmgr(myState->myinfo[i].typoutput,
+                                                        attr,
+                                                        myState->myinfo[i].typelem,
                                                         typeinfo->attrs[i]->atttypmod);
 #ifdef MULTIBYTE
                        p = pg_server_to_client(outputstr, strlen(outputstr));
@@ -147,6 +231,19 @@ printtup(HeapTuple tuple, TupleDesc typeinfo)
        }
 }
 
+/* ----------------
+ *             printtup_cleanup
+ * ----------------
+ */
+static void
+printtup_cleanup(DestReceiver* self)
+{
+       DR_printtup* myState = (DR_printtup*) self;
+       if (myState->myinfo)
+               pfree(myState->myinfo);
+       pfree(myState);
+}
+
 /* ----------------
  *             printatt
  * ----------------
@@ -190,7 +287,7 @@ showatts(char *name, TupleDesc tupleDesc)
  * ----------------
  */
 void
-debugtup(HeapTuple tuple, TupleDesc typeinfo)
+debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
 {
        int                     i;
        Datum           attr;
@@ -221,11 +318,12 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo)
  *             We use a different data prefix, e.g. 'B' instead of 'D' to
  *             indicate a tuple in internal (binary) form.
  *
- *             This is same as printtup, except we don't use the typout func.
+ *             This is same as printtup, except we don't use the typout func,
+ *             and therefore have no need for persistent state.
  * ----------------
  */
 void
-printtup_internal(HeapTuple tuple, TupleDesc typeinfo)
+printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
 {
        int                     i,
                                j,
index e79816389ccc1522b02be53ab9c0db5f41c43502..79cffc49f8f698b61aa8def87eeb9f7996533c6f 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.63 1999/01/25 12:01:03 vadim Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.64 1999/01/27 00:36:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -66,9 +66,10 @@ static void EndPlan(Plan *plan, EState *estate);
 static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
                        Query *parseTree, CmdType operation,
                        int numberTuples, ScanDirection direction,
-                       void (*printfunc) ());
-static void ExecRetrieve(TupleTableSlot *slot, void (*printfunc) (),
-                                                                        EState *estate);
+                       DestReceiver *destfunc);
+static void ExecRetrieve(TupleTableSlot *slot,
+                                                DestReceiver *destfunc,
+                                                EState *estate);
 static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
                   EState *estate);
 static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
@@ -171,7 +172,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
        Plan       *plan;
        TupleTableSlot *result;
        CommandDest dest;
-       void            (*destination) ();
+       DestReceiver   *destfunc;
 
        /******************
         *      sanity checks
@@ -188,10 +189,19 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
        parseTree = queryDesc->parsetree;
        plan = queryDesc->plantree;
        dest = queryDesc->dest;
-       destination = (void (*) ()) DestToFunction(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.
+        ******************
+        */
+       (*destfunc->setup) (destfunc, (TupleDesc) NULL);
+
        switch (feature)
        {
 
@@ -202,7 +212,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                                                                 operation,
                                                                 ALL_TUPLES,
                                                                 ForwardScanDirection,
-                                                                destination);
+                                                                destfunc);
                        break;
                case EXEC_FOR:
                        result = ExecutePlan(estate,
@@ -211,7 +221,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                                                                 operation,
                                                                 count,
                                                                 ForwardScanDirection,
-                                                                destination);
+                                                                destfunc);
                        break;
 
                        /******************
@@ -225,7 +235,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                                                                 operation,
                                                                 count,
                                                                 BackwardScanDirection,
-                                                                destination);
+                                                                destfunc);
                        break;
 
                        /******************
@@ -240,7 +250,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                                                                 operation,
                                                                 ONE_TUPLE,
                                                                 ForwardScanDirection,
-                                                                destination);
+                                                                destfunc);
                        break;
                default:
                        result = NULL;
@@ -248,6 +258,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
                        break;
        }
 
+       (*destfunc->cleanup) (destfunc);
+
        return result;
 }
 
@@ -745,7 +757,7 @@ ExecutePlan(EState *estate,
                        CmdType operation,
                        int numberTuples,
                        ScanDirection direction,
-                       void (*printfunc) ())
+                       DestReceiver* destfunc)
 {
        JunkFilter *junkfilter;
 
@@ -905,7 +917,7 @@ ExecutePlan(EState *estate,
                {
                        case CMD_SELECT:
                                ExecRetrieve(slot,              /* slot containing tuple */
-                                                        printfunc, /* print function */
+                                                        destfunc,      /* destination's tuple-receiver obj */
                                                         estate);       /* */
                                result = slot;
                                break;
@@ -961,7 +973,7 @@ ExecutePlan(EState *estate,
  */
 static void
 ExecRetrieve(TupleTableSlot *slot,
-                        void (*printfunc) (),
+                        DestReceiver *destfunc,
                         EState *estate)
 {
        HeapTuple       tuple;
@@ -988,7 +1000,7 @@ ExecRetrieve(TupleTableSlot *slot,
         *      send the tuple to the front end (or the screen)
         ******************
         */
-       (*printfunc) (tuple, attrtype);
+       (*destfunc->receiveTuple) (tuple, attrtype, destfunc);
        IncrRetrieved();
        (estate->es_processed)++;
 }
index 5620cf789162fcf9149d12ff5d7732880b201ae8..a7358425b47582587b5411624e6b1305ff5e4379 100644 (file)
@@ -3,7 +3,7 @@
  * spi.c--
  *                             Server Programming Interface
  *
- * $Id: spi.c,v 1.30 1999/01/24 05:40:48 tgl Exp $
+ * $Id: spi.c,v 1.31 1999/01/27 00:36:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,8 +32,6 @@ uint32                SPI_processed = 0;
 SPITupleTable *SPI_tuptable;
 int                    SPI_result;
 
-void           spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
-
 typedef struct
 {
        QueryTreeList *qtlist;
@@ -566,7 +564,7 @@ SPI_pfree(void *pointer)
  *
  */
 void
-spi_printtup(HeapTuple tuple, TupleDesc tupdesc)
+spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver* self)
 {
        SPITupleTable *tuptable;
        MemoryContext oldcxt;
index 70d01e4dcf8fe178816b47387f9f245d3910b7b5..4247b1c674cc763e9891ed9d245cbd91a1fa3d8c 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- *  $Id: be-dumpdata.c,v 1.20 1999/01/24 05:40:49 tgl Exp $
+ *  $Id: be-dumpdata.c,v 1.21 1999/01/27 00:36:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -208,7 +208,7 @@ be_typeinit(PortalEntry *entry,
  * ----------------
  */
 void
-be_printtup(HeapTuple tuple, TupleDesc typeinfo)
+be_printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
 {
        int                     i;
        Datum           attr;
index af3a3eb84725caffb7116c716fdfb92e42c65fbf..3acf895e7c3c67a636b0060793b64667ac11cda4 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.18 1998/09/01 04:29:10 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.19 1999/01/27 00:36:28 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -275,7 +275,7 @@ print_slot(TupleTableSlot *slot)
                return;
        }
 
-       debugtup(slot->val, slot->ttc_tupleDescriptor);
+       debugtup(slot->val, slot->ttc_tupleDescriptor, NULL);
 }
 
 static char *
index 0c1a7c530fd2e21442a66c5518f924f802d0bf91..0d946287f37c02567dd13c69ec0d9455adb82968 100644 (file)
@@ -1,19 +1,20 @@
 /*-------------------------------------------------------------------------
  *
  * dest.c--
- *       support for various communication destinations - see lib/H/tcop/dest.h
+ *       support for various communication destinations - see include/tcop/dest.h
  *
  * Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.23 1998/09/01 04:32:10 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.24 1999/01/27 00:36:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  *      INTERFACE ROUTINES
  *             BeginCommand - prepare destination for tuples of the given type
+ *             DestToFunction - identify per-tuple processing routines
  *             EndCommand - tell destination that no more tuples will arrive
  *             NullCommand - tell dest that an empty query string was recognized
  *             ReadyForQuery - tell dest that we are ready for a new query
  *             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 <stdio.h>                             /* for sprintf() */
 #include <string.h>
 static char CommandInfo[32] = {0};
 
 /* ----------------
- *             output functions
+ *             dummy DestReceiver functions
  * ----------------
  */
 static void
-donothing(HeapTuple tuple, TupleDesc attrdesc)
+donothingReceive (HeapTuple tuple, TupleDesc typeinfo, DestReceiver* self)
 {
 }
 
-extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
+static void
+donothingSetup (DestReceiver* self, TupleDesc typeinfo)
+{
+}
 
-void           (*
-                        DestToFunction(CommandDest dest)) (HeapTuple, TupleDesc)
+static void
+donothingCleanup (DestReceiver* self)
 {
+}
+
+/* ----------------
+ *             static DestReceiver structs for dest types needing no local state
+ * ----------------
+ */
+static DestReceiver donothingDR = {
+       donothingReceive, donothingSetup, donothingCleanup
+};
+static DestReceiver printtup_internalDR = {
+       printtup_internal, donothingSetup, donothingCleanup
+};
+static DestReceiver be_printtupDR = {
+       be_printtup, donothingSetup, donothingCleanup
+};
+static DestReceiver debugtupDR = {
+       debugtup, donothingSetup, donothingCleanup
+};
+static DestReceiver spi_printtupDR = {
+       spi_printtup, donothingSetup, donothingCleanup
+};
+
+/* ----------------
+ *             BeginCommand - prepare destination for tuples of the given type
+ * ----------------
+ */
+void
+BeginCommand(char *pname,
+                        int operation,
+                        TupleDesc tupdesc,
+                        bool isIntoRel,
+                        bool isIntoPortal,
+                        char *tag,
+                        CommandDest dest)
+{
+       PortalEntry *entry;
+       Form_pg_attribute *attrs = tupdesc->attrs;
+       int                     natts = tupdesc->natts;
+       int                     i;
+       char       *p;
+
        switch (dest)
        {
-                       case RemoteInternal:
-                       return printtup_internal;
+               case Remote:
+               case RemoteInternal:
+                       /* ----------------
+                        *              if this is a "retrieve portal" query, done
+                        *              because nothing needs to be sent to the fe.
+                        * ----------------
+                        */
+                       CommandInfo[0] = '\0';
+                       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_putnchar("P", 1);/* new portal.. */
+                       pq_putstr(pname);       /* portal name */
+
+                       /* ----------------
+                        *              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)
+                       {
+                               pq_putnchar("T", 1);    /* type info to follow.. */
+                               pq_putint(natts, 2);    /* number of attributes in tuples */
+
+                               for (i = 0; i < natts; ++i)
+                               {
+                                       pq_putstr(attrs[i]->attname.data);
+                                       pq_putint((int) attrs[i]->atttypid, sizeof(attrs[i]->atttypid));
+                                       pq_putint(attrs[i]->attlen, sizeof(attrs[i]->attlen));
+                                       if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
+                                               pq_putint(attrs[i]->atttypmod, sizeof(attrs[i]->atttypmod));
+                               }
+                       }
                        break;
 
+               case Local:
+                       /* ----------------
+                        *              prepare local portal buffer for query results
+                        *              and setup result for PQexec()
+                        * ----------------
+                        */
+                       entry = be_currentportal();
+                       if (pname != NULL)
+                               pbuf_setportalinfo(entry, pname);
+
+                       if (operation == CMD_SELECT && !isIntoRel)
+                       {
+                               be_typeinit(entry, tupdesc, natts);
+                               p = (char *) palloc(strlen(entry->name) + 2);
+                               p[0] = 'P';
+                               strcpy(p + 1, entry->name);
+                       }
+                       else
+                       {
+                               p = (char *) palloc(strlen(tag) + 2);
+                               p[0] = 'C';
+                               strcpy(p + 1, tag);
+                       }
+                       entry->result = p;
+                       break;
+
+               case Debug:
+                       /* ----------------
+                        *              show the return type of the tuples
+                        * ----------------
+                        */
+                       if (pname == NULL)
+                               pname = "blank";
+
+                       showatts(pname, tupdesc);
+                       break;
+
+               case None:
+               default:
+                       break;
+       }
+}
+
+/* ----------------
+ *             DestToFunction - return appropriate receiver function set for dest
+ * ----------------
+ */
+DestReceiver*
+DestToFunction(CommandDest dest)
+{
+       switch (dest)
+       {
                case Remote:
-                       return printtup;
+                       /* printtup wants a dynamically allocated DestReceiver */
+                       return printtup_create_DR();
+                       break;
+
+               case RemoteInternal:
+                       return & printtup_internalDR;
                        break;
 
                case Local:
-                       return be_printtup;
+                       return & be_printtupDR;
                        break;
 
                case Debug:
-                       return debugtup;
+                       return & debugtupDR;
                        break;
 
                case SPI:
-                       return spi_printtup;
+                       return & spi_printtupDR;
                        break;
 
                case None:
                default:
-                       return donothing;
+                       return & donothingDR;
                        break;
        }
 
@@ -92,7 +245,7 @@ void         (*
         * never gets here, but DECstation lint appears to be stupid...
         */
 
-       return donothing;
+       return & donothingDR;
 }
 
 /* ----------------
@@ -106,16 +259,15 @@ EndCommand(char *commandTag, CommandDest dest)
 
        switch (dest)
        {
-               case RemoteInternal:
                case Remote:
+               case RemoteInternal:
                        /* ----------------
                         *              tell the fe that the query is over
                         * ----------------
                         */
-                       pq_putnchar("C", 1);
-                       sprintf(buf, "%s%s", commandTag, CommandInfo);
-                       CommandInfo[0] = 0;
+                       sprintf(buf, "C%s%s", commandTag, CommandInfo);
                        pq_putstr(buf);
+                       CommandInfo[0] = '\0';
                        break;
 
                case Local:
@@ -172,15 +324,13 @@ NullCommand(CommandDest dest)
 {
        switch (dest)
        {
-                       case RemoteInternal:
-                       case Remote:
-                       {
-                               /* ----------------
-                                *              tell the fe that we saw an empty query string
-                                * ----------------
-                                */
-                               pq_putstr("I");
-                       }
+               case RemoteInternal:
+               case Remote:
+                       /* ----------------
+                        *              tell the fe that we saw an empty query string
+                        * ----------------
+                        */
+                       pq_putstr("I");
                        break;
 
                case Local:
@@ -204,132 +354,18 @@ NullCommand(CommandDest dest)
 void
 ReadyForQuery(CommandDest dest)
 {
-       switch (dest)
-       {
-                       case RemoteInternal:
-                       case Remote:
-                       {
-                               if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
-                                       pq_putnchar("Z", 1);
-                               /* Flush output at end of cycle in any case. */
-                               pq_flush();
-                       }
-                       break;
-
-               case Local:
-               case Debug:
-               case None:
-               default:
-                       break;
-       }
-}
-
-/* ----------------
- *             BeginCommand - prepare destination for tuples of the given type
- * ----------------
- */
-void
-BeginCommand(char *pname,
-                        int operation,
-                        TupleDesc tupdesc,
-                        bool isIntoRel,
-                        bool isIntoPortal,
-                        char *tag,
-                        CommandDest dest)
-{
-       PortalEntry *entry;
-       Form_pg_attribute *attrs = tupdesc->attrs;
-       int                     natts = tupdesc->natts;
-       int                     i;
-       char       *p;
-
        switch (dest)
        {
                case RemoteInternal:
                case Remote:
-                       /* ----------------
-                        *              if this is a "retrieve portal" query, just return
-                        *              because nothing needs to be sent to the fe.
-                        * ----------------
-                        */
-                       CommandInfo[0] = 0;
-                       if (isIntoPortal)
-                               return;
-
-                       /* ----------------
-                        *              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_putnchar("P", 1);/* new portal.. */
-                       pq_putstr(pname);       /* portal name */
-
-                       /* ----------------
-                        *              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)
-                       {
-                               pq_putnchar("T", 1);    /* type info to follow.. */
-                               pq_putint(natts, 2);    /* number of attributes in tuples */
-
-                               for (i = 0; i < natts; ++i)
-                               {
-                                       pq_putstr(attrs[i]->attname.data);
-                                       pq_putint((int) attrs[i]->atttypid, sizeof(attrs[i]->atttypid));
-                                       pq_putint(attrs[i]->attlen, sizeof(attrs[i]->attlen));
-                                       if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
-                                               pq_putint(attrs[i]->atttypmod, sizeof(attrs[i]->atttypmod));
-                               }
-                       }
+                       if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
+                               pq_putnchar("Z", 1);
+                       /* Flush output at end of cycle in any case. */
+                       pq_flush();
                        break;
 
                case Local:
-                       /* ----------------
-                        *              prepare local portal buffer for query results
-                        *              and setup result for PQexec()
-                        * ----------------
-                        */
-                       entry = be_currentportal();
-                       if (pname != NULL)
-                               pbuf_setportalinfo(entry, pname);
-
-                       if (operation == CMD_SELECT && !isIntoRel)
-                       {
-                               be_typeinit(entry, tupdesc, natts);
-                               p = (char *) palloc(strlen(entry->name) + 2);
-                               p[0] = 'P';
-                               strcpy(p + 1, entry->name);
-                       }
-                       else
-                       {
-                               p = (char *) palloc(strlen(tag) + 2);
-                               p[0] = 'C';
-                               strcpy(p + 1, tag);
-                       }
-                       entry->result = p;
-                       break;
-
                case Debug:
-                       /* ----------------
-                        *              show the return type of the tuples
-                        * ----------------
-                        */
-                       if (pname == NULL)
-                               pname = "blank";
-
-                       showatts(pname, tupdesc);
-                       break;
-
                case None:
                default:
                        break;
@@ -341,7 +377,7 @@ UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples)
 {
        switch (operation)
        {
-                       case CMD_INSERT:
+               case CMD_INSERT:
                        if (tuples > 1)
                                lastoid = InvalidOid;
                        sprintf(CommandInfo, " %u %u", lastoid, tuples);
@@ -351,7 +387,7 @@ UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples)
                        sprintf(CommandInfo, " %u", tuples);
                        break;
                default:
-                       CommandInfo[0] = 0;
+                       CommandInfo[0] = '\0';
+                       break;
        }
-       return;
 }
index 0b4f7b0f0425cc36ef33df9d0611cf092984fef1..c1b1c51ef898a65b4abcf51dc9de623a8d862c52 100644 (file)
@@ -6,20 +6,26 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: printtup.h,v 1.6 1999/01/24 05:40:46 tgl Exp $
+ * $Id: printtup.h,v 1.7 1999/01/27 00:36:10 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef PRINTTUP_H
 #define PRINTTUP_H
 
-#include <access/htup.h>
-#include <access/tupdesc.h>
+#include <tcop/dest.h>
 
-extern int     getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem);
-extern void printtup(HeapTuple tuple, TupleDesc typeinfo);
+extern DestReceiver* printtup_create_DR(void);
 extern void showatts(char *name, TupleDesc attinfo);
-extern void debugtup(HeapTuple tuple, TupleDesc typeinfo);
-extern void printtup_internal(HeapTuple tuple, TupleDesc typeinfo);
+extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
+                                        DestReceiver* self);
+extern void printtup_internal(HeapTuple tuple, TupleDesc typeinfo,
+                                                         DestReceiver* self);
+
+/* XXX this one is really in executor/spi.c */
+extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc,
+                                                DestReceiver* self);
+
+extern int     getTypeOutAndElem(Oid type, Oid* typOutput, Oid* typElem);
 
 #endif  /* PRINTTUP_H */
index cd036ca67f554ea8f3acbb8bb5a7967b1bb3de9c..e654899909c9a9bff73f5f07bf311e33dbd9c8c8 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: libpq.h,v 1.25 1999/01/24 02:47:15 tgl Exp $
+ * $Id: libpq.h,v 1.26 1999/01/27 00:36:09 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,8 +18,7 @@
 #include <netinet/in.h>
 
 #include "libpq/libpq-be.h"
-#include "access/htup.h"
-#include "access/tupdesc.h"
+#include "tcop/dest.h"
 
 
 /* ----------------
@@ -236,7 +235,8 @@ extern PortalEntry *be_currentportal(void);
 extern PortalEntry *be_newportal(void);
 extern void be_typeinit(PortalEntry *entry, TupleDesc attrs,
                        int natts);
-extern void be_printtup(HeapTuple tuple, TupleDesc typeinfo);
+extern void be_printtup(HeapTuple tuple, TupleDesc typeinfo,
+                                               DestReceiver* self);
 
 
 /* in be-pqexec.c */
index 9a0322e7260e24cf81a6f2be4745a84caaee0642..0b5a80908be2c65494224886ba69e3c030a29f98 100644 (file)
@@ -1,7 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * dest.h--
- *             Whenever the backend is submitted a query, the results
+ *             Whenever the backend executes a query, the results
  *             have to go someplace - either to the standard output,
  *             to a local portal buffer or to a remote portal buffer.
  *
  *             a query internally.  This is not used now but it may be
  *             useful for the parallel optimiser/executor.
  *
+ * dest.c defines three functions that implement destination management:
+ *
+ * BeginCommand: initialize the destination.
+ * DestToFunction: return a pointer to a struct of destination-specific
+ * receiver functions.
+ * EndCommand: clean up the destination when output is complete.
+ *
+ * The DestReceiver object returned by DestToFunction may be a statically
+ * allocated object (for destination types that require no local state)
+ * or can be a palloc'd object that has DestReceiver as its first field
+ * and contains additional fields (see printtup.c for an example).  These
+ * additional fields are then accessible to the DestReceiver functions
+ * 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.
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: dest.h,v 1.16 1998/09/01 04:38:39 momjian Exp $
+ * $Id: dest.h,v 1.17 1999/01/27 00:36:08 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef DEST_H
 #define DEST_H
 
+#include <access/htup.h>
 #include <access/tupdesc.h>
 
 /* ----------------
- *             CommandDest is used to allow the results of calling
- *             pg_eval() to go to the right place.
+ *             CommandDest is a simplistic means of identifying the desired
+ *             destination.  Someday this will probably need to be improved.
  * ----------------
  */
 typedef enum
@@ -51,25 +70,38 @@ typedef enum
        SPI                                                     /* results sent to SPI manager */
 } CommandDest;
 
+/* ----------------
+ *             DestReceiver is a base type for destination-specific local state.
+ *             In the simplest cases, there is no state info, just the function
+ *             pointers that the executor must call.
+ * ----------------
+ */
+typedef struct _DestReceiver DestReceiver;
 
-/* AttrInfo* replaced with TupleDesc, now that TupleDesc also has within it
-   the number of attributes
+struct _DestReceiver {
+       /* Called for each tuple to be output: */
+       void (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo,
+                                                 DestReceiver* self);
+       /* Initialization and teardown: */
+       void (*setup) (DestReceiver* self, TupleDesc typeinfo);
+       void (*cleanup) (DestReceiver* self);
+       /* Private fields might appear beyond this point... */
+};
 
-typedef struct AttrInfo {
-       int                                     numAttr;
-       Form_pg_attribute       *attrs;
-} AttrInfo;
-*/
+/* The primary destination management functions */
 
-extern void (*DestToFunction(CommandDest dest)) ();
+extern void BeginCommand(char *pname, int operation, TupleDesc attinfo,
+                                                bool isIntoRel, bool isIntoPortal, char *tag,
+                                                CommandDest dest);
+extern DestReceiver* DestToFunction(CommandDest dest);
 extern void EndCommand(char *commandTag, CommandDest dest);
+
+/* Additional functions that go with destination management, more or less. */
+
 extern void SendCopyBegin(void);
 extern void ReceiveCopyBegin(void);
 extern void NullCommand(CommandDest dest);
 extern void ReadyForQuery(CommandDest dest);
-extern void BeginCommand(char *pname, int operation, TupleDesc attinfo,
-                        bool isIntoRel, bool isIntoPortal, char *tag,
-                        CommandDest dest);
 extern void UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples);
 
 #endif  /* DEST_H */