From 30e5b3bbe9ca9f3594816788fe4469798da04f64 Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 4 Oct 2019 10:34:21 -0400 Subject: [PATCH] Fix bitshiftright()'s zero-padding some more. Commit 5ac0d9360 failed to entirely fix bitshiftright's habit of leaving one-bits in the pad space that should be all zeroes, because in a moment of sheer brain fade I'd concluded that only the code path used for not-a-multiple-of-8 shift distances needed to be fixed. Of course, a multiple-of-8 shift distance can also cause the problem, so we need to forcibly zero the extra bits in both cases. Per bug #16037 from Alexander Lakhin. As before, back-patch to all supported branches. Discussion: https://postgr.es/m/16037-1d1ebca564db54f4@postgresql.org --- src/backend/utils/adt/varbit.c | 6 ++- src/test/regress/expected/bit.out | 66 +++++++++++++++++++++++++++++++ src/test/regress/sql/bit.sql | 6 +++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 3b409d7d3b..ef57fdac78 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -1473,6 +1473,7 @@ bitshiftright(PG_FUNCTION_ARGS) /* Special case: we can do a memcpy */ len = VARBITBYTES(arg) - byte_shift; memcpy(r, p, len); + r += len; } else { @@ -1484,10 +1485,11 @@ bitshiftright(PG_FUNCTION_ARGS) if ((++r) < VARBITEND(result)) *r = (*p << (BITS_PER_BYTE - ishift)) & BITMASK; } - /* We may have shifted 1's into the pad bits, so fix that */ - VARBIT_PAD_LAST(result, r); } + /* We may have shifted 1's into the pad bits, so fix that */ + VARBIT_PAD_LAST(result, r); + PG_RETURN_VARBIT_P(result); } diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out index 07491bb84c..657b91a89f 100644 --- a/src/test/regress/expected/bit.out +++ b/src/test/regress/expected/bit.out @@ -499,6 +499,28 @@ SELECT b, b >> 1 AS bsr, b << 1 AS bsl 0000000000000001 | 0000000000000000 | 0000000000000010 (16 rows) +SELECT b, b >> 8 AS bsr8, b << 8 AS bsl8 + FROM BIT_SHIFT_TABLE ; + b | bsr8 | bsl8 +------------------+------------------+------------------ + 1101100000000000 | 0000000011011000 | 0000000000000000 + 0110110000000000 | 0000000001101100 | 0000000000000000 + 0011011000000000 | 0000000000110110 | 0000000000000000 + 0001101100000000 | 0000000000011011 | 0000000000000000 + 0000110110000000 | 0000000000001101 | 1000000000000000 + 0000011011000000 | 0000000000000110 | 1100000000000000 + 0000001101100000 | 0000000000000011 | 0110000000000000 + 0000000110110000 | 0000000000000001 | 1011000000000000 + 0000000011011000 | 0000000000000000 | 1101100000000000 + 0000000001101100 | 0000000000000000 | 0110110000000000 + 0000000000110110 | 0000000000000000 | 0011011000000000 + 0000000000011011 | 0000000000000000 | 0001101100000000 + 0000000000001101 | 0000000000000000 | 0000110100000000 + 0000000000000110 | 0000000000000000 | 0000011000000000 + 0000000000000011 | 0000000000000000 | 0000001100000000 + 0000000000000001 | 0000000000000000 | 0000000100000000 +(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 @@ -521,6 +543,28 @@ SELECT b::bit(15), b::bit(15) >> 1 AS bsr, b::bit(15) << 1 AS bsl 000000000000000 | 000000000000000 | 000000000000000 (16 rows) +SELECT b::bit(15), b::bit(15) >> 8 AS bsr8, b::bit(15) << 8 AS bsl8 + FROM BIT_SHIFT_TABLE ; + b | bsr8 | bsl8 +-----------------+-----------------+----------------- + 110110000000000 | 000000001101100 | 000000000000000 + 011011000000000 | 000000000110110 | 000000000000000 + 001101100000000 | 000000000011011 | 000000000000000 + 000110110000000 | 000000000001101 | 000000000000000 + 000011011000000 | 000000000000110 | 100000000000000 + 000001101100000 | 000000000000011 | 110000000000000 + 000000110110000 | 000000000000001 | 011000000000000 + 000000011011000 | 000000000000000 | 101100000000000 + 000000001101100 | 000000000000000 | 110110000000000 + 000000000110110 | 000000000000000 | 011011000000000 + 000000000011011 | 000000000000000 | 001101100000000 + 000000000001101 | 000000000000000 | 000110100000000 + 000000000000110 | 000000000000000 | 000011000000000 + 000000000000011 | 000000000000000 | 000001100000000 + 000000000000001 | 000000000000000 | 000000100000000 + 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; @@ -573,6 +617,28 @@ SELECT v, v >> 1 AS vsr, v << 1 AS vsl 00000000000000011011 | 00000000000000001101 | 00000000000000110110 (16 rows) +SELECT v, v >> 8 AS vsr8, v << 8 AS vsl8 + FROM VARBIT_SHIFT_TABLE ; + v | vsr8 | vsl8 +----------------------+----------------------+---------------------- + 11011 | 00000 | 00000 + 011011 | 000000 | 000000 + 0011011 | 0000000 | 0000000 + 00011011 | 00000000 | 00000000 + 000011011 | 000000000 | 100000000 + 0000011011 | 0000000000 | 1100000000 + 00000011011 | 00000000000 | 01100000000 + 000000011011 | 000000000000 | 101100000000 + 0000000011011 | 0000000000000 | 1101100000000 + 00000000011011 | 00000000000000 | 01101100000000 + 000000000011011 | 000000000000000 | 001101100000000 + 0000000000011011 | 0000000000000000 | 0001101100000000 + 00000000000011011 | 00000000000000000 | 00001101100000000 + 000000000000011011 | 000000000000000000 | 000001101100000000 + 0000000000000011011 | 0000000000000000000 | 0000001101100000000 + 00000000000000011011 | 00000000000000000000 | 00000001101100000000 +(16 rows) + DROP TABLE BIT_SHIFT_TABLE; DROP TABLE VARBIT_SHIFT_TABLE; -- Get/Set bit diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql index cf2460b212..a740c28e2d 100644 --- a/src/test/regress/sql/bit.sql +++ b/src/test/regress/sql/bit.sql @@ -170,8 +170,12 @@ SELECT POSITION(B'1101' IN b), FROM BIT_SHIFT_TABLE ; SELECT b, b >> 1 AS bsr, b << 1 AS bsl FROM BIT_SHIFT_TABLE ; +SELECT b, b >> 8 AS bsr8, b << 8 AS bsl8 + FROM BIT_SHIFT_TABLE ; SELECT b::bit(15), b::bit(15) >> 1 AS bsr, b::bit(15) << 1 AS bsl FROM BIT_SHIFT_TABLE ; +SELECT b::bit(15), b::bit(15) >> 8 AS bsr8, b::bit(15) << 8 AS bsl8 + FROM BIT_SHIFT_TABLE ; CREATE TABLE VARBIT_SHIFT_TABLE(v BIT VARYING(20)); @@ -186,6 +190,8 @@ SELECT POSITION(B'1101' IN v), FROM VARBIT_SHIFT_TABLE ; SELECT v, v >> 1 AS vsr, v << 1 AS vsl FROM VARBIT_SHIFT_TABLE ; +SELECT v, v >> 8 AS vsr8, v << 8 AS vsl8 + FROM VARBIT_SHIFT_TABLE ; DROP TABLE BIT_SHIFT_TABLE; DROP TABLE VARBIT_SHIFT_TABLE; -- 2.40.0