Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1efcd57

Browse files
committed
Fix incorrect return value in pg_size_pretty(bigint)
Due to how pg_size_pretty(bigint) was implemented, it's possible that whengiven a negative number of bytes that the returning value would not matchthe equivalent positive return value when given the equivalent positivenumber of bytes. This was due to two separate issues.1. The function used bit shifting to convert the number of bytes intolarger units. The rounding performed by bit shifting is not the same asdividing. For example -3 >> 1 = -2, but -3 / 2 = -1. These twooperations are only equivalent with positive numbers.2. The half_rounded() macro rounded towards positive infinity. This meantthat negative numbers rounded towards zero and positive numbers roundedaway from zero.Here wefix#1 by dividing the values instead of bit shifting. Wefix#2by adjusting the half_rounded macro always to round away from zero.Additionally, adjust the pg_size_pretty(numeric) function to be moreexplicit that it's using division rather than bit shifting. A casualobserver might have believed bit shifting was used due to a staticfunction being named numeric_shift_right. However, that function wascalculating the divisor from the number of bits and performed division.Here we make that more clear. This change is just cosmetic and does notaffect the return value of the numeric version of the function.Here we also add a set of regression tests both versions ofpg_size_pretty() which test the values directly before and after thefunction switches to the next unit.This bug was introduced in8a1fab3. Prior to that negative values werealways displayed in bytes.Author: Dean Rasheed, David RowleyDiscussion:https://postgr.es/m/CAEZATCXnNW4HsmZnxhfezR5FuiGgp+mkY4AzcL5eRGO4fuadWg@mail.gmail.comBackpatch-through: 9.6, where the bug was introduced.
1 parentb23ac5a commit1efcd57

File tree

3 files changed

+79
-18
lines changed

3 files changed

+79
-18
lines changed

‎src/backend/utils/adt/dbsize.c

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
#include"utils/relmapper.h"
3232
#include"utils/syscache.h"
3333

34-
/* Divide by two and roundtowards positive infinity. */
35-
#definehalf_rounded(x) (((x) + ((x) < 0 ?0 : 1)) / 2)
34+
/* Divide by two and roundaway from zero */
35+
#definehalf_rounded(x) (((x) + ((x) < 0 ?-1 : 1)) / 2)
3636

3737
/* Return physical size of directory contents, or 0 if dir doesn't exist */
3838
staticint64
@@ -547,25 +547,29 @@ pg_size_pretty(PG_FUNCTION_ARGS)
547547
snprintf(buf,sizeof(buf),INT64_FORMAT" bytes",size);
548548
else
549549
{
550-
size >>=9;/* keep one extra bit for rounding */
550+
/*
551+
* We use divide instead of bit shifting so that behavior matches for
552+
* both positive and negative size values.
553+
*/
554+
size /= (1 <<9);/* keep one extra bit for rounding */
551555
if (Abs(size)<limit2)
552556
snprintf(buf,sizeof(buf),INT64_FORMAT" kB",
553557
half_rounded(size));
554558
else
555559
{
556-
size>>=10;
560+
size/= (1 <<10);
557561
if (Abs(size)<limit2)
558562
snprintf(buf,sizeof(buf),INT64_FORMAT" MB",
559563
half_rounded(size));
560564
else
561565
{
562-
size>>=10;
566+
size/= (1 <<10);
563567
if (Abs(size)<limit2)
564568
snprintf(buf,sizeof(buf),INT64_FORMAT" GB",
565569
half_rounded(size));
566570
else
567571
{
568-
size>>=10;
572+
size/= (1 <<10);
569573
snprintf(buf,sizeof(buf),INT64_FORMAT" TB",
570574
half_rounded(size));
571575
}
@@ -634,15 +638,13 @@ numeric_half_rounded(Numeric n)
634638
}
635639

636640
staticNumeric
637-
numeric_shift_right(Numericn,unsignedcount)
641+
numeric_truncated_divide(Numericn,int64divisor)
638642
{
639643
Datumd=NumericGetDatum(n);
640-
Datumdivisor_int64;
641644
Datumdivisor_numeric;
642645
Datumresult;
643646

644-
divisor_int64=Int64GetDatum((int64) (1 <<count));
645-
divisor_numeric=DirectFunctionCall1(int8_numeric,divisor_int64);
647+
divisor_numeric=DirectFunctionCall1(int8_numeric,divisor);
646648
result=DirectFunctionCall2(numeric_div_trunc,d,divisor_numeric);
647649
returnDatumGetNumeric(result);
648650
}
@@ -665,8 +667,8 @@ pg_size_pretty_numeric(PG_FUNCTION_ARGS)
665667
else
666668
{
667669
/* keep one extra bit for rounding */
668-
/* size>>= 9 */
669-
size=numeric_shift_right(size,9);
670+
/* size/= (1 << 9) */
671+
size=numeric_truncated_divide(size,1 <<9);
670672

671673
if (numeric_is_less(numeric_absolute(size),limit2))
672674
{
@@ -675,17 +677,18 @@ pg_size_pretty_numeric(PG_FUNCTION_ARGS)
675677
}
676678
else
677679
{
678-
/* size >>= 10 */
679-
size=numeric_shift_right(size,10);
680+
/* size /= (1 << 10) */
681+
size=numeric_truncated_divide(size,1 <<10);
682+
680683
if (numeric_is_less(numeric_absolute(size),limit2))
681684
{
682685
size=numeric_half_rounded(size);
683686
result=psprintf("%s MB",numeric_to_cstring(size));
684687
}
685688
else
686689
{
687-
/* size>>= 10 */
688-
size=numeric_shift_right(size,10);
690+
/* size/= (1 << 10) */
691+
size=numeric_truncated_divide(size,1 <<10);
689692

690693
if (numeric_is_less(numeric_absolute(size),limit2))
691694
{
@@ -694,8 +697,8 @@ pg_size_pretty_numeric(PG_FUNCTION_ARGS)
694697
}
695698
else
696699
{
697-
/* size>>= 10 */
698-
size=numeric_shift_right(size,10);
700+
/* size/= (1 << 10) */
701+
size=numeric_truncated_divide(size,1 <<10);
699702
size=numeric_half_rounded(size);
700703
result=psprintf("%s TB",numeric_to_cstring(size));
701704
}

‎src/test/regress/expected/dbsize.out

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,48 @@ SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
3535
1000000000000000.5 | 909 TB | -909 TB
3636
(12 rows)
3737

38+
-- test where units change up
39+
SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
40+
(VALUES (10239::bigint), (10240::bigint),
41+
(10485247::bigint), (10485248::bigint),
42+
(10736893951::bigint), (10736893952::bigint),
43+
(10994579406847::bigint), (10994579406848::bigint),
44+
(11258449312612351::bigint), (11258449312612352::bigint)) x(size);
45+
size | pg_size_pretty | pg_size_pretty
46+
-------------------+----------------+----------------
47+
10239 | 10239 bytes | -10239 bytes
48+
10240 | 10 kB | -10 kB
49+
10485247 | 10239 kB | -10239 kB
50+
10485248 | 10 MB | -10 MB
51+
10736893951 | 10239 MB | -10239 MB
52+
10736893952 | 10 GB | -10 GB
53+
10994579406847 | 10239 GB | -10239 GB
54+
10994579406848 | 10 TB | -10 TB
55+
11258449312612351 | 10239 TB | -10239 TB
56+
11258449312612352 | 10240 TB | -10240 TB
57+
(10 rows)
58+
59+
SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
60+
(VALUES (10239::numeric), (10240::numeric),
61+
(10485247::numeric), (10485248::numeric),
62+
(10736893951::numeric), (10736893952::numeric),
63+
(10994579406847::numeric), (10994579406848::numeric),
64+
(11258449312612351::numeric), (11258449312612352::numeric)) x(size);
65+
size | pg_size_pretty | pg_size_pretty
66+
-------------------+----------------+----------------
67+
10239 | 10239 bytes | -10239 bytes
68+
10240 | 10 kB | -10 kB
69+
10485247 | 10239 kB | -10239 kB
70+
10485248 | 10 MB | -10 MB
71+
10736893951 | 10239 MB | -10239 MB
72+
10736893952 | 10 GB | -10 GB
73+
10994579406847 | 10239 GB | -10239 GB
74+
10994579406848 | 10 TB | -10 TB
75+
11258449312612351 | 10239 TB | -10239 TB
76+
11258449312612352 | 10240 TB | -10240 TB
77+
(10 rows)
78+
79+
-- pg_size_bytes() tests
3880
SELECT size, pg_size_bytes(size) FROM
3981
(VALUES ('1'), ('123bytes'), ('1kB'), ('1MB'), (' 1 GB'), ('1.5 GB '),
4082
('1TB'), ('3000 TB'), ('1e6 MB')) x(size);

‎src/test/regress/sql/dbsize.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,22 @@ SELECT size, pg_size_pretty(size), pg_size_pretty(-1 * size) FROM
1111
(1000000000.5::numeric), (1000000000000.5::numeric),
1212
(1000000000000000.5::numeric)) x(size);
1313

14+
-- test where units change up
15+
SELECT size, pg_size_pretty(size), pg_size_pretty(-1* size)FROM
16+
(VALUES (10239::bigint), (10240::bigint),
17+
(10485247::bigint), (10485248::bigint),
18+
(10736893951::bigint), (10736893952::bigint),
19+
(10994579406847::bigint), (10994579406848::bigint),
20+
(11258449312612351::bigint), (11258449312612352::bigint)) x(size);
21+
22+
SELECT size, pg_size_pretty(size), pg_size_pretty(-1* size)FROM
23+
(VALUES (10239::numeric), (10240::numeric),
24+
(10485247::numeric), (10485248::numeric),
25+
(10736893951::numeric), (10736893952::numeric),
26+
(10994579406847::numeric), (10994579406848::numeric),
27+
(11258449312612351::numeric), (11258449312612352::numeric)) x(size);
28+
29+
-- pg_size_bytes() tests
1430
SELECT size, pg_size_bytes(size)FROM
1531
(VALUES ('1'), ('123bytes'), ('1kB'), ('1MB'), (' 1 GB'), ('1.5 GB'),
1632
('1TB'), ('3000 TB'), ('1e6 MB')) x(size);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp