summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/equivclass.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/equivclass.c')
-rw-r--r--src/backend/optimizer/path/equivclass.c81
1 files changed, 64 insertions, 17 deletions
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 12669d1b090..c911bcda242 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -28,7 +28,7 @@
static EquivalenceMember *add_eq_member(EquivalenceClass *ec,
- Expr *expr, Relids relids,
+ Expr *expr, Relids relids, Relids nullable_relids,
bool is_child, Oid datatype);
static void generate_base_implied_equalities_const(PlannerInfo *root,
EquivalenceClass *ec);
@@ -98,7 +98,9 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
Expr *item1;
Expr *item2;
Relids item1_relids,
- item2_relids;
+ item2_relids,
+ item1_nullable_relids,
+ item2_nullable_relids;
List *opfamilies;
EquivalenceClass *ec1,
*ec2;
@@ -140,6 +142,12 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
return false; /* RHS is non-strict but not constant */
}
+ /* Calculate nullable-relid sets for each side of the clause */
+ item1_nullable_relids = bms_intersect(item1_relids,
+ restrictinfo->nullable_relids);
+ item2_nullable_relids = bms_intersect(item2_relids,
+ restrictinfo->nullable_relids);
+
/*
* We use the declared input types of the operator, not exprType() of the
* inputs, as the nominal datatypes for opfamily lookup. This presumes
@@ -274,7 +282,8 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
else if (ec1)
{
/* Case 3: add item2 to ec1 */
- em2 = add_eq_member(ec1, item2, item2_relids, false, item2_type);
+ em2 = add_eq_member(ec1, item2, item2_relids, item2_nullable_relids,
+ false, item2_type);
ec1->ec_sources = lappend(ec1->ec_sources, restrictinfo);
ec1->ec_below_outer_join |= below_outer_join;
/* mark the RI as usable with this pair of EMs */
@@ -284,7 +293,8 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
else if (ec2)
{
/* Case 3: add item1 to ec2 */
- em1 = add_eq_member(ec2, item1, item1_relids, false, item1_type);
+ em1 = add_eq_member(ec2, item1, item1_relids, item1_nullable_relids,
+ false, item1_type);
ec2->ec_sources = lappend(ec2->ec_sources, restrictinfo);
ec2->ec_below_outer_join |= below_outer_join;
/* mark the RI as usable with this pair of EMs */
@@ -307,8 +317,10 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
ec->ec_broken = false;
ec->ec_sortref = 0;
ec->ec_merged = NULL;
- em1 = add_eq_member(ec, item1, item1_relids, false, item1_type);
- em2 = add_eq_member(ec, item2, item2_relids, false, item2_type);
+ em1 = add_eq_member(ec, item1, item1_relids, item1_nullable_relids,
+ false, item1_type);
+ em2 = add_eq_member(ec, item2, item2_relids, item2_nullable_relids,
+ false, item2_type);
root->eq_classes = lappend(root->eq_classes, ec);
@@ -325,12 +337,13 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
*/
static EquivalenceMember *
add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
- bool is_child, Oid datatype)
+ Relids nullable_relids, bool is_child, Oid datatype)
{
EquivalenceMember *em = makeNode(EquivalenceMember);
em->em_expr = expr;
em->em_relids = relids;
+ em->em_nullable_relids = nullable_relids;
em->em_is_const = false;
em->em_is_child = is_child;
em->em_datatype = datatype;
@@ -452,7 +465,7 @@ get_eclass_for_sort_expr(PlannerInfo *root,
elog(ERROR, "volatile EquivalenceClass has no sortref");
newem = add_eq_member(newec, expr, pull_varnos((Node *) expr),
- false, expr_datatype);
+ NULL, false, expr_datatype);
/*
* add_eq_member doesn't check for volatile functions, set-returning
@@ -632,7 +645,9 @@ generate_base_implied_equalities_const(PlannerInfo *root,
}
process_implied_equality(root, eq_op,
cur_em->em_expr, const_em->em_expr,
- ec->ec_relids,
+ bms_copy(ec->ec_relids),
+ bms_union(cur_em->em_nullable_relids,
+ const_em->em_nullable_relids),
ec->ec_below_outer_join,
cur_em->em_is_const);
}
@@ -687,7 +702,9 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
}
process_implied_equality(root, eq_op,
prev_em->em_expr, cur_em->em_expr,
- ec->ec_relids,
+ bms_copy(ec->ec_relids),
+ bms_union(prev_em->em_nullable_relids,
+ cur_em->em_nullable_relids),
ec->ec_below_outer_join,
false);
}
@@ -1089,7 +1106,9 @@ create_join_clause(PlannerInfo *root,
leftem->em_expr,
rightem->em_expr,
bms_union(leftem->em_relids,
- rightem->em_relids));
+ rightem->em_relids),
+ bms_union(leftem->em_nullable_relids,
+ rightem->em_nullable_relids));
/* Mark the clause as redundant, or not */
rinfo->parent_ec = parent_ec;
@@ -1310,7 +1329,8 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo,
left_type,
right_type,
inner_datatype;
- Relids inner_relids;
+ Relids inner_relids,
+ inner_nullable_relids;
ListCell *lc1;
Assert(is_opclause(rinfo->clause));
@@ -1336,6 +1356,8 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo,
inner_datatype = left_type;
inner_relids = rinfo->left_relids;
}
+ inner_nullable_relids = bms_intersect(inner_relids,
+ rinfo->nullable_relids);
/* Scan EquivalenceClasses for a match to outervar */
foreach(lc1, root->eq_classes)
@@ -1390,7 +1412,8 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo,
newrinfo = build_implied_join_equality(eq_op,
innervar,
cur_em->em_expr,
- inner_relids);
+ bms_copy(inner_relids),
+ bms_copy(inner_nullable_relids));
if (process_equivalence(root, newrinfo, true))
match = true;
}
@@ -1423,7 +1446,9 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
left_type,
right_type;
Relids left_relids,
- right_relids;
+ right_relids,
+ left_nullable_relids,
+ right_nullable_relids;
ListCell *lc1;
/* Can't use an outerjoin_delayed clause here */
@@ -1438,6 +1463,10 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
rightvar = (Expr *) get_rightop(rinfo->clause);
left_relids = rinfo->left_relids;
right_relids = rinfo->right_relids;
+ left_nullable_relids = bms_intersect(left_relids,
+ rinfo->nullable_relids);
+ right_nullable_relids = bms_intersect(right_relids,
+ rinfo->nullable_relids);
foreach(lc1, root->eq_classes)
{
@@ -1519,7 +1548,8 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
newrinfo = build_implied_join_equality(eq_op,
leftvar,
cur_em->em_expr,
- left_relids);
+ bms_copy(left_relids),
+ bms_copy(left_nullable_relids));
if (process_equivalence(root, newrinfo, true))
matchleft = true;
}
@@ -1531,7 +1561,8 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
newrinfo = build_implied_join_equality(eq_op,
rightvar,
cur_em->em_expr,
- right_relids);
+ bms_copy(right_relids),
+ bms_copy(right_nullable_relids));
if (process_equivalence(root, newrinfo, true))
matchright = true;
}
@@ -1651,11 +1682,27 @@ add_child_rel_equivalences(PlannerInfo *root,
{
/* Yes, generate transformed child version */
Expr *child_expr;
+ Relids new_nullable_relids;
child_expr = (Expr *)
adjust_appendrel_attrs((Node *) cur_em->em_expr,
appinfo);
- (void) add_eq_member(cur_ec, child_expr, child_rel->relids,
+
+ /*
+ * Must translate nullable_relids. Note this code assumes
+ * parent and child relids are singletons.
+ */
+ new_nullable_relids = cur_em->em_nullable_relids;
+ if (bms_overlap(new_nullable_relids, parent_rel->relids))
+ {
+ new_nullable_relids = bms_difference(new_nullable_relids,
+ parent_rel->relids);
+ new_nullable_relids = bms_add_members(new_nullable_relids,
+ child_rel->relids);
+ }
+
+ (void) add_eq_member(cur_ec, child_expr,
+ child_rel->relids, new_nullable_relids,
true, cur_em->em_datatype);
}
}