From 7527408f142ab61d8e68bfc52601185d18f42d47 Mon Sep 17 00:00:00 2001 From: "Paul A. Jungwirth" Date: Tue, 2 Dec 2025 21:30:13 -0800 Subject: [PATCH v63 1/8] Add range_get_constructor2 Look up the two-arg constructor for a given rangetype. We need this for UPDATE/DELETE FOR PORTION OF, so that we can build a range from the FROM/TO bounds. There doesn't seem to be an easy way to find the constructor. The rule is that the function has the same name as the rangetype, with arguments making the range's subtype. Ideally we could just use the range's type oid, but I see a way to do that. There are no pg_depend entries for built-in rangetypes, only user-defined ones. Author: Paul A. Jungwirth --- src/backend/utils/cache/lsyscache.c | 68 +++++++++++++++++++++++++++++ src/include/utils/lsyscache.h | 1 + 2 files changed, 69 insertions(+) diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index fa7cd7e06a7..102692884bb 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -3615,6 +3615,74 @@ get_range_collation(Oid rangeOid) return InvalidOid; } +/* + * get_range_constructor2 + * Gets the 2-arg constructor for the given rangetype. + * + * It should be the function whose name and namespace match the rangetype, + * has 2 args matching the subtype, and returns the rangetype. To be extra sure, + * we make sure that prosrc is 'range_constructor2' and probin IS NULL. + * + * We can't use pg_depend, because built-in rangetypes don't have entries there. + * + * Domains on rangetypes don't define their own constructors, + * so caller should pass the basetype oid. + */ +Oid +get_range_constructor2(Oid rngtypid) +{ + Oid range_typelem = get_range_subtype(rngtypid); + char *rngname; + Oid rngnamespace; + Oid argoids[2]; + oidvector *argtypes; + HeapTuple tp; + + /* Is it really a rangetype? */ + if (!OidIsValid(range_typelem)) + elog(ERROR, "cache lookup failed for range %u", rngtypid); + + /* Get the range's name and namespace */ + tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rngtypid)); + if (HeapTupleIsValid(tp)) + { + Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp); + + rngname = pstrdup(NameStr(typtup->typname)); + rngnamespace = typtup->typnamespace; + ReleaseSysCache(tp); + } + else + elog(ERROR, "cache lookup failed for type %u", rngtypid); + + /* Find the constructor */ + argoids[0] = range_typelem; + argoids[1] = range_typelem; + argtypes = buildoidvector(argoids, 2); + tp = SearchSysCache3(PROCNAMEARGSNSP, + PointerGetDatum(rngname), + PointerGetDatum(argtypes), + ObjectIdGetDatum(rngnamespace)); + if (HeapTupleIsValid(tp)) + { + Form_pg_proc proctup = (Form_pg_proc) GETSTRUCT(tp); + Oid result; + Datum prosrc = SysCacheGetAttrNotNull(PROCNAMEARGSNSP, tp, + Anum_pg_proc_prosrc); + + /* Sanity-checking */ + if (proctup->prorettype == rngtypid && + strcmp(TextDatumGetCString(prosrc), "range_constructor2") == 0 && + heap_attisnull(tp, Anum_pg_proc_probin, NULL)) + { + result = proctup->oid; + ReleaseSysCache(tp); + return result; + } + } + elog(ERROR, "cache lookup failed for procedure %s", rngname); +} + /* * get_range_multirange * Returns the multirange type of a given range type diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 50fb149e9ac..ad3d5f33b5e 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -200,6 +200,7 @@ extern char *get_namespace_name(Oid nspid); extern char *get_namespace_name_or_temp(Oid nspid); extern Oid get_range_subtype(Oid rangeOid); extern Oid get_range_collation(Oid rangeOid); +extern Oid get_range_constructor2(Oid rangeOid); extern Oid get_range_multirange(Oid rangeOid); extern Oid get_multirange_range(Oid multirangeOid); extern Oid get_index_column_opclass(Oid index_oid, int attno); -- 2.47.3