From 143591c6bbae43056ae48a038d6e89b181dafc63 Mon Sep 17 00:00:00 2001 From: Mark Dilger Date: Sat, 1 Mar 2025 05:00:43 -0800 Subject: [PATCH v22 06/10] Convert from StrategyNumber to CompareType Reduce the number of places that hardcode a btree strategy number by instead using comparison types. Generalize predicate tests beyond btree strategies. Extend routines which prove logical implications between predicate expressions to be usable by more than just B-tree index strategies. Allow non-btree indexes to participate in mergejoin. Rather than hardcoding a requirement that the index be of type btree, just require that it provide ordering support. A number of places in the code still had references to btree strategies where not appropriate, so fix those. Leave untouched such strategy numbers in nbtree, spgist, and brin indexes, and also in table partitioning. Hardcoded hash and btree references in table partitioning are part of the design of table partitioning; their replacement, if even a good idea, is beyond the scope of this patch series. Author: Mark Dilger Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com --- contrib/postgres_fdw/deparse.c | 10 +- contrib/postgres_fdw/postgres_fdw.c | 2 +- src/backend/executor/execExpr.c | 1 + src/backend/executor/nodeIndexscan.c | 2 + src/backend/executor/nodeMergejoin.c | 7 +- src/backend/optimizer/path/allpaths.c | 28 ++-- src/backend/optimizer/path/costsize.c | 8 +- src/backend/optimizer/path/equivclass.c | 3 +- src/backend/optimizer/path/indxpath.c | 10 +- src/backend/optimizer/path/pathkeys.c | 45 ++++--- src/backend/optimizer/plan/createplan.c | 34 ++--- src/backend/optimizer/util/plancat.c | 27 ++-- src/backend/optimizer/util/predtest.c | 119 ++++++++--------- src/backend/parser/parse_clause.c | 4 +- src/backend/parser/parse_expr.c | 34 ++--- src/backend/partitioning/partprune.c | 13 +- src/backend/utils/adt/selfuncs.c | 133 +++++++++---------- src/backend/utils/cache/lsyscache.c | 162 +++++++++++++++--------- src/backend/utils/sort/sortsupport.c | 6 +- src/include/nodes/pathnodes.h | 12 +- src/include/optimizer/paths.h | 2 +- src/include/utils/lsyscache.h | 16 ++- src/include/utils/selfuncs.h | 2 +- src/tools/pgindent/typedefs.list | 2 +- 24 files changed, 364 insertions(+), 318 deletions(-) diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index 6e7dc3d2df9..cc2035a44f9 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -3973,13 +3973,13 @@ appendOrderByClause(List *pathkeys, bool has_final_sort, * 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 6beae0fa37f..5be3726de99 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -996,7 +996,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/executor/execExpr.c b/src/backend/executor/execExpr.c index f1569879b52..4b9388af154 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -2098,6 +2098,7 @@ ExecInitExprRec(Expr *node, ExprState *state, get_op_opfamily_properties(opno, opfamily, false, &strategy, + NULL, /* don't need cmptype */ &lefttype, &righttype); proc = get_opfamily_proc(opfamily, diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 7fcaa37fe62..c04fe461083 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -1246,6 +1246,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, get_op_opfamily_properties(opno, opfamily, isorderby, &op_strategy, + NULL, /* don't need cmptype */ &op_lefttype, &op_righttype); @@ -1487,6 +1488,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, get_op_opfamily_properties(opno, opfamily, isorderby, &op_strategy, + NULL, /* don't need cmptype */ &op_lefttype, &op_righttype); diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index f70239a2c9d..c7b813ac090 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -195,7 +195,7 @@ MJExamineQuals(List *mergeclauses, Oid collation = mergecollations[iClause]; bool reversed = mergereversals[iClause]; bool nulls_first = mergenullsfirst[iClause]; - int op_strategy; + CompareType op_cmptype; Oid op_lefttype; Oid op_righttype; Oid sortfunc; @@ -217,10 +217,11 @@ MJExamineQuals(List *mergeclauses, /* Extract the operator's declared left/right datatypes */ get_op_opfamily_properties(qual->opno, opfamily, false, - &op_strategy, + NULL, + &op_cmptype, &op_lefttype, &op_righttype); - if (op_strategy != BTEqualStrategyNumber) /* should not happen */ + if (op_cmptype != COMPARE_EQ) /* should not happen */ elog(ERROR, "cannot merge using non-equality operator %u", qual->opno); diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index df3453f99f0..905250b3325 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -2313,16 +2313,15 @@ find_window_run_conditions(Query *subquery, RangeTblEntry *rte, Index rti, runopexpr = NULL; runoperator = InvalidOid; - opinfos = get_op_btree_interpretation(opexpr->opno); + opinfos = get_op_index_interpretation(opexpr->opno); foreach(lc, opinfos) { - OpBtreeInterpretation *opinfo = (OpBtreeInterpretation *) lfirst(lc); - int strategy = opinfo->strategy; + OpIndexInterpretation *opinfo = (OpIndexInterpretation *) lfirst(lc); + CompareType cmptype = opinfo->cmptype; /* handle < / <= */ - if (strategy == BTLessStrategyNumber || - strategy == BTLessEqualStrategyNumber) + if (cmptype == COMPARE_LT || cmptype == COMPARE_LE) { /* * < / <= is supported for monotonically increasing functions in @@ -2339,8 +2338,7 @@ find_window_run_conditions(Query *subquery, RangeTblEntry *rte, Index rti, break; } /* handle > / >= */ - else if (strategy == BTGreaterStrategyNumber || - strategy == BTGreaterEqualStrategyNumber) + else if (cmptype == COMPARE_GT || cmptype == COMPARE_GE) { /* * > / >= is supported for monotonically decreasing functions in @@ -2357,9 +2355,9 @@ find_window_run_conditions(Query *subquery, RangeTblEntry *rte, Index rti, break; } /* handle = */ - else if (strategy == BTEqualStrategyNumber) + else if (cmptype == COMPARE_EQ) { - int16 newstrategy; + CompareType newcmptype; /* * When both monotonically increasing and decreasing then the @@ -2383,19 +2381,19 @@ find_window_run_conditions(Query *subquery, RangeTblEntry *rte, Index rti, * below the value in the equality condition. */ if (res->monotonic & MONOTONICFUNC_INCREASING) - newstrategy = wfunc_left ? BTLessEqualStrategyNumber : BTGreaterEqualStrategyNumber; + newcmptype = wfunc_left ? COMPARE_LE : COMPARE_GE; else - newstrategy = wfunc_left ? BTGreaterEqualStrategyNumber : BTLessEqualStrategyNumber; + newcmptype = wfunc_left ? COMPARE_GE : COMPARE_LE; /* We must keep the original equality qual */ *keep_original = true; runopexpr = opexpr; /* determine the operator to use for the WindowFuncRunCondition */ - runoperator = get_opfamily_member(opinfo->opfamily_id, - opinfo->oplefttype, - opinfo->oprighttype, - newstrategy); + runoperator = get_opfamily_member_for_cmptype(opinfo->opfamily_id, + opinfo->oplefttype, + opinfo->oprighttype, + newcmptype); break; } } diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index f6f77b8fe19..c1bf67c95dc 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/equivclass.c b/src/backend/optimizer/path/equivclass.c index 0f9ecf5ee8b..0ae7c6d4f74 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -1788,8 +1788,7 @@ select_equality_operator(EquivalenceClass *ec, Oid lefttype, Oid righttype) Oid opfamily = lfirst_oid(lc); Oid opno; - opno = get_opfamily_member(opfamily, lefttype, righttype, - BTEqualStrategyNumber); + opno = get_opfamily_member_for_cmptype(opfamily, lefttype, righttype, COMPARE_EQ); if (!OidIsValid(opno)) continue; /* If no barrier quals in query, don't worry about leaky operators */ diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index a43ca16d683..e81cd8e1f45 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -3526,6 +3526,7 @@ expand_indexqual_rowcompare(PlannerInfo *root, { IndexClause *iclause = makeNode(IndexClause); RowCompareExpr *clause = (RowCompareExpr *) rinfo->clause; + CompareType op_cmptype; int op_strategy; Oid op_lefttype; Oid op_righttype; @@ -3554,6 +3555,7 @@ expand_indexqual_rowcompare(PlannerInfo *root, get_op_opfamily_properties(expr_op, index->opfamily[indexcol], false, &op_strategy, + &op_cmptype, &op_lefttype, &op_righttype); @@ -3615,6 +3617,7 @@ expand_indexqual_rowcompare(PlannerInfo *root, /* Add operator info to lists */ get_op_opfamily_properties(expr_op, index->opfamily[i], false, &op_strategy, + &op_cmptype, &op_lefttype, &op_righttype); expr_ops = lappend_oid(expr_ops, expr_op); @@ -3688,6 +3691,10 @@ expand_indexqual_rowcompare(PlannerInfo *root, { RowCompareExpr *rc = makeNode(RowCompareExpr); + /* + * XXX This assumes that CompareType values match btree strategy + * numbers; see cmptype.h. + */ rc->cmptype = (CompareType) op_strategy; rc->opnos = new_ops; rc->opfamilies = list_copy_head(clause->opfamilies, @@ -3760,8 +3767,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..5db7033e3a9 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 @@ -219,13 +219,13 @@ make_pathkey_from_sortinfo(PlannerInfo *root, * more than one opfamily. So we have to look up the opfamily's equality * operator and get its membership. */ - equality_op = get_opfamily_member(opfamily, - opcintype, - opcintype, - BTEqualStrategyNumber); + equality_op = get_opfamily_member_for_cmptype(opfamily, + opcintype, + opcintype, + COMPARE_EQ); if (!OidIsValid(equality_op)) /* shouldn't happen */ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", - BTEqualStrategyNumber, opcintype, opcintype, opfamily); + COMPARE_EQ, opcintype, opcintype, opfamily); opfamilies = get_mergejoin_opfamilies(equality_op); if (!opfamilies) /* certainly should find some */ elog(ERROR, "could not find opfamilies for equality operator %u", @@ -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); } /* @@ -264,11 +264,10 @@ make_pathkey_from_sortop(PlannerInfo *root, Oid opfamily, opcintype, collation; - int16 strategy; /* Find the operator in pg_amop --- failure shouldn't happen */ if (!get_ordering_op_properties(ordering_op, - &opfamily, &opcintype, &strategy)) + &opfamily, &opcintype, NULL, NULL)) elog(ERROR, "operator %u is not a valid ordering operator", ordering_op); @@ -1006,12 +1005,12 @@ build_expression_pathkey(PlannerInfo *root, List *pathkeys; Oid opfamily, opcintype; - int16 strategy; + CompareType cmptype; PathKey *cpathkey; /* Find the operator in pg_amop --- failure shouldn't happen */ if (!get_ordering_op_properties(opno, - &opfamily, &opcintype, &strategy)) + &opfamily, &opcintype, NULL, &cmptype)) elog(ERROR, "operator %u is not a valid ordering operator", opno); @@ -1020,8 +1019,8 @@ build_expression_pathkey(PlannerInfo *root, opfamily, opcintype, exprCollation((Node *) expr), - (strategy == BTGreaterStrategyNumber), - (strategy == BTGreaterStrategyNumber), + (cmptype == COMPARE_GT), + (cmptype == COMPARE_GT), 0, rel, create_it); @@ -1118,7 +1117,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 +1199,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 +1815,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 +1908,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 +2133,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..a8f22a8c154 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 */ @@ -6893,13 +6893,13 @@ make_unique_from_pathkeys(Plan *lefttree, List *pathkeys, int numCols) * Look up the correct equality operator from the PathKey's slightly * abstracted representation. */ - eqop = get_opfamily_member(pathkey->pk_opfamily, - pk_datatype, - pk_datatype, - BTEqualStrategyNumber); + eqop = get_opfamily_member_for_cmptype(pathkey->pk_opfamily, + pk_datatype, + pk_datatype, + COMPARE_EQ); if (!OidIsValid(eqop)) /* should not happen */ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u", - BTEqualStrategyNumber, pk_datatype, pk_datatype, + COMPARE_EQ, pk_datatype, pk_datatype, pathkey->pk_opfamily); uniqColIdx[keyno] = tle->resno; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 0489ad36644..f8b15062ce2 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -382,27 +382,28 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, { int16 opt = indexRelation->rd_indoption[i]; Oid ltopr; - Oid btopfamily; - Oid btopcintype; - int16 btstrategy; + Oid opfamily; + Oid opcintype; + CompareType cmptype; info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0; info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0; - ltopr = get_opfamily_member(info->opfamily[i], - info->opcintype[i], - info->opcintype[i], - BTLessStrategyNumber); + ltopr = get_opfamily_member_for_cmptype(info->opfamily[i], + info->opcintype[i], + info->opcintype[i], + COMPARE_LT); if (OidIsValid(ltopr) && get_ordering_op_properties(ltopr, - &btopfamily, - &btopcintype, - &btstrategy) && - btopcintype == info->opcintype[i] && - btstrategy == BTLessStrategyNumber) + &opfamily, + &opcintype, + NULL, + &cmptype) && + opcintype == info->opcintype[i] && + cmptype == COMPARE_LT) { /* Successful mapping */ - info->sortopfamily[i] = btopfamily; + info->sortopfamily[i] = opfamily; } else { diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index b76fc81b08d..b35b985233e 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -1605,36 +1605,36 @@ clause_is_strict_for(Node *clause, Node *subexpr, bool allow_false) /* - * Define "operator implication tables" for btree operators ("strategies"), + * Define "operator implication tables" for index operators ("cmptypes"), * and similar tables for refutation. * - * The strategy numbers defined by btree indexes (see access/stratnum.h) are: - * 1 < 2 <= 3 = 4 >= 5 > + * The row compare numbers defined by indexes (see access/cmptype.h) are: + * 1 < 2 <= 3 = 4 >= 5 > 6 <> * and in addition we use 6 to represent <>. <> is not a btree-indexable * operator, but we assume here that if an equality operator of a btree * opfamily has a negator operator, the negator behaves as <> for the opfamily. - * (This convention is also known to get_op_btree_interpretation().) + * (This convention is also known to get_op_index_interpretation().) * - * BT_implies_table[] and BT_refutes_table[] are used for cases where we have + * RC_implies_table[] and RC_refutes_table[] are used for cases where we have * two identical subexpressions and we want to know whether one operator * expression implies or refutes the other. That is, if the "clause" is * EXPR1 clause_op EXPR2 and the "predicate" is EXPR1 pred_op EXPR2 for the * same two (immutable) subexpressions: - * BT_implies_table[clause_op-1][pred_op-1] + * RC_implies_table[clause_op-1][pred_op-1] * is true if the clause implies the predicate - * BT_refutes_table[clause_op-1][pred_op-1] + * RC_refutes_table[clause_op-1][pred_op-1] * is true if the clause refutes the predicate - * where clause_op and pred_op are strategy numbers (from 1 to 6) in the - * same btree opfamily. For example, "x < y" implies "x <= y" and refutes + * where clause_op and pred_op are cmptype numbers (from 1 to 6) in the + * same opfamily. For example, "x < y" implies "x <= y" and refutes * "x > y". * - * BT_implic_table[] and BT_refute_table[] are used where we have two + * RC_implic_table[] and RC_refute_table[] are used where we have two * constants that we need to compare. The interpretation of: * - * test_op = BT_implic_table[clause_op-1][pred_op-1] + * test_op = RC_implic_table[clause_op-1][pred_op-1] * - * where test_op, clause_op and pred_op are strategy numbers (from 1 to 6) - * of btree operators, is as follows: + * where test_op, clause_op and pred_op are cmptypes (from 1 to 6) + * of index operators, is as follows: * * If you know, for some EXPR, that "EXPR clause_op CONST1" is true, and you * want to determine whether "EXPR pred_op CONST2" must also be true, then @@ -1645,7 +1645,7 @@ clause_is_strict_for(Node *clause, Node *subexpr, bool allow_false) * For example, if clause is "Quantity > 10" and pred is "Quantity > 5" * then we test "5 <= 10" which evals to true, so clause implies pred. * - * Similarly, the interpretation of a BT_refute_table entry is: + * Similarly, the interpretation of a RC_refute_table entry is: * * If you know, for some EXPR, that "EXPR clause_op CONST1" is true, and you * want to determine whether "EXPR pred_op CONST2" must be false, then @@ -1659,17 +1659,17 @@ clause_is_strict_for(Node *clause, Node *subexpr, bool allow_false) * An entry where test_op == 0 means the implication cannot be determined. */ -#define BTLT BTLessStrategyNumber -#define BTLE BTLessEqualStrategyNumber -#define BTEQ BTEqualStrategyNumber -#define BTGE BTGreaterEqualStrategyNumber -#define BTGT BTGreaterStrategyNumber -#define BTNE COMPARE_NE +#define RCLT COMPARE_LT +#define RCLE COMPARE_LE +#define RCEQ COMPARE_EQ +#define RCGE COMPARE_GE +#define RCGT COMPARE_GT +#define RCNE COMPARE_NE /* We use "none" for 0/false to make the tables align nicely */ #define none 0 -static const bool BT_implies_table[6][6] = { +static const bool RC_implies_table[6][6] = { /* * The predicate operator: * LT LE EQ GE GT NE @@ -1682,7 +1682,7 @@ static const bool BT_implies_table[6][6] = { {none, none, none, none, none, true} /* NE */ }; -static const bool BT_refutes_table[6][6] = { +static const bool RC_refutes_table[6][6] = { /* * The predicate operator: * LT LE EQ GE GT NE @@ -1695,30 +1695,30 @@ static const bool BT_refutes_table[6][6] = { {none, none, true, none, none, none} /* NE */ }; -static const StrategyNumber BT_implic_table[6][6] = { +static const StrategyNumber RC_implic_table[6][6] = { /* * The predicate operator: * LT LE EQ GE GT NE */ - {BTGE, BTGE, none, none, none, BTGE}, /* LT */ - {BTGT, BTGE, none, none, none, BTGT}, /* LE */ - {BTGT, BTGE, BTEQ, BTLE, BTLT, BTNE}, /* EQ */ - {none, none, none, BTLE, BTLT, BTLT}, /* GE */ - {none, none, none, BTLE, BTLE, BTLE}, /* GT */ - {none, none, none, none, none, BTEQ} /* NE */ + {RCGE, RCGE, none, none, none, RCGE}, /* LT */ + {RCGT, RCGE, none, none, none, RCGT}, /* LE */ + {RCGT, RCGE, RCEQ, RCLE, RCLT, RCNE}, /* EQ */ + {none, none, none, RCLE, RCLT, RCLT}, /* GE */ + {none, none, none, RCLE, RCLE, RCLE}, /* GT */ + {none, none, none, none, none, RCEQ} /* NE */ }; -static const StrategyNumber BT_refute_table[6][6] = { +static const StrategyNumber RC_refute_table[6][6] = { /* * The predicate operator: * LT LE EQ GE GT NE */ - {none, none, BTGE, BTGE, BTGE, none}, /* LT */ - {none, none, BTGT, BTGT, BTGE, none}, /* LE */ - {BTLE, BTLT, BTNE, BTGT, BTGE, BTEQ}, /* EQ */ - {BTLE, BTLT, BTLT, none, none, none}, /* GE */ - {BTLE, BTLE, BTLE, none, none, none}, /* GT */ - {none, none, BTEQ, none, none, none} /* NE */ + {none, none, RCGE, RCGE, RCGE, none}, /* LT */ + {none, none, RCGT, RCGT, RCGE, none}, /* LE */ + {RCLE, RCLT, RCNE, RCGT, RCGE, RCEQ}, /* EQ */ + {RCLE, RCLT, RCLT, none, none, none}, /* GE */ + {RCLE, RCLE, RCLE, none, none, none}, /* GT */ + {none, none, RCEQ, none, none, none} /* NE */ }; @@ -2165,66 +2165,67 @@ lookup_proof_cache(Oid pred_op, Oid clause_op, bool refute_it) * operator. This can happen in cases with incomplete sets of cross-type * comparison operators. */ - clause_op_infos = get_op_btree_interpretation(clause_op); + clause_op_infos = get_op_index_interpretation(clause_op); if (clause_op_infos) - pred_op_infos = get_op_btree_interpretation(pred_op); + pred_op_infos = get_op_index_interpretation(pred_op); else /* no point in looking */ pred_op_infos = NIL; foreach(lcp, pred_op_infos) { - OpBtreeInterpretation *pred_op_info = lfirst(lcp); + OpIndexInterpretation *pred_op_info = lfirst(lcp); Oid opfamily_id = pred_op_info->opfamily_id; foreach(lcc, clause_op_infos) { - OpBtreeInterpretation *clause_op_info = lfirst(lcc); - StrategyNumber pred_strategy, - clause_strategy, - test_strategy; + OpIndexInterpretation *clause_op_info = lfirst(lcc); + CompareType pred_cmptype, + clause_cmptype, + test_cmptype; /* Must find them in same opfamily */ if (opfamily_id != clause_op_info->opfamily_id) continue; /* Lefttypes should match */ - Assert(clause_op_info->oplefttype == pred_op_info->oplefttype); + if (clause_op_info->oplefttype != pred_op_info->oplefttype) + continue; - pred_strategy = pred_op_info->strategy; - clause_strategy = clause_op_info->strategy; + pred_cmptype = pred_op_info->cmptype; + clause_cmptype = clause_op_info->cmptype; /* * Check to see if we can make a proof for same-subexpressions * cases based on the operators' relationship in this opfamily. */ if (refute_it) - same_subexprs |= BT_refutes_table[clause_strategy - 1][pred_strategy - 1]; + same_subexprs |= RC_refutes_table[clause_cmptype - 1][pred_cmptype - 1]; else - same_subexprs |= BT_implies_table[clause_strategy - 1][pred_strategy - 1]; + same_subexprs |= RC_implies_table[clause_cmptype - 1][pred_cmptype - 1]; /* - * Look up the "test" strategy number in the implication table + * Look up the "test" cmptype number in the implication table */ if (refute_it) - test_strategy = BT_refute_table[clause_strategy - 1][pred_strategy - 1]; + test_cmptype = RC_refute_table[clause_cmptype - 1][pred_cmptype - 1]; else - test_strategy = BT_implic_table[clause_strategy - 1][pred_strategy - 1]; + test_cmptype = RC_implic_table[clause_cmptype - 1][pred_cmptype - 1]; - if (test_strategy == 0) + if (test_cmptype == 0) { /* Can't determine implication using this interpretation */ continue; } /* - * See if opfamily has an operator for the test strategy and the + * See if opfamily has an operator for the test cmptype and the * datatypes. */ - if (test_strategy == BTNE) + if (test_cmptype == RCNE) { - test_op = get_opfamily_member(opfamily_id, - pred_op_info->oprighttype, - clause_op_info->oprighttype, - BTEqualStrategyNumber); + test_op = get_opfamily_member_for_cmptype(opfamily_id, + pred_op_info->oprighttype, + clause_op_info->oprighttype, + COMPARE_EQ); if (OidIsValid(test_op)) test_op = get_negator(test_op); } @@ -2233,7 +2234,7 @@ lookup_proof_cache(Oid pred_op, Oid clause_op, bool refute_it) test_op = get_opfamily_member(opfamily_id, pred_op_info->oprighttype, clause_op_info->oprighttype, - test_strategy); + test_cmptype); } if (!OidIsValid(test_op)) diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 2e64fcae7b2..bf50a0e656d 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -2915,7 +2915,6 @@ transformWindowDefinitions(ParseState *pstate, { SortGroupClause *sortcl; Node *sortkey; - int16 rangestrategy; if (list_length(wc->orderClause) != 1) ereport(ERROR, @@ -2928,7 +2927,8 @@ transformWindowDefinitions(ParseState *pstate, if (!get_ordering_op_properties(sortcl->sortop, &rangeopfamily, &rangeopcintype, - &rangestrategy)) + NULL, + NULL)) elog(ERROR, "operator %u is not a valid ordering operator", sortcl->sortop); /* Record properties of sort ordering */ diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 9caf1e481a2..806ccb97537 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -2832,7 +2832,7 @@ make_row_comparison_op(ParseState *pstate, List *opname, ListCell *l, *r; List **opinfo_lists; - Bitmapset *strats; + Bitmapset *cmptypes; int nopers; int i; @@ -2897,45 +2897,45 @@ make_row_comparison_op(ParseState *pstate, List *opname, /* * Now we must determine which row comparison semantics (= <> < <= > >=) - * apply to this set of operators. We look for btree opfamilies - * containing the operators, and see which interpretations (strategy - * numbers) exist for each operator. + * apply to this set of operators. We look for opfamilies containing the + * operators, and see which interpretations (cmptypes) exist for each + * operator. */ opinfo_lists = (List **) palloc(nopers * sizeof(List *)); - strats = NULL; + cmptypes = NULL; i = 0; foreach(l, opexprs) { Oid opno = ((OpExpr *) lfirst(l))->opno; - Bitmapset *this_strats; + Bitmapset *this_cmptypes; ListCell *j; - opinfo_lists[i] = get_op_btree_interpretation(opno); + opinfo_lists[i] = get_op_index_interpretation(opno); /* - * convert strategy numbers into a Bitmapset to make the intersection + * convert comparison types into a Bitmapset to make the intersection * calculation easy. */ - this_strats = NULL; + this_cmptypes = NULL; foreach(j, opinfo_lists[i]) { - OpBtreeInterpretation *opinfo = lfirst(j); + OpIndexInterpretation *opinfo = lfirst(j); - this_strats = bms_add_member(this_strats, opinfo->strategy); + this_cmptypes = bms_add_member(this_cmptypes, opinfo->cmptype); } if (i == 0) - strats = this_strats; + cmptypes = this_cmptypes; else - strats = bms_int_members(strats, this_strats); + cmptypes = bms_int_members(cmptypes, this_cmptypes); i++; } /* * If there are multiple common interpretations, we may use any one of - * them ... this coding arbitrarily picks the lowest btree strategy + * them ... this coding arbitrarily picks the lowest comparison type * number. */ - i = bms_next_member(strats, -1); + i = bms_next_member(cmptypes, -1); if (i < 0) { /* No common interpretation, so fail */ @@ -2969,9 +2969,9 @@ make_row_comparison_op(ParseState *pstate, List *opname, foreach(j, opinfo_lists[i]) { - OpBtreeInterpretation *opinfo = lfirst(j); + OpIndexInterpretation *opinfo = lfirst(j); - if (opinfo->strategy == cmptype) + if (opinfo->cmptype == cmptype) { opfamily = opinfo->opfamily_id; break; diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 48a35f763e9..12b5884bb9c 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -1455,6 +1455,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context, part_scheme->partopfamily[i], false, &pc->op_strategy, + NULL, /* don't need cmptype */ &lefttype, &righttype); @@ -1982,7 +1983,9 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, if (op_in_opfamily(opno, partopfamily)) { get_op_opfamily_properties(opno, partopfamily, false, - &op_strategy, &op_lefttype, + &op_strategy, + NULL, /* don't need cmptype */ + &op_lefttype, &op_righttype); } else @@ -1996,7 +1999,9 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, if (OidIsValid(negator) && op_in_opfamily(negator, partopfamily)) { get_op_opfamily_properties(negator, partopfamily, false, - &op_strategy, &op_lefttype, + &op_strategy, + NULL, /* don't need cmptype */ + &op_lefttype, &op_righttype); if (op_strategy == BTEqualStrategyNumber) is_opne_listp = true; /* bingo */ @@ -2211,7 +2216,9 @@ match_clause_to_partition_key(GeneratePruningStepsContext *context, righttype; get_op_opfamily_properties(negator, partopfamily, - false, &strategy, + false, + &strategy, + NULL, /* don't need cmptype */ &lefttype, &righttype); if (strategy != BTEqualStrategyNumber) return PARTCLAUSE_NOMATCH; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 5b35debc8ff..8c722cf46ce 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -2954,7 +2954,7 @@ scalargejoinsel(PG_FUNCTION_ARGS) */ void mergejoinscansel(PlannerInfo *root, Node *clause, - Oid opfamily, int strategy, bool nulls_first, + Oid opfamily, CompareType cmptype, bool nulls_first, Selectivity *leftstart, Selectivity *leftend, Selectivity *rightstart, Selectivity *rightend) { @@ -2963,6 +2963,7 @@ mergejoinscansel(PlannerInfo *root, Node *clause, VariableStatData leftvar, rightvar; int op_strategy; + CompareType op_cmptype; Oid op_lefttype; Oid op_righttype; Oid opno, @@ -3004,9 +3005,10 @@ mergejoinscansel(PlannerInfo *root, Node *clause, /* Extract the operator's declared left/right datatypes */ get_op_opfamily_properties(opno, opfamily, false, &op_strategy, + &op_cmptype, &op_lefttype, &op_righttype); - Assert(op_strategy == BTEqualStrategyNumber); + Assert(op_cmptype == COMPARE_EQ); /* * Look up the various operators we need. If we don't find them all, it @@ -3015,19 +3017,17 @@ mergejoinscansel(PlannerInfo *root, Node *clause, * Note: we expect that pg_statistic histograms will be sorted by the '<' * operator, regardless of which sort direction we are considering. */ - switch (strategy) + switch (cmptype) { - case BTLessStrategyNumber: + case COMPARE_LT: isgt = false; if (op_lefttype == op_righttype) { /* easy case */ - ltop = get_opfamily_member(opfamily, - op_lefttype, op_righttype, - BTLessStrategyNumber); - leop = get_opfamily_member(opfamily, - op_lefttype, op_righttype, - BTLessEqualStrategyNumber); + ltop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, + op_righttype, COMPARE_LT); + leop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, + op_righttype, COMPARE_LE); lsortop = ltop; rsortop = ltop; lstatop = lsortop; @@ -3037,75 +3037,58 @@ mergejoinscansel(PlannerInfo *root, Node *clause, } else { - ltop = get_opfamily_member(opfamily, - op_lefttype, op_righttype, - BTLessStrategyNumber); - leop = get_opfamily_member(opfamily, - op_lefttype, op_righttype, - BTLessEqualStrategyNumber); - lsortop = get_opfamily_member(opfamily, - op_lefttype, op_lefttype, - BTLessStrategyNumber); - rsortop = get_opfamily_member(opfamily, - op_righttype, op_righttype, - BTLessStrategyNumber); + ltop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, + op_righttype, COMPARE_LT); + leop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, + op_righttype, COMPARE_LE); + lsortop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, + op_lefttype, COMPARE_LT); + rsortop = get_opfamily_member_for_cmptype(opfamily, op_righttype, + op_righttype, COMPARE_LT); lstatop = lsortop; rstatop = rsortop; - revltop = get_opfamily_member(opfamily, - op_righttype, op_lefttype, - BTLessStrategyNumber); - revleop = get_opfamily_member(opfamily, - op_righttype, op_lefttype, - BTLessEqualStrategyNumber); + revltop = get_opfamily_member_for_cmptype(opfamily, op_righttype, + op_lefttype, COMPARE_LT); + revleop = get_opfamily_member_for_cmptype(opfamily, op_righttype, + op_lefttype, COMPARE_LE); } break; - case BTGreaterStrategyNumber: + case COMPARE_GT: /* descending-order case */ isgt = true; if (op_lefttype == op_righttype) { /* easy case */ - ltop = get_opfamily_member(opfamily, - op_lefttype, op_righttype, - BTGreaterStrategyNumber); - leop = get_opfamily_member(opfamily, - op_lefttype, op_righttype, - BTGreaterEqualStrategyNumber); + ltop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, op_righttype, + COMPARE_GT); + leop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, op_righttype, + COMPARE_GE); lsortop = ltop; rsortop = ltop; - lstatop = get_opfamily_member(opfamily, - op_lefttype, op_lefttype, - BTLessStrategyNumber); + lstatop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, op_lefttype, + COMPARE_LT); rstatop = lstatop; revltop = ltop; revleop = leop; } else { - ltop = get_opfamily_member(opfamily, - op_lefttype, op_righttype, - BTGreaterStrategyNumber); - leop = get_opfamily_member(opfamily, - op_lefttype, op_righttype, - BTGreaterEqualStrategyNumber); - lsortop = get_opfamily_member(opfamily, - op_lefttype, op_lefttype, - BTGreaterStrategyNumber); - rsortop = get_opfamily_member(opfamily, - op_righttype, op_righttype, - BTGreaterStrategyNumber); - lstatop = get_opfamily_member(opfamily, - op_lefttype, op_lefttype, - BTLessStrategyNumber); - rstatop = get_opfamily_member(opfamily, - op_righttype, op_righttype, - BTLessStrategyNumber); - revltop = get_opfamily_member(opfamily, - op_righttype, op_lefttype, - BTGreaterStrategyNumber); - revleop = get_opfamily_member(opfamily, - op_righttype, op_lefttype, - BTGreaterEqualStrategyNumber); + ltop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, + op_righttype, COMPARE_GT); + leop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, + op_righttype, COMPARE_GE); + lsortop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, + op_lefttype, COMPARE_GT); + rsortop = get_opfamily_member_for_cmptype(opfamily, op_righttype, + op_righttype, COMPARE_GT); + lstatop = get_opfamily_member_for_cmptype(opfamily, op_lefttype, + op_lefttype, COMPARE_LT); + rstatop = get_opfamily_member_for_cmptype(opfamily, op_righttype, + op_righttype, COMPARE_LT); + revltop = get_opfamily_member_for_cmptype(opfamily, op_righttype, + op_lefttype, COMPARE_GT); + revleop = get_opfamily_member_for_cmptype(opfamily, op_righttype, + op_lefttype, COMPARE_GE); } break; default: @@ -6327,10 +6310,7 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata, { IndexOptInfo *index = (IndexOptInfo *) lfirst(lc); ScanDirection indexscandir; - - /* Ignore non-btree indexes */ - if (index->relam != BTREE_AM_OID) - continue; + StrategyNumber strategy; /* * Ignore partial indexes --- we only want stats that cover the entire @@ -6354,15 +6334,16 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata, continue; /* test first 'cause it's cheapest */ if (!match_index_to_operand(vardata->var, 0, index)) continue; - switch (get_op_opfamily_strategy(sortop, index->sortopfamily[0])) + strategy = get_op_opfamily_strategy(sortop, index->sortopfamily[0]); + switch (IndexAmTranslateStrategy(strategy, index->relam, index->sortopfamily[0], true)) { - case BTLessStrategyNumber: + case COMPARE_LT: if (index->reverse_sort[0]) indexscandir = BackwardScanDirection; else indexscandir = ForwardScanDirection; break; - case BTGreaterStrategyNumber: + case COMPARE_GT: if (index->reverse_sort[0]) indexscandir = ForwardScanDirection; else @@ -6602,13 +6583,17 @@ get_actual_variable_endpoint(Relation heapRel, } /* - * We expect that btree will return data in IndexTuple not HeapTuple - * format. It's not lossy either. + * We expect that the index will return data in IndexTuple not + * HeapTuple format. */ if (!index_scan->xs_itup) elog(ERROR, "no data returned for index-only scan"); + + /* + * We do not yet support recheck here. + */ if (index_scan->xs_recheck) - elog(ERROR, "unexpected recheck indication from btree"); + break; /* OK to deconstruct the index tuple */ index_deform_tuple(index_scan->xs_itup, @@ -7544,7 +7529,9 @@ gincost_pattern(IndexOptInfo *index, int indexcol, * find a matching pg_amop entry.) */ get_op_opfamily_properties(clause_op, index->opfamily[indexcol], false, - &strategy_op, &lefttype, &righttype); + &strategy_op, + NULL, /* don't need cmptype */ + &lefttype, &righttype); /* * GIN always uses the "default" support functions, which are those with diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 82031c1e8e5..4ffcca545d2 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -136,6 +136,7 @@ get_op_opfamily_sortfamily(Oid opno, Oid opfamily) void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, + CompareType *cmptype, Oid *lefttype, Oid *righttype) { @@ -150,9 +151,17 @@ get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, elog(ERROR, "operator %u is not a member of opfamily %u", opno, opfamily); amop_tup = (Form_pg_amop) GETSTRUCT(tp); - *strategy = amop_tup->amopstrategy; - *lefttype = amop_tup->amoplefttype; - *righttype = amop_tup->amoprighttype; + if (strategy) + *strategy = amop_tup->amopstrategy; + if (cmptype) + *cmptype = IndexAmTranslateStrategy(amop_tup->amopstrategy, + amop_tup->amopmethod, + opfamily, + true); + if (lefttype) + *lefttype = amop_tup->amoplefttype; + if (righttype) + *righttype = amop_tup->amoprighttype; ReleaseSysCache(tp); } @@ -208,9 +217,9 @@ get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, /* * get_ordering_op_properties - * Given the OID of an ordering operator (a btree "<" or ">" operator), - * determine its opfamily, its declared input datatype, and its - * strategy number (BTLessStrategyNumber or BTGreaterStrategyNumber). + * Given the OID of an ordering operator (a "<" or ">" operator), + * determine its opmethod, its opfamily, its declared input datatype, its + * strategy number, and its row comparison type. * * Returns true if successful, false if no matching pg_amop entry exists. * (This indicates that the operator is not a valid ordering operator.) @@ -228,16 +237,21 @@ get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, */ bool get_ordering_op_properties(Oid opno, - Oid *opfamily, Oid *opcintype, int16 *strategy) + Oid *opfamily, Oid *opcintype, int16 *strategy, CompareType *cmptype) { bool result = false; CatCList *catlist; int i; /* ensure outputs are initialized on failure */ - *opfamily = InvalidOid; - *opcintype = InvalidOid; - *strategy = 0; + if (opfamily) + *opfamily = InvalidOid; + if (opcintype) + *opcintype = InvalidOid; + if (strategy) + *strategy = InvalidStrategy; + if (cmptype) + *cmptype = COMPARE_INVALID; /* * Search pg_amop to see if the target operator is registered as the "<" @@ -249,21 +263,30 @@ get_ordering_op_properties(Oid opno, { HeapTuple tuple = &catlist->members[i]->tuple; Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); + CompareType am_cmptype; - /* must be btree */ - if (aform->amopmethod != BTREE_AM_OID) - continue; + am_cmptype = IndexAmTranslateStrategy(aform->amopstrategy, + aform->amopmethod, + aform->amopfamily, + true); - if (aform->amopstrategy == BTLessStrategyNumber || - aform->amopstrategy == BTGreaterStrategyNumber) + if (am_cmptype == COMPARE_LT || am_cmptype == COMPARE_GT) { /* Found it ... should have consistent input types */ if (aform->amoplefttype == aform->amoprighttype) { /* Found a suitable opfamily, return info */ - *opfamily = aform->amopfamily; - *opcintype = aform->amoplefttype; - *strategy = aform->amopstrategy; + if (opfamily) + *opfamily = aform->amopfamily; + if (opcintype) + *opcintype = aform->amoplefttype; + if (strategy) + *strategy = aform->amopstrategy; + if (cmptype) + *cmptype = IndexAmTranslateStrategy(aform->amopstrategy, + aform->amopmethod, + aform->amopfamily, + false); result = true; break; } @@ -293,18 +316,19 @@ get_equality_op_for_ordering_op(Oid opno, bool *reverse) Oid opfamily; Oid opcintype; int16 strategy; + CompareType cmptype; /* Find the operator in pg_amop */ - if (get_ordering_op_properties(opno, - &opfamily, &opcintype, &strategy)) + if (get_ordering_op_properties(opno, &opfamily, + &opcintype, &strategy, &cmptype)) { /* Found a suitable opfamily, get matching equality operator */ - result = get_opfamily_member(opfamily, - opcintype, - opcintype, - BTEqualStrategyNumber); + result = get_opfamily_member_for_cmptype(opfamily, + opcintype, + opcintype, + COMPARE_EQ); if (reverse) - *reverse = (strategy == BTGreaterStrategyNumber); + *reverse = (cmptype == COMPARE_GT); } return result; @@ -341,20 +365,25 @@ get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type) { HeapTuple tuple = &catlist->members[i]->tuple; Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); + IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(aform->amopmethod, false); + CompareType cmptype; - /* must be btree */ - if (aform->amopmethod != BTREE_AM_OID) + if (!amroutine->amcanorder) continue; - if (aform->amopstrategy == BTEqualStrategyNumber) + cmptype = IndexAmTranslateStrategy(aform->amopstrategy, + aform->amopmethod, + aform->amopfamily, + true); + if (cmptype == COMPARE_EQ) { /* Found a suitable opfamily, get matching ordering operator */ Oid typid; typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype; - result = get_opfamily_member(aform->amopfamily, - typid, typid, - BTLessStrategyNumber); + result = get_opfamily_member_for_cmptype(aform->amopfamily, + typid, typid, + COMPARE_LT); if (OidIsValid(result)) break; /* failure probably shouldn't happen, but keep looking if so */ @@ -402,10 +431,14 @@ get_mergejoin_opfamilies(Oid opno) { HeapTuple tuple = &catlist->members[i]->tuple; Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple); - - /* must be btree equality */ - if (aform->amopmethod == BTREE_AM_OID && - aform->amopstrategy == BTEqualStrategyNumber) + IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(aform->amopmethod, false); + + /* must be equality from an ordering index */ + if (amroutine->amcanorder && + IndexAmTranslateStrategy(aform->amopstrategy, + aform->amopmethod, + aform->amopfamily, + true) == COMPARE_EQ) result = lappend_oid(result, aform->amopfamily); } @@ -611,20 +644,20 @@ get_op_hash_functions(Oid opno, } /* - * get_op_btree_interpretation + * get_op_index_interpretation * Given an operator's OID, find out which btree opfamilies it belongs to, * and what properties it has within each one. The results are returned - * as a palloc'd list of OpBtreeInterpretation structs. + * as a palloc'd list of OpIndexInterpretation structs. * * In addition to the normal btree operators, we consider a <> operator to be * a "member" of an opfamily if its negator is an equality operator of the * opfamily. COMPARE_NE is returned as the strategy number for this case. */ List * -get_op_btree_interpretation(Oid opno) +get_op_index_interpretation(Oid opno) { List *result = NIL; - OpBtreeInterpretation *thisresult; + OpIndexInterpretation *thisresult; CatCList *catlist; int i; @@ -637,20 +670,28 @@ get_op_btree_interpretation(Oid opno) { HeapTuple op_tuple = &catlist->members[i]->tuple; Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple); - StrategyNumber op_strategy; + IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false); + CompareType cmptype; - /* must be btree */ - if (op_form->amopmethod != BTREE_AM_OID) + /* must be ordering index */ + if (!amroutine->amcanorder) continue; - /* Get the operator's btree strategy number */ - op_strategy = (StrategyNumber) op_form->amopstrategy; - Assert(op_strategy >= 1 && op_strategy <= 5); + /* Get the operator's row comparision type */ + cmptype = IndexAmTranslateStrategy(op_form->amopstrategy, + op_form->amopmethod, + op_form->amopfamily, + true); + + /* should not happen */ + if (cmptype == COMPARE_INVALID) + continue; - thisresult = (OpBtreeInterpretation *) - palloc(sizeof(OpBtreeInterpretation)); + thisresult = (OpIndexInterpretation *) + palloc(sizeof(OpIndexInterpretation)); + thisresult->opmethod = op_form->amopmethod; thisresult->opfamily_id = op_form->amopfamily; - thisresult->strategy = op_strategy; + thisresult->cmptype = cmptype; thisresult->oplefttype = op_form->amoplefttype; thisresult->oprighttype = op_form->amoprighttype; result = lappend(result, thisresult); @@ -675,25 +716,28 @@ get_op_btree_interpretation(Oid opno) { HeapTuple op_tuple = &catlist->members[i]->tuple; Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple); - StrategyNumber op_strategy; + IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false); + CompareType cmptype; - /* must be btree */ - if (op_form->amopmethod != BTREE_AM_OID) + /* must be ordering index */ + if (!amroutine->amcanorder) continue; - /* Get the operator's btree strategy number */ - op_strategy = (StrategyNumber) op_form->amopstrategy; - Assert(op_strategy >= 1 && op_strategy <= 5); + /* Get the operator's row comparision type */ + cmptype = IndexAmTranslateStrategy(op_form->amopstrategy, + op_form->amopmethod, + op_form->amopfamily, + true); /* Only consider negators that are = */ - if (op_strategy != BTEqualStrategyNumber) + if (cmptype != COMPARE_EQ) continue; - /* OK, report it with "strategy" COMPARE_NE */ - thisresult = (OpBtreeInterpretation *) - palloc(sizeof(OpBtreeInterpretation)); + /* OK, report it as COMPARE_NE */ + thisresult = (OpIndexInterpretation *) + palloc(sizeof(OpIndexInterpretation)); thisresult->opfamily_id = op_form->amopfamily; - thisresult->strategy = COMPARE_NE; + thisresult->cmptype = COMPARE_NE; thisresult->oplefttype = op_form->amoplefttype; thisresult->oprighttype = op_form->amoprighttype; result = lappend(result, thisresult); diff --git a/src/backend/utils/sort/sortsupport.c b/src/backend/utils/sort/sortsupport.c index 0b4f08ed2ec..bfa31fa2225 100644 --- a/src/backend/utils/sort/sortsupport.c +++ b/src/backend/utils/sort/sortsupport.c @@ -135,16 +135,16 @@ PrepareSortSupportFromOrderingOp(Oid orderingOp, SortSupport ssup) { Oid opfamily; Oid opcintype; - int16 strategy; + CompareType cmptype; Assert(ssup->comparator == NULL); /* Find the operator in pg_amop */ if (!get_ordering_op_properties(orderingOp, &opfamily, &opcintype, - &strategy)) + NULL, &cmptype)) elog(ERROR, "operator %u is not a valid ordering operator", orderingOp); - ssup->ssup_reverse = (strategy == BTGreaterStrategyNumber); + ssup->ssup_reverse = (cmptype == COMPARE_GT); FinishSortSupportFunction(opfamily, opcintype, ssup); } diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index c24a1fc8514..9525ad0b150 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -1492,9 +1492,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 { @@ -1504,8 +1502,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; @@ -2770,9 +2768,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 bc5dfd7db41..17879fc461a 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -270,7 +270,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); diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index d42380a0d46..960e9f8f4d8 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -21,14 +21,15 @@ /* avoid including subscripting.h here */ struct SubscriptRoutines; -/* Result list element for get_op_btree_interpretation */ -typedef struct OpBtreeInterpretation +/* Result list element for get_op_index_interpretation */ +typedef struct OpIndexInterpretation { - Oid opfamily_id; /* btree opfamily containing operator */ - int strategy; /* its strategy number */ + Oid opmethod; /* index access method of opfamily */ + Oid opfamily_id; /* opfamily containing operator */ + CompareType cmptype; /* its generic comparison type */ Oid oplefttype; /* declared left input datatype */ Oid oprighttype; /* declared right input datatype */ -} OpBtreeInterpretation; +} OpIndexInterpretation; /* I/O function selector for get_type_io_data */ typedef enum IOFuncSelector @@ -71,6 +72,7 @@ extern int get_op_opfamily_strategy(Oid opno, Oid opfamily); extern Oid get_op_opfamily_sortfamily(Oid opno, Oid opfamily); extern void get_op_opfamily_properties(Oid opno, Oid opfamily, bool ordering_op, int *strategy, + CompareType *cmptype, Oid *lefttype, Oid *righttype); extern Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, @@ -78,7 +80,7 @@ extern Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, extern Oid get_opfamily_member_for_cmptype(Oid opfamily, Oid lefttype, Oid righttype, CompareType cmptype); extern bool get_ordering_op_properties(Oid opno, - Oid *opfamily, Oid *opcintype, int16 *strategy); + Oid *opfamily, Oid *opcintype, int16 *strategy, CompareType *cmptype); extern Oid get_equality_op_for_ordering_op(Oid opno, bool *reverse); extern Oid get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type); extern List *get_mergejoin_opfamilies(Oid opno); @@ -86,7 +88,7 @@ extern bool get_compatible_hash_operators(Oid opno, Oid *lhs_opno, Oid *rhs_opno); extern bool get_op_hash_functions(Oid opno, RegProcedure *lhs_procno, RegProcedure *rhs_procno); -extern List *get_op_btree_interpretation(Oid opno); +extern List *get_op_index_interpretation(Oid opno); extern bool equality_ops_are_compatible(Oid opno1, Oid opno2); extern bool comparison_ops_are_compatible(Oid opno1, Oid opno2); extern Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h index 82ac8c6d9da..013049b3098 100644 --- a/src/include/utils/selfuncs.h +++ b/src/include/utils/selfuncs.h @@ -210,7 +210,7 @@ extern Selectivity rowcomparesel(PlannerInfo *root, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo); extern void mergejoinscansel(PlannerInfo *root, Node *clause, - Oid opfamily, int strategy, bool nulls_first, + Oid opfamily, CompareType cmptype, bool nulls_first, Selectivity *leftstart, Selectivity *leftend, Selectivity *rightstart, Selectivity *rightend); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index bfa276d2d35..79a1f8370ac 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -1780,11 +1780,11 @@ OnConflictAction OnConflictClause OnConflictExpr OnConflictSetState -OpBtreeInterpretation OpClassCacheEnt OpExpr OpFamilyMember OpFamilyOpFuncGroup +OpIndexInterpretation OpclassInfo Operator OperatorElement -- 2.49.0