diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2014-06-09 21:28:56 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2014-06-09 21:28:56 -0400 |
commit | 187ae17300776f48b2bd9d0737923b1bf70f606e (patch) | |
tree | b3f0f827848a36a55205fad3cb55d72eec188ff6 /src/backend/optimizer/plan/createplan.c | |
parent | 93328b2dfb9aa08e5f56a049d84df4ad3c9ff225 (diff) |
Fix planner bug with nested PlaceHolderVars in 9.2 (only).
Commit 9e7e29c75ad441450f9b8287bd51c13521641e3b fixed some problems with
LATERAL references in PlaceHolderVars, one of which was that "createplan.c
wasn't handling nested PlaceHolderVars properly". I failed to see that
this problem might occur in older versions as well; but it can, as
demonstrated in bug #10587 from Geoff Speicher. In this case the nesting
occurs due to push-down of PlaceHolderVar expressions into a parameterized
path. So, back-patch the relevant changes from 9e7e29c75ad4 into 9.2 where
parameterized paths were introduced. (Perhaps I'm still being too myopic,
but I'm hesitant to change older branches without some evidence that the
case can occur there.)
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 36997be5889..c5df505d491 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -2532,16 +2532,37 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root) 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. + * Check whether we need to replace the PHV. 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; + if (!bms_overlap(phv->phrels, root->curOuterRels) || + !bms_is_subset(find_placeholder_info(root, phv, false)->ph_eval_at, + root->curOuterRels)) + { + /* + * We can't replace the whole PHV, but we might still need to + * replace Vars or PHVs within its expression, in case it ends up + * actually getting evaluated here. (It might get evaluated in + * this plan node, or some child node; in the latter case we don't + * really need to process the expression here, but we haven't got + * enough info to tell if that's the case.) Flat-copy the PHV + * node and then recurse on its expression. + * + * Note that after doing this, we might have different + * representations of the contents of the same PHV in different + * parts of the plan tree. This is OK because equal() will just + * match on phid/phlevelsup, so setrefs.c will still recognize an + * upper-level reference to a lower-level copy of the same PHV. + */ + PlaceHolderVar *newphv = makeNode(PlaceHolderVar); + + memcpy(newphv, phv, sizeof(PlaceHolderVar)); + newphv->phexpr = (Expr *) + replace_nestloop_params_mutator((Node *) phv->phexpr, + root); + return (Node *) newphv; + } /* Create a Param representing the PlaceHolderVar */ param = assign_nestloop_param_placeholdervar(root, phv); /* Is this param already listed in root->curOuterParams? */ |