Fix inconsistent AST formatting for kql_array_sort subscript followed by an operator (STID 1941-1bfa)#107634
Conversation
… by an operator (STID 1941-1bfa) kql_array_sort_asc/kql_array_sort_desc return Tuple(Array, ...), so a [i] subscript on their result is tuple-element access and the parser rewrites the arrayElement operator to tupleElement. That rewrite lived only in Layer::mergeElement. When the subscript is immediately followed by another equal-or-lower-priority operator (.j, [k], +, =, ...), the arrayElement node is instead built by the operator-merge loop in ParserExpressionImpl::tryParseOperator, which had no rewrite, so a raw arrayElement(kql_array_sort_*, i) survived. The formatter emits that as [i], which re-parses (now with no trailing operator) through the rewrite as tupleElement, so the format-parse-format round-trip diverged and the consistency check in executeQueryImpl aborted the server with a LOGICAL_ERROR in debug and sanitizer builds. The rewrite is factored into Layer::foldKqlArraySortSubscript and applied at both arrayElement construction sites. It inspects the actual first argument of the just-built node instead of guessing from the operand stack, and keeps the operator-syntax guard so call-syntax arrayElement(kql_array_sort_*, ...) is preserved verbatim. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
cc @evillique @george-larionov -- could you review this? It fixes a debug-build server abort (Inconsistent AST formatting, STID 1941-1bfa) for |
|
Workflow [PR], commit [bb54b60] Summary: ❌
AI ReviewSummaryThis PR fixes the parser asymmetry for Final VerdictStatus: ✅ Approve. No required changes. |
|
CI summary for head 5a342b6. All three red checks are pre-existing failures unrelated to this parser-only change (KQL array_sort subscript fold). The new regression test
Finish Workflow is green; Mergeable Check is red only due to the non-PR-caused failures above. |
|
@groeneai, fix flaky test |
…ray-sort-subscript-operator-1941-1bfa
|
@alexey-milovidov done.
|
LLVM Coverage Report
Changed lines: Changed C/C++ lines covered by tests: 22/24 (91.67%) | Lost baseline coverage (was covered on master, now uncovered in this PR): 3 line(s) · Uncovered code |
|
CI fully finished on bb54b60. The only red is The two failures from the directive are green on this head: |
|
@groeneai, we don't like KQL, because it is experimental and was implemented with low quality. Send another PR that will remove |
|
Done: #108101 removes That makes this PR moot: with the functions gone, the |

Related: #105396
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
Fix a
LOGICAL_ERROR("Inconsistent AST formatting") when a[i]subscript on akql_array_sort_asc/kql_array_sort_descresult is followed by another operator, for examplekql_array_sort_desc([...])[i].j.Description
CI report (BuzzHouse, amd_debug, STID 1941-1bfa): https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=107210&sha=61447331cad5ae84cca31abe742548cfa907b3db&name_0=PR&name_1=BuzzHouse%20%28amd_debug%29
kql_array_sort_asc/kql_array_sort_descreturnTuple(Array, ...), so a[i]subscript on their result is tuple-element access and the parser rewrites thearrayElementoperator totupleElement. That rewrite lived only inLayer::mergeElement. When the subscript is immediately followed by another equal-or-lower-priority operator (.j,[k],+,=, ...), thearrayElementnode is instead built by the operator-merge loop inParserExpressionImpl::tryParseOperator, which had no rewrite, so a rawarrayElement(kql_array_sort_*, i)survived. The formatter emits that as[i], which re-parses (now with no trailing operator) through the rewrite astupleElement, so the format-parse-format round-trip diverged and the consistency check inexecuteQueryImplaborted the server with aLOGICAL_ERRORin debug and sanitizer builds.Minimal reproducer (aborts the server on master, returns a clean type error with this fix):
The rewrite is factored into
Layer::foldKqlArraySortSubscriptand applied at botharrayElementconstruction sites. It inspects the actual first argument of the just-built node instead of guessing from the operand stack, and keeps the operator-syntax guard so call-syntaxarrayElement(kql_array_sort_*, ...)is preserved verbatim.