diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index 5d163292c5..ac622a34d9 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -246,6 +246,7 @@ pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode, * as a sublink that is executed only for row pairs that meet the * other join conditions. Fixing this seems to require considerable * restructuring of the executor, but maybe someday it can happen. + * (See also the comparable case in pull_up_sublinks_qual_recurse.) * * We don't expect to see any pre-existing JOIN_SEMI or JOIN_ANTI * nodes here. @@ -331,9 +332,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg, &child_rels); - /* Pulled-up ANY/EXISTS quals can use those rels too */ - child_rels = bms_add_members(child_rels, available_rels); - /* ... and any inserted joins get stacked onto j->rarg */ + /* Any inserted joins get stacked onto j->rarg */ j->quals = pull_up_sublinks_qual_recurse(root, j->quals, child_rels, @@ -355,9 +354,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg, &child_rels); - /* Pulled-up ANY/EXISTS quals can use those rels too */ - child_rels = bms_add_members(child_rels, available_rels); - /* ... and any inserted joins get stacked onto j->rarg */ + /* Any inserted joins get stacked onto j->rarg */ j->quals = pull_up_sublinks_qual_recurse(root, j->quals, child_rels, @@ -377,7 +374,6 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, /* If the immediate argument of NOT is EXISTS, try to convert */ SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node); JoinExpr *j; - Relids child_rels; if (sublink && IsA(sublink, SubLink)) { @@ -387,17 +383,27 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, available_rels); if (j) { + /* + * For the moment, refrain from recursing underneath NOT. + * As in pull_up_sublinks_jointree_recurse, recursing here + * would result in inserting a join underneath an ANTI + * join with which it could not commute, and that could + * easily lead to a worse plan than what we've + * historically generated. + */ +#ifdef NOT_USED /* Yes; recursively process what we pulled up */ + Relids child_rels; + j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg, &child_rels); - /* Pulled-up ANY/EXISTS quals can use those rels too */ - child_rels = bms_add_members(child_rels, available_rels); - /* ... and any inserted joins get stacked onto j->rarg */ + /* Any inserted joins get stacked onto j->rarg */ j->quals = pull_up_sublinks_qual_recurse(root, j->quals, child_rels, &j->rarg); +#endif /* Now insert the new join node into the join tree */ j->larg = *jtlink; *jtlink = (Node *) j; diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index 2440dcd822..8f180b9b19 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -530,3 +530,15 @@ select '1'::text in (select '1'::name union all select '1'::name); t (1 row) +-- +-- Test case for planner bug with nested EXISTS handling +-- +select a.thousand from tenk1 a, tenk1 b +where a.thousand = b.thousand + and exists ( select 1 from tenk1 c where b.hundred = c.hundred + and not exists ( select 1 from tenk1 d + where a.thousand = d.thousand ) ); + thousand +---------- +(0 rows) + diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql index 296e38b8c1..0d117c878f 100644 --- a/src/test/regress/sql/subselect.sql +++ b/src/test/regress/sql/subselect.sql @@ -341,3 +341,12 @@ from -- select '1'::text in (select '1'::name union all select '1'::name); + +-- +-- Test case for planner bug with nested EXISTS handling +-- +select a.thousand from tenk1 a, tenk1 b +where a.thousand = b.thousand + and exists ( select 1 from tenk1 c where b.hundred = c.hundred + and not exists ( select 1 from tenk1 d + where a.thousand = d.thousand ) );