Skip to content

Commit 6e6b74a

Browse files
committed
Adjust bytea get_bit/set_bit to cope with bytea strings > 256MB.
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. However, it'd be good if they could do at least that much, and not fall over entirely for longer bytea values. Adjust the comparisons to be done in int64 arithmetic so that works. Also tweak the error reports to show sane values in case of overflow. Also add some test cases to improve the miserable code coverage of these functions. Apply patch to back branches only; HEAD has a better solution as of commit 26a944c. Extracted from a much larger patch by Movead Li Discussion: https://postgr.es/m/20200312115135445367128@highgo.ca
1 parent 3e62dd3 commit 6e6b74a

File tree

3 files changed

+105
-4
lines changed

3 files changed

+105
-4
lines changed

src/backend/utils/adt/varlena.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3443,11 +3443,12 @@ byteaGetBit(PG_FUNCTION_ARGS)
34433443

34443444
len = VARSIZE_ANY_EXHDR(v);
34453445

3446-
if (n < 0 || n >= len * 8)
3446+
/* Do comparison arithmetic in int64 in case len exceeds INT_MAX/8 */
3447+
if (n < 0 || n >= (int64) len * 8)
34473448
ereport(ERROR,
34483449
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
34493450
errmsg("index %d out of valid range, 0..%d",
3450-
n, len * 8 - 1)));
3451+
n, (int) Min((int64) len * 8 - 1, INT_MAX))));
34513452

34523453
byteNo = n / 8;
34533454
bitNo = n % 8;
@@ -3514,11 +3515,12 @@ byteaSetBit(PG_FUNCTION_ARGS)
35143515

35153516
len = VARSIZE(res) - VARHDRSZ;
35163517

3517-
if (n < 0 || n >= len * 8)
3518+
/* Do comparison arithmetic in int64 in case len exceeds INT_MAX/8 */
3519+
if (n < 0 || n >= (int64) len * 8)
35183520
ereport(ERROR,
35193521
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
35203522
errmsg("index %d out of valid range, 0..%d",
3521-
n, len * 8 - 1)));
3523+
n, (int) Min((int64) len * 8 - 1, INT_MAX))));
35223524

35233525
byteNo = n / 8;
35243526
bitNo = n % 8;

src/test/regress/expected/strings.out

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,82 @@ SELECT sha512('The quick brown fox jumps over the lazy dog.');
15941594
\x91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed
15951595
(1 row)
15961596

1597+
--
1598+
-- encode/decode
1599+
--
1600+
SELECT encode('\x1234567890abcdef00', 'hex');
1601+
encode
1602+
--------------------
1603+
1234567890abcdef00
1604+
(1 row)
1605+
1606+
SELECT decode('1234567890abcdef00', 'hex');
1607+
decode
1608+
----------------------
1609+
\x1234567890abcdef00
1610+
(1 row)
1611+
1612+
SELECT encode(('\x' || repeat('1234567890abcdef0001', 7))::bytea, 'base64');
1613+
encode
1614+
------------------------------------------------------------------------------
1615+
EjRWeJCrze8AARI0VniQq83vAAESNFZ4kKvN7wABEjRWeJCrze8AARI0VniQq83vAAESNFZ4kKvN+
1616+
7wABEjRWeJCrze8AAQ==
1617+
(1 row)
1618+
1619+
SELECT decode(encode(('\x' || repeat('1234567890abcdef0001', 7))::bytea,
1620+
'base64'), 'base64');
1621+
decode
1622+
------------------------------------------------------------------------------------------------------------------------------------------------
1623+
\x1234567890abcdef00011234567890abcdef00011234567890abcdef00011234567890abcdef00011234567890abcdef00011234567890abcdef00011234567890abcdef0001
1624+
(1 row)
1625+
1626+
SELECT encode('\x1234567890abcdef00', 'escape');
1627+
encode
1628+
-----------------------------
1629+
\x124Vx\220\253\315\357\000
1630+
(1 row)
1631+
1632+
SELECT decode(encode('\x1234567890abcdef00', 'escape'), 'escape');
1633+
decode
1634+
----------------------
1635+
\x1234567890abcdef00
1636+
(1 row)
1637+
1638+
--
1639+
-- get_bit/set_bit etc
1640+
--
1641+
SELECT get_bit('\x1234567890abcdef00'::bytea, 43);
1642+
get_bit
1643+
---------
1644+
1
1645+
(1 row)
1646+
1647+
SELECT get_bit('\x1234567890abcdef00'::bytea, 99); -- error
1648+
ERROR: index 99 out of valid range, 0..71
1649+
SELECT set_bit('\x1234567890abcdef00'::bytea, 43, 0);
1650+
set_bit
1651+
----------------------
1652+
\x1234567890a3cdef00
1653+
(1 row)
1654+
1655+
SELECT set_bit('\x1234567890abcdef00'::bytea, 99, 0); -- error
1656+
ERROR: index 99 out of valid range, 0..71
1657+
SELECT get_byte('\x1234567890abcdef00'::bytea, 3);
1658+
get_byte
1659+
----------
1660+
120
1661+
(1 row)
1662+
1663+
SELECT get_byte('\x1234567890abcdef00'::bytea, 99); -- error
1664+
ERROR: index 99 out of valid range, 0..8
1665+
SELECT set_byte('\x1234567890abcdef00'::bytea, 7, 11);
1666+
set_byte
1667+
----------------------
1668+
\x1234567890abcd0b00
1669+
(1 row)
1670+
1671+
SELECT set_byte('\x1234567890abcdef00'::bytea, 99, 11); -- error
1672+
ERROR: index 99 out of valid range, 0..8
15971673
--
15981674
-- test behavior of escape_string_warning and standard_conforming_strings options
15991675
--

src/test/regress/sql/strings.sql

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,29 @@ SELECT sha384('The quick brown fox jumps over the lazy dog.');
563563
SELECT sha512('');
564564
SELECT sha512('The quick brown fox jumps over the lazy dog.');
565565

566+
--
567+
-- encode/decode
568+
--
569+
SELECT encode('\x1234567890abcdef00', 'hex');
570+
SELECT decode('1234567890abcdef00', 'hex');
571+
SELECT encode(('\x' || repeat('1234567890abcdef0001', 7))::bytea, 'base64');
572+
SELECT decode(encode(('\x' || repeat('1234567890abcdef0001', 7))::bytea,
573+
'base64'), 'base64');
574+
SELECT encode('\x1234567890abcdef00', 'escape');
575+
SELECT decode(encode('\x1234567890abcdef00', 'escape'), 'escape');
576+
577+
--
578+
-- get_bit/set_bit etc
579+
--
580+
SELECT get_bit('\x1234567890abcdef00'::bytea, 43);
581+
SELECT get_bit('\x1234567890abcdef00'::bytea, 99); -- error
582+
SELECT set_bit('\x1234567890abcdef00'::bytea, 43, 0);
583+
SELECT set_bit('\x1234567890abcdef00'::bytea, 99, 0); -- error
584+
SELECT get_byte('\x1234567890abcdef00'::bytea, 3);
585+
SELECT get_byte('\x1234567890abcdef00'::bytea, 99); -- error
586+
SELECT set_byte('\x1234567890abcdef00'::bytea, 7, 11);
587+
SELECT set_byte('\x1234567890abcdef00'::bytea, 99, 11); -- error
588+
566589
--
567590
-- test behavior of escape_string_warning and standard_conforming_strings options
568591
--

0 commit comments

Comments
 (0)