Implement feature of new FE/BE protocol whereby RowDescription identifies
authorTom Lane
Tue, 6 May 2003 00:20:33 +0000 (00:20 +0000)
committerTom Lane
Tue, 6 May 2003 00:20:33 +0000 (00:20 +0000)
the column by table OID and column number, if it's a simple column
reference.  Along the way, get rid of reskey/reskeyop fields in Resdoms.
Turns out that representation was not convenient for either the planner
or the executor; we can make the planner deliver exactly what the
executor wants with no more effort.
initdb forced due to change in stored rule representation.

32 files changed:
src/backend/access/common/printtup.c
src/backend/commands/explain.c
src/backend/executor/execMain.c
src/backend/executor/execTuples.c
src/backend/executor/functions.c
src/backend/executor/nodeSort.c
src/backend/executor/spi.c
src/backend/executor/tstoreReceiver.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/print.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/tlist.c
src/backend/parser/analyze.c
src/backend/parser/parse_target.c
src/backend/tcop/dest.c
src/backend/tcop/postgres.c
src/backend/tcop/pquery.c
src/include/access/printtup.h
src/include/catalog/catversion.h
src/include/executor/executor.h
src/include/nodes/plannodes.h
src/include/nodes/primnodes.h
src/include/optimizer/planmain.h
src/include/optimizer/tlist.h
src/include/parser/parse_target.h
src/include/tcop/dest.h

index 584233c1873f569788fa521708b85decdc04c6e1..27d6ffd508e48000c77b9ac8489c09e36307c70c 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.68 2003/05/05 00:44:55 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.69 2003/05/06 00:20:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,7 +23,7 @@
 
 
 static void printtup_setup(DestReceiver *self, int operation,
-              const char *portalName, TupleDesc typeinfo);
+              const char *portalName, TupleDesc typeinfo, List *targetlist);
 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);
@@ -78,7 +78,7 @@ printtup_create_DR(bool isBinary, bool sendDescrip)
 
 static void
 printtup_setup(DestReceiver *self, int operation,
-              const char *portalName, TupleDesc typeinfo)
+              const char *portalName, TupleDesc typeinfo, List *targetlist)
 {
    DR_printtup *myState = (DR_printtup *) self;
 
@@ -100,7 +100,7 @@ printtup_setup(DestReceiver *self, int operation,
     * then we send back the tuple descriptor of the tuples.  
     */
    if (operation == CMD_SELECT && myState->sendDescrip)
-       SendRowDescriptionMessage(typeinfo);
+       SendRowDescriptionMessage(typeinfo, targetlist);
 
    /* ----------------
     * We could set up the derived attr info at this time, but we postpone it
@@ -116,9 +116,15 @@ printtup_setup(DestReceiver *self, int operation,
 
 /*
  * SendRowDescriptionMessage --- send a RowDescription message to the frontend
+ *
+ * Notes: the TupleDesc has typically been manufactured by ExecTypeFromTL()
+ * or some similar function; it does not contain a full set of fields.
+ * The targetlist will be NIL when executing a utility function that does
+ * not have a plan.  If the targetlist isn't NIL then it is a Plan node's
+ * targetlist; it is up to us to ignore resjunk columns in it.
  */
 void
-SendRowDescriptionMessage(TupleDesc typeinfo)
+SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist)
 {
    Form_pg_attribute *attrs = typeinfo->attrs;
    int         natts = typeinfo->natts;
@@ -135,9 +141,24 @@ SendRowDescriptionMessage(TupleDesc typeinfo)
        /* column ID info appears in protocol 3.0 and up */
        if (proto >= 3)
        {
-           /* XXX not yet implemented, send zeroes */
-           pq_sendint(&buf, 0, 4);
-           pq_sendint(&buf, 0, 2);
+           /* Do we have a non-resjunk tlist item? */
+           while (targetlist &&
+                  ((TargetEntry *) lfirst(targetlist))->resdom->resjunk)
+               targetlist = lnext(targetlist);
+           if (targetlist)
+           {
+               Resdom     *res = ((TargetEntry *) lfirst(targetlist))->resdom;
+
+               pq_sendint(&buf, res->resorigtbl, 4);
+               pq_sendint(&buf, res->resorigcol, 2);
+               targetlist = lnext(targetlist);
+           }
+           else
+           {
+               /* No info available, so send zeroes */
+               pq_sendint(&buf, 0, 4);
+               pq_sendint(&buf, 0, 2);
+           }
        }
        pq_sendint(&buf, (int) attrs[i]->atttypid,
                   sizeof(attrs[i]->atttypid));
@@ -324,7 +345,7 @@ showatts(const char *name, TupleDesc tupleDesc)
  */
 void
 debugSetup(DestReceiver *self, int operation,
-          const char *portalName, TupleDesc typeinfo)
+          const char *portalName, TupleDesc typeinfo, List *targetlist)
 {
    /*
     * show the return type of the tuples
index d117d2e9a23e05f4fb967fb8c37cad3e1db291bd..2504d69fd063d1284848fd7e1b036cb280e43436 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.106 2003/04/24 21:16:42 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.107 2003/05/06 00:20:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,8 +57,9 @@ static void show_upper_qual(List *qual, const char *qlabel,
                const char *outer_name, int outer_varno, Plan *outer_plan,
                const char *inner_name, int inner_varno, Plan *inner_plan,
                StringInfo str, int indent, ExplainState *es);
-static void show_sort_keys(List *tlist, int nkeys, const char *qlabel,
-              StringInfo str, int indent, ExplainState *es);
+static void show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
+                          const char *qlabel,
+                          StringInfo str, int indent, ExplainState *es);
 static Node *make_ors_ands_explicit(List *orclauses);
 
 /*
@@ -193,18 +194,10 @@ ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
    ExplainState *es;
    StringInfo  str;
 
-   /*
-    * If we are not going to execute, suppress any SELECT INTO marker.
-    * Without this, ExecutorStart will create the INTO target table,
-    * which we don't want.
-    */
-   if (!stmt->analyze)
-       queryDesc->parsetree->into = NULL;
-
    gettimeofday(&starttime, NULL);
 
    /* call ExecutorStart to prepare the plan for execution */
-   ExecutorStart(queryDesc);
+   ExecutorStart(queryDesc, !stmt->analyze);
 
    /* Execute the plan for statistics if asked for */
    if (stmt->analyze)
@@ -672,7 +665,9 @@ explain_outNode(StringInfo str,
                            str, indent, es);
            break;
        case T_Sort:
-           show_sort_keys(plan->targetlist, ((Sort *) plan)->keycount,
+           show_sort_keys(plan->targetlist,
+                          ((Sort *) plan)->numCols,
+                          ((Sort *) plan)->sortColIdx,
                           "Sort Key",
                           str, indent, es);
            break;
@@ -937,7 +932,8 @@ show_upper_qual(List *qual, const char *qlabel,
  * Show the sort keys for a Sort node.
  */
 static void
-show_sort_keys(List *tlist, int nkeys, const char *qlabel,
+show_sort_keys(List *tlist, int nkeys, AttrNumber *keycols,
+              const char *qlabel,
               StringInfo str, int indent, ExplainState *es)
 {
    List       *context;
@@ -985,27 +981,30 @@ show_sort_keys(List *tlist, int nkeys, const char *qlabel,
    }
    bms_free(varnos);
 
-   for (keyno = 1; keyno <= nkeys; keyno++)
+   for (keyno = 0; keyno < nkeys; keyno++)
    {
        /* find key expression in tlist */
+       AttrNumber  keyresno = keycols[keyno];
+
        foreach(tl, tlist)
        {
            TargetEntry *target = (TargetEntry *) lfirst(tl);
 
-           if (target->resdom->reskey == keyno)
+           if (target->resdom->resno == keyresno)
            {
                /* Deparse the expression, showing any top-level cast */
                exprstr = deparse_expression((Node *) target->expr, context,
                                             useprefix, true);
                /* And add to str */
-               if (keyno > 1)
+               if (keyno > 0)
                    appendStringInfo(str, ", ");
                appendStringInfo(str, "%s", exprstr);
                break;
            }
        }
        if (tl == NIL)
-           elog(ERROR, "show_sort_keys: no tlist entry for key %d", keyno);
+           elog(ERROR, "show_sort_keys: no tlist entry for key %d",
+                keyresno);
    }
 
    appendStringInfo(str, "\n");
index d70b3379217f29f0dda8e64a9453b4059a5b7f67..719c94565625cd600c3f5c1fcad090811947ad4d 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.206 2003/05/05 17:57:47 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.207 2003/05/06 00:20:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -63,7 +63,7 @@ typedef struct evalPlanQual
 } evalPlanQual;
 
 /* decls for local routines only used within this module */
-static void InitPlan(QueryDesc *queryDesc);
+static void InitPlan(QueryDesc *queryDesc, bool explainOnly);
 static void initResultRelInfo(ResultRelInfo *resultRelInfo,
                  Index resultRelationIndex,
                  List *rangeTable,
@@ -104,12 +104,15 @@ static void EvalPlanQualStop(evalPlanQual *epq);
  * field of the QueryDesc is filled in to describe the tuples that will be
  * returned, and the internal fields (estate and planstate) are set up.
  *
+ * If explainOnly is true, we are not actually intending to run the plan,
+ * only to set up for EXPLAIN; so skip unwanted side-effects.
+ *
  * NB: the CurrentMemoryContext when this is called will become the parent
  * of the per-query context used for this Executor invocation.
  * ----------------------------------------------------------------
  */
 void
-ExecutorStart(QueryDesc *queryDesc)
+ExecutorStart(QueryDesc *queryDesc, bool explainOnly)
 {
    EState     *estate;
    MemoryContext oldcontext;
@@ -118,6 +121,13 @@ ExecutorStart(QueryDesc *queryDesc)
    Assert(queryDesc != NULL);
    Assert(queryDesc->estate == NULL);
 
+   /*
+    * If the transaction is read-only, we need to check if any writes
+    * are planned to non-temporary tables.
+    */
+   if (!explainOnly)
+       ExecCheckXactReadOnly(queryDesc->parsetree, queryDesc->operation);
+
    /*
     * Build EState, switch into per-query memory context for startup.
     */
@@ -149,7 +159,7 @@ ExecutorStart(QueryDesc *queryDesc)
    /*
     * Initialize the plan state tree
     */
-   InitPlan(queryDesc);
+   InitPlan(queryDesc, explainOnly);
 
    MemoryContextSwitchTo(oldcontext);
 }
@@ -202,14 +212,6 @@ ExecutorRun(QueryDesc *queryDesc,
    operation = queryDesc->operation;
    dest = queryDesc->dest;
 
-   /*
-    * If the transaction is read-only, we need to check if any writes
-    * are planned to non-temporary tables.  This is done here at this
-    * rather late stage so that we can handle EXPLAIN vs. EXPLAIN
-    * ANALYZE easily.
-    */
-   ExecCheckXactReadOnly(queryDesc->parsetree, operation);
-
    /*
     * startup tuple receiver
     */
@@ -217,8 +219,10 @@ ExecutorRun(QueryDesc *queryDesc,
    estate->es_lastoid = InvalidOid;
 
    destfunc = DestToFunction(dest);
-   (*destfunc->setup) (destfunc, operation, queryDesc->portalName,
-                       queryDesc->tupDesc);
+   (*destfunc->setup) (destfunc, operation,
+                       queryDesc->portalName,
+                       queryDesc->tupDesc,
+                       queryDesc->planstate->plan->targetlist);
 
    /*
     * run plan
@@ -468,7 +472,7 @@ fail:
  * ----------------------------------------------------------------
  */
 static void
-InitPlan(QueryDesc *queryDesc)
+InitPlan(QueryDesc *queryDesc, bool explainOnly)
 {
    CmdType     operation = queryDesc->operation;
    Query *parseTree = queryDesc->parsetree;
@@ -751,10 +755,12 @@ InitPlan(QueryDesc *queryDesc)
     * If doing SELECT INTO, initialize the "into" relation.  We must wait
     * till now so we have the "clean" result tuple type to create the
     * new table from.
+    *
+    * If EXPLAIN, skip creating the "into" relation.
     */
    intoRelationDesc = (Relation) NULL;
 
-   if (do_select_into)
+   if (do_select_into && !explainOnly)
    {
        char       *intoName;
        Oid         namespaceId;
index 2e7291a006dbb5cace4875a1a7d3c1d2a548cdd8..c81dd33d36a2547dc7f83ee5bca36e435ca47504 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.63 2002/12/13 19:45:52 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.64 2003/05/06 00:20:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -723,7 +723,7 @@ begin_tup_output_tupdesc(CommandDest dest, TupleDesc tupdesc)
    tstate->destfunc = DestToFunction(dest);
 
    (*tstate->destfunc->setup) (tstate->destfunc, (int) CMD_SELECT,
-                               NULL, tupdesc);
+                               NULL, tupdesc, NIL);
 
    return tstate;
 }
index d3ccf0dd90576b0c265555843350c6166b03d2f3..ba41828be3493d8ab39b66020891f3156ea20372 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.62 2002/12/15 16:17:46 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.63 2003/05/06 00:20:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -250,7 +250,7 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
 
    /* Utility commands don't need Executor. */
    if (es->qd->operation != CMD_UTILITY)
-       ExecutorStart(es->qd);
+       ExecutorStart(es->qd, false);
 
    es->status = F_EXEC_RUN;
 }
index 2be31ce09e809ad9451cfda698a725495cbfcbc8..468b91af9bbc1dbbb19b97beba9281656eae493e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.43 2003/05/05 17:57:47 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/nodeSort.c,v 1.44 2003/05/06 00:20:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "executor/nodeSort.h"
 #include "utils/tuplesort.h"
 
-/* ----------------------------------------------------------------
- *     ExtractSortKeys
- *
- *     Extract the sorting key information from the plan node.
- *
- *     Returns two palloc'd arrays, one of sort operator OIDs and
- *     one of attribute numbers.
- * ----------------------------------------------------------------
- */
-static void
-ExtractSortKeys(Sort *sortnode,
-               Oid **sortOperators,
-               AttrNumber **attNums)
-{
-   List       *targetList;
-   int         keycount;
-   Oid        *sortOps;
-   AttrNumber *attNos;
-   List       *tl;
-
-   /*
-    * get information from the node
-    */
-   targetList = sortnode->plan.targetlist;
-   keycount = sortnode->keycount;
-
-   /*
-    * first allocate space for results
-    */
-   if (keycount <= 0)
-       elog(ERROR, "ExtractSortKeys: keycount <= 0");
-   sortOps = (Oid *) palloc0(keycount * sizeof(Oid));
-   *sortOperators = sortOps;
-   attNos = (AttrNumber *) palloc0(keycount * sizeof(AttrNumber));
-   *attNums = attNos;
-
-   /*
-    * extract info from the resdom nodes in the target list
-    */
-   foreach(tl, targetList)
-   {
-       TargetEntry *target = (TargetEntry *) lfirst(tl);
-       Resdom     *resdom = target->resdom;
-       Index       reskey = resdom->reskey;
-
-       if (reskey > 0)         /* ignore TLEs that are not sort keys */
-       {
-           Assert(reskey <= keycount);
-           sortOps[reskey - 1] = resdom->reskeyop;
-           attNos[reskey - 1] = resdom->resno;
-       }
-   }
-}
 
 /* ----------------------------------------------------------------
  *     ExecSort
@@ -118,8 +65,6 @@ ExecSort(SortState *node)
        Sort       *plannode = (Sort *) node->ss.ps.plan;
        PlanState  *outerNode;
        TupleDesc   tupDesc;
-       Oid        *sortOperators;
-       AttrNumber *attNums;
 
        SO1_printf("ExecSort: %s\n",
                   "sorting subplan");
@@ -139,16 +84,13 @@ ExecSort(SortState *node)
        outerNode = outerPlanState(node);
        tupDesc = ExecGetResultType(outerNode);
 
-       ExtractSortKeys(plannode, &sortOperators, &attNums);
-
-       tuplesortstate = tuplesort_begin_heap(tupDesc, plannode->keycount,
-                                             sortOperators, attNums,
+       tuplesortstate = tuplesort_begin_heap(tupDesc,
+                                             plannode->numCols,
+                                             plannode->sortOperators,
+                                             plannode->sortColIdx,
                                              true /* randomAccess */ );
        node->tuplesortstate = (void *) tuplesortstate;
 
-       pfree(sortOperators);
-       pfree(attNums);
-
        /*
         * Scan the subplan and feed all the tuples to tuplesort.
         */
index 3b1e6c4bb3f99472ebd7e7b624e910c41891c6c1..74299ddf3ea9fe24928cdc2c743f775500211706 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.94 2003/05/02 20:54:34 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.95 2003/05/06 00:20:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -880,7 +880,7 @@ SPI_cursor_close(Portal portal)
  */
 void
 spi_dest_setup(DestReceiver *self, int operation,
-              const char *portalName, TupleDesc typeinfo)
+              const char *portalName, TupleDesc typeinfo, List *targetlist)
 {
    SPITupleTable *tuptable;
    MemoryContext oldcxt;
@@ -1209,7 +1209,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
        ResetUsage();
 #endif
 
-   ExecutorStart(queryDesc);
+   ExecutorStart(queryDesc, false);
 
    ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount);
 
index c4d16ef5e9846081e799b42f1bef7313501fb6ca..05b0c1f2397660282299ef6eb2f24528e869fe08 100644 (file)
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.3 2003/05/02 20:54:34 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.4 2003/05/06 00:20:31 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,7 +40,8 @@ typedef struct
  */
 static void
 tstoreSetupReceiver(DestReceiver *self, int operation,
-                   const char *portalname, TupleDesc typeinfo)
+                   const char *portalname,
+                   TupleDesc typeinfo, List *targetlist)
 {
    TStoreState *myState = (TStoreState *) self;
 
index 4c773657fe49bfed6e3b159bcfd147255df465e9..1dc79a4dc40834121169a4231b34f788097d1287 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.249 2003/05/02 20:54:34 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.250 2003/05/06 00:20:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -448,7 +448,9 @@ _copySort(Sort *from)
     */
    CopyPlanFields((Plan *) from, (Plan *) newnode);
 
-   COPY_SCALAR_FIELD(keycount);
+   COPY_SCALAR_FIELD(numCols);
+   COPY_POINTER_FIELD(sortColIdx, from->numCols * sizeof(AttrNumber));
+   COPY_POINTER_FIELD(sortOperators, from->numCols * sizeof(Oid));
 
    return newnode;
 }
@@ -596,8 +598,8 @@ _copyResdom(Resdom *from)
    COPY_SCALAR_FIELD(restypmod);
    COPY_STRING_FIELD(resname);
    COPY_SCALAR_FIELD(ressortgroupref);
-   COPY_SCALAR_FIELD(reskey);
-   COPY_SCALAR_FIELD(reskeyop);
+   COPY_SCALAR_FIELD(resorigtbl);
+   COPY_SCALAR_FIELD(resorigcol);
    COPY_SCALAR_FIELD(resjunk);
 
    return newnode;
index e4c10ed968665f4759c3e8eaf5ed413bddf3eff2..6b9cac028b990d87b128231ca10adf7f579c7188 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.192 2003/05/02 20:54:34 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.193 2003/05/06 00:20:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -104,8 +104,8 @@ _equalResdom(Resdom *a, Resdom *b)
    COMPARE_SCALAR_FIELD(restypmod);
    COMPARE_STRING_FIELD(resname);
    COMPARE_SCALAR_FIELD(ressortgroupref);
-   COMPARE_SCALAR_FIELD(reskey);
-   COMPARE_SCALAR_FIELD(reskeyop);
+   COMPARE_SCALAR_FIELD(resorigtbl);
+   COMPARE_SCALAR_FIELD(resorigcol);
    COMPARE_SCALAR_FIELD(resjunk);
 
    return true;
index e9f10720cbb2b0bb29bc07ac8e96b7a337751e39..4683d36bfbcdf4a16b078c01601dd0f5aa59ea10 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.38 2003/02/10 04:44:45 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.39 2003/05/06 00:20:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -117,16 +117,16 @@ makeResdom(AttrNumber resno,
    resdom->resname = resname;
 
    /*
-    * We always set the sorting/grouping fields to 0.  If the caller
-    * wants to change them he must do so explicitly.  Few if any callers
-    * should be doing that, so omitting these arguments reduces the
-    * chance of error.
+    * We always set these fields to 0. If the caller wants to change them
+    * he must do so explicitly.  Few callers do that, so omitting these
+    * arguments reduces the chance of error.
     */
    resdom->ressortgroupref = 0;
-   resdom->reskey = 0;
-   resdom->reskeyop = InvalidOid;
+   resdom->resorigtbl = InvalidOid;
+   resdom->resorigcol = 0;
 
    resdom->resjunk = resjunk;
+
    return resdom;
 }
 
index 654905b09628138f92dc6dc7ae8578b51e8bc1bb..377c6bd2297b54fbb4490ed8f9af6d35e4999ace 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.204 2003/05/02 20:54:34 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.205 2003/05/06 00:20:32 tgl Exp $
  *
  * NOTES
  *   Every node type that can appear in stored rules' parsetrees *must*
@@ -420,11 +420,17 @@ _outAgg(StringInfo str, Agg *node)
 static void
 _outGroup(StringInfo str, Group *node)
 {
-   WRITE_NODE_TYPE("GRP");
+   int         i;
+
+   WRITE_NODE_TYPE("GROUP");
 
    _outPlanInfo(str, (Plan *) node);
 
    WRITE_INT_FIELD(numCols);
+
+   appendStringInfo(str, " :grpColIdx");
+   for (i = 0; i < node->numCols; i++)
+       appendStringInfo(str, " %d", node->grpColIdx[i]);
 }
 
 static void
@@ -438,11 +444,21 @@ _outMaterial(StringInfo str, Material *node)
 static void
 _outSort(StringInfo str, Sort *node)
 {
+   int         i;
+
    WRITE_NODE_TYPE("SORT");
 
    _outPlanInfo(str, (Plan *) node);
 
-   WRITE_INT_FIELD(keycount);
+   WRITE_INT_FIELD(numCols);
+
+   appendStringInfo(str, " :sortColIdx");
+   for (i = 0; i < node->numCols; i++)
+       appendStringInfo(str, " %d", node->sortColIdx[i]);
+
+   appendStringInfo(str, " :sortOperators");
+   for (i = 0; i < node->numCols; i++)
+       appendStringInfo(str, " %u", node->sortOperators[i]);
 }
 
 static void
@@ -517,8 +533,8 @@ _outResdom(StringInfo str, Resdom *node)
    WRITE_INT_FIELD(restypmod);
    WRITE_STRING_FIELD(resname);
    WRITE_UINT_FIELD(ressortgroupref);
-   WRITE_UINT_FIELD(reskey);
-   WRITE_OID_FIELD(reskeyop);
+   WRITE_OID_FIELD(resorigtbl);
+   WRITE_INT_FIELD(resorigcol);
    WRITE_BOOL_FIELD(resjunk);
 }
 
index ccfa923c726612c155aef64712597cb86faf9e37..6e8c0d7bf079a89d9264be86f10a13d31b9da3ae 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.60 2003/01/22 19:26:35 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.61 2003/05/06 00:20:32 tgl Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -447,8 +447,8 @@ print_tl(List *tlist, List *rtable)
        TargetEntry *tle = lfirst(tl);
 
        printf("\t%d %s\t", tle->resdom->resno, tle->resdom->resname);
-       if (tle->resdom->reskey != 0)
-           printf("(%d):\t", tle->resdom->reskey);
+       if (tle->resdom->ressortgroupref != 0)
+           printf("(%u):\t", tle->resdom->ressortgroupref);
        else
            printf("    :\t");
        print_expr((Node *) tle->expr, rtable);
index 3c8e7501f434c6626e8b369a9918f44c33f31118..68daca4b5551557b25b113539b2d56543bbe0482 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.152 2003/05/02 20:54:34 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.153 2003/05/06 00:20:32 tgl Exp $
  *
  * NOTES
  *   Path and Plan nodes do not have any readfuncs support, because we
@@ -310,8 +310,8 @@ _readResdom(void)
    READ_INT_FIELD(restypmod);
    READ_STRING_FIELD(resname);
    READ_UINT_FIELD(ressortgroupref);
-   READ_UINT_FIELD(reskey);
-   READ_OID_FIELD(reskeyop);
+   READ_OID_FIELD(resorigtbl);
+   READ_INT_FIELD(resorigcol);
    READ_BOOL_FIELD(resjunk);
 
    READ_DONE();
index d01acdc6182afb172913718bc904bcc2cea1378c..b491065f03df42f93e9a5b97a16edd33e0b932ba 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.138 2003/03/10 03:53:50 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.139 2003/05/06 00:20:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -101,6 +101,8 @@ static MergeJoin *make_mergejoin(List *tlist,
               List *mergeclauses,
               Plan *lefttree, Plan *righttree,
               JoinType jointype);
+static Sort *make_sort(Query *root, List *tlist, Plan *lefttree, int numCols,
+                      AttrNumber *sortColIdx, Oid *sortOperators);
 static Sort *make_sort_from_pathkeys(Query *root, Plan *lefttree,
                                     Relids relids, List *pathkeys);
 
@@ -576,7 +578,7 @@ create_unique_plan(Query *root, UniquePath *best_path)
            subplan->targetlist = newtlist;
    }
 
-   my_tlist = new_unsorted_tlist(subplan->targetlist);
+   my_tlist = copyObject(subplan->targetlist);
 
    if (best_path->use_hash)
    {
@@ -1614,13 +1616,13 @@ make_mergejoin(List *tlist,
 }
 
 /*
- * To use make_sort directly, you must already have marked the tlist
- * with reskey and reskeyop information.  The keys had better be
- * non-redundant, too (ie, there had better be tlist items marked with
- * each key number from 1 to keycount), or the executor will get confused!
+ * make_sort --- basic routine to build a Sort plan node
+ *
+ * Caller must have built the sortColIdx and sortOperators arrays already.
  */
-Sort *
-make_sort(Query *root, List *tlist, Plan *lefttree, int keycount)
+static Sort *
+make_sort(Query *root, List *tlist, Plan *lefttree, int numCols,
+         AttrNumber *sortColIdx, Oid *sortOperators)
 {
    Sort       *node = makeNode(Sort);
    Plan       *plan = &node->plan;
@@ -1637,11 +1639,43 @@ make_sort(Query *root, List *tlist, Plan *lefttree, int keycount)
    plan->qual = NIL;
    plan->lefttree = lefttree;
    plan->righttree = NULL;
-   node->keycount = keycount;
+   node->numCols = numCols;
+   node->sortColIdx = sortColIdx;
+   node->sortOperators = sortOperators;
 
    return node;
 }
 
+/*
+ * add_sort_column --- utility subroutine for building sort info arrays
+ *
+ * We need this routine because the same column might be selected more than
+ * once as a sort key column; if so, the extra mentions are redundant.
+ *
+ * Caller is assumed to have allocated the arrays large enough for the
+ * max possible number of columns.  Return value is the new column count.
+ */
+static int
+add_sort_column(AttrNumber colIdx, Oid sortOp,
+               int numCols, AttrNumber *sortColIdx, Oid *sortOperators)
+{
+   int         i;
+
+   for (i = 0; i < numCols; i++)
+   {
+       if (sortColIdx[i] == colIdx)
+       {
+           /* Already sorting by this col, so extra sort key is useless */
+           return numCols;
+       }
+   }
+
+   /* Add the column */
+   sortColIdx[numCols] = colIdx;
+   sortOperators[numCols] = sortOp;
+   return numCols + 1;
+}
+
 /*
  * make_sort_from_pathkeys
  *   Create sort plan to sort according to given pathkeys
@@ -1650,8 +1684,8 @@ make_sort(Query *root, List *tlist, Plan *lefttree, int keycount)
  *   'relids' is the set of relids represented by the input node
  *   'pathkeys' is the list of pathkeys by which the result is to be sorted
  *
- * We must convert the pathkey information into reskey and reskeyop fields
- * of resdom nodes in the sort plan's target list.
+ * We must convert the pathkey information into arrays of sort key column
+ * numbers and sort operator OIDs.
  *
  * If the pathkeys include expressions that aren't simple Vars, we will
  * usually need to add resjunk items to the input plan's targetlist to
@@ -1666,10 +1700,16 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
    List       *tlist = lefttree->targetlist;
    List       *sort_tlist;
    List       *i;
-   int         numsortkeys = 0;
+   int         numsortkeys;
+   AttrNumber *sortColIdx;
+   Oid        *sortOperators;
 
-   /* Create a new target list for the sort, with sort keys set. */
-   sort_tlist = new_unsorted_tlist(tlist);
+   /* We will need at most length(pathkeys) sort columns; possibly less */
+   numsortkeys = length(pathkeys);
+   sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
+   sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
+
+   numsortkeys = 0;
 
    foreach(i, pathkeys)
    {
@@ -1681,7 +1721,7 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
        /*
         * We can sort by any one of the sort key items listed in this
         * sublist.  For now, we take the first one that corresponds to an
-        * available Var in the sort_tlist.  If there isn't any, use the
+        * available Var in the tlist.  If there isn't any, use the
         * first one that is an expression in the input's vars.
         *
         * XXX if we have a choice, is there any way of figuring out which
@@ -1694,7 +1734,7 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
        {
            pathkey = lfirst(j);
            Assert(IsA(pathkey, PathKeyItem));
-           resdom = tlist_member(pathkey->key, sort_tlist);
+           resdom = tlist_member(pathkey->key, tlist);
            if (resdom)
                break;
        }
@@ -1717,7 +1757,7 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
             */
            if (IsA(lefttree, Append))
            {
-               tlist = new_unsorted_tlist(tlist);
+               tlist = copyObject(tlist);
                lefttree = (Plan *) make_result(tlist, NULL, lefttree);
            }
            /*
@@ -1732,38 +1772,24 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree,
                            makeTargetEntry(resdom,
                                            (Expr *) pathkey->key));
            lefttree->targetlist = tlist; /* just in case NIL before */
-           /*
-            * Add one to sort node's tlist too.  This will be identical
-            * except we are going to set the sort key info in it.
-            */
-           resdom = makeResdom(length(sort_tlist) + 1,
-                               exprType(pathkey->key),
-                               exprTypmod(pathkey->key),
-                               NULL,
-                               true);
-           sort_tlist = lappend(sort_tlist,
-                                makeTargetEntry(resdom,
-                                                (Expr *) pathkey->key));
        }
        /*
-        * The resdom might be already marked as a sort key, if the
+        * The column might already be selected as a sort key, if the
         * pathkeys contain duplicate entries.  (This can happen in
         * scenarios where multiple mergejoinable clauses mention the same
-        * var, for example.) In that case the current pathkey is
-        * essentially a no-op, because only one value can be seen within
-        * any subgroup where it would be consulted.  We can ignore it.
+        * var, for example.)  So enter it only once in the sort arrays.
         */
-       if (resdom->reskey == 0)
-       {
-           /* OK, mark it as a sort key and set the sort operator */
-           resdom->reskey = ++numsortkeys;
-           resdom->reskeyop = pathkey->sortop;
-       }
+       numsortkeys = add_sort_column(resdom->resno, pathkey->sortop,
+                                     numsortkeys, sortColIdx, sortOperators);
    }
 
    Assert(numsortkeys > 0);
 
-   return make_sort(root, sort_tlist, lefttree, numsortkeys);
+   /* Give Sort node its own copy of the tlist (still necessary?) */
+   sort_tlist = copyObject(tlist);
+
+   return make_sort(root, sort_tlist, lefttree, numsortkeys,
+                    sortColIdx, sortOperators);
 }
 
 /*
@@ -1780,36 +1806,96 @@ make_sort_from_sortclauses(Query *root, List *tlist,
 {
    List       *sort_tlist;
    List       *i;
-   int         keyno = 0;
+   int         numsortkeys;
+   AttrNumber *sortColIdx;
+   Oid        *sortOperators;
 
-   /*
-    * First make a copy of the tlist so that we don't corrupt the
-    * original.
-    */
-   sort_tlist = new_unsorted_tlist(tlist);
+   /* We will need at most length(sortcls) sort columns; possibly less */
+   numsortkeys = length(sortcls);
+   sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
+   sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
+
+   numsortkeys = 0;
 
    foreach(i, sortcls)
    {
        SortClause *sortcl = (SortClause *) lfirst(i);
-       TargetEntry *tle = get_sortgroupclause_tle(sortcl, sort_tlist);
+       TargetEntry *tle = get_sortgroupclause_tle(sortcl, tlist);
        Resdom     *resdom = tle->resdom;
 
        /*
         * Check for the possibility of duplicate order-by clauses --- the
-        * parser should have removed 'em, but the executor will get
-        * terribly confused if any get through!
+        * parser should have removed 'em, but no point in sorting redundantly.
         */
-       if (resdom->reskey == 0)
-       {
-           /* OK, insert the ordering info needed by the executor. */
-           resdom->reskey = ++keyno;
-           resdom->reskeyop = sortcl->sortop;
-       }
+       numsortkeys = add_sort_column(resdom->resno, sortcl->sortop,
+                                     numsortkeys, sortColIdx, sortOperators);
    }
 
-   Assert(keyno > 0);
+   Assert(numsortkeys > 0);
+
+   /* Give Sort node its own copy of the tlist (still necessary?) */
+   sort_tlist = copyObject(tlist);
+
+   return make_sort(root, sort_tlist, lefttree, numsortkeys,
+                    sortColIdx, sortOperators);
+}
+
+/*
+ * make_sort_from_groupcols
+ *   Create sort plan to sort based on grouping columns
+ *
+ * 'groupcls' is the list of GroupClauses
+ * 'grpColIdx' gives the column numbers to use
+ *
+ * This might look like it could be merged with make_sort_from_sortclauses,
+ * but presently we *must* use the grpColIdx[] array to locate sort columns,
+ * because the child plan's tlist is not marked with ressortgroupref info
+ * appropriate to the grouping node.  So, only the sortop is used from the
+ * GroupClause entries.
+ */
+Sort *
+make_sort_from_groupcols(Query *root,
+                        List *groupcls,
+                        AttrNumber *grpColIdx,
+                        Plan *lefttree)
+{
+   List       *sub_tlist = lefttree->targetlist;
+   List       *sort_tlist;
+   int         grpno = 0;
+   List       *i;
+   int         numsortkeys;
+   AttrNumber *sortColIdx;
+   Oid        *sortOperators;
+
+   /* We will need at most length(groupcls) sort columns; possibly less */
+   numsortkeys = length(groupcls);
+   sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
+   sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
+
+   numsortkeys = 0;
+
+   foreach(i, groupcls)
+   {
+       GroupClause *grpcl = (GroupClause *) lfirst(i);
+       TargetEntry *tle = nth(grpColIdx[grpno] - 1, sub_tlist);
+       Resdom     *resdom = tle->resdom;
+
+       /*
+        * Check for the possibility of duplicate group-by clauses --- the
+        * parser should have removed 'em, but no point in sorting redundantly.
+        */
+       numsortkeys = add_sort_column(resdom->resno, grpcl->sortop,
+                                     numsortkeys, sortColIdx, sortOperators);
+       grpno++;
+   }
+
+   Assert(numsortkeys > 0);
+
+   /* Give Sort node its own copy of the tlist (still necessary?) */
+   sort_tlist = copyObject(sub_tlist);
 
-   return make_sort(root, sort_tlist, lefttree, keyno);
+   return make_sort(root, sort_tlist, lefttree, numsortkeys,
+                    sortColIdx, sortOperators);
 }
 
 Material *
index e53a18ac296e07ff7e763c81d837fe58d8f44aab..eca7a908f7a5ab57cafa58343092e7069cf1c260 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.152 2003/03/13 16:58:35 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.153 2003/05/06 00:20:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,10 +61,6 @@ static void locate_grouping_columns(Query *parse,
                                    List *tlist,
                                    List *sub_tlist,
                                    AttrNumber *groupColIdx);
-static Plan *make_groupsortplan(Query *parse,
-                               List *groupClause,
-                               AttrNumber *grpColIdx,
-                               Plan *subplan);
 static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
 
 
@@ -1145,10 +1141,11 @@ grouping_planner(Query *parse, double tuple_fraction)
            {
                if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))
                {
-                   result_plan = make_groupsortplan(parse,
-                                                    parse->groupClause,
-                                                    groupColIdx,
-                                                    result_plan);
+                   result_plan = (Plan *)
+                       make_sort_from_groupcols(parse,
+                                                parse->groupClause,
+                                                groupColIdx,
+                                                result_plan);
                    current_pathkeys = group_pathkeys;
                }
                aggstrategy = AGG_SORTED;
@@ -1193,10 +1190,11 @@ grouping_planner(Query *parse, double tuple_fraction)
                 */
                if (!pathkeys_contained_in(group_pathkeys, current_pathkeys))
                {
-                   result_plan = make_groupsortplan(parse,
-                                                    parse->groupClause,
-                                                    groupColIdx,
-                                                    result_plan);
+                   result_plan = (Plan *)
+                       make_sort_from_groupcols(parse,
+                                                parse->groupClause,
+                                                groupColIdx,
+                                                result_plan);
                    current_pathkeys = group_pathkeys;
                }
 
@@ -1219,10 +1217,11 @@ grouping_planner(Query *parse, double tuple_fraction)
    {
        if (!pathkeys_contained_in(sort_pathkeys, current_pathkeys))
        {
-           result_plan = (Plan *) make_sort_from_sortclauses(parse,
-                                                             tlist,
-                                                             result_plan,
-                                                             parse->sortClause);
+           result_plan = (Plan *)
+               make_sort_from_sortclauses(parse,
+                                          tlist,
+                                          result_plan,
+                                          parse->sortClause);
            current_pathkeys = sort_pathkeys;
        }
    }
@@ -1471,53 +1470,6 @@ locate_grouping_columns(Query *parse,
    }
 }
 
-/*
- * make_groupsortplan
- *     Add a Sort node to explicitly sort according to the GROUP BY clause.
- *
- * Note: the Sort node always just takes a copy of the subplan's tlist
- * plus ordering information.  (This might seem inefficient if the
- * subplan contains complex GROUP BY expressions, but in fact Sort
- * does not evaluate its targetlist --- it only outputs the same
- * tuples in a new order.  So the expressions we might be copying
- * are just dummies with no extra execution cost.)
- */
-static Plan *
-make_groupsortplan(Query *parse,
-                  List *groupClause,
-                  AttrNumber *grpColIdx,
-                  Plan *subplan)
-{
-   List       *sort_tlist = new_unsorted_tlist(subplan->targetlist);
-   int         grpno = 0;
-   int         keyno = 0;
-   List       *gl;
-
-   foreach(gl, groupClause)
-   {
-       GroupClause *grpcl = (GroupClause *) lfirst(gl);
-       TargetEntry *te = nth(grpColIdx[grpno] - 1, sort_tlist);
-       Resdom     *resdom = te->resdom;
-
-       /*
-        * Check for the possibility of duplicate group-by clauses ---
-        * the parser should have removed 'em, but the Sort executor
-        * will get terribly confused if any get through!
-        */
-       if (resdom->reskey == 0)
-       {
-           /* OK, insert the ordering info needed by the executor. */
-           resdom->reskey = ++keyno;
-           resdom->reskeyop = grpcl->sortop;
-       }
-       grpno++;
-   }
-
-   Assert(keyno > 0);
-
-   return (Plan *) make_sort(parse, sort_tlist, subplan, keyno);
-}
-
 /*
  * postprocess_setop_tlist
  *   Fix up targetlist returned by plan_set_operations().
index d2b91c2ec6d23510c92c9e6c6fca594ad830e57b..86a52645fe674a0571c2a8c9c0d122c247e609d1 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.94 2003/04/29 22:13:09 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.95 2003/05/06 00:20:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -238,7 +238,7 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
    {
        List       *sortList;
 
-       tlist = new_unsorted_tlist(tlist);
+       tlist = copyObject(tlist);
        sortList = addAllTargetsToSortList(NIL, tlist);
        plan = (Plan *) make_sort_from_sortclauses(parse, tlist,
                                                   plan, sortList);
@@ -292,7 +292,7 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
     * Sort the child results, then add a SetOp plan node to generate the
     * correct output.
     */
-   tlist = new_unsorted_tlist(tlist);
+   tlist = copyObject(tlist);
    sortList = addAllTargetsToSortList(NIL, tlist);
    plan = (Plan *) make_sort_from_sortclauses(parse, tlist, plan, sortList);
    switch (op->op)
index 53d5615cb0b8879f343d4c88c4a7063a73c227a2..9b10e8e97be34fc03b09c6460a458570e25472b9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.55 2003/02/15 20:12:40 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.56 2003/05/06 00:20:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -117,32 +117,6 @@ create_tl_element(Var *var, int resdomno)
  *     ---------- GENERAL target list routines ----------
  *****************************************************************************/
 
-/*
- * new_unsorted_tlist
- *   Creates a copy of a target list by creating new resdom nodes
- *   without sort information.
- *
- * 'targetlist' is the target list to be copied.
- *
- * Returns the resulting target list.
- *
- */
-List *
-new_unsorted_tlist(List *targetlist)
-{
-   List       *new_targetlist = (List *) copyObject((Node *) targetlist);
-   List       *x;
-
-   foreach(x, new_targetlist)
-   {
-       TargetEntry *tle = (TargetEntry *) lfirst(x);
-
-       tle->resdom->reskey = 0;
-       tle->resdom->reskeyop = (Oid) 0;
-   }
-   return new_targetlist;
-}
-
 /*
  * flatten_tlist
  *   Create a target list that only contains unique variables.
index ad2d5ab5681b9be914f340fd2d4a8a70fc65ee61..b7fc22c46bea5d45c9e5f182fd116e70a249ac92 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.270 2003/05/05 00:44:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.271 2003/05/06 00:20:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1747,6 +1747,9 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
    if (stmt->intoColNames)
        applyColumnNames(qry->targetList, stmt->intoColNames);
 
+   /* mark column origins */
+   markTargetListOrigins(pstate, qry->targetList);
+
    /* transform WHERE */
    qual = transformWhereClause(pstate, stmt->whereClause);
 
index dc8f241d45ea6e03450f4ace313a3c997a8b11ca..10892bc292d73014c9645a36e2b2b25ad30150d9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.100 2003/04/29 22:13:10 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.101 2003/05/06 00:20:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,6 +26,7 @@
 #include "utils/builtins.h"
 
 
+static void markTargetListOrigin(ParseState *pstate, Resdom *res, Var *var);
 static List *ExpandAllTables(ParseState *pstate);
 static char *FigureColname(Node *node);
 static int FigureColnameInternal(Node *node, char **name);
@@ -204,6 +205,94 @@ transformTargetList(ParseState *pstate, List *targetlist)
 }
 
 
+/*
+ * markTargetListOrigins()
+ *     Mark targetlist columns that are simple Vars with the source
+ *     table's OID and column number.
+ *
+ * Currently, this is done only for SELECT targetlists, since we only
+ * need the info if we are going to send it to the frontend.
+ */
+void
+markTargetListOrigins(ParseState *pstate, List *targetlist)
+{
+   List       *l;
+
+   foreach(l, targetlist)
+   {
+       TargetEntry *tle = (TargetEntry *) lfirst(l);
+
+       markTargetListOrigin(pstate, tle->resdom, (Var *) tle->expr);
+   }
+}
+
+/*
+ * markTargetListOrigin()
+ *     If 'var' is a Var of a plain relation, mark 'res' with its origin
+ *
+ * This is split out so it can recurse for join references.  Note that we
+ * do not drill down into views, but report the view as the column owner.
+ */
+static void
+markTargetListOrigin(ParseState *pstate, Resdom *res, Var *var)
+{
+   RangeTblEntry *rte;
+   AttrNumber  attnum;
+
+   if (var == NULL || !IsA(var, Var))
+       return;
+   Assert(var->varno > 0 &&
+          (int) var->varno <= length(pstate->p_rtable));
+   rte = rt_fetch(var->varno, pstate->p_rtable);
+   attnum = var->varattno;
+
+   switch (rte->rtekind)
+   {
+       case RTE_RELATION:
+           /* It's a table or view, report it */
+           res->resorigtbl = rte->relid;
+           res->resorigcol = attnum;
+           break;
+       case RTE_SUBQUERY:
+           {
+               /* Subselect-in-FROM: copy up from the subselect */
+               List       *subtl;
+
+               foreach(subtl, rte->subquery->targetList)
+               {
+                   TargetEntry *subte = (TargetEntry *) lfirst(subtl);
+
+                   if (subte->resdom->resjunk ||
+                       subte->resdom->resno != attnum)
+                       continue;
+                   res->resorigtbl = subte->resdom->resorigtbl;
+                   res->resorigcol = subte->resdom->resorigcol;
+                   break;
+               }
+               /* falling off end of list shouldn't happen... */
+               if (subtl == NIL)
+                   elog(ERROR, "Subquery %s does not have attribute %d",
+                        rte->eref->aliasname, attnum);
+           }
+           break;
+       case RTE_JOIN:
+           {
+               /* Join RTE --- recursively inspect the alias variable */
+               Var    *aliasvar;
+
+               Assert(attnum > 0 && attnum <= length(rte->joinaliasvars));
+               aliasvar = (Var *) nth(attnum - 1, rte->joinaliasvars);
+               markTargetListOrigin(pstate, res, aliasvar);
+           }
+           break;
+       case RTE_SPECIAL:
+       case RTE_FUNCTION:
+           /* not a simple relation, leave it unmarked */
+           break;
+   }
+}
+
+
 /*
  * updateTargetListEntry()
  * This is used in INSERT and UPDATE statements only.  It prepares a
index a5905dedc7fd93ebfb6bf252057e36d6cc6f02a1..54b5ef75c1a530fca7153b8ec10ae7a95c4ced8d 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.55 2003/05/05 00:44:56 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.56 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,7 +46,7 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
 
 static void
 donothingSetup(DestReceiver *self, int operation,
-              const char *portalName, TupleDesc typeinfo)
+              const char *portalName, TupleDesc typeinfo, List *targetlist)
 {
 }
 
index d57ccd973b2665d3ef199119ce1cea3baad9c51e..d9172655e2a22c5d798e70292f709887c18452f2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.332 2003/05/05 00:44:56 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.333 2003/05/06 00:20:33 tgl Exp $
  *
  * NOTES
  *   this is the "main" module of the postgres backend and
@@ -1460,7 +1460,15 @@ exec_describe_portal_message(const char *portal_name)
        return;                 /* can't actually do anything... */
 
    if (portal->tupDesc)
-       SendRowDescriptionMessage(portal->tupDesc);
+   {
+       List   *targetlist;
+
+       if (portal->strategy == PORTAL_ONE_SELECT)
+           targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist;
+       else
+           targetlist = NIL;
+       SendRowDescriptionMessage(portal->tupDesc, targetlist);
+   }
    else
        pq_putemptymessage('n');    /* NoData */
 }
@@ -2335,7 +2343,7 @@ PostgresMain(int argc, char *argv[], const char *username)
    if (!IsUnderPostmaster)
    {
        puts("\nPOSTGRES backend interactive interface ");
-       puts("$Revision: 1.332 $ $Date: 2003/05/05 00:44:56 $\n");
+       puts("$Revision: 1.333 $ $Date: 2003/05/06 00:20:33 $\n");
    }
 
    /*
index f70b91322445713f14921f0930037dd5b2b11acf..280f269c8f8fadf6feddd12f0ae4e052eebcb878 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.60 2003/05/02 20:54:35 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.61 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,7 +136,7 @@ ProcessQuery(Query *parsetree,
    /*
     * Call ExecStart to prepare the plan for execution
     */
-   ExecutorStart(queryDesc);
+   ExecutorStart(queryDesc, false);
 
    /*
     * Run the plan to completion.
@@ -256,7 +256,7 @@ PortalStart(Portal portal, ParamListInfo params)
            /*
             * Call ExecStart to prepare the plan for execution
             */
-           ExecutorStart(queryDesc);
+           ExecutorStart(queryDesc, false);
            /*
             * This tells PortalCleanup to shut down the executor
             */
@@ -571,10 +571,18 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
             CommandDest dest)
 {
    DestReceiver *destfunc;
+   List       *targetlist;
    long        current_tuple_count = 0;
 
    destfunc = DestToFunction(dest);
-   (*destfunc->setup) (destfunc, CMD_SELECT, portal->name, portal->tupDesc);
+
+   if (portal->strategy == PORTAL_ONE_SELECT)
+       targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist;
+   else
+       targetlist = NIL;
+
+   (*destfunc->setup) (destfunc, CMD_SELECT, portal->name, portal->tupDesc,
+                       targetlist);
 
    if (direction == NoMovementScanDirection)
    {
index 688a75cd2db48b340c050472309e3d3660428aac..c4c92fb1bb677022694ac519b42e038d8baf6f99 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: printtup.h,v 1.24 2003/05/05 00:44:56 tgl Exp $
+ * $Id: printtup.h,v 1.25 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 extern DestReceiver *printtup_create_DR(bool isBinary, bool sendDescrip);
 
-extern void SendRowDescriptionMessage(TupleDesc typeinfo);
+extern void SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist);
 
 extern void debugSetup(DestReceiver *self, int operation,
-          const char *portalName, TupleDesc typeinfo);
+          const char *portalName, TupleDesc typeinfo, List *targetlist);
 extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
         DestReceiver *self);
 
 /* XXX these are really in executor/spi.c */
 extern void spi_dest_setup(DestReceiver *self, int operation,
-          const char *portalName, TupleDesc typeinfo);
+          const char *portalName, TupleDesc typeinfo, List *targetlist);
 extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc,
             DestReceiver *self);
 
index 0c14811682d4e053e8b5044031d168452043eb62..74e36730c5432a73fe110afaeec20041b710512c 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.185 2003/05/02 20:54:35 tgl Exp $
+ * $Id: catversion.h,v 1.186 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 200305011
+#define CATALOG_VERSION_NO 200305051
 
 #endif
index 9693435977d15fef28c244d36531c32b9ed93613..302bc2681ceaa0bf4a8b2a54d8868e38c72be9a0 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: executor.h,v 1.92 2003/05/05 17:57:47 tgl Exp $
+ * $Id: executor.h,v 1.93 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -82,7 +82,7 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
 /*
  * prototypes from functions in execMain.c
  */
-extern void ExecutorStart(QueryDesc *queryDesc);
+extern void ExecutorStart(QueryDesc *queryDesc, bool explainOnly);
 extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
            ScanDirection direction, long count);
 extern void ExecutorEnd(QueryDesc *queryDesc);
index 2ca16b63272e16030a518996abda1707798dba71..9db779d8bf939358d34579dde781b8b077c6abc5 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plannodes.h,v 1.64 2003/02/09 00:30:40 tgl Exp $
+ * $Id: plannodes.h,v 1.65 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -278,7 +278,9 @@ typedef struct Material
 typedef struct Sort
 {
    Plan        plan;
-   int         keycount;
+   int         numCols;        /* number of sort-key columns */
+   AttrNumber *sortColIdx;     /* their indexes in the target list */
+   Oid        *sortOperators;  /* OIDs of operators to sort them by */
 } Sort;
 
 /* ---------------
index 35e2ab26278719f619914a8411cb20d3d93e7cc8..558621c900610d1a870318c3d7182cf3ee316219 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.81 2003/04/08 23:20:04 tgl Exp $
+ * $Id: primnodes.h,v 1.82 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  * Resdom (Result Domain)
  *
  * Notes:
- * ressortgroupref is the parse/plan-time representation of ORDER BY and
+ *
+ * resno will normally be equal to the item's position in a targetlist,
+ * but the code generally tries to avoid relying on that (eg, we avoid
+ * using "nth()" rather than a search to find an item by resno).
+ *
+ * resname will be null if no name can easily be assigned to the column.
+ * But it should never be null for user-visible columns (i.e., non-junk
+ * columns in a toplevel targetlist).
+ *
+ * ressortgroupref is used in the representation of ORDER BY and
  * GROUP BY items. Targetlist entries with ressortgroupref=0 are not
  * sort/group items.  If ressortgroupref>0, then this item is an ORDER BY or
  * GROUP BY value. No two entries in a targetlist may have the same nonzero
  * ressortgroupref means a more significant sort key.) The order of the
  * associated SortClause or GroupClause lists determine the semantics.
  *
- * reskey and reskeyop are the execution-time representation of sorting.
- * reskey must be zero in any non-sort-key item.  The reskey of sort key
- * targetlist items for a sort plan node is 1,2,...,n for the n sort keys.
- * The reskeyop of each such targetlist item is the sort operator's OID.
- * reskeyop will be zero in non-sort-key items.
+ * resorigtbl/resorigcol identify the source of the column, if it is a
+ * simple reference to a column of a base table (or view).  If it is not
+ * a simple reference, these fields are zeroes.
  *
- * Both reskey and reskeyop are typically zero during parse/plan stages.
- * The executor does not pay any attention to ressortgroupref.
+ * If resjunk is true then the column is a working column (such as a sort key)
+ * that should be removed from the final output of the query.
  *--------------------
  */
 typedef struct Resdom
 {
    NodeTag     type;
-   AttrNumber  resno;          /* attribute number */
+   AttrNumber  resno;          /* attribute number (1..N) */
    Oid         restype;        /* type of the value */
    int32       restypmod;      /* type-specific modifier of the value */
-   char       *resname;        /* name of the resdom (could be NULL) */
-   Index       ressortgroupref;
-   /* nonzero if referenced by a sort/group clause */
-   Index       reskey;         /* order of key in a sort (for those > 0) */
-   Oid         reskeyop;       /* sort operator's Oid */
+   char       *resname;        /* name of the column (could be NULL) */
+   Index       ressortgroupref;    /* nonzero if referenced by a
+                                    * sort/group clause */
+   Oid         resorigtbl;     /* OID of column's source table */
+   AttrNumber  resorigcol;     /* column's number in source table */
    bool        resjunk;        /* set to true to eliminate the attribute
                                 * from final target list */
 } Resdom;
index bd1d757e6a7d90f8e061832cc41c76c99eed380d..35a85e311abf325185210153c7283bea5b116964 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: planmain.h,v 1.69 2003/03/10 03:53:52 tgl Exp $
+ * $Id: planmain.h,v 1.70 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,10 +30,10 @@ extern Plan *create_plan(Query *root, Path *best_path);
 extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
                  Index scanrelid, Plan *subplan);
 extern Append *make_append(List *appendplans, bool isTarget, List *tlist);
-extern Sort *make_sort(Query *root, List *tlist,
-         Plan *lefttree, int keycount);
 extern Sort *make_sort_from_sortclauses(Query *root, List *tlist,
                                        Plan *lefttree, List *sortcls);
+extern Sort *make_sort_from_groupcols(Query *root, List *groupcls,
+                                     AttrNumber *grpColIdx, Plan *lefttree);
 extern Agg *make_agg(Query *root, List *tlist, List *qual,
                     AggStrategy aggstrategy,
                     int numGroupCols, AttrNumber *grpColIdx,
index bce5db6c55cf1a378ea81f40de1b9a8414b7ba86..e2afc3ac82192fbb2074bb78e14628039aaef964 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: tlist.h,v 1.34 2003/02/15 20:12:41 tgl Exp $
+ * $Id: tlist.h,v 1.35 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,7 +22,6 @@ extern Resdom *tlist_member(Node *node, List *targetlist);
 extern void add_var_to_tlist(RelOptInfo *rel, Var *var);
 extern TargetEntry *create_tl_element(Var *var, int resdomno);
 
-extern List *new_unsorted_tlist(List *targetlist);
 extern List *flatten_tlist(List *tlist);
 extern List *add_to_flat_tlist(List *tlist, List *vars);
 
index b89ed3a30d6643fcd7f2c9c52358aaf27fa407dd..880673800ae54d2a15c290c4a35469081af15912 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_target.h,v 1.29 2003/02/13 05:53:46 momjian Exp $
+ * $Id: parse_target.h,v 1.30 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 
 
 extern List *transformTargetList(ParseState *pstate, List *targetlist);
+extern void markTargetListOrigins(ParseState *pstate, List *targetlist);
 extern TargetEntry *transformTargetEntry(ParseState *pstate,
                     Node *node, Node *expr,
                     char *colname, bool resjunk);
index 5fbe9d33afebd39d890af3952da8dc8637d18521..be2338b7f34e2557e211f106819e8ddfdc76d783 100644 (file)
@@ -44,7 +44,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: dest.h,v 1.35 2003/05/05 00:44:56 tgl Exp $
+ * $Id: dest.h,v 1.36 2003/05/06 00:20:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -92,10 +92,12 @@ 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, int operation,
-                            const char *portalName, TupleDesc typeinfo);
+                         const char *portalName,
+                         TupleDesc typeinfo,
+                         List *targetlist);
    void        (*cleanup) (DestReceiver *self);
    /* Private fields might appear beyond this point... */
 };