Supposons que j'ai créé certains types définis par l'utilisateur dans la base de données,
c'est à dire. CREATE TYPE abc ...
Est-il alors possible de déterminer si le type défini par l'utilisateur existe ou non? Peut-être, en utilisant l'un des tableaux d'informations postgres?
La raison principale en est que PostgreSQL ne semble pas prendre en charge CREATE OR REPLACE TYPE ...
, et si un certain type est créé plus d'une fois, je veux pouvoir supprimer celui existant d'abord, puis recharger le nouveau.
J'ajoute ici la solution complète pour créer des types dans un script simple, sans avoir besoin de créer une fonction juste à cet effet.
--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$$;
La solution la plus simple que j'ai trouvée jusqu'à présent et qui résiste aux schémas, inspirée de la réponse de @ Cromax, est la suivante:
DO $$ BEGIN
CREATE TYPE my_type AS (/* fields go here */);
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
Exactement ce à quoi vous pouvez vous attendre - nous encapsulons simplement l'instruction CREATE TYPE dans un gestionnaire d'exceptions pour qu'elle n'interrompe pas la transaction en cours.
Vous pouvez regarder dans le pg_type
table:
select exists (select 1 from pg_type where typname = 'abc');
Si c'est vrai, alors abc
existe.
En effet, Postgres n'a pas CREATE OR REPLACE
fonctionnalité pour les types. La meilleure approche consiste donc à le supprimer:
DROP TYPE IF EXISTS YOUR_TYPE;
CREATE TYPE YOUR_TYPE AS (
id integer,
field varchar
);
Une solution simple est toujours la meilleure.
-- All of this to create a type if it does not exist
CREATE OR REPLACE FUNCTION create_abc_type() RETURNS integer AS $$
DECLARE v_exists INTEGER;
BEGIN
SELECT into v_exists (SELECT 1 FROM pg_type WHERE typname = 'abc');
IF v_exists IS NULL THEN
CREATE TYPE abc AS ENUM ('height', 'weight', 'distance');
END IF;
RETURN v_exists;
END;
$$ LANGUAGE plpgsql;
-- Call the function you just created
SELECT create_abc_type();
-- Remove the function you just created
DROP function create_abc_type();
-----------------------------------
Pour résoudre le dilemme de @ rog à la réponse de @ bluish, il pourrait être plus approprié d'utiliser le type de données regtype
. Considère ceci:
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 est comme SELECT
, mais elle rejette les résultats, donc en gros nous vérifions s'il est possible de cast 'my_schema.my_type'
(ou juste 'my_type'
si vous ne vous souciez pas d'être spécifique au schéma) au type enregistré réel. Si le type existe, alors rien de "mauvais" ne se produira et à cause de RETURN
tout le bloc se terminera — pas de changement, car le type my_type
est déjà là. Mais si le cast n'est pas possible, alors il y aura un code d'erreur jeté 42704
qui porte le libellé undefined_object
. Donc, dans les lignes suivantes, nous essayons de détecter cette erreur et si cela se produit, nous créons simplement notre nouveau type de données.
J'essaie de faire la même chose, de m'assurer qu'un type existe.
J'ai commencé psql avec l'option --echo-hidden
(-E
) Et entré \dT
:
$ psql -E
psql (9.1.9)
testdb=> \dT
********* QUERY **********
SELECT n.nspname as "Schema",
pg_catalog.format_type(t.oid, NULL) AS "Name",
pg_catalog.obj_description(t.oid, 'pg_type') as "Description"
FROM pg_catalog.pg_type t
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))
AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
AND pg_catalog.pg_type_is_visible(t.oid)
ORDER BY 1, 2;
**************************
List of data types
Schema | Name | Description
--------+------------------+-------------
public | errmsg_agg_state |
(1 row)
Si vous utilisez des schémas et search_path (je le suis), vous devrez probablement conserver la vérification pg_catalog.pg_type_is_visible(t.oid)
. Je ne sais pas ce que font toutes les conditions du WHERE, mais elles ne semblaient pas pertinentes pour mon cas. Utilisant actuellement:
SELECT 1 FROM pg_catalog.pg_type as t
WHERE typname = 'mytype' AND pg_catalog.pg_type_is_visible(t.oid);
Une solution plus générique
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;
et vous pouvez l'appeler comme ceci:
select create_type('lwm2m_instancetype', 'enum (''single'',''multiple'')');