Strictness and canonical form
This page covers two related topics: how the compiler reacts to a problem, and how many ways there are to write the same thing.
Errors, warnings and trust
The compiler's reaction depends on what it can establish from the query text.
| What the compiler can establish | Reaction |
|---|---|
| The query breaks a rule: a unit mismatch, a sum across a non-additive axis, a lookup through the wrong entity | Error |
| The result may be ambiguous or lossy, and the query cannot show which: a possible tie, a comparison on floating values without a stated precision | Warning. The query runs |
| A declaration made at a source | Trusted |
An error has a stable code (UE/...), a location, the feature it concerns and, where one exists, a repair that compiles. Cycles are reported with the cycle listed. The examples in Semantic contracts show several.
A warning carries an acknowledgment token, for example ACK-YLZJ. A persisted view does not accept unacknowledged warnings: CREATE VIEW fails unless the view body contains the token in a comment.
CREATE OR REPLACE VIEW FMV.DOCS.WARNED AS
-- ACK-MW54
DEFINE
X := 1e0
RETURN
FLAG := X > 0e0
;
An acknowledgment never hides an error.
One canonical syntax, a permissive surface
Each construct has one canonical spelling. DEFINE hides a formula, RETURN sends it to the caller, and PERSIST stores it on CREATE FEATURES. WITH and SELECT are SQL, so they are not FeatureQL clause spellings. Other permissive spellings below still compile during exploration, and only when that spelling has one meaning.
| Permissive | Canonical |
|---|---|
CAST(x AS T) | x::T |
ARRAY[1, 2] | ARRAY(1, 2) |
COUNT(*) | COUNT() |
GROUP BY k | GROUP BY (k) |
YEAR(d), EXTRACT(YEAR FROM d) | DATE_PART(d, 'year') |
SLICE(arr, i, n) | SLICE_LEN(arr, i, n) |
DISPLAYS AS | IS [NOT] DISTINCT FROM |
BIGINT[], LIST<T> | ARRAY<BIGINT> |
COUNT(x) is not accepted, see Absence, emptiness and errors .
Two tools move a query to the canonical form.
/* STRICT */ refuses permissive spellings and names each one:
/* STRICT */
DEFINE
XS := ARRAY[1, 2, 3],
RETURN N := XS.TRANSFORM(RETURN COUNT(*)).UNWRAP_ONE();FORMAT (FIX) rewrites them. Identifiers are case-insensitive, and the formatter writes them in lowercase.
FORMAT (FIX)
DEFINE
XS := ARRAY[1, 2, 3],
RETURN N := XS.TRANSFORM(RETURN COUNT(*)).UNWRAP_ONE();
returns
DEFINE
xs := ARRAY(1, 2, 3)
RETURN
n := xs.TRANSFORM(RETURN COUNT()).UNWRAP_ONE()
;
The registry stores features in normalized form, so a stored definition does not depend on how it was typed. See Friendly syntax .
Naming conventions for weaker guarantees
A function or modifier that weakens a guarantee says so in its name.
| Form | Meaning | Examples |
|---|---|---|
UNSAFE_ prefix | A contract check is bypassed | UNSAFE_CAST |
UNSAFE modifier | The additivity check is bypassed for one call | UNSAFE SUM(...) |
ANY_ prefix | An arbitrary selection | ANY_VALUE |
APPROX_ prefix | An approximate result | APPROX_DISTINCT, APPROX_PERCENTILE |
TRY modifier | An error in one call becomes NULL | TRY LN(x) |
A query that uses none of these stays within the checks described in this section.