balance.sumatra
MERGE statements — the compiler produces all of that. The program
reads in 50,000-row batches, carries running across every row and
every batch in order, and commits each batch as a durable checkpoint.
The problem it solves
Modern analytical engines — Firebolt among them — deliberately ship no stored procedures and no procedural SQL dialect. Set-based SQL covers enormous ground, but the moment a pipeline needs a step that carries state across rows, branches on a value the data just produced, or loops until a computed condition is met, that step has to leave the database: a Python script here, a Spark job there, dbt orchestrating around the gap, and data movement stitching it together. Sumatra collapses that split. The procedural mid-work is written in one small language and executes as batch-shaped SQL on the engine itself, next to the set-based steps it belongs with.
The full case — what staying in-database saves you operationally, and
what the batch and merge machinery buys you technically — is on
Why Sumatra.
The mental model
Every Sumatra program reduces to one shape: Read → Compute → Write- Read — pull rows from the engine in batches into memory. Never a per-row server query.
- Compute — arbitrary in-memory work: loops, branches, carried variables, record and collection types. No server round-trips.
- Write — push results back in batches. Never a per-row server write.
ORDER KEY and BATCH SIZE.
Beyond that frame, the language is deliberately familiar PL/SQL:
DECLARE/BEGIN/END, := assignment, IF/ELSIF, CASE, WHILE,
FOR loops, records, %ROWTYPE, keyed collections, EXCEPTION
handlers, explicit COMMIT. A handful of new words cover the batch
boundary: BATCH SIZE, ORDER KEY, PARAM, STOP.
How programs run
Thesumatra shell compiles a program against the live catalog of
the connected database — the database itself is the schema — then
generates native code, builds it with g++ on your host, and runs it.
The compiled program makes its own connection from the same DSN file
and speaks batch-shaped SQL to the engine.
Writes are routed, not written by hand:
- A write that is already set-shaped (plain
UPDATE/DELETE/INSERT ... SELECT) runs server-side as-is — rows never leave the engine. - Per-row writes captured inside a loop are staged and applied as one
set-based
MERGEper batch. You never writeMERGEor manage staging tables yourself.
@prog.sumatra), or are stored in
the database as named procedures and run with
EXEC — compiled once, cached per host, and automatically recompiled
when the source, the toolchain, or the table schemas change.
Semantics you can trust
Sumatra’s answer for what a program means is deliberately boring: it means what the engine underneath means. Values, types, rounding, overflow, NULL handling — the in-memory evaluator is bit-exact to the bound engine’s own semantics (today, Firebolt’s), so moving a computation between the read SQL and the procedural middle never changes the answer, and a program never invents behavior the engine does not have. Three properties are worth calling out:- Determinism. A compute program’s result is declared-order
deterministic:
ORDER KEYfixes a strict total order, state carries across batch boundaries, and the answer is invariant underBATCH SIZE. An order tie or a NULL key at runtime is a loud error, never a silent skip or duplicate. - Loud failure. Overflow, division by zero, and lossy surprises are errors, never silently wrong values. Committed batches always survive a fault as a durable prefix; recovery is explicit and yours.
- Honest rejection. A program the model cannot run well — a nested read, a per-row server op, an unbounded server-dependent loop — is rejected at compile time with a named reason. The failure mode is a compile error, not a production performance cliff.
Status at a glance
Sumatra is built by the Wirekite team and documented here, but it is a
standalone product: it is not part of the Wirekite replication
pipeline, is not invoked by Wirekite, and nothing in this section
depends on Wirekite in any way.
Reading order
- Why Sumatra — the case for in-database transformation, and the batch and merge engines in depth.
- Quickstart — install, connect, and run your first two programs.
- Learning by example — small annotated programs covering the everyday shapes.
- Programs and batches — the program skeleton, read blocks, write routing, and commit grains.
- Types, expressions, and control flow — the language reference.
- Exceptions and recovery · Stored procedures · Built-in functions · The sumatra shell · Limitations
