Skip to content

Commit a6715af

Browse files
committed
Add bit_count SQL function
This function for bit and bytea counts the set bits in the bit or byte string. Internally, we use the existing popcount functionality. For the name, after some discussion, we settled on bit_count, which also exists with this meaning in MySQL, Java, and Python. Author: David Fetter <david@fetter.org> Discussion: https://www.postgresql.org/message-id/flat/20201230105535.GJ13234@fetter.org
1 parent 5aed6a1 commit a6715af

File tree

9 files changed

+97
-1
lines changed

9 files changed

+97
-1
lines changed

doc/src/sgml/func.sgml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4010,6 +4010,28 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
40104010
</thead>
40114011

40124012
<tbody>
4013+
<row>
4014+
<entry role="func_table_entry"><para role="func_signature">
4015+
<indexterm>
4016+
<primary>bit_count</primary>
4017+
</indexterm>
4018+
<indexterm>
4019+
<primary>popcount</primary>
4020+
<see>bit_count</see>
4021+
</indexterm>
4022+
<function>bit_count</function> ( <parameter>bytes</parameter> <type>bytea</type> )
4023+
<returnvalue>bigint</returnvalue>
4024+
</para>
4025+
<para>
4026+
Returns the number of bits set in the binary string (also known as
4027+
<quote>popcount</quote>).
4028+
</para>
4029+
<para>
4030+
<literal>bit_count('\x1234567890'::bytea)</literal>
4031+
<returnvalue>31</returnvalue>
4032+
</para></entry>
4033+
</row>
4034+
40134035
<row>
40144036
<entry role="func_table_entry"><para role="func_signature">
40154037
<indexterm>
@@ -4714,6 +4736,24 @@ SELECT format('Testing %3$s, %2$s, %s', 'one', 'two', 'three');
47144736
</thead>
47154737

47164738
<tbody>
4739+
<row>
4740+
<entry role="func_table_entry"><para role="func_signature">
4741+
<indexterm>
4742+
<primary>bit_count</primary>
4743+
</indexterm>
4744+
<function>bit_count</function> ( <type>bit</type> )
4745+
<returnvalue>bigint</returnvalue>
4746+
</para>
4747+
<para>
4748+
Returns the number of bits set in the bit string (also known as
4749+
<quote>popcount</quote>).
4750+
</para>
4751+
<para>
4752+
<literal>bit_count(B'10111')</literal>
4753+
<returnvalue>4</returnvalue>
4754+
</para></entry>
4755+
</row>
4756+
47174757
<row>
47184758
<entry role="func_table_entry"><para role="func_signature">
47194759
<indexterm>

src/backend/utils/adt/varbit.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "libpq/pqformat.h"
3737
#include "nodes/nodeFuncs.h"
3838
#include "nodes/supportnodes.h"
39+
#include "port/pg_bitutils.h"
3940
#include "utils/array.h"
4041
#include "utils/builtins.h"
4142
#include "utils/varbit.h"
@@ -1201,6 +1202,19 @@ bit_overlay(VarBit *t1, VarBit *t2, int sp, int sl)
12011202
return result;
12021203
}
12031204

1205+
/*
1206+
* bit_count
1207+
*
1208+
* Returns the number of bits set in a bit string.
1209+
*/
1210+
Datum
1211+
bit_bit_count(PG_FUNCTION_ARGS)
1212+
{
1213+
VarBit *arg = PG_GETARG_VARBIT_P(0);
1214+
1215+
PG_RETURN_INT64(pg_popcount((char *) VARBITS(arg), VARBITBYTES(arg)));
1216+
}
1217+
12041218
/*
12051219
* bitlength, bitoctetlength
12061220
* Return the length of a bit string

src/backend/utils/adt/varlena.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3440,6 +3440,17 @@ bytea_overlay(bytea *t1, bytea *t2, int sp, int sl)
34403440
return result;
34413441
}
34423442

3443+
/*
3444+
* bit_count
3445+
*/
3446+
Datum
3447+
bytea_bit_count(PG_FUNCTION_ARGS)
3448+
{
3449+
bytea *t1 = PG_GETARG_BYTEA_PP(0);
3450+
3451+
PG_RETURN_INT64(pg_popcount(VARDATA_ANY(t1), VARSIZE_ANY_EXHDR(t1)));
3452+
}
3453+
34433454
/*
34443455
* byteapos -
34453456
* Return the position of the specified substring.

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 202103231
56+
#define CATALOG_VERSION_NO 202103232
5757

5858
#endif

src/include/catalog/pg_proc.dat

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,6 +1446,9 @@
14461446
{ oid => '752', descr => 'substitute portion of string',
14471447
proname => 'overlay', prorettype => 'bytea',
14481448
proargtypes => 'bytea bytea int4', prosrc => 'byteaoverlay_no_len' },
1449+
{ oid => '8436', descr => 'number of set bits',
1450+
proname => 'bit_count', prorettype => 'int8', proargtypes => 'bytea',
1451+
prosrc => 'bytea_bit_count'},
14491452

14501453
{ oid => '725',
14511454
proname => 'dist_pl', prorettype => 'float8', proargtypes => 'point line',
@@ -3876,6 +3879,9 @@
38763879
{ oid => '3033', descr => 'set bit',
38773880
proname => 'set_bit', prorettype => 'bit', proargtypes => 'bit int4 int4',
38783881
prosrc => 'bitsetbit' },
3882+
{ oid => '8435', descr => 'number of set bits',
3883+
proname => 'bit_count', prorettype => 'int8', proargtypes => 'bit',
3884+
prosrc => 'bit_bit_count'},
38793885

38803886
# for macaddr type support
38813887
{ oid => '436', descr => 'I/O',

src/test/regress/expected/bit.out

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,19 @@ SELECT overlay(B'0101011100' placing '001' from 20);
710710
0101011100001
711711
(1 row)
712712

713+
-- bit_count
714+
SELECT bit_count(B'0101011100'::bit(10));
715+
bit_count
716+
-----------
717+
5
718+
(1 row)
719+
720+
SELECT bit_count(B'1111111111'::bit(10));
721+
bit_count
722+
-----------
723+
10
724+
(1 row)
725+
713726
-- This table is intentionally left around to exercise pg_dump/pg_upgrade
714727
CREATE TABLE bit_defaults(
715728
b1 bit(4) DEFAULT '1001',

src/test/regress/expected/strings.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2227,3 +2227,9 @@ SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5
22272227
Th\000o\x02\x03
22282228
(1 row)
22292229

2230+
SELECT bit_count('\x1234567890'::bytea);
2231+
bit_count
2232+
-----------
2233+
31
2234+
(1 row)
2235+

src/test/regress/sql/bit.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ SELECT overlay(B'0101011100' placing '101' from 6);
215215
SELECT overlay(B'0101011100' placing '001' from 11);
216216
SELECT overlay(B'0101011100' placing '001' from 20);
217217

218+
-- bit_count
219+
SELECT bit_count(B'0101011100'::bit(10));
220+
SELECT bit_count(B'1111111111'::bit(10));
221+
218222
-- This table is intentionally left around to exercise pg_dump/pg_upgrade
219223
CREATE TABLE bit_defaults(
220224
b1 bit(4) DEFAULT '1001',

src/test/regress/sql/strings.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,3 +742,5 @@ SELECT btrim(E'\\000trim\\000'::bytea, ''::bytea);
742742
SELECT encode(overlay(E'Th\\000omas'::bytea placing E'Th\\001omas'::bytea from 2),'escape');
743743
SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 8),'escape');
744744
SELECT encode(overlay(E'Th\\000omas'::bytea placing E'\\002\\003'::bytea from 5 for 3),'escape');
745+
746+
SELECT bit_count('\x1234567890'::bytea);

0 commit comments

Comments
 (0)