tursodatabase/turso · error

Unsupported operator in trivial expression: {op:?}

Error message

Unsupported operator in trivial expression: {op:?}

What it means

The incremental-maintenance expression compiler can lower 'trivial' binary expressions to a fast path, but TrivialExpression::evaluate only implements Add, Subtract, Multiply and Divide (via Value::exec_*). Any other Operator reaching this match panics - the analyzer/lowering admitted an expression the evaluator cannot run.

Source

Thrown at core/incremental/expr_compiler.rs:132

impl TrivialExpression {
    /// Evaluate the trivial expression with the given input values
    /// Automatically promotes integers to floats when mixing types in arithmetic
    pub fn evaluate(&self, values: &[Value]) -> Value {
        match self {
            TrivialExpression::Column(idx) => values.get(*idx).cloned().unwrap_or(Value::Null),
            TrivialExpression::Immediate(val) => val.clone(),
            TrivialExpression::Binary { left, op, right } => {
                let left_val = left.evaluate(values);
                let right_val = right.evaluate(values);

                // Use Value's exec_* methods which handle all type coercion
                // (including Text → Numeric) consistently with SQLite semantics
                match op {
                    Operator::Add => left_val.exec_add(&right_val),
                    Operator::Subtract => left_val.exec_subtract(&right_val),
                    Operator::Multiply => left_val.exec_multiply(&right_val),
                    Operator::Divide => left_val.exec_divide(&right_val),
                    _ => panic!("Unsupported operator in trivial expression: {op:?}"),
                }
            }
        }
    }
}

/// Compiled expression that can be executed on row values
#[derive(Clone)]
pub struct CompiledExpression {
    /// The expression executor (trivial or compiled)
    pub executor: ExpressionExecutor,
    /// Number of input values expected (columns from the row)
    pub input_count: usize,
}

impl std::fmt::Debug for CompiledExpression {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut s = f.debug_struct("CompiledExpression");

View on GitHub (pinned to 492c4a71cd)

Solutions

  1. Restrict incremental-maintained expressions to +, -, *, / until the operator is supported
  2. If you maintain the compiler, keep the analyzer whitelist in sync with the operators handled in evaluate()
  3. Report or add support for the specific operator with a minimal SQL repro

Example fix

-- before
CREATE MATERIALIZED VIEW v AS SELECT (n % 10) AS bucket FROM t; -- modulo has no trivial path

-- after
CREATE MATERIALIZED VIEW v AS SELECT (n / 10) AS decade FROM t; -- division is supported
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_trivial_op(op: &Operator) -> bool {
    matches!(op, Operator::Add | Operator::Subtract | Operator::Multiply | Operator::Divide)
}
// reject anything else before lowering to TrivialExpression

Type guard

fn is_trivial_expression(e: &TrivialExpression) -> bool {
    match e {
        TrivialExpression::Immediate(_) => true,
        TrivialExpression::Binary { op, .. } => matches!(
            op,
            Operator::Add | Operator::Subtract | Operator::Multiply | Operator::Divide
        ),
    }
}

Prevention

When it happens

Trigger: Creating incrementally-maintained structures in core/incremental whose expression uses an operator outside + - * / (e.g. %, ||, <<, comparisons); or a lowering change that routes wider expression classes into TrivialExpression.

Common situations: Writing new incremental view definitions with rich expressions; analyzer refactors that widen the trivial-expression filter without extending evaluate().

Related errors


AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20). Data as JSON: /api/errors/b6c81e518d851bca. Report an issue: GitHub.