У вас есть несколько вариантов. Первый - использовать полиморфный тип, который будет приведен по вызову, второй - использовать приведение, а третий - возвращать рефкурсор.
Полиморфный тип
В этом случае вы бы сделали что-то вроде:
CREATE FUNCTION foo (bar varchar, baz ANYELEMENT) returns ANYELEMENT AS
$$
SELECT 'test'::TEXT;
$$ language sql;
Затем, чтобы вызвать его, вы должны вызвать аргумент NULL при вызове:
SELECT * FROM foo('test', null::varchar);
Настоящая проблема, с которой вы столкнулись, заключается в том, что вам придется указывать тип при каждом вызове.
Одиночный тип возврата с Cast
В вашем примере один тип имеет подмножество полей другого типа. Чтобы вы могли:
CREATE TYPE all_info AS (
name text,
email text,
address text,
phone text
);
CREATE TYPE email_only AS (
name text,
email text
);
CREATE FUNCTION email_only(all_info) returns email_only LANGUAGE SQL IMMUTABLE AS $$
SELECT $1.name, $1.email;
$$;
CREATE CAST (all_info as email_only) WITH FUNCTION email_only(all_info);
Затем вы создаете свою функцию, которая возвращает all_info, и вы можете привести ее к выводу. Что-то вроде:
SELECT (f::email_only).* FROM my_function('foo') f;
Обратите внимание, что эти два позволяют вам использовать функции языка SQL, которые не используются в рефкурсорах.
REFCURSOR
В этом случае вы должны использовать plpgsql
CREATE OR REPLACE FUNCTION foo(bar varchar) RETURNS refcursor LANGUAGE plpgsql AS
$$
DECLARE a REFCURSOR;
BEGIN
OPEN a FOR SELECT ....;
RETURN a;
END;
$$;
В общем, я думаю, что проще всего начать с подхода суперсет и приведение актеров, чем с другими. Отражатели, возможно, второй подход. Последний будет настаивать на приведении типа.