Expand description
Query execution for the Postgres explorer.
Sprint 5 strategy: server-side cursors driven by simple_query.
The cursor holds the result set on the server; the explorer streams
pages on demand. This replaces the Sprint 3 “fetch everything up to
max_rows” approach so users can browse genuinely large tables.
§Why simple_query (still)
Even with cursors, we use simple_query for the FETCH itself —
it returns text representations of every value, which gives us
universal type support (bytea, JSON, arrays, ranges, custom enums,
geometry) without per-OID decoding.
§Cursor lifecycle
BEGIN; DECLARE c_<uuid> NO SCROLL CURSOR FOR <user_sql>opens.FETCH FORWARD <n> FROM c_<uuid>returns the next page; the server’sCommandComplete(actual)tells us how many rows came back, so we know whether more remain (actual == n means there’s probably more; actual < n means the cursor exhausted).CLOSE c_<uuid>; COMMITreleases the server resources.
Single-cursor invariant is enforced by PgClient
(one transaction per connection on the wire). If a second execute
call comes in while a cursor is open, the old one is closed first
— the surfaced CursorExpired error tells the previous tab’s UI
that “Load more” can no longer fetch.
Structs§
- Active
Cursor - Server-side cursor metadata. Held by the client when a query has
remaining rows; consumed (closed) on
close_queryor when the nextexecutecall supersedes it. - Column
Meta - Execution
Outcome - Page
Result
Functions§
- close_
query - Close an active cursor and end its transaction. Best effort — if the connection is already broken we don’t surface an error to callers, since “the result is gone” is the expected interpretation.
- fetch_
page - Fetch the next page from an active cursor.
- open_
query - Open a new query. Closes any previously-active cursor (and its transaction) before starting. Returns the first page synchronously along with a cursor id when more rows remain.