v7-0008-remove-nullable_relids.patch
text/x-diff
Filename: v7-0008-remove-nullable_relids.patch
Type: text/x-diff
Part: 8
Message:
Re: Making Vars outer-join aware
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v7-0008
| File | + | − |
|---|---|---|
| contrib/postgres_fdw/postgres_fdw.c | 0 | 1 |
| src/backend/optimizer/path/allpaths.c | 0 | 1 |
| src/backend/optimizer/path/equivclass.c | 14 | 80 |
| src/backend/optimizer/path/pathkeys.c | 7 | 33 |
| src/backend/optimizer/plan/initsplan.c | 11 | 61 |
| src/backend/optimizer/util/appendinfo.c | 0 | 3 |
| src/backend/optimizer/util/inherit.c | 2 | 2 |
| src/backend/optimizer/util/orclauses.c | 0 | 1 |
| src/backend/optimizer/util/restrictinfo.c | 13 | 25 |
| src/include/nodes/pathnodes.h | 1 | 15 |
| src/include/optimizer/paths.h | 1 | 2 |
| src/include/optimizer/planmain.h | 0 | 2 |
| src/include/optimizer/restrictinfo.h | 2 | 3 |
commit d3e9a64ebc89bd2fa9005386e5a7380884d3c512
Author: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed Nov 16 16:21:54 2022 -0500
Remove RestrictInfo.nullable_relids and associated infrastructure.
There is no more code using this field, only code computing it,
so just delete all that. We can likewise get rid of
EquivalenceMember.em_nullable_relids and
PlannerInfo.nullable_baserels.
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 39cc37053c..10aa27a78a 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -6313,7 +6313,6 @@ foreign_grouping_ok(PlannerInfo *root, RelOptInfo *grouped_rel,
false,
root->qual_security_level,
grouped_rel->relids,
- NULL,
NULL);
if (is_foreign_expr(root, grouped_rel, expr))
fpinfo->remote_conds = lappend(fpinfo->remote_conds, rinfo);
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 5902c80747..8a6a40f672 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -2733,7 +2733,6 @@ set_function_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
if (var)
pathkeys = build_expression_pathkey(root,
(Expr *) var,
- NULL, /* below outer joins */
Int8LessOperator,
rel->relids,
false);
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index d4f8b7893d..0737cc355f 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -34,7 +34,7 @@
static EquivalenceMember *add_eq_member(EquivalenceClass *ec,
- Expr *expr, Relids relids, Relids nullable_relids,
+ Expr *expr, Relids relids,
EquivalenceMember *parent,
Oid datatype);
static bool is_exprlist_member(Expr *node, List *exprs);
@@ -131,9 +131,7 @@ process_equivalence(PlannerInfo *root,
Expr *item1;
Expr *item2;
Relids item1_relids,
- item2_relids,
- item1_nullable_relids,
- item2_nullable_relids;
+ item2_relids;
List *opfamilies;
EquivalenceClass *ec1,
*ec2;
@@ -206,8 +204,7 @@ process_equivalence(PlannerInfo *root,
restrictinfo->pseudoconstant,
restrictinfo->security_level,
NULL,
- restrictinfo->outer_relids,
- restrictinfo->nullable_relids);
+ restrictinfo->outer_relids);
}
return false;
}
@@ -225,12 +222,6 @@ process_equivalence(PlannerInfo *root,
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
@@ -400,7 +391,7 @@ process_equivalence(PlannerInfo *root,
else if (ec1)
{
/* Case 3: add item2 to ec1 */
- em2 = add_eq_member(ec1, item2, item2_relids, item2_nullable_relids,
+ em2 = add_eq_member(ec1, item2, item2_relids,
NULL, item2_type);
ec1->ec_sources = lappend(ec1->ec_sources, restrictinfo);
ec1->ec_below_outer_join |= below_outer_join;
@@ -418,7 +409,7 @@ process_equivalence(PlannerInfo *root,
else if (ec2)
{
/* Case 3: add item1 to ec2 */
- em1 = add_eq_member(ec2, item1, item1_relids, item1_nullable_relids,
+ em1 = add_eq_member(ec2, item1, item1_relids,
NULL, item1_type);
ec2->ec_sources = lappend(ec2->ec_sources, restrictinfo);
ec2->ec_below_outer_join |= below_outer_join;
@@ -452,9 +443,9 @@ process_equivalence(PlannerInfo *root,
ec->ec_min_security = restrictinfo->security_level;
ec->ec_max_security = restrictinfo->security_level;
ec->ec_merged = NULL;
- em1 = add_eq_member(ec, item1, item1_relids, item1_nullable_relids,
+ em1 = add_eq_member(ec, item1, item1_relids,
NULL, item1_type);
- em2 = add_eq_member(ec, item2, item2_relids, item2_nullable_relids,
+ em2 = add_eq_member(ec, item2, item2_relids,
NULL, item2_type);
root->eq_classes = lappend(root->eq_classes, ec);
@@ -545,13 +536,12 @@ canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation)
*/
static EquivalenceMember *
add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
- Relids nullable_relids, EquivalenceMember *parent, Oid datatype)
+ EquivalenceMember *parent, 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 = (parent != NULL);
em->em_datatype = datatype;
@@ -588,13 +578,6 @@ add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
* equivalence class it is a member of; if none, optionally build a new
* single-member EquivalenceClass for it.
*
- * expr is the expression, and nullable_relids is the set of base relids
- * that are potentially nullable below it. We actually only care about
- * the set of such relids that are used in the expression; but for caller
- * convenience, we perform that intersection step here. The caller need
- * only be sure that nullable_relids doesn't omit any nullable rels that
- * might appear in the expr.
- *
* sortref is the SortGroupRef of the originating SortGroupClause, if any,
* or zero if not. (It should never be zero if the expression is volatile!)
*
@@ -623,7 +606,6 @@ add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
EquivalenceClass *
get_eclass_for_sort_expr(PlannerInfo *root,
Expr *expr,
- Relids nullable_relids,
List *opfamilies,
Oid opcintype,
Oid collation,
@@ -719,13 +701,12 @@ get_eclass_for_sort_expr(PlannerInfo *root,
elog(ERROR, "volatile EquivalenceClass has no sortref");
/*
- * Get the precise set of nullable relids appearing in the expression.
+ * Get the precise set of relids appearing in the expression.
*/
expr_relids = pull_varnos(root, (Node *) expr);
- nullable_relids = bms_intersect(nullable_relids, expr_relids);
newem = add_eq_member(newec, copyObject(expr), expr_relids,
- nullable_relids, NULL, opcintype);
+ NULL, opcintype);
/*
* add_eq_member doesn't check for volatile functions, set-returning
@@ -1211,8 +1192,6 @@ generate_base_implied_equalities_const(PlannerInfo *root,
rinfo = process_implied_equality(root, eq_op, ec->ec_collation,
cur_em->em_expr, const_em->em_expr,
bms_copy(ec->ec_relids),
- bms_union(cur_em->em_nullable_relids,
- const_em->em_nullable_relids),
ec->ec_min_security,
ec->ec_below_outer_join,
cur_em->em_is_const);
@@ -1285,8 +1264,6 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
rinfo = process_implied_equality(root, eq_op, ec->ec_collation,
prev_em->em_expr, cur_em->em_expr,
bms_copy(ec->ec_relids),
- bms_union(prev_em->em_nullable_relids,
- cur_em->em_nullable_relids),
ec->ec_min_security,
ec->ec_below_outer_join,
false);
@@ -1889,8 +1866,6 @@ create_join_clause(PlannerInfo *root,
rightem->em_expr,
bms_union(leftem->em_relids,
rightem->em_relids),
- bms_union(leftem->em_nullable_relids,
- rightem->em_nullable_relids),
ec->ec_min_security);
/* If it's a child clause, copy the parent's rinfo_serial */
@@ -2105,8 +2080,7 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo,
left_type,
right_type,
inner_datatype;
- Relids inner_relids,
- inner_nullable_relids;
+ Relids inner_relids;
ListCell *lc1;
Assert(is_opclause(rinfo->clause));
@@ -2133,8 +2107,6 @@ 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)
@@ -2195,7 +2167,6 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo,
innervar,
cur_em->em_expr,
bms_copy(inner_relids),
- bms_copy(inner_nullable_relids),
cur_ec->ec_min_security);
if (process_equivalence(root, &newrinfo, true))
match = true;
@@ -2233,9 +2204,7 @@ reconsider_full_join_clause(PlannerInfo *root, FullJoinClauseInfo *fjinfo)
left_type,
right_type;
Relids left_relids,
- right_relids,
- left_nullable_relids,
- right_nullable_relids;
+ right_relids;
ListCell *lc1;
/* Can't use an outerjoin_delayed clause here */
@@ -2251,10 +2220,6 @@ reconsider_full_join_clause(PlannerInfo *root, FullJoinClauseInfo *fjinfo)
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)
{
@@ -2356,7 +2321,6 @@ reconsider_full_join_clause(PlannerInfo *root, FullJoinClauseInfo *fjinfo)
leftvar,
cur_em->em_expr,
bms_copy(left_relids),
- bms_copy(left_nullable_relids),
cur_ec->ec_min_security);
if (process_equivalence(root, &newrinfo, true))
matchleft = true;
@@ -2372,7 +2336,6 @@ reconsider_full_join_clause(PlannerInfo *root, FullJoinClauseInfo *fjinfo)
rightvar,
cur_em->em_expr,
bms_copy(right_relids),
- bms_copy(right_nullable_relids),
cur_ec->ec_min_security);
if (process_equivalence(root, &newrinfo, true))
matchright = true;
@@ -2662,7 +2625,6 @@ add_child_rel_equivalences(PlannerInfo *root,
/* Yes, generate transformed child version */
Expr *child_expr;
Relids new_relids;
- Relids new_nullable_relids;
if (parent_rel->reloptkind == RELOPT_BASEREL)
{
@@ -2692,21 +2654,7 @@ add_child_rel_equivalences(PlannerInfo *root,
top_parent_relids);
new_relids = bms_add_members(new_relids, child_relids);
- /*
- * And likewise for 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, top_parent_relids))
- {
- new_nullable_relids = bms_difference(new_nullable_relids,
- top_parent_relids);
- new_nullable_relids = bms_add_members(new_nullable_relids,
- child_relids);
- }
-
- (void) add_eq_member(cur_ec, child_expr,
- new_relids, new_nullable_relids,
+ (void) add_eq_member(cur_ec, child_expr, new_relids,
cur_em, cur_em->em_datatype);
/* Record this EC index for the child rel */
@@ -2803,7 +2751,6 @@ add_child_join_rel_equivalences(PlannerInfo *root,
/* Yes, generate transformed child version */
Expr *child_expr;
Relids new_relids;
- Relids new_nullable_relids;
if (parent_joinrel->reloptkind == RELOPT_JOINREL)
{
@@ -2834,20 +2781,7 @@ add_child_join_rel_equivalences(PlannerInfo *root,
top_parent_relids);
new_relids = bms_add_members(new_relids, child_relids);
- /*
- * For nullable_relids, we must selectively replace parent
- * nullable relids with child ones.
- */
- new_nullable_relids = cur_em->em_nullable_relids;
- if (bms_overlap(new_nullable_relids, top_parent_relids))
- new_nullable_relids =
- adjust_child_relids_multilevel(root,
- new_nullable_relids,
- child_joinrel,
- child_joinrel->top_parent);
-
- (void) add_eq_member(cur_ec, child_expr,
- new_relids, new_nullable_relids,
+ (void) add_eq_member(cur_ec, child_expr, new_relids,
cur_em, cur_em->em_datatype);
}
}
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index a9943cd6e0..bf919ca97f 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -180,9 +180,6 @@ pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys)
* Given an expression and sort-order information, create a PathKey.
* The result is always a "canonical" PathKey, but it might be redundant.
*
- * expr is the expression, and nullable_relids is the set of base relids
- * that are potentially nullable below it.
- *
* If the PathKey is being generated from a SortGroupClause, sortref should be
* the SortGroupClause's SortGroupRef; otherwise zero.
*
@@ -198,7 +195,6 @@ pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys)
static PathKey *
make_pathkey_from_sortinfo(PlannerInfo *root,
Expr *expr,
- Relids nullable_relids,
Oid opfamily,
Oid opcintype,
Oid collation,
@@ -234,7 +230,7 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
equality_op);
/* Now find or (optionally) create a matching EquivalenceClass */
- eclass = get_eclass_for_sort_expr(root, expr, nullable_relids,
+ eclass = get_eclass_for_sort_expr(root, expr,
opfamilies, opcintype, collation,
sortref, rel, create_it);
@@ -257,7 +253,6 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
static PathKey *
make_pathkey_from_sortop(PlannerInfo *root,
Expr *expr,
- Relids nullable_relids,
Oid ordering_op,
bool nulls_first,
Index sortref,
@@ -279,7 +274,6 @@ make_pathkey_from_sortop(PlannerInfo *root,
return make_pathkey_from_sortinfo(root,
expr,
- nullable_relids,
opfamily,
opcintype,
collation,
@@ -584,12 +578,10 @@ build_index_pathkeys(PlannerInfo *root,
}
/*
- * OK, try to make a canonical pathkey for this sort key. Note we're
- * underneath any outer joins, so nullable_relids should be NULL.
+ * OK, try to make a canonical pathkey for this sort key.
*/
cpathkey = make_pathkey_from_sortinfo(root,
indexkey,
- NULL,
index->sortopfamily[i],
index->opcintype[i],
index->indexcollations[i],
@@ -743,14 +735,12 @@ build_partition_pathkeys(PlannerInfo *root, RelOptInfo *partrel,
/*
* Try to make a canonical pathkey for this partkey.
*
- * We're considering a baserel scan, so nullable_relids should be
- * NULL. Also, we assume the PartitionDesc lists any NULL partition
- * last, so we treat the scan like a NULLS LAST index: we have
- * nulls_first for backwards scan only.
+ * We assume the PartitionDesc lists any NULL partition last, so we
+ * treat the scan like a NULLS LAST index: we have nulls_first for
+ * backwards scan only.
*/
cpathkey = make_pathkey_from_sortinfo(root,
keyCol,
- NULL,
partscheme->partopfamily[i],
partscheme->partopcintype[i],
partscheme->partcollation[i],
@@ -799,7 +789,7 @@ build_partition_pathkeys(PlannerInfo *root, RelOptInfo *partrel,
* Build a pathkeys list that describes an ordering by a single expression
* using the given sort operator.
*
- * expr, nullable_relids, and rel are as for make_pathkey_from_sortinfo.
+ * expr and rel are as for make_pathkey_from_sortinfo.
* We induce the other arguments assuming default sort order for the operator.
*
* Similarly to make_pathkey_from_sortinfo, the result is NIL if create_it
@@ -808,7 +798,6 @@ build_partition_pathkeys(PlannerInfo *root, RelOptInfo *partrel,
List *
build_expression_pathkey(PlannerInfo *root,
Expr *expr,
- Relids nullable_relids,
Oid opno,
Relids rel,
bool create_it)
@@ -827,7 +816,6 @@ build_expression_pathkey(PlannerInfo *root,
cpathkey = make_pathkey_from_sortinfo(root,
expr,
- nullable_relids,
opfamily,
opcintype,
exprCollation((Node *) expr),
@@ -908,14 +896,11 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
* expression is *not* volatile in the outer query: it's just
* a Var referencing whatever the subquery emitted. (IOW, the
* outer query isn't going to re-execute the volatile
- * expression itself.) So this is okay. Likewise, it's
- * correct to pass nullable_relids = NULL, because we're
- * underneath any outer joins appearing in the outer query.
+ * expression itself.) So this is okay.
*/
outer_ec =
get_eclass_for_sort_expr(root,
(Expr *) outer_var,
- NULL,
sub_eclass->ec_opfamilies,
sub_member->em_datatype,
sub_eclass->ec_collation,
@@ -997,7 +982,6 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
/* See if we have a matching EC for the TLE */
outer_ec = get_eclass_for_sort_expr(root,
(Expr *) outer_var,
- NULL,
sub_eclass->ec_opfamilies,
sub_expr_type,
sub_expr_coll,
@@ -1138,13 +1122,6 @@ build_join_pathkeys(PlannerInfo *root,
* The resulting PathKeys are always in canonical form. (Actually, there
* is no longer any code anywhere that creates non-canonical PathKeys.)
*
- * We assume that root->nullable_baserels is the set of base relids that could
- * have gone to NULL below the SortGroupClause expressions. This is okay if
- * the expressions came from the query's top level (ORDER BY, DISTINCT, etc)
- * and if this function is only invoked after deconstruct_jointree. In the
- * future we might have to make callers pass in the appropriate
- * nullable-relids set, but for now it seems unnecessary.
- *
* 'sortclauses' is a list of SortGroupClause nodes
* 'tlist' is the targetlist to find the referenced tlist entries in
*/
@@ -1166,7 +1143,6 @@ make_pathkeys_for_sortclauses(PlannerInfo *root,
Assert(OidIsValid(sortcl->sortop));
pathkey = make_pathkey_from_sortop(root,
sortkey,
- root->nullable_baserels,
sortcl->sortop,
sortcl->nulls_first,
sortcl->tleSortGroupRef,
@@ -1222,7 +1198,6 @@ initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
restrictinfo->left_ec =
get_eclass_for_sort_expr(root,
(Expr *) get_leftop(clause),
- restrictinfo->nullable_relids,
restrictinfo->mergeopfamilies,
lefttype,
((OpExpr *) clause)->inputcollid,
@@ -1232,7 +1207,6 @@ initialize_mergeclause_eclasses(PlannerInfo *root, RestrictInfo *restrictinfo)
restrictinfo->right_ec =
get_eclass_for_sort_expr(root,
(Expr *) get_rightop(clause),
- restrictinfo->nullable_relids,
restrictinfo->mergeopfamilies,
righttype,
((OpExpr *) clause)->inputcollid,
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 794f5fd197..c3ffc25670 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -92,7 +92,7 @@ static void distribute_qual_to_rels(PlannerInfo *root, Node *clause,
bool is_clone,
List **postponed_qual_list);
static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
- Relids *nullable_relids_p, bool is_pushed_down);
+ bool is_pushed_down);
static bool check_equivalence_delay(PlannerInfo *root,
RestrictInfo *restrictinfo);
static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
@@ -748,9 +748,8 @@ deconstruct_jointree(PlannerInfo *root)
Assert(root->parse->jointree != NULL &&
IsA(root->parse->jointree, FromExpr));
- /* These are filled as we scan the jointree */
+ /* This is filled as we scan the jointree */
root->outer_join_rels = NULL;
- root->nullable_baserels = NULL;
result = deconstruct_recurse(root, (Node *) root->parse->jointree, false,
&qualscope, &inner_join_rels,
@@ -907,7 +906,6 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
left_inners,
right_inners,
nonnullable_rels,
- nullable_rels,
ojscope;
List *leftjoinlist,
*rightjoinlist;
@@ -943,8 +941,6 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
*inner_join_rels = *qualscope;
/* Inner join adds no restrictions for quals */
nonnullable_rels = NULL;
- /* and it doesn't force anything to null, either */
- nullable_rels = NULL;
break;
case JOIN_LEFT:
case JOIN_ANTI:
@@ -967,7 +963,6 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
}
*inner_join_rels = bms_union(left_inners, right_inners);
nonnullable_rels = leftids;
- nullable_rels = rightids;
break;
case JOIN_SEMI:
leftjoinlist = deconstruct_recurse(root, j->larg,
@@ -984,13 +979,6 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
*inner_join_rels = bms_union(left_inners, right_inners);
/* Semi join adds no restrictions for quals */
nonnullable_rels = NULL;
-
- /*
- * Theoretically, a semijoin would null the RHS; but since the
- * RHS can't be accessed above the join, this is immaterial
- * and we needn't account for it.
- */
- nullable_rels = NULL;
break;
case JOIN_FULL:
leftjoinlist = deconstruct_recurse(root, j->larg,
@@ -1011,22 +999,16 @@ deconstruct_recurse(PlannerInfo *root, Node *jtnode, bool below_outer_join,
*inner_join_rels = bms_union(left_inners, right_inners);
/* each side is both outer and inner */
nonnullable_rels = *qualscope;
- nullable_rels = *qualscope;
break;
default:
/* JOIN_RIGHT was eliminated during reduce_outer_joins() */
elog(ERROR, "unrecognized join type: %d",
(int) j->jointype);
nonnullable_rels = NULL; /* keep compiler quiet */
- nullable_rels = NULL;
leftjoinlist = rightjoinlist = NIL;
break;
}
- /* Report all rels that will be nulled anywhere in the jointree */
- root->nullable_baserels = bms_add_members(root->nullable_baserels,
- nullable_rels);
-
/*
* Try to process any quals postponed by children. If they need
* further postponement, add them to my output postponed_qual_list.
@@ -2103,7 +2085,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
bool pseudoconstant = false;
bool maybe_equivalence;
bool maybe_outer_join;
- Relids nullable_relids;
RestrictInfo *restrictinfo;
/*
@@ -2257,7 +2238,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
/* Check to see if must be delayed by lower outer join */
outerjoin_delayed = check_outerjoin_delay(root,
&relids,
- &nullable_relids,
false);
/*
@@ -2285,7 +2265,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
/* Check to see if must be delayed by lower outer join */
outerjoin_delayed = check_outerjoin_delay(root,
&relids,
- &nullable_relids,
true);
if (outerjoin_delayed)
@@ -2345,8 +2324,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
pseudoconstant,
security_level,
relids,
- outerjoin_nonnullable,
- nullable_relids);
+ outerjoin_nonnullable);
/* Apply appropriate clone marking, too */
restrictinfo->has_clone = has_clone;
@@ -2483,9 +2461,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* If the qual must be delayed, add relids to *relids_p to reflect the lowest
* safe level for evaluating the qual, and return true. Any extra delay for
* higher-level joins is reflected by setting delay_upper_joins to true in
- * SpecialJoinInfo structs. We also compute nullable_relids, the set of
- * referenced relids that are nullable by lower outer joins (note that this
- * can be nonempty even for a non-delayed qual).
+ * SpecialJoinInfo structs.
*
* For an is_pushed_down qual, we can evaluate the qual as soon as (1) we have
* all the rels it mentions, and (2) we are at or above any outer joins that
@@ -2508,8 +2484,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* mentioning only C cannot be applied below the join to A.
*
* For a non-pushed-down qual, this isn't going to determine where we place the
- * qual, but we need to determine outerjoin_delayed and nullable_relids anyway
- * for use later in the planning process.
+ * qual, but we need to determine outerjoin_delayed anyway for use later in
+ * the planning process.
*
* Lastly, a pushed-down qual that references the nullable side of any current
* join_info_list member and has to be evaluated above that OJ (because its
@@ -2527,24 +2503,18 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
static bool
check_outerjoin_delay(PlannerInfo *root,
Relids *relids_p, /* in/out parameter */
- Relids *nullable_relids_p, /* output parameter */
bool is_pushed_down)
{
Relids relids;
- Relids nullable_relids;
bool outerjoin_delayed;
bool found_some;
/* fast path if no special joins */
if (root->join_info_list == NIL)
- {
- *nullable_relids_p = NULL;
return false;
- }
/* must copy relids because we need the original value at the end */
relids = bms_copy(*relids_p);
- nullable_relids = NULL;
outerjoin_delayed = false;
do
{
@@ -2571,12 +2541,6 @@ check_outerjoin_delay(PlannerInfo *root,
/* we'll need another iteration */
found_some = true;
}
- /* track all the nullable rels of relevant OJs */
- nullable_relids = bms_add_members(nullable_relids,
- sjinfo->min_righthand);
- if (sjinfo->jointype == JOIN_FULL)
- nullable_relids = bms_add_members(nullable_relids,
- sjinfo->min_lefthand);
/* set delay_upper_joins if needed */
if (is_pushed_down && sjinfo->jointype != JOIN_FULL &&
bms_overlap(relids, sjinfo->min_lefthand))
@@ -2585,13 +2549,9 @@ check_outerjoin_delay(PlannerInfo *root,
}
} while (found_some);
- /* identify just the actually-referenced nullable rels */
- nullable_relids = bms_int_members(nullable_relids, *relids_p);
-
- /* replace *relids_p, and return nullable_relids */
+ /* replace *relids_p */
bms_free(*relids_p);
*relids_p = relids;
- *nullable_relids_p = nullable_relids;
return outerjoin_delayed;
}
@@ -2613,7 +2573,6 @@ check_equivalence_delay(PlannerInfo *root,
RestrictInfo *restrictinfo)
{
Relids relids;
- Relids nullable_relids;
/* fast path if no special joins */
if (root->join_info_list == NIL)
@@ -2622,12 +2581,12 @@ check_equivalence_delay(PlannerInfo *root,
/* must copy restrictinfo's relids to avoid changing it */
relids = bms_copy(restrictinfo->left_relids);
/* check left side does not need delay */
- if (check_outerjoin_delay(root, &relids, &nullable_relids, true))
+ if (check_outerjoin_delay(root, &relids, true))
return false;
/* and similarly for the right side */
relids = bms_copy(restrictinfo->right_relids);
- if (check_outerjoin_delay(root, &relids, &nullable_relids, true))
+ if (check_outerjoin_delay(root, &relids, true))
return false;
return true;
@@ -2753,11 +2712,6 @@ distribute_restrictinfo_to_rels(PlannerInfo *root,
* variable-free. Otherwise the qual is applied at the lowest join level
* that provides all its variables.
*
- * "nullable_relids" is the set of relids used in the expressions that are
- * potentially nullable below the expressions. (This has to be supplied by
- * caller because this function is used after deconstruct_jointree, so we
- * don't have knowledge of where the clause items came from.)
- *
* "security_level" is the security level to assign to the new restrictinfo.
*
* "both_const" indicates whether both items are known pseudo-constant;
@@ -2783,7 +2737,6 @@ process_implied_equality(PlannerInfo *root,
Expr *item1,
Expr *item2,
Relids qualscope,
- Relids nullable_relids,
Index security_level,
bool below_outer_join,
bool both_const)
@@ -2867,8 +2820,7 @@ process_implied_equality(PlannerInfo *root,
pseudoconstant,
security_level,
relids,
- NULL, /* outer_relids */
- nullable_relids);
+ NULL); /* outer_relids */
/*
* If it's a join clause, add vars used in the clause to targetlists of
@@ -2933,7 +2885,6 @@ build_implied_join_equality(PlannerInfo *root,
Expr *item1,
Expr *item2,
Relids qualscope,
- Relids nullable_relids,
Index security_level)
{
RestrictInfo *restrictinfo;
@@ -2961,8 +2912,7 @@ build_implied_join_equality(PlannerInfo *root,
false, /* pseudoconstant */
security_level, /* security_level */
qualscope, /* required_relids */
- NULL, /* outer_relids */
- nullable_relids); /* nullable_relids */
+ NULL); /* outer_relids */
/* Set mergejoinability/hashjoinability flags */
check_mergejoinable(restrictinfo);
diff --git a/src/backend/optimizer/util/appendinfo.c b/src/backend/optimizer/util/appendinfo.c
index e18d64b6dc..662d2c1f17 100644
--- a/src/backend/optimizer/util/appendinfo.c
+++ b/src/backend/optimizer/util/appendinfo.c
@@ -448,9 +448,6 @@ adjust_appendrel_attrs_mutator(Node *node,
newinfo->outer_relids = adjust_child_relids(oldinfo->outer_relids,
context->nappinfos,
context->appinfos);
- newinfo->nullable_relids = adjust_child_relids(oldinfo->nullable_relids,
- context->nappinfos,
- context->appinfos);
newinfo->left_relids = adjust_child_relids(oldinfo->left_relids,
context->nappinfos,
context->appinfos);
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 3d270e91d6..eb20583f75 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -815,7 +815,7 @@ apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel,
rinfo->outerjoin_delayed,
pseudoconstant,
rinfo->security_level,
- NULL, NULL, NULL));
+ NULL, NULL));
/* track minimum security level among child quals */
cq_min_security = Min(cq_min_security, rinfo->security_level);
}
@@ -850,7 +850,7 @@ apply_child_basequals(PlannerInfo *root, RelOptInfo *parentrel,
make_restrictinfo(root, qual,
true, false, false,
security_level,
- NULL, NULL, NULL));
+ NULL, NULL));
cq_min_security = Min(cq_min_security, security_level);
}
security_level++;
diff --git a/src/backend/optimizer/util/orclauses.c b/src/backend/optimizer/util/orclauses.c
index 9cfde2f790..336a73d3b9 100644
--- a/src/backend/optimizer/util/orclauses.c
+++ b/src/backend/optimizer/util/orclauses.c
@@ -275,7 +275,6 @@ consider_new_or_clause(PlannerInfo *root, RelOptInfo *rel,
false,
join_or_rinfo->security_level,
NULL,
- NULL,
NULL);
/*
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index 15f410cf36..1d8912608b 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -29,8 +29,7 @@ static RestrictInfo *make_restrictinfo_internal(PlannerInfo *root,
bool pseudoconstant,
Index security_level,
Relids required_relids,
- Relids outer_relids,
- Relids nullable_relids);
+ Relids outer_relids);
static Expr *make_sub_restrictinfos(PlannerInfo *root,
Expr *clause,
bool is_pushed_down,
@@ -38,8 +37,7 @@ static Expr *make_sub_restrictinfos(PlannerInfo *root,
bool pseudoconstant,
Index security_level,
Relids required_relids,
- Relids outer_relids,
- Relids nullable_relids);
+ Relids outer_relids);
/*
@@ -49,7 +47,7 @@ static Expr *make_sub_restrictinfos(PlannerInfo *root,
*
* The is_pushed_down, outerjoin_delayed, and pseudoconstant flags for the
* RestrictInfo must be supplied by the caller, as well as the correct values
- * for security_level, outer_relids, and nullable_relids.
+ * for security_level and outer_relids.
* required_relids can be NULL, in which case it defaults to the actual clause
* contents (i.e., clause_relids).
*
@@ -69,8 +67,7 @@ make_restrictinfo(PlannerInfo *root,
bool pseudoconstant,
Index security_level,
Relids required_relids,
- Relids outer_relids,
- Relids nullable_relids)
+ Relids outer_relids)
{
/*
* If it's an OR clause, build a modified copy with RestrictInfos inserted
@@ -84,8 +81,7 @@ make_restrictinfo(PlannerInfo *root,
pseudoconstant,
security_level,
required_relids,
- outer_relids,
- nullable_relids);
+ outer_relids);
/* Shouldn't be an AND clause, else AND/OR flattening messed up */
Assert(!is_andclause(clause));
@@ -98,8 +94,7 @@ make_restrictinfo(PlannerInfo *root,
pseudoconstant,
security_level,
required_relids,
- outer_relids,
- nullable_relids);
+ outer_relids);
}
/*
@@ -116,8 +111,7 @@ make_restrictinfo_internal(PlannerInfo *root,
bool pseudoconstant,
Index security_level,
Relids required_relids,
- Relids outer_relids,
- Relids nullable_relids)
+ Relids outer_relids)
{
RestrictInfo *restrictinfo = makeNode(RestrictInfo);
Relids baserels;
@@ -132,7 +126,6 @@ make_restrictinfo_internal(PlannerInfo *root,
restrictinfo->can_join = false; /* may get set below */
restrictinfo->security_level = security_level;
restrictinfo->outer_relids = outer_relids;
- restrictinfo->nullable_relids = nullable_relids;
/*
* If it's potentially delayable by lower-level security quals, figure out
@@ -260,7 +253,7 @@ make_restrictinfo_internal(PlannerInfo *root,
*
* The same is_pushed_down, outerjoin_delayed, and pseudoconstant flag
* values can be applied to all RestrictInfo nodes in the result. Likewise
- * for security_level, outer_relids, and nullable_relids.
+ * for security_level and outer_relids.
*
* The given required_relids are attached to our top-level output,
* but any OR-clause constituents are allowed to default to just the
@@ -274,8 +267,7 @@ make_sub_restrictinfos(PlannerInfo *root,
bool pseudoconstant,
Index security_level,
Relids required_relids,
- Relids outer_relids,
- Relids nullable_relids)
+ Relids outer_relids)
{
if (is_orclause(clause))
{
@@ -291,8 +283,7 @@ make_sub_restrictinfos(PlannerInfo *root,
pseudoconstant,
security_level,
NULL,
- outer_relids,
- nullable_relids));
+ outer_relids));
return (Expr *) make_restrictinfo_internal(root,
clause,
make_orclause(orlist),
@@ -301,8 +292,7 @@ make_sub_restrictinfos(PlannerInfo *root,
pseudoconstant,
security_level,
required_relids,
- outer_relids,
- nullable_relids);
+ outer_relids);
}
else if (is_andclause(clause))
{
@@ -318,8 +308,7 @@ make_sub_restrictinfos(PlannerInfo *root,
pseudoconstant,
security_level,
required_relids,
- outer_relids,
- nullable_relids));
+ outer_relids));
return make_andclause(andlist);
}
else
@@ -331,8 +320,7 @@ make_sub_restrictinfos(PlannerInfo *root,
pseudoconstant,
security_level,
required_relids,
- outer_relids,
- nullable_relids);
+ outer_relids);
}
/*
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 70c37118c1..c93543bf0e 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -263,14 +263,6 @@ struct PlannerInfo
*/
Relids all_query_rels;
- /*
- * nullable_baserels is a Relids set of base relids that are nullable by
- * some outer join in the jointree; these are rels that are potentially
- * nullable below the WHERE clause, SELECT targetlist, etc. This is
- * computed in deconstruct_jointree.
- */
- Relids nullable_baserels;
-
/*
* join_rel_list is a list of all join-relation RelOptInfos we have
* considered in this planning run. For small problems we just scan the
@@ -1356,7 +1348,6 @@ typedef struct EquivalenceMember
Expr *em_expr; /* the expression represented */
Relids em_relids; /* all relids appearing in em_expr */
- Relids em_nullable_relids; /* nullable by lower outer joins */
bool em_is_const; /* expression is pseudoconstant? */
bool em_is_child; /* derived version for a child relation? */
Oid em_datatype; /* the "nominal type" used by the opfamily */
@@ -2382,9 +2373,7 @@ typedef struct LimitPath
* in parameterized scans, since pushing it into the join's outer side would
* lead to wrong answers.)
*
- * There is also a nullable_relids field, which is the set of rels the clause
- * references that can be forced null by some outer join below the clause.
- *
+ * XXX this comment needs work, if we don't remove it completely:
* outerjoin_delayed = true is subtly different from nullable_relids != NULL:
* a clause might reference some nullable rels and yet not be
* outerjoin_delayed because it also references all the other rels of the
@@ -2498,9 +2487,6 @@ typedef struct RestrictInfo
/* If an outer-join clause, the outer-side relations, else NULL: */
Relids outer_relids;
- /* The relids used in the clause that are nullable by lower outer joins: */
- Relids nullable_relids;
-
/*
* Relids in the left/right side of the clause. These fields are set for
* any binary opclause.
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 41f765d342..03866de136 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -128,7 +128,6 @@ extern Expr *canonicalize_ec_expression(Expr *expr,
extern void reconsider_outer_join_clauses(PlannerInfo *root);
extern EquivalenceClass *get_eclass_for_sort_expr(PlannerInfo *root,
Expr *expr,
- Relids nullable_relids,
List *opfamilies,
Oid opcintype,
Oid collation,
@@ -216,7 +215,7 @@ extern List *build_index_pathkeys(PlannerInfo *root, IndexOptInfo *index,
extern List *build_partition_pathkeys(PlannerInfo *root, RelOptInfo *partrel,
ScanDirection scandir, bool *partialkeys);
extern List *build_expression_pathkey(PlannerInfo *root, Expr *expr,
- Relids nullable_relids, Oid opno,
+ Oid opno,
Relids rel, bool create_it);
extern List *convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
List *subquery_pathkeys,
diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h
index 9dffdcfd1e..57b963c0f7 100644
--- a/src/include/optimizer/planmain.h
+++ b/src/include/optimizer/planmain.h
@@ -83,7 +83,6 @@ extern RestrictInfo *process_implied_equality(PlannerInfo *root,
Expr *item1,
Expr *item2,
Relids qualscope,
- Relids nullable_relids,
Index security_level,
bool below_outer_join,
bool both_const);
@@ -93,7 +92,6 @@ extern RestrictInfo *build_implied_join_equality(PlannerInfo *root,
Expr *item1,
Expr *item2,
Relids qualscope,
- Relids nullable_relids,
Index security_level);
extern void match_foreign_keys_to_quals(PlannerInfo *root);
diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h
index 17d3b4ab05..1f092371ea 100644
--- a/src/include/optimizer/restrictinfo.h
+++ b/src/include/optimizer/restrictinfo.h
@@ -19,7 +19,7 @@
/* Convenience macro for the common case of a valid-everywhere qual */
#define make_simple_restrictinfo(root, clause) \
- make_restrictinfo(root, clause, true, false, false, 0, NULL, NULL, NULL)
+ make_restrictinfo(root, clause, true, false, false, 0, NULL, NULL)
extern RestrictInfo *make_restrictinfo(PlannerInfo *root,
Expr *clause,
@@ -28,8 +28,7 @@ extern RestrictInfo *make_restrictinfo(PlannerInfo *root,
bool pseudoconstant,
Index security_level,
Relids required_relids,
- Relids outer_relids,
- Relids nullable_relids);
+ Relids outer_relids);
extern RestrictInfo *commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op);
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
extern bool restriction_is_securely_promotable(RestrictInfo *restrictinfo,