Hi
> 2. using independent implementation - there is some redundant code, but we > can support duble insted int, and we can support some additional units. > new patch is based on own implementation - use numeric/bigint calculations + regress tests and doc Regards Pavel
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml new file mode 100644 index 60b9a09..c94743e *** a/doc/src/sgml/func.sgml --- b/doc/src/sgml/func.sgml *************** postgres=# SELECT * FROM pg_xlogfile_nam *** 17607,17612 **** --- 17607,17615 ---- <primary>pg_relation_size</primary> </indexterm> <indexterm> + <primary>pg_size_bytes</primary> + </indexterm> + <indexterm> <primary>pg_size_pretty</primary> </indexterm> <indexterm> *************** postgres=# SELECT * FROM pg_xlogfile_nam *** 17677,17682 **** --- 17680,17695 ---- </entry> </row> <row> + <entry> + <literal><function>pg_size_bytes(<type>text</type>)</function></literal> + </entry> + <entry><type>bigint</type></entry> + <entry> + Converts a size in human-readable format with size units + to bytes + </entry> + </row> + <row> <entry> <literal><function>pg_size_pretty(<type>bigint</type>)</function></literal> </entry> diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c new file mode 100644 index 5ee59d0..a87c6a7 *** a/src/backend/utils/adt/dbsize.c --- b/src/backend/utils/adt/dbsize.c *************** *** 25,36 **** --- 25,59 ---- #include "storage/fd.h" #include "utils/acl.h" #include "utils/builtins.h" + #include "utils/guc.h" #include "utils/numeric.h" #include "utils/rel.h" #include "utils/relfilenodemap.h" #include "utils/relmapper.h" #include "utils/syscache.h" + #define MAX_UNIT_LEN 3 + #define MAX_DIGITS 20 + + typedef struct + { + char unit[MAX_UNIT_LEN + 1]; + long int multiplier; + } unit_multiplier; + + static const unit_multiplier unit_multiplier_table[] = + { + {"PB", 1024L * 1024 * 1024 * 1024 * 1024}, + {"TB", 1024L * 1024 * 1024 * 1024}, + {"GB", 1024L * 1024 * 1024}, + {"MB", 1024L * 1024}, + {"kB", 1024L}, + {"B", 1L}, + + {""} /* end of table marker */ + }; + + /* Divide by two and round towards positive infinity. */ #define half_rounded(x) (((x) + ((x) < 0 ? 0 : 1)) / 2) *************** pg_size_pretty_numeric(PG_FUNCTION_ARGS) *** 700,705 **** --- 723,830 ---- } /* + * Convert human readable size to long int. + * + * cannot to use parse_int due too low limits there + */ + Datum + pg_size_bytes(PG_FUNCTION_ARGS) + { + text *arg = PG_GETARG_TEXT_PP(0); + const char *cp = text_to_cstring(arg); + char digits[MAX_DIGITS + 1]; + int ndigits = 0; + Numeric num; + int64 result; + + /* Skip leading spaces */ + while (isspace((unsigned char) *cp)) + cp++; + + switch (*cp) + { + case '+': + cp++; + break; + case '-': + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("size cannot be negative"))); + } + + while (*cp) + { + if ((isdigit(*cp) || *cp == '.') && ndigits < MAX_DIGITS) + digits[ndigits++] = *cp++; + else + break; + } + + if (ndigits == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("string is empty"))); + + digits[ndigits] = '\0'; + num = DatumGetNumeric(DirectFunctionCall3(numeric_in, + CStringGetDatum(digits), 0, -1)); + + /* allow whitespace between integer and unit */ + while (isspace((unsigned char) *cp)) + cp++; + + /* Handle possible unit */ + if (*cp != '\0') + { + char unit[MAX_UNIT_LEN + 1]; + int unitlen = 0; + int i; + long int multiplier; + bool found = false; + Numeric mul_num; + + + while (*cp && !isspace(*cp) && unitlen < MAX_UNIT_LEN) + unit[unitlen++] = *cp++; + + unit[unitlen] = '\0'; + + /* allow whitespace after unit */ + while (isspace((unsigned char) *cp)) + cp++; + + if (*cp != '\0') + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid format"))); + + for (i = 0; *unit_multiplier_table[i].unit; i++) + { + if (strcmp(unit, unit_multiplier_table[i].unit) == 0) + { + multiplier = unit_multiplier_table[i].multiplier; + found = true; + break; + } + } + + if (!found) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unknown unit \"%s\"", unit))); + + mul_num = DatumGetNumeric(DirectFunctionCall1(int8_numeric, Int64GetDatum(multiplier))); + num = DatumGetNumeric(DirectFunctionCall2(numeric_mul, + NumericGetDatum(mul_num), + NumericGetDatum(num))); + } + + result = DatumGetInt64(DirectFunctionCall1(numeric_int8, NumericGetDatum(num))); + + PG_RETURN_INT64(result); + } + + /* * Get the filenode of a relation * * This is expected to be used in queries like diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h new file mode 100644 index d8640db..b68c8fa *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** DATA(insert OID = 2286 ( pg_total_relati *** 3662,3667 **** --- 3662,3669 ---- 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 s 1 0 25 "20" _null_ _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 = 3317 ( pg_size_bytes PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 20 "25" _null_ _null_ _null_ _null_ _null_ pg_size_bytes _null_ _null_ _null_ )); + DESCR("convert a human readable text with size units to long int bytes"); DATA(insert OID = 3166 ( pg_size_pretty PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 25 "1700" _null_ _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 s 1 0 20 "2205" _null_ _null_ _null_ _null_ _null_ pg_table_size _null_ _null_ _null_ )); diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h new file mode 100644 index e610bf3..227e5f5 *** a/src/include/utils/builtins.h --- b/src/include/utils/builtins.h *************** extern Datum pg_relation_size(PG_FUNCTIO *** 462,467 **** --- 462,468 ---- 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_size_bytes(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); diff --git a/src/test/regress/expected/dbsize.out b/src/test/regress/expected/dbsize.out new file mode 100644 index aa513e7..41d8336 *** a/src/test/regress/expected/dbsize.out --- b/src/test/regress/expected/dbsize.out *************** SELECT size, pg_size_pretty(size), pg_si *** 35,37 **** --- 35,84 ---- 1000000000000000.5 | 909 TB | -909 TB (12 rows) + SELECT pg_size_bytes('1'); + pg_size_bytes + --------------- + 1 + (1 row) + + SELECT pg_size_bytes('1kB'); + pg_size_bytes + --------------- + 1024 + (1 row) + + SELECT pg_size_bytes('1MB'); + pg_size_bytes + --------------- + 1048576 + (1 row) + + SELECT pg_size_bytes('1 GB '); + pg_size_bytes + --------------- + 1073741824 + (1 row) + + SELECT pg_size_bytes('1.5GB'); + pg_size_bytes + --------------- + 1610612736 + (1 row) + + SELECT pg_size_bytes('100000TB'); + pg_size_bytes + -------------------- + 109951162777600000 + (1 row) + + SELECT pg_size_bytes('1PB'); + pg_size_bytes + ------------------ + 1125899906842624 + (1 row) + + --should fail + SELECT pg_size_bytes('1 AB'); + ERROR: unknown unit "AB" + SELECT pg_size_bytes('1 AB A'); + ERROR: invalid format diff --git a/src/test/regress/sql/dbsize.sql b/src/test/regress/sql/dbsize.sql new file mode 100644 index c118090..0e63384 *** a/src/test/regress/sql/dbsize.sql --- b/src/test/regress/sql/dbsize.sql *************** SELECT size, pg_size_pretty(size), pg_si *** 10,12 **** --- 10,25 ---- (10.5::numeric), (1000.5::numeric), (1000000.5::numeric), (1000000000.5::numeric), (1000000000000.5::numeric), (1000000000000000.5::numeric)) x(size); + + + SELECT pg_size_bytes('1'); + SELECT pg_size_bytes('1kB'); + SELECT pg_size_bytes('1MB'); + SELECT pg_size_bytes('1 GB '); + SELECT pg_size_bytes('1.5GB'); + SELECT pg_size_bytes('100000TB'); + SELECT pg_size_bytes('1PB'); + + --should fail + SELECT pg_size_bytes('1 AB'); + SELECT pg_size_bytes('1 AB A'); \ No newline at end of file
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers