v5-0002-Add-get_bytes-and-set_bytes-functions.patch
application/octet-stream
Filename: v5-0002-Add-get_bytes-and-set_bytes-functions.patch
Type: application/octet-stream
Part: 1
Patch
Format: format-patch
Series: patch v5-0002
Subject: Add get_bytes() and set_bytes() functions.
| File | + | − |
|---|---|---|
| doc/src/sgml/func.sgml | 45 | 1 |
| src/backend/utils/adt/varlena.c | 80 | 0 |
| src/include/catalog/pg_proc.dat | 6 | 0 |
| src/test/regress/expected/strings.out | 36 | 0 |
| src/test/regress/sql/strings.sql | 10 | 0 |
From 6fd52c99926bfdac215a94afc00f2b5a8afb3690 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@timescale.com>
Date: Wed, 14 Aug 2024 12:11:47 +0300
Subject: [PATCH v5 2/2] Add get_bytes() and set_bytes() functions.
The new functions provide a convenient way of extracting integers from
bytea's and putting integer values into bytea's. Previously there were only
get_byte() and set_byte() which operate with a single byte.
Aleksander Alekseev, reviewed by Joel Jacobson, Yugo Nagata
Discussion: https://postgr.es/m/CAJ7c6TPtOp6%2BkFX5QX3fH1SVr7v65uHr-7yEJ%3DGMGQi5uhGtcA%40mail.gmail.com
BUMP CATVERSION
---
doc/src/sgml/func.sgml | 46 ++++++++++++++-
src/backend/utils/adt/varlena.c | 80 +++++++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 6 ++
src/test/regress/expected/strings.out | 36 ++++++++++++
src/test/regress/sql/strings.sql | 10 ++++
5 files changed, 177 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index f8a0d76d12..5d907c9e44 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -4562,6 +4562,27 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
</para></entry>
</row>
+ <row>
+ <entry role="func_table_entry"><para role="func_signature">
+ <indexterm>
+ <primary>get_bytes</primary>
+ </indexterm>
+ <function>get_bytes</function> ( <parameter>bytes</parameter> <type>bytea</type>,
+ <parameter>offset</parameter> <type>integer</type>,
+ <parameter>size</parameter> <type>integer</type> )
+ <returnvalue>bigint</returnvalue>
+ </para>
+ <para>
+ Extracts <parameter>size</parameter> bytes at a given
+ <link linkend="functions-zerobased-note">offset</link>
+ from binary string.
+ </para>
+ <para>
+ <literal>get_bytes('\x0123456789ABCDEF'::bytea, 5, 2)</literal>
+ <returnvalue>43981</returnvalue>
+ </para></entry>
+ </row>
+
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -4662,6 +4683,28 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
</para></entry>
</row>
+ <row>
+ <entry role="func_table_entry"><para role="func_signature">
+ <indexterm>
+ <primary>set_bytes</primary>
+ </indexterm>
+ <function>set_bytes</function> ( <parameter>bytes</parameter> <type>bytea</type>,
+ <parameter>offset</parameter> <type>integer</type>,
+ <parameter>size</parameter> <type>integer</type>,
+ <parameter>newvalue</parameter> <type>bigint</type> )
+ <returnvalue>bytea</returnvalue>
+ </para>
+ <para>
+ Sets <parameter>size</parameter> bytes at a given
+ <link linkend="functions-zerobased-note">offset</link>
+ in binary string to <parameter>newvalue</parameter>.
+ </para>
+ <para>
+ <literal>set_bytes('\x0123456789abcdef'::bytea, 5, 2, 0x1122)</literal>
+ <returnvalue>\x01234567891122ef</returnvalue>
+ </para></entry>
+ </row>
+
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -4761,7 +4804,8 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
</table>
<para id="functions-zerobased-note">
- Functions <function>get_byte</function> and <function>set_byte</function>
+ Functions <function>get_byte</function>, <function>set_byte</function>,
+ <function>get_bytes</function> and <function>set_bytes</function>
number the first byte of a binary string as byte 0.
Functions <function>get_bit</function> and <function>set_bit</function>
number bits from the right within each byte; for example bit 0 is the least
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 533bebc1c7..0a1560556d 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -3201,6 +3201,46 @@ byteaGetByte(PG_FUNCTION_ARGS)
PG_RETURN_INT32(byte);
}
+/*-------------------------------------------------------------
+ * byteaGetBytes
+ *
+ * This routine treats "bytea" as an array of bytes.
+ * It returns the N bytes at a given offset as a bigint value.
+ *-------------------------------------------------------------
+ */
+Datum
+byteaGetBytes(PG_FUNCTION_ARGS)
+{
+ bytea *v = PG_GETARG_BYTEA_PP(0);
+ int32 offset = PG_GETARG_INT32(1);
+ int32 size = PG_GETARG_INT32(2);
+ int64 result = 0;
+ int len;
+
+ if (size < 1 || size > 8)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("size %d out of valid range, 1..8",
+ size)));
+
+ len = VARSIZE_ANY_EXHDR(v);
+
+ if (offset < 0 || offset > (len-size))
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ errmsg("index %d out of valid range, 0..%d",
+ offset, len - size)));
+
+ while (size--)
+ {
+ result = result << 8;
+ result |= ((unsigned char *) VARDATA_ANY(v))[offset];
+ offset++;
+ }
+
+ PG_RETURN_INT64(result);
+}
+
/*-------------------------------------------------------------
* byteaGetBit
*
@@ -3271,6 +3311,46 @@ byteaSetByte(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(res);
}
+/*-------------------------------------------------------------
+ * byteaSetBytes
+ *
+ * Given an instance of type 'bytea' creates a new one with
+ * the N bytes at a given offset set to the provided bigint value.
+ *
+ *-------------------------------------------------------------
+ */
+Datum
+byteaSetBytes(PG_FUNCTION_ARGS)
+{
+ bytea *res = PG_GETARG_BYTEA_P_COPY(0);
+ int32 offset = PG_GETARG_INT32(1);
+ int32 size = PG_GETARG_INT32(2);
+ int64 newValue = PG_GETARG_INT64(3);
+ int len;
+
+ if (size < 1 || size > 8)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("size %d out of valid range, 1..8",
+ size)));
+
+ len = VARSIZE_ANY_EXHDR(res);
+
+ if (offset < 0 || offset > (len-size))
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ errmsg("index %d out of valid range, 0..%d",
+ offset, len - size)));
+ while (size)
+ {
+ ((unsigned char*) VARDATA_ANY(res))[offset+size-1] = newValue & 0xFF;
+ newValue = newValue >> 8;
+ size--;
+ }
+
+ PG_RETURN_BYTEA_P(res);
+}
+
/*-------------------------------------------------------------
* byteaSetBit
*
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 0336110b0d..8ff28a4139 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -1502,6 +1502,12 @@
{ oid => '722', descr => 'set byte',
proname => 'set_byte', prorettype => 'bytea',
proargtypes => 'bytea int4 int4', prosrc => 'byteaSetByte' },
+{ oid => '8575', descr => 'get bytes',
+ proname => 'get_bytes', prorettype => 'int8', proargtypes => 'bytea int4 int4',
+ prosrc => 'byteaGetBytes' },
+{ oid => '8576', descr => 'set bytes',
+ proname => 'set_bytes', prorettype => 'bytea',
+ proargtypes => 'bytea int4 int4 int8', prosrc => 'byteaSetBytes' },
{ oid => '723', descr => 'get bit',
proname => 'get_bit', prorettype => 'int4', proargtypes => 'bytea int8',
prosrc => 'byteaGetBit' },
diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out
index 709f58ad7f..c58fc9b918 100644
--- a/src/test/regress/expected/strings.out
+++ b/src/test/regress/expected/strings.out
@@ -2358,6 +2358,42 @@ SELECT set_byte('\x1234567890abcdef00'::bytea, 7, 11);
SELECT set_byte('\x1234567890abcdef00'::bytea, 99, 11); -- error
ERROR: index 99 out of valid range, 0..8
+SELECT get_bytes('\x1122334455667788'::bytea, 0, 8) = 0x1122334455667788;
+ ?column?
+----------
+ t
+(1 row)
+
+SELECT get_bytes('\x1122334455667788'::bytea, 1, 2) = 0x2233;
+ ?column?
+----------
+ t
+(1 row)
+
+SELECT get_bytes('\x1122334455667788'::bytea, 0, 0); -- error
+ERROR: size 0 out of valid range, 1..8
+SELECT get_bytes('\x1122334455667788'::bytea, 0, 9); -- error
+ERROR: size 9 out of valid range, 1..8
+SELECT get_bytes('\x1122334455667788'::bytea, 1, 8); -- error
+ERROR: index 1 out of valid range, 0..0
+SELECT set_bytes('\x0123456789abcdef'::bytea, 0, 8, 0x1122334455667788);
+ set_bytes
+--------------------
+ \x1122334455667788
+(1 row)
+
+SELECT set_bytes('\x1122334455667788'::bytea, 1, 2, 0xAABB);
+ set_bytes
+--------------------
+ \x11aabb4455667788
+(1 row)
+
+SELECT set_bytes('\x0123456789abcdef'::bytea, 0, 0, 123); -- error
+ERROR: size 0 out of valid range, 1..8
+SELECT set_bytes('\x0123456789abcdef'::bytea, 0, 9, 123); -- error
+ERROR: size 9 out of valid range, 1..8
+SELECT set_bytes('\x0123456789abcdef'::bytea, 1, 8, 123); -- error
+ERROR: index 1 out of valid range, 0..0
--
-- test behavior of escape_string_warning and standard_conforming_strings options
--
diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql
index b8858c9aea..82d677562a 100644
--- a/src/test/regress/sql/strings.sql
+++ b/src/test/regress/sql/strings.sql
@@ -750,6 +750,16 @@ SELECT get_byte('\x1234567890abcdef00'::bytea, 3);
SELECT get_byte('\x1234567890abcdef00'::bytea, 99); -- error
SELECT set_byte('\x1234567890abcdef00'::bytea, 7, 11);
SELECT set_byte('\x1234567890abcdef00'::bytea, 99, 11); -- error
+SELECT get_bytes('\x1122334455667788'::bytea, 0, 8) = 0x1122334455667788;
+SELECT get_bytes('\x1122334455667788'::bytea, 1, 2) = 0x2233;
+SELECT get_bytes('\x1122334455667788'::bytea, 0, 0); -- error
+SELECT get_bytes('\x1122334455667788'::bytea, 0, 9); -- error
+SELECT get_bytes('\x1122334455667788'::bytea, 1, 8); -- error
+SELECT set_bytes('\x0123456789abcdef'::bytea, 0, 8, 0x1122334455667788);
+SELECT set_bytes('\x1122334455667788'::bytea, 1, 2, 0xAABB);
+SELECT set_bytes('\x0123456789abcdef'::bytea, 0, 0, 123); -- error
+SELECT set_bytes('\x0123456789abcdef'::bytea, 0, 9, 123); -- error
+SELECT set_bytes('\x0123456789abcdef'::bytea, 1, 8, 123); -- error
--
-- test behavior of escape_string_warning and standard_conforming_strings options
--
2.47.0