Rindle docs and package mapSkip to main content

validate_default_expression

Function validate_default_expression 

pub fn validate_default_expression(
    conn: &Connection,
    table: &str,
    column: &str,
    default_sql: &str,
    value_type: ValueType,
) -> Result<(), ReplicaError>
Expand description

Prove that a column default cannot manufacture a BLOB on a later evaluation.

A sampled typeof(default) is insufficient: an expression such as CASE WHEN random() = 0 THEN x'00' ELSE 'ok' END will almost always sample as TEXT but can still poison a future omitted-column insert. SQLite defaults cannot refer to table columns, subqueries, or bind parameters, so their only dynamic value producers are scalar functions. Inspecting the compiled expression lets us reject every BLOB literal/cast on every control-flow path and every arbitrary function. The three SQL clock keywords are the sole function-like exception; SQLite defines them to return TEXT. Literal/operator defaults remain supported.

An exact-i64 (BIGINT/INT8) column additionally requires its default to evaluate to the INTEGER storage class (or NULL): SQLite affinity stores a REAL/TEXT default verbatim on a later omitted-column insert — and an additive ALTER TABLE … ADD COLUMN … DEFAULT exposes existing rows’ new cells without firing CDC — so an off-plane default would make every subsequent hydrate/capture fail the strict int64 storage-class guard. That check samples typeof, which is only sound for a TIME-INVARIANT expression — a clock keyword inside a conditional (CASE WHEN CURRENT_DATE = … THEN 1.5 ELSE 1 END) samples INTEGER today and produces REAL tomorrow — so exact-i64 columns reject the clock keywords outright; the remaining literal/operator subset is constant, making the sampled typeof the storage class of every future evaluation.