#postgresql #bigint
#postgresql #bigint
Вопрос:
Я играл с pg_size_pretty () и обнаружил, что когда я передаю ему большое значение, он начинает возвращать отрицательное значение. Это мой тест:
select pg_size_pretty(9223370000000000000); -- "8388606 TB"
select pg_size_pretty(9223371000000000000); -- "8388607 TB"
select pg_size_pretty(9223372000000000000); -- "-8388607 TB"
Можете ли вы объяснить мне, почему?
Спасибо.
Комментарии:
1. 1 за обнаружение ошибки в PostgreSQL.
2. Я сообщал об этом минуту назад. Еще раз всем спасибо. 🙂
3. Исправлена ошибка. archives.postgresql.org/pgsql-bugs/2011-04/msg00189.php С уважением. 🙂
Ответ №1:
64-разрядное значение с наивысшим знаком равно 922337203685477587. Это лишь немного больше, чем рассматриваемое число. Наверняка где-то в pg_size_pretty
есть переполнение.
Основываясь на коде, упомянутом в комментарии, pg_size_pretty
пытается округлить число и делает это, используя промежуточное значение, которое больше максимального 64-разрядного int со знаком. 9223372000000000000 1024*1024*1024*1024/2 = 9223372549755813888, которое больше, чем 922337203685477587.
Обновление: Добавлен второй абзац и уточнено, что переполнение не в вызывающем.
Комментарии:
1. Для дополнительной справки, вот функция, о которой идет речь в dbsize.c
2. @mu слишком короткое, понятно? Не уверен, почему вы указываете на это, поскольку я уже указывал на ошибку
pg_size_pretty
3 часами ранее.3. 1 Привет, икегами. Спасибо за ваше объяснение. Я использую версию 8.4. Я не знаю, сохраняется ли ошибка также в версии 9.0. Также спасибо Джереми за ссылку на исходный код.
Ответ №2:
Вы не переполняетесь, pg_size_pretty
переполняется. pg_size_pretty
Функция должна принимать bigint
:
pg_size_pretty(bigint)
text
Преобразует размер в байтах в удобочитаемый формат с единицами измерения размера
И 9223372000000000000 < 9223372036854775808
so 9223372000000000000
является совершенно допустимым, bigint
и pg_size_pretty
с ним следует поступать правильно. Вы должны сообщить об ошибке сотрудникам PostgreSQL и заслужить признание.
ОБНОВЛЕНИЕ: Изучение исходного кода PostgreSQL (спасибо Джереми Пешке за предоставленную ссылку) показывает нам, в чем заключается ошибка:
491 else
492 {
493 mult *= 1024;
494 snprintf(buf, sizeof(buf), INT64_FORMAT " TB",
495 (size mult / 2) / mult); /* OVERFLOW! */
496 }
Если size
значение близко к пределу int64
, то добавление mult/2
к нему приведет к переполнению, прежде чем следующее деление на mult
сможет вернуть его обратно в диапазон.
Комментарии:
1. Черт возьми, Му. Ты сегодня в ударе.
2. Шотландские шляпки, да? Обычно я заканчиваю с Serranos.
3. 1. Привет, му. Спасибо даже вам. Вы всегда очень добры. Я принял ответ икегами, потому что он ответил первым. Еще раз спасибо всем. Мне нравится этот сайт. 😉
4. Хехе, спасибо Му. Хороший ответ. Мне просто нравится использовать это как предлог, чтобы узнать больше о том, как работает PostgreSQL.