Permanent, by design
These are not roadmap items — they define the execution model.- No per-row server operations. A per-row server query or write — the cursor-style pattern from OLTP databases — is inexpressible by grammar. All server interaction is batched.
- No nested read blocks, and no read inside a row, counted, or
WHILEloop in compute position. Decorrelate with a JOIN in the read, load the inner table as a keyed collection and probe it, or — when the shape is genuinely “repeat a whole read → compute → write pass” — use a top-level pipeline loop, whose body legally contains read blocks and whose bound is the program’s own (a counted range or a predicate over carried state), never a per-row server call. - Chained comparison is a parse error.
a = b = cis rejected — parenthesize the comparison you mean. (The engine would parse it left-associatively; Sumatra is deliberately stricter.) ORDER KEYcolumns must beINT,BIGINT, orTIMESTAMP. Floats are excluded on principle (float equality is unsound as a cursor);DATEis excluded because keyset pagination over a one-value-per-day key cannot make progress within a day.- No text-crossing casts in compute.
TEXT→ number or number →TEXTconversions belong in the read’s SQL, where the engine’s full conversion machinery (and error surface) applies. - A write cannot change its own merge key.
SETof a key column, or aSET ROWmatched on anything other than the record’s own key field, is a compile error. - One change per key per batch. Duplicate writes to one merge key in a flush unit are a program error, surfaced loudly (repeated DELETEs excepted).
- Bare table names only. No
schema.tablequalification, and engine identifiers must be usable unquoted — reach exotic names by aliasing them inside the read’s SQL. Identifiers are ASCII.
Not in this release
Absent from 0.2.0; some are roadmapped, none are promised here:- User-defined functions (
FUNCTION/RETURN exprare reserved words today). - User-defined exceptions — the catchable set is
ZERO_DIVIDE,OVERFLOW,NO_DATA_FOUND,OTHERS. - Iterating or aggregating a collection. Keyed maps are probe-only
lookups: no
FOR x IN map, no.COUNT, no in-memorySUMover a map. Aggregate in the read instead. BYTEAandARRAYin compute. Both types carry fine through server-side statements; neither can enter an in-memory record.- Regex, format masks, and transcendental math in compute position
(
REGEXP_*,TO_CHAR/TO_DATE,POWER/EXP/LN/trig —SQRTis the exception). Use them in the read’s SQL. - Loop labels (
EXITalways exits the innermost loop) and procedure calling procedure. EXECliteral escaping — a text argument containing a single quote cannot be passed.- Reloading a keyed collection inside a batch loop.
BULK COLLECTruns at the top level (or a top-level arm): the map loads once. A per-batch reload is rejected while the replace-versus-accumulate question is open. Per-batchSELECT INTOscalar lookups are the supported re-fetch. - A pipeline iteration must drain its own at-end read. A read block
inside a pipeline whose staged write-back would only be committed by
a later iteration’s
COMMITis rejected — commit each iteration’s work in that iteration, or after the loop.
Classic stored-procedure features deliberately not carried over
For readers arriving from a classic procedural SQL dialect: explicit cursors and cursor attributes (%FOUND, %NOTFOUND, %ROWCOUNT),
FORALL, GOTO, packages, overloading, autonomous transactions,
SAVEPOINT, explicit ROLLBACK (a fault’s rollback is automatic;
graceful stops are the EXCEPTION block’s job), dynamic SQL
(EXECUTE IMMEDIATE — though a table name can be a program input;
see dynamic table names),
%TYPE, CONSTANT, and declaration DEFAULT/NOT NULL modifiers.
VARRAY, nested tables, and MULTISET are replaced by the single
keyed-map collection.
Operational boundaries
- The backends are the new-class warehouses — Firebolt and Snowflake. The toolchain is engine-neutral by construction — the DSN scheme declares the backend, and everything engine-specific lives behind per-backend profiles. The examples and the deepest proof in these docs run on Firebolt.
- Linux x86-64 only, and compiling hosts need
g++,pkg-config, and libcurl headers. (Hosts that only run cached stored procedures need none of that.) - Compiling requires a live connection — the connected database is
the schema. The offline
sumatra-compiletool works only against its built-in sample schema. BATCH SIZE ALLon a compute path holds the whole result in client memory. A result that does not fit is a loud fault, not a spill. Chunk withBATCH SIZE Nwhere results are large.- Aggregating reads re-evaluate per chunk under
BATCH SIZE N— useBATCH SIZE ALLforGROUP BYsources. - The
sumatra_prefix is reserved in target databases: the toolchain creates and dropssumatra_stage_*andsumatra_stage_lock_*tables and ownssumatra_source. It also reserves one staging column name on its own staging tables. There is no collision guard — keep your own objects off the prefix. - DSN files are plaintext — protect them with file permissions
(
chmod 600). There is no encrypted-DSN mechanism in this release. - Concurrent identical runs are refused. The same procedure with the same argument values will not start twice at once (a stale lock from a crashed run clears itself after a timeout).
- A dynamic table name is validated, not open-ended. A
%TABLEargument’s runtime value must be a plain Sumatra identifier (lowercase word characters, at most 128 bytes) naming a table shape-identical to the declared reference table — anything else is refused before the run starts. - The shell is one statement per line — no multi-line input, no SQL passthrough.
- Shared host cache across accounts. Two same-named databases on different Firebolt accounts share one per-host binary-cache directory; prefer distinct database names.
- One exotic cursor edge: a row whose
ORDER KEYvalue equals the exact type minimum (INT/BIGINTminimum, or timestamp0001-01-01 00:00:00) is never fetched by a chunked read. Real keys never live there; synthetic sentinel keys should not.
Reading an error you did not expect
Compile-time rejections name the rule that fired and, where one exists, the supported alternative — the error text is the documentation of first resort. If a program you believe should compile is rejected, check this page’s permanent list first, then Programs and batches for the structural rules (commit placement,ORDER KEY requirements, write shapes).