diff options
Diffstat (limited to 'src/backend/optimizer/plan/setrefs.c')
-rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 74 |
1 files changed, 52 insertions, 22 deletions
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 167901acdf0..2f48821ece6 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -9,25 +9,29 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.73 2001/11/05 17:46:26 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.74 2002/03/12 00:51:48 tgl Exp $ * *------------------------------------------------------------------------- */ -#include <sys/types.h> - #include "postgres.h" +#include <sys/types.h> + #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "optimizer/clauses.h" #include "optimizer/planmain.h" #include "optimizer/tlist.h" +#include "optimizer/var.h" + typedef struct { + Query *root; List *outer_tlist; List *inner_tlist; Index acceptable_rel; + Index join_rti; } join_references_context; typedef struct @@ -38,7 +42,7 @@ typedef struct } replace_vars_with_subplan_refs_context; static void fix_expr_references(Plan *plan, Node *node); -static void set_join_references(Join *join); +static void set_join_references(Query *root, Join *join); static void set_uppernode_references(Plan *plan, Index subvarno); static Node *join_references_mutator(Node *node, join_references_context *context); @@ -71,7 +75,7 @@ static bool fix_opids_walker(Node *node, void *context); * Returns nothing of interest, but modifies internal fields of nodes. */ void -set_plan_references(Plan *plan) +set_plan_references(Query *root, Plan *plan) { List *pl; @@ -115,16 +119,16 @@ set_plan_references(Plan *plan) fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); /* Recurse into subplan too */ - set_plan_references(((SubqueryScan *) plan)->subplan); + set_plan_references(root, ((SubqueryScan *) plan)->subplan); break; case T_NestLoop: - set_join_references((Join *) plan); + set_join_references(root, (Join *) plan); fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual); break; case T_MergeJoin: - set_join_references((Join *) plan); + set_join_references(root, (Join *) plan); fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual); @@ -132,7 +136,7 @@ set_plan_references(Plan *plan) (Node *) ((MergeJoin *) plan)->mergeclauses); break; case T_HashJoin: - set_join_references((Join *) plan); + set_join_references(root, (Join *) plan); fix_expr_references(plan, (Node *) plan->targetlist); fix_expr_references(plan, (Node *) plan->qual); fix_expr_references(plan, (Node *) ((Join *) plan)->joinqual); @@ -186,7 +190,7 @@ set_plan_references(Plan *plan) * recurse into subplans. */ foreach(pl, ((Append *) plan)->appendplans) - set_plan_references((Plan *) lfirst(pl)); + set_plan_references(root, (Plan *) lfirst(pl)); break; default: elog(ERROR, "set_plan_references: unknown plan type %d", @@ -203,21 +207,21 @@ set_plan_references(Plan *plan) * plan's var nodes against the already-modified nodes of the * subplans. */ - set_plan_references(plan->lefttree); - set_plan_references(plan->righttree); + set_plan_references(root, plan->lefttree); + set_plan_references(root, plan->righttree); foreach(pl, plan->initPlan) { SubPlan *sp = (SubPlan *) lfirst(pl); Assert(IsA(sp, SubPlan)); - set_plan_references(sp->plan); + set_plan_references(root, sp->plan); } foreach(pl, plan->subPlan) { SubPlan *sp = (SubPlan *) lfirst(pl); Assert(IsA(sp, SubPlan)); - set_plan_references(sp->plan); + set_plan_references(root, sp->plan); } } @@ -256,7 +260,7 @@ fix_expr_references(Plan *plan, Node *node) * 'join' is a join plan node */ static void -set_join_references(Join *join) +set_join_references(Query *root, Join *join) { Plan *outer = join->plan.lefttree; Plan *inner = join->plan.righttree; @@ -264,9 +268,11 @@ set_join_references(Join *join) List *inner_tlist = ((inner == NULL) ? NIL : inner->targetlist); join->plan.targetlist = join_references(join->plan.targetlist, + root, outer_tlist, inner_tlist, - (Index) 0); + (Index) 0, + join->joinrti); } /* @@ -343,7 +349,8 @@ set_uppernode_references(Plan *plan, Index subvarno) * Creates a new set of targetlist entries or join qual clauses by * changing the varno/varattno values of variables in the clauses * to reference target list values from the outer and inner join - * relation target lists. + * relation target lists. Also, any join alias variables in the + * clauses are expanded into references to their component variables. * * This is used in two different scenarios: a normal join clause, where * all the Vars in the clause *must* be replaced by OUTER or INNER references; @@ -360,21 +367,27 @@ set_uppernode_references(Plan *plan, Index subvarno) * 'inner_tlist' is the target list of the inner join relation, or NIL * 'acceptable_rel' is either zero or the rangetable index of a relation * whose Vars may appear in the clause without provoking an error. + * 'join_rti' is either zero or the join RTE index of join alias variables + * that should be expanded. * * Returns the new expression tree. The original clause structure is * not modified. */ List * join_references(List *clauses, + Query *root, List *outer_tlist, List *inner_tlist, - Index acceptable_rel) + Index acceptable_rel, + Index join_rti) { join_references_context context; + context.root = root; context.outer_tlist = outer_tlist; context.inner_tlist = inner_tlist; context.acceptable_rel = acceptable_rel; + context.join_rti = join_rti; return (List *) join_references_mutator((Node *) clauses, &context); } @@ -387,12 +400,14 @@ join_references_mutator(Node *node, if (IsA(node, Var)) { Var *var = (Var *) node; - Var *newvar = (Var *) copyObject(var); Resdom *resdom; + /* First look for the var in the input tlists */ resdom = tlist_member((Node *) var, context->outer_tlist); if (resdom) { + Var *newvar = (Var *) copyObject(var); + newvar->varno = OUTER; newvar->varattno = resdom->resno; return (Node *) newvar; @@ -400,18 +415,33 @@ join_references_mutator(Node *node, resdom = tlist_member((Node *) var, context->inner_tlist); if (resdom) { + Var *newvar = (Var *) copyObject(var); + newvar->varno = INNER; newvar->varattno = resdom->resno; return (Node *) newvar; } + /* Perhaps it's a join alias that can be resolved to input vars? */ + if (var->varno == context->join_rti) + { + Node *newnode; + + newnode = flatten_join_alias_vars((Node *) var, + context->root, + context->join_rti); + /* Must now resolve the input vars... */ + newnode = join_references_mutator(newnode, context); + return newnode; + } + /* - * Var not in either tlist --- either raise an error, or return - * the Var unmodified. + * No referent found for Var --- either raise an error, or return + * the Var unmodified if it's for acceptable_rel. */ if (var->varno != context->acceptable_rel) elog(ERROR, "join_references: variable not in subplan target lists"); - return (Node *) newvar; + return (Node *) copyObject(var); } return expression_tree_mutator(node, join_references_mutator, |