summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/initsplan.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-08-01 20:57:41 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2015-08-01 20:57:41 -0400
commitb9dfa07e8ebc4b6fded7a64038873e589eebd7df (patch)
treee0cb41fe82d70e7247e419859960601dc394e5d5 /src/backend/optimizer/plan/initsplan.c
parentea6e286491210e4ec2ddd542faccfe9227eb890f (diff)
Fix some planner issues with degenerate outer join clauses.
An outer join clause that didn't actually reference the RHS (perhaps only after constant-folding) could confuse the join order enforcement logic, leading to wrong query results. Also, nested occurrences of such things could trigger an Assertion that on reflection seems incorrect. Per fuzz testing by Andreas Seltenreich. The practical use of such cases seems thin enough that it's not too surprising we've not heard field reports about it. This has been broken for a long time, so back-patch to all active branches.
Diffstat (limited to 'src/backend/optimizer/plan/initsplan.c')
-rw-r--r--src/backend/optimizer/plan/initsplan.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 5328f19afea..4ab3a6ea42b 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -641,6 +641,20 @@ make_outerjoininfo(PlannerInfo *root,
min_righthand = bms_int_members(bms_union(clause_relids, inner_join_rels),
right_rels);
+ /*
+ * If we have a degenerate join clause that doesn't mention any RHS rels,
+ * force the min RHS to be the syntactic RHS; otherwise we can end up
+ * making serious errors, like putting the LHS on the wrong side of an
+ * outer join. It seems to be safe to not do this when we have a
+ * contribution from inner_join_rels, though; that's enough to pin the SJ
+ * to occur at a reasonable place in the tree.
+ */
+ if (bms_is_empty(min_righthand))
+ min_righthand = bms_copy(right_rels);
+
+ /*
+ * Now check previous outer joins for ordering restrictions.
+ */
foreach(l, root->join_info_list)
{
SpecialJoinInfo *otherinfo = (SpecialJoinInfo *) lfirst(l);
@@ -742,12 +756,10 @@ make_outerjoininfo(PlannerInfo *root,
* If we found nothing to put in min_lefthand, punt and make it the full
* LHS, to avoid having an empty min_lefthand which will confuse later
* processing. (We don't try to be smart about such cases, just correct.)
- * Likewise for min_righthand.
+ * We already forced min_righthand nonempty, so nothing to do for that.
*/
if (bms_is_empty(min_lefthand))
min_lefthand = bms_copy(left_rels);
- if (bms_is_empty(min_righthand))
- min_righthand = bms_copy(right_rels);
/* Now they'd better be nonempty */
Assert(!bms_is_empty(min_lefthand));