E2 parametric codecs: composite (record), range, and enum types.
Unlike the leaf codecs in._codecs(one OID, one fixed Python type), these three
families are parametric: a composite decodes through a per-field codec list, a range
decodes through its element codec, and an enum's OID is assigned per-database at
CREATE TYPEtime. So this module exports factories that close over the element/field
codecs (or, for enums, the runtime OID) and hand back a ready-to-registerCodec,
plus the standalonedecode_*/encode_*primitives the factories wrap. The
LEAF_CODECStuple is empty — there is no non-parametric codec to pre-register here.
Wire layouts are bit-exact to the PostgreSQL binary protocol (src/backend/utils/adt):
- record (
record_recv):int32 nfields; then per fieldint32 column_oid,int32 length(-1⇒ SQL NULL), thenlengthraw bytes. - range (
range_recv):uint8 flags; then, for each finite bound that is present,int32 length+lengthraw bytes. Flag bits (rangetypes.h):0x01empty,0x02lower-inclusive,0x04upper-inclusive,0x08lower-infinite,0x10upper-infinite. - enum: the value is just its label text; enums share
enum_recv/enum_outwhich are UTF-8 in/out, so the codec is a thin TEXT alias bound to the per-DB OID.
Decoding a record yields a plaintuple(positional) — mapping field names onto a
dict/Row is a plan-layer concern (epic E6), not the codec's. Malformed wire bytes raise
ProtocolError(the sans-I/O fault channel); bad factory arguments raise
ValueError (programmer misuse), mirroring frame().
Live-PG parity is deferred to the E4/E6 integration suite; here we prove the layouts against hand-built wire vectors.
data.drivers._pelt._codecs_composite_range_enum
| Name | Type | Default | Description |
|---|---|---|---|
type
|
|
— | |
qualified_name
|
|
— | |
element_type
|
|
— | |
description
|
|
— | |
source_file
|
|
— | |
line_number
|
|
— | |
is_autodoc
|
|
— | |
autodoc_element
|
|
— | |
_autodoc_template
|
|
— | |
_autodoc_url_path
|
|
— | |
_autodoc_page_type
|
|
— | |
title
|
|
— | |
doc_content_hash
|
|
— |
Symbols on this page
Decode binaryrecord wire bytes into a positional tuple.
field_decoders[i] decodes column i's raw bytes; a Noneentry passes the raw bytes…
Encode a positional sequence into binaryrecordwire bytes.
field_oids[i] is written as the column OID; field_encoders[i]turns a non-NULL value into raw bytes…
Build a binary-only composite/recordCodecfrom per-field codecs.
The three field sequences are positional and must be the same length; a mismatch raises
ValueError…
An immutable PostgreSQL range value.
lower/upper are the decoded bound values, or Nonefor an infinite (unbounded)
or absent bound.lower_inc/…
Decode binaryrange wire bytes into a Range.
A finite, present bound is laid out asint32 length + lengthelement bytes, decoded…
Encode aRange into binary rangewire bytes.
An empty range is a lone flags byte. Otherwise the flags byte is followed by each…
Build a binary-only rangeCodecfrom its element codec's decode/encode pair.
Text format (PostgreSQL's[lo,hi)syntax) is a plan-layer concern and is not modelled;
…
Build aCodec for a user-defined enum at its per-database oid.
Enums are assigned dynamic OIDs atCREATE TYPEtime, so there is…
decode_record
function
def decode_record(data: bytes, field_decoders: Sequence[Callable[[bytes], Any] | None]) -> tuple[Any, ...]
Decode binaryrecord wire bytes into a positional tuple.
field_decoders[i] decodes column i's raw bytes; a Noneentry passes the raw
bytes through undecoded (the OID had no registered codec). SQL NULL columns become
None regardless of the decoder. The on-wire nfieldscount is authoritative; a
decoder-list length mismatch raisesProtocolErrorrather than silently truncating.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data
|
bytes
|
— | |
field_decoders
|
Sequence[Callable[[bytes], Any] | None]
|
— |
encode_record
function
def encode_record(values: Sequence[Any], field_oids: Sequence[int], field_encoders: Sequence[Callable[[Any], bytes] | None]) -> bytes
Encode a positional sequence into binaryrecordwire bytes.
field_oids[i] is written as the column OID; field_encoders[i]turns a non-NULL
value into raw bytes (aNone encoder requires the value to already be bytes).
None values are emitted as SQL NULL (length -1). The three sequences must be the
same length — a mismatch is programmer misuse and raisesValueError.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
values
|
Sequence[Any]
|
— | |
field_oids
|
Sequence[int]
|
— | |
field_encoders
|
Sequence[Callable[[Any], bytes] | None]
|
— |
make_record_codec
function
def make_record_codec(*, oid: int, name: str, field_oids: Sequence[int], field_decoders: Sequence[Callable[[bytes], Any] | None], field_encoders: Sequence[Callable[[Any], bytes] | None]) -> Codec
Build a binary-only composite/recordCodecfrom per-field codecs.
The three field sequences are positional and must be the same length; a mismatch raises
ValueError. Text format is not modelled for composites — PostgreSQL's text record
syntax (quoted, comma-separated) is a plan-layer concern — sodecode_text/
encode_text raise ProtocolErrorif reached.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
oid
|
int
|
— | |
name
|
str
|
— | |
field_oids
|
Sequence[int]
|
— | |
field_decoders
|
Sequence[Callable[[bytes], Any] | None]
|
— | |
field_encoders
|
Sequence[Callable[[Any], bytes] | None]
|
— |
Range
class
An immutable PostgreSQL range value.
lower/upper are the decoded bound values, or Nonefor an infinite (unbounded)
or absent bound.lower_inc/upper_inc flag inclusive bounds. emptymarks the
empty range, in which case the bounds carry no meaning.
decode_range
function
def decode_range(data: bytes, element_decode: Callable[[bytes], Any]) -> Range
Decode binaryrange wire bytes into a Range.
A finite, present bound is laid out asint32 length + lengthelement bytes, decoded
viaelement_decode. Infinite bounds carry no payload. The empty range carries only the
flags byte. Truncation or a stray trailing byte raisesProtocolError.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
data
|
bytes
|
— | |
element_decode
|
Callable[[bytes], Any]
|
— |
encode_range
function
def encode_range(value: Range, element_encode: Callable[[Any], bytes]) -> bytes
Encode aRange into binary rangewire bytes.
An empty range is a lone flags byte. Otherwise the flags byte is followed by each present
finite bound (int32 length+ element bytes); a bound is treated as infinite when its
value isNone. Inclusivity flags ride along — except for an infinite bound, whose
inclusive bit is always cleared to match PostgreSQL's canonical wire form (range_serialize /
make_range force an infinite bound to inclusive=false). SoRange(lower=None, lower_inc=True)serializes with RANGE_LB_INC cleared, not RANGE_LB_INC | RANGE_LB_INF.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
value
|
Range
|
— | |
element_encode
|
Callable[[Any], bytes]
|
— |
make_range_codec
function
def make_range_codec(*, oid: int, name: str, element_decode: Callable[[bytes], Any], element_encode: Callable[[Any], bytes]) -> Codec
Build a binary-only rangeCodecfrom its element codec's decode/encode pair.
Text format (PostgreSQL's[lo,hi)syntax) is a plan-layer concern and is not modelled;
decode_text/encode_text raise ProtocolErrorif reached.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
oid
|
int
|
— | |
name
|
str
|
— | |
element_decode
|
Callable[[bytes], Any]
|
— | |
element_encode
|
Callable[[Any], bytes]
|
— |
make_enum_codec
function
def make_enum_codec(oid: int, name: str) -> Codec
Build aCodec for a user-defined enum at its per-database oid.
Enums are assigned dynamic OIDs atCREATE TYPEtime, so there is no static codec to
pre-register — the connection discovers the OID and calls this factory. On the wire an enum
value is just its label, identical in binary and text format, so the codec is a thin UTF-8
str alias (text-preferred, like _text_codec()).
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
oid
|
int
|
— | |
name
|
str
|
— |