diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 93b0bc2bc6e..b694b2883c3 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -25129,6 +25129,30 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); + + + + pg_basetype + + pg_basetype ( regtype ) + regtype + + + Returns the OID of the base type of a domain identified by its + type OID. If the argument is the OID of a non-domain type, + returns the argument as-is. Returns NULL if the argument is + not a valid type OID. If there's a chain of domain dependencies, + it will recurse until finding the base type. + + + Assuming CREATE DOMAIN mytext AS text: + + + pg_basetype('mytext'::regtype) + text + + + diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index d4a92d0b3fa..0e6c45807a1 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -44,6 +44,7 @@ #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/ruleutils.h" +#include "utils/syscache.h" #include "utils/timestamp.h" @@ -566,6 +567,50 @@ pg_typeof(PG_FUNCTION_ARGS) } +/* + * Return the base type of the argument. + * If the given type is a domain, return its base type; + * otherwise return the type's own OID. + * Return NULL if the type OID doesn't exist or points to a + * non-existent base type. + * + * This is a SQL-callable version of getBaseType(). Unlike that function, + * we don't want to fail for a bogus type OID; this is helpful to keep race + * conditions from turning into query failures when scanning the catalogs. + * Hence we need our own implementation. + */ +Datum +pg_basetype(PG_FUNCTION_ARGS) +{ + Oid typid = PG_GETARG_OID(0); + + /* + * We loop to find the bottom base type in a stack of domains. + */ + for (;;) + { + HeapTuple tup; + Form_pg_type typTup; + + tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + if (!HeapTupleIsValid(tup)) + PG_RETURN_NULL(); /* return NULL for bogus OID */ + typTup = (Form_pg_type) GETSTRUCT(tup); + if (typTup->typtype != TYPTYPE_DOMAIN) + { + /* Not a domain, so done */ + ReleaseSysCache(tup); + break; + } + + typid = typTup->typbasetype; + ReleaseSysCache(tup); + } + + PG_RETURN_OID(typid); +} + + /* * Implementation of the COLLATE FOR expression; returns the collation * of the argument. diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 0303973822e..86ace33dbeb 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202403301 +#define CATALOG_VERSION_NO 202403302 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 07023ee61d9..134e3b22fd8 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -3889,6 +3889,9 @@ { oid => '1619', descr => 'type of the argument', proname => 'pg_typeof', proisstrict => 'f', provolatile => 's', prorettype => 'regtype', proargtypes => 'any', prosrc => 'pg_typeof' }, +{ oid => '8312', descr => 'base type of a domain type', + proname => 'pg_basetype', provolatile => 's', prorettype => 'regtype', + proargtypes => 'regtype', prosrc => 'pg_basetype' }, { oid => '3162', descr => 'collation of the argument; implementation of the COLLATION FOR expression', proname => 'pg_collation_for', proisstrict => 'f', provolatile => 's', diff --git a/src/test/regress/expected/domain.out b/src/test/regress/expected/domain.out index dc58793e3f5..fa8459e10ff 100644 --- a/src/test/regress/expected/domain.out +++ b/src/test/regress/expected/domain.out @@ -1244,6 +1244,31 @@ alter domain testdomain1 rename constraint unsigned to unsigned_foo; alter domain testdomain1 drop constraint unsigned_foo; drop domain testdomain1; -- +-- Get the base type of a domain +-- +create domain mytext as text; +create domain mytext_child_1 as mytext; +select pg_basetype('mytext'::regtype); + pg_basetype +------------- + text +(1 row) + +select pg_basetype('mytext_child_1'::regtype); + pg_basetype +------------- + text +(1 row) + +select pg_basetype(1); -- expect NULL not error + pg_basetype +------------- + +(1 row) + +drop domain mytext cascade; +NOTICE: drop cascades to type mytext_child_1 +-- -- Information schema -- SELECT * FROM information_schema.column_domain_usage diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql index ae1b7fbf97a..763c68f1db6 100644 --- a/src/test/regress/sql/domain.sql +++ b/src/test/regress/sql/domain.sql @@ -839,6 +839,18 @@ alter domain testdomain1 rename constraint unsigned to unsigned_foo; alter domain testdomain1 drop constraint unsigned_foo; drop domain testdomain1; +-- +-- Get the base type of a domain +-- +create domain mytext as text; +create domain mytext_child_1 as mytext; + +select pg_basetype('mytext'::regtype); +select pg_basetype('mytext_child_1'::regtype); +select pg_basetype(1); -- expect NULL not error + +drop domain mytext cascade; + -- -- Information schema