fix(nodes,scalar): fix EXPLAIN crash and wrong scan range with CASE WHEN expression#35125
fix(nodes,scalar): fix EXPLAIN crash and wrong scan range with CASE WHEN expression#35125guanshengliang merged 2 commits intomainfrom
Conversation
…HEN subquery Three bugs triggered when a CASE WHEN expression appears as a computed column in a subquery and the outer WHERE filters on an alias of that expression (e.g. WHERE period IS NOT NULL): 1. Wrong vnode scan time range (filter.c) classifyConditionImpl traversed into the CASE WHEN subtree, found a ts column reference inside, and mis-classified the entire expression as COND_TYPE_PRIMARY_KEY. filterGetTimeRange could not extract a valid range and fell back to TSWINDOW_INITIALIZER, which was then clipped to earlyTs, producing [-29759981076409, INT64_MAX] instead of the intended window. Fix: return DEAL_RES_IGNORE_CHILD for QUERY_NODE_CASE_WHEN and mark hasOtherCol = true so the condition is treated as a non-PK filter. 2. EXPLAIN VERBOSE TRUE / ANALYZE crash - "unknown node = CaseWhen" (nodesToSQLFuncs.c) nodesNodeToSQLFormat had no cases for QUERY_NODE_WHEN_THEN or QUERY_NODE_CASE_WHEN, falling through to the default branch which returned TSDB_CODE_APP_ERROR. Fix: add serialization logic for both node types. 3. NULL datum.p segfault for ELSE NULL (nodesUtilFuncs.c) ELSE NULL produces a SValueNode with NCHAR type but datum.p == NULL. nodesGetStrValueFromNode called varDataLen(NULL), causing a segfault. Fix: add a NULL guard before the varDataLen call; callers that receive NULL now emit the SQL literal "NULL" instead of erroring. Also adds test/cases/07-DataQuerying/14-Explain/test_explain_case_when.py and registers it in test/ci/cases.task.
There was a problem hiding this comment.
Code Review
This pull request introduces support for CASE WHEN and WHEN THEN nodes in the SQL formatting logic, specifically to support EXPLAIN output. It also updates the condition classification logic to correctly handle CASE WHEN expressions, preventing them from being misclassified as primary key filters which previously led to inefficient full scans. A review comment highlights a potential issue in nodesNodeToSQLFormat where memory allocation failures in nodesGetStrValueFromNode are now treated as SQL NULL literals, potentially masking out-of-memory errors.
There was a problem hiding this comment.
Pull request overview
Fixes multiple crashes/mis-optimizations triggered by CASE WHEN expressions used as computed columns in subqueries (especially when the outer query filters on the computed alias), improving both EXPLAIN stability and scan-range correctness in the planner/executor pipeline.
Changes:
- Prevent
CASE WHENsubtrees from being misclassified as primary-key conditions during filter classification (avoids incorrect full-history scan ranges). - Add SQL serialization support for
CASE WHEN/WHEN THENnodes to avoid EXPLAIN/ANALYZE failures. - Add a regression test covering EXPLAIN + scan time range behavior for the reported
CASE WHENsubquery pattern, and wire it into CI.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| test/ci/cases.task | Registers the new CASE-WHEN EXPLAIN regression test in CI. |
| test/cases/09-DataQuerying/15-Explain/test_explain_case_when.py | Adds a regression test for EXPLAIN crash + scan-range correctness with CASE WHEN in subquery. |
| source/libs/scalar/src/filter.c | Avoids descending into CASE WHEN during condition classification to prevent incorrect PK classification. |
| source/libs/nodes/src/nodesUtilFuncs.c | Adds a NULL guard for string-like value nodes (but currently returns NULL). |
| source/libs/nodes/src/nodesToSQLFuncs.c | Adds CASE WHEN / WHEN THEN formatting and changes NULL handling for value-node stringification. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
After the CASE WHEN serialization fix in nodesToSQLFuncs.c, EXPLAIN VERBOSE TRUE and EXPLAIN ANALYZE VERBOSE TRUE now correctly output the Filter condition for CASE WHEN expressions. Update the reference result files to match the new output.
…HEN subquery
Three bugs triggered when a CASE WHEN expression appears as a computed column in a subquery and the outer WHERE filters on an alias of that expression (e.g. WHERE period IS NOT NULL):
Wrong vnode scan time range (filter.c) classifyConditionImpl traversed into the CASE WHEN subtree, found a ts column reference inside, and mis-classified the entire expression as COND_TYPE_PRIMARY_KEY. filterGetTimeRange could not extract a valid range and fell back to TSWINDOW_INITIALIZER, which was then clipped to earlyTs, producing [-29759981076409, INT64_MAX] instead of the intended window. Fix: return DEAL_RES_IGNORE_CHILD for QUERY_NODE_CASE_WHEN and mark hasOtherCol = true so the condition is treated as a non-PK filter.
EXPLAIN VERBOSE TRUE / ANALYZE crash - "unknown node = CaseWhen" (nodesToSQLFuncs.c) nodesNodeToSQLFormat had no cases for QUERY_NODE_WHEN_THEN or QUERY_NODE_CASE_WHEN, falling through to the default branch which returned TSDB_CODE_APP_ERROR. Fix: add serialization logic for both node types.
NULL datum.p segfault for ELSE NULL (nodesUtilFuncs.c) ELSE NULL produces a SValueNode with NCHAR type but datum.p == NULL. nodesGetStrValueFromNode called varDataLen(NULL), causing a segfault. Fix: add a NULL guard before the varDataLen call; callers that receive NULL now emit the SQL literal "NULL" instead of erroring.
Also adds test/cases/07-DataQuerying/14-Explain/test_explain_case_when.py and registers it in test/ci/cases.task.
Description
Issue(s)
Checklist
Please check the items in the checklist if applicable.