-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Runtime filter crash on Tuple(Variant(...), ...) join key — incomplete fix for nested Variant #101415
Description
Found via ClickGap automated review. Please close or comment if this is incorrect or needs adjustment.
Retrospective finding from a historical scan of PR #100182 (merged 2026-03-20). Confirmed on current codebase — close with a note if already fixed.
Describe what's wrong
Joining on a Tuple containing a Variant element with exactly 1 row on the right side crashes with LOGICAL_ERROR: 'Unexpected return type from __applyFilter. Expected UInt8. Got Nullable(UInt8)'
Root cause: RuntimeFilterLookup.h:109-111 — isVariant()/isDynamic() only checks top-level type, while hasNullable() traverses nested types (Array, Tuple, Map) but doesn't recognize Variant/Dynamic as null-containing. Nested Variant inside compound types is missed.
Affected locations:
src/Processors/QueryPlan/RuntimeFilterLookup.h:109— argument_can_have_nulls initialization misses nested Variant in compound typessrc/DataTypes/hasNullable.cpp:9— hasNullable() doesn't check for Variant/Dynamic types during recursive traversal
Impact: Server crashes (LOGICAL_ERROR) on valid SQL when joining on Tuple or other compound types containing Variant elements, with exactly 1 distinct value on the right side of the join.
Does it reproduce on most recent release?
Yes — confirmed on current master (commit 3b93559b0d1c).
How to reproduce
-- Bug: Tuple(Variant(...), ...) as join key with 1 row on right triggers ValuesCount::ONE path
-- which uses equals function producing Nullable(UInt8) instead of UInt8, causing LOGICAL_ERROR.
-- hasNullable() doesn't detect Variant inside Tuple, and isVariant() only checks top-level type.
SELECT *
FROM
(SELECT tuple(v, 1) as k FROM format(TSV, 'v Variant(String, Bool)', 'true\nfalse')) AS t1
JOIN
(SELECT tuple(v, 1) as k FROM format(TSV, 'v Variant(String, Bool)', 'true')) AS t2
USING (k);Expected behavior
(true,1)
Error message and/or stacktrace
Code: 49. DB::Exception: Unexpected return type from __applyFilter. Expected UInt8. Got Nullable(UInt8). (LOGICAL_ERROR)
Additional context
Open risks:
- Map(String, Variant(...)) as join key may also be affected, though Map join keys are uncommon
Suggested fix: Either extend hasNullable() in hasNullable.cpp to also return true for Variant/Dynamic types (fixing it for all callers), or change the runtime filter check to recursively inspect nested types for Variant/Dynamic. The hasNullable.cpp fix is more robust: add if (WhichDataType(type).isVariant() || WhichDataType(type).isDynamic()) return true; before the Array/Tuple/Map checks.
Analysis details: Confidence HIGH | Severity P0 | Testability: STATELESS_SQL
Found during automated review of PR #100182.