fix: ORDER BY CASE WHEN expression fails with NPE on baseExpr.identifier#3778
fix: ORDER BY CASE WHEN expression fails with NPE on baseExpr.identifier#3778
Conversation
…ier (#3777) Add null check for baseExpr.identifier in visitOrderByItem to handle CASE WHEN expressions, which produce a BaseExpression with identifier=null. Store the full expression in OrderByItem.expression for evaluation at sort time, and use it in calculateAdditionalOrderByProjections to inject a computed projection (SELECT fields case) or evaluate directly (SELECT *). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request fixes a NullPointerException occurring when complex expressions, such as CASE WHEN, are used in an ORDER BY clause. The changes involve updating SQLASTBuilder to store the Expression object directly within OrderByItem instead of relying on identifier extraction or string-based aliases. Additionally, SelectExecutionPlanner and OrderByItem were updated to handle the evaluation and projection of these expressions. Regression tests have been added to SQLCaseTest to verify the fix. I have no feedback to provide.
Code ReviewOverall, this is a clean and well-targeted fix for the NPE issue. The approach - storing the What works well
Issues1. The method currently checks only public boolean refersToParent() {
if (alias != null && alias.equalsIgnoreCase("$parent"))
return true;
return modifier != null && modifier.refersToParent();
}If a CASE WHEN expression in ORDER BY references if (expression != null && expression.refersToParent())
return true;2. Inconsistent field access pattern The new 3. public String getName() {
return alias != null ? alias : recordAttr != null ? recordAttr : null;
}This returns if (!allAliases.contains(item.getName()))
4. The The new branch: } else {
continue;
}This silently skips an ORDER BY item that has no alias, no expression, and no recordAttr. Previously this case couldn't occur (the expression was serialized to an alias string). With the new code it still shouldn't occur, but if it does (e.g. a bug elsewhere), the ORDER BY item would be silently ignored. A defensive log warning here would help debugging. Minor
SummaryThe fix is correct and the test coverage is solid. The main actionable items before merge are:
|
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 6 |
🟢 Coverage 100.00% diff coverage · -7.87% coverage variation
Metric Results Coverage variation ✅ -7.87% coverage variation Diff coverage ✅ 100.00% diff coverage Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (6964490) 116313 85427 73.45% Head commit (ce5a052) 147469 (+31156) 96700 (+11273) 65.57% (-7.87%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#3778) 6 6 100.00% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
TIP This summary will be updated as you push new changes. Give us feedback
- Check expression.refersToParent() in OrderByItem.refersToParent() to correctly handle CASE WHEN expressions referencing $parent in subquery contexts - Add comment to getName() clarifying null return semantics when only expression is set Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Code Review (follow-up correction)I need to correct an error in my previous review comment: if (expression != null && expression.refersToParent())
return true;Accurate assessment of remaining points
Mutation in
OverallThe fix is correct and complete. All the right methods ( |
|
Addressed the review in a follow-up commit:
The getter/setter suggestion was skipped - |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3778 +/- ##
==========================================
+ Coverage 64.61% 65.15% +0.54%
==========================================
Files 1580 1580
Lines 116313 116354 +41
Branches 24669 24677 +8
==========================================
+ Hits 75155 75813 +658
+ Misses 30914 30224 -690
- Partials 10244 10317 +73 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Summary
Fixes #3777
baseExpr.identifierinSQLASTBuilder.visitOrderByItem-CASE WHENproduces aBaseExpressionwithidentifier = null, causing NPE on.suffixaccessexpressionfield toOrderByItemto store complex expressions (CASE WHEN, etc.)OrderByItem.compare()to evaluate the expression directly forSELECT *queriesSelectExecutionPlanner.calculateAdditionalOrderByProjections()to inject a computed projection forSELECT fieldsqueriesTest plan
orderByCaseWhenExpression- inline CASE WHEN in ORDER BY ASCorderByCaseWhenExpressionDesc- inline CASE WHEN in ORDER BY DESCorderByCaseWhenWithSelectStar- CASE WHEN in ORDER BY with SELECT *orderByExtendedCaseWhenExpression- extended CASE expr WHEN val THEN result in ORDER BYSQLCaseTesttests pass, no regressions in ORDER BY related tests🤖 Generated with Claude Code