On 22.02.23 03:39, David Rowley wrote:
hmm. I didn't really code pg_size_pretty with aliases in mind. I don't think you can do this. There's code in pg_size_pretty() and pg_size_pretty_numeric() that'll not work correctly. We look ahead to the next unit to check if there is one so we know we must use this unit if there are no other units to convert to.
I think you'll need to find another way to make the aliases work. Maybe another array with the name and an int to reference the corresponding index in size_pretty_units.
Ok, here is a new patch with a separate table of aliases. (Might look like overkill, but I think the "PiB" etc. example you had could actually be a good use case for this as well.)
From 4e493128adddc2656f3f139b2ca402f0d13721ba Mon Sep 17 00:00:00 2001 From: Peter Eisentraut <pe...@eisentraut.org> Date: Mon, 27 Feb 2023 09:28:25 +0100 Subject: [PATCH v3] Add support for unit "B" to pg_size_bytes() This makes it consistent with the units support in GUC. Discussion: https://www.postgresql.org/message-id/flat/0106914a-9eb5-22be-40d8-652cc88c827d%40enterprisedb.com --- doc/src/sgml/func.sgml | 2 +- src/backend/utils/adt/dbsize.c | 34 +++++++++++++++++++++++++--- src/test/regress/expected/dbsize.out | 15 ++++++------ src/test/regress/sql/dbsize.sql | 2 +- 4 files changed, 41 insertions(+), 12 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 0cbdf63632..718d0cb550 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -27176,7 +27176,7 @@ <title>Database Object Size Functions</title> </para> <para> Converts a size in bytes into a more easily human-readable format with - size units (bytes, kB, MB, GB or TB as appropriate). Note that the + size units (bytes, B, kB, MB, GB or TB as appropriate). Note that the units are powers of 2 rather than powers of 10, so 1kB is 1024 bytes, 1MB is 1024<superscript>2</superscript> = 1048576 bytes, and so on. </para></entry> diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index dbd404101f..338e990aeb 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -57,6 +57,19 @@ static const struct size_pretty_unit size_pretty_units[] = { {NULL, 0, false, 0} }; +/* Additional unit aliases acceted by pg_size_bytes */ +struct size_bytes_unit_alias +{ + const char *alias; + const char *base; +}; + +/* When adding units here also update the error message in pg_size_bytes */ +static const struct size_bytes_unit_alias size_bytes_aliases[] = { + {"B", "bytes"}, + {NULL, NULL} +}; + /* Return physical size of directory contents, or 0 if dir doesn't exist */ static int64 db_dir_size(const char *path) @@ -801,9 +814,22 @@ pg_size_bytes(PG_FUNCTION_ARGS) { /* Parse the unit case-insensitively */ if (pg_strcasecmp(strptr, unit->name) == 0) - { - multiplier = ((int64) 1) << unit->unitbits; break; + } + + /* If not found, look in table of aliases */ + if (unit->name == NULL) + { + for (const struct size_bytes_unit_alias *a = size_bytes_aliases; a->alias != NULL; a++) + { + if (pg_strcasecmp(strptr, a->alias) == 0) + { + for (unit = size_pretty_units; unit->name != NULL; unit++) + { + if (pg_strcasecmp(a->base, unit->name) == 0) + break; + } + } } } @@ -813,7 +839,9 @@ pg_size_bytes(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid size: \"%s\"", text_to_cstring(arg)), errdetail("Invalid size unit: \"%s\".", strptr), - errhint("Valid units are \"bytes\", \"kB\", \"MB\", \"GB\", \"TB\", and \"PB\"."))); + errhint("Valid units are \"bytes\", \"B\", \"kB\", \"MB\", \"GB\", \"TB\", and \"PB\"."))); + + multiplier = ((int64) 1) << unit->unitbits; if (multiplier > 1) { diff --git a/src/test/regress/expected/dbsize.out b/src/test/regress/expected/dbsize.out index d8d6686b5f..f1121a87aa 100644 --- a/src/test/regress/expected/dbsize.out +++ b/src/test/regress/expected/dbsize.out @@ -81,12 +81,13 @@ SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM -- pg_size_bytes() tests SELECT size, pg_size_bytes(size) FROM - (VALUES ('1'), ('123bytes'), ('1kB'), ('1MB'), (' 1 GB'), ('1.5 GB '), + (VALUES ('1'), ('123bytes'), ('256 B'), ('1kB'), ('1MB'), (' 1 GB'), ('1.5 GB '), ('1TB'), ('3000 TB'), ('1e6 MB'), ('99 PB')) x(size); size | pg_size_bytes ----------+-------------------- 1 | 1 123bytes | 123 + 256 B | 256 1kB | 1024 1MB | 1048576 1 GB | 1073741824 @@ -95,7 +96,7 @@ SELECT size, pg_size_bytes(size) FROM 3000 TB | 3298534883328000 1e6 MB | 1048576000000 99 PB | 111464090777419776 -(10 rows) +(11 rows) -- case-insensitive units are supported SELECT size, pg_size_bytes(size) FROM @@ -153,15 +154,15 @@ SELECT size, pg_size_bytes(size) FROM SELECT pg_size_bytes('1 AB'); ERROR: invalid size: "1 AB" DETAIL: Invalid size unit: "AB". -HINT: Valid units are "bytes", "kB", "MB", "GB", "TB", and "PB". +HINT: Valid units are "bytes", "B", "kB", "MB", "GB", "TB", and "PB". SELECT pg_size_bytes('1 AB A'); ERROR: invalid size: "1 AB A" DETAIL: Invalid size unit: "AB A". -HINT: Valid units are "bytes", "kB", "MB", "GB", "TB", and "PB". +HINT: Valid units are "bytes", "B", "kB", "MB", "GB", "TB", and "PB". SELECT pg_size_bytes('1 AB A '); ERROR: invalid size: "1 AB A " DETAIL: Invalid size unit: "AB A". -HINT: Valid units are "bytes", "kB", "MB", "GB", "TB", and "PB". +HINT: Valid units are "bytes", "B", "kB", "MB", "GB", "TB", and "PB". SELECT pg_size_bytes('9223372036854775807.9'); ERROR: bigint out of range SELECT pg_size_bytes('1e100'); @@ -171,7 +172,7 @@ ERROR: value overflows numeric format SELECT pg_size_bytes('1 byte'); -- the singular "byte" is not supported ERROR: invalid size: "1 byte" DETAIL: Invalid size unit: "byte". -HINT: Valid units are "bytes", "kB", "MB", "GB", "TB", and "PB". +HINT: Valid units are "bytes", "B", "kB", "MB", "GB", "TB", and "PB". SELECT pg_size_bytes(''); ERROR: invalid size: "" SELECT pg_size_bytes('kb'); @@ -189,6 +190,6 @@ ERROR: invalid size: ".+912" SELECT pg_size_bytes('+912+ kB'); ERROR: invalid size: "+912+ kB" DETAIL: Invalid size unit: "+ kB". -HINT: Valid units are "bytes", "kB", "MB", "GB", "TB", and "PB". +HINT: Valid units are "bytes", "B", "kB", "MB", "GB", "TB", and "PB". SELECT pg_size_bytes('++123 kB'); ERROR: invalid size: "++123 kB" diff --git a/src/test/regress/sql/dbsize.sql b/src/test/regress/sql/dbsize.sql index 7df865271b..b34cf33385 100644 --- a/src/test/regress/sql/dbsize.sql +++ b/src/test/regress/sql/dbsize.sql @@ -29,7 +29,7 @@ -- pg_size_bytes() tests SELECT size, pg_size_bytes(size) FROM - (VALUES ('1'), ('123bytes'), ('1kB'), ('1MB'), (' 1 GB'), ('1.5 GB '), + (VALUES ('1'), ('123bytes'), ('256 B'), ('1kB'), ('1MB'), (' 1 GB'), ('1.5 GB '), ('1TB'), ('3000 TB'), ('1e6 MB'), ('99 PB')) x(size); -- case-insensitive units are supported base-commit: a6cd1fc692eff708fd42c72b03f756fa1860530e -- 2.39.2