diff --git a/src/backend/utils/adt/encode.c b/src/backend/utils/adt/encode.c index b8d9ec7e00..5be5739501 100644 --- a/src/backend/utils/adt/encode.c +++ b/src/backend/utils/adt/encode.c @@ -20,10 +20,10 @@ struct pg_encoding { - unsigned (*encode_len) (const char *data, unsigned dlen); - unsigned (*decode_len) (const char *data, unsigned dlen); - unsigned (*encode) (const char *data, unsigned dlen, char *res); - unsigned (*decode) (const char *data, unsigned dlen, char *res); + uint64 (*encode_len) (const char *data, size_t dlen); + uint64 (*decode_len) (const char *data, size_t dlen); + uint64 (*encode) (const char *data, size_t dlen, char *res); + uint64 (*decode) (const char *data, size_t dlen, char *res); }; static const struct pg_encoding *pg_find_encoding(const char *name); @@ -39,9 +39,9 @@ binary_encode(PG_FUNCTION_ARGS) Datum name = PG_GETARG_DATUM(1); text *result; char *namebuf; - int datalen, - resultlen, - res; + size_t datalen; + uint64 res; + uint64 resultlen; const struct pg_encoding *enc; datalen = VARSIZE_ANY_EXHDR(data); @@ -75,9 +75,9 @@ binary_decode(PG_FUNCTION_ARGS) Datum name = PG_GETARG_DATUM(1); bytea *result; char *namebuf; - int datalen, - resultlen, - res; + size_t datalen; + uint64 resultlen; + uint64 res; const struct pg_encoding *enc; datalen = VARSIZE_ANY_EXHDR(data); @@ -122,8 +122,8 @@ static const int8 hexlookup[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; -unsigned -hex_encode(const char *src, unsigned len, char *dst) +uint64 +hex_encode(const char *src, size_t len, char *dst) { const char *end = src + len; @@ -133,7 +133,7 @@ hex_encode(const char *src, unsigned len, char *dst) *dst++ = hextbl[*src & 0xF]; src++; } - return len * 2; + return (int64)len * 2; } static inline char @@ -152,8 +152,8 @@ get_hex(char c) return (char) res; } -unsigned -hex_decode(const char *src, unsigned len, char *dst) +uint64 +hex_decode(const char *src, size_t len, char *dst) { const char *s, *srcend; @@ -184,16 +184,16 @@ hex_decode(const char *src, unsigned len, char *dst) return p - dst; } -static unsigned -hex_enc_len(const char *src, unsigned srclen) +static uint64 +hex_enc_len(const char *src, size_t srclen) { - return srclen << 1; + return (uint64)srclen << 1; } -static unsigned -hex_dec_len(const char *src, unsigned srclen) +static uint64 +hex_dec_len(const char *src, size_t srclen) { - return srclen >> 1; + return (uint64)srclen >> 1; } /* @@ -214,8 +214,8 @@ static const int8 b64lookup[128] = { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, }; -static unsigned -pg_base64_encode(const char *src, unsigned len, char *dst) +static uint64 +pg_base64_encode(const char *src, size_t len, char *dst) { char *p, *lend = dst + 76; @@ -261,8 +261,8 @@ pg_base64_encode(const char *src, unsigned len, char *dst) return p - dst; } -static unsigned -pg_base64_decode(const char *src, unsigned len, char *dst) +static uint64 +pg_base64_decode(const char *src, size_t len, char *dst) { const char *srcend = src + len, *s = src; @@ -331,17 +331,17 @@ pg_base64_decode(const char *src, unsigned len, char *dst) } -static unsigned -pg_base64_enc_len(const char *src, unsigned srclen) +static uint64 +pg_base64_enc_len(const char *src, size_t srclen) { /* 3 bytes will be converted to 4, linefeed after 76 chars */ - return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4); + return ((uint64)srclen + 2) * 4 / 3 + (uint64)srclen / (76 * 3 / 4); } -static unsigned -pg_base64_dec_len(const char *src, unsigned srclen) +static uint64 +pg_base64_dec_len(const char *src, size_t srclen) { - return (srclen * 3) >> 2; + return ((uint64)srclen * 3) >> 2; } /* @@ -361,12 +361,12 @@ pg_base64_dec_len(const char *src, unsigned srclen) #define VAL(CH) ((CH) - '0') #define DIG(VAL) ((VAL) + '0') -static unsigned -esc_encode(const char *src, unsigned srclen, char *dst) +static uint64 +esc_encode(const char *src, size_t srclen, char *dst) { const char *end = src + srclen; char *rp = dst; - int len = 0; + uint64 len = 0; while (src < end) { @@ -400,12 +400,12 @@ esc_encode(const char *src, unsigned srclen, char *dst) return len; } -static unsigned -esc_decode(const char *src, unsigned srclen, char *dst) +static uint64 +esc_decode(const char *src, size_t srclen, char *dst) { const char *end = src + srclen; char *rp = dst; - int len = 0; + uint64 len = 0; while (src < end) { @@ -448,11 +448,11 @@ esc_decode(const char *src, unsigned srclen, char *dst) return len; } -static unsigned -esc_enc_len(const char *src, unsigned srclen) +static uint64 +esc_enc_len(const char *src, size_t srclen) { const char *end = src + srclen; - int len = 0; + uint64 len = 0; while (src < end) { @@ -469,11 +469,11 @@ esc_enc_len(const char *src, unsigned srclen) return len; } -static unsigned -esc_dec_len(const char *src, unsigned srclen) +static uint64 +esc_dec_len(const char *src, size_t srclen) { const char *end = src + srclen; - int len = 0; + uint64 len = 0; while (src < end) { diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 907b5ab7b0..47aa5be3a9 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -388,7 +388,7 @@ byteaout(PG_FUNCTION_ARGS) { /* Print traditional escaped format */ char *vp; - int len; + int64 len; int i; len = 1; /* empty string has 1 char */ @@ -3455,7 +3455,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; @@ -3463,14 +3463,17 @@ 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))); - - byteNo = n / 8; - bitNo = n % 8; + errmsg("index "INT64_FORMAT" out of valid range, 0.."INT64_FORMAT, + n, (int64)len * 8 - 1))); + /* + * The value of 'n' is smaller than 'len * 8', and 'len' is by int type, + * so it is safe to downcasting 'n' from int64 to int. + */ + byteNo = (int)(n / 8); + bitNo = (int)(n % 8); byte = ((unsigned char *) VARDATA_ANY(v))[byteNo]; @@ -3524,7 +3527,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, @@ -3534,14 +3537,17 @@ 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))); - - byteNo = n / 8; - bitNo = n % 8; + errmsg("index "INT64_FORMAT" out of valid range, 0.."INT64_FORMAT, + n, (int64)len * 8 - 1))); + /* + * The value of 'n' is smaller than 'len * 8', and 'len' is by int type, + * so it is safe to downcasting 'n' from int64 to int. + */ + byteNo = (int64)(n / 8); + bitNo = (int64)(n % 8); /* * sanity check! diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index a6a708cca9..218af5ab2f 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -1403,10 +1403,10 @@ proname => 'set_byte', prorettype => 'bytea', proargtypes => 'bytea int4 int4', prosrc => 'byteaSetByte' }, { oid => '723', descr => 'get bit', - proname => 'get_bit', prorettype => 'int4', proargtypes => 'bytea int4', + proname => 'get_bit', prorettype => 'int4', proargtypes => 'bytea int8', prosrc => 'byteaGetBit' }, { oid => '724', descr => 'set bit', - proname => 'set_bit', prorettype => 'bytea', proargtypes => 'bytea int4 int4', + proname => 'set_bit', prorettype => 'bytea', proargtypes => 'bytea int8 int4', prosrc => 'byteaSetBit' }, { oid => '749', descr => 'substitute portion of string', proname => 'overlay', prorettype => 'bytea', diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index e2016a8bc2..a352a8b773 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -32,8 +32,8 @@ extern int errdatatype(Oid datatypeOid); extern int errdomainconstraint(Oid datatypeOid, const char *conname); /* encode.c */ -extern unsigned hex_encode(const char *src, unsigned len, char *dst); -extern unsigned hex_decode(const char *src, unsigned len, char *dst); +extern uint64 hex_encode(const char *src, size_t len, char *dst); +extern uint64 hex_decode(const char *src, size_t len, char *dst); /* int.c */ extern int2vector *buildint2vector(const int16 *int2s, int n); diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out index a1fab7ebcb..8e56289968 100644 --- a/src/test/regress/expected/bit.out +++ b/src/test/regress/expected/bit.out @@ -656,6 +656,40 @@ SELECT set_bit(B'0101011000100100', 15, 1); SELECT set_bit(B'0101011000100100', 16, 1); -- fail ERROR: bit index 16 out of valid range (0..15) +SELECT get_bit( + set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, 0, 0) + ,0); + get_bit +--------- + 0 +(1 row) + +SELECT get_bit( + set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, 0, 1) + ,0); + get_bit +--------- + 1 +(1 row) + +select get_bit( + set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, + 512::bigint * 1024 * 1024 * 8 - 1, 0) + ,512::bigint * 1024 * 1024 * 8 - 1); + get_bit +--------- + 0 +(1 row) + +select get_bit( + set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, + 512::bigint * 1024 * 1024 * 8 - 1, 1) + ,512::bigint * 1024 * 1024 * 8 - 1); + get_bit +--------- + 1 +(1 row) + -- Overlay SELECT overlay(B'0101011100' placing '001' from 2 for 3); overlay diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql index 7681d4ab4d..5914095941 100644 --- a/src/test/regress/sql/bit.sql +++ b/src/test/regress/sql/bit.sql @@ -200,6 +200,21 @@ DROP TABLE VARBIT_SHIFT_TABLE; SELECT get_bit(B'0101011000100', 10); SELECT set_bit(B'0101011000100100', 15, 1); SELECT set_bit(B'0101011000100100', 16, 1); -- fail +SELECT get_bit( + set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, 0, 0) + ,0); +SELECT get_bit( + set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, 0, 1) + ,0); +select get_bit( + set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, + 512::bigint * 1024 * 1024 * 8 - 1, 0) + ,512::bigint * 1024 * 1024 * 8 - 1); +select get_bit( + set_bit((repeat('Postgres', 512 * 1024 * 1024 / 8))::bytea, + 512::bigint * 1024 * 1024 * 8 - 1, 1) + ,512::bigint * 1024 * 1024 * 8 - 1); + -- Overlay SELECT overlay(B'0101011100' placing '001' from 2 for 3);