aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/utils/adt/varbit.c165
1 files changed, 77 insertions, 88 deletions
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index d969a5b9c23..c36d8ded40a 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -3,6 +3,21 @@
* varbit.c
* Functions for the SQL datatypes BIT() and BIT VARYING().
*
+ * The data structure contains the following elements:
+ * header -- length of the whole data structure (incl header)
+ * in bytes (as with all varying length datatypes)
+ * data section -- private data section for the bits data structures
+ * bitlength -- length of the bit string in bits
+ * bitdata -- bit string, most significant byte first
+ *
+ * The length of the bitdata vector should always be exactly as many
+ * bytes as are needed for the given bitlength. If the bitlength is
+ * not a multiple of 8, the extra low-order padding bits of the last
+ * byte must be zeroes.
+ *
+ * attypmod is defined as the length of the bit string in bits, or for
+ * varying bits the maximum length.
+ *
* Code originally contributed by Adriaan Joubert.
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
@@ -27,6 +42,40 @@
#define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'A'))
+/* Mask off any bits that should be zero in the last byte of a bitstring */
+#define VARBIT_PAD(vb) \
+ do { \
+ int32 pad_ = VARBITPAD(vb); \
+ Assert(pad_ >= 0 && pad_ < BITS_PER_BYTE); \
+ if (pad_ > 0) \
+ *(VARBITS(vb) + VARBITBYTES(vb) - 1) &= BITMASK << pad_; \
+ } while (0)
+
+/*
+ * Many functions work byte-by-byte, so they have a pointer handy to the
+ * last-plus-one byte, which saves a cycle or two.
+ */
+#define VARBIT_PAD_LAST(vb, ptr) \
+ do { \
+ int32 pad_ = VARBITPAD(vb); \
+ Assert(pad_ >= 0 && pad_ < BITS_PER_BYTE); \
+ if (pad_ > 0) \
+ *((ptr) - 1) &= BITMASK << pad_; \
+ } while (0)
+
+/* Assert proper padding of a bitstring */
+#ifdef USE_ASSERT_CHECKING
+#define VARBIT_CORRECTLY_PADDED(vb) \
+ do { \
+ int32 pad_ = VARBITPAD(vb); \
+ Assert(pad_ >= 0 && pad_ < BITS_PER_BYTE); \
+ Assert(pad_ == 0 || \
+ (*(VARBITS(vb) + VARBITBYTES(vb) - 1) & ~(BITMASK << pad_)) == 0); \
+ } while (0)
+#else
+#define VARBIT_CORRECTLY_PADDED(vb) ((void) 0)
+#endif
+
static VarBit *bit_catenate(VarBit *arg1, VarBit *arg2);
static VarBit *bitsubstring(VarBit *arg, int32 s, int32 l,
bool length_not_specified);
@@ -87,24 +136,6 @@ anybit_typmodout(int32 typmod)
}
-/*----------
- * attypmod -- contains the length of the bit string in bits, or for
- * varying bits the maximum length.
- *
- * The data structure contains the following elements:
- * header -- length of the whole data structure (incl header)
- * in bytes. (as with all varying length datatypes)
- * data section -- private data section for the bits data structures
- * bitlength -- length of the bit string in bits
- * bitdata -- bit string, most significant byte first
- *
- * The length of the bitdata vector should always be exactly as many
- * bytes as are needed for the given bitlength. If the bitlength is
- * not a multiple of 8, the extra low-order padding bits of the last
- * byte must be zeroes.
- *----------
- */
-
/*
* bit_in -
* converts a char string to the internal representation of a bitstring.
@@ -264,6 +295,9 @@ bit_out(PG_FUNCTION_ARGS)
len,
bitlen;
+ /* Assertion to help catch any bit functions that don't pad correctly */
+ VARBIT_CORRECTLY_PADDED(s);
+
bitlen = VARBITLEN(s);
len = (bitlen + 3) / 4;
result = (char *) palloc(len + 2);
@@ -304,8 +338,6 @@ bit_recv(PG_FUNCTION_ARGS)
VarBit *result;
int len,
bitlen;
- int ipad;
- bits8 mask;
bitlen = pq_getmsgint(buf, sizeof(int32));
if (bitlen < 0 || bitlen > VARBITMAXLEN)
@@ -330,13 +362,8 @@ bit_recv(PG_FUNCTION_ARGS)
pq_copymsgbytes(buf, (char *) VARBITS(result), VARBITBYTES(result));
- /* Make sure last byte is zero-padded if needed */
- ipad = VARBITPAD(result);
- if (ipad > 0)
- {
- mask = BITMASK << ipad;
- *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
- }
+ /* Make sure last byte is correctly zero-padded */
+ VARBIT_PAD(result);
PG_RETURN_VARBIT_P(result);
}
@@ -367,8 +394,6 @@ bit(PG_FUNCTION_ARGS)
bool isExplicit = PG_GETARG_BOOL(2);
VarBit *result;
int rlen;
- int ipad;
- bits8 mask;
/* No work if typmod is invalid or supplied data matches it already */
if (len <= 0 || len > VARBITMAXLEN || len == VARBITLEN(arg))
@@ -394,12 +419,7 @@ bit(PG_FUNCTION_ARGS)
* if source data was shorter than target length (we assume the last byte
* of the source data was itself correctly zero-padded).
*/
- ipad = VARBITPAD(result);
- if (ipad > 0)
- {
- mask = BITMASK << ipad;
- *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
- }
+ VARBIT_PAD(result);
PG_RETURN_VARBIT_P(result);
}
@@ -574,6 +594,9 @@ varbit_out(PG_FUNCTION_ARGS)
k,
len;
+ /* Assertion to help catch any bit functions that don't pad correctly */
+ VARBIT_CORRECTLY_PADDED(s);
+
len = VARBITLEN(s);
result = (char *) palloc(len + 1);
sp = VARBITS(s);
@@ -620,8 +643,6 @@ varbit_recv(PG_FUNCTION_ARGS)
VarBit *result;
int len,
bitlen;
- int ipad;
- bits8 mask;
bitlen = pq_getmsgint(buf, sizeof(int32));
if (bitlen < 0 || bitlen > VARBITMAXLEN)
@@ -646,13 +667,8 @@ varbit_recv(PG_FUNCTION_ARGS)
pq_copymsgbytes(buf, (char *) VARBITS(result), VARBITBYTES(result));
- /* Make sure last byte is zero-padded if needed */
- ipad = VARBITPAD(result);
- if (ipad > 0)
- {
- mask = BITMASK << ipad;
- *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
- }
+ /* Make sure last byte is correctly zero-padded */
+ VARBIT_PAD(result);
PG_RETURN_VARBIT_P(result);
}
@@ -729,8 +745,6 @@ varbit(PG_FUNCTION_ARGS)
bool isExplicit = PG_GETARG_BOOL(2);
VarBit *result;
int rlen;
- int ipad;
- bits8 mask;
/* No work if typmod is invalid or supplied data matches it already */
if (len <= 0 || len >= VARBITLEN(arg))
@@ -749,13 +763,8 @@ varbit(PG_FUNCTION_ARGS)
memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result));
- /* Make sure last byte is zero-padded if needed */
- ipad = VARBITPAD(result);
- if (ipad > 0)
- {
- mask = BITMASK << ipad;
- *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
- }
+ /* Make sure last byte is correctly zero-padded */
+ VARBIT_PAD(result);
PG_RETURN_VARBIT_P(result);
}
@@ -1013,6 +1022,8 @@ bit_catenate(VarBit *arg1, VarBit *arg2)
}
}
+ /* The pad bits should be already zero at this point */
+
return result;
}
@@ -1046,14 +1057,12 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified)
int bitlen,
rbitlen,
len,
- ipad = 0,
ishift,
i;
int e,
s1,
e1;
- bits8 mask,
- *r,
+ bits8 *r,
*ps;
bitlen = VARBITLEN(arg);
@@ -1118,13 +1127,9 @@ bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified)
r++;
}
}
- /* Do we need to pad at the end? */
- ipad = VARBITPAD(result);
- if (ipad > 0)
- {
- mask = BITMASK << ipad;
- *(VARBITS(result) + len - 1) &= mask;
- }
+
+ /* Make sure last byte is correctly zero-padded */
+ VARBIT_PAD(result);
}
return result;
@@ -1246,7 +1251,7 @@ bit_and(PG_FUNCTION_ARGS)
for (i = 0; i < VARBITBYTES(arg1); i++)
*r++ = *p1++ & *p2++;
- /* Padding is not needed as & of 0 pad is 0 */
+ /* Padding is not needed as & of 0 pads is 0 */
PG_RETURN_VARBIT_P(result);
}
@@ -1268,7 +1273,6 @@ bit_or(PG_FUNCTION_ARGS)
bits8 *p1,
*p2,
*r;
- bits8 mask;
bitlen1 = VARBITLEN(arg1);
bitlen2 = VARBITLEN(arg2);
@@ -1287,13 +1291,7 @@ bit_or(PG_FUNCTION_ARGS)
for (i = 0; i < VARBITBYTES(arg1); i++)
*r++ = *p1++ | *p2++;
- /* Pad the result */
- mask = BITMASK << VARBITPAD(result);
- if (mask)
- {
- r--;
- *r &= mask;
- }
+ /* Padding is not needed as | of 0 pads is 0 */
PG_RETURN_VARBIT_P(result);
}
@@ -1315,7 +1313,6 @@ bitxor(PG_FUNCTION_ARGS)
bits8 *p1,
*p2,
*r;
- bits8 mask;
bitlen1 = VARBITLEN(arg1);
bitlen2 = VARBITLEN(arg2);
@@ -1335,13 +1332,7 @@ bitxor(PG_FUNCTION_ARGS)
for (i = 0; i < VARBITBYTES(arg1); i++)
*r++ = *p1++ ^ *p2++;
- /* Pad the result */
- mask = BITMASK << VARBITPAD(result);
- if (mask)
- {
- r--;
- *r &= mask;
- }
+ /* Padding is not needed as ^ of 0 pads is 0 */
PG_RETURN_VARBIT_P(result);
}
@@ -1357,7 +1348,6 @@ bitnot(PG_FUNCTION_ARGS)
VarBit *result;
bits8 *p,
*r;
- bits8 mask;
result = (VarBit *) palloc(VARSIZE(arg));
SET_VARSIZE(result, VARSIZE(arg));
@@ -1368,13 +1358,8 @@ bitnot(PG_FUNCTION_ARGS)
for (; p < VARBITEND(arg); p++)
*r++ = ~*p;
- /* Pad the result */
- mask = BITMASK << VARBITPAD(result);
- if (mask)
- {
- r--;
- *r &= mask;
- }
+ /* Must zero-pad the result, because extra bits are surely 1's here */
+ VARBIT_PAD_LAST(result, r);
PG_RETURN_VARBIT_P(result);
}
@@ -1441,6 +1426,8 @@ bitshiftleft(PG_FUNCTION_ARGS)
*r = 0;
}
+ /* The pad bits should be already zero at this point */
+
PG_RETURN_VARBIT_P(result);
}
@@ -1507,6 +1494,8 @@ 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);
}
PG_RETURN_VARBIT_P(result);