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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user