Skip to content

Commit e774d42

Browse files
authored
Merge pull request #6 from PostHog/docs/update-readme
Add COPY protocol, graceful shutdown, and enhanced pg_catalog support
2 parents 6d94943 + ce06834 commit e774d42

7 files changed

Lines changed: 861 additions & 7 deletions

File tree

‎CLAUDE.md‎

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Claude Code Context for Duckgres
2+
3+
This file provides context for Claude Code sessions working on this codebase.
4+
5+
## Project Overview
6+
7+
Duckgres is a PostgreSQL wire protocol server backed by DuckDB. It allows any PostgreSQL client (psql, pgAdmin, lib/pq, psycopg2, JDBC, etc.) to connect and execute queries against DuckDB databases.
8+
9+
## Architecture
10+
11+
```
12+
PostgreSQL Client → TLS → Duckgres Server → DuckDB (per-user database)
13+
```
14+
15+
### Key Components
16+
17+
- **main.go**: Entry point, configuration loading (CLI flags, env vars, YAML)
18+
- **server/server.go**: Server struct, connection handling, graceful shutdown
19+
- **server/conn.go**: Client connection handling, query execution, COPY protocol
20+
- **server/protocol.go**: PostgreSQL wire protocol message encoding/decoding
21+
- **server/catalog.go**: pg_catalog compatibility (views, functions, query rewriting)
22+
- **server/types.go**: Type OID mapping between DuckDB and PostgreSQL
23+
- **server/ratelimit.go**: Rate limiting for brute-force protection
24+
- **server/tls.go**: Auto-generation of self-signed TLS certificates
25+
26+
## PostgreSQL Wire Protocol
27+
28+
The server implements the PostgreSQL v3 protocol:
29+
30+
### Message Types (server/protocol.go)
31+
- **Frontend (client→server)**: Query, Parse, Bind, Describe, Execute, Sync, Close, CopyData, CopyDone
32+
- **Backend (server→client)**: AuthOK, RowDescription, DataRow, CommandComplete, ReadyForQuery, CopyInResponse, CopyOutResponse
33+
34+
### Query Flow
35+
1. Client sends Query message ('Q')
36+
2. Server parses SQL, rewrites pg_catalog references
37+
3. Server executes via DuckDB's database/sql driver
38+
4. Server sends RowDescription + DataRow messages
39+
5. Server sends CommandComplete + ReadyForQuery
40+
41+
### Extended Query Protocol
42+
Supports prepared statements (Parse/Bind/Execute) for parameterized queries and binary result formats.
43+
44+
## pg_catalog Compatibility (server/catalog.go)
45+
46+
psql and other clients expect PostgreSQL system catalogs. We provide compatibility by:
47+
48+
1. **Creating views** in main schema that mirror pg_catalog tables:
49+
- `pg_database`, `pg_class_full`, `pg_collation`, `pg_policy`, `pg_roles`
50+
- `pg_statistic_ext`, `pg_publication`, `pg_publication_rel`, `pg_inherits`, etc.
51+
52+
2. **Creating macros** for PostgreSQL functions:
53+
- `pg_get_userbyid`, `pg_table_is_visible`, `format_type`, `pg_get_expr`
54+
- `obj_description`, `col_description`, `pg_get_indexdef`, etc.
55+
56+
3. **Query rewriting** to replace PostgreSQL-specific syntax:
57+
- `pg_catalog.pg_class` → `pg_class_full`
58+
- `OPERATOR(pg_catalog.~)` → `~`
59+
- `::pg_catalog.regtype` → `::VARCHAR`
60+
61+
## COPY Protocol (server/conn.go)
62+
63+
Supports bulk data transfer:
64+
- **COPY TO STDOUT**: Streams query results to client
65+
- **COPY FROM STDIN**: Receives data from client, inserts row by row
66+
- Supports CSV format with HEADER option
67+
68+
## Configuration
69+
70+
Three-tier configuration (highest to lowest priority):
71+
1. CLI flags (`--port`, `--config`, etc.)
72+
2. Environment variables (`DUCKGRES_PORT`, etc.)
73+
3. YAML config file
74+
4. Built-in defaults
75+
76+
## Testing
77+
78+
```bash
79+
# Build
80+
go build -o duckgres .
81+
82+
# Run on non-standard port
83+
./duckgres --port 35437
84+
85+
# Connect with psql
86+
PGPASSWORD=postgres psql "host=127.0.0.1 port=35437 user=postgres sslmode=require"
87+
88+
# Test commands
89+
\dt # List tables
90+
\d tablename # Describe table
91+
\l # List databases
92+
```
93+
94+
## Common Development Tasks
95+
96+
### Adding a new pg_catalog view
97+
1. Add view creation SQL in `initPgCatalog()` in `catalog.go`
98+
2. Add regex pattern to rewrite `pg_catalog.viewname` to `viewname`
99+
3. Add the replacement in `rewritePgCatalogQuery()`
100+
101+
### Adding a new PostgreSQL function
102+
1. Add `CREATE MACRO` in the `functions` slice in `initPgCatalog()`
103+
2. Add function name to `pgCatalogFunctions` slice for query rewriting
104+
105+
### Adding protocol support
106+
1. Add message type constant in `protocol.go`
107+
2. Add write function (e.g., `writeCopyData()`)
108+
3. Handle in message loop in `conn.go`
109+
110+
## Dependencies
111+
112+
- `github.com/duckdb/duckdb-go/v2` - DuckDB Go driver
113+
- `gopkg.in/yaml.v3` - YAML config parsing
114+
115+
## Known Limitations
116+
117+
- Single process (all users share one process)
118+
- No replication
119+
- Some pg_catalog tables are stubs (return empty)
120+
- Type OID mapping is incomplete (some types show as "unknown")
121+
122+
## TODO Reference
123+
124+
See `TODO.md` for the full feature roadmap and known issues.

‎README.md‎

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ A PostgreSQL wire protocol compatible server backed by DuckDB. Connect with any
77
- **PostgreSQL Wire Protocol**: Full compatibility with PostgreSQL clients
88
- **TLS Encryption**: Required TLS connections with auto-generated self-signed certificates
99
- **Per-User Databases**: Each authenticated user gets their own isolated DuckDB database file
10-
- **Password Authentication**: MD5 password authentication
10+
- **Password Authentication**: Cleartext password authentication over TLS
1111
- **Extended Query Protocol**: Support for prepared statements, binary format, and parameterized queries
12+
- **COPY Protocol**: Bulk data import/export with `COPY FROM STDIN` and `COPY TO STDOUT`
1213
- **DuckDB Extensions**: Configurable extension loading (ducklake enabled by default)
1314
- **DuckLake Integration**: Auto-attach DuckLake catalogs for lakehouse workflows
1415
- **Rate Limiting**: Built-in protection against brute-force attacks
16+
- **Graceful Shutdown**: Waits for in-flight queries before exiting
1517
- **Flexible Configuration**: YAML config files, environment variables, and CLI flags
1618

1719
## Quick Start
@@ -144,6 +146,46 @@ ATTACH 'ducklake:postgres:host=localhost dbname=ducklake' (DATA_PATH 's3://my-bu
144146

145147
See [DuckLake documentation](https://ducklake.select/docs/stable/duckdb/usage/connecting) for more details.
146148

149+
## COPY Protocol
150+
151+
Duckgres supports PostgreSQL's COPY protocol for efficient bulk data import and export:
152+
153+
```sql
154+
-- Export data to stdout (tab-separated)
155+
COPY tablename TO STDOUT;
156+
157+
-- Export as CSV with headers
158+
COPY tablename TO STDOUT WITH CSV HEADER;
159+
160+
-- Export query results
161+
COPY (SELECT * FROM tablename WHERE id > 100) TO STDOUT WITH CSV;
162+
163+
-- Import data from stdin
164+
COPY tablename FROM STDIN;
165+
166+
-- Import CSV with headers
167+
COPY tablename FROM STDIN WITH CSV HEADER;
168+
```
169+
170+
This works with psql's `\copy` command and programmatic COPY operations from PostgreSQL drivers.
171+
172+
## Graceful Shutdown
173+
174+
Duckgres handles shutdown signals (SIGINT, SIGTERM) gracefully:
175+
176+
- Stops accepting new connections immediately
177+
- Waits for in-flight queries to complete (default 30s timeout)
178+
- Logs active connection count during shutdown
179+
- Closes all database connections cleanly
180+
181+
The shutdown timeout can be configured:
182+
183+
```go
184+
cfg := server.Config{
185+
ShutdownTimeout: 60 * time.Second,
186+
}
187+
```
188+
147189
## Rate Limiting
148190

149191
Built-in rate limiting protects against brute-force authentication attacks:
@@ -219,6 +261,7 @@ GROUP BY name;
219261
- `DROP TABLE/INDEX/VIEW`
220262
- `ALTER TABLE`
221263
- `BEGIN/COMMIT/ROLLBACK` (DuckDB transaction support)
264+
- `COPY` - Bulk data loading and export (see below)
222265

223266
### PostgreSQL Compatibility
224267
- Extended query protocol (prepared statements)

‎TODO.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,26 @@
1616

1717
### Protocol Compatibility
1818
- [ ] **Binary Format Support**: Encode results in binary format for better performance with some clients
19-
- [ ] **COPY Protocol**: Support `COPY FROM`/`COPY TO` for bulk data loading
19+
- [x] **COPY Protocol**: Support `COPY FROM`/`COPY TO` for bulk data loading
2020
- [ ] **Cancel Request Handling**: Properly cancel long-running queries
2121

2222
### Compatibility
2323
- [x] **System Catalog Emulation**: Basic `pg_catalog` compatibility for psql
2424
- [x] `\dt` (list tables) - working
2525
- [x] `\l` (list databases) - working
26-
- [ ] `\d <table>` (describe table) - needs more pg_class columns
26+
- [x] `\d <table>` (describe table) - working
2727
- [ ] **Information Schema**: Emulate PostgreSQL's `information_schema`
2828
- [ ] **Session Variables**: Support `SET` commands (timezone, search_path, etc.)
2929
- [ ] **Type OID Mapping**: Proper PostgreSQL OID mapping for all DuckDB types
3030

3131
### Features
32-
- [ ] **Extensions**: Load DuckDB extensions on startup
32+
- [x] **Extensions**: Load DuckDB extensions on startup
3333

3434
### Operations
3535
- [ ] **Hot Reload**: Reload config without restart
3636
- [ ] **Admin Commands**: `\duckgres status`, `\duckgres users`, etc.
3737
- [ ] **Docker Image**: Official container image
38-
- [ ] **Graceful Shutdown**: Finish in-flight queries before shutdown
38+
- [x] **Graceful Shutdown**: Finish in-flight queries before shutdown
3939

4040
## Medium Priority
4141

@@ -73,7 +73,7 @@
7373
## Known Issues
7474

7575
- [ ] Some PostgreSQL drivers may fail with unsupported OIDs
76-
- [ ] `\d` commands in psql don't work (need system catalog)
76+
- [x] `\d` commands in psql don't work (need system catalog) - fixed
7777
- [ ] Transaction isolation may differ from PostgreSQL behavior
7878
- [ ] Large result sets may cause memory issues (no streaming)
7979

0 commit comments

Comments
 (0)