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:21 +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 3b409d7d3b3a5a1c10dc09af18473a3ff049e708..ef57fdac78d0ce394baa673a0f3044467d91711b 100644 (file)
@@ -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);
 }
 
index 07491bb84caa217dd9b59ddb89f07b9fdd669f4b..657b91a89fdbc504fd7bfd7e3c5573bb0af0dac1 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 cf2460b2122cfe3e7cef560428758c9dfe001920..a740c28e2dbcf25b02ffcf871b444df785f59079 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;