1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-29 23:43:17 +03:00

Get rid of the rather fuzzily defined FlattenedSubLink node type in favor of

making pull_up_sublinks() construct a full-blown JoinExpr tree representation
of IN/EXISTS SubLinks that it is able to convert to semi or anti joins.
This makes pull_up_sublinks() a shade more complex, but the gain in semantic
clarity is worth it.  I still have more to do in this area to address the
previously-discussed problems, but this commit in itself fixes at least one
bug in HEAD, as shown by added regression test case.
This commit is contained in:
Tom Lane
2009-02-25 03:30:38 +00:00
parent 7380b6384b
commit e549722a8b
18 changed files with 298 additions and 496 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.147 2009/02/20 00:01:03 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.148 2009/02/25 03:30:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -52,9 +52,6 @@ static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
Relids qualscope,
Relids ojscope,
Relids outerjoin_nonnullable);
static void distribute_sublink_quals_to_rels(PlannerInfo *root,
FlattenedSubLink *fslink,
bool below_outer_join);
static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
bool is_pushed_down);
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
@@ -336,15 +333,9 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
/* FlattenedSubLink wrappers need special processing */
if (qual && IsA(qual, FlattenedSubLink))
distribute_sublink_quals_to_rels(root,
(FlattenedSubLink *) qual,
below_outer_join);
else
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
*qualscope, NULL, NULL);
distribute_qual_to_rels(root, qual,
false, below_outer_join, JOIN_INNER,
*qualscope, NULL, NULL);
}
}
else if (IsA(jtnode, JoinExpr))
@@ -399,6 +390,18 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
*inner_join_rels = bms_union(left_inners, right_inners);
nonnullable_rels = leftids;
break;
case JOIN_SEMI:
leftjoinlist = deconstruct_recurse(root, j->larg,
below_outer_join,
&leftids, &left_inners);
rightjoinlist = deconstruct_recurse(root, j->rarg,
below_outer_join,
&rightids, &right_inners);
*qualscope = bms_union(leftids, rightids);
*inner_join_rels = bms_union(left_inners, right_inners);
/* Semi join adds no restrictions for quals */
nonnullable_rels = NULL;
break;
case JOIN_FULL:
leftjoinlist = deconstruct_recurse(root, j->larg,
true,
@@ -425,6 +428,9 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
* semantic scope (ojscope) to pass to distribute_qual_to_rels. But
* we mustn't add it to join_info_list just yet, because we don't want
* distribute_qual_to_rels to think it is an outer join below us.
*
* Semijoins are a bit of a hybrid: we build a SpecialJoinInfo,
* but we want ojscope = NULL for distribute_qual_to_rels.
*/
if (j->jointype != JOIN_INNER)
{
@@ -433,7 +439,11 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
*inner_join_rels,
j->jointype,
(List *) j->quals);
ojscope = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
if (j->jointype == JOIN_SEMI)
ojscope = NULL;
else
ojscope = bms_union(sjinfo->min_lefthand,
sjinfo->min_righthand);
}
else
{
@@ -446,16 +456,10 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
{
Node *qual = (Node *) lfirst(l);
/* FlattenedSubLink wrappers need special processing */
if (qual && IsA(qual, FlattenedSubLink))
distribute_sublink_quals_to_rels(root,
(FlattenedSubLink *) qual,
below_outer_join);
else
distribute_qual_to_rels(root, qual,
false, below_outer_join, j->jointype,
*qualscope,
ojscope, nonnullable_rels);
distribute_qual_to_rels(root, qual,
false, below_outer_join, j->jointype,
*qualscope,
ojscope, nonnullable_rels);
}
/* Now we can add the SpecialJoinInfo to join_info_list */
@@ -1044,64 +1048,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
distribute_restrictinfo_to_rels(root, restrictinfo);
}
/*
* distribute_sublink_quals_to_rels
* Pull sublink quals out of a FlattenedSubLink node and distribute
* them appropriately; then add a SpecialJoinInfo node to the query's
* join_info_list. The FlattenedSubLink node itself is no longer
* needed and does not propagate into further processing.
*/
static void
distribute_sublink_quals_to_rels(PlannerInfo *root,
FlattenedSubLink *fslink,
bool below_outer_join)
{
List *quals = make_ands_implicit(fslink->quals);
SpecialJoinInfo *sjinfo;
Relids qualscope;
Relids ojscope;
Relids outerjoin_nonnullable;
ListCell *l;
/*
* Build a suitable SpecialJoinInfo for the sublink. Note: using
* righthand as inner_join_rels is the conservative worst case;
* it might be possible to use a smaller set and thereby allow
* the sublink join to commute with others inside its RHS.
*/
sjinfo = make_outerjoininfo(root,
fslink->lefthand, fslink->righthand,
fslink->righthand,
fslink->jointype,
quals);
/* Treat as inner join if SEMI, outer join if ANTI */
qualscope = bms_union(sjinfo->syn_lefthand, sjinfo->syn_righthand);
if (fslink->jointype == JOIN_SEMI)
{
ojscope = outerjoin_nonnullable = NULL;
}
else
{
Assert(fslink->jointype == JOIN_ANTI);
ojscope = bms_union(sjinfo->min_lefthand, sjinfo->min_righthand);
outerjoin_nonnullable = fslink->lefthand;
}
/* Distribute the join quals much as for a regular JOIN node */
foreach(l, quals)
{
Node *qual = (Node *) lfirst(l);
distribute_qual_to_rels(root, qual,
false, below_outer_join, fslink->jointype,
qualscope, ojscope, outerjoin_nonnullable);
}
/* Now we can add the SpecialJoinInfo to join_info_list */
root->join_info_list = lappend(root->join_info_list, sjinfo);
}
/*
* check_outerjoin_delay
* Detect whether a qual referencing the given relids must be delayed