Context
Surfaced by Wave 11 (#168 recursive CTE; commit 0c69604).
The QueryEngine's expression-builder cannot compare a DataRow column whose runtime value is DBNull to an int operand inside a JOIN ON predicate. Specifically: JOIN parent ON child.ParentId = parent.Id where ParentId is nullable and the parent column type is int — when ParentId is NULL, the comparison throws or produces incorrect results instead of evaluating to NULL (and being excluded by the ON predicate per SQL three-valued logic).
This forced Wave 11's recursive CTE tests to use sentinel 0 for "no parent" instead of NULL. Real-world hierarchy data (org charts, tree structures) typically uses NULL for the root, so this is a practical gap.
Repro
Engineering hierarchy table:
Id | ParentId
1 | NULL
2 | 1
3 | 2
Query:
WITH RECURSIVE chain AS (
SELECT Id, ParentId FROM Engineers WHERE ParentId IS NULL
UNION ALL
SELECT e.Id, e.ParentId FROM Engineers e JOIN chain c ON e.ParentId = c.Id
)
SELECT * FROM chain
Expected: 3 rows (the entire chain).
Actual: NULL/Int promotion error in the JOIN ON predicate's expression compilation.
Diagnosis pointer
src/Core/QueryProcessing/QueryEngine.cs LINQ expression builder for JOIN ON predicates. The runtime value extracted from DataRow[col] is object, which becomes DBNull for NULL rows. The expression builder needs to compare-or-fail-fast on DBNull rather than attempting an int conversion.
SQL three-valued logic semantics: any comparison involving NULL evaluates to NULL (UNKNOWN), which is not TRUE, so the ON predicate excludes the row. The expression builder must implement this short-circuit.
Acceptance Criteria
Priority
P1 (NULL-handling correctness gap; common pattern in real-world data; produces silently-wrong results today).
Discovered by
Wave 11 of /uber-report 2026-05-09 (sqlbuildingblocks-developer).
Context
Surfaced by Wave 11 (#168 recursive CTE; commit 0c69604).
The QueryEngine's expression-builder cannot compare a DataRow column whose runtime value is
DBNullto anintoperand inside a JOIN ON predicate. Specifically:JOIN parent ON child.ParentId = parent.IdwhereParentIdis nullable and the parent column type isint— whenParentIdis NULL, the comparison throws or produces incorrect results instead of evaluating to NULL (and being excluded by the ON predicate per SQL three-valued logic).This forced Wave 11's recursive CTE tests to use sentinel
0for "no parent" instead of NULL. Real-world hierarchy data (org charts, tree structures) typically uses NULL for the root, so this is a practical gap.Repro
Engineering hierarchy table:
Query:
Expected: 3 rows (the entire chain).
Actual: NULL/Int promotion error in the JOIN ON predicate's expression compilation.
Diagnosis pointer
src/Core/QueryProcessing/QueryEngine.csLINQ expression builder for JOIN ON predicates. The runtime value extracted fromDataRow[col]isobject, which becomesDBNullfor NULL rows. The expression builder needs to compare-or-fail-fast on DBNull rather than attempting an int conversion.SQL three-valued logic semantics: any comparison involving NULL evaluates to NULL (UNKNOWN), which is not TRUE, so the ON predicate excludes the row. The expression builder must implement this short-circuit.
Acceptance Criteria
Priority
P1 (NULL-handling correctness gap; common pattern in real-world data; produces silently-wrong results today).
Discovered by
Wave 11 of /uber-report 2026-05-09 (sqlbuildingblocks-developer).