Add min and max aggregates for bytea type.
authorTom Lane <[email protected]>
Tue, 8 Oct 2024 17:52:14 +0000 (13:52 -0400)
committerTom Lane <[email protected]>
Tue, 8 Oct 2024 17:52:14 +0000 (13:52 -0400)
Similar to a0f1fce80, although we chose to duplicate logic
rather than invoke byteacmp, primarily to avoid repeat detoasting.

Marat Buharov, Aleksander Alekseev

Discussion: https://postgr.es/m/CAPCEVGXiASjodos4P8pgyV7ixfVn-ZgG9YyiRZRbVqbGmfuDyg@mail.gmail.com

doc/src/sgml/func.sgml
src/backend/utils/adt/varlena.c
src/include/catalog/catversion.h
src/include/catalog/pg_aggregate.dat
src/include/catalog/pg_proc.dat
src/test/regress/expected/aggregates.out
src/test/regress/expected/opr_sanity.out
src/test/regress/sql/aggregates.sql

index 7b4fbb50471b9e1c1d41be7edbc429970463ceed..b26db3b04b0919b916740d0e5e6e04188da7fc5a 100644 (file)
@@ -22125,7 +22125,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 also arrays and composite types containing sortable data types.
@@ -22144,7 +22144,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 also arrays and composite types containing sortable data types.
index d46ed3ccf9f1053bf44e480738446efdc12c5d3d..533bebc1c7b2506d164b7f74172037b4ab02d6e0 100644 (file)
@@ -3931,6 +3931,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_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_sortsupport(PG_FUNCTION_ARGS)
 {
index 504bbe5327677a673ecdabfcb8f162b2bb9ddedf..4d4a2dd7afac960ba01a05e23f4d1ab2de40ad54 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202410021
+#define CATALOG_VERSION_NO 202410081
 
 #endif
index b6b6352d91712b399841498da6f5d26852f8e237..6ba6a997c2916deb4604b28269ed99cc927c7a24 100644 (file)
 { 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',
 { 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',
index 77f54a79e6ad92cb4c21dcb3fee161a025651c75..3ae31a614cec2a62d571edcd7e29bb2dc0df1f90 100644 (file)
   proname => 'text_smaller', proleakproof => 't', prorettype => 'text',
   proargtypes => 'text text', prosrc => 'text_smaller' },
 
+{ oid => '8920', descr => 'larger of two',
+  proname => 'bytea_larger', proleakproof => 't', prorettype => 'bytea',
+  proargtypes => 'bytea bytea', prosrc => 'bytea_larger' },
+{ oid => '8921', 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' },
 { oid => '5099', descr => 'maximum value of all xid8 input values',
   proname => 'max', prokind => 'a', proisstrict => 'f', prorettype => 'xid8',
   proargtypes => 'xid8', prosrc => 'aggregate_dummy' },
+{ oid => '8922', 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',
 { oid => '5100', descr => 'minimum value of all xid8 input values',
   proname => 'min', prokind => 'a', proisstrict => 'f', prorettype => 'xid8',
   proargtypes => 'xid8', prosrc => 'aggregate_dummy' },
+{ oid => '8923', 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',
index 8ac13b562c4975fc0abd4381939c0d0030be4765..e14e73565675564a799248f265175af0d650c18e 100644 (file)
@@ -1950,7 +1950,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 
@@ -1984,6 +1984,32 @@ 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)
+
+insert into bytea_test_table values(decode('ffff','hex'));
+insert into bytea_test_table values(decode('aaaa','hex'));
+select min(v) from bytea_test_table;
+ min  
+------
+ \xaa
+(1 row)
+
+select max(v) from bytea_test_table;
+  max   
+--------
+ \xffff
+(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);
index 0d734169f11c74a9a994735f05bf660611550046..34a32bd11d219d7bc16f1a0d251964c7a501b555 100644 (file)
@@ -876,6 +876,8 @@ uuid_extract_timestamp(uuid)
 uuid_extract_version(uuid)
 crc32(bytea)
 crc32c(bytea)
+bytea_larger(bytea,bytea)
+bytea_smaller(bytea,bytea)
 -- restore normal output mode
 \a\t
 -- List of functions used by libpq's fe-lobj.c
index ca6d1bcfb7fa7fc3388833ca1bf8086ab7efc460..ddf38bafb4280d8ac8e5b97011d4983a8b5e7fce 100644 (file)
@@ -747,7 +747,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;
@@ -762,6 +762,15 @@ 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;
+
+insert into bytea_test_table values(decode('ffff','hex'));
+insert into bytea_test_table values(decode('aaaa','hex'));
+
+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