diff options
author | Tom Lane | 2003-05-06 00:20:33 +0000 |
---|---|---|
committer | Tom Lane | 2003-05-06 00:20:33 +0000 |
commit | 2cf57c8f8d060711c1ad7e1dd6cc1115a2839b47 (patch) | |
tree | b3b2a9616d425072d26cfc57efcbe676c56b399e | |
parent | 94a3c60324465f98850b60f548c1ea481ab4e52f (diff) |
Implement feature of new FE/BE protocol whereby RowDescription identifies
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, 454 insertions, 336 deletions
diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index 584233c1873..27d6ffd508e 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 d117d2e9a23..2504d69fd06 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 d70b3379217..719c9456562 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; @@ -119,6 +122,13 @@ ExecutorStart(QueryDesc *queryDesc) 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. */ estate = CreateExecutorState(); @@ -149,7 +159,7 @@ ExecutorStart(QueryDesc *queryDesc) /* * Initialize the plan state tree */ - InitPlan(queryDesc); + InitPlan(queryDesc, explainOnly); MemoryContextSwitchTo(oldcontext); } @@ -203,22 +213,16 @@ ExecutorRun(QueryDesc *queryDesc, 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 */ estate->es_processed = 0; 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 2e7291a006d..c81dd33d36a 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 d3ccf0dd905..ba41828be34 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 2be31ce09e8..468b91af9bb 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 3b1e6c4bb3f..74299ddf3ea 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 c4d16ef5e98..05b0c1f2397 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 4c773657fe4..1dc79a4dc40 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 e4c10ed9686..6b9cac028b9 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 e9f10720cbb..4683d36bfbc 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 654905b0962..377c6bd2297 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 ccfa923c726..6e8c0d7bf07 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 3c8e7501f43..68daca4b555 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 d01acdc6182..b491065f03d 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,12 +1639,44 @@ 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 e53a18ac296..eca7a908f7a 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; } } @@ -1472,53 +1471,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 d2b91c2ec6d..86a52645fe6 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 53d5615cb0b..9b10e8e97be 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 $ * *------------------------------------------------------------------------- */ @@ -118,32 +118,6 @@ create_tl_element(Var *var, int resdomno) *****************************************************************************/ /* - * 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 ad2d5ab5681..b7fc22c46be 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 dc8f241d45e..10892bc292d 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); @@ -205,6 +206,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 * TargetEntry for assignment to a column of the target table. diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c index a5905dedc7f..54b5ef75c1a 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 d57ccd973b2..d9172655e2a 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 f70b9132244..280f269c8f8 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 688a75cd2db..c4c92fb1bb6 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 0c14811682d..74e36730c54 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 9693435977d..302bc2681ce 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 2ca16b63272..9db779d8bf9 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 35e2ab26278..558621c9006 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 bd1d757e6a7..35a85e311ab 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 bce5db6c55c..e2afc3ac821 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 b89ed3a30d6..880673800ae 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 5fbe9d33afe..be2338b7f34 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... */ }; |