*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.151 2003/08/04 02:40:00 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.152 2003/08/07 19:20:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
Plan *plan;
Plan *subplan;
- List *sub_targetlist;
+ List *uniq_exprs;
+ int numGroupCols;
+ AttrNumber *groupColIdx;
+ int groupColPos;
+ List *newtlist;
+ int nextresno;
+ bool newitems;
List *my_tlist;
List *l;
subplan = create_plan(root, best_path->subpath);
/*
- * If the subplan came from an IN subselect (currently always the
- * case), we need to instantiate the correct output targetlist for the
- * subselect, rather than using the flattened tlist.
+ * As constructed, the subplan has a "flat" tlist containing just the
+ * Vars needed here and at upper levels. The values we are supposed
+ * to unique-ify may be expressions in these variables. We have to
+ * add any such expressions to the subplan's tlist. We then build
+ * control information showing which subplan output columns are to be
+ * examined by the grouping step. (Since we do not remove any existing
+ * subplan outputs, not all the output columns may be used for grouping.)
+ *
+ * Note: the reason we don't remove any subplan outputs is that there
+ * are scenarios where a Var is needed at higher levels even though it
+ * is not one of the nominal outputs of an IN clause. Consider
+ * WHERE x IN (SELECT y FROM t1,t2 WHERE y = z)
+ * Implied equality deduction will generate an "x = z" clause, which may
+ * get used instead of "x = y" in the upper join step. Therefore the
+ * sub-select had better deliver both y and z in its targetlist. It is
+ * sufficient to unique-ify on y, however.
+ *
+ * To find the correct list of values to unique-ify, we look in the
+ * information saved for IN expressions. If this code is ever used in
+ * other scenarios, some other way of finding what to unique-ify will
+ * be needed.
*/
- sub_targetlist = NIL;
+ uniq_exprs = NIL; /* just to keep compiler quiet */
foreach(l, root->in_info_list)
{
InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);
if (bms_equal(ininfo->righthand, best_path->path.parent->relids))
{
- sub_targetlist = ininfo->sub_targetlist;
+ uniq_exprs = ininfo->sub_targetlist;
break;
}
}
-
- if (sub_targetlist)
+ if (l == NIL) /* fell out of loop? */
+ elog(ERROR, "could not find UniquePath in in_info_list");
+
+ /* set up to record positions of unique columns */
+ numGroupCols = length(uniq_exprs);
+ groupColIdx = (AttrNumber *) palloc(numGroupCols * sizeof(AttrNumber));
+ groupColPos = 0;
+ /* not sure if tlist might be shared with other nodes, so copy */
+ newtlist = copyObject(subplan->targetlist);
+ nextresno = length(newtlist) + 1;
+ newitems = false;
+
+ foreach(l, uniq_exprs)
{
- /*
- * Transform list of plain Vars into targetlist
- */
- List *newtlist = NIL;
- int resno = 1;
+ Node *uniqexpr = lfirst(l);
+ TargetEntry *tle;
- foreach(l, sub_targetlist)
+ tle = tlistentry_member(uniqexpr, newtlist);
+ if (!tle)
{
- Node *tlexpr = lfirst(l);
- TargetEntry *tle;
-
- tle = makeTargetEntry(makeResdom(resno,
- exprType(tlexpr),
- exprTypmod(tlexpr),
+ tle = makeTargetEntry(makeResdom(nextresno,
+ exprType(uniqexpr),
+ exprTypmod(uniqexpr),
NULL,
false),
- (Expr *) tlexpr);
+ (Expr *) uniqexpr);
newtlist = lappend(newtlist, tle);
- resno++;
+ nextresno++;
+ newitems = true;
}
+ groupColIdx[groupColPos++] = tle->resdom->resno;
+ }
+ if (newitems)
+ {
/*
* If the top plan node can't do projections, we need to add a
* Result node to help it along.
subplan->targetlist = newtlist;
}
+ /* Copy tlist again to make one we can put sorting labels on */
my_tlist = copyObject(subplan->targetlist);
if (best_path->use_hash)
{
- int numGroupCols = length(my_tlist);
long numGroups;
- AttrNumber *groupColIdx;
- int i;
numGroups = (long) Min(best_path->rows, (double) LONG_MAX);
- groupColIdx = (AttrNumber *) palloc(numGroupCols * sizeof(AttrNumber));
- for (i = 0; i < numGroupCols; i++)
- groupColIdx[i] = i + 1;
-
plan = (Plan *) make_agg(root,
my_tlist,
NIL,
}
else
{
- List *sortList;
+ List *sortList = NIL;
- sortList = addAllTargetsToSortList(NULL, NIL, my_tlist, false);
+ for (groupColPos = 0; groupColPos < numGroupCols; groupColPos++)
+ {
+ TargetEntry *tle;
+
+ tle = nth(groupColIdx[groupColPos] - 1, my_tlist);
+ Assert(tle->resdom->resno == groupColIdx[groupColPos]);
+ sortList = addTargetToSortList(NULL, tle, sortList,
+ my_tlist, NIL, false);
+ }
plan = (Plan *) make_sort_from_sortclauses(root, my_tlist,
subplan, sortList);
plan = (Plan *) make_unique(my_tlist, plan, sortList);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.120 2003/08/04 02:40:01 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.121 2003/08/07 19:20:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Var *l_colvar, Var *r_colvar);
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
List *tlist, int clause);
-static List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
- List *sortlist, List *targetlist,
- List *opname, bool resolveUnknown);
/*
*
* Returns the updated ORDER BY list.
*/
-static List *
+List *
addTargetToSortList(ParseState *pstate, TargetEntry *tle,
List *sortlist, List *targetlist,
List *opname, bool resolveUnknown)
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_clause.h,v 1.35 2003/08/04 02:40:14 momjian Exp $
+ * $Id: parse_clause.h,v 1.36 2003/08/07 19:20:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern List *addAllTargetsToSortList(ParseState *pstate,
List *sortlist, List *targetlist,
bool resolveUnknown);
+extern List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
+ List *sortlist, List *targetlist,
+ List *opname, bool resolveUnknown);
extern Index assignSortGroupRef(TargetEntry *tle, List *tlist);
extern bool targetIsInSortList(TargetEntry *tle, List *sortList);