diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index 584233c1873f569788fa521708b85decdc04c6e1..27d6ffd508e48000c77b9ac8489c09e36307c70c 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -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 diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index d117d2e9a23e05f4fb967fb8c37cad3e1db291bd..2504d69fd063d1284848fd7e1b036cb280e43436 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -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"); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index d70b3379217f29f0dda8e64a9453b4059a5b7f67..719c94565625cd600c3f5c1fcad090811947ad4d 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -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; diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 2e7291a006dbb5cace4875a1a7d3c1d2a548cdd8..c81dd33d36a2547dc7f83ee5bca36e435ca47504 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -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; } diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index d3ccf0dd90576b0c265555843350c6166b03d2f3..ba41828be3493d8ab39b66020891f3156ea20372 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -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; } diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c index 2be31ce09e809ad9451cfda698a725495cbfcbc8..468b91af9bbc1dbbb19b97beba9281656eae493e 100644 --- a/src/backend/executor/nodeSort.c +++ b/src/backend/executor/nodeSort.c @@ -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 $ * *------------------------------------------------------------------------- */ @@ -19,59 +19,6 @@ #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. */ diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 3b1e6c4bb3f99472ebd7e7b624e910c41891c6c1..74299ddf3ea9fe24928cdc2c743f775500211706 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -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); diff --git a/src/backend/executor/tstoreReceiver.c b/src/backend/executor/tstoreReceiver.c index c4d16ef5e9846081e799b42f1bef7313501fb6ca..05b0c1f2397660282299ef6eb2f24528e869fe08 100644 --- a/src/backend/executor/tstoreReceiver.c +++ b/src/backend/executor/tstoreReceiver.c @@ -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; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 4c773657fe49bfed6e3b159bcfd147255df465e9..1dc79a4dc40834121169a4231b34f788097d1287 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -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; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index e4c10ed968665f4759c3e8eaf5ed413bddf3eff2..6b9cac028b990d87b128231ca10adf7f579c7188 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -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; diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index e9f10720cbb2b0bb29bc07ac8e96b7a337751e39..4683d36bfbcdf4a16b078c01601dd0f5aa59ea10 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -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; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 654905b09628138f92dc6dc7ae8578b51e8bc1bb..377c6bd2297b54fbb4490ed8f9af6d35e4999ace 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -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); } diff --git a/src/backend/nodes/print.c b/src/backend/nodes/print.c index ccfa923c726612c155aef64712597cb86faf9e37..6e8c0d7bf079a89d9264be86f10a13d31b9da3ae 100644 --- a/src/backend/nodes/print.c +++ b/src/backend/nodes/print.c @@ -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); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 3c8e7501f434c6626e8b369a9918f44c33f31118..68daca4b5551557b25b113539b2d56543bbe0482 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -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(); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index d01acdc6182afb172913718bc904bcc2cea1378c..b491065f03df42f93e9a5b97a16edd33e0b932ba 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -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 * diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index e53a18ac296e07ff7e763c81d837fe58d8f44aab..eca7a908f7a5ab57cafa58343092e7069cf1c260 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -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(). diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index d2b91c2ec6d23510c92c9e6c6fca594ad830e57b..86a52645fe674a0571c2a8c9c0d122c247e609d1 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -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) diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c index 53d5615cb0b8879f343d4c88c4a7063a73c227a2..9b10e8e97be34fc03b09c6460a458570e25472b9 100644 --- a/src/backend/optimizer/util/tlist.c +++ b/src/backend/optimizer/util/tlist.c @@ -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. diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index ad2d5ab5681b9be914f340fd2d4a8a70fc65ee61..b7fc22c46bea5d45c9e5f182fd116e70a249ac92 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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); diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index dc8f241d45ea6e03450f4ace313a3c997a8b11ca..10892bc292d73014c9645a36e2b2b25ad30150d9 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -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 diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c index a5905dedc7fd93ebfb6bf252057e36d6cc6f02a1..54b5ef75c1a530fca7153b8ec10ae7a95c4ced8d 100644 --- a/src/backend/tcop/dest.c +++ b/src/backend/tcop/dest.c @@ -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) { } diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index d57ccd973b2665d3ef199119ce1cea3baad9c51e..d9172655e2a22c5d798e70292f709887c18452f2 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -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"); } /* diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index f70b91322445713f14921f0930037dd5b2b11acf..280f269c8f8fadf6feddd12f0ae4e052eebcb878 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -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) { diff --git a/src/include/access/printtup.h b/src/include/access/printtup.h index 688a75cd2db48b340c050472309e3d3660428aac..c4c92fb1bb677022694ac519b42e038d8baf6f99 100644 --- a/src/include/access/printtup.h +++ b/src/include/access/printtup.h @@ -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 $ * *------------------------------------------------------------------------- */ @@ -18,16 +18,16 @@ 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); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 0c14811682d4e053e8b5044031d168452043eb62..74e36730c5432a73fe110afaeec20041b710512c 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -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 diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 9693435977d15fef28c244d36531c32b9ed93613..302bc2681ceaa0bf4a8b2a54d8868e38c72be9a0 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -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); diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 2ca16b63272e16030a518996abda1707798dba71..9db779d8bf939358d34579dde781b8b077c6abc5 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -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; /* --------------- diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 35e2ab26278719f619914a8411cb20d3d93e7cc8..558621c900610d1a870318c3d7182cf3ee316219 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -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 $ * *------------------------------------------------------------------------- */ @@ -30,7 +30,16 @@ * 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 @@ -39,27 +48,25 @@ * 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; diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index bd1d757e6a7d90f8e061832cc41c76c99eed380d..35a85e311abf325185210153c7283bea5b116964 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -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, diff --git a/src/include/optimizer/tlist.h b/src/include/optimizer/tlist.h index bce5db6c55cf1a378ea81f40de1b9a8414b7ba86..e2afc3ac82192fbb2074bb78e14628039aaef964 100644 --- a/src/include/optimizer/tlist.h +++ b/src/include/optimizer/tlist.h @@ -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); diff --git a/src/include/parser/parse_target.h b/src/include/parser/parse_target.h index b89ed3a30d6643fcd7f2c9c52358aaf27fa407dd..880673800ae54d2a15c290c4a35469081af15912 100644 --- a/src/include/parser/parse_target.h +++ b/src/include/parser/parse_target.h @@ -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); diff --git a/src/include/tcop/dest.h b/src/include/tcop/dest.h index 5fbe9d33afebd39d890af3952da8dc8637d18521..be2338b7f34e2557e211f106819e8ddfdc76d783 100644 --- a/src/include/tcop/dest.h +++ b/src/include/tcop/dest.h @@ -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... */ };