Skip to content

Commit b154d8a

Browse files
committed
Add pg_basetype() function to extract a domain's base type.
This SQL-callable function behaves much like our internal utility function getBaseType(), except it returns NULL rather than failing for an invalid type OID. (That behavior is modeled on our experience with other catalog-inquiry functions such as the ACL checking functions.) The key advantage over doing a join to pg_type is that it will loop as needed to find the bottom base type of a nest of domains. Steve Chavez, reviewed by jian he and others Discussion: https://postgr.es/m/CAGRrpzZSX8j=MQcbCSEisFA=ic=K3bknVfnFjAv1diVJxFHJvg@mail.gmail.com
1 parent ecf741c commit b154d8a

File tree

6 files changed

+110
-1
lines changed

6 files changed

+110
-1
lines changed

doc/src/sgml/func.sgml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25129,6 +25129,30 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
2512925129
</para></entry>
2513025130
</row>
2513125131

25132+
<row>
25133+
<entry role="func_table_entry"><para role="func_signature">
25134+
<indexterm>
25135+
<primary>pg_basetype</primary>
25136+
</indexterm>
25137+
<function>pg_basetype</function> ( <type>regtype</type> )
25138+
<returnvalue>regtype</returnvalue>
25139+
</para>
25140+
<para>
25141+
Returns the OID of the base type of a domain identified by its
25142+
type OID. If the argument is the OID of a non-domain type,
25143+
returns the argument as-is. Returns NULL if the argument is
25144+
not a valid type OID. If there's a chain of domain dependencies,
25145+
it will recurse until finding the base type.
25146+
</para>
25147+
<para>
25148+
Assuming <literal>CREATE DOMAIN mytext AS text</literal>:
25149+
</para>
25150+
<para>
25151+
<literal>pg_basetype('mytext'::regtype)</literal>
25152+
<returnvalue>text</returnvalue>
25153+
</para></entry>
25154+
</row>
25155+
2513225156
<row>
2513325157
<entry id="pg-char-to-encoding" role="func_table_entry"><para role="func_signature">
2513425158
<indexterm>

src/backend/utils/adt/misc.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "utils/fmgroids.h"
4545
#include "utils/lsyscache.h"
4646
#include "utils/ruleutils.h"
47+
#include "utils/syscache.h"
4748
#include "utils/timestamp.h"
4849

4950

@@ -566,6 +567,50 @@ pg_typeof(PG_FUNCTION_ARGS)
566567
}
567568

568569

570+
/*
571+
* Return the base type of the argument.
572+
* If the given type is a domain, return its base type;
573+
* otherwise return the type's own OID.
574+
* Return NULL if the type OID doesn't exist or points to a
575+
* non-existent base type.
576+
*
577+
* This is a SQL-callable version of getBaseType(). Unlike that function,
578+
* we don't want to fail for a bogus type OID; this is helpful to keep race
579+
* conditions from turning into query failures when scanning the catalogs.
580+
* Hence we need our own implementation.
581+
*/
582+
Datum
583+
pg_basetype(PG_FUNCTION_ARGS)
584+
{
585+
Oid typid = PG_GETARG_OID(0);
586+
587+
/*
588+
* We loop to find the bottom base type in a stack of domains.
589+
*/
590+
for (;;)
591+
{
592+
HeapTuple tup;
593+
Form_pg_type typTup;
594+
595+
tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
596+
if (!HeapTupleIsValid(tup))
597+
PG_RETURN_NULL(); /* return NULL for bogus OID */
598+
typTup = (Form_pg_type) GETSTRUCT(tup);
599+
if (typTup->typtype != TYPTYPE_DOMAIN)
600+
{
601+
/* Not a domain, so done */
602+
ReleaseSysCache(tup);
603+
break;
604+
}
605+
606+
typid = typTup->typbasetype;
607+
ReleaseSysCache(tup);
608+
}
609+
610+
PG_RETURN_OID(typid);
611+
}
612+
613+
569614
/*
570615
* Implementation of the COLLATE FOR expression; returns the collation
571616
* of the argument.

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@
5757
*/
5858

5959
/* yyyymmddN */
60-
#define CATALOG_VERSION_NO 202403301
60+
#define CATALOG_VERSION_NO 202403302
6161

6262
#endif

src/include/catalog/pg_proc.dat

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3889,6 +3889,9 @@
38893889
{ oid => '1619', descr => 'type of the argument',
38903890
proname => 'pg_typeof', proisstrict => 'f', provolatile => 's',
38913891
prorettype => 'regtype', proargtypes => 'any', prosrc => 'pg_typeof' },
3892+
{ oid => '8312', descr => 'base type of a domain type',
3893+
proname => 'pg_basetype', provolatile => 's', prorettype => 'regtype',
3894+
proargtypes => 'regtype', prosrc => 'pg_basetype' },
38923895
{ oid => '3162',
38933896
descr => 'collation of the argument; implementation of the COLLATION FOR expression',
38943897
proname => 'pg_collation_for', proisstrict => 'f', provolatile => 's',

src/test/regress/expected/domain.out

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,6 +1244,31 @@ alter domain testdomain1 rename constraint unsigned to unsigned_foo;
12441244
alter domain testdomain1 drop constraint unsigned_foo;
12451245
drop domain testdomain1;
12461246
--
1247+
-- Get the base type of a domain
1248+
--
1249+
create domain mytext as text;
1250+
create domain mytext_child_1 as mytext;
1251+
select pg_basetype('mytext'::regtype);
1252+
pg_basetype
1253+
-------------
1254+
text
1255+
(1 row)
1256+
1257+
select pg_basetype('mytext_child_1'::regtype);
1258+
pg_basetype
1259+
-------------
1260+
text
1261+
(1 row)
1262+
1263+
select pg_basetype(1); -- expect NULL not error
1264+
pg_basetype
1265+
-------------
1266+
1267+
(1 row)
1268+
1269+
drop domain mytext cascade;
1270+
NOTICE: drop cascades to type mytext_child_1
1271+
--
12471272
-- Information schema
12481273
--
12491274
SELECT * FROM information_schema.column_domain_usage

src/test/regress/sql/domain.sql

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,18 @@ alter domain testdomain1 rename constraint unsigned to unsigned_foo;
839839
alter domain testdomain1 drop constraint unsigned_foo;
840840
drop domain testdomain1;
841841

842+
--
843+
-- Get the base type of a domain
844+
--
845+
create domain mytext as text;
846+
create domain mytext_child_1 as mytext;
847+
848+
select pg_basetype('mytext'::regtype);
849+
select pg_basetype('mytext_child_1'::regtype);
850+
select pg_basetype(1); -- expect NULL not error
851+
852+
drop domain mytext cascade;
853+
842854

843855
--
844856
-- Information schema

0 commit comments

Comments
 (0)