Fix bitshiftright()'s zero-padding some more.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 4 Oct 2019 14:34:21 +0000 (10:34 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 4 Oct 2019 14:34:40 +0000 (10:34 -0400)
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
src/test/regress/expected/bit.out
src/test/regress/sql/bit.sql

index c36d8ded40a0a164d0eb9492dc1da4e8153f7628..cf1c9cd99264751e4c55050e4f84e29243d8e151 100644 (file)
@@ -1483,6 +1483,7 @@ bitshiftright(PG_FUNCTION_ARGS)
        /* Special case: we can do a memcpy */
        len = VARBITBYTES(arg) - byte_shift;
        memcpy(r, p, len);
+       r += len;
    }
    else
    {
@@ -1494,10 +1495,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);
 }
 
index 255b39b07e29ffb4a922e90865aef2e8afee7746..a1fab7ebcb0758a9f5c5f0b5367136479e43c035 100644 (file)
@@ -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
index f47b8699207f3759ed82efc2f245faea0e7d7185..7681d4ab4d06daa3485f912eb2bba179b9a71158 100644 (file)
@@ -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;