Reputation: 25282
I can returns setof record
and provide definition list to get result:
select (f.row).* from tree( 'resource_type' ) f( id int, path int[], fullname text, level int, row resource_type );
But how to rewrite my function to return any
type with automatic cast?
This does not work:
create or replace function tree( _tbl regclass )
--returns setof record
returns table( id int, path int[], fullname text, level int, r record )
as $$
BEGIN
return query execute format( '
WITH RECURSIVE parent ( id, path, fullname, level, row ) AS (
SELECT
id,
ARRAY[ id ],
''/'' || name::text,
1,
%1$s
FROM %1$s
WHERE parent_id = 13
UNION ALL
SELECT
child.id,
parent.path || child.id,
parent.fullname || ''/'' || child.name,
parent.level +1,
child
FROM parent
JOIN %1$s child ON parent.id = child.parent_id
WHERE NOT child.id = ANY(path)
)
SELECT * FROM parent ', _tbl);
END;
$$ LANGUAGE plpgsql
=> select f.r from tree( 'resource_type' ) f
ERROR: structure of query does not match function result type
DETAIL: Returned type resource_type does not match expected type record in column 5.
CONTEXT: PL/pgSQL function tree(regclass) line 3 at RETURN QUERY
Upvotes: 0
Views: 2549
Reputation: 25282
The solution is to pass anyelement
as argument, then I can use anyelement
for returns ...
statement. doc
create or replace function tree( _tbl anyelement )
returns table( id int, path int[], fullname text, level int, "row" anyelement )
as $$
BEGIN
return query execute format( '...', pg_typeof( _tbl )::text );
END;
$$ LANGUAGE plpgsql
Upvotes: 0
Reputation: 248225
The way to write a polymorphic function is to use anyelement
. But you must provide an argument of type anyelement
as well. The actual data type will then be deduced from the type of that argument:
CREATE FUNCTION poly(
outtype anyelement,
otherparam integer
) RETURNS TABLE (res anyelement)
LANGUAGE plpgsql AS
$$DECLARE
resulttype regtype := pg_typeof(outtype);
whetever text;
BEGIN
/* calculate a text representation of the result in "whatever" */
EXECUTE format('SELECT CAST ($1 AS %s)', resulttype)
USING whatever INTO res;
RETURN NEXT;
END;$$
You call a function like this by supplying a dummy argument of the desired type:
SELECT * FROM poly(NULL::myresulttype, 42);
Upvotes: 3