diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c index 3c08d0def9..49c2cdf2f5 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 8b432ba93f..40a659391c 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 1e4e9fe565..d4374516ac 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 241ad66807..24e9fdb0b0 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. - * - * Returns the possibly-modified version of the given qual-tree node. - * There may be side-effects on the query's rtable and jointree, too. */ -Node * -pull_up_sublinks(PlannerInfo *root, Node *node) +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() + * + * In addition to returning the possibly-modified jointree node, we return + * a relids set of the contained rels into *relids. + */ +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 1a90a13208..9326623b91 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 b9bd76b07f..97e230a2db 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,