aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/analyzejoins.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-09-25 19:03:50 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2010-09-25 19:03:50 -0400
commitc8c03d72e10cab3cc47975b2689c8efbb4eade94 (patch)
tree8b2d457b2976c808393db387e99d5e61aa5606a1 /src/backend/optimizer/plan/analyzejoins.c
parent635de8365f0299cfa2db24c56abcfccb65d020f0 (diff)
downloadpostgresql-c8c03d72e10cab3cc47975b2689c8efbb4eade94.tar.gz
postgresql-c8c03d72e10cab3cc47975b2689c8efbb4eade94.zip
Fix another join removal bug: the check on PlaceHolderVars was wrong.
The previous coding would decide that join removal was unsafe upon finding a PlaceHolderVar that needed to be evaluated at the inner rel and then used above the join. However, this fails to cover the case of PlaceHolderVars that refer to both the inner rel and some other rels. Per bug report from Andrus.
Diffstat (limited to 'src/backend/optimizer/plan/analyzejoins.c')
-rw-r--r--src/backend/optimizer/plan/analyzejoins.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/src/backend/optimizer/plan/analyzejoins.c b/src/backend/optimizer/plan/analyzejoins.c
index 97f8839ff2c..2a913578eba 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -26,6 +26,7 @@
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
+#include "optimizer/var.h"
/* local functions */
static bool join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo);
@@ -197,16 +198,23 @@ join_is_removable(PlannerInfo *root, SpecialJoinInfo *sjinfo)
}
/*
- * Similarly check that the inner rel doesn't produce any PlaceHolderVars
- * that will be used above the join.
+ * Similarly check that the inner rel isn't needed by any PlaceHolderVars
+ * that will be used above the join. We only need to fail if such a PHV
+ * actually references some inner-rel attributes; but the correct check
+ * for that is relatively expensive, so we first check against ph_eval_at,
+ * which must mention the inner rel if the PHV uses any inner-rel attrs.
*/
foreach(l, root->placeholder_list)
{
PlaceHolderInfo *phinfo = (PlaceHolderInfo *) lfirst(l);
- if (bms_is_subset(phinfo->ph_eval_at, innerrel->relids) &&
- !bms_is_subset(phinfo->ph_needed, joinrelids))
- return false;
+ if (bms_is_subset(phinfo->ph_needed, joinrelids))
+ continue; /* PHV is not used above the join */
+ if (!bms_overlap(phinfo->ph_eval_at, innerrel->relids))
+ continue; /* it definitely doesn't reference innerrel */
+ if (bms_overlap(pull_varnos((Node *) phinfo->ph_var),
+ innerrel->relids))
+ return false; /* it does reference innerrel */
}
/*