aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/executor/nodeNestloop.c1
-rw-r--r--src/backend/optimizer/plan/createplan.c71
-rw-r--r--src/backend/optimizer/plan/setrefs.c4
-rw-r--r--src/backend/optimizer/plan/subselect.c61
4 files changed, 129 insertions, 8 deletions
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index e98bc0f5a30..b4793583587 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -148,6 +148,7 @@ ExecNestLoop(NestLoopState *node)
prm = &(econtext->ecxt_param_exec_vals[paramno]);
/* Param value should be an OUTER var */
+ Assert(IsA(nlp->paramval, Var));
Assert(nlp->paramval->varno == OUTER);
Assert(nlp->paramval->varattno > 0);
prm->value = slot_getattr(outerTupleSlot,
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 8243802199d..7a81010e4cf 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"
@@ -1886,7 +1887,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);
@@ -2314,11 +2328,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)
@@ -2345,7 +2360,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)
{
@@ -2365,6 +2380,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);
@@ -2377,7 +2434,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.
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 60a1484c992..01d2cec562f 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1019,6 +1019,10 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset)
(Node *) nlp->paramval,
outer_itlist,
rtoffset);
+ /* Check we replaced any PlaceHolderVar with simple Var */
+ if (!(IsA(nlp->paramval, Var) &&
+ nlp->paramval->varno == OUTER))
+ elog(ERROR, "NestLoopParam was not reduced to a simple Var");
}
}
else if (IsA(join, MergeJoin))
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 71ffc17b599..570151e6065 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -172,7 +172,7 @@ replace_outer_var(PlannerInfo *root, Var *var)
* the Var to be local to the current query level.
*/
Param *
-assign_nestloop_param(PlannerInfo *root, Var *var)
+assign_nestloop_param_var(PlannerInfo *root, Var *var)
{
Param *retval;
int i;
@@ -193,6 +193,65 @@ assign_nestloop_param(PlannerInfo *root, Var *var)
}
/*
+ * 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;
+ ListCell *ppl;
+ PlannerParamItem *pitem;
+ Index abslevel;
+ int i;
+
+ Assert(phv->phlevelsup == 0);
+ abslevel = root->query_level;
+
+ /* 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)
+ {
+ pitem = (PlannerParamItem *) lfirst(ppl);
+ if (pitem->abslevel == abslevel && IsA(pitem->item, PlaceHolderVar))
+ {
+ PlaceHolderVar *pphv = (PlaceHolderVar *) pitem->item;
+
+ if (pphv->phid == phv->phid)
+ break;
+ }
+ i++;
+ }
+
+ if (ppl == NULL)
+ {
+ /* Nope, so make a new one */
+ phv = (PlaceHolderVar *) copyObject(phv);
+
+ pitem = makeNode(PlannerParamItem);
+ pitem->item = (Node *) phv;
+ pitem->abslevel = abslevel;
+
+ root->glob->paramlist = lappend(root->glob->paramlist, pitem);
+
+ /* i is already the correct list index for the new item */
+ }
+
+ 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 Aggref
* which is expected to have agglevelsup > 0 (ie, it is not local).
*/