Skip to content

Commit 65a7cd0

Browse files
committed
Fix pull_up_sublinks' failure to handle nested pull-up opportunities.
After finding an EXISTS or ANY sub-select that can be converted to a semi-join or anti-join, we should recurse into the body of the sub-select. This allows cases such as EXISTS-within-EXISTS to be optimized properly. The original coding would leave the lower sub-select as a SubLink, which is no better and often worse than what we can do with a join. Per example from Wayne Conrad. Back-patch to 8.4. There is a related issue in older versions' handling of pull_up_IN_clauses, but they're lame enough anyway about the whole area that it seems not worth the extra work to try to fix.
1 parent e79518e commit 65a7cd0

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

src/backend/optimizer/plan/subselect.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,11 @@ SS_process_ctes(PlannerInfo *root)
995995
* (Notionally, we replace the SubLink with a constant TRUE, then elide the
996996
* redundant constant from the qual.)
997997
*
998+
* On success, the caller is also responsible for recursively applying
999+
* pull_up_sublinks processing to the rarg and quals of the returned JoinExpr.
1000+
* (On failure, there is no need to do anything, since pull_up_sublinks will
1001+
* be applied when we recursively plan the sub-select.)
1002+
*
9981003
* Side effects of a successful conversion include adding the SubLink's
9991004
* subselect to the query's rangetable, so that it can be referenced in
10001005
* the JoinExpr's rarg.

src/backend/optimizer/prep/prepjointree.c

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
317317
{
318318
SubLink *sublink = (SubLink *) node;
319319
JoinExpr *j;
320+
Relids child_rels;
320321

321322
/* Is it a convertible ANY or EXISTS clause? */
322323
if (sublink->subLinkType == ANY_SUBLINK)
@@ -325,7 +326,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
325326
available_rels);
326327
if (j)
327328
{
328-
/* Yes, insert the new join node into the join tree */
329+
/* Yes; recursively process what we pulled up */
330+
j->rarg = pull_up_sublinks_jointree_recurse(root,
331+
j->rarg,
332+
&child_rels);
333+
/* Pulled-up ANY/EXISTS quals can use those rels too */
334+
child_rels = bms_add_members(child_rels, available_rels);
335+
/* ... and any inserted joins get stacked onto j->rarg */
336+
j->quals = pull_up_sublinks_qual_recurse(root,
337+
j->quals,
338+
child_rels,
339+
&j->rarg);
340+
/* Now insert the new join node into the join tree */
329341
j->larg = *jtlink;
330342
*jtlink = (Node *) j;
331343
/* and return NULL representing constant TRUE */
@@ -338,7 +350,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
338350
available_rels);
339351
if (j)
340352
{
341-
/* Yes, insert the new join node into the join tree */
353+
/* Yes; recursively process what we pulled up */
354+
j->rarg = pull_up_sublinks_jointree_recurse(root,
355+
j->rarg,
356+
&child_rels);
357+
/* Pulled-up ANY/EXISTS quals can use those rels too */
358+
child_rels = bms_add_members(child_rels, available_rels);
359+
/* ... and any inserted joins get stacked onto j->rarg */
360+
j->quals = pull_up_sublinks_qual_recurse(root,
361+
j->quals,
362+
child_rels,
363+
&j->rarg);
364+
/* Now insert the new join node into the join tree */
342365
j->larg = *jtlink;
343366
*jtlink = (Node *) j;
344367
/* and return NULL representing constant TRUE */
@@ -353,6 +376,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
353376
/* If the immediate argument of NOT is EXISTS, try to convert */
354377
SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
355378
JoinExpr *j;
379+
Relids child_rels;
356380

357381
if (sublink && IsA(sublink, SubLink))
358382
{
@@ -362,7 +386,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
362386
available_rels);
363387
if (j)
364388
{
365-
/* Yes, insert the new join node into the join tree */
389+
/* Yes; recursively process what we pulled up */
390+
j->rarg = pull_up_sublinks_jointree_recurse(root,
391+
j->rarg,
392+
&child_rels);
393+
/* Pulled-up ANY/EXISTS quals can use those rels too */
394+
child_rels = bms_add_members(child_rels, available_rels);
395+
/* ... and any inserted joins get stacked onto j->rarg */
396+
j->quals = pull_up_sublinks_qual_recurse(root,
397+
j->quals,
398+
child_rels,
399+
&j->rarg);
400+
/* Now insert the new join node into the join tree */
366401
j->larg = *jtlink;
367402
*jtlink = (Node *) j;
368403
/* and return NULL representing constant TRUE */

0 commit comments

Comments
 (0)