diff options
author | Robert Haas <rhaas@postgresql.org> | 2012-04-14 08:04:11 -0400 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2012-04-14 08:07:25 -0400 |
commit | 4a2d7ad76f5f275ef2d6a57e1a61d5bf756349e8 (patch) | |
tree | 95875b3c3bf1facfce84e317a863ce8aaf57da81 /src/backend/utils/adt/dbsize.c | |
parent | d4db16d303b24ba5c9a6ddf8c2d70f6fd2da36d7 (diff) | |
download | postgresql-4a2d7ad76f5f275ef2d6a57e1a61d5bf756349e8.tar.gz postgresql-4a2d7ad76f5f275ef2d6a57e1a61d5bf756349e8.zip |
pg_size_pretty(numeric)
The output of the new pg_xlog_location_diff function is of type numeric,
since it could theoretically overflow an int8 due to signedness; this
provides a convenient way to format such values.
Fujii Masao, with some beautification by me.
Diffstat (limited to 'src/backend/utils/adt/dbsize.c')
-rw-r--r-- | src/backend/utils/adt/dbsize.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index 26a8c01432c..fd19de72cb6 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 * |