Hello hackers, Currently obtaining the base type of a domain involves a somewhat long recursive query. Consider:
``` create domain mytext as text; create domain mytext_child_1 as mytext; create domain mytext_child_2 as mytext_child_1; ``` To get `mytext_child_2` base type we can do: ``` WITH RECURSIVE recurse AS ( SELECT oid, typbasetype, COALESCE(NULLIF(typbasetype, 0), oid) AS base FROM pg_type UNION SELECT t.oid, b.typbasetype, COALESCE(NULLIF(b.typbasetype, 0), b.oid) AS base FROM recurse t JOIN pg_type b ON t.typbasetype = b.oid ) SELECT oid::regtype, base::regtype FROM recurse WHERE typbasetype = 0 and oid = 'mytext_child_2'::regtype; oid | base ----------------+------ mytext_child_2 | text ``` Core has the `getBaseType` function, which already gets a domain base type recursively. I've attached a patch that exposes a `pg_basetype` SQL function that uses `getBaseType`, so the long query above just becomes: ``` select pg_basetype('mytext_child_2'::regtype); pg_basetype ------------- text (1 row) ``` Tests and docs are added. Best regards, Steve Chavez
From 9be553c2a3896c12d959bc722a808589765f3db0 Mon Sep 17 00:00:00 2001 From: steve-chavez <stevechavez...@gmail.com> Date: Sat, 9 Sep 2023 00:58:44 -0300 Subject: [PATCH] Add pg_basetype(regtype) Currently obtaining the base type of a domain involves a long SQL query, this specially in the case of recursive domain types. To solve this, use the already available getBaseType() function, and expose it as the pg_basetype SQL function. --- doc/src/sgml/func.sgml | 25 +++++++++++++++++++ src/backend/utils/adt/misc.c | 14 +++++++++++ src/include/catalog/pg_proc.dat | 3 +++ src/test/regress/expected/domain.out | 36 ++++++++++++++++++++++++++++ src/test/regress/sql/domain.sql | 17 +++++++++++++ 5 files changed, 95 insertions(+) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 24ad87f910..69393ca557 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -24723,6 +24723,31 @@ SELECT typlen FROM pg_type WHERE oid = pg_typeof(33); </para></entry> </row> + <row> + <entry role="func_table_entry"><para role="func_signature"> + <indexterm> + <primary>pg_basetype</primary> + </indexterm> + <function>pg_basetype</function> ( <parameter>type</parameter> <type>oid</type> ) + <returnvalue>regtype</returnvalue> + </para> + <para> + Returns the OID of the base type of a domain or if the argument is a basetype it returns the same type. + If there's a chain of domain dependencies, it will recurse until finding the base type. + </para> + <para> + For example: +<programlisting> +CREATE DOMAIN mytext as text; + +SELECT pg_basetype('mytext'::regtype); + pg_typeof +----------- + text +</programlisting> + </para></entry> + </row> + <row> <entry role="func_table_entry"><para role="func_signature"> <indexterm> diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 5d78d6dc06..c0c3c9e98b 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -43,6 +43,7 @@ #include "tcop/tcopprot.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/syscache.h" #include "utils/lsyscache.h" #include "utils/ruleutils.h" #include "utils/timestamp.h" @@ -566,6 +567,19 @@ pg_typeof(PG_FUNCTION_ARGS) PG_RETURN_OID(get_fn_expr_argtype(fcinfo->flinfo, 0)); } +/* + * Return the base type of the argument. + */ +Datum +pg_basetype(PG_FUNCTION_ARGS) +{ + Oid oid = PG_GETARG_OID(0); + + if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(oid))) + PG_RETURN_NULL(); + + PG_RETURN_OID(getBaseType(oid)); +} /* * Implementation of the COLLATE FOR expression; returns the collation diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 9805bc6118..f19bf47242 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -3874,6 +3874,9 @@ { oid => '1619', descr => 'type of the argument', proname => 'pg_typeof', proisstrict => 'f', provolatile => 's', prorettype => 'regtype', proargtypes => 'any', prosrc => 'pg_typeof' }, +{ oid => '6312', descr => 'get the base type of a domain', + proname => 'pg_basetype', proisstrict => 'f', provolatile => 's', + prorettype => 'regtype', proargtypes => 'oid', 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 6d94e84414..4f0253cd71 100644 --- a/src/test/regress/expected/domain.out +++ b/src/test/regress/expected/domain.out @@ -1207,3 +1207,39 @@ create domain testdomain1 as int constraint unsigned check (value > 0); 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; +create domain mytext_child_2 as mytext_child_1; +select pg_basetype('mytext'::regtype); + pg_basetype +------------- + text +(1 row) + +-- gets base types recursively +select pg_basetype('mytext_child_1'::regtype); + pg_basetype +------------- + text +(1 row) + +select pg_basetype('mytext_child_2'::regtype); + pg_basetype +------------- + text +(1 row) + +-- if already a base type, get the same +select pg_basetype('text'::regtype); + pg_basetype +------------- + text +(1 row) + +drop domain mytext cascade; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to type mytext_child_1 +drop cascades to type mytext_child_2 diff --git a/src/test/regress/sql/domain.sql b/src/test/regress/sql/domain.sql index 745f5d5fd2..3c824da03a 100644 --- a/src/test/regress/sql/domain.sql +++ b/src/test/regress/sql/domain.sql @@ -809,3 +809,20 @@ create domain testdomain1 as int constraint unsigned check (value > 0); 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; +create domain mytext_child_2 as mytext_child_1; + +select pg_basetype('mytext'::regtype); +-- gets base types recursively +select pg_basetype('mytext_child_1'::regtype); +select pg_basetype('mytext_child_2'::regtype); +-- if already a base type, get the same +select pg_basetype('text'::regtype); + +drop domain mytext cascade; -- 2.34.1