почему pg_size_pretty возвращает отрицательное значение?

#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.