diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-11-03 00:50:58 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-11-03 00:50:58 -0400 |
commit | 7e3bf99baa18524de6ef1492cb3057314da97e68 (patch) | |
tree | 3ebe96ce2088e06cf2e2ee471ff5e259926cba46 /src/backend/optimizer/plan/createplan.c | |
parent | 1a77f8b63d159b88ceb6245fcb5e81a7f9ac9a22 (diff) | |
download | postgresql-7e3bf99baa18524de6ef1492cb3057314da97e68.tar.gz postgresql-7e3bf99baa18524de6ef1492cb3057314da97e68.zip |
Fix handling of PlaceHolderVars in nestloop parameter management.
If we use a PlaceHolderVar from the outer relation in an inner indexscan,
we need to reference the PlaceHolderVar as such as the value to be passed
in from the outer relation. The previous code effectively tried to
reconstruct the PHV from its component expression, which doesn't work since
(a) the Vars therein aren't necessarily bubbled up far enough, and (b) it
would be the wrong semantics anyway because of the possibility that the PHV
is supposed to have gone to null at some point before the current join.
Point (a) led to "variable not found in subplan target list" planner
errors, but point (b) would have led to silently wrong answers.
Per report from Roger Niederland.
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 71 |
1 files changed, 64 insertions, 7 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index a76f2c603cd..8138b0118b4 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -27,6 +27,7 @@ #include "optimizer/clauses.h" #include "optimizer/cost.h" #include "optimizer/paths.h" +#include "optimizer/placeholder.h" #include "optimizer/plancat.h" #include "optimizer/planmain.h" #include "optimizer/predtest.h" @@ -1926,7 +1927,20 @@ create_nestloop_plan(PlannerInfo *root, NestLoopParam *nlp = (NestLoopParam *) lfirst(cell); next = lnext(cell); - if (bms_is_member(nlp->paramval->varno, outerrelids)) + if (IsA(nlp->paramval, Var) && + bms_is_member(nlp->paramval->varno, outerrelids)) + { + root->curOuterParams = list_delete_cell(root->curOuterParams, + cell, prev); + nestParams = lappend(nestParams, nlp); + } + else if (IsA(nlp->paramval, PlaceHolderVar) && + bms_overlap(((PlaceHolderVar *) nlp->paramval)->phrels, + outerrelids) && + bms_is_subset(find_placeholder_info(root, + (PlaceHolderVar *) nlp->paramval, + false)->ph_eval_at, + outerrelids)) { root->curOuterParams = list_delete_cell(root->curOuterParams, cell, prev); @@ -2354,11 +2368,12 @@ create_hashjoin_plan(PlannerInfo *root, /* * replace_nestloop_params - * Replace outer-relation Vars in the given expression with nestloop Params + * Replace outer-relation Vars and PlaceHolderVars in the given expression + * with nestloop Params * - * All Vars belonging to the relation(s) identified by root->curOuterRels - * are replaced by Params, and entries are added to root->curOuterParams if - * not already present. + * All Vars and PlaceHolderVars belonging to the relation(s) identified by + * root->curOuterRels are replaced by Params, and entries are added to + * root->curOuterParams if not already present. */ static Node * replace_nestloop_params(PlannerInfo *root, Node *expr) @@ -2385,7 +2400,7 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root) if (!bms_is_member(var->varno, root->curOuterRels)) return node; /* Create a Param representing the Var */ - param = assign_nestloop_param(root, var); + param = assign_nestloop_param_var(root, var); /* Is this param already listed in root->curOuterParams? */ foreach(lc, root->curOuterParams) { @@ -2405,6 +2420,48 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root) /* And return the replacement Param */ return (Node *) param; } + if (IsA(node, PlaceHolderVar)) + { + PlaceHolderVar *phv = (PlaceHolderVar *) node; + Param *param; + NestLoopParam *nlp; + ListCell *lc; + + /* Upper-level PlaceHolderVars should be long gone at this point */ + Assert(phv->phlevelsup == 0); + + /* + * If not to be replaced, just return the PlaceHolderVar unmodified. + * We use bms_overlap as a cheap/quick test to see if the PHV might + * be evaluated in the outer rels, and then grab its PlaceHolderInfo + * to tell for sure. + */ + if (!bms_overlap(phv->phrels, root->curOuterRels)) + return node; + if (!bms_is_subset(find_placeholder_info(root, phv, false)->ph_eval_at, + root->curOuterRels)) + return node; + /* Create a Param representing the PlaceHolderVar */ + param = assign_nestloop_param_placeholdervar(root, phv); + /* Is this param already listed in root->curOuterParams? */ + foreach(lc, root->curOuterParams) + { + nlp = (NestLoopParam *) lfirst(lc); + if (nlp->paramno == param->paramid) + { + Assert(equal(phv, nlp->paramval)); + /* Present, so we can just return the Param */ + return (Node *) param; + } + } + /* No, so add it */ + nlp = makeNode(NestLoopParam); + nlp->paramno = param->paramid; + nlp->paramval = (Var *) phv; + root->curOuterParams = lappend(root->curOuterParams, nlp); + /* And return the replacement Param */ + return (Node *) param; + } return expression_tree_mutator(node, replace_nestloop_params_mutator, (void *) root); @@ -2417,7 +2474,7 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root) * * We have four tasks here: * * Remove RestrictInfo nodes from the input clauses. - * * Replace any outer-relation Var nodes with nestloop Params. + * * Replace any outer-relation Var or PHV nodes with nestloop Params. * (XXX eventually, that responsibility should go elsewhere?) * * Index keys must be represented by Var nodes with varattno set to the * index's attribute number, not the attribute number in the original rel. |