0001-Record-range-constructor-functions-in-pg_range.patch
text/plain
Filename: 0001-Record-range-constructor-functions-in-pg_range.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0001
Subject: Record range constructor functions in pg_range
| File | + | − |
|---|---|---|
| src/backend/catalog/pg_range.c | 8 | 1 |
| src/backend/commands/typecmds.c | 22 | 10 |
| src/include/catalog/pg_range.dat | 12 | 0 |
| src/include/catalog/pg_range.h | 12 | 1 |
| src/test/regress/expected/oidjoins.out | 5 | 0 |
| src/test/regress/expected/type_sanity.out | 55 | 1 |
| src/test/regress/sql/type_sanity.sql | 43 | 1 |
From 8c2684ee197c882bf035e5163c3be777cd63280c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter@eisentraut.org>
Date: Thu, 8 Jan 2026 15:56:12 +0100
Subject: [PATCH] Record range constructor functions in pg_range
---
src/backend/catalog/pg_range.c | 9 +++-
src/backend/commands/typecmds.c | 32 +++++++++----
src/include/catalog/pg_range.dat | 12 +++++
src/include/catalog/pg_range.h | 13 +++++-
src/test/regress/expected/oidjoins.out | 5 ++
src/test/regress/expected/type_sanity.out | 56 ++++++++++++++++++++++-
src/test/regress/sql/type_sanity.sql | 44 +++++++++++++++++-
7 files changed, 157 insertions(+), 14 deletions(-)
diff --git a/src/backend/catalog/pg_range.c b/src/backend/catalog/pg_range.c
index cd21c84c8fd..3d194e67fbf 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 rangeConstr2, RegProcedure rangeConstr3,
+ RegProcedure multirangeConstr0, RegProcedure multirangeConstr1, RegProcedure multirangeConstr2)
{
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_rngconstr2 - 1] = ObjectIdGetDatum(rangeConstr2);
+ values[Anum_pg_range_rngconstr3 - 1] = ObjectIdGetDatum(rangeConstr3);
+ values[Anum_pg_range_rngmconstr0 - 1] = ObjectIdGetDatum(multirangeConstr0);
+ values[Anum_pg_range_rngmconstr1 - 1] = ObjectIdGetDatum(multirangeConstr1);
+ values[Anum_pg_range_rngmconstr2 - 1] = ObjectIdGetDatum(multirangeConstr2);
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..0a92688b298 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 rangeConstrOids[]);
static void makeMultirangeConstructors(const char *name, Oid namespace,
Oid multirangeOid, Oid rangeOid,
- Oid rangeArrayOid, Oid *castFuncOid);
+ Oid rangeArrayOid, Oid *castFuncOid,
+ Oid multirangeConstrOids[]);
static Oid findTypeInputFunction(List *procname, Oid typeOid);
static Oid findTypeOutputFunction(List *procname, Oid typeOid);
static Oid findTypeReceiveFunction(List *procname, Oid typeOid);
@@ -1406,6 +1408,8 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
ListCell *lc;
ObjectAddress address;
ObjectAddress mltrngaddress PG_USED_FOR_ASSERTS_ONLY;
+ Oid rangeConstrOids[2];
+ Oid multirangeConstrOids[3];
Oid castFuncOid;
/* Convert list of names to a name and namespace */
@@ -1661,10 +1665,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 +1746,16 @@ 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, rangeConstrOids);
makeMultirangeConstructors(multirangeTypeName, typeNamespace,
multirangeOid, typoid, rangeArrayOid,
- &castFuncOid);
+ &castFuncOid, multirangeConstrOids);
+
+ /* Create the entry in pg_range */
+ RangeCreate(typoid, rangeSubtype, rangeCollation, rangeSubOpclass,
+ rangeCanonical, rangeSubtypeDiff, multirangeOid,
+ rangeConstrOids[0], rangeConstrOids[1],
+ multirangeConstrOids[0], multirangeConstrOids[1], multirangeConstrOids[2]);
/* Create cast from the range type to its multirange type */
CastCreate(typoid, multirangeOid, castFuncOid, InvalidOid, InvalidOid,
@@ -1772,7 +1778,8 @@ DefineRange(ParseState *pstate, CreateRangeStmt *stmt)
*/
static void
makeRangeConstructors(const char *name, Oid namespace,
- Oid rangeOid, Oid subtype)
+ Oid rangeOid, Oid subtype,
+ Oid rangeConstrOids[])
{
static const char *const prosrc[2] = {"range_constructor2",
"range_constructor3"};
@@ -1833,6 +1840,8 @@ makeRangeConstructors(const char *name, Oid namespace,
* pg_dump depends on this choice to avoid dumping the constructors.
*/
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+
+ rangeConstrOids[i] = myself.objectId;
}
}
@@ -1848,7 +1857,7 @@ makeRangeConstructors(const char *name, Oid namespace,
static void
makeMultirangeConstructors(const char *name, Oid namespace,
Oid multirangeOid, Oid rangeOid, Oid rangeArrayOid,
- Oid *castFuncOid)
+ Oid *castFuncOid, Oid multirangeConstrOids[])
{
ObjectAddress myself,
referenced;
@@ -1899,6 +1908,7 @@ makeMultirangeConstructors(const char *name, Oid namespace,
* depends on this choice to avoid dumping the constructors.
*/
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+ multirangeConstrOids[0] = myself.objectId;
pfree(argtypes);
/*
@@ -1939,6 +1949,7 @@ makeMultirangeConstructors(const char *name, Oid namespace,
0.0); /* prorows */
/* ditto */
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+ multirangeConstrOids[1] = myself.objectId;
pfree(argtypes);
*castFuncOid = myself.objectId;
@@ -1978,6 +1989,7 @@ makeMultirangeConstructors(const char *name, Oid namespace,
0.0); /* prorows */
/* ditto */
recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL);
+ multirangeConstrOids[2] = myself.objectId;
pfree(argtypes);
pfree(allParameterTypes);
pfree(parameterModes);
diff --git a/src/include/catalog/pg_range.dat b/src/include/catalog/pg_range.dat
index 830971c4944..f1e46a9d830 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',
+ rngconstr2 => 'int4range(int4,int4)', rngconstr3 => 'int4range(int4,int4,text)',
+ rngmconstr0 => 'int4multirange()', rngmconstr1 => 'int4multirange(int4range)', rngmconstr2 => 'int4multirange(_int4range)',
rngcanonical => 'int4range_canonical', rngsubdiff => 'int4range_subdiff' },
{ rngtypid => 'numrange', rngsubtype => 'numeric',
rngmultitypid => 'nummultirange', rngsubopc => 'btree/numeric_ops',
+ rngconstr2 => 'numrange(numeric,numeric)', rngconstr3 => 'numrange(numeric,numeric,text)',
+ rngmconstr0 => 'nummultirange()', rngmconstr1 => 'nummultirange(numrange)', rngmconstr2 => 'nummultirange(_numrange)',
rngcanonical => '-', rngsubdiff => 'numrange_subdiff' },
{ rngtypid => 'tsrange', rngsubtype => 'timestamp',
rngmultitypid => 'tsmultirange', rngsubopc => 'btree/timestamp_ops',
+ rngconstr2 => 'tsrange(timestamp,timestamp)', rngconstr3 => 'tsrange(timestamp,timestamp,text)',
+ rngmconstr0 => 'tsmultirange()', rngmconstr1 => 'tsmultirange(tsrange)', rngmconstr2 => 'tsmultirange(_tsrange)',
rngcanonical => '-', rngsubdiff => 'tsrange_subdiff' },
{ rngtypid => 'tstzrange', rngsubtype => 'timestamptz',
rngmultitypid => 'tstzmultirange', rngsubopc => 'btree/timestamptz_ops',
+ rngconstr2 => 'tstzrange(timestamptz,timestamptz)', rngconstr3 => 'tstzrange(timestamptz,timestamptz,text)',
+ rngmconstr0 => 'tstzmultirange()', rngmconstr1 => 'tstzmultirange(tstzrange)', rngmconstr2 => 'tstzmultirange(_tstzrange)',
rngcanonical => '-', rngsubdiff => 'tstzrange_subdiff' },
{ rngtypid => 'daterange', rngsubtype => 'date',
rngmultitypid => 'datemultirange', rngsubopc => 'btree/date_ops',
+ rngconstr2 => 'daterange(date,date)', rngconstr3 => 'daterange(date,date,text)',
+ rngmconstr0 => 'datemultirange()', rngmconstr1 => 'datemultirange(daterange)', rngmconstr2 => 'datemultirange(_daterange)',
rngcanonical => 'daterange_canonical', rngsubdiff => 'daterange_subdiff' },
{ rngtypid => 'int8range', rngsubtype => 'int8',
rngmultitypid => 'int8multirange', rngsubopc => 'btree/int8_ops',
+ rngconstr2 => 'int8range(int8,int8)', rngconstr3 => 'int8range(int8,int8,text)',
+ rngmconstr0 => 'int8multirange()', rngmconstr1 => 'int8multirange(int8range)', rngmconstr2 => '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..ad4d1e9187f 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 rngconstr2 BKI_LOOKUP(pg_proc);
+ regproc rngconstr3 BKI_LOOKUP(pg_proc);
+
+ /* multirange constructor functions */
+ regproc rngmconstr0 BKI_LOOKUP(pg_proc);
+ regproc rngmconstr1 BKI_LOOKUP(pg_proc);
+ regproc rngmconstr2 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 rangeConstr2, RegProcedure rangeConstr3,
+ RegProcedure multirangeConstr0, RegProcedure multirangeConstr1, RegProcedure multirangeConstr2);
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..f2d731a3017 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 {rngconstr2} => pg_proc {oid}
+NOTICE: checking pg_range {rngconstr3} => pg_proc {oid}
+NOTICE: checking pg_range {rngmconstr0} => pg_proc {oid}
+NOTICE: checking pg_range {rngmconstr1} => pg_proc {oid}
+NOTICE: checking pg_range {rngmconstr2} => 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..1d941d20b6b 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.rngconstr2 = 0 OR r.rngconstr3 = 0
+ OR r.rngmconstr0 = 0 OR r.rngmconstr1 = 0 OR r.rngmconstr2 = 0;
rngtypid | rngsubtype
----------+------------
(0 rows)
@@ -663,6 +665,58 @@ WHERE r.rngmultitypid IS NULL OR r.rngmultitypid = 0;
----------+------------+---------------
(0 rows)
+-- check constructor function arguments and return types
+-- proname and prosrc are not required but match 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.rngconstr2 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.rngconstr3 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.rngmconstr0 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.rngmconstr1 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.rngmconstr2 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..1a1bd3f14a7 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -451,7 +451,9 @@ CREATE FUNCTION is_catalog_text_unique_index_oid(oid) RETURNS bool
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.rngconstr2 = 0 OR r.rngconstr3 = 0
+ OR r.rngmconstr0 = 0 OR r.rngmconstr1 = 0 OR r.rngmconstr2 = 0;
-- rngcollation should be specified iff subtype is collatable
@@ -491,6 +493,46 @@ CREATE FUNCTION is_catalog_text_unique_index_oid(oid) RETURNS bool
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 but match 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.rngconstr2 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.rngconstr3 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.rngmconstr0 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.rngmconstr1 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.rngmconstr2 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
--
2.52.0