Procedural function
Basic problems
Declaring the dimensions of an array variable, like float8[][]
for a 2-dimensional array, only serves documentation. Consider details in this related answer:
You confused 1-dimenstional and 2-dimensional arrays. While declaring a 2-dimenstional array (to no effect), you only make it out to be a 1-dimensional array.
To initialize an array, use array_fill()
:
img := array_fill(0, ARRAY[rows,cols])
This example produces a 2-dimensional array - as opposed to your faulty statement, producing a 1-dimensional array:
img := ARRAY( SELECT 0 FROM generate_series(1, rows* cols) ); -- wrong!
The displayed array subscripts img[i * cols + j]
hardly make sense. The maximum would be twice of what you initialized, resulting in "out-of-bound" errors. I suppose you mean img[i][j]
.
Working version
Everything put together it could work like this:
CREATE OR REPLACE FUNCTION f_array_fill(rows integer, cols integer, OUT img float8[][])
LANGUAGE plpgsql AS
$func$
DECLARE
i int;
j int;
BEGIN
img := array_fill(0, ARRAY[rows,cols]);
FOR i IN 1 .. rows LOOP
FOR j IN 1 .. cols LOOP
img[i][j] := (i * cols + j)::float8;
END LOOP;
END LOOP;
END
$func$;
Call:
SELECT f_array_fill(2,3);
Result:
{{4,5,6},{7,8,9}}
To make the function useful, return the produced array. Using an OUT
parameter for that.
Superior set-based version
Looping and individual assignments are comparatively slow in PL/pgSQL. See:
Array handling performs particularly poorly as explained by @Craig in this related answer:
A set-based approach used to scale better with old versions. But the difference is mostly gone with modern Postgres.
Aggregate function for multi-dimensional arrays
In Postgres 9.4 or older, we needed a custom aggregate function. array_agg()
only produced 1-dimensional arrays. Since Postgres 9.5 we can just use built-in functions. See.
SQL function doing the the same as the above:
CREATE OR REPLACE FUNCTION f_array_fill_sql(_rows integer, _cols integer)
RETURNS float8[][] -- 2nd dim only for documentation
LANGUAGE sql AS
$func$
SELECT array_agg(arr1) AS arr2
FROM (
SELECT array_agg((i * $2 + j)::float8) AS arr1
FROM generate_series(1, _rows) i
CROSS JOIN generate_series(1, _cols) j
GROUP BY i
ORDER BY i
) sub
$func$;
Call:
SELECT f_array_fill_sql(2,3);
Result:
{{4,5,6},{7,8,9}}