~24K lines of C. Zero dependencies. Four stages: wire protocol, parser, executor, storage. Every query flows through the same pipeline. The block-oriented plan executor processes 1,024-row column blocks for cache-friendly, vectorized execution.
Every query passes through four stages:
| Stage | Source | Description |
|---|---|---|
| Wire protocol | pgwire.c |
Accepts TCP connections on port 5433, handles SSL negotiation,
implements the Simple Query, Extended Query (prepared
statements, portals, $1/$2 parameter
substitution), and COPY protocols (tab-delimited and CSV),
intercepts information_schema and
pg_catalog queries for tool compatibility,
and serializes result rows |
| SQL parser | parser.c |
Hand-written recursive-descent parser producing a typed
struct query AST—no generators.
~4,500 lines with proper operator precedence,
CTEs, window functions, set operations, and
generate_series() table functions |
| Query executor | query.c, database.c |
Block-oriented plan executor (plan.c, ~4,500 lines)
handles most queries with vectorized operators: scan, filter,
project, sort, hash join, hash aggregation, index scan,
window functions, set operations, CTEs, and
generate_series().
A scan cache with generation tracking skips redundant scans.
Direct columnar-to-wire serialization bypasses row materialization.
Complex queries (correlated subqueries, ROLLUP/CUBE)
fall back to the legacy row-at-a-time evaluator
(query.c, database.c) |
| Storage | table.c, row.c, index.c |
Tables are arrays of rows; rows are arrays of typed cells. B-tree indexes for equality lookups. Snapshot-and-restore for transaction rollback |
All memory is managed through a pool-based arena (arena.h).
Parsed structures use uint32_t indices instead of pointers.
Freeing an entire query is one query_arena_destroy() call—no
recursive walks, no per-node free().
A slab-chain bump allocator (arena.scratch) handles temporary
executor state: aggregate accumulators, sort buffers, window-function arrays.
All freed in bulk per query—zero malloc/free
calls at steady state. A separate result-text bump allocator
(arena.result_text) eliminates per-cell strdup
for text results.
Expressions are a tagged-union AST (struct expr) evaluated
by eval_expr(). Supports CAST/::,
date/time arithmetic, 30+ built-in scalar functions (math, string, temporal),
CASE WHEN, and subqueries.
Dynamic-array macro (dynamic_array.h), zero-copy string views
(stringview.h), and JPL-style ownership: the allocating module
deallocates.
Fast. The block-oriented executor with columnar scan caching beats PostgreSQL on 16 of 19 batch benchmarks. Aggregate queries run 8× faster. Direct columnar-to-wire serialization avoids row materialization entirely.
Simple. Zero external dependencies. One .c file per
stage. The entire codebase fits in a single developer’s head.
Safe. Every test runs under AddressSanitizer. Arena allocation eliminates use-after-free and leak classes by construction.
Benchmarks vs PostgreSQL · SQL grammar · Source on GitHub · Try it in the browser