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.