summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-11-03 00:50:58 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2011-11-03 00:50:58 -0400
commit7e3bf99baa18524de6ef1492cb3057314da97e68 (patch)
tree3ebe96ce2088e06cf2e2ee471ff5e259926cba46 /src/backend/optimizer/plan
parent1a77f8b63d159b88ceb6245fcb5e81a7f9ac9a22 (diff)
downloadpostgresql-7e3bf99baa18524de6ef1492cb3057314da97e68.tar.gz
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')
-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
3 files changed, 128 insertions, 8 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index a76f2c603c..8138b0118b 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.
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 493103a1db..1c0d70b5b3 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1082,6 +1082,10 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset)
outer_itlist,
OUTER_VAR,
rtoffset);
+ /* Check we replaced any PlaceHolderVar with simple Var */
+ if (!(IsA(nlp->paramval, Var) &&
+ nlp->paramval->varno == OUTER_VAR))
+ 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 c4046ca534..e396520652 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -170,7 +170,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;
@@ -191,6 +191,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).
*/