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.
This commit is contained in:
parent
d862045dfc
commit
ecbed6e1b9
@ -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)
|
|||||||
{
|
{
|
||||||
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));
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
/*
|
Node *uniqexpr = lfirst(l);
|
||||||
* Transform list of plain Vars into targetlist
|
TargetEntry *tle;
|
||||||
*/
|
|
||||||
List *newtlist = NIL;
|
|
||||||
int resno = 1;
|
|
||||||
|
|
||||||
foreach(l, sub_targetlist)
|
tle = tlistentry_member(uniqexpr, newtlist);
|
||||||
|
if (!tle)
|
||||||
{
|
{
|
||||||
Node *tlexpr = lfirst(l);
|
tle = makeTargetEntry(makeResdom(nextresno,
|
||||||
TargetEntry *tle;
|
exprType(uniqexpr),
|
||||||
|
exprTypmod(uniqexpr),
|
||||||
tle = makeTargetEntry(makeResdom(resno,
|
|
||||||
exprType(tlexpr),
|
|
||||||
exprTypmod(tlexpr),
|
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
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,
|
|||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
* 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,
|
|||||||
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);
|
|||||||
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);
|
|||||||
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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user