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 /src/backend/optimizer | |
| 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.
Diffstat (limited to 'src/backend/optimizer')
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 200 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 80 | ||||
| -rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 6 | ||||
| -rw-r--r-- | src/backend/optimizer/util/tlist.c | 28 |
4 files changed, 163 insertions, 151 deletions
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. * |
