diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 68fe6a95b49..1d3429fbd9c 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -4010,6 +4010,28 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three'); + + + + bit_count + + + popcount + bit_count + + bit_count ( bytes bytea ) + bigint + + + Returns the number of bits set in the binary string (also known as + popcount). + + + bit_count('\x1234567890'::bytea) + 31 + + + @@ -4714,6 +4736,24 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three'); + + + + bit_count + + bit_count ( bit ) + bigint + + + Returns the number of bits set in the bit string (also known as + popcount). + + + bit_count(B'10111') + 4 + + + diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c index 2235866244d..0d0c0fd9f3c 100644 --- a/src/backend/utils/adt/varbit.c +++ b/src/backend/utils/adt/varbit.c @@ -36,6 +36,7 @@ #include "libpq/pqformat.h" #include "nodes/nodeFuncs.h" #include "nodes/supportnodes.h" +#include "port/pg_bitutils.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/varbit.h" @@ -1201,6 +1202,19 @@ bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl) return result; } +/* + * bit_count + * + * Returns the number of bits set in a bit string. + */ +Datum +bit_bit_count(PG_FUNCTION_ARGS) +{ + VarBit *arg = PG_GETARG_VARBIT_P(0); + + PG_RETURN_INT64(pg_popcount((char *) VARBITS(arg), VARBITBYTES(arg))); +} + /* * bitlength, bitoctetlength * Return the length of a bit string diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 0bc345aa4d3..640e3fd4c04 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -3440,6 +3440,17 @@ bytea_overlay(bytea *t1, bytea *t2, int sp, int sl) return result; } +/* + * bit_count + */ +Datum +bytea_bit_count(PG_FUNCTION_ARGS) +{ + bytea *t1 = PG_GETARG_BYTEA_PP(0); + + PG_RETURN_INT64(pg_popcount(VARDATA_ANY(t1), VARSIZE_ANY_EXHDR(t1))); +} + /* * byteapos - * Return the position of the specified substring. diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 3cf93fd381b..2f18734235a 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202103231 +#define CATALOG_VERSION_NO 202103232 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index b9f4afba050..464fa8d614b 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -1446,6 +1446,9 @@ { oid => '752', descr => 'substitute portion of string', proname => 'overlay', prorettype => 'bytea', proargtypes => 'bytea bytea int4', prosrc => 'byteaoverlay_no_len' }, +{ oid => '8436', descr => 'number of set bits', + proname => 'bit_count', prorettype => 'int8', proargtypes => 'bytea', + prosrc => 'bytea_bit_count'}, { oid => '725', proname => 'dist_pl', prorettype => 'float8', proargtypes => 'point line', @@ -3876,6 +3879,9 @@ { oid => '3033', descr => 'set bit', proname => 'set_bit', prorettype => 'bit', proargtypes => 'bit int4 int4', prosrc => 'bitsetbit' }, +{ oid => '8435', descr => 'number of set bits', + proname => 'bit_count', prorettype => 'int8', proargtypes => 'bit', + prosrc => 'bit_bit_count'}, # for macaddr type support { oid => '436', descr => 'I/O', diff --git a/src/test/regress/expected/bit.out b/src/test/regress/expected/bit.out index a7f95b846d9..a5aab9c0e35 100644 --- a/src/test/regress/expected/bit.out +++ b/src/test/regress/expected/bit.out @@ -710,6 +710,19 @@ SELECT overlay(B'0101011100' placing '001' from 20); 0101011100001 (1 row) +-- bit_count +SELECT bit_count(B'0101011100'::bit(10)); + bit_count +----------- + 5 +(1 row) + +SELECT bit_count(B'1111111111'::bit(10)); + bit_count +----------- + 10 +(1 row) + -- This table is intentionally left around to exercise pg_dump/pg_upgrade CREATE TABLE bit_defaults( b1 bit(4) DEFAULT '1001', diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index fb4573d85ff..f751f0ca159 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -2227,3 +2227,9 @@ SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5 Th\000o\x02\x03 (1 row) +SELECT bit_count('\x1234567890'::bytea); + bit_count +----------- + 31 +(1 row) + diff --git a/src/test/regress/sql/bit.sql b/src/test/regress/sql/bit.sql index ea01742c4aa..0a424e796b9 100644 --- a/src/test/regress/sql/bit.sql +++ b/src/test/regress/sql/bit.sql @@ -215,6 +215,10 @@ SELECT overlay(B'0101011100' placing '101' from 6); SELECT overlay(B'0101011100' placing '001' from 11); SELECT overlay(B'0101011100' placing '001' from 20); +-- bit_count +SELECT bit_count(B'0101011100'::bit(10)); +SELECT bit_count(B'1111111111'::bit(10)); + -- This table is intentionally left around to exercise pg_dump/pg_upgrade CREATE TABLE bit_defaults( b1 bit(4) DEFAULT '1001', diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql index 57a48c9d0b0..c043f025417 100644 --- a/src/test/regress/sql/strings.sql +++ b/src/test/regress/sql/strings.sql @@ -742,3 +742,5 @@ SELECT btrim(E'\\000trim\\000'::bytea, ''::bytea); SELECT encode(overlay(E'Th\\000omas'::bytea placing E'Th\\001omas'::bytea from 2),'escape'); SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 8),'escape'); SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5 for 3),'escape'); + +SELECT bit_count('\x1234567890'::bytea);