Say I have created some user-defined types in the DB,
i.e. CREATE TYPE abc ...
Is it then possible to determine if the user-defined type exists
I add here the complete solution for creating types in a simple script, without the need of creating a function just for this purpose.
--create types
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'my_type') THEN
CREATE TYPE my_type AS
(
--my fields here...
);
END IF;
--more types here...
END$$;
To solve @rog's dilemma to @bluish's answer it could be more appropriate to make use of regtype
data type. Consider this:
DO $$ BEGIN
PERFORM 'my_schema.my_type'::regtype;
EXCEPTION
WHEN undefined_object THEN
CREATE TYPE my_schema.my_type AS (/* fields go here */);
END $$;
PERFORM
clause is like SELECT
, but it discards results, so basically we're checking if it is possible to cast 'my_schema.my_type'
(or just 'my_type'
if you don't care to be schema specific) to actual registered type. If the type does exist, then nothing "wrong" will happen and because of RETURN
whole block will end—no changes, since the type my_type
is already there. But if the cast is not possible, then there will be thrown error code 42704
which has label of undefined_object
. So in the next lines we try to catch that error and if that happens, we simply create our new data type.
Another alternative
WITH namespace AS(
SELECT oid
FROM pg_namespace
WHERE nspname = 'my_schema'
),
type_name AS (
SELECT 1 type_exist
FROM pg_type
WHERE typname = 'my_type' AND typnamespace = (SELECT * FROM namespace)
)
SELECT EXISTS (SELECT * FROM type_name);
This plays well with schemas, and avoids exception handling:
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_type t
LEFT JOIN pg_namespace p ON t.typnamespace=p.oid
WHERE t.typname='my_type' AND p.nspname='my_schema'
) THEN
CREATE TYPE my_schema.my_type AS (/* fields go here */);
END IF;
END
$$;
The simplest solution I've found so far that copes with schemas, inspired by @Cromax's answer, is this:
DO $$ BEGIN
CREATE TYPE my_type AS (/* fields go here */);
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
Just what you might expect really - we just wrap the CREATE TYPE statement in an exception handler so it doesn't abort the current transaction.
A more generic solution
CREATE OR REPLACE FUNCTION create_type(name text, _type text) RETURNS
integer AS $$
DECLARE v_exists INTEGER;
BEGIN
SELECT into v_exists (SELECT 1 FROM pg_type WHERE typname = name);
IF v_exists IS NULL THEN
EXECUTE format('CREATE TYPE %I AS %s', name, _type);
END IF;
RETURN v_exists;
END;
$$ LANGUAGE plpgsql;
and then you can call it like this:
select create_type('lwm2m_instancetype', 'enum (''single'',''multiple'')');