mirror of
https://github.com/postgres/postgres.git
synced 2025-11-19 13:42:17 +03:00
Adjust bytea get_bit/set_bit to use int8 not int4 for bit numbering.
Since the existing bit number argument can't exceed INT32_MAX, it's not possible for these functions to manipulate bits beyond the first 256MB of a bytea value. Lift that restriction by redeclaring the bit number arguments as int8 (which requires a catversion bump, hence is not back-patchable). The similarly-named functions for bit/varbit don't really have a problem because we restrict those types to at most VARBITMAXLEN bits; hence leave them alone. While here, extend the encode/decode functions in utils/adt/encode.c to allow dealing with values wider than 1GB. This is not a live bug or restriction in current usage, because no input could be more than 1GB, and since none of the encoders can expand a string more than 4X, the result size couldn't overflow uint32. But it might be desirable to support more in future, so make the input length values size_t and the potential-output-length values uint64. Also add some test cases to improve the miserable code coverage of these functions. Movead Li, editorialized some by me; also reviewed by Ashutosh Bapat Discussion: https://postgr.es/m/20200312115135445367128@highgo.ca
This commit is contained in:
@@ -389,7 +389,7 @@ byteaout(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/* Print traditional escaped format */
|
||||
char *vp;
|
||||
int len;
|
||||
uint64 len;
|
||||
int i;
|
||||
|
||||
len = 1; /* empty string has 1 char */
|
||||
@@ -403,7 +403,18 @@ byteaout(PG_FUNCTION_ARGS)
|
||||
else
|
||||
len++;
|
||||
}
|
||||
|
||||
/*
|
||||
* In principle len can't overflow uint32 if the input fit in 1GB, but
|
||||
* for safety let's check rather than relying on palloc's internal
|
||||
* check.
|
||||
*/
|
||||
if (len > MaxAllocSize)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg_internal("result of bytea output conversion is too large")));
|
||||
rp = result = (char *) palloc(len);
|
||||
|
||||
vp = VARDATA_ANY(vlena);
|
||||
for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++)
|
||||
{
|
||||
@@ -3456,7 +3467,7 @@ Datum
|
||||
byteaGetBit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bytea *v = PG_GETARG_BYTEA_PP(0);
|
||||
int32 n = PG_GETARG_INT32(1);
|
||||
int64 n = PG_GETARG_INT64(1);
|
||||
int byteNo,
|
||||
bitNo;
|
||||
int len;
|
||||
@@ -3464,14 +3475,15 @@ byteaGetBit(PG_FUNCTION_ARGS)
|
||||
|
||||
len = VARSIZE_ANY_EXHDR(v);
|
||||
|
||||
if (n < 0 || n >= len * 8)
|
||||
if (n < 0 || n >= (int64) len * 8)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("index %d out of valid range, 0..%d",
|
||||
n, len * 8 - 1)));
|
||||
errmsg("index %lld out of valid range, 0..%lld",
|
||||
(long long) n, (long long) len * 8 - 1)));
|
||||
|
||||
byteNo = n / 8;
|
||||
bitNo = n % 8;
|
||||
/* n/8 is now known < len, so safe to cast to int */
|
||||
byteNo = (int) (n / 8);
|
||||
bitNo = (int) (n % 8);
|
||||
|
||||
byte = ((unsigned char *) VARDATA_ANY(v))[byteNo];
|
||||
|
||||
@@ -3525,7 +3537,7 @@ Datum
|
||||
byteaSetBit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bytea *res = PG_GETARG_BYTEA_P_COPY(0);
|
||||
int32 n = PG_GETARG_INT32(1);
|
||||
int64 n = PG_GETARG_INT64(1);
|
||||
int32 newBit = PG_GETARG_INT32(2);
|
||||
int len;
|
||||
int oldByte,
|
||||
@@ -3535,14 +3547,15 @@ byteaSetBit(PG_FUNCTION_ARGS)
|
||||
|
||||
len = VARSIZE(res) - VARHDRSZ;
|
||||
|
||||
if (n < 0 || n >= len * 8)
|
||||
if (n < 0 || n >= (int64) len * 8)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("index %d out of valid range, 0..%d",
|
||||
n, len * 8 - 1)));
|
||||
errmsg("index %lld out of valid range, 0..%lld",
|
||||
(long long) n, (long long) len * 8 - 1)));
|
||||
|
||||
byteNo = n / 8;
|
||||
bitNo = n % 8;
|
||||
/* n/8 is now known < len, so safe to cast to int */
|
||||
byteNo = (int) (n / 8);
|
||||
bitNo = (int) (n % 8);
|
||||
|
||||
/*
|
||||
* sanity check!
|
||||
|
||||
Reference in New Issue
Block a user