Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

sql.postgres.types

import sql.postgres.types

sql lifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelled sql.postgres.types.* needs import 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