1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-12 21:01:52 +03:00

Fix failure to zero-pad the result of bitshiftright().

If the bitstring length is not a multiple of 8, we'd shift the
rightmost bits into the pad space, which must be zeroes --- bit_cmp,
for one, depends on that.  This'd lead to the result failing to
compare equal to what it should compare equal to, as reported in
bug #16013 from Daryl Waycott.

This is, if memory serves, not the first such bug in the bitstring
functions.  In hopes of making it the last one, do a bit more work
than minimally necessary to fix the bug:

* Add assertion checks to bit_out() and varbit_out() to complain if
they are given incorrectly-padded input.  This will improve the
odds that manual testing of any new patch finds problems.

* Encapsulate the padding-related logic in macros to make it
easier to use.

Also, remove unnecessary padding logic from bit_or() and bitxor().
Somebody had already noted that we need not re-pad the result of
bit_and() since the inputs are required to be the same length,
but failed to extrapolate that to the other two.

Also, move a comment block that once was near the head of varbit.c
(but people kept putting other stuff in front of it), to put it in
the header block.

Note for the release notes: if anyone has inconsistent data as a
result of saving the output of bitshiftright() in a table, it's
possible to fix it with something like
UPDATE mytab SET bitcol = ~(~bitcol) WHERE bitcol != ~(~bitcol);

This has been broken since day one, so back-patch to all supported
branches.

Discussion: https://postgr.es/m/16013-c2765b6996aacae9@postgresql.org
This commit is contained in:
Tom Lane
2019-09-22 17:46:00 -04:00
parent 308813846e
commit 860216efa1
4 changed files with 154 additions and 89 deletions

View File

@ -477,6 +477,50 @@ SELECT POSITION(B'1101' IN b),
0 | 0 | 0000000000000001
(16 rows)
SELECT b, b >> 1 AS bsr, b << 1 AS bsl
FROM BIT_SHIFT_TABLE ;
b | bsr | bsl
------------------+------------------+------------------
1101100000000000 | 0110110000000000 | 1011000000000000
0110110000000000 | 0011011000000000 | 1101100000000000
0011011000000000 | 0001101100000000 | 0110110000000000
0001101100000000 | 0000110110000000 | 0011011000000000
0000110110000000 | 0000011011000000 | 0001101100000000
0000011011000000 | 0000001101100000 | 0000110110000000
0000001101100000 | 0000000110110000 | 0000011011000000
0000000110110000 | 0000000011011000 | 0000001101100000
0000000011011000 | 0000000001101100 | 0000000110110000
0000000001101100 | 0000000000110110 | 0000000011011000
0000000000110110 | 0000000000011011 | 0000000001101100
0000000000011011 | 0000000000001101 | 0000000000110110
0000000000001101 | 0000000000000110 | 0000000000011010
0000000000000110 | 0000000000000011 | 0000000000001100
0000000000000011 | 0000000000000001 | 0000000000000110
0000000000000001 | 0000000000000000 | 0000000000000010
(16 rows)
SELECT b::bit(15), b::bit(15) >> 1 AS bsr, b::bit(15) << 1 AS bsl
FROM BIT_SHIFT_TABLE ;
b | bsr | bsl
-----------------+-----------------+-----------------
110110000000000 | 011011000000000 | 101100000000000
011011000000000 | 001101100000000 | 110110000000000
001101100000000 | 000110110000000 | 011011000000000
000110110000000 | 000011011000000 | 001101100000000
000011011000000 | 000001101100000 | 000110110000000
000001101100000 | 000000110110000 | 000011011000000
000000110110000 | 000000011011000 | 000001101100000
000000011011000 | 000000001101100 | 000000110110000
000000001101100 | 000000000110110 | 000000011011000
000000000110110 | 000000000011011 | 000000001101100
000000000011011 | 000000000001101 | 000000000110110
000000000001101 | 000000000000110 | 000000000011010
000000000000110 | 000000000000011 | 000000000001100
000000000000011 | 000000000000001 | 000000000000110
000000000000001 | 000000000000000 | 000000000000010
000000000000000 | 000000000000000 | 000000000000000
(16 rows)
CREATE TABLE VARBIT_SHIFT_TABLE(v BIT VARYING(20));
INSERT INTO VARBIT_SHIFT_TABLE VALUES (B'11011');
INSERT INTO VARBIT_SHIFT_TABLE SELECT CAST(v || B'0' AS BIT VARYING(6)) >>1 FROM VARBIT_SHIFT_TABLE;
@ -507,6 +551,28 @@ SELECT POSITION(B'1101' IN v),
16 | 16 | 00000000000000011011
(16 rows)
SELECT v, v >> 1 AS vsr, v << 1 AS vsl
FROM VARBIT_SHIFT_TABLE ;
v | vsr | vsl
----------------------+----------------------+----------------------
11011 | 01101 | 10110
011011 | 001101 | 110110
0011011 | 0001101 | 0110110
00011011 | 00001101 | 00110110
000011011 | 000001101 | 000110110
0000011011 | 0000001101 | 0000110110
00000011011 | 00000001101 | 00000110110
000000011011 | 000000001101 | 000000110110
0000000011011 | 0000000001101 | 0000000110110
00000000011011 | 00000000001101 | 00000000110110
000000000011011 | 000000000001101 | 000000000110110
0000000000011011 | 0000000000001101 | 0000000000110110
00000000000011011 | 00000000000001101 | 00000000000110110
000000000000011011 | 000000000000001101 | 000000000000110110
0000000000000011011 | 0000000000000001101 | 0000000000000110110
00000000000000011011 | 00000000000000001101 | 00000000000000110110
(16 rows)
DROP TABLE BIT_SHIFT_TABLE;
DROP TABLE VARBIT_SHIFT_TABLE;
-- Get/Set bit

View File

@ -168,6 +168,10 @@ SELECT POSITION(B'1101' IN b),
POSITION(B'11011' IN b),
b
FROM BIT_SHIFT_TABLE ;
SELECT b, b >> 1 AS bsr, b << 1 AS bsl
FROM BIT_SHIFT_TABLE ;
SELECT b::bit(15), b::bit(15) >> 1 AS bsr, b::bit(15) << 1 AS bsl
FROM BIT_SHIFT_TABLE ;
CREATE TABLE VARBIT_SHIFT_TABLE(v BIT VARYING(20));
@ -180,7 +184,8 @@ SELECT POSITION(B'1101' IN v),
POSITION(B'11011' IN v),
v
FROM VARBIT_SHIFT_TABLE ;
SELECT v, v >> 1 AS vsr, v << 1 AS vsl
FROM VARBIT_SHIFT_TABLE ;
DROP TABLE BIT_SHIFT_TABLE;
DROP TABLE VARBIT_SHIFT_TABLE;