If the results are not meant to be used in a subquery but by code, you may use a REFCURSOR
in a transaction.
Example:
CREATE FUNCTION example_cursor() RETURNS refcursor AS $$
DECLARE
c refcursor;
BEGIN
c:='mycursorname';
OPEN c FOR select * from generate_series(1,100000);
return c;
end;
$$ language plpgsql;
Usage for the caller:
BEGIN;
SELECT example_cursor();
[output: mycursor]
FETCH 10 FROM mycursor;
Output:
generate_series
-----------------
1
2
3
4
5
6
7
8
9
10
CLOSE mycursor;
END;
When not interested in piecemeal retrieval, FETCH ALL FROM cursorname
may also be used to stream all results to the caller in one step.
Confusion?
From the docs json_populate_recordset(base anyelement, from_json json)
does not return an ARRAY
, it returns a setof anyelement
. That's fundamentally different from an array.
SELECT * FROM (SELECT ARRAY[1,2]) AS gs(x); -- array (int[])
SELECT * FROM (VALUES (1), (2) ) AS gs(x); -- setof anyelement (setof int)
I am of the opinion that you do not need an array, nor a setof anyelement
.
What you need to do things your way
For comparison this will turn json into foo[]
,
CREATE TYPE foo AS ( id int );
SELECT pg_typeof(
ARRAY(
SELECT *
FROM json_populate_recordset( NULL::foo, '[{"id":1},{"id":2}]' ) )
)
);
Which you can call like this
SELECT test_gps(
ARRAY(
SELECT *
FROM json_populate_recordset( NULL::foo, '[{"id":1},{"id":2}]' ) )
)
);
A better way!
But the better way is to simply not process the whole result set but only a single json value.
CREATE OR REPLACE FUNCTION test_gps
(
gps_points API_GPS_POINT
)
RETURNS BOOLEAN
LANGUAGE plpgsql
AS $$
DECLARE
api_gps_points API_GPS_POINT;
BEGIN
RAISE NOTICE 'API_GPS_POINT : %', API_GPS_POINT;
END;
$$;
And then call it like this..
SELECT test_gps(myjson)
FROM json_populate_recordset( null::foo, '[{"id":1},{"id":2}]' )
AS myjson;
Which you can see returns one type of foo.
SELECT pg_typeof(myjson)
FROM json_populate_recordset( null::foo, '[{"id":1},{"id":2}]' )
AS myjson;
Best Answer
Burns down to a simple solution:
This is concatenating two jsonb arrays with the
||
operator.. You need to wrap the simpletext
value_x
into ajsonb
array for this. There are various way,to_jsonb(ARRAY[_x])
is one.Or even just:
The manual:
So this happens to work for element-to-array concatenation as well.
You could unnest the array and reconstruct it (like you were trying), but that's more expensive. And might be tricky since a JSON array can hold elements of various types, unlike a Postgres array. (Which would not be a problem for your JSONB array of text.)
Your attempt failed because (as commented at the related answer),
jsonb_build_array()
expects a list of values, which can be replaced with a single array following the keywordVARIADIC
- but not with a single element, followed byVARIADIC
array.