diff options
Diffstat (limited to 'src/backend/optimizer/plan/subselect.c')
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 151 |
1 files changed, 107 insertions, 44 deletions
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index f30f02f266d..fb6c7045484 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -191,25 +191,22 @@ assign_nestloop_param_var(PlannerInfo *root, Var *var) } /* - * Generate a Param node to replace the given PlaceHolderVar, which will be - * supplied from an upper NestLoop join node. + * Select a PARAM_EXEC number to identify the given PlaceHolderVar. + * If the PlaceHolderVar already has a param slot, return that one. * - * This is just like assign_nestloop_param_var, except for PlaceHolderVars. + * This is just like assign_param_for_var, except for PlaceHolderVars. */ -Param * -assign_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) +static int +assign_param_for_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) { - Param *retval; ListCell *ppl; PlannerParamItem *pitem; Index abslevel; int i; - Assert(phv->phlevelsup == 0); - abslevel = root->query_level; + abslevel = root->query_level - phv->phlevelsup; /* If there's already a paramlist entry for this same PHV, just use it */ - /* We assume comparing the PHIDs is sufficient */ i = 0; foreach(ppl, root->glob->paramlist) { @@ -218,25 +215,77 @@ assign_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) { PlaceHolderVar *pphv = (PlaceHolderVar *) pitem->item; + /* We assume comparing the PHIDs is sufficient */ if (pphv->phid == phv->phid) - break; + return i; } i++; } - if (ppl == NULL) + /* Nope, so make a new one */ + phv = (PlaceHolderVar *) copyObject(phv); + if (phv->phlevelsup != 0) { - /* Nope, so make a new one */ - phv = (PlaceHolderVar *) copyObject(phv); + IncrementVarSublevelsUp((Node *) phv, -((int) phv->phlevelsup), 0); + Assert(phv->phlevelsup == 0); + } - pitem = makeNode(PlannerParamItem); - pitem->item = (Node *) phv; - pitem->abslevel = abslevel; + pitem = makeNode(PlannerParamItem); + pitem->item = (Node *) phv; + pitem->abslevel = abslevel; - root->glob->paramlist = lappend(root->glob->paramlist, pitem); + root->glob->paramlist = lappend(root->glob->paramlist, pitem); - /* i is already the correct list index for the new item */ - } + /* i is already the correct list index for the new item */ + return i; +} + +/* + * Generate a Param node to replace the given PlaceHolderVar, + * which is expected to have phlevelsup > 0 (ie, it is not local). + * + * This is just like replace_outer_var, except for PlaceHolderVars. + */ +static Param * +replace_outer_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) +{ + Param *retval; + int i; + + Assert(phv->phlevelsup > 0 && phv->phlevelsup < root->query_level); + + /* + * Find the PlaceHolderVar in root->glob->paramlist, or add it if not + * present. + */ + i = assign_param_for_placeholdervar(root, phv); + + retval = makeNode(Param); + retval->paramkind = PARAM_EXEC; + retval->paramid = i; + retval->paramtype = exprType((Node *) phv->phexpr); + retval->paramtypmod = exprTypmod((Node *) phv->phexpr); + retval->paramcollid = exprCollation((Node *) phv->phexpr); + retval->location = -1; + + return retval; +} + +/* + * Generate a Param node to replace the given PlaceHolderVar, which will be + * supplied from an upper NestLoop join node. + * + * This is just like assign_nestloop_param_var, except for PlaceHolderVars. + */ +Param * +assign_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv) +{ + Param *retval; + int i; + + Assert(phv->phlevelsup == 0); + + i = assign_param_for_placeholdervar(root, phv); retval = makeNode(Param); retval->paramkind = PARAM_EXEC; @@ -555,17 +604,19 @@ build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot, Node *arg; /* - * The Var or Aggref has already been adjusted to have the correct - * varlevelsup or agglevelsup. We probably don't even need to - * copy it again, but be safe. + * The Var, PlaceHolderVar, or Aggref has already been adjusted to + * have the correct varlevelsup, phlevelsup, or agglevelsup. We + * probably don't even need to copy it again, but be safe. */ arg = copyObject(pitem->item); /* - * If it's an Aggref, its arguments might contain SubLinks, which - * have not yet been processed. Do that now. + * If it's a PlaceHolderVar or Aggref, its arguments might contain + * SubLinks, which have not yet been processed (see the comments + * for SS_replace_correlation_vars). Do that now. */ - if (IsA(arg, Aggref)) + if (IsA(arg, PlaceHolderVar) || + IsA(arg, Aggref)) arg = SS_process_sublinks(root, arg, false); splan->parParam = lappend_int(splan->parParam, paramid); @@ -1668,24 +1719,25 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect, /* * Replace correlation vars (uplevel vars) with Params. * - * Uplevel aggregates are replaced, too. + * Uplevel PlaceHolderVars and aggregates are replaced, too. * * Note: it is critical that this runs immediately after SS_process_sublinks. - * Since we do not recurse into the arguments of uplevel aggregates, they will - * get copied to the appropriate subplan args list in the parent query with - * uplevel vars not replaced by Params, but only adjusted in level (see - * replace_outer_agg). That's exactly what we want for the vars of the parent - * level --- but if an aggregate's argument contains any further-up variables, - * they have to be replaced with Params in their turn. That will happen when - * the parent level runs SS_replace_correlation_vars. Therefore it must do - * so after expanding its sublinks to subplans. And we don't want any steps - * in between, else those steps would never get applied to the aggregate - * argument expressions, either in the parent or the child level. + * Since we do not recurse into the arguments of uplevel PHVs and aggregates, + * they will get copied to the appropriate subplan args list in the parent + * query with uplevel vars not replaced by Params, but only adjusted in level + * (see replace_outer_placeholdervar and replace_outer_agg). That's exactly + * what we want for the vars of the parent level --- but if a PHV's or + * aggregate's argument contains any further-up variables, they have to be + * replaced with Params in their turn. That will happen when the parent level + * runs SS_replace_correlation_vars. Therefore it must do so after expanding + * its sublinks to subplans. And we don't want any steps in between, else + * those steps would never get applied to the argument expressions, either in + * the parent or the child level. * * Another fairly tricky thing going on here is the handling of SubLinks in - * the arguments of uplevel aggregates. Those are not touched inside the - * intermediate query level, either. Instead, SS_process_sublinks recurses - * on them after copying the Aggref expression into the parent plan level + * the arguments of uplevel PHVs/aggregates. Those are not touched inside the + * intermediate query level, either. Instead, SS_process_sublinks recurses on + * them after copying the PHV or Aggref expression into the parent plan level * (this is actually taken care of in build_subplan). */ Node * @@ -1705,6 +1757,12 @@ replace_correlation_vars_mutator(Node *node, PlannerInfo *root) if (((Var *) node)->varlevelsup > 0) return (Node *) replace_outer_var(root, (Var *) node); } + if (IsA(node, PlaceHolderVar)) + { + if (((PlaceHolderVar *) node)->phlevelsup > 0) + return (Node *) replace_outer_placeholdervar(root, + (PlaceHolderVar *) node); + } if (IsA(node, Aggref)) { if (((Aggref *) node)->agglevelsup > 0) @@ -1764,12 +1822,17 @@ process_sublinks_mutator(Node *node, process_sublinks_context *context) } /* - * Don't recurse into the arguments of an outer aggregate here. Any - * SubLinks in the arguments have to be dealt with at the outer query - * level; they'll be handled when build_subplan collects the Aggref into - * the arguments to be passed down to the current subplan. + * Don't recurse into the arguments of an outer PHV or aggregate here. + * Any SubLinks in the arguments have to be dealt with at the outer query + * level; they'll be handled when build_subplan collects the PHV or Aggref + * into the arguments to be passed down to the current subplan. */ - if (IsA(node, Aggref)) + if (IsA(node, PlaceHolderVar)) + { + if (((PlaceHolderVar *) node)->phlevelsup > 0) + return node; + } + else if (IsA(node, Aggref)) { if (((Aggref *) node)->agglevelsup > 0) return node; |