sumatra --dsn my.dsn @file.sumatra.
They build on each other in order, so if this is your first contact
with Sumatra, read top to bottom.
1. The smallest program: set-DML
When the work is already set-shaped, a program is just SQL statements and aCOMMIT — no variables, no loops. Sumatra runs these server-side
exactly as written.
Tables
expire.sumatra
- A body can hold plain
UPDATE/DELETE/INSERT ... SELECTstatements directly. They run on the engine as-is — rows never move to the client. - The single top-level
COMMIT;makes both statements one atomic transaction. - The datetime expression is the engine’s own dialect — inside SQL statements you write the engine’s SQL (Firebolt here), verbatim.
2. Branching per row: CASE and write-back
The canonical Sumatra shape: read in batches, compute per row, write each row back.Tables
grades.sumatra
- The
CASE ... END CASE;statement puts statements in each branch. Its cousin, the CASE expression, selects a value instead — see the language reference. - The read selects every column of the table because
SET ROW = recwrites the whole record back (all columns except the key it matches on). - The compiler turns the loop’s captured writes into one set-based statement per batch — you get row-by-row logic at set-based cost.
3. Carried state: a running balance
The pattern SQL struggles with most: each row’s result depends on the previous row’s result. Variables declared inDECLARE carry across
rows and across batches, and ORDER KEY guarantees the order they
carry in.
Tables
balance.sumatra
50.00, 30.00, 0.00 (the clamp
caught the overdraft); customer 200’s as 10.00, 25.00.
What to notice:
ORDER KEY (customer_id, entry_id)makes each customer’s rows contiguous and ordered — which is exactly what letsrunningandlast_customercarry correctly, even across batch boundaries.- The per-customer reset is runtime logic (
IFon a comparison with carried state), not a window-function trick. BATCH SIZE 50000bounds memory; the answer is identical at any batch size — that invariance is a language guarantee.
4. Runtime-routed writes: insert, update, or delete per row
A per-row branch choosesDELETE, UPDATE, or INSERT based on a
value the data produced. Compile-time templating cannot express this;
in Sumatra it is just an IF.
Tables
apply_changes.sumatra
- All three writes target one table, keyed on
customer_id; the compiler captures whichever branch fired for each row and applies the whole batch’s mixed changes as one set-based statement. - Inside a row loop,
INSERTusesVALUES— per-row inserts are captured and batched like the other writes. - Writing the same key twice in one batch is a program error surfaced loudly at run time — never a silent last-write-wins.
5. Parameters: one program, many runs
PARAM declares program inputs; values arrive on the command line, in
declaration order, and bind into the read’s SQL as real query
parameters.
Tables
region_rollup.sumatra
- A parameter is referenced only inside SQL, as
PARAM('name'), and a non-text parameter needs a cast at the point of use. BATCH SIZE ALLruns the aggregating read as one whole-set batch — the right grain for aGROUP BYsource — and, because the body is order-independent, noORDER KEYis needed.- There is no row loop here: the statements reference
batchas a set, so the whole body runs server-side. The update-then-insert pair is the idiomatic upsert — accumulate existing keys, insert the complement.
6. Exceptions: fail safe, keep the checkpoint
Arithmetic on real data can fault: a zero divisor, an overflow. Rather than guard every row, this program handles faults at the program level and leans on per-batch commits for recovery.Tables
score.sumatra
- The
UPDATEhere sets two named columns rather thanSET ROW— a sparse update. Only those columns are written; everything else is untouched, and the read projects just the columns it needs. - On a fault,
STOPdiscards only the in-flight batch and exits with code2. Already-committed batches remain a valid prefix — and because processed rows are flaggedscored = TRUE, re-running the same program picks up exactly where it stopped. WHEN OTHERS THEN RAISEis the recommended tail: anticipated faults stop gracefully, everything else stays loud.
Where to go deeper
- Programs and batches — the rules behind read blocks, write routing, and commit grains.
- Types, expressions, and control flow — the full language reference, including records and keyed collections.
- Exceptions and recovery — the fault model in detail.
- Stored procedures — turn any of these programs into a named, schedulable procedure.
