From 84db7de83afbf35b95687baa2893b42183fa872e Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 24 Jan 2025 16:12:38 +0100 Subject: [PATCH v19.2 5/6] Convert strategies to and from compare types For each Index AM, provide a mapping between operator strategies and the system-wide generic concept of a comparison type. For example, for btree, BTLessStrategyNumber maps to and from COMPARE_LT. Numerous places in the planner and executor think directly in terms of btree strategy numbers (and a few in terms of hash strategy numbers.) These should be converted over subsequent commits to think in terms of CompareType instead. Author: Mark Dilger Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com --- contrib/bloom/blutils.c | 2 ++ doc/src/sgml/indexam.sgml | 26 +++++++++++++++ src/backend/access/brin/brin.c | 2 ++ src/backend/access/gist/gist.c | 2 ++ src/backend/access/hash/hash.c | 19 +++++++++++ src/backend/access/index/amapi.c | 50 ++++++++++++++++++++++++++++ src/backend/access/nbtree/nbtree.c | 43 ++++++++++++++++++++++++ src/backend/access/spgist/spgutils.c | 2 ++ src/include/access/amapi.h | 14 ++++++++ src/include/access/hash.h | 3 ++ src/include/access/nbtree.h | 3 ++ src/tools/pgindent/typedefs.list | 2 ++ 12 files changed, 168 insertions(+) diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index 3796bea786b..04b61042a57 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@ -150,6 +150,8 @@ blhandler(PG_FUNCTION_ARGS) amroutine->amestimateparallelscan = NULL; amroutine->aminitparallelscan = NULL; amroutine->amparallelrescan = NULL; + amroutine->amtranslatestrategy = NULL; + amroutine->amtranslatecmptype = NULL; PG_RETURN_POINTER(amroutine); } diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index dc7d14b60dd..d17fcbd5cec 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -164,6 +164,10 @@ Basic API Structure for Indexes amestimateparallelscan_function amestimateparallelscan; /* can be NULL */ aminitparallelscan_function aminitparallelscan; /* can be NULL */ amparallelrescan_function amparallelrescan; /* can be NULL */ + + /* interface functions to support planning */ + amtranslate_strategy_function amtranslatestrategy; /* can be NULL */ + amtranslate_cmptype_function amtranslatecmptype; /* can be NULL */ } IndexAmRoutine; @@ -876,6 +880,28 @@ Index Access Method Functions the beginning. + + +CompareType +amtranslatestrategy (StrategyNumber strategy, Oid opfamily, Oid opcintype); + +StrategyNumber +amtranslatecmptype (CompareType cmptype, Oid opfamily, Oid opcintype); + + These functions, if implemented, will be called by the planer and executor + to convert between fixed CompareType values and the specific + strategy numbers used by the access method. These functions can be + implemented by access methods that implement functionality similar to the + built-in btree or hash access methods, and by implementing these + translations, the system can learn about the semantics of the access + method's operations and can use them in place of btree or hash indexes in + various places. If the functionality of the access method is not similar + to those built-in access methods, these functions do not need to be + implemented. If the functions are not implemented, the access method will + be ignored for certain planner and executor decisions, but is otherwise + fully functional. + + diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 4289142e20b..ccf824bbdb2 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -298,6 +298,8 @@ brinhandler(PG_FUNCTION_ARGS) amroutine->amestimateparallelscan = NULL; amroutine->aminitparallelscan = NULL; amroutine->amparallelrescan = NULL; + amroutine->amtranslatestrategy = NULL; + amroutine->amtranslatecmptype = NULL; PG_RETURN_POINTER(amroutine); } diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index b6bc75b44e3..70f8086db7b 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -107,6 +107,8 @@ gisthandler(PG_FUNCTION_ARGS) amroutine->amestimateparallelscan = NULL; amroutine->aminitparallelscan = NULL; amroutine->amparallelrescan = NULL; + amroutine->amtranslatestrategy = NULL; + amroutine->amtranslatecmptype = NULL; PG_RETURN_POINTER(amroutine); } diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index f950b9925f5..504991215ea 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -21,6 +21,7 @@ #include "access/hash.h" #include "access/hash_xlog.h" #include "access/relscan.h" +#include "access/stratnum.h" #include "access/tableam.h" #include "access/xloginsert.h" #include "commands/progress.h" @@ -105,6 +106,8 @@ hashhandler(PG_FUNCTION_ARGS) amroutine->amestimateparallelscan = NULL; amroutine->aminitparallelscan = NULL; amroutine->amparallelrescan = NULL; + amroutine->amtranslatestrategy = hashtranslatestrategy; + amroutine->amtranslatecmptype = hashtranslatecmptype; PG_RETURN_POINTER(amroutine); } @@ -922,3 +925,19 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf, else LockBuffer(bucket_buf, BUFFER_LOCK_UNLOCK); } + +CompareType +hashtranslatestrategy(StrategyNumber strategy, Oid opfamily, Oid opcintype) +{ + if (strategy == HTEqualStrategyNumber) + return COMPARE_EQ; + return COMPARE_INVALID; +} + +StrategyNumber +hashtranslatecmptype(CompareType cmptype, Oid opfamily, Oid opcintype) +{ + if (cmptype == COMPARE_EQ) + return HTEqualStrategyNumber; + return InvalidStrategy; +} diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c index 3522bcaa401..5f53f49ec32 100644 --- a/src/backend/access/index/amapi.c +++ b/src/backend/access/index/amapi.c @@ -107,6 +107,56 @@ GetIndexAmRoutineByAmId(Oid amoid, bool noerror) } +/* + * IndexAmTranslateStrategy - given an access method and strategy, get the + * corresponding compare type. + * + * If missing_ok is false, throw an error if no compare type is found. If + * true, just return COMPARE_INVALID. + */ +CompareType +IndexAmTranslateStrategy(StrategyNumber strategy, Oid amoid, Oid opfamily, Oid opcintype, bool missing_ok) +{ + CompareType result; + IndexAmRoutine *amroutine; + + amroutine = GetIndexAmRoutineByAmId(amoid, false); + if (amroutine->amtranslatestrategy) + result = amroutine->amtranslatestrategy(strategy, opfamily, opcintype); + else + result = COMPARE_INVALID; + + if (!missing_ok && result == COMPARE_INVALID) + elog(ERROR, "could not translate strategy number %d for index AM %u", strategy, amoid); + + return result; +} + +/* + * IndexAmTranslateCompareType - given an access method and compare type, get + * the corresponding strategy number. + * + * If missing_ok is false, throw an error if no strategy is found correlating + * to the given cmptype. If true, just return InvalidStrategy. + */ +StrategyNumber +IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, Oid opcintype, bool missing_ok) +{ + StrategyNumber result; + IndexAmRoutine *amroutine; + + amroutine = GetIndexAmRoutineByAmId(amoid, false); + if (amroutine->amtranslatecmptype) + result = amroutine->amtranslatecmptype(cmptype, opfamily, opcintype); + else + result = InvalidStrategy; + + if (!missing_ok && result == InvalidStrategy) + elog(ERROR, "could not translate compare type %u for index AM %u", cmptype, amoid); + + return result; +} + /* * Ask appropriate access method to validate the specified opclass. */ diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 3d617f168f5..971405e89af 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -20,6 +20,7 @@ #include "access/nbtree.h" #include "access/relscan.h" +#include "access/stratnum.h" #include "commands/progress.h" #include "commands/vacuum.h" #include "nodes/execnodes.h" @@ -148,6 +149,8 @@ bthandler(PG_FUNCTION_ARGS) amroutine->amestimateparallelscan = btestimateparallelscan; amroutine->aminitparallelscan = btinitparallelscan; amroutine->amparallelrescan = btparallelrescan; + amroutine->amtranslatestrategy = bttranslatestrategy; + amroutine->amtranslatecmptype = bttranslatecmptype; PG_RETURN_POINTER(amroutine); } @@ -1508,3 +1511,43 @@ btgettreeheight(Relation rel) { return _bt_getrootheight(rel); } + +CompareType +bttranslatestrategy(StrategyNumber strategy, Oid opfamily, Oid opcintype) +{ + switch (strategy) + { + case BTLessStrategyNumber: + return COMPARE_LT; + case BTLessEqualStrategyNumber: + return COMPARE_LE; + case BTEqualStrategyNumber: + return COMPARE_EQ; + case BTGreaterEqualStrategyNumber: + return COMPARE_GE; + case BTGreaterStrategyNumber: + return COMPARE_GT; + default: + return COMPARE_INVALID; + } +} + +StrategyNumber +bttranslatecmptype(CompareType cmptype, Oid opfamily, Oid opcintype) +{ + switch (cmptype) + { + case COMPARE_LT: + return BTLessStrategyNumber; + case COMPARE_LE: + return BTLessEqualStrategyNumber; + case COMPARE_EQ: + return BTEqualStrategyNumber; + case COMPARE_GE: + return BTGreaterEqualStrategyNumber; + case COMPARE_GT: + return BTGreaterStrategyNumber; + default: + return InvalidStrategy; + } +} diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 6e968048917..367c36ef9af 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -92,6 +92,8 @@ spghandler(PG_FUNCTION_ARGS) amroutine->amestimateparallelscan = NULL; amroutine->aminitparallelscan = NULL; amroutine->amparallelrescan = NULL; + amroutine->amtranslatestrategy = NULL; + amroutine->amtranslatecmptype = NULL; PG_RETURN_POINTER(amroutine); } diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index fb94b3d1acf..6723de75a4d 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -12,7 +12,9 @@ #ifndef AMAPI_H #define AMAPI_H +#include "access/cmptype.h" #include "access/genam.h" +#include "access/stratnum.h" /* * We don't wish to include planner header files here, since most of an index @@ -99,6 +101,12 @@ typedef struct OpFamilyMember * Callback function signatures --- see indexam.sgml for more info. */ +/* translate AM-specific strategies to general operator types */ +typedef CompareType (*amtranslate_strategy_function) (StrategyNumber strategy, Oid opfamily, Oid opcintype); + +/* translate general operator types to AM-specific strategies */ +typedef StrategyNumber (*amtranslate_cmptype_function) (CompareType cmptype, Oid opfamily, Oid opcintype); + /* build new index */ typedef IndexBuildResult *(*ambuild_function) (Relation heapRelation, Relation indexRelation, @@ -301,11 +309,17 @@ typedef struct IndexAmRoutine amestimateparallelscan_function amestimateparallelscan; /* can be NULL */ aminitparallelscan_function aminitparallelscan; /* can be NULL */ amparallelrescan_function amparallelrescan; /* can be NULL */ + + /* interface functions to support planning */ + amtranslate_strategy_function amtranslatestrategy; /* can be NULL */ + amtranslate_cmptype_function amtranslatecmptype; /* can be NULL */ } IndexAmRoutine; /* Functions in access/index/amapi.c */ extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler); extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid, bool noerror); +extern CompareType IndexAmTranslateStrategy(StrategyNumber strategy, Oid amoid, Oid opfamily, Oid opcintype, bool missing_ok); +extern StrategyNumber IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, Oid opcintype, bool missing_ok); #endif /* AMAPI_H */ diff --git a/src/include/access/hash.h b/src/include/access/hash.h index 0f09f35a9fd..e91f2b00ad9 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -387,6 +387,9 @@ extern void hashadjustmembers(Oid opfamilyoid, List *operators, List *functions); +extern CompareType hashtranslatestrategy(StrategyNumber strategy, Oid opfamily, Oid opcintype); +extern StrategyNumber hashtranslatecmptype(CompareType cmptype, Oid opfamily, Oid opcintype); + /* private routines */ /* hashinsert.c */ diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index 6a501537e1e..000c7289b80 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -1183,6 +1183,9 @@ extern IndexBulkDeleteResult *btvacuumcleanup(IndexVacuumInfo *info, extern bool btcanreturn(Relation index, int attno); extern int btgettreeheight(Relation rel); +extern CompareType bttranslatestrategy(StrategyNumber strategy, Oid opfamily, Oid opcintype); +extern StrategyNumber bttranslatecmptype(CompareType cmptype, Oid opfamily, Oid opcintype); + /* * prototypes for internal functions in nbtree.c */ diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index a2644a2e653..9a3bee93dec 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -3318,6 +3318,8 @@ amparallelrescan_function amproperty_function amrescan_function amrestrpos_function +amtranslate_strategy_function amtranslatestrategy; +amtranslate_cmptype_function amtranslatecmptype; amvacuumcleanup_function amvalidate_function array_iter -- 2.48.1