aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/plan/initsplan.c6
-rw-r--r--src/backend/optimizer/plan/planner.c13
-rw-r--r--src/backend/optimizer/plan/subselect.c126
-rw-r--r--src/backend/optimizer/prep/prepjointree.c275
-rw-r--r--src/include/optimizer/prep.h6
-rw-r--r--src/include/optimizer/subselect.h12
6 files changed, 330 insertions, 108 deletions
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 3c08d0def91..49c2cdf2f55 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.141 2008/08/14 18:47:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.142 2008/08/17 01:19:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -778,7 +778,9 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
root->hasPseudoConstantQuals = true;
/* if not below outer join, push it to top of tree */
if (!below_outer_join)
- relids = get_relids_in_jointree((Node *) root->parse->jointree);
+ relids =
+ get_relids_in_jointree((Node *) root->parse->jointree,
+ false);
}
}
}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 8b432ba93fb..40a659391c6 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.241 2008/08/14 18:47:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.242 2008/08/17 01:19:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -268,14 +268,13 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
root->append_rel_list = NIL;
/*
- * Look for ANY and EXISTS SubLinks at the top level of WHERE, and try to
- * transform them into joins. Note that this step only handles SubLinks
- * originally at top level of WHERE; if we pull up any subqueries below,
- * their SubLinks are processed just before pulling them up.
+ * Look for ANY and EXISTS SubLinks in WHERE and JOIN/ON clauses, and try
+ * to transform them into joins. Note that this step does not descend
+ * into subqueries; if we pull up any subqueries below, their SubLinks are
+ * processed just before pulling them up.
*/
if (parse->hasSubLinks)
- parse->jointree->quals = pull_up_sublinks(root,
- parse->jointree->quals);
+ pull_up_sublinks(root);
/*
* Scan the rangetable for set-returning functions, and inline them
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 1e4e9fe565b..d4374516ac8 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.133 2008/08/14 18:47:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.134 2008/08/17 01:20:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -725,18 +725,31 @@ hash_ok_operator(OpExpr *expr)
/*
* convert_ANY_sublink_to_join: can we convert an ANY SubLink to a join?
*
- * The caller has found an ANY SubLink at the top level of WHERE, but has not
- * checked the properties of the SubLink further. Decide whether it is
- * appropriate to process this SubLink in join style. If not, return NULL.
- * If so, build the qual clause(s) to replace the SubLink, and return them.
- * The qual clauses are wrapped in a FlattenedSubLink node to help later
- * processing place them properly.
+ * The caller has found an ANY SubLink at the top level of one of the query's
+ * qual clauses, but has not checked the properties of the SubLink further.
+ * Decide whether it is appropriate to process this SubLink in join style.
+ * Return TRUE if so, FALSE if the SubLink cannot be converted.
+ *
+ * The only non-obvious input parameter is available_rels: this is the set
+ * of query rels that can safely be referenced in the sublink expression.
+ * (We must restrict this to avoid changing the semantics when a sublink
+ * is present in an outer join's ON qual.) The conversion must fail if
+ * the converted qual would reference any but these parent-query relids.
+ *
+ * On success, two output parameters are returned:
+ * *new_qual is set to the qual tree that should replace the SubLink in
+ * the parent query's qual tree. The qual clauses are wrapped in a
+ * FlattenedSubLink node to help later processing place them properly.
+ * *fromlist is set to a list of pulled-up jointree item(s) that must be
+ * added at the proper spot in the parent query's jointree.
*
* Side effects of a successful conversion include adding the SubLink's
* subselect to the query's rangetable.
*/
-Node *
-convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
+bool
+convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
+ Relids available_rels,
+ Node **new_qual, List **fromlist)
{
Query *parse = root->parse;
Query *subselect = (Query *) sublink->subselect;
@@ -755,7 +768,7 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
* higher levels should be okay, though.)
*/
if (contain_vars_of_level((Node *) subselect, 1))
- return NULL;
+ return false;
/*
* The test expression must contain some Vars of the current query,
@@ -764,16 +777,22 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
*/
left_varnos = pull_varnos(sublink->testexpr);
if (bms_is_empty(left_varnos))
- return NULL;
+ return false;
+
+ /*
+ * However, it can't refer to anything outside available_rels.
+ */
+ if (!bms_is_subset(left_varnos, available_rels))
+ return false;
/*
* The combining operators and left-hand expressions mustn't be volatile.
*/
if (contain_volatile_functions(sublink->testexpr))
- return NULL;
+ return false;
/*
- * Okay, pull up the sub-select into top range table and jointree.
+ * Okay, pull up the sub-select into upper range table.
*
* We rely here on the assumption that the outer query has no references
* to the inner (necessarily true, other than the Vars that we build
@@ -786,16 +805,15 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
false);
parse->rtable = lappend(parse->rtable, rte);
rtindex = list_length(parse->rtable);
- rtr = makeNode(RangeTblRef);
- rtr->rtindex = rtindex;
/*
- * We assume it's okay to add the pulled-up subquery to the topmost FROM
- * list. This should be all right for ANY clauses appearing in WHERE
- * or in upper-level plain JOIN/ON clauses. ANYs appearing below any
- * outer joins couldn't be placed there, however.
+ * Form a RangeTblRef for the pulled-up sub-select. This must be added
+ * to the upper jointree, but it is caller's responsibility to figure
+ * out where.
*/
- parse->jointree->fromlist = lappend(parse->jointree->fromlist, rtr);
+ rtr = makeNode(RangeTblRef);
+ rtr->rtindex = rtindex;
+ *fromlist = list_make1(rtr);
/*
* Build a list of Vars representing the subselect outputs.
@@ -805,14 +823,14 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
rtindex);
/*
- * Build the result qual expression, replacing Params with these Vars.
+ * Build the replacement qual expression, replacing Params with these Vars.
*/
quals = (Expr *) convert_testexpr(root,
sublink->testexpr,
subquery_vars);
/*
- * Now build the FlattenedSubLink node.
+ * And finally, build the FlattenedSubLink node.
*/
fslink = makeNode(FlattenedSubLink);
fslink->jointype = JOIN_SEMI;
@@ -820,7 +838,9 @@ convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink)
fslink->righthand = bms_make_singleton(rtindex);
fslink->quals = quals;
- return (Node *) fslink;
+ *new_qual = (Node *) fslink;
+
+ return true;
}
/*
@@ -883,20 +903,15 @@ simplify_EXISTS_query(Query *query)
/*
* convert_EXISTS_sublink_to_join: can we convert an EXISTS SubLink to a join?
*
- * The caller has found an EXISTS SubLink at the top level of WHERE, or just
- * underneath a NOT, but has not checked the properties of the SubLink
- * further. Decide whether it is appropriate to process this SubLink in join
- * style. If not, return NULL. If so, build the qual clause(s) to replace
- * the SubLink, and return them. (In the NOT case, the returned clauses are
- * intended to replace the NOT as well.) The qual clauses are wrapped in a
- * FlattenedSubLink node to help later processing place them properly.
- *
- * Side effects of a successful conversion include adding the SubLink's
- * subselect to the query's rangetable.
+ * The API of this function is identical to convert_ANY_sublink_to_join's,
+ * except that we also support the case where the caller has found NOT EXISTS,
+ * so we need an additional input parameter "under_not".
*/
-Node *
+bool
convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
- bool under_not)
+ bool under_not,
+ Relids available_rels,
+ Node **new_qual, List **fromlist)
{
Query *parse = root->parse;
Query *subselect = (Query *) sublink->subselect;
@@ -924,7 +939,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
* us with noplace to evaluate the targetlist.
*/
if (!simplify_EXISTS_query(subselect))
- return NULL;
+ return false;
/*
* Separate out the WHERE clause. (We could theoretically also remove
@@ -939,20 +954,20 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
* query. (Vars of higher levels should be okay, though.)
*/
if (contain_vars_of_level((Node *) subselect, 1))
- return NULL;
+ return false;
/*
* On the other hand, the WHERE clause must contain some Vars of the
* parent query, else it's not gonna be a join.
*/
if (!contain_vars_of_level(whereClause, 1))
- return NULL;
+ return false;
/*
* We don't risk optimizing if the WHERE clause is volatile, either.
*/
if (contain_volatile_functions(whereClause))
- return NULL;
+ return false;
/*
* Also disallow SubLinks within the WHERE clause. (XXX this could
@@ -960,10 +975,10 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
* below, and it doesn't seem worth worrying about in a first pass.)
*/
if (contain_subplans(whereClause))
- return NULL;
+ return false;
/*
- * Okay, pull up the sub-select into top range table and jointree.
+ * Prepare to pull up the sub-select into top range table.
*
* We rely here on the assumption that the outer query has no references
* to the inner (necessarily true). Therefore this is a lot easier than
@@ -973,7 +988,7 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
* to do. The machinations of simplify_EXISTS_query ensured that there
* is nothing interesting in the subquery except an rtable and jointree,
* and even the jointree FromExpr no longer has quals. So we can just
- * append the rtable to our own and append the fromlist to our own.
+ * append the rtable to our own and attach the fromlist to our own.
* But first, adjust all level-zero varnos in the subquery to account
* for the rtable merger.
*/
@@ -1007,24 +1022,29 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
bms_free(clause_varnos);
Assert(!bms_is_empty(left_varnos));
- /* Also identify all the rels syntactically within the subselect */
- subselect_varnos = get_relids_in_jointree((Node *) subselect->jointree);
+ /*
+ * Now that we've got the set of upper-level varnos, we can make the
+ * last check: only available_rels can be referenced.
+ */
+ if (!bms_is_subset(left_varnos, available_rels))
+ return false;
+
+ /* Identify all the rels syntactically within the subselect */
+ subselect_varnos = get_relids_in_jointree((Node *) subselect->jointree,
+ true);
Assert(bms_is_subset(right_varnos, subselect_varnos));
/* Now we can attach the modified subquery rtable to the parent */
parse->rtable = list_concat(parse->rtable, subselect->rtable);
/*
- * We assume it's okay to add the pulled-up subquery to the topmost FROM
- * list. This should be all right for EXISTS clauses appearing in WHERE
- * or in upper-level plain JOIN/ON clauses. EXISTS appearing below any
- * outer joins couldn't be placed there, however.
+ * Pass back the subquery fromlist to be attached to upper jointree
+ * in a suitable place.
*/
- parse->jointree->fromlist = list_concat(parse->jointree->fromlist,
- subselect->jointree->fromlist);
+ *fromlist = subselect->jointree->fromlist;
/*
- * Now build the FlattenedSubLink node.
+ * And finally, build the FlattenedSubLink node.
*/
fslink = makeNode(FlattenedSubLink);
fslink->jointype = under_not ? JOIN_ANTI : JOIN_SEMI;
@@ -1032,7 +1052,9 @@ convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
fslink->righthand = subselect_varnos;
fslink->quals = (Expr *) whereClause;
- return (Node *) fslink;
+ *new_qual = (Node *) fslink;
+
+ return true;
}
/*
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index 241ad668072..24e9fdb0b0a 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -16,7 +16,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.52 2008/08/14 20:31:29 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.53 2008/08/17 01:20:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,6 +40,10 @@ typedef struct reduce_outer_joins_state
List *sub_states; /* List of states for subtree components */
} reduce_outer_joins_state;
+static Node *pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
+ Relids *relids);
+static Node *pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
+ Relids available_rels, List **fromlist);
static Node *pull_up_simple_subquery(PlannerInfo *root, Node *jtnode,
RangeTblEntry *rte,
bool below_outer_join,
@@ -76,51 +80,228 @@ static Node *find_jointree_node_for_rel(Node *jtnode, int relid);
/*
* pull_up_sublinks
- * Attempt to pull up top-level ANY and EXISTS SubLinks to be treated
- * as semijoins or anti-semijoins.
+ * Attempt to pull up ANY and EXISTS SubLinks to be treated as
+ * semijoins or anti-semijoins.
*
- * A clause "foo op ANY (sub-SELECT)" appearing at the top level of WHERE
- * can be processed by pulling the sub-SELECT up to become a rangetable entry
- * and handling the implied comparisons as quals of a semijoin.
- * This optimization *only* works at the top level of WHERE, because
- * it cannot distinguish whether the ANY ought to return FALSE or NULL in
- * cases involving NULL inputs. Similarly, EXISTS and NOT EXISTS clauses
- * can be handled by pulling up the sub-SELECT and creating a semijoin
- * or anti-semijoin respectively.
+ * A clause "foo op ANY (sub-SELECT)" can be processed by pulling the
+ * sub-SELECT up to become a rangetable entry and treating the implied
+ * comparisons as quals of a semijoin. However, this optimization *only*
+ * works at the top level of WHERE or a JOIN/ON clause, because we cannot
+ * distinguish whether the ANY ought to return FALSE or NULL in cases
+ * involving NULL inputs. Also, in an outer join's ON clause we can only
+ * do this if the sublink is degenerate (ie, references only the nullable
+ * side of the join). In that case we can effectively push the semijoin
+ * down into the nullable side of the join. If the sublink references any
+ * nonnullable-side variables then it would have to be evaluated as part
+ * of the outer join, which makes things way too complicated.
+ *
+ * Under similar conditions, EXISTS and NOT EXISTS clauses can be handled
+ * by pulling up the sub-SELECT and creating a semijoin or anti-semijoin.
*
* This routine searches for such clauses and does the necessary parsetree
* transformations if any are found.
*
- * This routine has to run before preprocess_expression(), so the WHERE
- * clause is not yet reduced to implicit-AND format. That means we need
+ * This routine has to run before preprocess_expression(), so the quals
+ * clauses are not yet reduced to implicit-AND format. That means we need
* to recursively search through explicit AND clauses, which are
* probably only binary ANDs. We stop as soon as we hit a non-AND item.
+ */
+void
+pull_up_sublinks(PlannerInfo *root)
+{
+ Relids relids;
+
+ /* Begin recursion through the jointree */
+ root->parse->jointree = (FromExpr *)
+ pull_up_sublinks_jointree_recurse(root,
+ (Node *) root->parse->jointree,
+ &relids);
+}
+
+/*
+ * Recurse through jointree nodes for pull_up_sublinks()
*
- * Returns the possibly-modified version of the given qual-tree node.
- * There may be side-effects on the query's rtable and jointree, too.
+ * In addition to returning the possibly-modified jointree node, we return
+ * a relids set of the contained rels into *relids.
*/
-Node *
-pull_up_sublinks(PlannerInfo *root, Node *node)
+static Node *
+pull_up_sublinks_jointree_recurse(PlannerInfo *root, Node *jtnode,
+ Relids *relids)
+{
+ if (jtnode == NULL)
+ {
+ *relids = NULL;
+ }
+ else if (IsA(jtnode, RangeTblRef))
+ {
+ int varno = ((RangeTblRef *) jtnode)->rtindex;
+
+ *relids = bms_make_singleton(varno);
+ /* jtnode is returned unmodified */
+ }
+ else if (IsA(jtnode, FromExpr))
+ {
+ FromExpr *f = (FromExpr *) jtnode;
+ List *newfromlist = NIL;
+ Node *newquals;
+ List *subfromlist = NIL;
+ Relids frelids = NULL;
+ ListCell *l;
+
+ /* First, recurse to process children and collect their relids */
+ foreach(l, f->fromlist)
+ {
+ Node *newchild;
+ Relids childrelids;
+
+ newchild = pull_up_sublinks_jointree_recurse(root,
+ lfirst(l),
+ &childrelids);
+ newfromlist = lappend(newfromlist, newchild);
+ frelids = bms_join(frelids, childrelids);
+ }
+ /* Now process qual --- all children are available for use */
+ newquals = pull_up_sublinks_qual_recurse(root, f->quals, frelids,
+ &subfromlist);
+ /* Any pulled-up subqueries can just be attached to the fromlist */
+ newfromlist = list_concat(newfromlist, subfromlist);
+
+ /*
+ * Although we could include the pulled-up subqueries in the returned
+ * relids, there's no need since upper quals couldn't refer to their
+ * outputs anyway.
+ */
+ *relids = frelids;
+ jtnode = (Node *) makeFromExpr(newfromlist, newquals);
+ }
+ else if (IsA(jtnode, JoinExpr))
+ {
+ JoinExpr *j;
+ Relids leftrelids;
+ Relids rightrelids;
+ List *subfromlist = NIL;
+
+ /*
+ * Make a modifiable copy of join node, but don't bother copying
+ * its subnodes (yet).
+ */
+ j = (JoinExpr *) palloc(sizeof(JoinExpr));
+ memcpy(j, jtnode, sizeof(JoinExpr));
+
+ /* Recurse to process children and collect their relids */
+ j->larg = pull_up_sublinks_jointree_recurse(root, j->larg,
+ &leftrelids);
+ j->rarg = pull_up_sublinks_jointree_recurse(root, j->rarg,
+ &rightrelids);
+
+ /*
+ * Now process qual, showing appropriate child relids as available,
+ * and then attach any pulled-up jointree items at the right place.
+ * The pulled-up items must go below where the quals that refer to
+ * them will be placed. Since the JoinExpr itself can only handle
+ * two child nodes, we hack up a valid jointree by inserting dummy
+ * FromExprs that have no quals. These should get flattened out
+ * during deconstruct_recurse(), so they won't impose any extra
+ * overhead.
+ */
+ switch (j->jointype)
+ {
+ case JOIN_INNER:
+ j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
+ bms_union(leftrelids,
+ rightrelids),
+ &subfromlist);
+ /* We arbitrarily put pulled-up subqueries into right child */
+ if (subfromlist)
+ j->rarg = (Node *) makeFromExpr(lcons(j->rarg,
+ subfromlist),
+ NULL);
+ break;
+ case JOIN_LEFT:
+ j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
+ rightrelids,
+ &subfromlist);
+ /* Any pulled-up subqueries must go into right child */
+ if (subfromlist)
+ j->rarg = (Node *) makeFromExpr(lcons(j->rarg,
+ subfromlist),
+ NULL);
+ break;
+ case JOIN_FULL:
+ /* can't do anything with full-join quals */
+ break;
+ case JOIN_RIGHT:
+ j->quals = pull_up_sublinks_qual_recurse(root, j->quals,
+ leftrelids,
+ &subfromlist);
+ /* Any pulled-up subqueries must go into left child */
+ if (subfromlist)
+ j->larg = (Node *) makeFromExpr(lcons(j->larg,
+ subfromlist),
+ NULL);
+ break;
+ default:
+ elog(ERROR, "unrecognized join type: %d",
+ (int) j->jointype);
+ break;
+ }
+
+ /*
+ * Although we could include the pulled-up subqueries in the returned
+ * relids, there's no need since upper quals couldn't refer to their
+ * outputs anyway. But we *do* need to include the join's own rtindex
+ * because we haven't yet collapsed join alias variables, so upper
+ * levels would mistakenly think they couldn't use references to this
+ * join.
+ */
+ *relids = bms_add_member(bms_join(leftrelids, rightrelids),
+ j->rtindex);
+ jtnode = (Node *) j;
+ }
+ else
+ elog(ERROR, "unrecognized node type: %d",
+ (int) nodeTag(jtnode));
+ return jtnode;
+}
+
+/*
+ * Recurse through top-level qual nodes for pull_up_sublinks()
+ *
+ * Caller must have initialized *fromlist to NIL. We append any new
+ * jointree items to that list.
+ */
+static Node *
+pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
+ Relids available_rels, List **fromlist)
{
if (node == NULL)
return NULL;
if (IsA(node, SubLink))
{
SubLink *sublink = (SubLink *) node;
- Node *subst;
+ Node *new_qual;
+ List *new_fromlist;
/* Is it a convertible ANY or EXISTS clause? */
if (sublink->subLinkType == ANY_SUBLINK)
{
- subst = convert_ANY_sublink_to_join(root, sublink);
- if (subst)
- return subst;
+ if (convert_ANY_sublink_to_join(root, sublink,
+ available_rels,
+ &new_qual, &new_fromlist))
+ {
+ *fromlist = list_concat(*fromlist, new_fromlist);
+ return new_qual;
+ }
}
else if (sublink->subLinkType == EXISTS_SUBLINK)
{
- subst = convert_EXISTS_sublink_to_join(root, sublink, false);
- if (subst)
- return subst;
+ if (convert_EXISTS_sublink_to_join(root, sublink, false,
+ available_rels,
+ &new_qual, &new_fromlist))
+ {
+ *fromlist = list_concat(*fromlist, new_fromlist);
+ return new_qual;
+ }
}
/* Else return it unmodified */
return node;
@@ -129,15 +310,20 @@ pull_up_sublinks(PlannerInfo *root, Node *node)
{
/* If the immediate argument of NOT is EXISTS, try to convert */
SubLink *sublink = (SubLink *) get_notclausearg((Expr *) node);
- Node *subst;
+ Node *new_qual;
+ List *new_fromlist;
if (sublink && IsA(sublink, SubLink))
{
if (sublink->subLinkType == EXISTS_SUBLINK)
{
- subst = convert_EXISTS_sublink_to_join(root, sublink, true);
- if (subst)
- return subst;
+ if (convert_EXISTS_sublink_to_join(root, sublink, true,
+ available_rels,
+ &new_qual, &new_fromlist))
+ {
+ *fromlist = list_concat(*fromlist, new_fromlist);
+ return new_qual;
+ }
}
}
/* Else return it unmodified */
@@ -145,6 +331,7 @@ pull_up_sublinks(PlannerInfo *root, Node *node)
}
if (and_clause(node))
{
+ /* Recurse into AND clause */
List *newclauses = NIL;
ListCell *l;
@@ -153,7 +340,10 @@ pull_up_sublinks(PlannerInfo *root, Node *node)
Node *oldclause = (Node *) lfirst(l);
newclauses = lappend(newclauses,
- pull_up_sublinks(root, oldclause));
+ pull_up_sublinks_qual_recurse(root,
+ oldclause,
+ available_rels,
+ fromlist));
}
return (Node *) make_andclause(newclauses);
}
@@ -383,12 +573,11 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
subroot->append_rel_list = NIL;
/*
- * Pull up any SubLinks within the subquery's WHERE, so that we don't
+ * Pull up any SubLinks within the subquery's quals, so that we don't
* leave unoptimized SubLinks behind.
*/
if (subquery->hasSubLinks)
- subquery->jointree->quals = pull_up_sublinks(subroot,
- subquery->jointree->quals);
+ pull_up_sublinks(subroot);
/*
* Similarly, inline any set-returning functions in its rangetable.
@@ -516,7 +705,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
{
Relids subrelids;
- subrelids = get_relids_in_jointree((Node *) subquery->jointree);
+ subrelids = get_relids_in_jointree((Node *) subquery->jointree, false);
fix_flattened_sublink_relids((Node *) parse, varno, subrelids);
fix_append_rel_relids(root->append_rel_list, varno, subrelids);
}
@@ -1484,10 +1673,13 @@ fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
}
/*
- * get_relids_in_jointree: get set of base RT indexes present in a jointree
+ * get_relids_in_jointree: get set of RT indexes present in a jointree
+ *
+ * If include_joins is true, join RT indexes are included; if false,
+ * only base rels are included.
*/
Relids
-get_relids_in_jointree(Node *jtnode)
+get_relids_in_jointree(Node *jtnode, bool include_joins)
{
Relids result = NULL;
@@ -1507,16 +1699,19 @@ get_relids_in_jointree(Node *jtnode)
foreach(l, f->fromlist)
{
result = bms_join(result,
- get_relids_in_jointree(lfirst(l)));
+ get_relids_in_jointree(lfirst(l),
+ include_joins));
}
}
else if (IsA(jtnode, JoinExpr))
{
JoinExpr *j = (JoinExpr *) jtnode;
- /* join's own RT index is not wanted in result */
- result = get_relids_in_jointree(j->larg);
- result = bms_join(result, get_relids_in_jointree(j->rarg));
+ result = get_relids_in_jointree(j->larg, include_joins);
+ result = bms_join(result,
+ get_relids_in_jointree(j->rarg, include_joins));
+ if (include_joins)
+ result = bms_add_member(result, j->rtindex);
}
else
elog(ERROR, "unrecognized node type: %d",
@@ -1536,7 +1731,7 @@ get_relids_for_join(PlannerInfo *root, int joinrelid)
joinrelid);
if (!jtnode)
elog(ERROR, "could not find join node %d", joinrelid);
- return get_relids_in_jointree(jtnode);
+ return get_relids_in_jointree(jtnode, false);
}
/*
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index 1a90a13208c..9326623b91a 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/prep.h,v 1.61 2008/08/14 18:48:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/prep.h,v 1.62 2008/08/17 01:20:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,12 +21,12 @@
/*
* prototypes for prepjointree.c
*/
-extern Node *pull_up_sublinks(PlannerInfo *root, Node *node);
+extern void pull_up_sublinks(PlannerInfo *root);
extern void inline_set_returning_functions(PlannerInfo *root);
extern Node *pull_up_subqueries(PlannerInfo *root, Node *jtnode,
bool below_outer_join, bool append_rel_member);
extern void reduce_outer_joins(PlannerInfo *root);
-extern Relids get_relids_in_jointree(Node *jtnode);
+extern Relids get_relids_in_jointree(Node *jtnode, bool include_joins);
extern Relids get_relids_for_join(PlannerInfo *root, int joinrelid);
/*
diff --git a/src/include/optimizer/subselect.h b/src/include/optimizer/subselect.h
index b9bd76b07ff..97e230a2dbf 100644
--- a/src/include/optimizer/subselect.h
+++ b/src/include/optimizer/subselect.h
@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.32 2008/08/14 18:48:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/subselect.h,v 1.33 2008/08/17 01:20:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -15,9 +15,13 @@
#include "nodes/plannodes.h"
#include "nodes/relation.h"
-extern Node *convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink);
-extern Node *convert_EXISTS_sublink_to_join(PlannerInfo *root,
- SubLink *sublink, bool under_not);
+extern bool convert_ANY_sublink_to_join(PlannerInfo *root, SubLink *sublink,
+ Relids available_rels,
+ Node **new_qual, List **fromlist);
+extern bool convert_EXISTS_sublink_to_join(PlannerInfo *root, SubLink *sublink,
+ bool under_not,
+ Relids available_rels,
+ Node **new_qual, List **fromlist);
extern Node *SS_replace_correlation_vars(PlannerInfo *root, Node *expr);
extern Node *SS_process_sublinks(PlannerInfo *root, Node *expr, bool isQual);
extern void SS_finalize_plan(PlannerInfo *root, Plan *plan,