Commit c59d8dd4 authored by Tom Lane's avatar Tom Lane

Improve pull_up_subqueries logic so that it doesn't insert unnecessary

PlaceHolderVar nodes in join quals appearing in or below the lowest
outer join that could null the subquery being pulled up.  This improves
the planner's ability to recognize constant join quals, and probably
helps with detection of common sort keys (equivalence classes) as well.
parent 636edd55
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.254 2009/04/19 19:46:33 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.255 2009/04/28 21:31:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -324,7 +324,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, ...@@ -324,7 +324,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
* this query. * this query.
*/ */
parse->jointree = (FromExpr *) parse->jointree = (FromExpr *)
pull_up_subqueries(root, (Node *) parse->jointree, false, false); pull_up_subqueries(root, (Node *) parse->jointree, NULL, NULL);
/* /*
* Detect whether any rangetable entries are RTE_JOIN kind; if not, we can * Detect whether any rangetable entries are RTE_JOIN kind; if not, we can
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.64 2009/02/27 23:30:29 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.65 2009/04/28 21:31:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -47,8 +47,8 @@ static Node *pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node, ...@@ -47,8 +47,8 @@ static Node *pull_up_sublinks_qual_recurse(PlannerInfo *root, Node *node,
Relids available_rels, Node **jtlink); Relids available_rels, Node **jtlink);
static Node *pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, static Node *pull_up_simple_subquery(PlannerInfo *root, Node *jtnode,
RangeTblEntry *rte, RangeTblEntry *rte,
bool below_outer_join, JoinExpr *lowest_outer_join,
bool append_rel_member); AppendRelInfo *containing_appendrel);
static Node *pull_up_simple_union_all(PlannerInfo *root, Node *jtnode, static Node *pull_up_simple_union_all(PlannerInfo *root, Node *jtnode,
RangeTblEntry *rte); RangeTblEntry *rte);
static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root,
...@@ -63,8 +63,9 @@ static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, ...@@ -63,8 +63,9 @@ static bool is_simple_union_all_recurse(Node *setOp, Query *setOpQuery,
static List *insert_targetlist_placeholders(PlannerInfo *root, List *tlist, static List *insert_targetlist_placeholders(PlannerInfo *root, List *tlist,
int varno, bool wrap_non_vars); int varno, bool wrap_non_vars);
static bool is_safe_append_member(Query *subquery); static bool is_safe_append_member(Query *subquery);
static void resolvenew_in_jointree(Node *jtnode, int varno, static void resolvenew_in_jointree(Node *jtnode, int varno, RangeTblEntry *rte,
RangeTblEntry *rte, List *subtlist); List *subtlist, List *subtlist_with_phvs,
JoinExpr *lowest_outer_join);
static reduce_outer_joins_state *reduce_outer_joins_pass1(Node *jtnode); static reduce_outer_joins_state *reduce_outer_joins_pass1(Node *jtnode);
static void reduce_outer_joins_pass2(Node *jtnode, static void reduce_outer_joins_pass2(Node *jtnode,
reduce_outer_joins_state *state, reduce_outer_joins_state *state,
...@@ -440,14 +441,15 @@ inline_set_returning_functions(PlannerInfo *root) ...@@ -440,14 +441,15 @@ inline_set_returning_functions(PlannerInfo *root)
* Also, subqueries that are simple UNION ALL structures can be * Also, subqueries that are simple UNION ALL structures can be
* converted into "append relations". * converted into "append relations".
* *
* below_outer_join is true if this jointree node is within the nullable * If this jointree node is within the nullable side of an outer join, then
* side of an outer join. This forces use of the PlaceHolderVar mechanism * lowest_outer_join references the lowest such JoinExpr node; otherwise it
* for non-nullable targetlist items. * is NULL. This forces use of the PlaceHolderVar mechanism for references
* to non-nullable targetlist items, but only for references above that join.
* *
* append_rel_member is true if we are looking at a member subquery of * If we are looking at a member subquery of an append relation,
* an append relation. This forces use of the PlaceHolderVar mechanism * containing_appendrel describes that relation; else it is NULL.
* for all non-Var targetlist items, and puts some additional restrictions * This forces use of the PlaceHolderVar mechanism for all non-Var targetlist
* on what can be pulled up. * items, and puts some additional restrictions on what can be pulled up.
* *
* A tricky aspect of this code is that if we pull up a subquery we have * A tricky aspect of this code is that if we pull up a subquery we have
* to replace Vars that reference the subquery's outputs throughout the * to replace Vars that reference the subquery's outputs throughout the
...@@ -457,10 +459,15 @@ inline_set_returning_functions(PlannerInfo *root) ...@@ -457,10 +459,15 @@ inline_set_returning_functions(PlannerInfo *root)
* subquery RangeTblRef entries will be replaced. Also, we can't turn * subquery RangeTblRef entries will be replaced. Also, we can't turn
* ResolveNew loose on the whole jointree, because it'll return a mutated * ResolveNew loose on the whole jointree, because it'll return a mutated
* copy of the tree; we have to invoke it just on the quals, instead. * copy of the tree; we have to invoke it just on the quals, instead.
* This behavior is what makes it reasonable to pass lowest_outer_join as a
* pointer rather than some more-indirect way of identifying the lowest OJ.
* Likewise, we don't replace append_rel_list members but only their
* substructure, so the containing_appendrel reference is safe to use.
*/ */
Node * Node *
pull_up_subqueries(PlannerInfo *root, Node *jtnode, pull_up_subqueries(PlannerInfo *root, Node *jtnode,
bool below_outer_join, bool append_rel_member) JoinExpr *lowest_outer_join,
AppendRelInfo *containing_appendrel)
{ {
if (jtnode == NULL) if (jtnode == NULL)
return NULL; return NULL;
...@@ -478,10 +485,11 @@ pull_up_subqueries(PlannerInfo *root, Node *jtnode, ...@@ -478,10 +485,11 @@ pull_up_subqueries(PlannerInfo *root, Node *jtnode,
*/ */
if (rte->rtekind == RTE_SUBQUERY && if (rte->rtekind == RTE_SUBQUERY &&
is_simple_subquery(rte->subquery) && is_simple_subquery(rte->subquery) &&
(!append_rel_member || is_safe_append_member(rte->subquery))) (containing_appendrel == NULL ||
is_safe_append_member(rte->subquery)))
return pull_up_simple_subquery(root, jtnode, rte, return pull_up_simple_subquery(root, jtnode, rte,
below_outer_join, lowest_outer_join,
append_rel_member); containing_appendrel);
/* /*
* Alternatively, is it a simple UNION ALL subquery? If so, flatten * Alternatively, is it a simple UNION ALL subquery? If so, flatten
...@@ -503,44 +511,44 @@ pull_up_subqueries(PlannerInfo *root, Node *jtnode, ...@@ -503,44 +511,44 @@ pull_up_subqueries(PlannerInfo *root, Node *jtnode,
FromExpr *f = (FromExpr *) jtnode; FromExpr *f = (FromExpr *) jtnode;
ListCell *l; ListCell *l;
Assert(!append_rel_member); Assert(containing_appendrel == NULL);
foreach(l, f->fromlist) foreach(l, f->fromlist)
lfirst(l) = pull_up_subqueries(root, lfirst(l), lfirst(l) = pull_up_subqueries(root, lfirst(l),
below_outer_join, false); lowest_outer_join, NULL);
} }
else if (IsA(jtnode, JoinExpr)) else if (IsA(jtnode, JoinExpr))
{ {
JoinExpr *j = (JoinExpr *) jtnode; JoinExpr *j = (JoinExpr *) jtnode;
Assert(!append_rel_member); Assert(containing_appendrel == NULL);
/* Recurse, being careful to tell myself when inside outer join */ /* Recurse, being careful to tell myself when inside outer join */
switch (j->jointype) switch (j->jointype)
{ {
case JOIN_INNER: case JOIN_INNER:
j->larg = pull_up_subqueries(root, j->larg, j->larg = pull_up_subqueries(root, j->larg,
below_outer_join, false); lowest_outer_join, NULL);
j->rarg = pull_up_subqueries(root, j->rarg, j->rarg = pull_up_subqueries(root, j->rarg,
below_outer_join, false); lowest_outer_join, NULL);
break; break;
case JOIN_LEFT: case JOIN_LEFT:
case JOIN_SEMI: case JOIN_SEMI:
case JOIN_ANTI: case JOIN_ANTI:
j->larg = pull_up_subqueries(root, j->larg, j->larg = pull_up_subqueries(root, j->larg,
below_outer_join, false); lowest_outer_join, NULL);
j->rarg = pull_up_subqueries(root, j->rarg, j->rarg = pull_up_subqueries(root, j->rarg,
true, false); j, NULL);
break; break;
case JOIN_FULL: case JOIN_FULL:
j->larg = pull_up_subqueries(root, j->larg, j->larg = pull_up_subqueries(root, j->larg,
true, false); j, NULL);
j->rarg = pull_up_subqueries(root, j->rarg, j->rarg = pull_up_subqueries(root, j->rarg,
true, false); j, NULL);
break; break;
case JOIN_RIGHT: case JOIN_RIGHT:
j->larg = pull_up_subqueries(root, j->larg, j->larg = pull_up_subqueries(root, j->larg,
true, false); j, NULL);
j->rarg = pull_up_subqueries(root, j->rarg, j->rarg = pull_up_subqueries(root, j->rarg,
below_outer_join, false); lowest_outer_join, NULL);
break; break;
default: default:
elog(ERROR, "unrecognized join type: %d", elog(ERROR, "unrecognized join type: %d",
...@@ -562,10 +570,14 @@ pull_up_subqueries(PlannerInfo *root, Node *jtnode, ...@@ -562,10 +570,14 @@ pull_up_subqueries(PlannerInfo *root, Node *jtnode,
* subquery by pull_up_subqueries. We return the replacement jointree node, * subquery by pull_up_subqueries. We return the replacement jointree node,
* or jtnode itself if we determine that the subquery can't be pulled up after * or jtnode itself if we determine that the subquery can't be pulled up after
* all. * all.
*
* rte is the RangeTblEntry referenced by jtnode. Remaining parameters are
* as for pull_up_subqueries.
*/ */
static Node * static Node *
pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
bool below_outer_join, bool append_rel_member) JoinExpr *lowest_outer_join,
AppendRelInfo *containing_appendrel)
{ {
Query *parse = root->parse; Query *parse = root->parse;
int varno = ((RangeTblRef *) jtnode)->rtindex; int varno = ((RangeTblRef *) jtnode)->rtindex;
...@@ -573,7 +585,8 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, ...@@ -573,7 +585,8 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
PlannerInfo *subroot; PlannerInfo *subroot;
int rtoffset; int rtoffset;
List *subtlist; List *subtlist;
ListCell *rt; List *subtlist_with_phvs;
ListCell *lc;
/* /*
* Need a modifiable copy of the subquery to hack on. Even if we didn't * Need a modifiable copy of the subquery to hack on. Even if we didn't
...@@ -624,13 +637,13 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, ...@@ -624,13 +637,13 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
* pull_up_subqueries' processing is complete for its jointree and * pull_up_subqueries' processing is complete for its jointree and
* rangetable. * rangetable.
* *
* Note: below_outer_join = false is correct here even if we are within an * Note: we should pass NULL for containing-join info even if we are within
* outer join in the upper query; the lower query starts with a clean * an outer join in the upper query; the lower query starts with a clean
* slate for outer-join semantics. Likewise, we say we aren't handling an * slate for outer-join semantics. Likewise, we say we aren't handling an
* appendrel member. * appendrel member.
*/ */
subquery->jointree = (FromExpr *) subquery->jointree = (FromExpr *)
pull_up_subqueries(subroot, (Node *) subquery->jointree, false, false); pull_up_subqueries(subroot, (Node *) subquery->jointree, NULL, NULL);
/* /*
* Now we must recheck whether the subquery is still simple enough to pull * Now we must recheck whether the subquery is still simple enough to pull
...@@ -641,7 +654,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, ...@@ -641,7 +654,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
* pull_up_subqueries. * pull_up_subqueries.
*/ */
if (is_simple_subquery(subquery) && if (is_simple_subquery(subquery) &&
(!append_rel_member || is_safe_append_member(subquery))) (containing_appendrel == NULL || is_safe_append_member(subquery)))
{ {
/* good to go */ /* good to go */
} }
...@@ -677,51 +690,82 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte, ...@@ -677,51 +690,82 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
/* /*
* The subquery's targetlist items are now in the appropriate form to * The subquery's targetlist items are now in the appropriate form to
* insert into the top query, but if we are under an outer join then * insert into the top query, but if we are under an outer join then
* non-nullable items have to be turned into PlaceHolderVars. If we * non-nullable items may have to be turned into PlaceHolderVars. If we
* are dealing with an appendrel member then anything that's not a * are dealing with an appendrel member then anything that's not a
* simple Var has to be turned into a PlaceHolderVar. * simple Var has to be turned into a PlaceHolderVar.
*/ */
if (below_outer_join || append_rel_member) subtlist = subquery->targetList;
subtlist = insert_targetlist_placeholders(root, subquery->targetList, if (lowest_outer_join != NULL || containing_appendrel != NULL)
varno, append_rel_member); subtlist_with_phvs = insert_targetlist_placeholders(root,
subtlist,
varno,
containing_appendrel != NULL);
else else
subtlist = subquery->targetList; subtlist_with_phvs = subtlist;
/* /*
* Replace all of the top query's references to the subquery's outputs * Replace all of the top query's references to the subquery's outputs
* with copies of the adjusted subtlist items, being careful not to * with copies of the adjusted subtlist items, being careful not to
* replace any of the jointree structure. (This'd be a lot cleaner if we * replace any of the jointree structure. (This'd be a lot cleaner if we
* could use query_tree_mutator.) * could use query_tree_mutator.) We have to use PHVs in the targetList,
* returningList, and havingQual, since those are certainly above any
* outer join. resolvenew_in_jointree tracks its location in the jointree
* and uses PHVs or not appropriately.
*/ */
parse->targetList = (List *) parse->targetList = (List *)
ResolveNew((Node *) parse->targetList, ResolveNew((Node *) parse->targetList,
varno, 0, rte, varno, 0, rte,
subtlist, CMD_SELECT, 0); subtlist_with_phvs, CMD_SELECT, 0);
parse->returningList = (List *) parse->returningList = (List *)
ResolveNew((Node *) parse->returningList, ResolveNew((Node *) parse->returningList,
varno, 0, rte, varno, 0, rte,
subtlist, CMD_SELECT, 0); subtlist_with_phvs, CMD_SELECT, 0);
resolvenew_in_jointree((Node *) parse->jointree, varno, resolvenew_in_jointree((Node *) parse->jointree, varno, rte,
rte, subtlist); subtlist, subtlist_with_phvs,
lowest_outer_join);
Assert(parse->setOperations == NULL); Assert(parse->setOperations == NULL);
parse->havingQual = parse->havingQual =
ResolveNew(parse->havingQual, ResolveNew(parse->havingQual,
varno, 0, rte, varno, 0, rte,
subtlist, CMD_SELECT, 0); subtlist_with_phvs, CMD_SELECT, 0);
root->append_rel_list = (List *)
ResolveNew((Node *) root->append_rel_list,
varno, 0, rte,
subtlist, CMD_SELECT, 0);
foreach(rt, parse->rtable) /*
* Replace references in the translated_vars lists of appendrels.
* When pulling up an appendrel member, we do not need PHVs in the list
* of the parent appendrel --- there isn't any outer join between.
* Elsewhere, use PHVs for safety. (This analysis could be made tighter
* but it seems unlikely to be worth much trouble.)
*/
foreach(lc, root->append_rel_list)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
appinfo->translated_vars = (List *)
ResolveNew((Node *) appinfo->translated_vars,
varno, 0, rte,
(appinfo == containing_appendrel) ?
subtlist : subtlist_with_phvs,
CMD_SELECT, 0);
}
/*
* Replace references in the joinaliasvars lists of join RTEs.
*
* You might think that we could avoid using PHVs for alias vars of joins
* below lowest_outer_join, but that doesn't work because the alias vars
* could be referenced above that join; we need the PHVs to be present
* in such references after the alias vars get flattened. (It might be
* worth trying to be smarter here, someday.)
*/
foreach(lc, parse->rtable)
{ {
RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(rt); RangeTblEntry *otherrte = (RangeTblEntry *) lfirst(lc);
if (otherrte->rtekind == RTE_JOIN) if (otherrte->rtekind == RTE_JOIN)
otherrte->joinaliasvars = (List *) otherrte->joinaliasvars = (List *)
ResolveNew((Node *) otherrte->joinaliasvars, ResolveNew((Node *) otherrte->joinaliasvars,
varno, 0, rte, varno, 0, rte,
subtlist, CMD_SELECT, 0); subtlist_with_phvs, CMD_SELECT, 0);
} }
/* /*
...@@ -884,13 +928,13 @@ pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex, ...@@ -884,13 +928,13 @@ pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
/* /*
* Recursively apply pull_up_subqueries to the new child RTE. (We * Recursively apply pull_up_subqueries to the new child RTE. (We
* must build the AppendRelInfo first, because this will modify it.) * must build the AppendRelInfo first, because this will modify it.)
* Note that we can pass below_outer_join = false even if we're * Note that we can pass NULL for containing-join info even if we're
* actually under an outer join, because the child's expressions * actually under an outer join, because the child's expressions
* aren't going to propagate up above the join. * aren't going to propagate up above the join.
*/ */
rtr = makeNode(RangeTblRef); rtr = makeNode(RangeTblRef);
rtr->rtindex = childRTindex; rtr->rtindex = childRTindex;
(void) pull_up_subqueries(root, (Node *) rtr, false, true); (void) pull_up_subqueries(root, (Node *) rtr, NULL, appinfo);
} }
else if (IsA(setOp, SetOperationStmt)) else if (IsA(setOp, SetOperationStmt))
{ {
...@@ -1096,7 +1140,7 @@ is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes) ...@@ -1096,7 +1140,7 @@ is_simple_union_all_recurse(Node *setOp, Query *setOpQuery, List *colTypes)
* Insert PlaceHolderVar nodes into any non-junk targetlist items that are * Insert PlaceHolderVar nodes into any non-junk targetlist items that are
* not simple variables or strict functions of simple variables (and hence * not simple variables or strict functions of simple variables (and hence
* might not correctly go to NULL when examined above the point of an outer * might not correctly go to NULL when examined above the point of an outer
* join). We assume we can modify the tlist items in-place. * join).
* *
* varno is the upper-query relid of the subquery; this is used as the * varno is the upper-query relid of the subquery; this is used as the
* syntactic location of the PlaceHolderVars. * syntactic location of the PlaceHolderVars.
...@@ -1107,15 +1151,20 @@ static List * ...@@ -1107,15 +1151,20 @@ static List *
insert_targetlist_placeholders(PlannerInfo *root, List *tlist, insert_targetlist_placeholders(PlannerInfo *root, List *tlist,
int varno, bool wrap_non_vars) int varno, bool wrap_non_vars)
{ {
List *result = NIL;
ListCell *lc; ListCell *lc;
foreach(lc, tlist) foreach(lc, tlist)
{ {
TargetEntry *tle = (TargetEntry *) lfirst(lc); TargetEntry *tle = (TargetEntry *) lfirst(lc);
TargetEntry *newtle;
/* ignore resjunk columns */ /* resjunk columns need not be changed */
if (tle->resjunk) if (tle->resjunk)
{
result = lappend(result, tle);
continue; continue;
}
/* /*
* Simple Vars always escape being wrapped. This is common enough * Simple Vars always escape being wrapped. This is common enough
...@@ -1123,7 +1172,10 @@ insert_targetlist_placeholders(PlannerInfo *root, List *tlist, ...@@ -1123,7 +1172,10 @@ insert_targetlist_placeholders(PlannerInfo *root, List *tlist,
*/ */
if (tle->expr && IsA(tle->expr, Var) && if (tle->expr && IsA(tle->expr, Var) &&
((Var *) tle->expr)->varlevelsup == 0) ((Var *) tle->expr)->varlevelsup == 0)
{
result = lappend(result, tle);
continue; continue;
}
if (!wrap_non_vars) if (!wrap_non_vars)
{ {
...@@ -1136,15 +1188,22 @@ insert_targetlist_placeholders(PlannerInfo *root, List *tlist, ...@@ -1136,15 +1188,22 @@ insert_targetlist_placeholders(PlannerInfo *root, List *tlist,
*/ */
if (contain_vars_of_level((Node *) tle->expr, 0) && if (contain_vars_of_level((Node *) tle->expr, 0) &&
!contain_nonstrict_functions((Node *) tle->expr)) !contain_nonstrict_functions((Node *) tle->expr))
{
result = lappend(result, tle);
continue; continue;
}
} }
/* Else wrap it in a PlaceHolderVar */ /* Else wrap it in a PlaceHolderVar */
tle->expr = (Expr *) make_placeholder_expr(root, newtle = makeNode(TargetEntry);
tle->expr, memcpy(newtle, tle, sizeof(TargetEntry));
bms_make_singleton(varno)); newtle->expr = (Expr *)
make_placeholder_expr(root,
tle->expr,
bms_make_singleton(varno));
result = lappend(result, newtle);
} }
return tlist; return result;
} }
/* /*
...@@ -1187,10 +1246,15 @@ is_safe_append_member(Query *subquery) ...@@ -1187,10 +1246,15 @@ is_safe_append_member(Query *subquery)
* Helper routine for pull_up_subqueries: do ResolveNew on every expression * Helper routine for pull_up_subqueries: do ResolveNew on every expression
* in the jointree, without changing the jointree structure itself. Ugly, * in the jointree, without changing the jointree structure itself. Ugly,
* but there's no other way... * but there's no other way...
*
* If we are above lowest_outer_join then use subtlist_with_phvs; at or
* below it, use subtlist. (When no outer joins are in the picture,
* these will be the same list.)
*/ */
static void static void
resolvenew_in_jointree(Node *jtnode, int varno, resolvenew_in_jointree(Node *jtnode, int varno, RangeTblEntry *rte,
RangeTblEntry *rte, List *subtlist) List *subtlist, List *subtlist_with_phvs,
JoinExpr *lowest_outer_join)
{ {
if (jtnode == NULL) if (jtnode == NULL)
return; return;
...@@ -1204,20 +1268,32 @@ resolvenew_in_jointree(Node *jtnode, int varno, ...@@ -1204,20 +1268,32 @@ resolvenew_in_jointree(Node *jtnode, int varno,
ListCell *l; ListCell *l;
foreach(l, f->fromlist) foreach(l, f->fromlist)
resolvenew_in_jointree(lfirst(l), varno, rte, subtlist); resolvenew_in_jointree(lfirst(l), varno, rte,
subtlist, subtlist_with_phvs,
lowest_outer_join);
f->quals = ResolveNew(f->quals, f->quals = ResolveNew(f->quals,
varno, 0, rte, varno, 0, rte,
subtlist, CMD_SELECT, 0); subtlist_with_phvs, CMD_SELECT, 0);
} }
else if (IsA(jtnode, JoinExpr)) else if (IsA(jtnode, JoinExpr))
{ {
JoinExpr *j = (JoinExpr *) jtnode; JoinExpr *j = (JoinExpr *) jtnode;
resolvenew_in_jointree(j->larg, varno, rte, subtlist); if (j == lowest_outer_join)
resolvenew_in_jointree(j->rarg, varno, rte, subtlist); {
/* no more PHVs in or below this join */
subtlist_with_phvs = subtlist;
lowest_outer_join = NULL;
}
resolvenew_in_jointree(j->larg, varno, rte,
subtlist, subtlist_with_phvs,
lowest_outer_join);
resolvenew_in_jointree(j->rarg, varno, rte,
subtlist, subtlist_with_phvs,
lowest_outer_join);
j->quals = ResolveNew(j->quals, j->quals = ResolveNew(j->quals,
varno, 0, rte, varno, 0, rte,
subtlist, CMD_SELECT, 0); subtlist_with_phvs, CMD_SELECT, 0);
/* /*
* We don't bother to update the colvars list, since it won't be used * We don't bother to update the colvars list, since it won't be used
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/prep.h,v 1.64 2009/01/01 17:24:00 momjian Exp $ * $PostgreSQL: pgsql/src/include/optimizer/prep.h,v 1.65 2009/04/28 21:31:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
extern void pull_up_sublinks(PlannerInfo *root); extern void pull_up_sublinks(PlannerInfo *root);
extern void inline_set_returning_functions(PlannerInfo *root); extern void inline_set_returning_functions(PlannerInfo *root);
extern Node *pull_up_subqueries(PlannerInfo *root, Node *jtnode, extern Node *pull_up_subqueries(PlannerInfo *root, Node *jtnode,
bool below_outer_join, bool append_rel_member); JoinExpr *lowest_outer_join,
AppendRelInfo *containing_appendrel);
extern void reduce_outer_joins(PlannerInfo *root); extern void reduce_outer_joins(PlannerInfo *root);
extern Relids get_relids_in_jointree(Node *jtnode, bool include_joins); extern Relids get_relids_in_jointree(Node *jtnode, bool include_joins);
extern Relids get_relids_for_join(PlannerInfo *root, int joinrelid); extern Relids get_relids_for_join(PlannerInfo *root, int joinrelid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment