From 7406ab623fee1addcb21c881afecbe638a0d56e9 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Tue, 17 Sep 2024 10:19:26 +0200 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. (previously committed as 6db4598fcb8, reverted by 8aee330af55; this is essentially unchanged from those) 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 073dcc745c4..9ab8548bc0e 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 00000000000..307bfe574b0 --- /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 92520aedae1..5fd4cce27d0 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 supported operators, 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 fa9171a80a2..abf66538f32 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 00000000000..9d80c6590d9 --- /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 c88a6ac84ae..a44ce905e59 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 00000000000..f58cdbe93da --- /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 39c7bf370d6..f789824c83b 100644 --- a/doc/src/sgml/gist.sgml +++ b/doc/src/sgml/gist.sgml @@ -266,7 +266,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 @@ -289,6 +289,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. @@ -1163,6 +1167,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 22d8ad1aac4..3a19dab15e0 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 78e98d68b15..8686735f234 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -21,6 +21,7 @@ #include "common/pg_prng.h" #include "storage/indexfsm.h" #include "utils/float.h" +#include "utils/fmgrprotos.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/snapmgr.h" @@ -1055,3 +1056,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 36b5a85cf31..0901543a60a 100644 --- a/src/backend/access/gist/gistvalidate.c +++ b/src/backend/access/gist/gistvalidate.c @@ -146,6 +146,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), @@ -266,7 +270,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), @@ -338,6 +343,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 c6dcd6a90dd..e7ced18a5ba 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 92ed2f927e0..d46a9efe908 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202409122 +#define CATALOG_VERSION_NO 202409171 #endif diff --git a/src/include/catalog/pg_amproc.dat b/src/include/catalog/pg_amproc.dat index 1d97e12a050..5d7fe292bf6 100644 --- a/src/include/catalog/pg_amproc.dat +++ b/src/include/catalog/pg_amproc.dat @@ -506,6 +506,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' }, @@ -525,6 +528,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' }, @@ -543,6 +549,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)' }, @@ -597,6 +606,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' }, @@ -613,6 +625,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' }, @@ -631,6 +646,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 53a081ed886..2513c36fcbf 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -12310,4 +12310,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 35fb72f302b..5f7bf6b8af6 100644 --- a/src/test/regress/expected/misc_functions.out +++ b/src/test/regress/expected/misc_functions.out @@ -819,3 +819,16 @@ SELECT pg_column_toast_chunk_id(a) IS NULL, DROP TABLE test_chunk_id; DROP FUNCTION explain_mask_costs(text, bool, bool, bool, bool); +-- 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 e570783453c..1e90d60af35 100644 --- a/src/test/regress/sql/misc_functions.sql +++ b/src/test/regress/sql/misc_functions.sql @@ -360,3 +360,7 @@ SELECT pg_column_toast_chunk_id(a) IS NULL, FROM test_chunk_id; DROP TABLE test_chunk_id; DROP FUNCTION explain_mask_costs(text, bool, bool, bool, bool); + +-- test stratnum support functions +SELECT gist_stratnum_identity(3::smallint); +SELECT gist_stratnum_identity(18::smallint);