diff options
Diffstat (limited to 'src/backend/optimizer/util/paramassign.c')
-rw-r--r-- | src/backend/optimizer/util/paramassign.c | 70 |
1 files changed, 40 insertions, 30 deletions
diff --git a/src/backend/optimizer/util/paramassign.c b/src/backend/optimizer/util/paramassign.c index e94f7e7563d..d6a923b0b68 100644 --- a/src/backend/optimizer/util/paramassign.c +++ b/src/backend/optimizer/util/paramassign.c @@ -421,26 +421,8 @@ replace_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) * provide these values. This differs from replace_nestloop_param_var in * that the PARAM_EXEC slots to use have already been determined. * - * An additional complication is that the subplan_params may contain - * nullingrel markers that need adjustment. This occurs if we have applied - * outer join identity 3, - * (A leftjoin B on (Pab)) leftjoin C on (Pb*c) - * = A leftjoin (B leftjoin C on (Pbc)) on (Pab) - * and C is a subquery containing lateral references to B. It's still safe - * to apply the identity, but the parser will have created those references - * in the form "b*" (i.e., with varnullingrels listing the A/B join), while - * what we will have available from the nestloop's outer side is just "b". - * We deal with that here by stripping the nullingrels down to what is - * available from the outer side according to root->curOuterRels. - * That fixes matters for the case of forward application of identity 3. - * If the identity was applied in the reverse direction, we will have - * subplan_params containing too few nullingrel bits rather than too many. - * Currently, that causes no problems because setrefs.c applies only a - * subset check to nullingrels in NestLoopParams, but we'd have to work - * harder if we ever want to tighten that check. - * * Note that we also use root->curOuterRels as an implicit parameter for - * sanity checks and nullingrel adjustments. + * sanity checks. */ void process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params) @@ -467,19 +449,17 @@ process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params) nlp = (NestLoopParam *) lfirst(lc2); if (nlp->paramno == pitem->paramId) { + Assert(equal(var, nlp->paramval)); /* Present, so nothing to do */ break; } } if (lc2 == NULL) { - /* No, so add it after adjusting its nullingrels */ - var = copyObject(var); - var->varnullingrels = bms_intersect(var->varnullingrels, - root->curOuterRels); + /* No, so add it */ nlp = makeNode(NestLoopParam); nlp->paramno = pitem->paramId; - nlp->paramval = var; + nlp->paramval = copyObject(var); root->curOuterParams = lappend(root->curOuterParams, nlp); } } @@ -500,19 +480,17 @@ process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params) nlp = (NestLoopParam *) lfirst(lc2); if (nlp->paramno == pitem->paramId) { + Assert(equal(phv, nlp->paramval)); /* Present, so nothing to do */ break; } } if (lc2 == NULL) { - /* No, so add it after adjusting its nullingrels */ - phv = copyObject(phv); - phv->phnullingrels = bms_intersect(phv->phnullingrels, - root->curOuterRels); + /* No, so add it */ nlp = makeNode(NestLoopParam); nlp->paramno = pitem->paramId; - nlp->paramval = (Var *) phv; + nlp->paramval = (Var *) copyObject(phv); root->curOuterParams = lappend(root->curOuterParams, nlp); } } @@ -525,6 +503,28 @@ process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params) * Identify any NestLoopParams that should be supplied by a NestLoop plan * node with the specified lefthand rels. Remove them from the active * root->curOuterParams list and return them as the result list. + * + * XXX Here we also hack up the returned Vars and PHVs so that they do not + * contain nullingrel sets exceeding what is available from the outer side. + * This is needed if we have applied outer join identity 3, + * (A leftjoin B on (Pab)) leftjoin C on (Pb*c) + * = A leftjoin (B leftjoin C on (Pbc)) on (Pab) + * and C contains lateral references to B. It's still safe to apply the + * identity, but the parser will have created those references in the form + * "b*" (i.e., with varnullingrels listing the A/B join), while what we will + * have available from the nestloop's outer side is just "b". We deal with + * that here by stripping the nullingrels down to what is available from the + * outer side according to leftrelids. + * + * That fixes matters for the case of forward application of identity 3. + * If the identity was applied in the reverse direction, we will have + * parameter Vars containing too few nullingrel bits rather than too many. + * Currently, that causes no problems because setrefs.c applies only a + * subset check to nullingrels in NestLoopParams, but we'd have to work + * harder if we ever want to tighten that check. This is all pretty annoying + * because it greatly weakens setrefs.c's cross-check, but the alternative + * seems to be to generate multiple versions of each laterally-parameterized + * subquery, which'd be unduly expensive. */ List * identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids) @@ -539,13 +539,19 @@ identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids) /* * We are looking for Vars and PHVs that can be supplied by the - * lefthand rels. + * lefthand rels. When we find one, it's okay to modify it in-place + * because all the routines above make a fresh copy to put into + * curOuterParams. */ if (IsA(nlp->paramval, Var) && bms_is_member(nlp->paramval->varno, leftrelids)) { + Var *var = (Var *) nlp->paramval; + root->curOuterParams = foreach_delete_current(root->curOuterParams, cell); + var->varnullingrels = bms_intersect(var->varnullingrels, + leftrelids); result = lappend(result, nlp); } else if (IsA(nlp->paramval, PlaceHolderVar) && @@ -553,8 +559,12 @@ identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids) (PlaceHolderVar *) nlp->paramval)->ph_eval_at, leftrelids)) { + PlaceHolderVar *phv = (PlaceHolderVar *) nlp->paramval; + root->curOuterParams = foreach_delete_current(root->curOuterParams, cell); + phv->phnullingrels = bms_intersect(phv->phnullingrels, + leftrelids); result = lappend(result, nlp); } } |