Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

DBNull / Int promotion gap in JOIN equality predicates #186

Copy link
Copy link

Description

@DaveRMaltby
Issue body actions

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

  • JOIN ON predicate with a nullable column compared to a non-null operand correctly evaluates to NULL/UNKNOWN, excluding the row from the join result
  • Recursive CTE hierarchy traversal with NULL "no parent" sentinel works end-to-end
  • Regression tests covering: nullable column = nullable column, nullable column = non-null literal, JOIN ON NULL = NULL (which should NOT match per SQL semantics)
  • No regression on existing JOIN tests

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).

Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.