Skip to content

Commit 59040a1

Browse files
committed
docs: add Postgres wire protocol page + export PgConnectionHandler
The pg-wire module (server, handler, protocol) had zero documentation despite being a complete, tested feature (14 tests). New docs page covers quick start, configuration, supported SQL, programmatic use, type mapping, and limitations. PgConnectionHandler and PgConnectionOptions now exported from the main package entry point.
1 parent 11c16b4 commit 59040a1

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed

docs/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export default defineConfig({
3232
{ label: "Error Handling", slug: "error-handling" },
3333
{ label: "Vector Search", slug: "vector-search" },
3434
{ label: "Write Path", slug: "write-path" },
35+
{ label: "Postgres Wire Protocol", slug: "pg-wire" },
3536
{ label: "Deployment", slug: "deployment" },
3637
],
3738
}),

docs/src/content/docs/pg-wire.mdx

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
title: Postgres Wire Protocol
3+
description: Connect with psql, DBeaver, or any BI tool that speaks PostgreSQL.
4+
---
5+
6+
QueryMode includes a PostgreSQL wire protocol server. Any tool that connects to Postgres — `psql`, DBeaver, Metabase, Grafana, TablePlus, DataGrip — can query your data without code changes.
7+
8+
## Quick start
9+
10+
```bash
11+
# Start the pg-wire server (reads files from current directory)
12+
npx tsx src/pg-wire/server.ts
13+
14+
# Connect with psql
15+
psql -h localhost -p 5433 -U querymode
16+
```
17+
18+
Then query as normal SQL:
19+
20+
```sql
21+
SELECT * FROM './data/events.parquet' WHERE region = 'us' LIMIT 10;
22+
SELECT region, COUNT(*), AVG(amount) FROM './data/orders.lance' GROUP BY region;
23+
```
24+
25+
## Configuration
26+
27+
| Environment variable | Default | Description |
28+
|---------------------|---------|-------------|
29+
| `PG_PORT` | `5433` | Listen port |
30+
| `PG_HOST` | `127.0.0.1` | Bind address |
31+
32+
```bash
33+
PG_PORT=5432 PG_HOST=0.0.0.0 npx tsx src/pg-wire/server.ts
34+
```
35+
36+
## Supported SQL
37+
38+
The pg-wire server uses QueryMode's SQL parser, so all [SQL syntax](/querymode/sql/) is supported:
39+
40+
- `SELECT`, `WHERE`, `GROUP BY`, `HAVING`, `ORDER BY`, `LIMIT`, `OFFSET`
41+
- `JOIN` (inner, left, right, full, cross)
42+
- Window functions (`ROW_NUMBER`, `RANK`, `LAG`, `LEAD`, rolling aggregates)
43+
- CTEs (`WITH ... AS`)
44+
- Set operations (`UNION`, `INTERSECT`, `EXCEPT`)
45+
- Vector search (`WHERE embedding NEAR [...] TOPK 10`)
46+
- All 14 filter operators, `CASE`, `CAST`, arithmetic, `||` concatenation
47+
- `--` line comments and `/* */` block comments
48+
49+
### Compatibility commands
50+
51+
These are accepted and acknowledged for BI tool compatibility but have no effect:
52+
53+
- `SET client_encoding TO 'UTF8'`
54+
- `RESET ALL`
55+
- `DISCARD ALL`
56+
- `SHOW <parameter>` (returns `"on"` for all parameters)
57+
58+
## Programmatic use
59+
60+
The `PgConnectionHandler` class can be embedded in any Node.js TCP server or WebSocket bridge:
61+
62+
```typescript
63+
import { QueryMode } from "querymode/local"
64+
import { PgConnectionHandler } from "querymode"
65+
import * as net from "node:net"
66+
67+
const qm = QueryMode.local()
68+
69+
net.createServer((socket) => {
70+
const handler = new PgConnectionHandler({
71+
executor: qm.getExecutor(),
72+
send: (data) => socket.write(data),
73+
})
74+
75+
socket.on("data", async (chunk) => {
76+
await handler.onData(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength))
77+
})
78+
}).listen(5433)
79+
```
80+
81+
The handler manages the full connection lifecycle:
82+
1. **Startup** — SSL negotiation (rejected), authentication (always ok), server parameters
83+
2. **Query** — SQL parsing, compilation, execution via the QueryMode pipeline
84+
3. **Response**`RowDescription` + `DataRow` messages with proper type OIDs
85+
4. **Error** — SQL errors return `ErrorResponse` and the connection stays open
86+
87+
## Type mapping
88+
89+
QueryMode types map to PostgreSQL type OIDs:
90+
91+
| QueryMode type | Postgres type | OID |
92+
|---------------|--------------|-----|
93+
| `int8`, `int16` | `INT2` | 21 |
94+
| `int32` | `INT4` | 23 |
95+
| `int64` | `INT8` | 20 |
96+
| `float32` | `FLOAT4` | 700 |
97+
| `float64` | `FLOAT8` | 701 |
98+
| `utf8` | `TEXT` | 25 |
99+
| `bool` | `BOOL` | 16 |
100+
| `binary` | `BYTEA` | 17 |
101+
102+
## Limitations
103+
104+
- **Simple Query protocol only** — extended query protocol (prepared statements, `DESCRIBE`, `BIND`) is not supported. Most BI tools fall back to Simple Query automatically.
105+
- **No authentication** — all connections are accepted. Run behind a firewall or SSH tunnel for production use.
106+
- **No SSL/TLS** — SSL requests are rejected; clients retry in plaintext. Use an SSH tunnel or reverse proxy for encrypted connections.
107+
- **Local mode only** — the built-in server uses `LocalExecutor`. For edge mode, build a custom server that passes a `RemoteExecutor` to `PgConnectionHandler`.

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ export type { LocalTimingInfo } from "./format.js";
4141
export { sqlToDescriptor } from "./sql/index.js";
4242
export { parse as parseSql } from "./sql/index.js";
4343
export { SqlParseError, SqlLexerError } from "./sql/index.js";
44+
export { PgConnectionHandler } from "./pg-wire/handler.js";
45+
export type { PgConnectionOptions } from "./pg-wire/handler.js";
4446
export { HnswIndex, cosineDistance, l2DistanceSq, dotDistance } from "./hnsw.js";
4547
export type { HnswOptions } from "./hnsw.js";
4648
export { MaterializationCache, queryHashKey } from "./lazy.js";

0 commit comments

Comments
 (0)