sql.postgres.types
import sql.postgres.types
sqllifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledsql.postgres.types.*needsimport sql.postgres.types.
Encoding and decoding PostgreSQL’s binary value formats.
PostgreSQL will send a value either as text or as the server’s own
binary representation, chosen per column. Binary is what this adapter
asks for wherever it has a decoder, because it is exact: a float8
arrives as the same eight bytes the server holds rather than as a
decimal rendering that has to be parsed back, and a numeric arrives as
its actual digits rather than as text that a double would round.
Where there is no decoder, text is asked for instead and the value arrives as a string. That is the important half of the design: a type this adapter has never heard of, including one an extension added, still comes back as something readable rather than as bytes nobody can interpret.
Constants
OIDS
sql.postgres.OIDS = {...}
PostgreSQL’s built-in type OIDs, by name.
An array type has an OID of its own, listed here as <Type>Array.
ARRAY_ELEMENTS
sql.postgres.types.ARRAY_ELEMENTS = {...}
The element type each array OID holds.
EPOCH_OFFSET
sql.postgres.types.EPOCH_OFFSET = 946684800
Seconds between the Unix epoch and PostgreSQL’s, which is 2000-01-01 rather than 1970-01-01.
DEFAULT_REGISTRY
sql.postgres.DEFAULT_REGISTRY
The registry every connection uses unless given one of its own.
Functions
read_int16()
sql.postgres.types.read_int16(buffer, at: number) -> number
Reads a signed 16 bit big-endian integer.
Parameters
buffer(bytes)at(number)
Returns number
read_uint16()
sql.postgres.types.read_uint16(buffer, at: number) -> number
Reads an unsigned 16 bit big-endian integer.
Parameters
buffer(bytes)at(number)
Returns number
read_int32()
sql.postgres.types.read_int32(buffer, at: number) -> number
Reads a signed 32 bit big-endian integer.
Parameters
buffer(bytes)at(number)
Returns number
read_uint32()
sql.postgres.types.read_uint32(buffer, at: number) -> number
Reads an unsigned 32 bit big-endian integer.
Parameters
buffer(bytes)at(number)
Returns number
read_int64()
sql.postgres.types.read_int64(buffer, at: number) -> number
Reads a signed 64 bit big-endian integer.
Built from the two halves rather than shifted in one go, because the top bits of a 64 bit value do not survive a bitwise shift on a double.
Parameters
buffer(bytes)at(number)
Returns number
write_int16()
sql.postgres.types.write_int16(value: number) -> list[number]
Writes a signed 16 bit big-endian integer.
Parameters
value(number)
Returns list[number]
write_int32()
sql.postgres.types.write_int32(value: number) -> list[number]
Writes a signed 32 bit big-endian integer.
Parameters
value(number)
Returns list[number]
write_int64()
sql.postgres.types.write_int64(value: number) -> list[number]
Writes a signed 64 bit big-endian integer.
Parameters
value(number)
Returns list[number]
text_of()
sql.postgres.types.text_of(buffer) -> string
A bytes slice as a UTF-8 string.
Parameters
buffer(bytes)
Returns string
decode_numeric()
sql.postgres.types.decode_numeric(buffer) -> Decimal|number
Decodes PostgreSQL’s numeric into an exact Decimal.
The wire form is a count of base 10000 digits, the position of the first
of them relative to the decimal point, a sign, the number of places to
display, and then the digits. Reassembling it as text and handing that
to Decimal keeps every digit; going through a double anywhere in here
would defeat the point of the type.
Parameters
buffer(bytes)
Returns Decimal|number
encode_numeric()
sql.postgres.types.encode_numeric(value) -> list[number]
Encodes a Decimal, a number or a bigint as numeric.
Parameters
value(Decimal|number|bigint)
Returns list[number]
date_from_micros()
sql.postgres.types.date_from_micros(micros: number) -> date.Date
Turns a count of microseconds since the PostgreSQL epoch into a
date.Date in UTC.
Parameters
micros(number)
Returns date.Date
micros_from_date()
sql.postgres.types.micros_from_date(moment) -> number
The microseconds since the PostgreSQL epoch a date.Date stands for.
Parameters
moment(date.Date)
Returns number
decode_bool()
sql.postgres.types.decode_bool(buffer, _oid)
A decoder reads one column value from its binary form.
Each takes the value’s bytes and the OID it arrived under, and returns a Zuri value.
decode_int2()
sql.postgres.types.decode_int2(buffer, _oid)
decode_int4()
sql.postgres.types.decode_int4(buffer, _oid)
decode_int8()
sql.postgres.types.decode_int8(buffer, _oid)
decode_oid()
sql.postgres.types.decode_oid(buffer, _oid)
decode_float4()
sql.postgres.types.decode_float4(buffer, _oid)
decode_float8()
sql.postgres.types.decode_float8(buffer, _oid)
decode_text()
sql.postgres.types.decode_text(buffer, _oid)
decode_bytea()
sql.postgres.types.decode_bytea(buffer, _oid)
decode_json()
sql.postgres.types.decode_json(buffer, _oid)
decode_jsonb()
sql.postgres.types.decode_jsonb(buffer, _oid)
jsonb carries a version byte in front of the text, which every server
so far sets to 1.
decode_uuid()
sql.postgres.types.decode_uuid(buffer, _oid)
decode_numeric_value()
sql.postgres.types.decode_numeric_value(buffer, _oid)
decode_date()
sql.postgres.types.decode_date(buffer, _oid)
date is a count of days from 2000-01-01, with no time part.
decode_time()
sql.postgres.types.decode_time(buffer, _oid)
time is microseconds since midnight, with no date part. It comes back
as a dictionary rather than a date.Date, because a time of day is not
a point in time and giving it an arbitrary date would be inventing
information.
decode_timetz()
sql.postgres.types.decode_timetz(buffer, _oid)
timetz is a time followed by its offset in seconds west of UTC.
decode_timestamp()
sql.postgres.types.decode_timestamp(buffer, _oid)
Both timestamp and timestamptz are microseconds from the PostgreSQL
epoch.
The server holds a timestamptz in UTC and converts on the way in and
out, so what arrives is already UTC and is handed back as such. A
timestamp has no zone at all; it is read as UTC because a date.Date
has to say something, and UTC is the only answer that does not invent a
zone the value never had.
decode_interval()
sql.postgres.types.decode_interval(buffer, _oid)
interval is a span rather than a point, so it comes back as its parts.
Months and days are kept separate from the time because neither has a
fixed length: a month is 28 to 31 days, and a day across a daylight
saving change is not 24 hours.
decode_inet()
sql.postgres.types.decode_inet(buffer, _oid)
inet and cidr share a form: address family, prefix bits, a flag
saying which of the two it is, then the address bytes.
decode_macaddr()
sql.postgres.types.decode_macaddr(buffer, _oid)
decode_point()
sql.postgres.types.decode_point(buffer, _oid)
decode_lseg()
sql.postgres.types.decode_lseg(buffer, _oid)
decode_box()
sql.postgres.types.decode_box(buffer, _oid)
decode_circle()
sql.postgres.types.decode_circle(buffer, _oid)
encode_bool()
sql.postgres.types.encode_bool(value)
An encoder turns a Zuri value into the bytes of its binary form.
encode_int2()
sql.postgres.types.encode_int2(value)
encode_int4()
sql.postgres.types.encode_int4(value)
encode_int8()
sql.postgres.types.encode_int8(value)
encode_float4()
sql.postgres.types.encode_float4(value)
encode_float8()
sql.postgres.types.encode_float8(value)
encode_text()
sql.postgres.types.encode_text(value)
encode_bytea()
sql.postgres.types.encode_bytea(value)
encode_json()
sql.postgres.types.encode_json(value)
encode_jsonb()
sql.postgres.types.encode_jsonb(value)
jsonb takes the same text behind the version byte the server expects.
encode_uuid()
sql.postgres.types.encode_uuid(value)
encode_date()
sql.postgres.types.encode_date(value)
encode_timestamp()
sql.postgres.types.encode_timestamp(value)
encode_array()
sql.postgres.types.encode_array(value, element_oid, registry)
Builds the binary form of an array.
One dimension only. PostgreSQL’s arrays can nest, but a nested Zuri list would have to be rectangular to become one, and quietly refusing a ragged list is worse than not offering it.
decode_array()
sql.postgres.types.decode_array(buffer, oid, registry)
Reads an array back, however many dimensions it has.
Classes
TypeRegistry
class sql.postgres.TypeRegistry
Which decoder and encoder each OID uses.
A registry can be extended, which is how a program teaches the adapter about a type its database defines that PostgreSQL does not ship:
registry.register(oid, decoder, encoder)
The important question a registry answers is knows(): the adapter asks
for a column in binary only when the answer is yes, and asks for text
otherwise, so an unregistered type arrives as a readable string rather
than as bytes.
Constructor
sql.postgres.TypeRegistry()
TypeRegistry.register()
sql.postgres.TypeRegistry.register(oid: number, decoder, encoder)
Adds or replaces the codec for one OID.
Parameters
oid(number)decoder(function) — Takes(bytes, oid)and returns a value.encoder(function) — Takes a value and returns a list of bytes.
TypeRegistry.knows()
sql.postgres.TypeRegistry.knows(oid: number) -> bool
Whether this registry can read oid in binary.
Parameters
oid(number)
Returns bool
TypeRegistry.can_encode()
sql.postgres.TypeRegistry.can_encode(oid: number) -> bool
Whether this registry can write oid in binary.
A parameter whose type has no encoder is sent as text and left to the server to read, which it can do for every type it knows.
Parameters
oid(number)
Returns bool
TypeRegistry.decode()
sql.postgres.TypeRegistry.decode(buffer, oid: number) -> any
Reads a value from its binary form.
Parameters
buffer(bytes)oid(number)
Returns any
TypeRegistry.encode()
sql.postgres.TypeRegistry.encode(value, oid: number) -> list[number]
Writes a value in binary form.
Parameters
value(any)oid(number)
Returns list[number]
TypeRegistry.infer()
sql.postgres.TypeRegistry.infer(value) -> number
The OID that best carries value when the server has not said which
type it expects.
Parameters
value(any)
Returns number
2026, Richard Ore and Zuri contributors