Skip to content

Fix assertion failure in IfTransformStringsToEnumPass for Nullable result types#97002

Open
alexey-milovidov wants to merge 2 commits intomasterfrom
fix-if-transform-strings-to-enum-nullable
Open

Fix assertion failure in IfTransformStringsToEnumPass for Nullable result types#97002
alexey-milovidov wants to merge 2 commits intomasterfrom
fix-if-transform-strings-to-enum-nullable

Conversation

@alexey-milovidov
Copy link
Member

@alexey-milovidov alexey-milovidov commented Feb 15, 2026

Summary

The IfTransformStringsToEnumPass assertion assert(isString(function_node.getResultType())) in wrapIntoToString fails when group_by_use_nulls = 1 is used with GROUP BY ... WITH CUBE/ROLLUP.

Root cause: When group_by_use_nulls is enabled with CUBE/ROLLUP, the analyzer clones GROUP BY key expressions for the projection and calls convertToNullable on the clones, setting wrap_with_nullable = true on the FunctionNode. This makes getResultType() return Nullable(String) for the projection copy while the GROUP BY key retains type String. After the optimization transforms the if to toString(if(..., Enum, Enum)), the assertion isString(...) fails because toString(Nullable(Enum8)) returns Nullable(String).

Fix: Use removeNullable in the assertion to accept both String and Nullable(String). The optimization is applied consistently to both the GROUP BY key and projection nodes, preserving structural equality so the planner can match them. Also apply the same removeNullable fix to the transform branch's result type check.

Reproducer query from the AST fuzzer:

SELECT DISTINCT if(number < 5, 'google', 'censor.net') AS value, value
FROM system.numbers
GROUP BY and(isZeroOrNull(10), *), 2 WITH CUBE
LIMIT 0

CI report: https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=96712&sha=ebc729143128f68f2f99c7a88691dc085c4574d0&name_0=PR&name_1=AST%20fuzzer%20%28amd_debug%29

Changelog category (leave one):

  • Bug Fix (user-visible misbehavior in an official stable release)

Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):

Fix assertion failure in IfTransformStringsToEnumPass when the if or transform function returns Nullable(String) (e.g. with GROUP BY ... WITH CUBE and group_by_use_nulls = true).

🤖 Generated with Claude Code

…result types

The `if` branch of `IfTransformStringsToEnumPass` was missing a check on the
function result type before attempting the string-to-enum optimization. When
`group_by_use_nulls = true` is combined with `GROUP BY ... WITH CUBE`, the
`if` function's result type becomes `Nullable(String)` instead of `String`.
The optimization then wraps into `toString`, which returns `Nullable(String)`,
triggering the debug assertion `isString(function_node.getResultType())`.

The `transform` branch already had this guard (line 157). Added the same
`isString(function_node->getResultType())` check to the `if` branch.

https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=96712&sha=ebc729143128f68f2f99c7a88691dc085c4574d0&name_0=PR&name_1=AST%20fuzzer%20%28amd_debug%29

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@clickhouse-gh
Copy link
Contributor

clickhouse-gh bot commented Feb 15, 2026

Workflow [PR], commit [6c06367]

Summary:

job_name test_name status info comment
Bugfix validation (functional tests) error

@clickhouse-gh clickhouse-gh bot added the pr-bugfix Pull request with bugfix, not backported by default label Feb 15, 2026
@@ -0,0 +1,8 @@
-- Regression test: IfTransformStringsToEnumPass should not crash when
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test reproduces the issue.

The previous fix (adding `isString` check on the `if` branch) caused a
mismatch between GROUP BY key and projection expressions when
`group_by_use_nulls` is used with CUBE/ROLLUP. The analyzer clones GROUP
BY keys for the projection and calls `convertToNullable` on the clones,
setting `wrap_with_nullable = true`. The `isString` check would skip the
optimization for the projection node (Nullable(String)) but apply it to
the GROUP BY key (String), creating a structural mismatch that causes
NOT_FOUND_COLUMN_IN_BLOCK errors.

The correct fix: allow the optimization to run on both nodes consistently,
and fix the assertion in `wrapIntoToString` to accept `Nullable(String)`
via `removeNullable`. Also fix the `transform` branch's `isString` check
similarly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-bugfix Pull request with bugfix, not backported by default

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant