diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 2fc63442980..332193565e2 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -6676,6 +6676,60 @@ SCRAM-SHA-256$<iteration count>:&l + + + rngconstruct2 regproc + (references pg_proc.oid) + + + OID of the 2-argument range constructor function (lower and upper) + + + + + + rngconstruct3 regproc + (references pg_proc.oid) + + + OID of the 3-argument range constructor function (lower, upper, and + flags) + + + + + + rngmltconstruct0 regproc + (references pg_proc.oid) + + + OID of the 0-argument multirange constructor function (constructs empty + range) + + + + + + rngmltconstruct1 regproc + (references pg_proc.oid) + + + OID of the 1-argument multirange constructor function (constructs + multirange from single range, also used as cast function) + + + + + + rngmltconstruct2 regproc + (references pg_proc.oid) + + + OID of the 2-argument multirange constructor function (constructs + multirange from array of ranges) + + + rngcanonical regproc diff --git a/src/backend/catalog/pg_range.c b/src/backend/catalog/pg_range.c index cd21c84c8fd..cb8c79d0e83 100644 --- a/src/backend/catalog/pg_range.c +++ b/src/backend/catalog/pg_range.c @@ -35,7 +35,9 @@ void RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, Oid rangeSubOpclass, RegProcedure rangeCanonical, - RegProcedure rangeSubDiff, Oid multirangeTypeOid) + RegProcedure rangeSubDiff, Oid multirangeTypeOid, + RegProcedure rangeConstruct2, RegProcedure rangeConstruct3, + RegProcedure mltrngConstruct0, RegProcedure mltrngConstruct1, RegProcedure mltrngConstruct2) { Relation pg_range; Datum values[Natts_pg_range]; @@ -57,6 +59,11 @@ RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, values[Anum_pg_range_rngcanonical - 1] = ObjectIdGetDatum(rangeCanonical); values[Anum_pg_range_rngsubdiff - 1] = ObjectIdGetDatum(rangeSubDiff); values[Anum_pg_range_rngmultitypid - 1] = ObjectIdGetDatum(multirangeTypeOid); + values[Anum_pg_range_rngconstruct2 - 1] = ObjectIdGetDatum(rangeConstruct2); + values[Anum_pg_range_rngconstruct3 - 1] = ObjectIdGetDatum(rangeConstruct3); + values[Anum_pg_range_rngmltconstruct0 - 1] = ObjectIdGetDatum(mltrngConstruct0); + values[Anum_pg_range_rngmltconstruct1 - 1] = ObjectIdGetDatum(mltrngConstruct1); + values[Anum_pg_range_rngmltconstruct2 - 1] = ObjectIdGetDatum(mltrngConstruct2); tup = heap_form_tuple(RelationGetDescr(pg_range), values, nulls); diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index e5fa0578889..288edb25f2f 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -111,10 +111,12 @@ Oid binary_upgrade_next_mrng_pg_type_oid = InvalidOid; Oid binary_upgrade_next_mrng_array_pg_type_oid = InvalidOid; static void makeRangeConstructors(const char *name, Oid namespace, - Oid rangeOid, Oid subtype); + Oid rangeOid, Oid subtype, + Oid *rangeConstruct2_p, Oid *rangeConstruct3_p); static void makeMultirangeConstructors(const char *name, Oid namespace, Oid multirangeOid, Oid rangeOid, - Oid rangeArrayOid, Oid *castFuncOid); + Oid rangeArrayOid, + Oid *mltrngConstruct0_p, Oid *mltrngConstruct1_p, Oid *mltrngConstruct2_p); static Oid findTypeInputFunction(List *procname, Oid typeOid); static Oid findTypeOutputFunction(List *procname, Oid typeOid); static Oid findTypeReceiveFunction(List *procname, Oid typeOid); @@ -1406,6 +1408,11 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt) ListCell *lc; ObjectAddress address; ObjectAddress mltrngaddress PG_USED_FOR_ASSERTS_ONLY; + Oid rangeConstruct2Oid = InvalidOid; + Oid rangeConstruct3Oid = InvalidOid; + Oid mltrngConstruct0Oid = InvalidOid; + Oid mltrngConstruct1Oid = InvalidOid; + Oid mltrngConstruct2Oid = InvalidOid; Oid castFuncOid; /* Convert list of names to a name and namespace */ @@ -1661,10 +1668,6 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt) InvalidOid); /* type's collation (ranges never have one) */ Assert(multirangeOid == mltrngaddress.objectId); - /* Create the entry in pg_range */ - RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass, - rangeCanonical, rangeSubtypeDiff, multirangeOid); - /* * Create the array type that goes with it. */ @@ -1746,10 +1749,18 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt) CommandCounterIncrement(); /* And create the constructor functions for this range type */ - makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype); + makeRangeConstructors(typeName, typeNamespace, typoid, rangeSubtype, + &rangeConstruct2Oid, &rangeConstruct3Oid); makeMultirangeConstructors(multirangeTypeName, typeNamespace, multirangeOid, typoid, rangeArrayOid, - &castFuncOid); + &mltrngConstruct0Oid, &mltrngConstruct1Oid, &mltrngConstruct2Oid); + castFuncOid = mltrngConstruct1Oid; + + /* Create the entry in pg_range */ + RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass, + rangeCanonical, rangeSubtypeDiff, multirangeOid, + rangeConstruct2Oid, rangeConstruct3Oid, + mltrngConstruct0Oid, mltrngConstruct1Oid, mltrngConstruct2Oid); /* Create cast from the range type to its multirange type */ CastCreate(typoid, multirangeOid, castFuncOid, InvalidOid, InvalidOid, @@ -1769,10 +1780,14 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt) * * We actually define 2 functions, with 2 through 3 arguments. This is just * to offer more convenience for the user. + * + * The OIDs of the created functions are returned through the pointer + * arguments. */ static void makeRangeConstructors(const char *name, Oid namespace, - Oid rangeOid, Oid subtype) + Oid rangeOid, Oid subtype, + Oid *rangeConstruct2_p, Oid *rangeConstruct3_p) { static const char *const prosrc[2] = {"range_constructor2", "range_constructor3"}; @@ -1833,6 +1848,11 @@ makeRangeConstructors(const char *name, Oid namespace, * pg_dump depends on this choice to avoid dumping the constructors. */ recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); + + if (pronargs[i] == 2) + *rangeConstruct2_p = myself.objectId; + else if (pronargs[i] == 3) + *rangeConstruct3_p = myself.objectId; } } @@ -1842,13 +1862,13 @@ makeRangeConstructors(const char *name, Oid namespace, * If we had an anyrangearray polymorphic type we could use it here, * but since each type has its own constructor name there's no need. * - * Sets castFuncOid to the oid of the new constructor that can be used - * to cast from a range to a multirange. + * The OIDs of the created functions are returned through the pointer + * arguments. */ static void makeMultirangeConstructors(const char *name, Oid namespace, Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid, - Oid *castFuncOid) + Oid *mltrngConstruct0_p, Oid *mltrngConstruct1_p, Oid *mltrngConstruct2_p) { ObjectAddress myself, referenced; @@ -1899,6 +1919,7 @@ makeMultirangeConstructors(const char *name, Oid namespace, * depends on this choice to avoid dumping the constructors. */ recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); + *mltrngConstruct0_p = myself.objectId; pfree(argtypes); /* @@ -1939,8 +1960,8 @@ makeMultirangeConstructors(const char *name, Oid namespace, 0.0); /* prorows */ /* ditto */ recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); + *mltrngConstruct1_p = myself.objectId; pfree(argtypes); - *castFuncOid = myself.objectId; /* n-arg constructor - vararg */ argtypes = buildoidvector(&rangeArrayOid, 1); @@ -1978,6 +1999,7 @@ makeMultirangeConstructors(const char *name, Oid namespace, 0.0); /* prorows */ /* ditto */ recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL); + *mltrngConstruct2_p = myself.objectId; pfree(argtypes); pfree(allParameterTypes); pfree(parameterModes); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 13ac6be613e..79db8731621 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202601161 +#define CATALOG_VERSION_NO 202601221 #endif diff --git a/src/include/catalog/pg_range.dat b/src/include/catalog/pg_range.dat index 830971c4944..fa5e6ff0c3e 100644 --- a/src/include/catalog/pg_range.dat +++ b/src/include/catalog/pg_range.dat @@ -14,21 +14,33 @@ { rngtypid => 'int4range', rngsubtype => 'int4', rngmultitypid => 'int4multirange', rngsubopc => 'btree/int4_ops', + rngconstruct2 => 'int4range(int4,int4)', rngconstruct3 => 'int4range(int4,int4,text)', + rngmltconstruct0 => 'int4multirange()', rngmltconstruct1 => 'int4multirange(int4range)', rngmltconstruct2 => 'int4multirange(_int4range)', rngcanonical => 'int4range_canonical', rngsubdiff => 'int4range_subdiff' }, { rngtypid => 'numrange', rngsubtype => 'numeric', rngmultitypid => 'nummultirange', rngsubopc => 'btree/numeric_ops', + rngconstruct2 => 'numrange(numeric,numeric)', rngconstruct3 => 'numrange(numeric,numeric,text)', + rngmltconstruct0 => 'nummultirange()', rngmltconstruct1 => 'nummultirange(numrange)', rngmltconstruct2 => 'nummultirange(_numrange)', rngcanonical => '-', rngsubdiff => 'numrange_subdiff' }, { rngtypid => 'tsrange', rngsubtype => 'timestamp', rngmultitypid => 'tsmultirange', rngsubopc => 'btree/timestamp_ops', + rngconstruct2 => 'tsrange(timestamp,timestamp)', rngconstruct3 => 'tsrange(timestamp,timestamp,text)', + rngmltconstruct0 => 'tsmultirange()', rngmltconstruct1 => 'tsmultirange(tsrange)', rngmltconstruct2 => 'tsmultirange(_tsrange)', rngcanonical => '-', rngsubdiff => 'tsrange_subdiff' }, { rngtypid => 'tstzrange', rngsubtype => 'timestamptz', rngmultitypid => 'tstzmultirange', rngsubopc => 'btree/timestamptz_ops', + rngconstruct2 => 'tstzrange(timestamptz,timestamptz)', rngconstruct3 => 'tstzrange(timestamptz,timestamptz,text)', + rngmltconstruct0 => 'tstzmultirange()', rngmltconstruct1 => 'tstzmultirange(tstzrange)', rngmltconstruct2 => 'tstzmultirange(_tstzrange)', rngcanonical => '-', rngsubdiff => 'tstzrange_subdiff' }, { rngtypid => 'daterange', rngsubtype => 'date', rngmultitypid => 'datemultirange', rngsubopc => 'btree/date_ops', + rngconstruct2 => 'daterange(date,date)', rngconstruct3 => 'daterange(date,date,text)', + rngmltconstruct0 => 'datemultirange()', rngmltconstruct1 => 'datemultirange(daterange)', rngmltconstruct2 => 'datemultirange(_daterange)', rngcanonical => 'daterange_canonical', rngsubdiff => 'daterange_subdiff' }, { rngtypid => 'int8range', rngsubtype => 'int8', rngmultitypid => 'int8multirange', rngsubopc => 'btree/int8_ops', + rngconstruct2 => 'int8range(int8,int8)', rngconstruct3 => 'int8range(int8,int8,text)', + rngmltconstruct0 => 'int8multirange()', rngmltconstruct1 => 'int8multirange(int8range)', rngmltconstruct2 => 'int8multirange(_int8range)', rngcanonical => 'int8range_canonical', rngsubdiff => 'int8range_subdiff' }, ] diff --git a/src/include/catalog/pg_range.h b/src/include/catalog/pg_range.h index 5b4f4615905..32ee8cf43a0 100644 --- a/src/include/catalog/pg_range.h +++ b/src/include/catalog/pg_range.h @@ -43,6 +43,15 @@ CATALOG(pg_range,3541,RangeRelationId) /* subtype's btree opclass */ Oid rngsubopc BKI_LOOKUP(pg_opclass); + /* range constructor functions */ + regproc rngconstruct2 BKI_LOOKUP(pg_proc); + regproc rngconstruct3 BKI_LOOKUP(pg_proc); + + /* multirange constructor functions */ + regproc rngmltconstruct0 BKI_LOOKUP(pg_proc); + regproc rngmltconstruct1 BKI_LOOKUP(pg_proc); + regproc rngmltconstruct2 BKI_LOOKUP(pg_proc); + /* canonicalize range, or 0 */ regproc rngcanonical BKI_LOOKUP_OPT(pg_proc); @@ -69,7 +78,9 @@ MAKE_SYSCACHE(RANGEMULTIRANGE, pg_range_rngmultitypid_index, 4); extern void RangeCreate(Oid rangeTypeOid, Oid rangeSubType, Oid rangeCollation, Oid rangeSubOpclass, RegProcedure rangeCanonical, - RegProcedure rangeSubDiff, Oid multirangeTypeOid); + RegProcedure rangeSubDiff, Oid multirangeTypeOid, + RegProcedure rangeConstruct2, RegProcedure rangeConstruct3, + RegProcedure mltrngConstruct0, RegProcedure mltrngConstruct1, RegProcedure mltrngConstruct2); extern void RangeDelete(Oid rangeTypeOid); #endif /* PG_RANGE_H */ diff --git a/src/test/regress/expected/oidjoins.out b/src/test/regress/expected/oidjoins.out index 215eb899be3..25aaae8d05a 100644 --- a/src/test/regress/expected/oidjoins.out +++ b/src/test/regress/expected/oidjoins.out @@ -249,6 +249,11 @@ NOTICE: checking pg_range {rngsubtype} => pg_type {oid} NOTICE: checking pg_range {rngmultitypid} => pg_type {oid} NOTICE: checking pg_range {rngcollation} => pg_collation {oid} NOTICE: checking pg_range {rngsubopc} => pg_opclass {oid} +NOTICE: checking pg_range {rngconstruct2} => pg_proc {oid} +NOTICE: checking pg_range {rngconstruct3} => pg_proc {oid} +NOTICE: checking pg_range {rngmltconstruct0} => pg_proc {oid} +NOTICE: checking pg_range {rngmltconstruct1} => pg_proc {oid} +NOTICE: checking pg_range {rngmltconstruct2} => pg_proc {oid} NOTICE: checking pg_range {rngcanonical} => pg_proc {oid} NOTICE: checking pg_range {rngsubdiff} => pg_proc {oid} NOTICE: checking pg_transform {trftype} => pg_type {oid} diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index 9ddcacec6bf..1d21d3eb446 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -610,7 +610,9 @@ WHERE (is_catalog_text_unique_index_oid(indexrelid) <> -- Look for illegal values in pg_range fields. SELECT r.rngtypid, r.rngsubtype FROM pg_range as r -WHERE r.rngtypid = 0 OR r.rngsubtype = 0 OR r.rngsubopc = 0; +WHERE r.rngtypid = 0 OR r.rngsubtype = 0 OR r.rngsubopc = 0 + OR r.rngconstruct2 = 0 OR r.rngconstruct3 = 0 + OR r.rngmltconstruct0 = 0 OR r.rngmltconstruct1 = 0 OR r.rngmltconstruct2 = 0; rngtypid | rngsubtype ----------+------------ (0 rows) @@ -663,6 +665,61 @@ WHERE r.rngmultitypid IS NULL OR r.rngmultitypid = 0; ----------+------------+--------------- (0 rows) +-- check constructor function arguments and return types +-- +-- proname and prosrc are not required to have these particular +-- values, but this matches what DefineRange() produces and serves to +-- sanity-check the catalog entries for built-in types. +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngconstruct2 JOIN pg_type t ON r.rngtypid = t.oid +WHERE p.pronargs != 2 + OR p.proargtypes[0] != r.rngsubtype OR p.proargtypes[1] != r.rngsubtype + OR p.prorettype != r.rngtypid + OR p.proname != t.typname OR p.prosrc != 'range_constructor2'; + rngtypid | rngsubtype | proname +----------+------------+--------- +(0 rows) + +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngconstruct3 JOIN pg_type t ON r.rngtypid = t.oid +WHERE p.pronargs != 3 + OR p.proargtypes[0] != r.rngsubtype OR p.proargtypes[1] != r.rngsubtype OR p.proargtypes[2] != 'pg_catalog.text'::regtype + OR p.prorettype != r.rngtypid + OR p.proname != t.typname OR p.prosrc != 'range_constructor3'; + rngtypid | rngsubtype | proname +----------+------------+--------- +(0 rows) + +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngmltconstruct0 JOIN pg_type t ON r.rngmultitypid = t.oid +WHERE p.pronargs != 0 + OR p.prorettype != r.rngmultitypid + OR p.proname != t.typname OR p.prosrc != 'multirange_constructor0'; + rngtypid | rngsubtype | proname +----------+------------+--------- +(0 rows) + +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngmltconstruct1 JOIN pg_type t ON r.rngmultitypid = t.oid +WHERE p.pronargs != 1 + OR p.proargtypes[0] != r.rngtypid + OR p.prorettype != r.rngmultitypid + OR p.proname != t.typname OR p.prosrc != 'multirange_constructor1'; + rngtypid | rngsubtype | proname +----------+------------+--------- +(0 rows) + +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngmltconstruct2 JOIN pg_type t ON r.rngmultitypid = t.oid JOIN pg_type t2 ON r.rngtypid = t2.oid +WHERE p.pronargs != 1 + OR p.proargtypes[0] != t2.typarray + OR p.prorettype != r.rngmultitypid + OR p.proname != t.typname OR p.prosrc != 'multirange_constructor2'; + rngtypid | rngsubtype | proname +----------+------------+--------- +(0 rows) + +-- ****************************************** -- Create a table that holds all the known in-core data types and leave it -- around so as pg_upgrade is able to test their binary compatibility. CREATE TABLE tab_core_types AS SELECT diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index c2496823d90..95d5b6e0915 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -451,7 +451,9 @@ WHERE (is_catalog_text_unique_index_oid(indexrelid) <> SELECT r.rngtypid, r.rngsubtype FROM pg_range as r -WHERE r.rngtypid = 0 OR r.rngsubtype = 0 OR r.rngsubopc = 0; +WHERE r.rngtypid = 0 OR r.rngsubtype = 0 OR r.rngsubopc = 0 + OR r.rngconstruct2 = 0 OR r.rngconstruct3 = 0 + OR r.rngmltconstruct0 = 0 OR r.rngmltconstruct1 = 0 OR r.rngmltconstruct2 = 0; -- rngcollation should be specified iff subtype is collatable @@ -491,6 +493,49 @@ SELECT r.rngtypid, r.rngsubtype, r.rngmultitypid FROM pg_range r WHERE r.rngmultitypid IS NULL OR r.rngmultitypid = 0; +-- check constructor function arguments and return types +-- +-- proname and prosrc are not required to have these particular +-- values, but this matches what DefineRange() produces and serves to +-- sanity-check the catalog entries for built-in types. + +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngconstruct2 JOIN pg_type t ON r.rngtypid = t.oid +WHERE p.pronargs != 2 + OR p.proargtypes[0] != r.rngsubtype OR p.proargtypes[1] != r.rngsubtype + OR p.prorettype != r.rngtypid + OR p.proname != t.typname OR p.prosrc != 'range_constructor2'; + +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngconstruct3 JOIN pg_type t ON r.rngtypid = t.oid +WHERE p.pronargs != 3 + OR p.proargtypes[0] != r.rngsubtype OR p.proargtypes[1] != r.rngsubtype OR p.proargtypes[2] != 'pg_catalog.text'::regtype + OR p.prorettype != r.rngtypid + OR p.proname != t.typname OR p.prosrc != 'range_constructor3'; + +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngmltconstruct0 JOIN pg_type t ON r.rngmultitypid = t.oid +WHERE p.pronargs != 0 + OR p.prorettype != r.rngmultitypid + OR p.proname != t.typname OR p.prosrc != 'multirange_constructor0'; + +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngmltconstruct1 JOIN pg_type t ON r.rngmultitypid = t.oid +WHERE p.pronargs != 1 + OR p.proargtypes[0] != r.rngtypid + OR p.prorettype != r.rngmultitypid + OR p.proname != t.typname OR p.prosrc != 'multirange_constructor1'; + +SELECT r.rngtypid, r.rngsubtype, p.proname +FROM pg_range r JOIN pg_proc p ON p.oid = r.rngmltconstruct2 JOIN pg_type t ON r.rngmultitypid = t.oid JOIN pg_type t2 ON r.rngtypid = t2.oid +WHERE p.pronargs != 1 + OR p.proargtypes[0] != t2.typarray + OR p.prorettype != r.rngmultitypid + OR p.proname != t.typname OR p.prosrc != 'multirange_constructor2'; + + +-- ****************************************** + -- Create a table that holds all the known in-core data types and leave it -- around so as pg_upgrade is able to test their binary compatibility. CREATE TABLE tab_core_types AS SELECT