summaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
authorTom Lane2003-05-06 00:20:33 +0000
committerTom Lane2003-05-06 00:20:33 +0000
commit2cf57c8f8d060711c1ad7e1dd6cc1115a2839b47 (patch)
treeb3b2a9616d425072d26cfc57efcbe676c56b399e /src/backend/optimizer
parent94a3c60324465f98850b60f548c1ea481ab4e52f (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.c200
-rw-r--r--src/backend/optimizer/plan/planner.c80
-rw-r--r--src/backend/optimizer/prep/prepunion.c6
-rw-r--r--src/backend/optimizer/util/tlist.c28
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.
*