[go: up one dir, main page]

Fix incorrect return value for pg_size_pretty(bigint)
authorDavid Rowley <drowley@postgresql.org>
Sun, 28 Jul 2024 10:24:15 +0000 (22:24 +1200)
committerDavid Rowley <drowley@postgresql.org>
Sun, 28 Jul 2024 10:24:15 +0000 (22:24 +1200)
pg_size_pretty(bigint) would return the value in bytes rather than PB
for the smallest-most bigint value.  This happened due to an incorrect
assumption that the absolute value of -9223372036854775808 could be
stored inside a signed 64-bit type.

Here we fix that by instead storing that value in an unsigned 64-bit type.

This bug does exist in versions prior to 15 but the code there is
sufficiently different and the bug seems sufficiently non-critical that
it does not seem worth risking backpatching further.

Author: Joseph Koshakow <koshy44@gmail.com>
Discussion: https://postgr.es/m/CAAvxfHdTsMZPWEHUrZ=h3cky9Ccc3Mtx2whUHygY+ABP-mCmUw@mail.gmail.com
Backpatch-through: 15

src/backend/utils/adt/dbsize.c
src/test/regress/expected/dbsize.out
src/test/regress/sql/dbsize.sql

index b4a2c8d21976f4b8dc41cad04aaf10acec30679c..9b01d9e3fbe5ccd248af959c22ab240d043a400f 100644 (file)
@@ -562,9 +562,13 @@ pg_size_pretty(PG_FUNCTION_ARGS)
    for (unit = size_pretty_units; unit->name != NULL; unit++)
    {
        uint8       bits;
+       uint64      abs_size = size < 0 ? 0 - (uint64) size : (uint64) size;
 
-       /* use this unit if there are no more units or we're below the limit */
-       if (unit[1].name == NULL || Abs(size) < unit->limit)
+       /*
+        * Use this unit if there are no more units or the absolute size is
+        * below the limit for the current unit.
+        */
+       if (unit[1].name == NULL || abs_size < unit->limit)
        {
            if (unit->round)
                size = half_rounded(size);
index d8d6686b5f4be23193d6f1c6902ee49c33cd4bd7..b6d0f678939e84c6da3e88649c9f87e9557c4d01 100644 (file)
@@ -79,6 +79,14 @@ SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
  11528652096115048448 | 10240 PB       | -10240 PB
 (12 rows)
 
+-- Ensure we get the expected results when passing the extremities of bigint
+SELECT pg_size_pretty('-9223372036854775808'::bigint),
+       pg_size_pretty('9223372036854775807'::bigint);
+ pg_size_pretty | pg_size_pretty 
+----------------+----------------
+ -8192 PB       | 8192 PB
+(1 row)
+
 -- pg_size_bytes() tests
 SELECT size, pg_size_bytes(size) FROM
     (VALUES ('1'), ('123bytes'), ('1kB'), ('1MB'), (' 1 GB'), ('1.5 GB '),
index 7df865271b681d424d991c7c14650e2c33a31dd2..2a4f9c4521a0a3647dbeeca07e09e8684bebe744 100644 (file)
@@ -27,6 +27,10 @@ SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
             (11258449312612351::numeric), (11258449312612352::numeric),
             (11528652096115048447::numeric), (11528652096115048448::numeric)) x(size);
 
+-- Ensure we get the expected results when passing the extremities of bigint
+SELECT pg_size_pretty('-9223372036854775808'::bigint),
+       pg_size_pretty('9223372036854775807'::bigint);
+
 -- pg_size_bytes() tests
 SELECT size, pg_size_bytes(size) FROM
     (VALUES ('1'), ('123bytes'), ('1kB'), ('1MB'), (' 1 GB'), ('1.5 GB '),