V3 patch with fixed length comparison
-- With best regards, Marat Bukharov > > V2 patch with fixed tests > > > > > Hello. BYTEA type has the ability to use comparison operations. But it > > is absent of min/max aggregate functions. They are nice to have to > > provide consistency with the TEXT type. > >
From a2cf0f0a7d1063b3fc6927c0117f4d463ab9087a Mon Sep 17 00:00:00 2001 From: Marat Bukharov <mara...@yandex-team.ru> Date: Wed, 3 Jul 2024 17:52:16 +0300 Subject: [PATCH v3] add bytea agg funcs --- doc/src/sgml/func.sgml | 4 +-- src/backend/utils/adt/varlena.c | 38 ++++++++++++++++++++++++ src/include/catalog/pg_aggregate.dat | 6 ++++ src/include/catalog/pg_proc.dat | 13 ++++++++ src/test/regress/expected/aggregates.out | 14 ++++++++- src/test/regress/expected/opr_sanity.out | 2 ++ src/test/regress/sql/aggregates.sql | 5 +++- 7 files changed, 78 insertions(+), 4 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index f1f22a1960..891f7a4259 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -21976,7 +21976,7 @@ SELECT NULLIF(value, '(none)') ... <para> Computes the maximum of the non-null input values. Available for any numeric, string, date/time, or enum type, - as well as <type>inet</type>, <type>interval</type>, + as well as <type>bytea</type>, <type>inet</type>, <type>interval</type>, <type>money</type>, <type>oid</type>, <type>pg_lsn</type>, <type>tid</type>, <type>xid8</type>, and arrays of any of these types. @@ -21995,7 +21995,7 @@ SELECT NULLIF(value, '(none)') ... <para> Computes the minimum of the non-null input values. Available for any numeric, string, date/time, or enum type, - as well as <type>inet</type>, <type>interval</type>, + as well as <type>bytea</type>, <type>inet</type>, <type>interval</type>, <type>money</type>, <type>oid</type>, <type>pg_lsn</type>, <type>tid</type>, <type>xid8</type>, and arrays of any of these types. diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index d2e2e9bbba..9fd7310d09 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -3956,6 +3956,44 @@ byteacmp(PG_FUNCTION_ARGS) PG_RETURN_INT32(cmp); } +Datum +bytea_larger(PG_FUNCTION_ARGS) +{ + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); + bytea *result; + int len1, + len2; + int cmp; + + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); + + cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2)); + result = ((cmp > 0) || ((cmp == 0) && (len1 > len2)) ? arg1 : arg2); + + PG_RETURN_BYTEA_P(result); +} + +Datum +bytea_smaller(PG_FUNCTION_ARGS) +{ + bytea *arg1 = PG_GETARG_TEXT_PP(0); + bytea *arg2 = PG_GETARG_TEXT_PP(1); + bytea *result; + int len1, + len2; + int cmp; + + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); + + cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2)); + result = ((cmp < 0) || ((cmp == 0) && (len1 < len2)) ? arg1 : arg2); + + PG_RETURN_BYTEA_P(result); +} + Datum bytea_sortsupport(PG_FUNCTION_ARGS) { diff --git a/src/include/catalog/pg_aggregate.dat b/src/include/catalog/pg_aggregate.dat index 5f13532abc..970d9a70fd 100644 --- a/src/include/catalog/pg_aggregate.dat +++ b/src/include/catalog/pg_aggregate.dat @@ -158,6 +158,9 @@ { aggfnoid => 'max(xid8)', aggtransfn => 'xid8_larger', aggcombinefn => 'xid8_larger', aggsortop => '>(xid8,xid8)', aggtranstype => 'xid8' }, +{ aggfnoid => 'max(bytea)', aggtransfn => 'bytea_larger', + aggcombinefn => 'bytea_larger', aggsortop => '>(bytea,bytea)', + aggtranstype => 'bytea' }, # min { aggfnoid => 'min(int8)', aggtransfn => 'int8smaller', @@ -226,6 +229,9 @@ { aggfnoid => 'min(xid8)', aggtransfn => 'xid8_smaller', aggcombinefn => 'xid8_smaller', aggsortop => '<(xid8,xid8)', aggtranstype => 'xid8' }, +{ aggfnoid => 'min(bytea)', aggtransfn => 'bytea_smaller', + aggcombinefn => 'bytea_smaller', aggsortop => '<(bytea,bytea)', + aggtranstype => 'bytea' }, # count { aggfnoid => 'count(any)', aggtransfn => 'int8inc_any', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index d4ac578ae6..f16f17ef3a 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -1278,6 +1278,13 @@ proname => 'text_smaller', proleakproof => 't', prorettype => 'text', proargtypes => 'text text', prosrc => 'text_smaller' }, +{ oid => '6347', descr => 'larger of two', + proname => 'bytea_larger', proleakproof => 't', prorettype => 'bytea', + proargtypes => 'bytea bytea', prosrc => 'bytea_larger' }, +{ oid => '6348', descr => 'smaller of two', + proname => 'bytea_smaller', proleakproof => 't', prorettype => 'bytea', + proargtypes => 'bytea bytea', prosrc => 'bytea_smaller' }, + { oid => '460', descr => 'I/O', proname => 'int8in', prorettype => 'int8', proargtypes => 'cstring', prosrc => 'int8in' }, @@ -6764,6 +6771,9 @@ { oid => '5099', descr => 'maximum value of all xid8 input values', proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'xid8', proargtypes => 'xid8', prosrc => 'aggregate_dummy' }, +{ oid => '6349', descr => 'maximum value of all bytea input values', + proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'bytea', + proargtypes => 'bytea', prosrc => 'aggregate_dummy' }, { oid => '2131', descr => 'minimum value of all bigint input values', proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'int8', @@ -6834,6 +6844,9 @@ { oid => '5100', descr => 'minimum value of all xid8 input values', proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'xid8', proargtypes => 'xid8', prosrc => 'aggregate_dummy' }, +{ oid => '6350', descr => 'minimum value of all bytea input values', + proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'bytea', + proargtypes => 'bytea', prosrc => 'aggregate_dummy' }, # count has two forms: count(any) and count(*) { oid => '2147', diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out index 1c1ca7573a..db741d0c36 100644 --- a/src/test/regress/expected/aggregates.out +++ b/src/test/regress/expected/aggregates.out @@ -1925,7 +1925,7 @@ select string_agg(distinct f1::text, ',' order by f1::text) from varchar_tbl; - a,ab,abcd (1 row) --- string_agg bytea tests +-- string_agg, min, max bytea tests create table bytea_test_table(v bytea); select string_agg(v, '') from bytea_test_table; string_agg @@ -1959,6 +1959,18 @@ select string_agg(v, decode('ee', 'hex')) from bytea_test_table; \xffeeaa (1 row) +select min(v) from bytea_test_table; + min +------ + \xaa +(1 row) + +select max(v) from bytea_test_table; + max +------ + \xff +(1 row) + drop table bytea_test_table; -- Test parallel string_agg and array_agg create table pagg_test (x int, y int) with (autovacuum_enabled = off); diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 9d047b21b8..087e349894 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -874,6 +874,8 @@ xid8ne(xid8,xid8) xid8cmp(xid8,xid8) uuid_extract_timestamp(uuid) uuid_extract_version(uuid) +bytea_larger(bytea,bytea) +bytea_smaller(bytea,bytea) -- restore normal output mode \a\t -- List of functions used by libpq's fe-lobj.c diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql index 1a18ca3d8f..1f438dbf79 100644 --- a/src/test/regress/sql/aggregates.sql +++ b/src/test/regress/sql/aggregates.sql @@ -741,7 +741,7 @@ select string_agg(distinct f1::text, ',' order by f1) from varchar_tbl; -- not select string_agg(distinct f1, ',' order by f1::text) from varchar_tbl; -- not ok select string_agg(distinct f1::text, ',' order by f1::text) from varchar_tbl; -- ok --- string_agg bytea tests +-- string_agg, min, max bytea tests create table bytea_test_table(v bytea); select string_agg(v, '') from bytea_test_table; @@ -756,6 +756,9 @@ select string_agg(v, '') from bytea_test_table; select string_agg(v, NULL) from bytea_test_table; select string_agg(v, decode('ee', 'hex')) from bytea_test_table; +select min(v) from bytea_test_table; +select max(v) from bytea_test_table; + drop table bytea_test_table; -- Test parallel string_agg and array_agg -- 2.44.2