问题
SELECT query I am using:
SELECT ARRAY[table_name,pg_size_pretty(table_size)]
FROM (
SELECT
table_name,
pg_table_size(table_name) AS table_size,
pg_indexes_size(table_name) AS indexes_size,
pg_total_relation_size(table_name) AS total_size
FROM (
SELECT ('"' || table_schema || '"."' || table_name || '"') AS table_name
FROM information_schema.tables where table_schema not in ('pg_catalog', 'information_schema')and table_schema not like 'pg_toast%'
) AS all_tables
ORDER BY total_size DESC
) AS have ;
This returns the output as:
But when I use the same query inside a plpgsql test case, it doesn't return me the same array.
Code for the test case:
DROP FUNCTION IF EXISTS unit_tests.example2();
CREATE FUNCTION unit_tests.example2()
RETURNS test_result
AS
$$
DECLARE message test_result;
DECLARE result boolean;
DECLARE have text[][];
DECLARE want text[][];
BEGIN
want := array[['"unit_tests"."tests"','8192 bytes'],
['"unit_tests"."test_details"','16 KB'],
['"unit_tests"."dependencies"','8192 bytes'],
['"DVDRental"."dvd_genre"','8192 bytes'],
['"DVDRental"."dvd_stock"','0 bytes']];
SELECT ARRAY[table_name,pg_size_pretty(table_size)] INTO have
FROM (
SELECT
table_name,
pg_table_size(table_name) AS table_size,
pg_indexes_size(table_name) AS indexes_size,
pg_total_relation_size(table_name) AS total_size
FROM (
SELECT ('"' || table_schema || '"."' || table_name || '"') AS table_name
FROM information_schema.tables where table_schema not in ('pg_catalog', 'information_schema')and table_schema not like 'pg_toast%'
) AS all_tables
ORDER BY total_size DESC
) AS have ;
SELECT * FROM assert.is_equal(have, want) INTO message, result;
--Test failed.
IF result = false THEN
RETURN message;
END IF;
--Test passed.
SELECT assert.ok('End of test.') INTO message;
RETURN message;
END
$$
LANGUAGE plpgsql;
--BEGIN TRANSACTION;
SELECT * FROM unit_tests.begin();
--ROLLBACK TRANSACTION;
Result being returned by the code:
INFO: Test started from : 2015-12-10 05:50:37.291
INFO: Running test unit_tests.example2() : 2015-12-10 05:50:37.291
INFO: Test failed unit_tests.example2() : ASSERT IS_EQUAL FAILED.
Have -> {"\"unit_tests\".\"tests\"","8192 bytes"}
Want -> {{"\"unit_tests\".\"tests\"","8192 bytes"},{"\"unit_tests\".\"test_details\"","16 KB"},{"\"unit_tests\".\"dependencies\"","8192 bytes"},{"\"DVDRental\".\"dvd_genre\"","8192 bytes"},{"\"DVDRental\".\"dvd_stock\"","0 bytes"}}
INFO: Test completed on : 2015-12-10 05:50:37.322 UTC.
Here have
variable represents the result of the query being returned and want
variable has the value which we expected the query to return. But as we can see the value in have
is not what the query was originally returning.
Is this an issue with the way I am using INTO
keyword or something else related to functions?
UPDATE Looks like only the first value of the resultset is being assigned to the have variable, maybe if we can iterate of the results returned and then assign it to have, that might work.
回答1:
You are not the first to run into this. Currently, array_agg()
(or the array constructor ARRAY(SELECT ...)
only accept scalar values as input, not array types. so you cannot build multi-dimensional arrays with it.
The fix is simple, though. Create a custom aggregate function:
CREATE AGGREGATE array_agg_mult (anyarray) (
SFUNC = array_cat
,STYPE = anyarray
,INITCOND = '{}'
);
After simplifying a couple of other things, a basic version of your function becomes:
CREATE FUNCTION example2()
RETURNS text[] AS
$func$
SELECT array_agg_mult(ARRAY[ARRAY[tbl, pg_size_pretty(pg_table_size(tbl))]]
ORDER BY pg_total_relation_size(tbl) DESC) AS have
FROM (
SELECT format('%I.%I', table_schema, table_name) AS tbl
FROM information_schema.tables
WHERE table_schema NOT LIKE 'pg_%'
AND table_schema <> 'information_schema'
) AS all_tables
$func$ LANGUAGE sql;
Related (with an outlook to Postgres 9.5):
- Selecting data into a Postgres array
来源:https://stackoverflow.com/questions/34194818/array-not-being-returned-by-select-query-inside-plpgsql-test-case