From 37fd13fa0f2b4d777e09bf5642739e9e83785df2 Mon Sep 17 00:00:00 2001 From: fox0430 Date: Wed, 22 Apr 2026 17:34:37 +0900 Subject: [PATCH] docs: Better pg_client docs --- async_postgres/pg_client.nim | 69 +++++++++++++++++++++++++++++++- async_postgres/pg_connection.nim | 31 ++++++++++++-- async_postgres/pg_pool.nim | 9 +++-- 3 files changed, 100 insertions(+), 9 deletions(-) diff --git a/async_postgres/pg_client.nim b/async_postgres/pg_client.nim index fb922fa..cabb0d7 100644 --- a/async_postgres/pg_client.nim +++ b/async_postgres/pg_client.nim @@ -1,3 +1,57 @@ +## Query execution API. +## +## Choosing between extended- and simple-protocol entry points +## =========================================================== +## +## ``exec`` / ``query`` use the **extended query protocol** (Parse / Bind / +## Describe / Execute). They are the default choice for application queries: +## +## - Exactly one statement per call. +## - Typed parameters via ``seq[PgParam]`` or ``openArray[PgParamInline]`` — +## values are bound out-of-band, so no string escaping is required. +## - Reuses server-side prepared statements across calls with identical SQL +## text (bounded by ``stmtCacheCapacity``); the statement is parsed once +## and rebound on subsequent calls. +## - Result rows may use the binary wire format when ``resultFormat = +## rfBinary`` is passed, or on paths that build per-column format codes +## via ``buildResultFormats``. The default ``rfAuto`` returns text rows. +## +## ``simpleExec`` / ``simpleQuery`` use the **simple query protocol** (a single +## ``Query`` message, text-only rows). Prefer them only when the extended +## protocol cannot express what you need: +## +## - **No parameters.** The SQL string is sent verbatim — only use with +## trusted input, or quote identifiers/literals yourself (e.g. via +## ``quoteIdentifier``). +## - **No prepared statement reuse.** Each call re-parses on the server; +## appropriate for one-off session commands (``BEGIN``, ``SET``, +## ``VACUUM`` …) where a cached statement would be wasted. For +## ``LISTEN`` / ``UNLISTEN`` / ``NOTIFY`` prefer the dedicated ``listen``, +## ``unlisten``, and ``notify`` helpers — they quote the channel name for +## you. +## - ``simpleQuery`` accepts multiple ``;``-separated statements and returns +## one ``QueryResult`` per statement — the one case the extended protocol +## cannot cover in a single round trip. +## - ``simpleExec`` expects a side-effect command; the returned tag is the +## **last** ``CommandComplete`` seen, so multi-statement input is accepted +## but per-statement results are not surfaced — use ``simpleQuery`` when +## you need them. +## +## Quick reference +## --------------- +## +## =========================== ========= ============ =========== ============== +## API Protocol Multi-stmt Parameters Plan cache +## =========================== ========= ============ =========== ============== +## ``query`` / ``exec`` extended no yes yes +## ``simpleQuery`` simple yes no no +## ``simpleExec`` simple last-wins no no +## =========================== ========= ============ =========== ============== +## +## Timeout behaviour is shared by all four: when a ``timeout`` is exceeded the +## connection is marked ``csClosed`` (the protocol may be mid-exchange) and a +## pooled connection is discarded on release. + import std/[options, tables, macros] import async_backend, pg_protocol, pg_connection, pg_types @@ -363,7 +417,13 @@ proc exec*( params: seq[PgParam] = @[], timeout: Duration = ZeroDuration, ): Future[CommandResult] {.async.} = - ## Execute a statement with typed parameters. + ## Execute a statement with typed parameters via the extended query protocol. + ## + ## Single statement only; the plan is cached per-connection. Use + ## ``simpleExec`` for parameter-less session commands (``BEGIN``, ``SET``, + ## ``VACUUM``, ``LISTEN`` …) or ``simpleQuery`` when you need multi-statement + ## execution in one round trip. + ## ## On timeout the connection is marked closed (protocol desync) and cannot be ## reused; pooled connections are discarded automatically. var tag: string @@ -991,7 +1051,12 @@ proc query*( resultFormat: ResultFormat = rfAuto, timeout: Duration = ZeroDuration, ): Future[QueryResult] {.async.} = - ## Execute a query with typed parameters. + ## Execute a query with typed parameters via the extended query protocol. + ## + ## Single statement only; the plan is cached per-connection. Use + ## ``simpleQuery`` when you need multiple ``;``-separated statements to run + ## in one round trip (no parameters, text-only rows). + ## ## On timeout the connection is marked closed (protocol desync) and cannot be ## reused; pooled connections are discarded automatically. var qr: QueryResult diff --git a/async_postgres/pg_connection.nim b/async_postgres/pg_connection.nim index 1b55b8a..ddaf31e 100644 --- a/async_postgres/pg_connection.nim +++ b/async_postgres/pg_connection.nim @@ -1547,8 +1547,18 @@ proc quoteIdentifier*(s: string): string = "\"" & s.replace("\"", "\"\"") & "\"" proc simpleQuery*(conn: PgConnection, sql: string): Future[seq[QueryResult]] {.async.} = - ## Execute one or more SQL statements via simple query protocol. - ## Returns one `QueryResult` per statement. Supports multiple statements separated by semicolons. + ## Execute one or more SQL statements via the **simple query protocol**. + ## + ## Returns one ``QueryResult`` per statement; supports multiple statements + ## separated by ``;`` in a single round trip — this is the main reason to + ## choose ``simpleQuery`` over ``query``. + ## + ## No parameters are supported (the SQL string is sent verbatim — only use + ## trusted input) and rows are always in the text wire format. No + ## server-side plan cache entry is created. + ## + ## For single-statement parameterised reads, prefer ``query``; for + ## parameter-less commands without rows, prefer ``simpleExec``. conn.checkReady() var results: seq[QueryResult] @@ -1718,8 +1728,21 @@ proc invalidateOnTimeout*(conn: PgConnection, reason: string) = proc simpleExec*( conn: PgConnection, sql: string, timeout: Duration = ZeroDuration ): Future[CommandResult] {.async.} = - ## Execute a SQL statement via simple query protocol, returning the command result. - ## Lighter than `exec` for parameter-less commands (no Parse/Bind/Describe overhead). + ## Execute a side-effect SQL command via the **simple query protocol**, + ## returning the final command tag. + ## + ## Lighter than ``exec`` for parameter-less commands — one ``Query`` message, + ## no Parse/Bind/Describe round trip and no plan cache entry. Intended for + ## session-level commands such as ``BEGIN``, ``SET``, ``VACUUM``, + ## ``LISTEN``, ``NOTIFY``. + ## + ## The SQL string is sent verbatim (no parameters) — only use trusted input, + ## or quote interpolated identifiers yourself via ``quoteIdentifier``. + ## + ## Multiple ``;``-separated statements are accepted, but only the **last** + ## command tag is returned; use ``simpleQuery`` if you need per-statement + ## results. For parameterised writes, prefer ``exec``. + ## ## On timeout, the connection is marked csClosed (protocol out of sync). var tag: string withConnTracing( diff --git a/async_postgres/pg_pool.nim b/async_postgres/pg_pool.nim index c49cbce..512585b 100644 --- a/async_postgres/pg_pool.nim +++ b/async_postgres/pg_pool.nim @@ -892,7 +892,9 @@ proc queryColumn*( result.add(row.getStr(0)) proc simpleQuery*(pool: PgPool, sql: string): Future[seq[QueryResult]] {.async.} = - ## Execute one or more SQL statements via simple query protocol using a pooled connection. + ## Execute one or more SQL statements via the simple query protocol using a + ## pooled connection. See ``PgConnection.simpleQuery`` for semantics — + ## multi-statement, no parameters, no plan cache. let conn = await pool.acquire() try: return await conn.simpleQuery(sql) @@ -903,8 +905,9 @@ proc simpleQuery*(pool: PgPool, sql: string): Future[seq[QueryResult]] {.async.} proc simpleExec*( pool: PgPool, sql: string, timeout: Duration = ZeroDuration ): Future[CommandResult] {.async.} = - ## Execute a SQL statement via simple query protocol using a pooled connection. - ## Returns the command result. + ## Execute a side-effect SQL command via the simple query protocol using a + ## pooled connection. See ``PgConnection.simpleExec`` for semantics — no + ## parameters, no plan cache, last command tag returned. let conn = await pool.acquire() try: return await conn.simpleExec(sql, timeout)