I want to write a plpython3u function in PostgreSQL that returns a set of texts. I've stumbled across a conundrum that looks strange to me. As per the manual, I can do the following:
drop schema if exists X cascade;
create schema X;
create type X.greeting AS (
who text
);
create function X.greet( how text )
returns setof X.greeting language plpython3u as $$
for who in [ 'World', 'PostgreSQL', 'PL/Python' ]:
yield ( who, )
$$;
This is a Python function that returns a set of rows with single texts; so much works, and I do get the expected output:
select X.greet( 'helo' );
greet
--------------
(World)
(PostgreSQL)
(PL/Python)
(3 rows)
select * from X.greet( 'helo' );
who
------------
World
PostgreSQL
PL/Python
(3 rows)
So far so good. However, I do not want to write a table definition for the purpose, I'd like to use setof record
instead, like in this example (which happens to use integers, but still):
create function X.pairs_of_integers_A( out integer, out integer )
returns setof record language plpython3u as $$
return [ ( 12, 24, ), ( 36, 48, ), ( 60, 72, ) ]
$$;
create function X.pairs_of_integers_B( out integer, out integer )
returns setof record language plpython3u as $$
for pair in [ ( 12, 24, ), ( 36, 48, ), ( 60, 72, ) ]:
yield pair
$$;
select * from X.pairs_of_integers_A();
select * from X.pairs_of_integers_B();
column1 | column2
---------+---------
12 | 24
36 | 48
60 | 72
(3 rows)
column1 | column2
---------+---------
12 | 24
36 | 48
60 | 72
(3 rows)
Now we come to the interesting part. Generalizing from the above, one or more formulations of the below should be correct: to return a set of single values, either return a list of Python tuples, a list of Python numbers, or else iterate either over tuples with single values or over single values:
create function X.single_integers_A( out integer )
returns setof record language plpython3u as $$
return [ ( 12, ), ( 36, ), ( 60, ), ]
$$;
create function X.single_integers_B( out integer )
returns setof record language plpython3u as $$
return [ 12, 36, 60, ]
$$;
create function X.single_integers_C( out integer )
returns setof record language plpython3u as $$
for n in [ ( 12, ), ( 36, ), ( 60, ), ]
yield n
$$;
create function X.single_integers_D( out integer )
returns setof record language plpython3u as $$
for n in [ 12, 36, 60, ]
yield n
$$;
Turns out none of the above even compile, they all cause the SQL parser to throw up with function result type must be integer because of OUT parameters. Since I the SQL parser does not look inside Python functions, this leads me to suspect that—
It is not possible, in PostgreSQL, to define a function with both returns setof record
and a single out
parameter; instead, the output type must always be defined as a table (or by similar means).
Can anyone please correct me? It would be really annoying if this should turn out to be true. Surely I have made a mistake somewhere?