Version / build tested against
origin/main @ f7fcc7718 (release build; predates #226, but the affected evaluator is untouched by that PR — see Summary).
Deployment mode
Origin — single node (local), via psql over pgwire.
Engine(s) involved
Procedural executor (trigger bodies / DO blocks) — a separate evaluator from the scalar-expression path fixed in #226.
Summary
The procedural executor has its own arithmetic evaluator, and it silently folds division by zero to NULL on the write path: a BEFORE INSERT trigger body assignment NEW.ratio := NEW.numerator / NEW.denominator; with a zero denominator writes NULL into the row and lets the INSERT commit — no error, no SQLSTATE 22012. This is the same suppressed-error class as #216, in a different evaluator: try_eval_constant's division arm only matches a non-zero divisor, the zero case falls through to None, and evaluate_to_value coerces None to Ok(Value::Null) (control/planner/procedural/executor/eval.rs ~181/195, ~88-92), reaching execute_assign / execute_return. #226 deliberately scoped this out (separate evaluator); filing so it is tracked rather than implicit.
Steps to reproduce
CREATE COLLECTION trig_probe (id TEXT PRIMARY KEY, numerator INT, denominator INT, ratio INT);
CREATE TRIGGER trig_ratio BEFORE INSERT ON trig_probe FOR EACH ROW
BEGIN NEW.ratio := NEW.numerator / NEW.denominator; END;
INSERT INTO trig_probe (id, numerator, denominator) VALUES ('r1', 10, 0); -- succeeds
INSERT INTO trig_probe (id, numerator, denominator) VALUES ('r2', 10, 2); -- succeeds
SELECT id, numerator, denominator, ratio FROM trig_probe ORDER BY id;
-- r1 | 10 | 0 | NULL <- silently wrong: 10/0 folded to NULL, write committed
-- r2 | 10 | 2 | 5 <- control: trigger works
Expected behavior
The zero-divisor assignment raises division_by_zero (SQLSTATE 22012), aborting the triggering statement — consistent with the post-#226 behavior of the main scalar evaluator, and with the procedural engine's own EXCEPTION WHEN DIVISION_BY_ZERO handler machinery (which string-matches a phrase that is currently never raised anywhere).
Actual behavior
The assignment silently produces NULL; the INSERT commits with the wrong value; no error is observable anywhere.
What actually happened? (check all that are true)
Proposed severity
SEV-2 — High: silently-wrong stored results on the write path; pre-existing data intact.
Reproducibility
Always — every attempt.
Last known-good version / commit (if a regression)
Not a regression — the procedural evaluator has folded eval failures to NULL since introduction.
Environment & logs
Linux x86_64, source build of origin/main @ f7fcc7718, single local node, fresh collections. Found during the adversarial review pass for #226. Note: the same None → Ok(Value::Null) coercion in evaluate_to_value also swallows other expression failures in trigger bodies (unknown identifiers, unsupported operators), so a fix probably wants a typed error out of try_eval_constant rather than a div-zero special case.
Before submitting
Version / build tested against
origin/main @ f7fcc7718(release build; predates #226, but the affected evaluator is untouched by that PR — see Summary).Deployment mode
Origin — single node (local), via psql over pgwire.
Engine(s) involved
Procedural executor (trigger bodies / DO blocks) — a separate evaluator from the scalar-expression path fixed in #226.
Summary
The procedural executor has its own arithmetic evaluator, and it silently folds division by zero to NULL on the write path: a
BEFORE INSERTtrigger body assignmentNEW.ratio := NEW.numerator / NEW.denominator;with a zero denominator writesNULLinto the row and lets the INSERT commit — no error, no SQLSTATE 22012. This is the same suppressed-error class as #216, in a different evaluator:try_eval_constant's division arm only matches a non-zero divisor, the zero case falls through toNone, andevaluate_to_valuecoercesNonetoOk(Value::Null)(control/planner/procedural/executor/eval.rs~181/195,~88-92), reachingexecute_assign/execute_return. #226 deliberately scoped this out (separate evaluator); filing so it is tracked rather than implicit.Steps to reproduce
Expected behavior
The zero-divisor assignment raises division_by_zero (SQLSTATE 22012), aborting the triggering statement — consistent with the post-#226 behavior of the main scalar evaluator, and with the procedural engine's own
EXCEPTION WHEN DIVISION_BY_ZEROhandler machinery (which string-matches a phrase that is currently never raised anywhere).Actual behavior
The assignment silently produces NULL; the INSERT commits with the wrong value; no error is observable anywhere.
What actually happened? (check all that are true)
Proposed severity
SEV-2 — High: silently-wrong stored results on the write path; pre-existing data intact.
Reproducibility
Always — every attempt.
Last known-good version / commit (if a regression)
Not a regression — the procedural evaluator has folded eval failures to NULL since introduction.
Environment & logs
Linux x86_64, source build of
origin/main @ f7fcc7718, single local node, fresh collections. Found during the adversarial review pass for #226. Note: the sameNone → Ok(Value::Null)coercion inevaluate_to_valuealso swallows other expression failures in trigger bodies (unknown identifiers, unsupported operators), so a fix probably wants a typed error out oftry_eval_constantrather than a div-zero special case.Before submitting
mainbuild.