Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit dcc685d

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 52897e5 commit dcc685d

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
@@ -1065,6 +1065,11 @@ SS_process_ctes(PlannerInfo *root)
10651065
* (Notionally, we replace the SubLink with a constant TRUE, then elide the
10661066
* redundant constant from the qual.)
10671067
*
1068+
* On success, the caller is also responsible for recursively applying
1069+
* pull_up_sublinks processing to the rarg and quals of the returned JoinExpr.
1070+
* (On failure, there is no need to do anything, since pull_up_sublinks will
1071+
* be applied when we recursively plan the sub-select.)
1072+
*
10681073
* Side effects of a successful conversion include adding the SubLink's
10691074
* subselect to the query's rangetable, so that it can be referenced in
10701075
* the JoinExpr's rarg.

src/backend/optimizer/prep/prepjointree.c

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

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

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

0 commit comments

Comments
 (0)