diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2010-09-28 14:15:42 -0400 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2010-09-28 14:15:42 -0400 |
| commit | dc9cc887b74bfa0d40829c4df66dead509fdd8f6 (patch) | |
| tree | 90e39f8b5f06e7acfd07bd7b1ba525f1af41643b /src/include | |
| parent | 2dc2ea81f67b96473cefe8fc7d515bda37255660 (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.h | 17 | ||||
| -rw-r--r-- | src/include/optimizer/placeholder.h | 5 |
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); |
