PostgreSQL BIT / BIT VARYING values.
Before this namespace a bit value was a bare java.lang.String of
'0'/'1' characters. The digits were right, but nothing else was: the
type reported as text (OID 25) rather than bit (1560), so
pg_typeof(0::bit) answered text and clients that consult the
RowDescription OID mapped the column wrong (issue #19).
A wrapper record — the same shape PgArray and PgRecord already
use — carries the two things a string cannot:
The WIDTH, which is part of the value. PG compares bit strings
with a memcmp of the left-aligned bytes and then breaks ties on
length (varbit.c:817), so B'101' and B'10100000' are NOT equal
and B'0' < B'00' < B'000'. Any representation that trims or
normalises the digits silently changes equality, ordering and
index lookups.
bit vs bit varying, which are distinct types (1560 / 1562) with
different coercion rules: bit(n) zero-pads on the RIGHT to
exactly n, bit varying(n) truncates but never pads.
The digit string stays the storage form because it is exactly PG's
text output format (varbit.c:586 always emits bitlen '0'/'1'
characters — never hex, never a B prefix), and because bits
already encodes the width in its length.
Ordering note: comparing the digit strings lexicographically and then by length gives the same answer as PG's memcmp-then-length, because the zero pad PG compares against behaves like trailing '0' characters and the tie-break covers the proper-prefix case.
PostgreSQL BIT / BIT VARYING values. Before this namespace a bit value was a bare `java.lang.String` of '0'/'1' characters. The digits were right, but nothing else was: the type reported as `text` (OID 25) rather than `bit` (1560), so `pg_typeof(0::bit)` answered `text` and clients that consult the RowDescription OID mapped the column wrong (issue #19). A wrapper record — the same shape `PgArray` and `PgRecord` already use — carries the two things a string cannot: 1. **The WIDTH, which is part of the value.** PG compares bit strings with a memcmp of the left-aligned bytes and then breaks ties on length (varbit.c:817), so `B'101'` and `B'10100000'` are NOT equal and `B'0' < B'00' < B'000'`. Any representation that trims or normalises the digits silently changes equality, ordering and index lookups. 2. **bit vs bit varying**, which are distinct types (1560 / 1562) with different coercion rules: `bit(n)` zero-pads on the RIGHT to exactly n, `bit varying(n)` truncates but never pads. The digit string stays the storage form because it is exactly PG's text output format (varbit.c:586 always emits `bitlen` '0'/'1' characters — never hex, never a `B` prefix), and because `bits` already encodes the width in its length. Ordering note: comparing the digit strings lexicographically and then by length gives the same answer as PG's memcmp-then-length, because the zero pad PG compares against behaves like trailing '0' characters and the tie-break covers the proper-prefix case.
(coerce-width b n explicit?)Apply a bit(n) / bit varying(n) width to a value.
bit zero-pads or truncates on the RIGHT to exactly n (varbit.c:390);
bit varying truncates on the right but NEVER pads, so a shorter
value passes through unchanged (varbit.c:751). Padding on the left,
or padding a varbit, silently corrupts the value.
explicit? distinguishes a cast from an assignment: PG only reshapes
silently for an explicit cast and otherwise raises 22026 / 22001.
Apply a `bit(n)` / `bit varying(n)` width to a value. `bit` zero-pads or truncates on the RIGHT to exactly n (varbit.c:390); `bit varying` truncates on the right but NEVER pads, so a shorter value passes through unchanged (varbit.c:751). Padding on the left, or padding a varbit, silently corrupts the value. `explicit?` distinguishes a cast from an assignment: PG only reshapes silently for an explicit cast and otherwise raises 22026 / 22001.
(compare-bits a b)PG's bit_cmp ordering: content first, then width.
PG's bit_cmp ordering: content first, then width.
(from-integer v n)PG's int -> bit(n): keep the RIGHTMOST n bits, sign-extending on the
left when n exceeds the source width (varbit.c:1550).
29::bit(4) is 1101 — the low nibble — and (-44)::bit(12) is
111111010100. Rendering the integer's binary string and padding on
the wrong end gives wrong bits for every negative value. This never
errors; high bits are silently discarded.
PG's `int -> bit(n)`: keep the RIGHTMOST n bits, sign-extending on the left when n exceeds the source width (varbit.c:1550). `29::bit(4)` is `1101` — the low nibble — and `(-44)::bit(12)` is `111111010100`. Rendering the integer's binary string and padding on the wrong end gives wrong bits for every negative value. This never errors; high bits are silently discarded.
(make-bit bits)(make-bit bits varying?)Construct a bit-string value from a '0'/'1' digit string.
Construct a bit-string value from a '0'/'1' digit string.
(octet-length b)PG's octet_length on a bit string: ceil(width / 8).
PG's `octet_length` on a bit string: ceil(width / 8).
(parse-bit-literal s)(parse-bit-literal s varying?)Parse the text form of a bit value.
Accepts what bit_in accepts (varbit.c:165): a b/B prefix, an
x/X prefix for hex, or a bare digit run. Hex expands to exactly
FOUR bits per digit including leading zeros — X'1F' is the 8-bit
value 00011111, not 5 bits — which is the detail a text-backed
implementation gets wrong (it changes length(), octet_length()
and the sort position).
Raises 22P02 with PG's wording on a bad character.
Parse the text form of a bit value. Accepts what `bit_in` accepts (varbit.c:165): a `b`/`B` prefix, an `x`/`X` prefix for hex, or a bare digit run. Hex expands to exactly FOUR bits per digit including leading zeros — `X'1F'` is the 8-bit value `00011111`, not 5 bits — which is the detail a text-backed implementation gets wrong (it changes `length()`, `octet_length()` and the sort position). Raises 22P02 with PG's wording on a bad character.
(to-long b)PG's bit -> int8: a REINTERPRETATION of the bits, not a range check.
32 one-bits cast to int4 give -1, not 4294967295 (varbit.c:1598).
Only the width is validated.
PG's `bit -> int8`: a REINTERPRETATION of the bits, not a range check. 32 one-bits cast to int4 give -1, not 4294967295 (varbit.c:1598). Only the width is validated.
(to-pg-text b)PG text output: the digit run itself, exactly width characters.
PG text output: the digit run itself, exactly `width` characters.
(width b)Number of bits — PG's length() / bit_length().
Number of bits — PG's `length()` / `bit_length()`.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |