]> granicus.if.org Git - postgresql/commitdiff
Implement feature of new FE/BE protocol whereby RowDescription identifies
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 6 May 2003 00:20:33 +0000 (00:20 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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... */
 };