diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2023-01-30 13:44:36 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2023-01-30 13:44:36 -0500 |
commit | b448f1c8d83f8b65e2f0080c556ee21a7076da25 (patch) | |
tree | bc76c0506f01f224521b14304224598b8ba6699a /src/backend/optimizer/path | |
parent | 2489d76c4906f4461a364ca8ad7e0751ead8aa0d (diff) | |
download | postgresql-b448f1c8d83f8b65e2f0080c556ee21a7076da25.tar.gz |
Do assorted mop-up in the planner.
Remove RestrictInfo.nullable_relids, along with a good deal of
infrastructure that calculated it. One use-case for it was in
join_clause_is_movable_to, but we can now replace that usage with
a check to see if the clause's relids include any outer join
that can null the target relation. The other use-case was in
join_clause_is_movable_into, but that test can just be dropped
entirely now that the clause's relids include outer joins.
Furthermore, join_clause_is_movable_into should now be
accurate enough that it will accept anything returned by
generate_join_implied_equalities, so we can restore the Assert
that was diked out in commit 95f4e59c3.
Remove the outerjoin_delayed mechanism. We needed this before to
prevent quals from getting evaluated below outer joins that should
null some of their vars. Now that we consider varnullingrels while
placing quals, that's taken care of automatically, so throw the
whole thing away.
Teach remove_useless_result_rtes to also remove useless FromExprs.
Having done that, the delay_upper_joins flag serves no purpose any
more and we can remove it, largely reverting 11086f2f2.
Use constant TRUE for "dummy" clauses when throwing back outer joins.
This improves on a hack I introduced in commit 6a6522529. If we
have a left-join clause l.x = r.y, and a WHERE clause l.x = constant,
we generate r.y = constant and then don't really have a need for the
join clause. But we must throw the join clause back anyway after
marking it redundant, so that the join search heuristics won't think
this is a clauseless join and avoid it. That was a kluge introduced
under time pressure, and after looking at it I thought of a better
way: let's just introduce constant-TRUE "join clauses" instead,
and get rid of them at the end. This improves the generated plans for
such cases by not having to test a redundant join clause. We can also
get rid of the ugly hack used to mark such clauses as redundant for
selectivity estimation.
Patch by me; thanks to Richard Guo for review.
Discussion: https://postgr.es/m/830269.1656693747@sss.pgh.pa.us
Diffstat (limited to 'src/backend/optimizer/path')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/path/clausesel.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/path/costsize.c | 2 | ||||
-rw-r--r-- | src/backend/optimizer/path/equivclass.c | 168 | ||||
-rw-r--r-- | src/backend/optimizer/path/joinrels.c | 1 | ||||
-rw-r--r-- | src/backend/optimizer/path/pathkeys.c | 40 |
6 files changed, 52 insertions, 166 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 26b294d5d0..ae0f9bdc8a 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -2745,7 +2745,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/clausesel.c b/src/backend/optimizer/path/clausesel.c index 61db6ad951..435438a173 100644 --- a/src/backend/optimizer/path/clausesel.c +++ b/src/backend/optimizer/path/clausesel.c @@ -716,12 +716,6 @@ clause_selectivity_ext(PlannerInfo *root, } /* - * If the clause is marked redundant, always return 1.0. - */ - if (rinfo->norm_selec > 1) - return (Selectivity) 1.0; - - /* * If possible, cache the result of the selectivity calculation for * the clause. We can cache if varRelid is zero or the clause * contains only vars of that relid --- otherwise varRelid will affect diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 7d957a47a4..7918bb6f0d 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -4787,7 +4787,6 @@ compute_semi_anti_join_factors(PlannerInfo *root, norm_sjinfo.commute_below = NULL; /* we don't bother trying to make the remaining fields valid */ norm_sjinfo.lhs_strict = false; - norm_sjinfo.delay_upper_joins = false; norm_sjinfo.semi_can_btree = false; norm_sjinfo.semi_can_hash = false; norm_sjinfo.semi_operators = NIL; @@ -4956,7 +4955,6 @@ approx_tuple_count(PlannerInfo *root, JoinPath *path, List *quals) sjinfo.commute_below = NULL; /* we don't bother trying to make the remaining fields valid */ sjinfo.lhs_strict = false; - sjinfo.delay_upper_joins = false; sjinfo.semi_can_btree = false; sjinfo.semi_can_hash = false; sjinfo.semi_operators = NIL; diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 490953f2ff..007229d26c 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; @@ -202,12 +200,10 @@ process_equivalence(PlannerInfo *root, make_restrictinfo(root, (Expr *) ntest, restrictinfo->is_pushed_down, - restrictinfo->outerjoin_delayed, restrictinfo->pseudoconstant, restrictinfo->security_level, NULL, - restrictinfo->outer_relids, - restrictinfo->nullable_relids); + restrictinfo->outer_relids); } return false; } @@ -225,12 +221,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 +390,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 +408,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 +442,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 +535,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 +577,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 +605,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 +700,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 @@ -1163,11 +1143,8 @@ generate_base_implied_equalities_const(PlannerInfo *root, { RestrictInfo *restrictinfo = (RestrictInfo *) linitial(ec->ec_sources); - if (bms_membership(restrictinfo->required_relids) != BMS_MULTIPLE) - { - distribute_restrictinfo_to_rels(root, restrictinfo); - return; - } + distribute_restrictinfo_to_rels(root, restrictinfo); + return; } /* @@ -1211,8 +1188,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 +1260,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 +1862,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 */ @@ -1979,23 +1950,11 @@ create_join_clause(PlannerInfo *root, * If we don't find any match for a set-aside outer join clause, we must * throw it back into the regular joinclause processing by passing it to * distribute_restrictinfo_to_rels(). If we do generate a derived clause, - * however, the outer-join clause is redundant. We still throw it back, - * because otherwise the join will be seen as a clauseless join and avoided - * during join order searching; but we mark it as redundant to keep from - * messing up the joinrel's size estimate. (This behavior means that the - * API for this routine is uselessly complex: we could have just put all - * the clauses into the regular processing initially. We keep it because - * someday we might want to do something else, such as inserting "dummy" - * joinclauses instead of real ones.) - * - * Outer join clauses that are marked outerjoin_delayed are special: this - * condition means that one or both VARs might go to null due to a lower - * outer join. We can still push a constant through the clause, but only - * if its operator is strict; and we *have to* throw the clause back into - * regular joinclause processing. By keeping the strict join clause, - * we ensure that any null-extended rows that are mistakenly generated due - * to suppressing rows not matching the constant will be rejected at the - * upper outer join. (This doesn't work for full-join clauses.) + * however, the outer-join clause is redundant. We must still put some + * clause into the regular processing, because otherwise the join will be + * seen as a clauseless join and avoided during join order searching. + * We handle this by generating a constant-TRUE clause that is marked with + * required_relids that make it a join between the correct relations. */ void reconsider_outer_join_clauses(PlannerInfo *root) @@ -2021,10 +1980,14 @@ reconsider_outer_join_clauses(PlannerInfo *root) /* remove it from the list */ root->left_join_clauses = foreach_delete_current(root->left_join_clauses, cell); - /* we throw it back anyway (see notes above) */ - /* but the thrown-back clause has no extra selectivity */ - rinfo->norm_selec = 2.0; - rinfo->outer_selec = 1.0; + /* throw back a dummy replacement clause (see notes above) */ + rinfo = make_restrictinfo(root, + (Expr *) makeBoolConst(true, false), + true, /* is_pushed_down */ + false, /* pseudoconstant */ + 0, /* security_level */ + rinfo->required_relids, + rinfo->outer_relids); distribute_restrictinfo_to_rels(root, rinfo); } } @@ -2042,10 +2005,14 @@ reconsider_outer_join_clauses(PlannerInfo *root) /* remove it from the list */ root->right_join_clauses = foreach_delete_current(root->right_join_clauses, cell); - /* we throw it back anyway (see notes above) */ - /* but the thrown-back clause has no extra selectivity */ - rinfo->norm_selec = 2.0; - rinfo->outer_selec = 1.0; + /* throw back a dummy replacement clause (see notes above) */ + rinfo = make_restrictinfo(root, + (Expr *) makeBoolConst(true, false), + true, /* is_pushed_down */ + false, /* pseudoconstant */ + 0, /* security_level */ + rinfo->required_relids, + rinfo->outer_relids); distribute_restrictinfo_to_rels(root, rinfo); } } @@ -2063,10 +2030,14 @@ reconsider_outer_join_clauses(PlannerInfo *root) /* remove it from the list */ root->full_join_clauses = foreach_delete_current(root->full_join_clauses, cell); - /* we throw it back anyway (see notes above) */ - /* but the thrown-back clause has no extra selectivity */ - rinfo->norm_selec = 2.0; - rinfo->outer_selec = 1.0; + /* throw back a dummy replacement clause (see notes above) */ + rinfo = make_restrictinfo(root, + (Expr *) makeBoolConst(true, false), + true, /* is_pushed_down */ + false, /* pseudoconstant */ + 0, /* security_level */ + rinfo->required_relids, + rinfo->outer_relids); distribute_restrictinfo_to_rels(root, rinfo); } } @@ -2110,18 +2081,13 @@ reconsider_outer_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo, left_type, right_type, inner_datatype; - Relids inner_relids, - inner_nullable_relids; + Relids inner_relids; ListCell *lc1; Assert(is_opclause(rinfo->clause)); opno = ((OpExpr *) rinfo->clause)->opno; collation = ((OpExpr *) rinfo->clause)->inputcollid; - /* If clause is outerjoin_delayed, operator must be strict */ - if (rinfo->outerjoin_delayed && !op_strict(opno)) - return false; - /* Extract needed info from the clause */ op_input_types(opno, &left_type, &right_type); if (outer_on_left) @@ -2138,8 +2104,6 @@ reconsider_outer_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo, 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) @@ -2200,7 +2164,6 @@ reconsider_outer_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo, 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; @@ -2238,15 +2201,9 @@ reconsider_full_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo) 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 */ - if (rinfo->outerjoin_delayed) - return false; - /* Extract needed info from the clause */ Assert(is_opclause(rinfo->clause)); opno = ((OpExpr *) rinfo->clause)->opno; @@ -2256,10 +2213,6 @@ reconsider_full_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo) 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) { @@ -2361,7 +2314,6 @@ reconsider_full_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo) 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; @@ -2377,7 +2329,6 @@ reconsider_full_join_clause(PlannerInfo *root, OuterJoinClauseInfo *ojcinfo) 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; @@ -2675,7 +2626,6 @@ add_child_rel_equivalences(PlannerInfo *root, /* OK, generate transformed child version */ Expr *child_expr; Relids new_relids; - Relids new_nullable_relids; if (parent_rel->reloptkind == RELOPT_BASEREL) { @@ -2705,21 +2655,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 */ @@ -2816,7 +2752,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) { @@ -2847,20 +2782,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/joinrels.c b/src/backend/optimizer/path/joinrels.c index 56dd1073c5..d7cb11c851 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -743,7 +743,6 @@ make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) sjinfo->commute_below = NULL; /* we don't bother trying to make the remaining fields valid */ sjinfo->lhs_strict = false; - sjinfo->delay_upper_joins = false; sjinfo->semi_can_btree = false; sjinfo->semi_can_hash = false; sjinfo->semi_operators = NIL; diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index d2e241c983..c4e7f97f68 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 */ @@ -1210,7 +1187,6 @@ make_pathkeys_for_sortclauses_extended(PlannerInfo *root, } pathkey = make_pathkey_from_sortop(root, sortkey, - root->nullable_baserels, sortcl->sortop, sortcl->nulls_first, sortcl->tleSortGroupRef, @@ -1268,7 +1244,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, @@ -1278,7 +1253,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, |