summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-09-28 14:15:42 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2010-09-28 14:15:42 -0400
commitdc9cc887b74bfa0d40829c4df66dead509fdd8f6 (patch)
tree90e39f8b5f06e7acfd07bd7b1ba525f1af41643b /src/include
parent2dc2ea81f67b96473cefe8fc7d515bda37255660 (diff)
Fix PlaceHolderVar mechanism's interaction with outer joins.
The point of a PlaceHolderVar is to allow a non-strict expression to be evaluated below an outer join, after which its value bubbles up like a Var and can be forced to NULL when the outer join's semantics require that. However, there was a serious design oversight in that, namely that we didn't ensure that there was actually a correct place in the plan tree to evaluate the placeholder :-(. It may be necessary to delay evaluation of an outer join to ensure that a placeholder that should be evaluated below the join can be evaluated there. Per recent bug report from Kirill Simonov. Back-patch to 8.4 where the PlaceHolderVar mechanism was introduced.
Diffstat (limited to 'src/include')
-rw-r--r--src/include/nodes/relation.h17
-rw-r--r--src/include/optimizer/placeholder.h5
2 files changed, 20 insertions, 2 deletions
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 5d306d7860a..6e003765e04 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -1279,8 +1279,22 @@ typedef struct AppendRelInfo
* then allow it to bubble up like a Var until the ph_needed join level.
* ph_needed has the same definition as attr_needed for a regular Var.
*
+ * ph_may_need is an initial estimate of ph_needed, formed using the
+ * syntactic locations of references to the PHV. We need this in order to
+ * determine whether the PHV reference forces a join ordering constraint:
+ * if the PHV has to be evaluated below the nullable side of an outer join,
+ * and then used above that outer join, we must constrain join order to ensure
+ * there's a valid place to evaluate the PHV below the join. The final
+ * actual ph_needed level might be lower than ph_may_need, but we can't
+ * determine that until later on. Fortunately this doesn't matter for what
+ * we need ph_may_need for: if there's a PHV reference syntactically
+ * above the outer join, it's not going to be allowed to drop below the outer
+ * join, so we would come to the same conclusions about join order even if
+ * we had the final ph_needed value to compare to.
+ *
* We create a PlaceHolderInfo only after determining that the PlaceHolderVar
- * is actually referenced in the plan tree.
+ * is actually referenced in the plan tree, so that unreferenced placeholders
+ * don't result in unnecessary constraints on join order.
*/
typedef struct PlaceHolderInfo
@@ -1291,6 +1305,7 @@ typedef struct PlaceHolderInfo
PlaceHolderVar *ph_var; /* copy of PlaceHolderVar tree */
Relids ph_eval_at; /* lowest level we can evaluate value at */
Relids ph_needed; /* highest level the value is needed at */
+ Relids ph_may_need; /* highest level it might be needed at */
int32 ph_width; /* estimated attribute width */
} PlaceHolderInfo;
diff --git a/src/include/optimizer/placeholder.h b/src/include/optimizer/placeholder.h
index 33f9a213992..e38edce27e9 100644
--- a/src/include/optimizer/placeholder.h
+++ b/src/include/optimizer/placeholder.h
@@ -21,7 +21,10 @@ extern PlaceHolderVar *make_placeholder_expr(PlannerInfo *root, Expr *expr,
Relids phrels);
extern PlaceHolderInfo *find_placeholder_info(PlannerInfo *root,
PlaceHolderVar *phv);
-extern void fix_placeholder_eval_levels(PlannerInfo *root);
+extern void find_placeholders_in_jointree(PlannerInfo *root);
+extern void update_placeholder_eval_levels(PlannerInfo *root,
+ SpecialJoinInfo *new_sjinfo);
+extern void fix_placeholder_input_needed_levels(PlannerInfo *root);
extern void add_placeholders_to_joinrel(PlannerInfo *root,
RelOptInfo *joinrel);