From 8123e91f5aeb26c6e4cf583bb61c99281485af83 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 4 Apr 2025 11:13:54 +0200 Subject: [PATCH] Convert PathKey to use CompareType Change the PathKey struct to use CompareType to record the sort direction instead of hardcoding btree strategy numbers. The CompareType is then converted to the index-type-specific strategy when the plan is created. This reduces the number of places btree strategy numbers are hardcoded, and it's a self-contained subset of a larger effort to allow non-btree indexes to behave like btrees. Author: Mark Dilger Co-authored-by: Peter Eisentraut Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com --- contrib/postgres_fdw/deparse.c | 16 ++++++++-------- contrib/postgres_fdw/postgres_fdw.c | 2 +- src/backend/optimizer/path/costsize.c | 8 ++++---- src/backend/optimizer/path/indxpath.c | 3 +-- src/backend/optimizer/path/pathkeys.c | 24 ++++++++++++------------ src/backend/optimizer/plan/createplan.c | 24 ++++++++++++------------ src/include/nodes/pathnodes.h | 12 +++++------- src/include/optimizer/paths.h | 2 +- 8 files changed, 44 insertions(+), 47 deletions(-) diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index 6e7dc3d2df9..d9970dd6753 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -3969,17 +3969,17 @@ appendOrderByClause(List *pathkeys, bool has_final_sort, appendStringInfoString(buf, ", "); /* - * Lookup the operator corresponding to the strategy in the opclass. - * The datatype used by the opfamily is not necessarily the same as - * the expression type (for array types for example). + * Lookup the operator corresponding to the compare type in the + * opclass. The datatype used by the opfamily is not necessarily the + * same as the expression type (for array types for example). */ - oprid = get_opfamily_member(pathkey->pk_opfamily, - em->em_datatype, - em->em_datatype, - pathkey->pk_strategy); + oprid = get_opfamily_member_for_cmptype(pathkey->pk_opfamily, + em->em_datatype, + em->em_datatype, + pathkey->pk_cmptype); if (!OidIsValid(oprid)) elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", - pathkey->pk_strategy, em->em_datatype, em->em_datatype, + pathkey->pk_cmptype, em->em_datatype, em->em_datatype, pathkey->pk_opfamily); deparseExpr(em_expr, context); diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index ac14c06c715..b4e0e60928b 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -999,7 +999,7 @@ get_useful_pathkeys_for_relation(PlannerInfo *root, RelOptInfo *rel) /* Looks like we can generate a pathkey, so let's do it. */ pathkey = make_canonical_pathkey(root, cur_ec, linitial_oid(cur_ec->ec_opfamilies), - BTLessStrategyNumber, + COMPARE_LT, false); useful_pathkeys_list = lappend(useful_pathkeys_list, list_make1(pathkey)); diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index c474c7a06af..60b0fcfb6be 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -3608,7 +3608,7 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace, /* debugging check */ if (opathkey->pk_opfamily != ipathkey->pk_opfamily || opathkey->pk_eclass->ec_collation != ipathkey->pk_eclass->ec_collation || - opathkey->pk_strategy != ipathkey->pk_strategy || + opathkey->pk_cmptype != ipathkey->pk_cmptype || opathkey->pk_nulls_first != ipathkey->pk_nulls_first) elog(ERROR, "left and right pathkeys do not match in mergejoin"); @@ -4093,7 +4093,7 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey) cache = (MergeScanSelCache *) lfirst(lc); if (cache->opfamily == pathkey->pk_opfamily && cache->collation == pathkey->pk_eclass->ec_collation && - cache->strategy == pathkey->pk_strategy && + cache->cmptype == pathkey->pk_cmptype && cache->nulls_first == pathkey->pk_nulls_first) return cache; } @@ -4102,7 +4102,7 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey) mergejoinscansel(root, (Node *) rinfo->clause, pathkey->pk_opfamily, - pathkey->pk_strategy, + pathkey->pk_cmptype, pathkey->pk_nulls_first, &leftstartsel, &leftendsel, @@ -4115,7 +4115,7 @@ cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey) cache = (MergeScanSelCache *) palloc(sizeof(MergeScanSelCache)); cache->opfamily = pathkey->pk_opfamily; cache->collation = pathkey->pk_eclass->ec_collation; - cache->strategy = pathkey->pk_strategy; + cache->cmptype = pathkey->pk_cmptype; cache->nulls_first = pathkey->pk_nulls_first; cache->leftstartsel = leftstartsel; cache->leftendsel = leftendsel; diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 6386ce82253..d8865f8c0c6 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -3817,8 +3817,7 @@ match_pathkeys_to_index(IndexOptInfo *index, List *pathkeys, /* Pathkey must request default sort order for the target opfamily */ - if (pathkey->pk_strategy != BTLessStrategyNumber || - pathkey->pk_nulls_first) + if (pathkey->pk_cmptype != COMPARE_LT || pathkey->pk_nulls_first) return; /* If eclass is volatile, no hope of using an indexscan */ diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 154eb505d75..6fac08cb0d9 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -55,7 +55,7 @@ static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey); PathKey * make_canonical_pathkey(PlannerInfo *root, EquivalenceClass *eclass, Oid opfamily, - int strategy, bool nulls_first) + CompareType cmptype, bool nulls_first) { PathKey *pk; ListCell *lc; @@ -74,7 +74,7 @@ make_canonical_pathkey(PlannerInfo *root, pk = (PathKey *) lfirst(lc); if (eclass == pk->pk_eclass && opfamily == pk->pk_opfamily && - strategy == pk->pk_strategy && + cmptype == pk->pk_cmptype && nulls_first == pk->pk_nulls_first) return pk; } @@ -88,7 +88,7 @@ make_canonical_pathkey(PlannerInfo *root, pk = makeNode(PathKey); pk->pk_eclass = eclass; pk->pk_opfamily = opfamily; - pk->pk_strategy = strategy; + pk->pk_cmptype = cmptype; pk->pk_nulls_first = nulls_first; root->canon_pathkeys = lappend(root->canon_pathkeys, pk); @@ -206,12 +206,12 @@ make_pathkey_from_sortinfo(PlannerInfo *root, Relids rel, bool create_it) { - int16 strategy; + CompareType cmptype; Oid equality_op; List *opfamilies; EquivalenceClass *eclass; - strategy = reverse_sort ? BTGreaterStrategyNumber : BTLessStrategyNumber; + cmptype = reverse_sort ? COMPARE_GT : COMPARE_LT; /* * EquivalenceClasses need to contain opfamily lists based on the family @@ -242,7 +242,7 @@ make_pathkey_from_sortinfo(PlannerInfo *root, /* And finally we can find or create a PathKey node */ return make_canonical_pathkey(root, eclass, opfamily, - strategy, nulls_first); + cmptype, nulls_first); } /* @@ -1118,7 +1118,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, make_canonical_pathkey(root, outer_ec, sub_pathkey->pk_opfamily, - sub_pathkey->pk_strategy, + sub_pathkey->pk_cmptype, sub_pathkey->pk_nulls_first); } } @@ -1200,7 +1200,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel, outer_pk = make_canonical_pathkey(root, outer_ec, sub_pathkey->pk_opfamily, - sub_pathkey->pk_strategy, + sub_pathkey->pk_cmptype, sub_pathkey->pk_nulls_first); /* score = # of equivalence peers */ score = list_length(outer_ec->ec_members) - 1; @@ -1816,7 +1816,7 @@ select_outer_pathkeys_for_merge(PlannerInfo *root, pathkey = make_canonical_pathkey(root, ec, linitial_oid(ec->ec_opfamilies), - BTLessStrategyNumber, + COMPARE_LT, false); /* can't be redundant because no duplicate ECs */ Assert(!pathkey_is_redundant(pathkey, pathkeys)); @@ -1909,7 +1909,7 @@ make_inner_pathkeys_for_merge(PlannerInfo *root, pathkey = make_canonical_pathkey(root, ieclass, opathkey->pk_opfamily, - opathkey->pk_strategy, + opathkey->pk_cmptype, opathkey->pk_nulls_first); /* @@ -2134,12 +2134,12 @@ right_merge_direction(PlannerInfo *root, PathKey *pathkey) * want to prefer only one of the two possible directions, and we * might as well use this one. */ - return (pathkey->pk_strategy == query_pathkey->pk_strategy); + return (pathkey->pk_cmptype == query_pathkey->pk_cmptype); } } /* If no matching ORDER BY request, prefer the ASC direction */ - return (pathkey->pk_strategy == BTLessStrategyNumber); + return (pathkey->pk_cmptype == COMPARE_LT); } /* diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 75e2b0b9036..359db4ba9dd 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -3129,13 +3129,13 @@ create_indexscan_plan(PlannerInfo *root, Oid sortop; /* Get sort operator from opfamily */ - sortop = get_opfamily_member(pathkey->pk_opfamily, - exprtype, - exprtype, - pathkey->pk_strategy); + sortop = get_opfamily_member_for_cmptype(pathkey->pk_opfamily, + exprtype, + exprtype, + pathkey->pk_cmptype); if (!OidIsValid(sortop)) elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", - pathkey->pk_strategy, exprtype, exprtype, pathkey->pk_opfamily); + pathkey->pk_cmptype, exprtype, exprtype, pathkey->pk_opfamily); indexorderbyops = lappend_oid(indexorderbyops, sortop); } } @@ -4739,14 +4739,14 @@ create_mergejoin_plan(PlannerInfo *root, opathkey->pk_eclass->ec_collation != ipathkey->pk_eclass->ec_collation) elog(ERROR, "left and right pathkeys do not match in mergejoin"); if (first_inner_match && - (opathkey->pk_strategy != ipathkey->pk_strategy || + (opathkey->pk_cmptype != ipathkey->pk_cmptype || opathkey->pk_nulls_first != ipathkey->pk_nulls_first)) elog(ERROR, "left and right pathkeys do not match in mergejoin"); /* OK, save info for executor */ mergefamilies[i] = opathkey->pk_opfamily; mergecollations[i] = opathkey->pk_eclass->ec_collation; - mergereversals[i] = (opathkey->pk_strategy == BTGreaterStrategyNumber ? true : false); + mergereversals[i] = (opathkey->pk_cmptype == COMPARE_GT ? true : false); mergenullsfirst[i] = opathkey->pk_nulls_first; i++; } @@ -6374,13 +6374,13 @@ prepare_sort_from_pathkeys(Plan *lefttree, List *pathkeys, * Look up the correct sort operator from the PathKey's slightly * abstracted representation. */ - sortop = get_opfamily_member(pathkey->pk_opfamily, - pk_datatype, - pk_datatype, - pathkey->pk_strategy); + sortop = get_opfamily_member_for_cmptype(pathkey->pk_opfamily, + pk_datatype, + pk_datatype, + pathkey->pk_cmptype); if (!OidIsValid(sortop)) /* should not happen */ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", - pathkey->pk_strategy, pk_datatype, pk_datatype, + pathkey->pk_cmptype, pk_datatype, pk_datatype, pathkey->pk_opfamily); /* Add the column to the sort arrays */ diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index 6e034960896..4c466f76778 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -1506,9 +1506,7 @@ typedef struct EquivalenceMember * equivalent and closely-related orderings. (See optimizer/README for more * information.) * - * Note: pk_strategy is either BTLessStrategyNumber (for ASC) or - * BTGreaterStrategyNumber (for DESC). We assume that all ordering-capable - * index types will use btree-compatible strategy numbers. + * Note: pk_strategy is either COMPARE_LT (for ASC) or COMPARE_GT (for DESC). */ typedef struct PathKey { @@ -1518,8 +1516,8 @@ typedef struct PathKey /* the value that is ordered */ EquivalenceClass *pk_eclass pg_node_attr(copy_as_scalar, equal_as_scalar); - Oid pk_opfamily; /* btree opfamily defining the ordering */ - int pk_strategy; /* sort direction (ASC or DESC) */ + Oid pk_opfamily; /* index opfamily defining the ordering */ + CompareType pk_cmptype; /* sort direction (ASC or DESC) */ bool pk_nulls_first; /* do NULLs come before normal values? */ } PathKey; @@ -2784,9 +2782,9 @@ typedef struct RestrictInfo typedef struct MergeScanSelCache { /* Ordering details (cache lookup key) */ - Oid opfamily; /* btree opfamily defining the ordering */ + Oid opfamily; /* index opfamily defining the ordering */ Oid collation; /* collation for the ordering */ - int strategy; /* sort direction (ASC or DESC) */ + CompareType cmptype; /* sort direction (ASC or DESC) */ bool nulls_first; /* do NULLs come before normal values? */ /* Results */ Selectivity leftstartsel; /* first-join fraction for clause left side */ diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index 16dc4d5ee82..b1a76816442 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -272,7 +272,7 @@ extern bool has_useful_pathkeys(PlannerInfo *root, RelOptInfo *rel); extern List *append_pathkeys(List *target, List *source); extern PathKey *make_canonical_pathkey(PlannerInfo *root, EquivalenceClass *eclass, Oid opfamily, - int strategy, bool nulls_first); + CompareType cmptype, bool nulls_first); extern void add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, List *live_childrels); -- 2.39.5