mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08: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:
parent
52897e54db
commit
dcc685debb
@ -1065,6 +1065,11 @@ SS_process_ctes(PlannerInfo *root)
|
|||||||
* (Notionally, we replace the SubLink with a constant TRUE, then elide the
|
* (Notionally, we replace the SubLink with a constant TRUE, then elide the
|
||||||
* redundant constant from the qual.)
|
* 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
|
* Side effects of a successful conversion include adding the SubLink's
|
||||||
* subselect to the query's rangetable, so that it can be referenced in
|
* subselect to the query's rangetable, so that it can be referenced in
|
||||||
* the JoinExpr's rarg.
|
* the JoinExpr's rarg.
|
||||||
|
@ -318,6 +318,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
|
|||||||
{
|
{
|
||||||
SubLink *sublink = (SubLink *) node;
|
SubLink *sublink = (SubLink *) node;
|
||||||
JoinExpr *j;
|
JoinExpr *j;
|
||||||
|
Relids child_rels;
|
||||||
|
|
||||||
/* Is it a convertible ANY or EXISTS clause? */
|
/* Is it a convertible ANY or EXISTS clause? */
|
||||||
if (sublink->subLinkType == ANY_SUBLINK)
|
if (sublink->subLinkType == ANY_SUBLINK)
|
||||||
@ -326,7 +327,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
|
|||||||
available_rels);
|
available_rels);
|
||||||
if (j)
|
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;
|
j->larg = *jtlink;
|
||||||
*jtlink = (Node *) j;
|
*jtlink = (Node *) j;
|
||||||
/* and return NULL representing constant TRUE */
|
/* and return NULL representing constant TRUE */
|
||||||
@ -339,7 +351,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
|
|||||||
available_rels);
|
available_rels);
|
||||||
if (j)
|
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;
|
j->larg = *jtlink;
|
||||||
*jtlink = (Node *) j;
|
*jtlink = (Node *) j;
|
||||||
/* and return NULL representing constant TRUE */
|
/* and return NULL representing constant TRUE */
|
||||||
@ -354,6 +377,7 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
|
|||||||
/* If the immediate argument of NOT is EXISTS, try to convert */
|
/* If the immediate argument of NOT is EXISTS, try to convert */
|
||||||
SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
|
SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
|
||||||
JoinExpr *j;
|
JoinExpr *j;
|
||||||
|
Relids child_rels;
|
||||||
|
|
||||||
if (sublink && IsA(sublink, SubLink))
|
if (sublink && IsA(sublink, SubLink))
|
||||||
{
|
{
|
||||||
@ -363,7 +387,18 @@ pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
|
|||||||
available_rels);
|
available_rels);
|
||||||
if (j)
|
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;
|
j->larg = *jtlink;
|
||||||
*jtlink = (Node *) j;
|
*jtlink = (Node *) j;
|
||||||
/* and return NULL representing constant TRUE */
|
/* and return NULL representing constant TRUE */
|
||||||
|
Loading…
Reference in New Issue
Block a user