Literals

Literals are the constant values you write directly in queries — numbers, strings, dates, arrays. Because FeatureQL infers types from literals, the way you write a value determines its type. 1 is a BIGINT, 1.0 is a DECIMAL, and 1e0 is a DOUBLE — three different types from three different notations.

Numeric literals

Integer size, decimal precision, and floating-point type are all controlled by how you write the number:

FeatureQL
SELECT
    TYPEOF(TINYINT '1') AS F_TINYINT,
    TYPEOF(SMALLINT '1') AS F_SMALLINT,
    TYPEOF(MEDIUMINT '1') AS F_MEDIUMINT,
    TYPEOF(1) AS F_BIGINT,
    TYPEOF(1.123) AS F_DECIMAL,
    TYPEOF(FLOAT '1.1') AS F_FLOAT,
    TYPEOF(DOUBLE '1.1') AS F_DOUBLE,
    TYPEOF(1.1e0) AS F_DOUBLESCI,
;
Result
F_TINYINT VARCHARF_SMALLINT VARCHARF_MEDIUMINT VARCHARF_BIGINT VARCHARF_DECIMAL VARCHARF_FLOAT VARCHARF_DOUBLE VARCHARF_DOUBLESCI VARCHAR
TINYINTSMALLINTMEDIUMINTBIGINTDECIMAL(4,3)FLOATDOUBLEDOUBLE

The TYPEOF() results reveal the inferred types. Plain 1 defaults to BIGINT. Decimal literals like 1.123 get automatic precision tracking (DECIMAL(4,3)). For floating point, use either the keyword prefix (FLOAT '1.1', DOUBLE '1.1') or scientific notation (1.1e0DOUBLE).

Other scalar literals

Strings, booleans, dates, timestamps, and JSON each have their own syntax:

FeatureQL
SELECT
    TYPEOF('A') AS F_VARCHAR,
    TYPEOF(TRUE) AS F_BOOLEAN,
    TYPEOF(DATE '2024-10-15') AS F_DATE,
    TYPEOF(TIMESTAMP '2024-10-15 10:04:00') AS F_TIMESTAMP,
    TYPEOF(JSON '"A"') AS F_JSON,
;
Result
F_VARCHAR VARCHARF_BOOLEAN VARCHARF_DATE VARCHARF_TIMESTAMP VARCHARF_JSON VARCHAR
VARCHARBOOLEANDATETIMESTAMP(3)JSON

Strings use single quotes only — 'A', never "A". Temporal literals require a keyword prefix: DATE '2024-10-15', TIMESTAMP '2024-10-15 10:04:00'. Timestamps support up to microsecond precision: TIMESTAMP '2024-10-15 10:04:00.123456'. JSON literals wrap JSON content in single quotes after the JSON keyword.

Complex type literals

Arrays and rows let you build structured data inline:

FeatureQL
SELECT
    TYPEOF(ARRAY[1,2,3]) AS F_ARRAY,
    TYPEOF(ROW(1, 'A')) AS F_ROW,
    TYPEOF(ARRAY[ROW(1 as col1, 'A' as col2)]) AS F_ARRAY_OF_ROWS,
;
Result
F_ARRAY VARCHARF_ROW VARCHARF_ARRAY_OF_ROWS VARCHAR
ARRAY(BIGINT)ROW(field_1 BIGINT, field_2 VARCHAR)ARRAY(ROW(col1 BIGINT, col2 VARCHAR))

ARRAY[1,2,3] creates a homogeneous list. ROW(1, 'A') creates a struct with auto-generated field names. Add AS to name the fields: ROW(1 as col1, 'A' as col2). Nest them — ARRAY[ROW(...)] — to create the array-of-rows structure that is central to FeatureQL's data model.

Special values

FeatureQL has two kinds of "nothing" — NULL and EMPTY — and they behave differently:

FeatureQL
SELECT
    EMPTY,
    TYPEOF(EMPTY),
    EMPTY(),
    TYPEOF(EMPTY()),
    NULL::VARCHAR,
    TYPEOF(NULL),
    NULL()::VARCHAR,
    TYPEOF(NULL()),
    NULL(DOUBLE)::VARCHAR,
    TYPEOF(NULL(DOUBLE)),
    -- EMPTY::BIGINT,  -- You cannot cast EMPTY to another type
    -- NULL::EMPTY  -- We cannot cast as EMPTY
    -- NULL::UNSPECIFIED  -- We cannot cast as UNSPECIFIED
;
Result
?_0 VARCHAR?_1 VARCHAR?_2 VARCHAR?_3 VARCHAR?_4 VARCHAR?_5 VARCHAR?_6 VARCHAR?_7 VARCHAR?_8 VARCHAR?_9 VARCHAR
EMPTY()EMPTYEMPTY()EMPTYNULLUNSPECIFIEDNULLUNSPECIFIEDNULLDOUBLE

NULL works like SQL's NULL: it represents a missing value and can be cast to any type. NULL without a type is UNSPECIFIED; NULL(DOUBLE) creates a typed null directly. NULL(DOUBLE) and NULL::DOUBLE are equivalent — both produce a typed null.

EMPTY is different — it represents an explicitly empty value used for optional function parameters. Unlike NULL, EMPTY cannot be cast to another type. If you try EMPTY::BIGINT, you get an error.

Last update at: 2026/03/03 16:47:38
Last updated: 2026-03-03 16:48:19