Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ce1fa4a

Browse files
author
Commitfest Bot
committed
[CF 5176] v10 - Allow casting between bytea and integer types
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5176 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/CAEZATCUQhKQ+i-R2ELvNL4YFKq68Qb4QUNpa-zYFZF2OeoQp=w@mail.gmail.com Author(s): Aleksander Alekseev
2 parents 0e76f25 + 1b35729 commit ce1fa4a

File tree

7 files changed

+274
-0
lines changed

7 files changed

+274
-0
lines changed

doc/src/sgml/func.sgml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5035,6 +5035,23 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
50355035
</variablelist>
50365036
</para>
50375037

5038+
<para>
5039+
In addition, it is possible to cast integral values to and from type
5040+
<type>bytea</type>. Casting an integer to <type>bytea</type> produces
5041+
2, 4, or 8 bytes, depending on the width of the integer type. The result
5042+
is the two's complement representation of the integer, with the most
5043+
significant byte first. Some examples:
5044+
<programlisting>
5045+
1234::smallint::bytea <lineannotation>\x04d2</lineannotation>
5046+
cast(1234 as bytea) <lineannotation>\x000004d2</lineannotation>
5047+
cast(-1234 as bytea) <lineannotation>\xfffffb2e</lineannotation>
5048+
'\x8000'::bytea::smallint <lineannotation>-32768</lineannotation>
5049+
'\x8000'::bytea::integer <lineannotation>32768</lineannotation>
5050+
</programlisting>
5051+
Casting a <type>bytea</type> to an integer will raise an error if the
5052+
length of the <type>bytea</type> exceeds the width of the integer type.
5053+
</para>
5054+
50385055
<para>
50395056
See also the aggregate function <function>string_agg</function> in
50405057
<xref linkend="functions-aggregate"/> and the large object functions

src/backend/utils/adt/varlena.c

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4057,6 +4057,96 @@ bytea_sortsupport(PG_FUNCTION_ARGS)
40574057
PG_RETURN_VOID();
40584058
}
40594059

4060+
/* Cast bytea -> int2 */
4061+
Datum
4062+
bytea_int2(PG_FUNCTION_ARGS)
4063+
{
4064+
bytea *v = PG_GETARG_BYTEA_PP(0);
4065+
int len = VARSIZE_ANY_EXHDR(v);
4066+
uint16 result;
4067+
4068+
if (len > sizeof(result))
4069+
ereport(ERROR,
4070+
errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4071+
errmsg("smallint out of range"));
4072+
4073+
result = 0;
4074+
for (int i = 0; i < len; i++)
4075+
{
4076+
result <<= BITS_PER_BYTE;
4077+
result |= ((unsigned char *) VARDATA_ANY(v))[i];
4078+
}
4079+
4080+
PG_RETURN_INT16(result);
4081+
}
4082+
4083+
/* Cast bytea -> int4 */
4084+
Datum
4085+
bytea_int4(PG_FUNCTION_ARGS)
4086+
{
4087+
bytea *v = PG_GETARG_BYTEA_PP(0);
4088+
int len = VARSIZE_ANY_EXHDR(v);
4089+
uint32 result;
4090+
4091+
if (len > sizeof(result))
4092+
ereport(ERROR,
4093+
errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4094+
errmsg("integer out of range"));
4095+
4096+
result = 0;
4097+
for (int i = 0; i < len; i++)
4098+
{
4099+
result <<= BITS_PER_BYTE;
4100+
result |= ((unsigned char *) VARDATA_ANY(v))[i];
4101+
}
4102+
4103+
PG_RETURN_INT32(result);
4104+
}
4105+
4106+
/* Cast bytea -> int8 */
4107+
Datum
4108+
bytea_int8(PG_FUNCTION_ARGS)
4109+
{
4110+
bytea *v = PG_GETARG_BYTEA_PP(0);
4111+
int len = VARSIZE_ANY_EXHDR(v);
4112+
uint64 result;
4113+
4114+
if (len > sizeof(result))
4115+
ereport(ERROR,
4116+
errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4117+
errmsg("bigint out of range"));
4118+
4119+
result = 0;
4120+
for (int i = 0; i < len; i++)
4121+
{
4122+
result <<= BITS_PER_BYTE;
4123+
result |= ((unsigned char *) VARDATA_ANY(v))[i];
4124+
}
4125+
4126+
PG_RETURN_INT64(result);
4127+
}
4128+
4129+
/* Cast int2 -> bytea; can just use int2send() */
4130+
Datum
4131+
int2_bytea(PG_FUNCTION_ARGS)
4132+
{
4133+
return int2send(fcinfo);
4134+
}
4135+
4136+
/* Cast int4 -> bytea; can just use int4send() */
4137+
Datum
4138+
int4_bytea(PG_FUNCTION_ARGS)
4139+
{
4140+
return int4send(fcinfo);
4141+
}
4142+
4143+
/* Cast int8 -> bytea; can just use int8send() */
4144+
Datum
4145+
int8_bytea(PG_FUNCTION_ARGS)
4146+
{
4147+
return int8send(fcinfo);
4148+
}
4149+
40604150
/*
40614151
* appendStringInfoText
40624152
*

src/include/catalog/pg_cast.dat

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,20 @@
320320
{ castsource => 'varchar', casttarget => 'name', castfunc => 'name(varchar)',
321321
castcontext => 'i', castmethod => 'f' },
322322

323+
# Allow explicit coercions between bytea and integer types
324+
{ castsource => 'int2', casttarget => 'bytea', castfunc => 'bytea(int2)',
325+
castcontext => 'e', castmethod => 'f' },
326+
{ castsource => 'int4', casttarget => 'bytea', castfunc => 'bytea(int4)',
327+
castcontext => 'e', castmethod => 'f' },
328+
{ castsource => 'int8', casttarget => 'bytea', castfunc => 'bytea(int8)',
329+
castcontext => 'e', castmethod => 'f' },
330+
{ castsource => 'bytea', casttarget => 'int2', castfunc => 'int2(bytea)',
331+
castcontext => 'e', castmethod => 'f' },
332+
{ castsource => 'bytea', casttarget => 'int4', castfunc => 'int4(bytea)',
333+
castcontext => 'e', castmethod => 'f' },
334+
{ castsource => 'bytea', casttarget => 'int8', castfunc => 'int8(bytea)',
335+
castcontext => 'e', castmethod => 'f' },
336+
323337
# Allow explicit coercions between int4 and "char"
324338
{ castsource => 'char', casttarget => 'int4', castfunc => 'int4(char)',
325339
castcontext => 'e', castmethod => 'f' },

src/include/catalog/pg_proc.dat

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,25 @@
11651165
proname => 'name', proleakproof => 't', prorettype => 'name',
11661166
proargtypes => 'bpchar', prosrc => 'bpchar_name' },
11671167

1168+
{ oid => '8577', descr => 'convert int2 to bytea',
1169+
proname => 'bytea', proleakproof => 't', prorettype => 'bytea',
1170+
proargtypes => 'int2', prosrc => 'int2_bytea' },
1171+
{ oid => '8578', descr => 'convert int4 to bytea',
1172+
proname => 'bytea', proleakproof => 't', prorettype => 'bytea',
1173+
proargtypes => 'int4', prosrc => 'int4_bytea' },
1174+
{ oid => '8579', descr => 'convert int8 to bytea',
1175+
proname => 'bytea', proleakproof => 't', prorettype => 'bytea',
1176+
proargtypes => 'int8', prosrc => 'int8_bytea' },
1177+
{ oid => '8580', descr => 'convert bytea to int2',
1178+
proname => 'int2', prorettype => 'int2',
1179+
proargtypes => 'bytea', prosrc => 'bytea_int2' },
1180+
{ oid => '8581', descr => 'convert bytea to int4',
1181+
proname => 'int4', prorettype => 'int4',
1182+
proargtypes => 'bytea', prosrc => 'bytea_int4' },
1183+
{ oid => '8582', descr => 'convert bytea to int8',
1184+
proname => 'int8', prorettype => 'int8',
1185+
proargtypes => 'bytea', prosrc => 'bytea_int8' },
1186+
11681187
{ oid => '449', descr => 'hash',
11691188
proname => 'hashint2', prorettype => 'int4', proargtypes => 'int2',
11701189
prosrc => 'hashint2' },

src/test/regress/expected/opr_sanity.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,9 @@ uuid_extract_timestamp(uuid)
875875
uuid_extract_version(uuid)
876876
crc32(bytea)
877877
crc32c(bytea)
878+
bytea(smallint)
879+
bytea(integer)
880+
bytea(bigint)
878881
bytea_larger(bytea,bytea)
879882
bytea_smaller(bytea,bytea)
880883
-- Check that functions without argument are not marked as leakproof.

src/test/regress/expected/strings.out

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,6 +2358,108 @@ SELECT set_byte('\x1234567890abcdef00'::bytea, 7, 11);
23582358

23592359
SELECT set_byte('\x1234567890abcdef00'::bytea, 99, 11); -- error
23602360
ERROR: index 99 out of valid range, 0..8
2361+
--
2362+
-- conversions between bytea and integer types
2363+
--
2364+
SELECT 0x1234::int2::bytea AS "\x1234", (-0x1234)::int2::bytea AS "\xedcc";
2365+
\x1234 | \xedcc
2366+
--------+--------
2367+
\x1234 | \xedcc
2368+
(1 row)
2369+
2370+
SELECT 0x12345678::int4::bytea AS "\x12345678", (-0x12345678)::int4::bytea AS "\xedcba988";
2371+
\x12345678 | \xedcba988
2372+
------------+------------
2373+
\x12345678 | \xedcba988
2374+
(1 row)
2375+
2376+
SELECT 0x1122334455667788::int8::bytea AS "\x1122334455667788",
2377+
(-0x1122334455667788)::int8::bytea AS "\xeeddccbbaa998878";
2378+
\x1122334455667788 | \xeeddccbbaa998878
2379+
--------------------+--------------------
2380+
\x1122334455667788 | \xeeddccbbaa998878
2381+
(1 row)
2382+
2383+
SELECT ''::bytea::int2 AS "0";
2384+
0
2385+
---
2386+
0
2387+
(1 row)
2388+
2389+
SELECT '\x12'::bytea::int2 AS "18";
2390+
18
2391+
----
2392+
18
2393+
(1 row)
2394+
2395+
SELECT '\x1234'::bytea::int2 AS "4460";
2396+
4460
2397+
------
2398+
4660
2399+
(1 row)
2400+
2401+
SELECT '\x123456'::bytea::int2; -- error
2402+
ERROR: smallint out of range
2403+
SELECT ''::bytea::int4 AS "0";
2404+
0
2405+
---
2406+
0
2407+
(1 row)
2408+
2409+
SELECT '\x12'::bytea::int4 AS "18";
2410+
18
2411+
----
2412+
18
2413+
(1 row)
2414+
2415+
SELECT '\x12345678'::bytea::int4 AS "305419896";
2416+
305419896
2417+
-----------
2418+
305419896
2419+
(1 row)
2420+
2421+
SELECT '\x123456789A'::bytea::int4; -- error
2422+
ERROR: integer out of range
2423+
SELECT ''::bytea::int8 AS "0";
2424+
0
2425+
---
2426+
0
2427+
(1 row)
2428+
2429+
SELECT '\x12'::bytea::int8 AS "18";
2430+
18
2431+
----
2432+
18
2433+
(1 row)
2434+
2435+
SELECT '\x1122334455667788'::bytea::int8 AS "1234605616436508552";
2436+
1234605616436508552
2437+
---------------------
2438+
1234605616436508552
2439+
(1 row)
2440+
2441+
SELECT '\x112233445566778899'::bytea::int8; -- error
2442+
ERROR: bigint out of range
2443+
-- min/max integer values
2444+
SELECT '\x8000'::bytea::int2 AS "-32768", '\x7FFF'::bytea::int2 AS "32767";
2445+
-32768 | 32767
2446+
--------+-------
2447+
-32768 | 32767
2448+
(1 row)
2449+
2450+
SELECT '\x80000000'::bytea::int4 AS "-2147483648", '\x7FFFFFFF'::bytea::int4 AS "2147483647";
2451+
-2147483648 | 2147483647
2452+
-------------+------------
2453+
-2147483648 | 2147483647
2454+
(1 row)
2455+
2456+
SELECT '\x8000000000000000'::bytea::int8 AS "-9223372036854775808",
2457+
'\x7FFFFFFFFFFFFFFF'::bytea::int8 AS "9223372036854775807";
2458+
-9223372036854775808 | 9223372036854775807
2459+
----------------------+---------------------
2460+
-9223372036854775808 | 9223372036854775807
2461+
(1 row)
2462+
23612463
--
23622464
-- test behavior of escape_string_warning and standard_conforming_strings options
23632465
--

src/test/regress/sql/strings.sql

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,35 @@ SELECT get_byte('\x1234567890abcdef00'::bytea, 99); -- error
751751
SELECT set_byte('\x1234567890abcdef00'::bytea, 7, 11);
752752
SELECT set_byte('\x1234567890abcdef00'::bytea, 99, 11); -- error
753753

754+
--
755+
-- conversions between bytea and integer types
756+
--
757+
SELECT 0x1234::int2::bytea AS "\x1234", (-0x1234)::int2::bytea AS "\xedcc";
758+
SELECT 0x12345678::int4::bytea AS "\x12345678", (-0x12345678)::int4::bytea AS "\xedcba988";
759+
SELECT 0x1122334455667788::int8::bytea AS "\x1122334455667788",
760+
(-0x1122334455667788)::int8::bytea AS "\xeeddccbbaa998878";
761+
762+
SELECT ''::bytea::int2 AS "0";
763+
SELECT '\x12'::bytea::int2 AS "18";
764+
SELECT '\x1234'::bytea::int2 AS "4460";
765+
SELECT '\x123456'::bytea::int2; -- error
766+
767+
SELECT ''::bytea::int4 AS "0";
768+
SELECT '\x12'::bytea::int4 AS "18";
769+
SELECT '\x12345678'::bytea::int4 AS "305419896";
770+
SELECT '\x123456789A'::bytea::int4; -- error
771+
772+
SELECT ''::bytea::int8 AS "0";
773+
SELECT '\x12'::bytea::int8 AS "18";
774+
SELECT '\x1122334455667788'::bytea::int8 AS "1234605616436508552";
775+
SELECT '\x112233445566778899'::bytea::int8; -- error
776+
777+
-- min/max integer values
778+
SELECT '\x8000'::bytea::int2 AS "-32768", '\x7FFF'::bytea::int2 AS "32767";
779+
SELECT '\x80000000'::bytea::int4 AS "-2147483648", '\x7FFFFFFF'::bytea::int4 AS "2147483647";
780+
SELECT '\x8000000000000000'::bytea::int8 AS "-9223372036854775808",
781+
'\x7FFFFFFFFFFFFFFF'::bytea::int8 AS "9223372036854775807";
782+
754783
--
755784
-- test behavior of escape_string_warning and standard_conforming_strings options
756785
--

0 commit comments

Comments
 (0)