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 compute loop. Decorrelate with a JOIN in the read, or load the inner table as a keyed collection and probe it.
- No unbounded server-dependent loops. A
WHILEthat needs fresh server data each iteration to decide termination does not fit the read → compute → write model and is rejected. 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), procedure calling procedure, and the!=spelling (use<>). EXECliteral escaping — a text argument containing a single quote cannot be passed.
PL/SQL features deliberately not carried over
For readers arriving from Oracle: 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), %TYPE,
CONSTANT, and declaration DEFAULT/NOT NULL modifiers. VARRAY,
nested tables, and MULTISET are replaced by the single keyed-map
collection.
Operational boundaries
- Firebolt is the only live backend in this release. The
toolchain is engine-neutral by construction — the DSN scheme
declares the backend, and everything engine-specific lives behind
per-backend profiles — but
fireboltis the only scheme that binds today. - 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).
- 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).