Convert strategies to and from compare types
authorPeter Eisentraut <peter@eisentraut.org>
Sun, 2 Feb 2025 09:26:04 +0000 (10:26 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Sun, 2 Feb 2025 09:26:04 +0000 (10:26 +0100)
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.  (This commit doesn't make any use of this API
yet.)

Author: Mark Dilger <mark.dilger@enterprisedb.com>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Discussion: https://www.postgresql.org/message-id/flat/E72EAA49-354D-4C2E-8EB9-255197F55330@enterprisedb.com

13 files changed:
contrib/bloom/blutils.c
doc/src/sgml/indexam.sgml
src/backend/access/brin/brin.c
src/backend/access/gist/gist.c
src/backend/access/hash/hash.c
src/backend/access/index/amapi.c
src/backend/access/nbtree/nbtree.c
src/backend/access/spgist/spgutils.c
src/include/access/amapi.h
src/include/access/cmptype.h
src/include/access/hash.h
src/include/access/nbtree.h
src/tools/pgindent/typedefs.list

index 3796bea786b4abe8dd37fc2274e7d072e55f2a46..04b61042a579ae53158249801f3f72dd17bcf29b 100644 (file)
@@ -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);
 }
index dc7d14b60dd24ddcd95c0b6c93d3a9464aba9394..d17fcbd5cec53b9421bb564bb73aa928d77c9584 100644 (file)
@@ -164,6 +164,10 @@ 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;
 </programlisting>
   </para>
@@ -876,6 +880,28 @@ amparallelrescan (IndexScanDesc scan);
    the beginning.
   </para>
 
+  <para>
+<programlisting>
+CompareType
+amtranslatestrategy (StrategyNumber strategy, Oid opfamily, Oid opcintype);
+
+StrategyNumber
+amtranslatecmptype (CompareType cmptype, Oid opfamily, Oid opcintype);
+</programlisting>
+   These functions, if implemented, will be called by the planer and executor
+   to convert between fixed <type>CompareType</type> 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.
+  </para>
+
  </sect1>
 
  <sect1 id="index-scanning">
index 4289142e20b6f006fbf2c1f574cf7a094d66a526..ccf824bbdb20a4c179a324154f84a0acccc8c9b3 100644 (file)
@@ -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);
 }
index b6bc75b44e3127c59b81ccf4f10951f85e904ed6..70f8086db7bd415800e206ca4346b45f73a81d32 100644 (file)
@@ -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);
 }
index df8409ab23301c39fbee248e19326d9ef0f7ab70..63b568e7f24671ff80353aabaf9157577ad3dad6 100644 (file)
@@ -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;
+}
index 3522bcaa4011de743c0233ffce0a502be6f2a173..5f53f49ec32450ae4f710c706227d7bf61eec283 100644 (file)
@@ -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.
  */
index 3d617f168f5dd2455bf55d397345b2c7315735e5..971405e89af8ffa76c672777b1afb64cfb9bfee4 100644 (file)
@@ -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;
+   }
+}
index 6e9680489178dcd9dc4a56ce80cf6d457a0546a4..367c36ef9afe3661b4e4ada001da24bd27f7e3e9 100644 (file)
@@ -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);
 }
index fb94b3d1acf29b2fca428a7209c0119fd655a73c..6723de75a4db7f1f3bb7688cc9ec6e0dfe1a9286 100644 (file)
@@ -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 */
index 2b964227d6018e3f56efca3a3f004da49d30db74..ed6da1eada12b6b75edae20e6667c8ca46e473bf 100644 (file)
@@ -30,6 +30,7 @@
  */
 typedef enum CompareType
 {
+   COMPARE_INVALID = 0,
    COMPARE_LT = 1,             /* BTLessStrategyNumber */
    COMPARE_LE = 2,             /* BTLessEqualStrategyNumber */
    COMPARE_EQ = 3,             /* BTEqualStrategyNumber */
index 0f09f35a9fdbfe4c2b5d6a952ec9d0786112d80e..e91f2b00ad92ea9715344b337ec30682814f1f29 100644 (file)
@@ -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 */
index 6a501537e1eb3f8c86d415ec20e52b5c97bac932..000c7289b80709f5724cb3622ca470e3c4b9fb4b 100644 (file)
@@ -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
  */
index a2644a2e6535ac2ae3ae8775feb56fe3fc05abd8..9a3bee93dec728148e06f8a1ee03376bc2667f74 100644 (file)
@@ -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