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

Commit 1b35729

Browse files
deanrasheedCommitfest Bot
authored and
Commitfest Bot
committed
Allow casting between bytea and integer types.
This allows smallint, integer, and bigint values to be cast to and from bytea. The bytea value is the two's complement representation of the integer, with the most significant byte first. For example: 1234::bytea -> \x000004d2 (-1234)::bytea -> \xfffffb2e Author: Aleksander Alekseev <aleksander@timescale.com> Reviewed-by: Joel Jacobson <joel@compiler.org> Reviewed-by: Yugo Nagata <nagata@sraoss.co.jp> Reviewed-by: Peter Eisentraut <peter@eisentraut.org> Reviewed-by: Michael Paquier <michael@paquier.xyz> Reviewed-by: Dean Rasheed <dean.a.rasheed@gmail.com> Discussion: https://postgr.es/m/CAJ7c6TPtOp6%2BkFX5QX3fH1SVr7v65uHr-7yEJ%3DGMGQi5uhGtcA%40mail.gmail.com
1 parent 0e76f25 commit 1b35729

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)