aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2015-08-12 21:18:45 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2015-08-12 21:19:04 -0400
commitec94bc1473475128ef4e7b62636e66effd314102 (patch)
tree9e3d55ae4c277ccc5e8c08beaeeb7a786880d903 /src/backend
parentfc0a6402306db3cc93a5f760acabab687998be1d (diff)
downloadpostgresql-ec94bc1473475128ef4e7b62636e66effd314102.tar.gz
postgresql-ec94bc1473475128ef4e7b62636e66effd314102.zip
Undo mistaken tightening in join_is_legal().
One of the changes I made in commit 8703059c6b55c427 turns out not to have been such a good idea: we still need the exception in join_is_legal() that allows a join if both inputs already overlap the RHS of the special join we're checking. Otherwise we can miss valid plans, and might indeed fail to find a plan at all, as in recent report from Andreas Seltenreich. That code was added way back in commit c17117649b9ae23d, but I failed to include a regression test case then; my bad. Put it back with a better explanation, and a test this time. The logic does end up a bit different than before though: I now believe it's appropriate to make this check first, thereby allowing such a case whether or not we'd consider the previous SJ(s) to commute with this one. (Presumably, we already decided they did; but it was confusing to have this consideration in the middle of the code that was handling the other case.) Back-patch to all active branches, like the previous patch.
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/optimizer/path/joinrels.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index e0103c80431..b2cc9f07f56 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -470,11 +470,30 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
{
/*
* Otherwise, the proposed join overlaps the RHS but isn't a valid
- * implementation of this SJ. It might still be a legal join,
- * however, if we're allowed to associate it into the RHS of this
- * SJ. That means this SJ must be a LEFT join (not SEMI or ANTI,
- * and certainly not FULL) and the proposed join must not overlap
- * the LHS.
+ * implementation of this SJ. But don't panic quite yet: the RHS
+ * violation might have occurred previously, in one or both input
+ * relations, in which case we must have previously decided that
+ * it was OK to commute some other SJ with this one. If we need
+ * to perform this join to finish building up the RHS, rejecting
+ * it could lead to not finding any plan at all. (This can occur
+ * because of the heuristics elsewhere in this file that postpone
+ * clauseless joins: we might not consider doing a clauseless join
+ * within the RHS until after we've performed other, validly
+ * commutable SJs with one or both sides of the clauseless join.)
+ * This consideration boils down to the rule that if both inputs
+ * overlap the RHS, we can allow the join --- they are either
+ * fully within the RHS, or represent previously-allowed joins to
+ * rels outside it.
+ */
+ if (bms_overlap(rel1->relids, sjinfo->min_righthand) &&
+ bms_overlap(rel2->relids, sjinfo->min_righthand))
+ continue; /* assume valid previous violation of RHS */
+
+ /*
+ * The proposed join could still be legal, but only if we're
+ * allowed to associate it into the RHS of this SJ. That means
+ * this SJ must be a LEFT join (not SEMI or ANTI, and certainly
+ * not FULL) and the proposed join must not overlap the LHS.
*/
if (sjinfo->jointype != JOIN_LEFT ||
bms_overlap(joinrelids, sjinfo->min_lefthand))