N'utilisez pas CREATE TYPE pour renvoyer un résultat polymorphe. Utilisez et abusez plutôt du type RECORD. Vérifiez-le :
CREATE FUNCTION test_ret(a TEXT, b TEXT) RETURNS RECORD AS $$
DECLARE
ret RECORD;
BEGIN
-- Arbitrary expression to change the first parameter
IF LENGTH(a) < LENGTH(b) THEN
SELECT TRUE, a || b, 'a shorter than b' INTO ret;
ELSE
SELECT FALSE, b || a INTO ret;
END IF;
RETURN ret;
END;$$ LANGUAGE plpgsql;
Faites attention au fait qu'il peut éventuellement retourner deux ou trois colonnes en fonction de l'entrée.
test=> SELECT test_ret('foo','barbaz');
test_ret
----------------------------------
(t,foobarbaz,"a shorter than b")
(1 row)
test=> SELECT test_ret('barbaz','foo');
test_ret
----------------------------------
(f,foobarbaz)
(1 row)
Cela fait des ravages sur le code, utilisez donc un nombre constant de colonnes, mais c'est ridiculement pratique pour renvoyer des messages d'erreur facultatifs avec le premier paramètre renvoyant le succès de l'opération. Réécrit en utilisant un nombre constant de colonnes :
CREATE FUNCTION test_ret(a TEXT, b TEXT) RETURNS RECORD AS $$
DECLARE
ret RECORD;
BEGIN
-- Note the CASTING being done for the 2nd and 3rd elements of the RECORD
IF LENGTH(a) < LENGTH(b) THEN
ret := (TRUE, (a || b)::TEXT, 'a shorter than b'::TEXT);
ELSE
ret := (FALSE, (b || a)::TEXT, NULL::TEXT);
END IF;
RETURN ret;
END;$$ LANGUAGE plpgsql;
Une chaleur presque épique :
test=> SELECT test_ret('foobar','bar');
test_ret
----------------
(f,barfoobar,)
(1 row)
test=> SELECT test_ret('foo','barbaz');
test_ret
----------------------------------
(t,foobarbaz,"a shorter than b")
(1 row)
Mais comment divisez-vous cela en plusieurs lignes afin que la couche ORM de votre choix puisse convertir les valeurs dans les types de données natifs de la langue de votre choix ? La chaleur :
test=> SELECT a, b, c FROM test_ret('foo','barbaz') AS (a BOOL, b TEXT, c TEXT);
a | b | c
---+-----------+------------------
t | foobarbaz | a shorter than b
(1 row)
test=> SELECT a, b, c FROM test_ret('foobar','bar') AS (a BOOL, b TEXT, c TEXT);
a | b | c
---+-----------+---
f | barfoobar |
(1 row)
C'est l'une des fonctionnalités les plus intéressantes et les moins utilisées de PostgreSQL. Merci de passer le mot.