1

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: Query Output

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 haveis 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.

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
Mitaksh Gupta
  • 1,029
  • 6
  • 24
  • 50

1 Answers1

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):

Community
  • 1
  • 1
Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228