async_postgres/pg_connection/cache

Client-side LRU cache for server-prepared statements.

Holds the server statement name, parameter OIDs, field descriptions and pre-computed result formats for each cached SQL. The Extended Query send paths look up cached entries with lookupStmtCache, evict before adding via addStmtCache, and use pendingStmtCloses to bundle Close messages with the next operation's Sync.

Internal module: not part of the public API. Import the pg_connection hub instead; what it re-exports is the supported surface (see tests/api_surface.golden).

Procs

proc addStmtCache(conn: PgConnection; sql: string; cached: CachedStmt) {.
    ...raises: [KeyError], tags: [], forbids: [].}
Add a prepared statement to the cache with auto-computed result formats. Callers are expected to evict and send a server-side Close for the evicted statement before sending Parse, so the loop below normally does not fire. It is a defensive guard: if a caller ever skips the pre-eviction step (or if stmtCacheCapacity was shrunk below the current size), we evict here instead of silently dropping the new entry and queue the evicted names in pendingStmtCloses so the next Extended Query operation can send their server-side Close.
proc beginSendBuf(conn: PgConnection) {....raises: [PgTypeError, PgProtocolError],
                                        tags: [], forbids: [].}

Start a new operation's send buffer: empty it, then stage the queued Close messages into it.

One call because the order is an invariant: staging first and emptying after would truncate the Closes back out. Emptying loses nothing — whatever the previous operation left was either sent or still staged, and the staging below takes it back.

proc clearStmtCache(conn: PgConnection) {....raises: [], tags: [], forbids: [].}
Clear the client-side statement cache. Does not close server-side statements, including any Close messages queued in pendingStmtCloses from defensive eviction — the queue is dropped on the assumption the caller will reset the session externally (e.g. via DISCARD ALL or by closing the connection).
proc evictForInsert(conn: PgConnection; buf: var seq[byte]) {.
    ...raises: [KeyError, PgTypeError, PgProtocolError], tags: [], forbids: [].}
Make room for one more cache entry, staging the Close of whatever was evicted into buf — the buffer this operation assembles, like stagePendingStmtCloses / stageEvictedClose. Keeping the capacity comparison here also lets the queryDirect / execDirect writers reach it without unlocking PgConnection in the caller's scope: they pass sendBuf(conn).
proc evictStmtCache(conn: PgConnection): CachedStmt {....raises: [KeyError],
    tags: [], forbids: [].}
Evict the least recently used entry from the cache. Returns the evicted entry.
proc lookupStmtCache(conn: PgConnection; sql: string): CachedStmt {....raises: [],
    tags: [], forbids: [].}
Look up a cached prepared statement by SQL text, updating LRU order on hit. Returns nil on miss. Because CachedStmt is a ref, the returned value remains valid even if the cache is mutated afterwards — the entry's lifetime is extended by the reference.
proc nextStmtName(conn: PgConnection): string {....raises: [], tags: [],
    forbids: [].}
Generate the next unique prepared statement name for the statement cache.
proc removeStmtCache(conn: PgConnection; sql: string) {....raises: [], tags: [],
    forbids: [].}
Remove a statement from the cache by its SQL text.
proc sendStagedBufMsg(conn: PgConnection): owned(Future[void]) {.
    ...stackTrace: false, raises: [Exception, CancelledError, PgStateError,
                                CatchableError, PgConnectionError, ValueError],
    tags: [RootEffect], forbids: [].}
sendBufMsg paired with stagePendingStmtCloses: drop the staged statement Closes only once the buffer is on the wire.
proc sendStagedMsg(conn: PgConnection; data: seq[byte]): owned(Future[void]) {.
    ...stackTrace: false, raises: [Exception, CancelledError, PgStateError,
                                CatchableError, PgConnectionError, ValueError],
    tags: [RootEffect], forbids: [].}
sendMsg counterpart, for builds that assemble their own buffer.
proc stageEvictedClose(conn: PgConnection; buf: var seq[byte]; name: string) {.
    ...raises: [PgTypeError, PgProtocolError], tags: [], forbids: [].}
Stage the Close for a statement the build itself evicted. Staged, not queued: the cache no longer remembers the name, and an aborted build leaves staged names owed just as the queue would.
proc stagePendingStmtCloses(conn: PgConnection; buf: var seq[byte]) {.
    ...raises: [PgTypeError, PgProtocolError], tags: [], forbids: [].}

Append a Close for every owed statement name to buf so they ride along with this operation's Sync, moving them from the queue to stagedStmtCloses.

Only sendStagedBufMsg / sendStagedMsg drop them, once the bytes are on the wire: an aborted build leaves them staged, the next one takes them back here, and a re-sent Close is a backend no-op.

buf must already be emptied, or the build truncates the Closes away.

proc stmtCachingEnabled(conn: PgConnection): bool {.inline, ...raises: [],
    tags: [], forbids: [].}
Whether prepared statements are cached on this connection.