diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 29d907ddd1..82bac4d664 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -14981,7 +14981,20 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); pg_size_pretty(bigint) text - Converts a size in bytes into a human-readable format with size units + + Converts a size in bytes expressed as a 64-bit integer into a + human-readable format with size units + + + + + pg_size_pretty(numeric) + + text + + Converts a size in bytes expressed as a numeric value into a + human-readable format with size units + diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index 26a8c01432..fd19de72cb 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -24,6 +24,7 @@ #include "storage/fd.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/numeric.h" #include "utils/rel.h" #include "utils/relmapper.h" #include "utils/syscache.h" @@ -550,6 +551,137 @@ pg_size_pretty(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring_to_text(buf)); } +static char * +numeric_to_cstring(Numeric n) +{ + Datum d = NumericGetDatum(n); + return DatumGetCString(DirectFunctionCall1(numeric_out, d)); +} + +static Numeric +int64_to_numeric(int64 v) +{ + Datum d = Int64GetDatum(v); + return DatumGetNumeric(DirectFunctionCall1(int8_numeric, d)); +} + +static bool +numeric_is_less(Numeric a, Numeric b) +{ + Datum da = NumericGetDatum(a); + Datum db = NumericGetDatum(b); + + return DatumGetBool(DirectFunctionCall2(numeric_lt, da, db)); +} + +static Numeric +numeric_plus_one_over_two(Numeric n) +{ + Datum d = NumericGetDatum(n); + Datum one; + Datum two; + Datum result; + + one = DirectFunctionCall1(int8_numeric, Int64GetDatum(1)); + two = DirectFunctionCall1(int8_numeric, Int64GetDatum(2)); + result = DirectFunctionCall2(numeric_add, d, one); + result = DirectFunctionCall2(numeric_div_trunc, result, two); + return DatumGetNumeric(result); +} + +static Numeric +numeric_shift_right(Numeric n, unsigned count) +{ + Datum d = NumericGetDatum(n); + Datum divisor_int64; + Datum divisor_numeric; + Datum result; + + divisor_int64 = Int64GetDatum((int64) (1 << count)); + divisor_numeric = DirectFunctionCall1(int8_numeric, divisor_int64); + result = DirectFunctionCall2(numeric_div_trunc, d, divisor_numeric); + return DatumGetNumeric(result); +} + +Datum +pg_size_pretty_numeric(PG_FUNCTION_ARGS) +{ + Numeric size = PG_GETARG_NUMERIC(0); + Numeric limit, + limit2; + char *buf, + *result; + + limit = int64_to_numeric(10 * 1024); + limit2 = int64_to_numeric(10 * 1024 * 2 - 1); + + if (numeric_is_less(size, limit)) + { + buf = numeric_to_cstring(size); + result = palloc(strlen(buf) + 7); + strcpy(result, buf); + strcat(result, " bytes"); + } + else + { + /* keep one extra bit for rounding */ + /* size >>= 9 */ + size = numeric_shift_right(size, 9); + + if (numeric_is_less(size, limit2)) + { + /* size = (size + 1) / 2 */ + size = numeric_plus_one_over_two(size); + buf = numeric_to_cstring(size); + result = palloc(strlen(buf) + 4); + strcpy(result, buf); + strcat(result, " kB"); + } + else + { + /* size >>= 10 */ + size = numeric_shift_right(size, 10); + if (numeric_is_less(size, limit2)) + { + /* size = (size + 1) / 2 */ + size = numeric_plus_one_over_two(size); + buf = numeric_to_cstring(size); + result = palloc(strlen(buf) + 4); + strcpy(result, buf); + strcat(result, " MB"); + } + else + { + /* size >>= 10 */ + size = numeric_shift_right(size, 10); + + if (numeric_is_less(size, limit2)) + { + /* size = (size + 1) / 2 */ + size = numeric_plus_one_over_two(size); + buf = numeric_to_cstring(size); + result = palloc(strlen(buf) + 4); + strcpy(result, buf); + strcat(result, " GB"); + } + else + { + /* size >>= 10 */ + size = numeric_shift_right(size, 10); + /* size = (size + 1) / 2 */ + size = numeric_plus_one_over_two(size); + buf = numeric_to_cstring(size); + result = palloc(strlen(buf) + 4); + strcpy(result, buf); + strcat(result, " TB"); + } + } + } + } + + PG_RETURN_TEXT_P(cstring_to_text(result)); +} + /* * Get the filenode of a relation * diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index d582015a5d..a43491503a 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201204131 +#define CATALOG_VERSION_NO 201204141 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index aa4d35072d..079b0b212b 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3410,6 +3410,8 @@ DATA(insert OID = 2286 ( pg_total_relation_size PGNSP PGUID 12 1 0 0 0 f f f f t DESCR("total disk space usage for the specified table and associated indexes"); DATA(insert OID = 2288 ( pg_size_pretty PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 25 "20" _null_ _null_ _null_ _null_ pg_size_pretty _null_ _null_ _null_ )); DESCR("convert a long int to a human readable text using size units"); +DATA(insert OID = 3166 ( pg_size_pretty PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 25 "1700" _null_ _null_ _null_ _null_ pg_size_pretty_numeric _null_ _null_ _null_ )); +DESCR("convert a numeric to a human readable text using size units"); DATA(insert OID = 2997 ( pg_table_size PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 20 "2205" _null_ _null_ _null_ _null_ pg_table_size _null_ _null_ _null_ )); DESCR("disk space usage for the specified table, including TOAST, free space and visibility map"); DATA(insert OID = 2998 ( pg_indexes_size PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 20 "2205" _null_ _null_ _null_ _null_ pg_indexes_size _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 201b23ec9d..f246f117ba 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -453,6 +453,7 @@ extern Datum pg_database_size_name(PG_FUNCTION_ARGS); extern Datum pg_relation_size(PG_FUNCTION_ARGS); extern Datum pg_total_relation_size(PG_FUNCTION_ARGS); extern Datum pg_size_pretty(PG_FUNCTION_ARGS); +extern Datum pg_size_pretty_numeric(PG_FUNCTION_ARGS); extern Datum pg_table_size(PG_FUNCTION_ARGS); extern Datum pg_indexes_size(PG_FUNCTION_ARGS); extern Datum pg_relation_filenode(PG_FUNCTION_ARGS);