Add stratnum GiST support function
authorPeter Eisentraut <peter@eisentraut.org>
Fri, 19 Jan 2024 14:41:44 +0000 (15:41 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Fri, 19 Jan 2024 14:42:13 +0000 (15:42 +0100)
This is support function 12 for the GiST AM and translates
"well-known" RT*StrategyNumber values into whatever strategy number is
used by the opclass (since no particular numbers are actually
required).  We will use this to support temporal PRIMARY
KEY/UNIQUE/FOREIGN KEY/FOR PORTION OF functionality.

This commit adds two implementations, one for internal GiST opclasses
(just an identity function) and another for btree_gist opclasses.  It
updates btree_gist from 1.7 to 1.8, adding the support function for
all its opclasses.

Author: Paul A. Jungwirth <pj@illuminatedcomputing.com>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Reviewed-by: jian he <jian.universality@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/CA+renyUApHgSZF9-nd-a0+OPGharLQLO=mDHcY4_qQ0+noCUVg@mail.gmail.com

17 files changed:
contrib/btree_gist/Makefile
contrib/btree_gist/btree_gist--1.7--1.8.sql [new file with mode: 0644]
contrib/btree_gist/btree_gist.c
contrib/btree_gist/btree_gist.control
contrib/btree_gist/expected/stratnum.out [new file with mode: 0644]
contrib/btree_gist/meson.build
contrib/btree_gist/sql/stratnum.sql [new file with mode: 0644]
doc/src/sgml/gist.sgml
doc/src/sgml/xindex.sgml
src/backend/access/gist/gistutil.c
src/backend/access/gist/gistvalidate.c
src/include/access/gist.h
src/include/catalog/catversion.h
src/include/catalog/pg_amproc.dat
src/include/catalog/pg_proc.dat
src/test/regress/expected/misc_functions.out
src/test/regress/sql/misc_functions.sql

index 073dcc745c4d3edc4e133cde257b859f9b48b49c..9ab8548bc0ed1df0e41aac3b4f70988621b63104 100644 (file)
@@ -33,12 +33,14 @@ EXTENSION = btree_gist
 DATA = btree_gist--1.0--1.1.sql \
        btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
        btree_gist--1.3--1.4.sql btree_gist--1.4--1.5.sql \
-       btree_gist--1.5--1.6.sql btree_gist--1.6--1.7.sql
+       btree_gist--1.5--1.6.sql btree_gist--1.6--1.7.sql \
+       btree_gist--1.7--1.8.sql
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
         time timetz date interval macaddr macaddr8 inet cidr text varchar char \
-        bytea bit varbit numeric uuid not_equal enum bool partitions
+        bytea bit varbit numeric uuid not_equal enum bool partitions \
+        stratnum
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
diff --git a/contrib/btree_gist/btree_gist--1.7--1.8.sql b/contrib/btree_gist/btree_gist--1.7--1.8.sql
new file mode 100644 (file)
index 0000000..307bfe5
--- /dev/null
@@ -0,0 +1,87 @@
+/* contrib/btree_gist/btree_gist--1.7--1.8.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.8'" to load this file. \quit
+
+CREATE FUNCTION gist_stratnum_btree(smallint)
+RETURNS smallint
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE PARALLEL SAFE STRICT;
+
+ALTER OPERATOR FAMILY gist_oid_ops USING gist ADD
+   FUNCTION 12 (oid, oid) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_int2_ops USING gist ADD
+   FUNCTION 12 (int2, int2) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_int4_ops USING gist ADD
+   FUNCTION 12 (int4, int4) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_int8_ops USING gist ADD
+   FUNCTION 12 (int8, int8) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_float4_ops USING gist ADD
+   FUNCTION 12 (float4, float4) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_float8_ops USING gist ADD
+   FUNCTION 12 (float8, float8) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_timestamp_ops USING gist ADD
+   FUNCTION 12 (timestamp, timestamp) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_timestamptz_ops USING gist ADD
+   FUNCTION 12 (timestamptz, timestamptz) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_time_ops USING gist ADD
+   FUNCTION 12 (time, time) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_date_ops USING gist ADD
+   FUNCTION 12 (date, date) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_interval_ops USING gist ADD
+   FUNCTION 12 (interval, interval) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_cash_ops USING gist ADD
+   FUNCTION 12 (money, money) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_macaddr_ops USING gist ADD
+   FUNCTION 12 (macaddr, macaddr) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_text_ops USING gist ADD
+   FUNCTION 12 (text, text) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_bpchar_ops USING gist ADD
+   FUNCTION 12 (bpchar, bpchar) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_bytea_ops USING gist ADD
+   FUNCTION 12 (bytea, bytea) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_numeric_ops USING gist ADD
+   FUNCTION 12 (numeric, numeric) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_bit_ops USING gist ADD
+   FUNCTION 12 (bit, bit) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_vbit_ops USING gist ADD
+   FUNCTION 12 (varbit, varbit) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_inet_ops USING gist ADD
+   FUNCTION 12 (inet, inet) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_cidr_ops USING gist ADD
+   FUNCTION 12 (cidr, cidr) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_timetz_ops USING gist ADD
+   FUNCTION 12 (timetz, timetz) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_uuid_ops USING gist ADD
+   FUNCTION 12 (uuid, uuid) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_macaddr8_ops USING gist ADD
+   FUNCTION 12 (macaddr8, macaddr8) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_enum_ops USING gist ADD
+   FUNCTION 12 (anyenum, anyenum) gist_stratnum_btree (int2) ;
+
+ALTER OPERATOR FAMILY gist_bool_ops USING gist ADD
+   FUNCTION 12 (bool, bool) gist_stratnum_btree (int2) ;
index 92520aedae1c07f0eb2fd3e051c826ae2fce3dfb..c4fc094c65285f6dba44257572d4436282a05c59 100644 (file)
@@ -3,6 +3,7 @@
  */
 #include "postgres.h"
 
+#include "access/stratnum.h"
 #include "utils/builtins.h"
 
 PG_MODULE_MAGIC;
@@ -10,6 +11,7 @@ PG_MODULE_MAGIC;
 PG_FUNCTION_INFO_V1(gbt_decompress);
 PG_FUNCTION_INFO_V1(gbtreekey_in);
 PG_FUNCTION_INFO_V1(gbtreekey_out);
+PG_FUNCTION_INFO_V1(gist_stratnum_btree);
 
 /**************************************************
  * In/Out for keys
@@ -51,3 +53,28 @@ gbt_decompress(PG_FUNCTION_ARGS)
 {
    PG_RETURN_POINTER(PG_GETARG_POINTER(0));
 }
+
+/*
+ * Returns the btree number for equals, otherwise invalid.
+ */
+Datum
+gist_stratnum_btree(PG_FUNCTION_ARGS)
+{
+   StrategyNumber strat = PG_GETARG_UINT16(0);
+
+   switch (strat)
+   {
+       case RTEqualStrategyNumber:
+           PG_RETURN_UINT16(BTEqualStrategyNumber);
+       case RTLessStrategyNumber:
+           PG_RETURN_UINT16(BTLessStrategyNumber);
+       case RTLessEqualStrategyNumber:
+           PG_RETURN_UINT16(BTLessEqualStrategyNumber);
+       case RTGreaterStrategyNumber:
+           PG_RETURN_UINT16(BTGreaterStrategyNumber);
+       case RTGreaterEqualStrategyNumber:
+           PG_RETURN_UINT16(BTGreaterEqualStrategyNumber);
+       default:
+           PG_RETURN_UINT16(InvalidStrategy);
+   }
+}
index fa9171a80a2e374866d2b927269c81ab9e1ca3fc..abf66538f32443b23e1f2a28bc9541f9d27e4883 100644 (file)
@@ -1,6 +1,6 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.7'
+default_version = '1.8'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
 trusted = true
diff --git a/contrib/btree_gist/expected/stratnum.out b/contrib/btree_gist/expected/stratnum.out
new file mode 100644 (file)
index 0000000..9d80c65
--- /dev/null
@@ -0,0 +1,13 @@
+-- test stratnum support func
+SELECT gist_stratnum_btree(3::smallint);
+ gist_stratnum_btree 
+---------------------
+                   0
+(1 row)
+
+SELECT gist_stratnum_btree(18::smallint);
+ gist_stratnum_btree 
+---------------------
+                   3
+(1 row)
+
index c88a6ac84aeffe99a9ce99e0ccaa06ce592b0578..a44ce905e5943187868a6668f578a017e346886a 100644 (file)
@@ -50,6 +50,7 @@ install_data(
   'btree_gist--1.4--1.5.sql',
   'btree_gist--1.5--1.6.sql',
   'btree_gist--1.6--1.7.sql',
+  'btree_gist--1.7--1.8.sql',
   kwargs: contrib_data_args,
 )
 
@@ -89,6 +90,7 @@ tests += {
       'enum',
       'bool',
       'partitions',
+      'stratnum',
     ],
   },
 }
diff --git a/contrib/btree_gist/sql/stratnum.sql b/contrib/btree_gist/sql/stratnum.sql
new file mode 100644 (file)
index 0000000..f58cdbe
--- /dev/null
@@ -0,0 +1,3 @@
+-- test stratnum support func
+SELECT gist_stratnum_btree(3::smallint);
+SELECT gist_stratnum_btree(18::smallint);
index 9ac6b03e6e4524006862b6ab27b3cac6b345a50d..7c20f8467b484516c7cce5c753c3953d1819bc63 100644 (file)
@@ -272,7 +272,7 @@ CREATE INDEX ON my_table USING GIST (my_inet_column inet_ops);
 
  <para>
    There are five methods that an index operator class for
-   <acronym>GiST</acronym> must provide, and six that are optional.
+   <acronym>GiST</acronym> must provide, and seven that are optional.
    Correctness of the index is ensured
    by proper implementation of the <function>same</function>, <function>consistent</function>
    and <function>union</function> methods, while efficiency (size and speed) of the
@@ -295,6 +295,10 @@ CREATE INDEX ON my_table USING GIST (my_inet_column inet_ops);
    user-specified parameters.
    The optional eleventh method <function>sortsupport</function> is used to
    speed up building a <acronym>GiST</acronym> index.
+   The optional twelfth method <function>stratnum</function> is used to
+   translate well-known <literal>RT*StrategyNumber</literal>s (from
+   <filename>src/include/access/stratnum.h</filename>) into strategy numbers
+   used by the operator class.
  </para>
 
  <variablelist>
@@ -1169,6 +1173,65 @@ my_sortsupport(PG_FUNCTION_ARGS)
       </para>
      </listitem>
     </varlistentry>
+
+    <varlistentry>
+     <term><function>stratnum</function></term>
+     <listitem>
+      <para>
+       Given an <literal>RT*StrategyNumber</literal> value from
+       <filename>src/include/access/stratnum.h</filename>, returns a strategy
+       number used by this operator class for matching functionality.  The
+       function should return <literal>InvalidStrategy</literal> if the
+       operator class has no matching strategy.
+      </para>
+
+      <para>
+       The <acronym>SQL</acronym> declaration of the function must look like
+       this:
+
+<programlisting>
+CREATE OR REPLACE FUNCTION my_stratnum(integer)
+RETURNS integer
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+</programlisting>
+      </para>
+
+       <para>
+        The matching code in the C module could then follow this skeleton:
+
+<programlisting>
+PG_FUNCTION_INFO_V1(my_stratnum);
+
+Datum
+my_stratnum(PG_FUNCTION_ARGS)
+{
+    StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(1);
+    StrategyNumber ret = InvalidStrategy;
+
+    switch (strategy)
+    {
+        case RTEqualStrategyNumber:
+            ret = BTEqualStrategyNumber;
+    }
+
+    PG_RETURN_UINT16(ret);
+}
+</programlisting>
+      </para>
+
+      <para>
+       One translation function is provided by
+       <productname>PostgreSQL</productname>:
+       <literal>gist_stratnum_identity</literal> is for operator classes that
+       already use the <literal>RT*StrategyNumber</literal> constants.  It
+       returns whatever is passed to it.  The <literal>btree_gist</literal>
+       extension defines a second translation function,
+       <literal>gist_stratnum_btree</literal>, for operator classes that use
+       the <literal>BT*StrategyNumber</literal> constants.
+      </para>
+     </listitem>
+    </varlistentry>
   </variablelist>
 
   <para>
index 22d8ad1aac43b38a119780da45de0159af6c6062..3a19dab15e031d865ab71de45bf0705a1d45a4fa 100644 (file)
    </table>
 
   <para>
-   GiST indexes have eleven support functions, six of which are optional,
+   GiST indexes have twelve support functions, seven of which are optional,
    as shown in <xref linkend="xindex-gist-support-table"/>.
    (For more information see <xref linkend="gist"/>.)
   </para>
         (optional)</entry>
        <entry>11</entry>
       </row>
+      <row>
+       <entry><function>stratnum</function></entry>
+       <entry>translate well-known strategy numbers to ones
+        used by the operator class (optional)</entry>
+       <entry>12</entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
index dddc08893a18167abf15834b1f796781da5710d1..d4d08bd118ff86aa869f5a51fe516ba4e9fe9fa4 100644 (file)
@@ -23,6 +23,7 @@
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 #include "utils/float.h"
+#include "utils/fmgrprotos.h"
 #include "utils/lsyscache.h"
 #include "utils/snapmgr.h"
 #include "utils/syscache.h"
@@ -1056,3 +1057,16 @@ gistGetFakeLSN(Relation rel)
        return GetFakeLSNForUnloggedRel();
    }
 }
+
+/*
+ * Returns the same number that was received.
+ *
+ * This is for GiST opclasses that use the RT*StrategyNumber constants.
+ */
+Datum
+gist_stratnum_identity(PG_FUNCTION_ARGS)
+{
+   StrategyNumber strat = PG_GETARG_UINT16(0);
+
+   PG_RETURN_UINT16(strat);
+}
index 7e2a715200aae59e737dae8fc67513159ed25ff9..698e01ed2f7ed48cd664905ef924e254a2884a3f 100644 (file)
@@ -147,6 +147,10 @@ gistvalidate(Oid opclassoid)
                ok = check_amproc_signature(procform->amproc, VOIDOID, true,
                                            1, 1, INTERNALOID);
                break;
+           case GIST_STRATNUM_PROC:
+               ok = check_amproc_signature(procform->amproc, INT2OID, true,
+                                           1, 1, INT2OID);
+               break;
            default:
                ereport(INFO,
                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
@@ -267,7 +271,8 @@ gistvalidate(Oid opclassoid)
            continue;           /* got it */
        if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC ||
            i == GIST_COMPRESS_PROC || i == GIST_DECOMPRESS_PROC ||
-           i == GIST_OPTIONS_PROC || i == GIST_SORTSUPPORT_PROC)
+           i == GIST_OPTIONS_PROC || i == GIST_SORTSUPPORT_PROC ||
+           i == GIST_STRATNUM_PROC)
            continue;           /* optional methods */
        ereport(INFO,
                (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
@@ -339,6 +344,7 @@ gistadjustmembers(Oid opfamilyoid,
            case GIST_FETCH_PROC:
            case GIST_OPTIONS_PROC:
            case GIST_SORTSUPPORT_PROC:
+           case GIST_STRATNUM_PROC:
                /* Optional, so force it to be a soft family dependency */
                op->ref_is_hard = false;
                op->ref_is_family = true;
index c6dcd6a90ddbc3b1ab2c97a191a53da4b5d49f9e..e7ced18a5ba5fadd96174ea08fd094d36a99efc7 100644 (file)
@@ -38,7 +38,8 @@
 #define GIST_FETCH_PROC                    9
 #define GIST_OPTIONS_PROC              10
 #define GIST_SORTSUPPORT_PROC          11
-#define GISTNProcs                 11
+#define GIST_STRATNUM_PROC             12
+#define GISTNProcs                 12
 
 /*
  * Page opaque data in a GiST index page.
index 460d80ac97e8b737b1d612aa7403b2aaf7cb2114..6496b3ffc9f597493d7449a015ff572b64511451 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202401131
+#define CATALOG_VERSION_NO 202401191
 
 #endif
index f639c3a6a518047900139c193c76b02831ce4d19..352558c1f06189fc1848eb21f36254ad8629a9d9 100644 (file)
   amprocrighttype => 'box', amprocnum => '7', amproc => 'gist_box_same' },
 { amprocfamily => 'gist/box_ops', amproclefttype => 'box',
   amprocrighttype => 'box', amprocnum => '8', amproc => 'gist_box_distance' },
+{ amprocfamily => 'gist/box_ops', amproclefttype => 'box',
+  amprocrighttype => 'box', amprocnum => '12',
+  amproc => 'gist_stratnum_identity' },
 { amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon',
   amprocrighttype => 'polygon', amprocnum => '1',
   amproc => 'gist_poly_consistent' },
 { amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon',
   amprocrighttype => 'polygon', amprocnum => '8',
   amproc => 'gist_poly_distance' },
+{ amprocfamily => 'gist/poly_ops', amproclefttype => 'polygon',
+  amprocrighttype => 'polygon', amprocnum => '12',
+  amproc => 'gist_stratnum_identity' },
 { amprocfamily => 'gist/circle_ops', amproclefttype => 'circle',
   amprocrighttype => 'circle', amprocnum => '1',
   amproc => 'gist_circle_consistent' },
 { amprocfamily => 'gist/circle_ops', amproclefttype => 'circle',
   amprocrighttype => 'circle', amprocnum => '8',
   amproc => 'gist_circle_distance' },
+{ amprocfamily => 'gist/circle_ops', amproclefttype => 'circle',
+  amprocrighttype => 'circle', amprocnum => '12',
+  amproc => 'gist_stratnum_identity' },
 { amprocfamily => 'gist/tsvector_ops', amproclefttype => 'tsvector',
   amprocrighttype => 'tsvector', amprocnum => '1',
   amproc => 'gtsvector_consistent(internal,tsvector,int2,oid,internal)' },
 { amprocfamily => 'gist/range_ops', amproclefttype => 'anyrange',
   amprocrighttype => 'anyrange', amprocnum => '7',
   amproc => 'range_gist_same' },
+{ amprocfamily => 'gist/range_ops', amproclefttype => 'anyrange',
+  amprocrighttype => 'anyrange', amprocnum => '12',
+  amproc => 'gist_stratnum_identity' },
 { amprocfamily => 'gist/network_ops', amproclefttype => 'inet',
   amprocrighttype => 'inet', amprocnum => '1',
   amproc => 'inet_gist_consistent' },
   amprocrighttype => 'inet', amprocnum => '7', amproc => 'inet_gist_same' },
 { amprocfamily => 'gist/network_ops', amproclefttype => 'inet',
   amprocrighttype => 'inet', amprocnum => '9', amproc => 'inet_gist_fetch' },
+{ amprocfamily => 'gist/network_ops', amproclefttype => 'inet',
+  amprocrighttype => 'inet', amprocnum => '12',
+  amproc => 'gist_stratnum_identity' },
 { amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange',
   amprocrighttype => 'anymultirange', amprocnum => '1',
   amproc => 'multirange_gist_consistent' },
 { amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange',
   amprocrighttype => 'anymultirange', amprocnum => '7',
   amproc => 'range_gist_same' },
+{ amprocfamily => 'gist/multirange_ops', amproclefttype => 'anymultirange',
+  amprocrighttype => 'anymultirange', amprocnum => '12',
+  amproc => 'gist_stratnum_identity' },
 
 # gin
 { amprocfamily => 'gin/array_ops', amproclefttype => 'anyarray',
index 58811a6530bd272cb64513d74e0394a863271cf2..a0277e57c7d68d3ac7b3755c5c1c01afb98b576e 100644 (file)
   proargnames => '{summarized_tli,summarized_lsn,pending_lsn,summarizer_pid}',
   prosrc => 'pg_get_wal_summarizer_state' },
 
+# GiST stratnum implementations
+{ oid => '8047', descr => 'GiST support',
+  proname => 'gist_stratnum_identity', prorettype => 'int2',
+  proargtypes => 'int2',
+  prosrc => 'gist_stratnum_identity' },
+
 ]
index 930213407733e11acd89b34f60cfa1a95e8c7e62..7c15477104baca912f191815744b5e24325f4119 100644 (file)
@@ -670,3 +670,16 @@ FROM pg_walfile_name_offset('0/0'::pg_lsn + :segment_size - 1),
               0 | t
 (1 row)
 
+-- test stratnum support functions
+SELECT gist_stratnum_identity(3::smallint);
+ gist_stratnum_identity 
+------------------------
+                      3
+(1 row)
+
+SELECT gist_stratnum_identity(18::smallint);
+ gist_stratnum_identity 
+------------------------
+                     18
+(1 row)
+
index d3dc591173d29f6f9b5558ed0f8ce89829a4244c..851dad90f443bffb1453a11f1f696647c625de95 100644 (file)
@@ -250,3 +250,7 @@ FROM pg_walfile_name_offset('0/0'::pg_lsn + :segment_size + 1),
 SELECT segment_number, file_offset = :segment_size - 1
 FROM pg_walfile_name_offset('0/0'::pg_lsn + :segment_size - 1),
      pg_split_walfile_name(file_name);
+
+-- test stratnum support functions
+SELECT gist_stratnum_identity(3::smallint);
+SELECT gist_stratnum_identity(18::smallint);