1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-18 17:42:25 +03:00

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.
This commit is contained in:
Tom Lane
2011-05-02 15:56:43 -04:00
parent e79518e937
commit 65a7cd0e9c
2 changed files with 43 additions and 3 deletions

View File

@ -995,6 +995,11 @@ SS_process_ctes(PlannerInfo *root)
* (Notionally, we replace the SubLink with a constant TRUE, then elide the
* redundant constant from the qual.)
*
* On success, the caller is also responsible for recursively applying
* pull_up_sublinks processing to the rarg and quals of the returned JoinExpr.
* (On failure, there is no need to do anything, since pull_up_sublinks will
* be applied when we recursively plan the sub-select.)
*
* Side effects of a successful conversion include adding the SubLink's
* subselect to the query's rangetable, so that it can be referenced in
* the JoinExpr's rarg.

View File

@ -317,6 +317,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
{
SubLink *sublink = (SubLink *) node;
JoinExpr *j;
Relids child_rels;
/* Is it a convertible ANY or EXISTS clause? */
if (sublink->subLinkType == ANY_SUBLINK)
@ -325,7 +326,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
available_rels);
if (j)
{
/* Yes, insert the new join node into the join tree */
/* Yes; recursively process what we pulled up */
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 */
j->quals = pull_up_sublinks_qual_recurse(root,
j->quals,
child_rels,
&j->rarg);
/* Now insert the new join node into the join tree */
j->larg = *jtlink;
*jtlink = (Node *) j;
/* and return NULL representing constant TRUE */
@ -338,7 +350,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
available_rels);
if (j)
{
/* Yes, insert the new join node into the join tree */
/* Yes; recursively process what we pulled up */
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 */
j->quals = pull_up_sublinks_qual_recurse(root,
j->quals,
child_rels,
&j->rarg);
/* Now insert the new join node into the join tree */
j->larg = *jtlink;
*jtlink = (Node *) j;
/* and return NULL representing constant TRUE */
@ -353,6 +376,7 @@ 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))
{
@ -362,7 +386,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
available_rels);
if (j)
{
/* Yes, insert the new join node into the join tree */
/* Yes; recursively process what we pulled up */
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 */
j->quals = pull_up_sublinks_qual_recurse(root,
j->quals,
child_rels,
&j->rarg);
/* Now insert the new join node into the join tree */
j->larg = *jtlink;
*jtlink = (Node *) j;
/* and return NULL representing constant TRUE */