Is there a way to do a non-zero bit string test without hard-coding the bit string width of 0?
For example, suppose I have two tables, Users and Features, each with masks, I want to test this:
SELECT u.name FROM Users u, Features f
WHERE u.mask & f.mask;
matching implicit non-zero results. However, SQL requires an explicit boolean result for WHERE
as opposed to an implicit cast, such as this:
SELECT u.name FROM Users u, Features f
WHERE (u.mask & f.mask) != 0::BIT(2048);
I don't want to hardcode 2048
(or whatever) in this query for a number of reasons.
Testing expr = 0
or expr > 0
results in a type error. Oddly, I can test expr = 0::BIT(1)
, but that gives the wrong answer because Postgres does not consider all all-zero bit strings to be equal.
select 0::BIT(2) > 0::BIT(1);
?column?
----------
t
(1 row)
I can create a calculated zero by doing this:
SELECT u.name FROM Users u, Features f
WHERE (u.mask & f.mask) != (u.mask & ~u.mask);
Which works but feels like an awful hack.
Any suggestions or insights?
RESULTS
I benchmarked several options provided below. Thanks for the suggestions, Erwin!
Based on a very large data set and 100,000 queries, I found the following constructs resulted in the associated queries per second. Hopefully someone from the Postgres team sees this and provides a generic 0 to speed things up! Unfortunately most generic approaches seem to incur a string conversion which is quite expensive.
Constructs | Queries / s
----------------------------------------+--------------
(u.mask & f.mask) <> 0::BIT(2048) | 158
(u.mask & f.mask) <> (u.mask # u.mask) | 135
(u.mask & f.mask) <> (u.mask & ~u.mask) | 125
position('1' IN (u.mask & f.mask)) > 0 | 37
(u.mask & f.mask)::TEXT !~ '^0+$' | 27