From 6db4598fcb82a87a683c4572707e522504830a2b Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 19 Jan 2024 15:41:44 +0100 Subject: [PATCH] Add stratnum GiST support function 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 Reviewed-by: Peter Eisentraut Reviewed-by: jian he Discussion: https://www.postgresql.org/message-id/flat/CA+renyUApHgSZF9-nd-a0+OPGharLQLO=mDHcY4_qQ0+noCUVg@mail.gmail.com --- contrib/btree_gist/Makefile | 6 +- contrib/btree_gist/btree_gist--1.7--1.8.sql | 87 ++++++++++++++++++++ contrib/btree_gist/btree_gist.c | 27 ++++++ contrib/btree_gist/btree_gist.control | 2 +- contrib/btree_gist/expected/stratnum.out | 13 +++ contrib/btree_gist/meson.build | 2 + contrib/btree_gist/sql/stratnum.sql | 3 + doc/src/sgml/gist.sgml | 65 ++++++++++++++- doc/src/sgml/xindex.sgml | 8 +- src/backend/access/gist/gistutil.c | 14 ++++ src/backend/access/gist/gistvalidate.c | 8 +- src/include/access/gist.h | 3 +- src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_amproc.dat | 18 ++++ src/include/catalog/pg_proc.dat | 6 ++ src/test/regress/expected/misc_functions.out | 13 +++ src/test/regress/sql/misc_functions.sql | 4 + 17 files changed, 273 insertions(+), 8 deletions(-) create mode 100644 contrib/btree_gist/btree_gist--1.7--1.8.sql create mode 100644 contrib/btree_gist/expected/stratnum.out create mode 100644 contrib/btree_gist/sql/stratnum.sql diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile index 073dcc745c..9ab8548bc0 100644 --- a/contrib/btree_gist/Makefile +++ b/contrib/btree_gist/Makefile @@ -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 index 0000000000..307bfe574b --- /dev/null +++ b/contrib/btree_gist/btree_gist--1.7--1.8.sql @@ -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) ; diff --git a/contrib/btree_gist/btree_gist.c b/contrib/btree_gist/btree_gist.c index 92520aedae..c4fc094c65 100644 --- a/contrib/btree_gist/btree_gist.c +++ b/contrib/btree_gist/btree_gist.c @@ -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); + } +} diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control index fa9171a80a..abf66538f3 100644 --- a/contrib/btree_gist/btree_gist.control +++ b/contrib/btree_gist/btree_gist.control @@ -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 index 0000000000..9d80c6590d --- /dev/null +++ b/contrib/btree_gist/expected/stratnum.out @@ -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) + diff --git a/contrib/btree_gist/meson.build b/contrib/btree_gist/meson.build index c88a6ac84a..a44ce905e5 100644 --- a/contrib/btree_gist/meson.build +++ b/contrib/btree_gist/meson.build @@ -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 index 0000000000..f58cdbe93d --- /dev/null +++ b/contrib/btree_gist/sql/stratnum.sql @@ -0,0 +1,3 @@ +-- test stratnum support func +SELECT gist_stratnum_btree(3::smallint); +SELECT gist_stratnum_btree(18::smallint); diff --git a/doc/src/sgml/gist.sgml b/doc/src/sgml/gist.sgml index 9ac6b03e6e..7c20f8467b 100644 --- a/doc/src/sgml/gist.sgml +++ b/doc/src/sgml/gist.sgml @@ -272,7 +272,7 @@ CREATE INDEX ON my_table USING GIST (my_inet_column inet_ops); There are five methods that an index operator class for - GiST must provide, and six that are optional. + GiST must provide, and seven that are optional. Correctness of the index is ensured by proper implementation of the same, consistent and union 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 sortsupport is used to speed up building a GiST index. + The optional twelfth method stratnum is used to + translate well-known RT*StrategyNumbers (from + src/include/access/stratnum.h) into strategy numbers + used by the operator class. @@ -1169,6 +1173,65 @@ my_sortsupport(PG_FUNCTION_ARGS) + + + stratnum + + + Given an RT*StrategyNumber value from + src/include/access/stratnum.h, returns a strategy + number used by this operator class for matching functionality. The + function should return InvalidStrategy if the + operator class has no matching strategy. + + + + The SQL declaration of the function must look like + this: + + +CREATE OR REPLACE FUNCTION my_stratnum(integer) +RETURNS integer +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT; + + + + + The matching code in the C module could then follow this skeleton: + + +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); +} + + + + + One translation function is provided by + PostgreSQL: + gist_stratnum_identity is for operator classes that + already use the RT*StrategyNumber constants. It + returns whatever is passed to it. The btree_gist + extension defines a second translation function, + gist_stratnum_btree, for operator classes that use + the BT*StrategyNumber constants. + + + diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml index 22d8ad1aac..3a19dab15e 100644 --- a/doc/src/sgml/xindex.sgml +++ b/doc/src/sgml/xindex.sgml @@ -508,7 +508,7 @@ - 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 . (For more information see .) @@ -590,6 +590,12 @@ (optional) 11 + + stratnum + translate well-known strategy numbers to ones + used by the operator class (optional) + 12 + diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index dddc08893a..d4d08bd118 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -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); +} diff --git a/src/backend/access/gist/gistvalidate.c b/src/backend/access/gist/gistvalidate.c index 7e2a715200..698e01ed2f 100644 --- a/src/backend/access/gist/gistvalidate.c +++ b/src/backend/access/gist/gistvalidate.c @@ -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; diff --git a/src/include/access/gist.h b/src/include/access/gist.h index c6dcd6a90d..e7ced18a5b 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -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. diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 460d80ac97..6496b3ffc9 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202401131 +#define CATALOG_VERSION_NO 202401191 #endif diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat index f639c3a6a5..352558c1f0 100644 --- a/src/include/catalog/pg_amproc.dat +++ b/src/include/catalog/pg_amproc.dat @@ -507,6 +507,9 @@ 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' }, @@ -526,6 +529,9 @@ { 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' }, @@ -544,6 +550,9 @@ { 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)' }, @@ -598,6 +607,9 @@ { 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' }, @@ -614,6 +626,9 @@ 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' }, @@ -632,6 +647,9 @@ { 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', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 58811a6530..a0277e57c7 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12152,4 +12152,10 @@ 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' }, + ] diff --git a/src/test/regress/expected/misc_functions.out b/src/test/regress/expected/misc_functions.out index 9302134077..7c15477104 100644 --- a/src/test/regress/expected/misc_functions.out +++ b/src/test/regress/expected/misc_functions.out @@ -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) + diff --git a/src/test/regress/sql/misc_functions.sql b/src/test/regress/sql/misc_functions.sql index d3dc591173..851dad90f4 100644 --- a/src/test/regress/sql/misc_functions.sql +++ b/src/test/regress/sql/misc_functions.sql @@ -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);