Commit ecbed6e1 authored by Tom Lane's avatar Tom Lane

create_unique_plan() should not discard existing output columns of the

subplan it starts with, as they may be needed at upper join levels.
See comments added to code for the non-obvious reason why.  Per bug report
from Robert Creager.
parent d862045d
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -504,52 +504,87 @@ create_unique_plan(Query *root, UniquePath * best_path) ...@@ -504,52 +504,87 @@ create_unique_plan(Query *root, UniquePath * best_path)
{ {
Plan *plan; Plan *plan;
Plan *subplan; Plan *subplan;
List *sub_targetlist; List *uniq_exprs;
int numGroupCols;
AttrNumber *groupColIdx;
int groupColPos;
List *newtlist;
int nextresno;
bool newitems;
List *my_tlist; List *my_tlist;
List *l; List *l;
subplan = create_plan(root, best_path->subpath); subplan = create_plan(root, best_path->subpath);
/* /*
* If the subplan came from an IN subselect (currently always the * As constructed, the subplan has a "flat" tlist containing just the
* case), we need to instantiate the correct output targetlist for the * Vars needed here and at upper levels. The values we are supposed
* subselect, rather than using the flattened tlist. * 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) foreach(l, root->in_info_list)
{ {
InClauseInfo *ininfo = (InClauseInfo *) lfirst(l); InClauseInfo *ininfo = (InClauseInfo *) lfirst(l);
if (bms_equal(ininfo->righthand, best_path->path.parent->relids)) if (bms_equal(ininfo->righthand, best_path->path.parent->relids))
{ {
sub_targetlist = ininfo->sub_targetlist; uniq_exprs = ininfo->sub_targetlist;
break; break;
} }
} }
if (l == NIL) /* fell out of loop? */
elog(ERROR, "could not find UniquePath in in_info_list");
if (sub_targetlist) /* set up to record positions of unique columns */
{ numGroupCols = length(uniq_exprs);
/* groupColIdx = (AttrNumber *) palloc(numGroupCols * sizeof(AttrNumber));
* Transform list of plain Vars into targetlist groupColPos = 0;
*/ /* not sure if tlist might be shared with other nodes, so copy */
List *newtlist = NIL; newtlist = copyObject(subplan->targetlist);
int resno = 1; nextresno = length(newtlist) + 1;
newitems = false;
foreach(l, sub_targetlist) foreach(l, uniq_exprs)
{ {
Node *tlexpr = lfirst(l); Node *uniqexpr = lfirst(l);
TargetEntry *tle; TargetEntry *tle;
tle = makeTargetEntry(makeResdom(resno, tle = tlistentry_member(uniqexpr, newtlist);
exprType(tlexpr), if (!tle)
exprTypmod(tlexpr), {
tle = makeTargetEntry(makeResdom(nextresno,
exprType(uniqexpr),
exprTypmod(uniqexpr),
NULL, NULL,
false), false),
(Expr *) tlexpr); (Expr *) uniqexpr);
newtlist = lappend(newtlist, tle); 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 * If the top plan node can't do projections, we need to add a
* Result node to help it along. * Result node to help it along.
...@@ -563,21 +598,15 @@ create_unique_plan(Query *root, UniquePath * best_path) ...@@ -563,21 +598,15 @@ create_unique_plan(Query *root, UniquePath * best_path)
subplan->targetlist = newtlist; subplan->targetlist = newtlist;
} }
/* Copy tlist again to make one we can put sorting labels on */
my_tlist = copyObject(subplan->targetlist); my_tlist = copyObject(subplan->targetlist);
if (best_path->use_hash) if (best_path->use_hash)
{ {
int numGroupCols = length(my_tlist);
long numGroups; long numGroups;
AttrNumber *groupColIdx;
int i;
numGroups = (long) Min(best_path->rows, (double) LONG_MAX); 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, plan = (Plan *) make_agg(root,
my_tlist, my_tlist,
NIL, NIL,
...@@ -590,9 +619,17 @@ create_unique_plan(Query *root, UniquePath * best_path) ...@@ -590,9 +619,17 @@ create_unique_plan(Query *root, UniquePath * best_path)
} }
else 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, plan = (Plan *) make_sort_from_sortclauses(root, my_tlist,
subplan, sortList); subplan, sortList);
plan = (Plan *) make_unique(my_tlist, plan, sortList); plan = (Plan *) make_unique(my_tlist, plan, sortList);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -59,9 +59,6 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype, ...@@ -59,9 +59,6 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
Var *l_colvar, Var *r_colvar); Var *l_colvar, Var *r_colvar);
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
List *tlist, int clause); List *tlist, int clause);
static List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
List *sortlist, List *targetlist,
List *opname, bool resolveUnknown);
/* /*
...@@ -1478,7 +1475,7 @@ addAllTargetsToSortList(ParseState *pstate, List *sortlist, ...@@ -1478,7 +1475,7 @@ addAllTargetsToSortList(ParseState *pstate, List *sortlist,
* *
* Returns the updated ORDER BY list. * Returns the updated ORDER BY list.
*/ */
static List * List *
addTargetToSortList(ParseState *pstate, TargetEntry *tle, addTargetToSortList(ParseState *pstate, TargetEntry *tle,
List *sortlist, List *targetlist, List *sortlist, List *targetlist,
List *opname, bool resolveUnknown) List *opname, bool resolveUnknown)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -35,6 +35,9 @@ extern List *transformDistinctClause(ParseState *pstate, List *distinctlist, ...@@ -35,6 +35,9 @@ extern List *transformDistinctClause(ParseState *pstate, List *distinctlist,
extern List *addAllTargetsToSortList(ParseState *pstate, extern List *addAllTargetsToSortList(ParseState *pstate,
List *sortlist, List *targetlist, List *sortlist, List *targetlist,
bool resolveUnknown); 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 Index assignSortGroupRef(TargetEntry *tle, List *tlist);
extern bool targetIsInSortList(TargetEntry *tle, List *sortList); extern bool targetIsInSortList(TargetEntry *tle, List *sortList);
......
...@@ -2127,6 +2127,18 @@ on (x1 = xx1) where (xx2 is not null); ...@@ -2127,6 +2127,18 @@ on (x1 = xx1) where (xx2 is not null);
4 | 44 | 4 | | 4 | 44 4 | 44 | 4 | | 4 | 44
(3 rows) (3 rows)
--
-- regression test: check for bug with propagation of implied equality
-- to outside an IN
--
select count(*) from tenk1 a where unique1 in
(select unique1 from tenk1 b join tenk1 c using (unique1)
where b.unique2 = 42);
count
-------
1
(1 row)
-- --
-- Clean up -- Clean up
-- --
......
...@@ -330,6 +330,14 @@ on (x1 = xx1) where (y2 is not null); ...@@ -330,6 +330,14 @@ on (x1 = xx1) where (y2 is not null);
select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2) select * from (x left join y on (x1 = y1)) left join x xx(xx1,xx2)
on (x1 = xx1) where (xx2 is not null); on (x1 = xx1) where (xx2 is not null);
--
-- regression test: check for bug with propagation of implied equality
-- to outside an IN
--
select count(*) from tenk1 a where unique1 in
(select unique1 from tenk1 b join tenk1 c using (unique1)
where b.unique2 = 42);
-- --
-- Clean up -- Clean up
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment