Не используйте CREATE TYPE , чтобы вернуть полиморфный результат.Используйте вместо этого RECORD .Проверьте это:
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;
Обратите внимание на тот факт, что при желании он может возвращать два или три столбца в зависимости от ввода.
Это наносит ущерб коду, поэтому используйте одинаковое количество столбцов, но это смехотворно удобно для возврата необязательных сообщений об ошибках, когда первый параметр возвращает успешное выполнение операции.Переписать, используя постоянное количество столбцов:
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;
Почти до эпической жары:
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)
Но как разделить это на несколько строк, чтобы ваш слой ORM мог выбратьпреобразовать значения в родные типы данных вашего языка?Жаркость:
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)
Это одна из самых крутых и недостаточно используемых функций в PostgreSQL.Пожалуйста, распространите слово.