data.drivers._pelt._protocol

Page actions AI-ready formats and sharing
Open LLM text
Share with AI
Ask Claude Ask ChatGPT Ask Gemini Ask Copilot

Sans-I/O connection protocol engine: backend bytes in → high-level events + outbound bytes.

SimpleQueryProtocolis the pure state machine that drives one PostgreSQL connection. It owns the inbound byte buffer, drains complete…

Sans-I/O connection protocol engine: backend bytes in → high-level events + outbound bytes.

SimpleQueryProtocolis the pure state machine that drives one PostgreSQL connection. It owns the inbound byte buffer, drains complete messages withparse_message() (carrying partial reads forward), and folds the wire-levelPGMessagestream into a small set of high-levelProtocolEventobjects. Outbound work goes the other way: the send_* helpers return frontend bytes (via ._builder) and advance the state, but the engine never touches a socket — connection / pool own anyio I/O in a later epic. This keeps the protocol fuzzable in isolation and parallelizable across free-threaded workers.

Two engines live here.SimpleQueryProtocol(E3 core) models the simple-query protocol: STARTUP/auth → READY, then oneQueryin flight (RowDescription → DataRow* → CommandComplete → ReadyForQuery) and back to READY.ExtendedQueryProtocolmodels the extended-query path — Parse/Bind/Describe/Execute/Sync with$Nparameters — plus a single-ownerPreparedStatementCache(LRU, bounded, clean-miss on plan invalidation) and server-side cursors (anExecute row limit yields PortalSuspended; resume() fetches the next batch). Cancellation lands in a later epic. Raw column bytes are passed through untouched — decoding against the codec plan is the next layer's job; both engines only pair eachDataRowEvent with its RowDescription.

Desync discipline: any message that is illegal for the current state raises ProtocolError. parse_message() already raises ProtocolErroron malformed bytes, so a corrupt object is never handed back; a desynced connection is unrecoverable and must be discarded by the I/O layer.

data.drivers._pelt._protocol

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

class ProtocolState

The connection's wire-protocol phase.

The simple-query lifecycle isSTARTUP → AUTHENTICATING → READY ⇄ BUSY. READY tracks the most recentReadyForQuerytransaction status; …

Jump to symbol
class TransactionStatus

The backend's transaction state, reported by everyReadyForQuery.

Jump to symbol
class AuthOkEvent

AuthenticationOkwas received — credentials accepted, session setup begins.

Jump to symbol
class AuthRequestEvent

The backend requested authentication material the I/O layer must answer.

requestis the originating auth message (cleartext / MD5 / SASL*); the auth layer…

Jump to symbol
class ReadyEvent

ReadyForQuery— the backend is idle and accepting a new command.

Jump to symbol
class RowDescriptionEvent

The column layout for the rows that follow within the current query.

Jump to symbol
class DataRowEvent

One result row, paired with theRowDescriptionit belongs to.

row.values are still raw wire bytes (or Nonefor SQL NULL); decoding against the…

Jump to symbol
class CommandCompleteEvent

A command in the current query finished.tag is e.g. 'SELECT 2' / 'INSERT 0 1'.

Jump to symbol
class EmptyQueryEvent

The submitted query string was empty (EmptyQueryResponse).

Jump to symbol
class ErrorEvent

A serverErrorResponse mapped onto a PostgresError.

The engine surfaces the error rather than raising it so the I/O layer decides whether to…

Jump to symbol
class ParameterStatusEvent

A server runtime parameter report (e.g.server_version), deliverable any time.

Jump to symbol
class BackendKeyDataEvent

Cancellation key material (PID + secret), captured during session setup.

Jump to symbol
class NoticeEvent

A non-fatal server notice, deliverable any time.fields are (code, value)pairs.

Jump to symbol
class NotificationEvent

An asyncNOTIFYpayload (LISTEN/NOTIFY), deliverable any time.

Jump to symbol
class ParseCompleteEvent

ParseComplete — the Parsewas accepted and the named statement now exists.

Jump to symbol
class BindCompleteEvent

BindComplete— parameters were bound and the named portal now exists.

Jump to symbol
class CloseCompleteEvent

CloseComplete — the backend dropped the named statement or portal a Closetargeted.

The acknowledgement of aClose request (the orphaned pelt_stmt_Nstatements that …

Jump to symbol
class ParameterDescriptionEvent

ParameterDescription — the OIDs the server inferred / accepted for $Nparams.

Surfaced after aDescribeof a statement; the cache stores these so…

Jump to symbol
class NoDataEvent

NoData — the described statement/portal returns no rows (e.g. an INSERT).

Jump to symbol
class PortalSuspendedEvent

PortalSuspended — an Executerow limit was reached and more rows remain.

The portal is left open; the I/O layer resumes by issuing another …

Jump to symbol
function map_error_response

Map a backendErrorResponse onto a PostgresError, pulling the standard fields off the message's properties. The SQLSTATE becomes the error's stablePELT_PG_*code;…

Jump to symbol
class SimpleQueryProtocol

A single PostgreSQL connection's sans-I/O protocol state machine.

Per-connection state is single-owner (one engine per connection, never shared between threads), so it is mutable…

Jump to symbol
class PreparedStatement

A cache entry: a server-side prepared statement and the plan it was prepared against.

param_oids is the explicit OID list sent in the Parse…

Jump to symbol
class PreparedStatementCache

A bounded, per-connection LRU cache of prepared statements.

Single-owner, lock-free by design. One cache belongs to one ExtendedQueryProtocol, which belongs to one connection,…

Jump to symbol
class ExtendedQueryProtocol

The extended-query (Parse/Bind/Describe/Execute/Sync) state machine for one connection.

Single-owner and lock-free for the same reason asSimpleQueryProtocol: one engine per connection, never shared.…

Jump to symbol
ProtocolState
class

The connection's wire-protocol phase.

The simple-query lifecycle isSTARTUP → AUTHENTICATING → READY ⇄ BUSY. READY tracks the most recentReadyForQuery transaction status; BUSY means a Queryis in flight and the engine is folding its result stream.CLOSEDis reached after the backend stops talking (gracefulTerminateis initiated by the I/O layer).

TransactionStatus
class

The backend's transaction state, reported by everyReadyForQuery.

AuthOkEvent
class

AuthenticationOkwas received — credentials accepted, session setup begins.

AuthRequestEvent
class

The backend requested authentication material the I/O layer must answer.

requestis the originating auth message (cleartext / MD5 / SASL*); the auth layer (epic E4) inspects it and replies with aPasswordMessage.

ReadyEvent
class

ReadyForQuery— the backend is idle and accepting a new command.

RowDescriptionEvent
class

The column layout for the rows that follow within the current query.

DataRowEvent
class

One result row, paired with theRowDescriptionit belongs to.

row.values are still raw wire bytes (or Nonefor SQL NULL); decoding against the codec plan happens in the next layer.description is never None — a DataRow with no precedingRowDescription is a desync and raises ProtocolError.

CommandCompleteEvent
class

A command in the current query finished.tag is e.g. 'SELECT 2' / 'INSERT 0 1'.

EmptyQueryEvent
class

The submitted query string was empty (EmptyQueryResponse).

ErrorEvent
class

A serverErrorResponse mapped onto a PostgresError.

The engine surfaces the error rather than raising it so the I/O layer decides whether to raise (the common case) or log; either way the trailingReadyForQueryresynchronizes the connection.

ParameterStatusEvent
class

A server runtime parameter report (e.g.server_version), deliverable any time.

BackendKeyDataEvent
class

Cancellation key material (PID + secret), captured during session setup.

NoticeEvent
class

A non-fatal server notice, deliverable any time.fields are (code, value)pairs.

NotificationEvent
class

An asyncNOTIFYpayload (LISTEN/NOTIFY), deliverable any time.

ParseCompleteEvent
class

ParseComplete — the Parsewas accepted and the named statement now exists.

BindCompleteEvent
class

BindComplete— parameters were bound and the named portal now exists.

CloseCompleteEvent
class

CloseComplete — the backend dropped the named statement or portal a Closetargeted.

The acknowledgement of aClose request (the orphaned pelt_stmt_Nstatements that drain_pending_close() surfaces are closed this way). It carries no payload and never desyncs: aCloseComplete is always a legal Closeack, so the engine surfaces it rather than treating it as an illegal message.

ParameterDescriptionEvent
class

ParameterDescription — the OIDs the server inferred / accepted for $Nparams.

Surfaced after aDescribeof a statement; the cache stores these so a later prepare of the same SQL with the same explicit param OIDs is a clean hit (and a different set is a clean miss → re-prepare).

NoDataEvent
class

NoData — the described statement/portal returns no rows (e.g. an INSERT).

PortalSuspendedEvent
class

PortalSuspended — an Executerow limit was reached and more rows remain.

The portal is left open; the I/O layer resumes by issuing anotherExecuteon the same portal (seeresume_execute()). This is the server-side cursor / prefetch-batching primitive that powersDatabase.stream().

map_error_response
function
def map_error_response(error: ErrorResponse) -> PostgresError

Map a backendErrorResponse onto a PostgresError, pulling the standard fields off the message's properties. The SQLSTATE becomes the error's stablePELT_PG_* code; the serverHint rides onto hint.

Parameters

Name Type Default Description
error ErrorResponse
SimpleQueryProtocol
class

A single PostgreSQL connection's sans-I/O protocol state machine.

Per-connection state is single-owner (one engine per connection, never shared between threads), so it is mutable and lock-free by construction — the free-threading discipline for owned state. Feed inbound bytes withreceive_bytes() (any chunking, including one byte at a time, is fine — partial reads are buffered); drive outbound work with the send_*helpers, which return frontend bytes and advance the state.

PreparedStatement
class

A cache entry: a server-side prepared statement and the plan it was prepared against.

param_oids is the explicit OID list sent in the Parse(empty when the server was asked to infer).resolved_param_oidsis what the backend reported back in its ParameterDescription (None until a Describeresolves it). A later prepare whose resolved OIDs disagree is a type mismatch — the entry is evicted and re-prepared rather than reusing a stale plan.

PreparedStatementCache
class

A bounded, per-connection LRU cache of prepared statements.

Single-owner, lock-free by design. One cache belongs to one ExtendedQueryProtocol, which belongs to one connection, which is never shared between threads (the free-threading discipline for owned state — cf.SimpleQueryProtocol). The codec registry is the shared-mutable structure that needs a lock; this cache is not. Putting a lock here would be cargo-culted overhead on a hot path that is provably single-owner.

Keyed by(sql, tuple(param_oids))so the same SQL prepared with different explicit parameter types gets distinct plans. Bounded bysize; reaching capacity evicts the least-recently-used entry (LRU via insertion-orderedOrderedDict, moved-to-end on every hit).size == 0disables caching entirely — every lookup misses and nothing is stored.

Plan invalidation is a clean miss, never a stale reuse: aget() against a stored entry whoseversionis older than the cache's current generation, or whose resolved parameter OIDs disagree with the caller's expectation, drops the entry and returnsNone so the caller re-prepares.bump_version() advances the generation (e.g. after a DDL / schema change the I/O layer observes), invalidating every older entry lazily on next touch.

ExtendedQueryProtocol
class

The extended-query (Parse/Bind/Describe/Execute/Sync) state machine for one connection.

Single-owner and lock-free for the same reason asSimpleQueryProtocol: one engine per connection, never shared. It shares theProtocolState / TransactionStatus vocabulary and the side-band / error / ReadyForQuery handling, then layers the extended message set on top:

  • Prepare (send_parse_describe()): ParseDescribe(statement)Sync. The backend answersParseCompleteParameterDescriptionRowDescription| NoDataReadyForQuery. The resolved parameter OIDs are folded back into the cache entry so a future prepare can detect a type mismatch.
  • Execute (send_bind_execute()): BindExecute(max_rows)Sync. The backend answersBindCompleteDataRow* → (CommandComplete| PortalSuspended) → ReadyForQuery.
  • Resume (resume_execute()): another ExecuteSyncagainst an open portal that previouslyPortalSuspendedEvent-suspended — the server-side cursor.

The whole Parse/Bind/Execute pipeline is sent as one batch terminated by a singleSync, so the backend reports any error once and a single trailingReadyForQueryresynchronizes. Raw column bytes pass through untouched; decoding against the codec plan is the next layer.

Owns an optionalPreparedStatementCache. The high-level prepare/execute helpers consult and update it, but the cache can also be driven directly for tests.

View source · /home/runner/work/chirp/chirp/site/../src/chirp/data/drivers/_pelt/_protocol.py:1