Generally, a PostgreSQL function only returns a single value (or row), or a set of values (or rows), but not both in parallel.
Return a table
You can either return the set or rows directly from the function, making it a "set-returning function", a.k.a. "table function". Then you have no other choice than to return the parameters o_call_status
and o_call_message
with every row (if you, in fact, need them at all?!)
CREATE OR REPLACE FUNCTION myplfunction(i_val1 int, i_val2 int)
RETURNS TABLE (col1 text, col2 text -- use matching types!
, o_call_status text -- text, not int
, o_call_message text) AS
$func$
BEGIN
RETURN QUERY
SELECT col1, col2
, '0'::text AS o_call_status
, ''::text AS o_call_message -- column aliases irrelevant here
FROM tb1
WHERE col3 = i_val1
UNION ALL
SELECT col4, col5, '0'::text, ''::text
FROM tb2
WHERE col6 = i_val2
AND col7 = i_val3; -- WHERE was specified twice
EXCEPTION WHEN OTHERS THEN
RETURN QUERY
SELECT NULL::text, NULL::text, SQLERRM, SQLSTATE;
END
$func$ LANGUAGE plpgsql;
The special variable SQLERRM
is of type text
, btw. Not integer
.
Or open a cursor
Or you would have to open a cursor to decouple the returned table from those two parameters.
CREATE OR REPLACE FUNCTION myplfunction(
i_val1 text, i_val2 text, i_val3 text, i_val4 text
, OUT o_call_status text
, OUT o_call_message text) AS
$func$
DECLARE
curs CURSOR FOR
SELECT col1, col2 FROM tb1
WHERE col3 = i_val1
UNION ALL
SELECT col4, col5 FROM tb2
WHERE col6 = i_val2
AND col7 = i_val3;
BEGIN
OPEN curs;
o_call_status := '0';
o_call_message := '';
EXCEPTION WHEN OTHERS THEN
o_call_status := SQLSTATE;
o_call_message := SQLERRM;
END
$func$ LANGUAGE plpgsql;
However, the cursor only exists within the same transaction. So you need to fetch the values before you COMMIT
or ROLLBACK
.
BEGIN;
SELECT * FROM myplfunction (10, 20, 30, 40);
FETCH ALL IN curs;
ROLLBACK;
You can even hand in arbitrary cursor names. This and other details in the manual.
And there is more information about errors available since Postgres 9.3..