Improve error message for unsupported window functions in eventstats/streamstats - #5600

Open
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error
Open

Improve error message for unsupported window functions in eventstats/streamstats#5600
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error

Conversation

@gingeekrishna

Copy link
Copy Markdown
Contributor

Description

Fixes#5168

eventstats/streamstats reject window functions outside WINDOW_FUNC_MAPPING (e.g. rank(), dense_rank(), nth_value()) with a bare "Unexpected window function: X" error.

As confirmed in the issue discussion by @songkant-aws, this is expected behavior, not a bug — rank/dense_rank/nth_value require ORDER BY semantics, but eventstats/streamstats only support partition by. The issue was relabeled error-experience: the fix is to make the error message clearer, not to add support for these functions.

Changes

  • CalciteRexNodeVisitor#visitWindowFunction: replaced the generic "Unexpected window function: X" message with one that names the rejected function and lists the functions eventstats/streamstats do support (sourced from WINDOW_FUNC_MAPPING), so users get actionable guidance instead of a bare error.
  • Updated the existing unit test (UnifiedQueryPlannerTest) and integration tests (CalcitePPLEventstatsIT, CalciteStreamstatsCommandIT) to assert against the new message.
  • Added new integration tests covering rank/dense_rank specifically, since the issue's repro queries used those functions.

Note: this PR builds on top of #5587 (already merged), which fixed the same throw site to return a 4xx instead of a 500. This PR only changes the message text, not the exception type or HTTP status.

Test plan

  • Unit test UnifiedQueryPlannerTest#unsupportedWindowFunctionIsRethrownAsSemanticCheckException passes
  • Integration tests added/updated for eventstats and streamstats (require a live cluster to run in CI)

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dd3ca1c)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

Hardcoded list

The error message hardcodes the list of supported functions as a string literal. If WINDOW_FUNC_MAPPING changes (functions added or removed), this message will become stale and misleading. The list should be generated dynamically from WINDOW_FUNC_MAPPING to stay accurate.

+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Latest suggestions up to dd3ca1c

Explore these optional code suggestions:

CategorySuggestion Impact
Possible issue
Add null check for queryType

Add null check for context.queryType before comparison to prevent potential
NullPointerException. The context object might have a null queryType field in
certain scenarios, which would cause the filter predicate to fail.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [773-777]

 .filter(
functionName ->
- !(context.queryType == QueryType.PPL+ !(context.queryType != null+ && context.queryType == QueryType.PPL
&& (functionName == BuiltinFunctionName.RANK
|| functionName == BuiltinFunctionName.DENSE_RANK)))
Suggestion importance[1-10]: 5

__

Why: While adding a null check for context.queryType is a defensive programming practice, there's no evidence in the PR that queryType can be null. The suggestion is technically valid but may be unnecessary without context showing this is a real issue. This is a standard null-safety suggestion that doesn't address a demonstrated bug.

Low

Previous suggestions

Suggestions up to commit 58fda66
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + ".");
Suggestion importance[1-10]: 7

__

Why: This is a valid maintainability improvement that prevents the hardcoded list from becoming stale when WINDOW_FUNC_MAPPING is updated. However, it's a moderate enhancement rather than a critical fix, as the current implementation is functional and the mapping is unlikely to change frequently.

Medium
Suggestions up to commit cf4cb1b
CategorySuggestion Impact
General
Verify row_number support in error message

The error message lists row_number as a supported function, but the grammar changes
in OpenSearchPPLParser.g4 removed RANK and DENSE_RANK from scalarWindowFunctionName,
leaving only ROW_NUMBER and other functions. Verify that row_number is actually
supported in eventstats/streamstats context, as the test changes suggest ranking
functions are now rejected at parse time.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " latest, max, min, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid concern about the consistency between the error message and grammar changes. However, examining the grammar file shows that ROW_NUMBER is still present in scalarWindowFunctionName, suggesting it remains supported. The suggestion asks for verification rather than identifying a definite error, and the existing_code matches the improved_code, indicating no concrete change is proposed.

Medium
Suggestions up to commit 99c53f5
CategorySuggestion Impact
General
Use String.format for error message

The error message concatenates multiple strings which can impact readability and
maintainability. Consider using String.format() or a text block for better
formatting and easier future modifications of the supported functions list.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
- "Window function '"- + funcName- + "' is not supported in eventstats/streamstats."- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ String.format(+ "Window function '%s' is not supported in eventstats/streamstats."+ + " Supported functions: avg, count, dc, distinct_count, earliest,"+ + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " var_pop, var_samp.",+ funcName));
Suggestion importance[1-10]: 4

__

Why: While using String.format() can improve readability, the current string concatenation approach is perfectly valid and readable. This is a minor style improvement that doesn't significantly impact code quality or functionality.

Low
Suggestions up to commit c16fc0c
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + "."));
Suggestion importance[1-10]: 7

__

Why: This suggestion improves maintainability by dynamically generating the list of supported functions from WINDOW_FUNC_MAPPING.keySet() instead of hardcoding them. This ensures the error message stays accurate when new functions are added, reducing maintenance burden and preventing outdated documentation.

Medium

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 99c53f5

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi, I'm trying to add support for rank and dense_rank function in Calcite for unified SQL for analytics engine. If we confirm both are not supported by PPL evenstats and streamstats, shall we remove them from PPL grammar directly? I assume that's the only place window function can be used. Otherwise it will be tricky to check language type in Calcite planner.

@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Good question — I dug into this a bit.

Your assumption holds for PPL specifically: in the PPL grammar, windowFunction (the parenthesized call syntax) is only ever invoked from eventstatsAggTerm/streamstatsAggTerm (OpenSearchPPLParser.g4:922-943), so that is the only place a window function can appear in PPL today.

But it's not the only place in the engine overall. SQL has its own windowFunctionClause/overClause grammar (OpenSearchSQLParser.g4:150-159) that already accepts RANK()/DENSE_RANK() in ... OVER (...). Both SQL and PPL build the same WindowFunction AST node and are resolved by the same CalciteRexNodeVisitor#visitWindowFunction — there's even a comment there noting "SQL emits AggregateFunction for aggregate-as-window (e.g., SUM(x) OVER); PPL emits Function." WINDOW_FUNC_MAPPING in BuiltinFunctionName (used by both paths) simply has no rank/dense_rank entries yet, so both languages fail identically right now.

Practical implication: if you add rank/dense_rank to WINDOW_FUNC_MAPPING and implement them in the shared visitor, that enables them for PPL eventstats/streamstats too, since the mapping/visitor is shared — not just SQL.

So yes, I think removing RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule (lines 933-934) is the right move, and it avoids the language-type check you were worried about: PPL's parser would reject the syntax before it ever reaches the AST/Calcite layer, while SQL's grammar (which already accepts it) passes through untouched. That pushes the language separation to parse time instead of planner time.

One side note on this PR itself: the new error message I added ("Window function 'x' is not supported in eventstats/streamstats") is thrown from that same shared visitor, so it would also currently fire — misleadingly — for a plain SQL RANK() OVER (...) query, since the check isn't actually PPL-specific. I may follow up with a tweak to make that message language-agnostic.

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna Thanks for digging in! I've put up PR #5720 for the SQL side. As you confirmed, removing them from grammar should make PPL reject at parse time and leaves my change SQL-only. With both PRs merged, I think we get the language separation at parse time rather than in the planner, which is where it belongs as expected. Thanks!

@dai-chendai-chen added enhancement New feature or request PPL Piped processing language labels Aug 26, 2026
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Nice, thanks for #5720. Pushed da13116 here: removed RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule, so eventstats rank()/streamstats dense_rank() now fail at parse time (SyntaxCheckException) instead of reaching the shared visitor.

Updated the tests this PR added for that case (testRankingWindowFunctionsUnsupportedInEventstats/...InStreamstats) to expect the parse-time rejection, and switched unsupportedWindowFunctionIsRethrownAsSemanticCheckException from rank() to percent_rank() since it needs a token that's still in the grammar but outside WINDOW_FUNC_MAPPING to exercise that path.

One caveat: I don't have a Java toolchain in my current environment, so I couldn't run generateGrammarSource/the actual test suite to confirm the exact ANTLR error message — the assertions only check for the generic "is not a valid term at this part of the query" substring rather than the full expected-tokens list, to stay robust either way, but it'd be good to have CI confirm this once it runs.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit da13116

…streamstats
Window functions outside WINDOW_FUNC_MAPPING (e.g. rank, dense_rank,
nth_value) throw a generic "Unexpected window function: X" from
CalciteRexNodeVisitor#visitWindowFunction. These functions require
ORDER BY semantics that eventstats/streamstats don't have (they only
support partition-by), so they are intentionally unsupported, not a
bug -- but the error message gave users no indication of what to use
instead.
Replace the message with one that names the function and lists the
functions eventstats/streamstats do support, so users get actionable
guidance instead of a bare "unexpected" error.
Fixesopensearch-project#5168
Signed-off-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
WINDOW_FUNC_MAPPING (used by eventstats/streamstats) never supported
rank/dense_rank, but PPL's scalarWindowFunctionName grammar rule still
accepted the tokens, so `eventstats rank()` reached
CalciteRexNodeVisitor#visitWindowFunction and failed there with the
"not supported" message this PR improves. Meanwhile SQL's grammar
already accepts RANK()/DENSE_RANK() OVER (...), and opensearch-project#5720 is adding
real support for them on the SQL side via the same shared visitor.
Remove RANK/DENSE_RANK from scalarWindowFunctionName so PPL rejects
them at parse time instead of falling through to the shared
SQL/PPL visitor - this keeps the language separation at the parser
rather than relying on a WINDOW_FUNC_MAPPING check in shared planner
code, and avoids PPL silently gaining rank/dense_rank as a side effect
of opensearch-project#5720 registering them for SQL.
Updates the eventstats/streamstats tests added earlier in this PR to
expect a SyntaxCheckException (parse-time) instead of the semantic
"not supported" error, and switches the unrelated
visitWindowFunction-rejection unit test from rank() to percent_rank(),
which remains unsupported and still exercises that code path.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna
gingeekrishnaforce-pushed the fix/5168-improve-unsupported-window-function-error branch from da13116 to cf4cb1bCompareAugust 30, 2026 05:23
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit cf4cb1b

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna My PR was already merged. You can rebase and verify yours by CI if you're unable locally. Btw, I recall changes in unsupportedWindowFunctionIsRethrownAsSemanticCheckException is already covered in my PR.

Comment on lines +816 to +818
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe revert this change because this list is dynamic and defined in grammar.

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor comment. Thanks for the changes!

@dai-chen

Copy link
Copy Markdown
Collaborator

I retried Linter CI but it still failed. Probably worth taking another look.

… time"
This reverts commit cf4cb1b.
The "PPL grammar compatibility" CI check failed after that commit:
[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/
eventstats-rank: expected 1, got 0
That check runs OpenSearch-Dashboards' own PPL linter (fetched via
`yarn osd bootstrap`) against this repo's grammar bundle, using test
cases from scripts/ppl-lint/grammar-cases.json. Its
"unsupported-window-function-in-eventstats" rule expects
`eventstats rank()` to parse successfully and then be flagged by a
semantic-layer diagnostic (giving IDE users a specific, friendly
error). Removing RANK/DENSE_RANK from the PPL grammar made the query
fail to parse at all, so that rule never gets a chance to run and the
diagnostic it's supposed to produce disappears - the ppl-lint test
expects the rule to fire (count 1) but the query now dies earlier with
a raw syntax error instead (count 0).
The rule implementation lives in OpenSearch-Dashboards, not this repo,
so fixing this properly would need a coordinated cross-repo change.
Reverting restores parsing (and the linter's diagnostic) while keeping
the actual point of this PR - the improved
"Window function 'x' is not supported in eventstats/streamstats"
message from CalciteRexNodeVisitor - fully intact, since that's a
semantic-layer check unaffected by this revert.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

Found it - pushed 58fda664f to fix it.

The failing check was the linter, specifically:

[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/eventstats-rank: expected 1, got 0

That's OpenSearch-Dashboards' own PPL linter (fetched via yarn osd bootstrap in that job) being run against this repo's grammar bundle, using the cases in scripts/ppl-lint/grammar-cases.json. Its unsupported-window-function-in-eventstats rule expects eventstats rank() to parse successfully and then get flagged by a semantic-layer diagnostic - that's how it surfaces a friendly, specific error in the IDE.

My earlier commit here (cf4cb1bd3, removing RANK/DENSE_RANK from the PPL grammar so eventstats rank() fails at parse time instead of reaching the shared visitor) broke exactly that: the query now dies with a raw syntax error before OSD's semantic rule ever gets a chance to run, so its diagnostic never fires. Since that rule lives in the OpenSearch-Dashboards repo, not here, fixing it properly would need a coordinated cross-repo change - out of scope for this PR.

Reverted that commit. This PR's actual point - the improved "Window function 'x' is not supported in eventstats/streamstats" message in CalciteRexNodeVisitor - is a semantic-layer check, so it's untouched by the revert and still works exactly as intended. The parse-time language-separation idea from our earlier discussion doesn't hold up against the existing linter contract, so I'm dropping it rather than pursuing it further here.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 58fda66

…layer
opensearch-project#5720 added rank/dense_rank to the WINDOW_FUNC_MAPPING shared by both
SQL's RANK()/DENSE_RANK() OVER (...) and PPL's eventstats/streamstats,
which silently enabled them for eventstats/streamstats too:
testRankingWindowFunctionsUnsupportedInEventstats/InStreamstats
(added earlier in this PR) started failing with "expected
ResponseException to be thrown, but nothing was thrown" once opensearch-project#5720
merged, since eventstats rank() now builds a real window call instead
of hitting the "not supported" check.
That's a real gap, not just a test artifact: PPL's eventstats/
streamstats grammar has no ORDER BY syntax at all, so ranking has no
defined ordering to rank by there - unlike SQL's OVER(), which at
least has (optional) ORDER BY in its own clause.
A prior commit on this branch tried fixing this by removing RANK/
DENSE_RANK from the PPL grammar entirely, rejecting them at parse
time. That broke a different, cross-repo contract: OpenSearch-
Dashboards' PPL linter (validated by the "PPL grammar compatibility"
CI check) expects `eventstats rank()` to parse successfully and be
flagged by a semantic-layer diagnostic instead, so it could no longer
produce that diagnostic once the query stopped parsing. That commit
was reverted.
Fix this at the semantic layer instead, where it belongs: PPL only
ever reaches CalciteRexNodeVisitor#visitWindowFunction through
eventstats/streamstats (no other PPL syntax builds a WindowFunction
node), so context.queryType == PPL is an exact, unambiguous signal for
"this is an eventstats/streamstats call". Filter rank/dense_rank out
of the WINDOW_FUNC_MAPPING lookup specifically when queryType is PPL,
so they fall through to the existing "not supported in eventstats/
streamstats" error - exactly the pre-opensearch-project#5720 behavior - while leaving
SQL's RANK()/DENSE_RANK() OVER (...) handling (and everything else)
completely untouched.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd3ca1c

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestPPLPiped processing language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] eventstats/streamstats reject window functions that grammar accepts

3 participants

@gingeekrishna@dai-chen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Improve error message for unsupported window functions in eventstats/streamstats - #5600

Open
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error
Open

Improve error message for unsupported window functions in eventstats/streamstats#5600
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error

Conversation

@gingeekrishna

Copy link
Copy Markdown
Contributor

Description

Fixes#5168

eventstats/streamstats reject window functions outside WINDOW_FUNC_MAPPING (e.g. rank(), dense_rank(), nth_value()) with a bare "Unexpected window function: X" error.

As confirmed in the issue discussion by @songkant-aws, this is expected behavior, not a bug — rank/dense_rank/nth_value require ORDER BY semantics, but eventstats/streamstats only support partition by. The issue was relabeled error-experience: the fix is to make the error message clearer, not to add support for these functions.

Changes

  • CalciteRexNodeVisitor#visitWindowFunction: replaced the generic "Unexpected window function: X" message with one that names the rejected function and lists the functions eventstats/streamstats do support (sourced from WINDOW_FUNC_MAPPING), so users get actionable guidance instead of a bare error.
  • Updated the existing unit test (UnifiedQueryPlannerTest) and integration tests (CalcitePPLEventstatsIT, CalciteStreamstatsCommandIT) to assert against the new message.
  • Added new integration tests covering rank/dense_rank specifically, since the issue's repro queries used those functions.

Note: this PR builds on top of #5587 (already merged), which fixed the same throw site to return a 4xx instead of a 500. This PR only changes the message text, not the exception type or HTTP status.

Test plan

  • Unit test UnifiedQueryPlannerTest#unsupportedWindowFunctionIsRethrownAsSemanticCheckException passes
  • Integration tests added/updated for eventstats and streamstats (require a live cluster to run in CI)

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dd3ca1c)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

Hardcoded list

The error message hardcodes the list of supported functions as a string literal. If WINDOW_FUNC_MAPPING changes (functions added or removed), this message will become stale and misleading. The list should be generated dynamically from WINDOW_FUNC_MAPPING to stay accurate.

+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Latest suggestions up to dd3ca1c

Explore these optional code suggestions:

CategorySuggestion Impact
Possible issue
Add null check for queryType

Add null check for context.queryType before comparison to prevent potential
NullPointerException. The context object might have a null queryType field in
certain scenarios, which would cause the filter predicate to fail.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [773-777]

 .filter(
functionName ->
- !(context.queryType == QueryType.PPL+ !(context.queryType != null+ && context.queryType == QueryType.PPL
&& (functionName == BuiltinFunctionName.RANK
|| functionName == BuiltinFunctionName.DENSE_RANK)))
Suggestion importance[1-10]: 5

__

Why: While adding a null check for context.queryType is a defensive programming practice, there's no evidence in the PR that queryType can be null. The suggestion is technically valid but may be unnecessary without context showing this is a real issue. This is a standard null-safety suggestion that doesn't address a demonstrated bug.

Low

Previous suggestions

Suggestions up to commit 58fda66
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + ".");
Suggestion importance[1-10]: 7

__

Why: This is a valid maintainability improvement that prevents the hardcoded list from becoming stale when WINDOW_FUNC_MAPPING is updated. However, it's a moderate enhancement rather than a critical fix, as the current implementation is functional and the mapping is unlikely to change frequently.

Medium
Suggestions up to commit cf4cb1b
CategorySuggestion Impact
General
Verify row_number support in error message

The error message lists row_number as a supported function, but the grammar changes
in OpenSearchPPLParser.g4 removed RANK and DENSE_RANK from scalarWindowFunctionName,
leaving only ROW_NUMBER and other functions. Verify that row_number is actually
supported in eventstats/streamstats context, as the test changes suggest ranking
functions are now rejected at parse time.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " latest, max, min, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid concern about the consistency between the error message and grammar changes. However, examining the grammar file shows that ROW_NUMBER is still present in scalarWindowFunctionName, suggesting it remains supported. The suggestion asks for verification rather than identifying a definite error, and the existing_code matches the improved_code, indicating no concrete change is proposed.

Medium
Suggestions up to commit 99c53f5
CategorySuggestion Impact
General
Use String.format for error message

The error message concatenates multiple strings which can impact readability and
maintainability. Consider using String.format() or a text block for better
formatting and easier future modifications of the supported functions list.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
- "Window function '"- + funcName- + "' is not supported in eventstats/streamstats."- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ String.format(+ "Window function '%s' is not supported in eventstats/streamstats."+ + " Supported functions: avg, count, dc, distinct_count, earliest,"+ + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " var_pop, var_samp.",+ funcName));
Suggestion importance[1-10]: 4

__

Why: While using String.format() can improve readability, the current string concatenation approach is perfectly valid and readable. This is a minor style improvement that doesn't significantly impact code quality or functionality.

Low
Suggestions up to commit c16fc0c
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + "."));
Suggestion importance[1-10]: 7

__

Why: This suggestion improves maintainability by dynamically generating the list of supported functions from WINDOW_FUNC_MAPPING.keySet() instead of hardcoding them. This ensures the error message stays accurate when new functions are added, reducing maintenance burden and preventing outdated documentation.

Medium

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 99c53f5

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi, I'm trying to add support for rank and dense_rank function in Calcite for unified SQL for analytics engine. If we confirm both are not supported by PPL evenstats and streamstats, shall we remove them from PPL grammar directly? I assume that's the only place window function can be used. Otherwise it will be tricky to check language type in Calcite planner.

@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Good question — I dug into this a bit.

Your assumption holds for PPL specifically: in the PPL grammar, windowFunction (the parenthesized call syntax) is only ever invoked from eventstatsAggTerm/streamstatsAggTerm (OpenSearchPPLParser.g4:922-943), so that is the only place a window function can appear in PPL today.

But it's not the only place in the engine overall. SQL has its own windowFunctionClause/overClause grammar (OpenSearchSQLParser.g4:150-159) that already accepts RANK()/DENSE_RANK() in ... OVER (...). Both SQL and PPL build the same WindowFunction AST node and are resolved by the same CalciteRexNodeVisitor#visitWindowFunction — there's even a comment there noting "SQL emits AggregateFunction for aggregate-as-window (e.g., SUM(x) OVER); PPL emits Function." WINDOW_FUNC_MAPPING in BuiltinFunctionName (used by both paths) simply has no rank/dense_rank entries yet, so both languages fail identically right now.

Practical implication: if you add rank/dense_rank to WINDOW_FUNC_MAPPING and implement them in the shared visitor, that enables them for PPL eventstats/streamstats too, since the mapping/visitor is shared — not just SQL.

So yes, I think removing RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule (lines 933-934) is the right move, and it avoids the language-type check you were worried about: PPL's parser would reject the syntax before it ever reaches the AST/Calcite layer, while SQL's grammar (which already accepts it) passes through untouched. That pushes the language separation to parse time instead of planner time.

One side note on this PR itself: the new error message I added ("Window function 'x' is not supported in eventstats/streamstats") is thrown from that same shared visitor, so it would also currently fire — misleadingly — for a plain SQL RANK() OVER (...) query, since the check isn't actually PPL-specific. I may follow up with a tweak to make that message language-agnostic.

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna Thanks for digging in! I've put up PR #5720 for the SQL side. As you confirmed, removing them from grammar should make PPL reject at parse time and leaves my change SQL-only. With both PRs merged, I think we get the language separation at parse time rather than in the planner, which is where it belongs as expected. Thanks!

@dai-chendai-chen added enhancement New feature or request PPL Piped processing language labels Aug 26, 2026
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Nice, thanks for #5720. Pushed da13116 here: removed RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule, so eventstats rank()/streamstats dense_rank() now fail at parse time (SyntaxCheckException) instead of reaching the shared visitor.

Updated the tests this PR added for that case (testRankingWindowFunctionsUnsupportedInEventstats/...InStreamstats) to expect the parse-time rejection, and switched unsupportedWindowFunctionIsRethrownAsSemanticCheckException from rank() to percent_rank() since it needs a token that's still in the grammar but outside WINDOW_FUNC_MAPPING to exercise that path.

One caveat: I don't have a Java toolchain in my current environment, so I couldn't run generateGrammarSource/the actual test suite to confirm the exact ANTLR error message — the assertions only check for the generic "is not a valid term at this part of the query" substring rather than the full expected-tokens list, to stay robust either way, but it'd be good to have CI confirm this once it runs.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit da13116

…streamstats
Window functions outside WINDOW_FUNC_MAPPING (e.g. rank, dense_rank,
nth_value) throw a generic "Unexpected window function: X" from
CalciteRexNodeVisitor#visitWindowFunction. These functions require
ORDER BY semantics that eventstats/streamstats don't have (they only
support partition-by), so they are intentionally unsupported, not a
bug -- but the error message gave users no indication of what to use
instead.
Replace the message with one that names the function and lists the
functions eventstats/streamstats do support, so users get actionable
guidance instead of a bare "unexpected" error.
Fixesopensearch-project#5168
Signed-off-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
WINDOW_FUNC_MAPPING (used by eventstats/streamstats) never supported
rank/dense_rank, but PPL's scalarWindowFunctionName grammar rule still
accepted the tokens, so `eventstats rank()` reached
CalciteRexNodeVisitor#visitWindowFunction and failed there with the
"not supported" message this PR improves. Meanwhile SQL's grammar
already accepts RANK()/DENSE_RANK() OVER (...), and opensearch-project#5720 is adding
real support for them on the SQL side via the same shared visitor.
Remove RANK/DENSE_RANK from scalarWindowFunctionName so PPL rejects
them at parse time instead of falling through to the shared
SQL/PPL visitor - this keeps the language separation at the parser
rather than relying on a WINDOW_FUNC_MAPPING check in shared planner
code, and avoids PPL silently gaining rank/dense_rank as a side effect
of opensearch-project#5720 registering them for SQL.
Updates the eventstats/streamstats tests added earlier in this PR to
expect a SyntaxCheckException (parse-time) instead of the semantic
"not supported" error, and switches the unrelated
visitWindowFunction-rejection unit test from rank() to percent_rank(),
which remains unsupported and still exercises that code path.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna
gingeekrishnaforce-pushed the fix/5168-improve-unsupported-window-function-error branch from da13116 to cf4cb1bCompareAugust 30, 2026 05:23
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit cf4cb1b

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna My PR was already merged. You can rebase and verify yours by CI if you're unable locally. Btw, I recall changes in unsupportedWindowFunctionIsRethrownAsSemanticCheckException is already covered in my PR.

Comment on lines +816 to +818
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe revert this change because this list is dynamic and defined in grammar.

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor comment. Thanks for the changes!

@dai-chen

Copy link
Copy Markdown
Collaborator

I retried Linter CI but it still failed. Probably worth taking another look.

… time"
This reverts commit cf4cb1b.
The "PPL grammar compatibility" CI check failed after that commit:
[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/
eventstats-rank: expected 1, got 0
That check runs OpenSearch-Dashboards' own PPL linter (fetched via
`yarn osd bootstrap`) against this repo's grammar bundle, using test
cases from scripts/ppl-lint/grammar-cases.json. Its
"unsupported-window-function-in-eventstats" rule expects
`eventstats rank()` to parse successfully and then be flagged by a
semantic-layer diagnostic (giving IDE users a specific, friendly
error). Removing RANK/DENSE_RANK from the PPL grammar made the query
fail to parse at all, so that rule never gets a chance to run and the
diagnostic it's supposed to produce disappears - the ppl-lint test
expects the rule to fire (count 1) but the query now dies earlier with
a raw syntax error instead (count 0).
The rule implementation lives in OpenSearch-Dashboards, not this repo,
so fixing this properly would need a coordinated cross-repo change.
Reverting restores parsing (and the linter's diagnostic) while keeping
the actual point of this PR - the improved
"Window function 'x' is not supported in eventstats/streamstats"
message from CalciteRexNodeVisitor - fully intact, since that's a
semantic-layer check unaffected by this revert.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

Found it - pushed 58fda664f to fix it.

The failing check was the linter, specifically:

[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/eventstats-rank: expected 1, got 0

That's OpenSearch-Dashboards' own PPL linter (fetched via yarn osd bootstrap in that job) being run against this repo's grammar bundle, using the cases in scripts/ppl-lint/grammar-cases.json. Its unsupported-window-function-in-eventstats rule expects eventstats rank() to parse successfully and then get flagged by a semantic-layer diagnostic - that's how it surfaces a friendly, specific error in the IDE.

My earlier commit here (cf4cb1bd3, removing RANK/DENSE_RANK from the PPL grammar so eventstats rank() fails at parse time instead of reaching the shared visitor) broke exactly that: the query now dies with a raw syntax error before OSD's semantic rule ever gets a chance to run, so its diagnostic never fires. Since that rule lives in the OpenSearch-Dashboards repo, not here, fixing it properly would need a coordinated cross-repo change - out of scope for this PR.

Reverted that commit. This PR's actual point - the improved "Window function 'x' is not supported in eventstats/streamstats" message in CalciteRexNodeVisitor - is a semantic-layer check, so it's untouched by the revert and still works exactly as intended. The parse-time language-separation idea from our earlier discussion doesn't hold up against the existing linter contract, so I'm dropping it rather than pursuing it further here.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 58fda66

…layer
opensearch-project#5720 added rank/dense_rank to the WINDOW_FUNC_MAPPING shared by both
SQL's RANK()/DENSE_RANK() OVER (...) and PPL's eventstats/streamstats,
which silently enabled them for eventstats/streamstats too:
testRankingWindowFunctionsUnsupportedInEventstats/InStreamstats
(added earlier in this PR) started failing with "expected
ResponseException to be thrown, but nothing was thrown" once opensearch-project#5720
merged, since eventstats rank() now builds a real window call instead
of hitting the "not supported" check.
That's a real gap, not just a test artifact: PPL's eventstats/
streamstats grammar has no ORDER BY syntax at all, so ranking has no
defined ordering to rank by there - unlike SQL's OVER(), which at
least has (optional) ORDER BY in its own clause.
A prior commit on this branch tried fixing this by removing RANK/
DENSE_RANK from the PPL grammar entirely, rejecting them at parse
time. That broke a different, cross-repo contract: OpenSearch-
Dashboards' PPL linter (validated by the "PPL grammar compatibility"
CI check) expects `eventstats rank()` to parse successfully and be
flagged by a semantic-layer diagnostic instead, so it could no longer
produce that diagnostic once the query stopped parsing. That commit
was reverted.
Fix this at the semantic layer instead, where it belongs: PPL only
ever reaches CalciteRexNodeVisitor#visitWindowFunction through
eventstats/streamstats (no other PPL syntax builds a WindowFunction
node), so context.queryType == PPL is an exact, unambiguous signal for
"this is an eventstats/streamstats call". Filter rank/dense_rank out
of the WINDOW_FUNC_MAPPING lookup specifically when queryType is PPL,
so they fall through to the existing "not supported in eventstats/
streamstats" error - exactly the pre-opensearch-project#5720 behavior - while leaving
SQL's RANK()/DENSE_RANK() OVER (...) handling (and everything else)
completely untouched.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd3ca1c

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestPPLPiped processing language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] eventstats/streamstats reject window functions that grammar accepts

3 participants

@gingeekrishna@dai-chen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Improve error message for unsupported window functions in eventstats/streamstats - #5600

Open
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error
Open

Improve error message for unsupported window functions in eventstats/streamstats#5600
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error

Conversation

@gingeekrishna

Copy link
Copy Markdown
Contributor

Description

Fixes#5168

eventstats/streamstats reject window functions outside WINDOW_FUNC_MAPPING (e.g. rank(), dense_rank(), nth_value()) with a bare "Unexpected window function: X" error.

As confirmed in the issue discussion by @songkant-aws, this is expected behavior, not a bug — rank/dense_rank/nth_value require ORDER BY semantics, but eventstats/streamstats only support partition by. The issue was relabeled error-experience: the fix is to make the error message clearer, not to add support for these functions.

Changes

  • CalciteRexNodeVisitor#visitWindowFunction: replaced the generic "Unexpected window function: X" message with one that names the rejected function and lists the functions eventstats/streamstats do support (sourced from WINDOW_FUNC_MAPPING), so users get actionable guidance instead of a bare error.
  • Updated the existing unit test (UnifiedQueryPlannerTest) and integration tests (CalcitePPLEventstatsIT, CalciteStreamstatsCommandIT) to assert against the new message.
  • Added new integration tests covering rank/dense_rank specifically, since the issue's repro queries used those functions.

Note: this PR builds on top of #5587 (already merged), which fixed the same throw site to return a 4xx instead of a 500. This PR only changes the message text, not the exception type or HTTP status.

Test plan

  • Unit test UnifiedQueryPlannerTest#unsupportedWindowFunctionIsRethrownAsSemanticCheckException passes
  • Integration tests added/updated for eventstats and streamstats (require a live cluster to run in CI)

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dd3ca1c)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

Hardcoded list

The error message hardcodes the list of supported functions as a string literal. If WINDOW_FUNC_MAPPING changes (functions added or removed), this message will become stale and misleading. The list should be generated dynamically from WINDOW_FUNC_MAPPING to stay accurate.

+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Latest suggestions up to dd3ca1c

Explore these optional code suggestions:

CategorySuggestion Impact
Possible issue
Add null check for queryType

Add null check for context.queryType before comparison to prevent potential
NullPointerException. The context object might have a null queryType field in
certain scenarios, which would cause the filter predicate to fail.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [773-777]

 .filter(
functionName ->
- !(context.queryType == QueryType.PPL+ !(context.queryType != null+ && context.queryType == QueryType.PPL
&& (functionName == BuiltinFunctionName.RANK
|| functionName == BuiltinFunctionName.DENSE_RANK)))
Suggestion importance[1-10]: 5

__

Why: While adding a null check for context.queryType is a defensive programming practice, there's no evidence in the PR that queryType can be null. The suggestion is technically valid but may be unnecessary without context showing this is a real issue. This is a standard null-safety suggestion that doesn't address a demonstrated bug.

Low

Previous suggestions

Suggestions up to commit 58fda66
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + ".");
Suggestion importance[1-10]: 7

__

Why: This is a valid maintainability improvement that prevents the hardcoded list from becoming stale when WINDOW_FUNC_MAPPING is updated. However, it's a moderate enhancement rather than a critical fix, as the current implementation is functional and the mapping is unlikely to change frequently.

Medium
Suggestions up to commit cf4cb1b
CategorySuggestion Impact
General
Verify row_number support in error message

The error message lists row_number as a supported function, but the grammar changes
in OpenSearchPPLParser.g4 removed RANK and DENSE_RANK from scalarWindowFunctionName,
leaving only ROW_NUMBER and other functions. Verify that row_number is actually
supported in eventstats/streamstats context, as the test changes suggest ranking
functions are now rejected at parse time.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " latest, max, min, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid concern about the consistency between the error message and grammar changes. However, examining the grammar file shows that ROW_NUMBER is still present in scalarWindowFunctionName, suggesting it remains supported. The suggestion asks for verification rather than identifying a definite error, and the existing_code matches the improved_code, indicating no concrete change is proposed.

Medium
Suggestions up to commit 99c53f5
CategorySuggestion Impact
General
Use String.format for error message

The error message concatenates multiple strings which can impact readability and
maintainability. Consider using String.format() or a text block for better
formatting and easier future modifications of the supported functions list.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
- "Window function '"- + funcName- + "' is not supported in eventstats/streamstats."- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ String.format(+ "Window function '%s' is not supported in eventstats/streamstats."+ + " Supported functions: avg, count, dc, distinct_count, earliest,"+ + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " var_pop, var_samp.",+ funcName));
Suggestion importance[1-10]: 4

__

Why: While using String.format() can improve readability, the current string concatenation approach is perfectly valid and readable. This is a minor style improvement that doesn't significantly impact code quality or functionality.

Low
Suggestions up to commit c16fc0c
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + "."));
Suggestion importance[1-10]: 7

__

Why: This suggestion improves maintainability by dynamically generating the list of supported functions from WINDOW_FUNC_MAPPING.keySet() instead of hardcoding them. This ensures the error message stays accurate when new functions are added, reducing maintenance burden and preventing outdated documentation.

Medium

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 99c53f5

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi, I'm trying to add support for rank and dense_rank function in Calcite for unified SQL for analytics engine. If we confirm both are not supported by PPL evenstats and streamstats, shall we remove them from PPL grammar directly? I assume that's the only place window function can be used. Otherwise it will be tricky to check language type in Calcite planner.

@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Good question — I dug into this a bit.

Your assumption holds for PPL specifically: in the PPL grammar, windowFunction (the parenthesized call syntax) is only ever invoked from eventstatsAggTerm/streamstatsAggTerm (OpenSearchPPLParser.g4:922-943), so that is the only place a window function can appear in PPL today.

But it's not the only place in the engine overall. SQL has its own windowFunctionClause/overClause grammar (OpenSearchSQLParser.g4:150-159) that already accepts RANK()/DENSE_RANK() in ... OVER (...). Both SQL and PPL build the same WindowFunction AST node and are resolved by the same CalciteRexNodeVisitor#visitWindowFunction — there's even a comment there noting "SQL emits AggregateFunction for aggregate-as-window (e.g., SUM(x) OVER); PPL emits Function." WINDOW_FUNC_MAPPING in BuiltinFunctionName (used by both paths) simply has no rank/dense_rank entries yet, so both languages fail identically right now.

Practical implication: if you add rank/dense_rank to WINDOW_FUNC_MAPPING and implement them in the shared visitor, that enables them for PPL eventstats/streamstats too, since the mapping/visitor is shared — not just SQL.

So yes, I think removing RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule (lines 933-934) is the right move, and it avoids the language-type check you were worried about: PPL's parser would reject the syntax before it ever reaches the AST/Calcite layer, while SQL's grammar (which already accepts it) passes through untouched. That pushes the language separation to parse time instead of planner time.

One side note on this PR itself: the new error message I added ("Window function 'x' is not supported in eventstats/streamstats") is thrown from that same shared visitor, so it would also currently fire — misleadingly — for a plain SQL RANK() OVER (...) query, since the check isn't actually PPL-specific. I may follow up with a tweak to make that message language-agnostic.

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna Thanks for digging in! I've put up PR #5720 for the SQL side. As you confirmed, removing them from grammar should make PPL reject at parse time and leaves my change SQL-only. With both PRs merged, I think we get the language separation at parse time rather than in the planner, which is where it belongs as expected. Thanks!

@dai-chendai-chen added enhancement New feature or request PPL Piped processing language labels Aug 26, 2026
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Nice, thanks for #5720. Pushed da13116 here: removed RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule, so eventstats rank()/streamstats dense_rank() now fail at parse time (SyntaxCheckException) instead of reaching the shared visitor.

Updated the tests this PR added for that case (testRankingWindowFunctionsUnsupportedInEventstats/...InStreamstats) to expect the parse-time rejection, and switched unsupportedWindowFunctionIsRethrownAsSemanticCheckException from rank() to percent_rank() since it needs a token that's still in the grammar but outside WINDOW_FUNC_MAPPING to exercise that path.

One caveat: I don't have a Java toolchain in my current environment, so I couldn't run generateGrammarSource/the actual test suite to confirm the exact ANTLR error message — the assertions only check for the generic "is not a valid term at this part of the query" substring rather than the full expected-tokens list, to stay robust either way, but it'd be good to have CI confirm this once it runs.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit da13116

…streamstats
Window functions outside WINDOW_FUNC_MAPPING (e.g. rank, dense_rank,
nth_value) throw a generic "Unexpected window function: X" from
CalciteRexNodeVisitor#visitWindowFunction. These functions require
ORDER BY semantics that eventstats/streamstats don't have (they only
support partition-by), so they are intentionally unsupported, not a
bug -- but the error message gave users no indication of what to use
instead.
Replace the message with one that names the function and lists the
functions eventstats/streamstats do support, so users get actionable
guidance instead of a bare "unexpected" error.
Fixesopensearch-project#5168
Signed-off-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
WINDOW_FUNC_MAPPING (used by eventstats/streamstats) never supported
rank/dense_rank, but PPL's scalarWindowFunctionName grammar rule still
accepted the tokens, so `eventstats rank()` reached
CalciteRexNodeVisitor#visitWindowFunction and failed there with the
"not supported" message this PR improves. Meanwhile SQL's grammar
already accepts RANK()/DENSE_RANK() OVER (...), and opensearch-project#5720 is adding
real support for them on the SQL side via the same shared visitor.
Remove RANK/DENSE_RANK from scalarWindowFunctionName so PPL rejects
them at parse time instead of falling through to the shared
SQL/PPL visitor - this keeps the language separation at the parser
rather than relying on a WINDOW_FUNC_MAPPING check in shared planner
code, and avoids PPL silently gaining rank/dense_rank as a side effect
of opensearch-project#5720 registering them for SQL.
Updates the eventstats/streamstats tests added earlier in this PR to
expect a SyntaxCheckException (parse-time) instead of the semantic
"not supported" error, and switches the unrelated
visitWindowFunction-rejection unit test from rank() to percent_rank(),
which remains unsupported and still exercises that code path.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna
gingeekrishnaforce-pushed the fix/5168-improve-unsupported-window-function-error branch from da13116 to cf4cb1bCompareAugust 30, 2026 05:23
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit cf4cb1b

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna My PR was already merged. You can rebase and verify yours by CI if you're unable locally. Btw, I recall changes in unsupportedWindowFunctionIsRethrownAsSemanticCheckException is already covered in my PR.

Comment on lines +816 to +818
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe revert this change because this list is dynamic and defined in grammar.

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor comment. Thanks for the changes!

@dai-chen

Copy link
Copy Markdown
Collaborator

I retried Linter CI but it still failed. Probably worth taking another look.

… time"
This reverts commit cf4cb1b.
The "PPL grammar compatibility" CI check failed after that commit:
[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/
eventstats-rank: expected 1, got 0
That check runs OpenSearch-Dashboards' own PPL linter (fetched via
`yarn osd bootstrap`) against this repo's grammar bundle, using test
cases from scripts/ppl-lint/grammar-cases.json. Its
"unsupported-window-function-in-eventstats" rule expects
`eventstats rank()` to parse successfully and then be flagged by a
semantic-layer diagnostic (giving IDE users a specific, friendly
error). Removing RANK/DENSE_RANK from the PPL grammar made the query
fail to parse at all, so that rule never gets a chance to run and the
diagnostic it's supposed to produce disappears - the ppl-lint test
expects the rule to fire (count 1) but the query now dies earlier with
a raw syntax error instead (count 0).
The rule implementation lives in OpenSearch-Dashboards, not this repo,
so fixing this properly would need a coordinated cross-repo change.
Reverting restores parsing (and the linter's diagnostic) while keeping
the actual point of this PR - the improved
"Window function 'x' is not supported in eventstats/streamstats"
message from CalciteRexNodeVisitor - fully intact, since that's a
semantic-layer check unaffected by this revert.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

Found it - pushed 58fda664f to fix it.

The failing check was the linter, specifically:

[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/eventstats-rank: expected 1, got 0

That's OpenSearch-Dashboards' own PPL linter (fetched via yarn osd bootstrap in that job) being run against this repo's grammar bundle, using the cases in scripts/ppl-lint/grammar-cases.json. Its unsupported-window-function-in-eventstats rule expects eventstats rank() to parse successfully and then get flagged by a semantic-layer diagnostic - that's how it surfaces a friendly, specific error in the IDE.

My earlier commit here (cf4cb1bd3, removing RANK/DENSE_RANK from the PPL grammar so eventstats rank() fails at parse time instead of reaching the shared visitor) broke exactly that: the query now dies with a raw syntax error before OSD's semantic rule ever gets a chance to run, so its diagnostic never fires. Since that rule lives in the OpenSearch-Dashboards repo, not here, fixing it properly would need a coordinated cross-repo change - out of scope for this PR.

Reverted that commit. This PR's actual point - the improved "Window function 'x' is not supported in eventstats/streamstats" message in CalciteRexNodeVisitor - is a semantic-layer check, so it's untouched by the revert and still works exactly as intended. The parse-time language-separation idea from our earlier discussion doesn't hold up against the existing linter contract, so I'm dropping it rather than pursuing it further here.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 58fda66

…layer
opensearch-project#5720 added rank/dense_rank to the WINDOW_FUNC_MAPPING shared by both
SQL's RANK()/DENSE_RANK() OVER (...) and PPL's eventstats/streamstats,
which silently enabled them for eventstats/streamstats too:
testRankingWindowFunctionsUnsupportedInEventstats/InStreamstats
(added earlier in this PR) started failing with "expected
ResponseException to be thrown, but nothing was thrown" once opensearch-project#5720
merged, since eventstats rank() now builds a real window call instead
of hitting the "not supported" check.
That's a real gap, not just a test artifact: PPL's eventstats/
streamstats grammar has no ORDER BY syntax at all, so ranking has no
defined ordering to rank by there - unlike SQL's OVER(), which at
least has (optional) ORDER BY in its own clause.
A prior commit on this branch tried fixing this by removing RANK/
DENSE_RANK from the PPL grammar entirely, rejecting them at parse
time. That broke a different, cross-repo contract: OpenSearch-
Dashboards' PPL linter (validated by the "PPL grammar compatibility"
CI check) expects `eventstats rank()` to parse successfully and be
flagged by a semantic-layer diagnostic instead, so it could no longer
produce that diagnostic once the query stopped parsing. That commit
was reverted.
Fix this at the semantic layer instead, where it belongs: PPL only
ever reaches CalciteRexNodeVisitor#visitWindowFunction through
eventstats/streamstats (no other PPL syntax builds a WindowFunction
node), so context.queryType == PPL is an exact, unambiguous signal for
"this is an eventstats/streamstats call". Filter rank/dense_rank out
of the WINDOW_FUNC_MAPPING lookup specifically when queryType is PPL,
so they fall through to the existing "not supported in eventstats/
streamstats" error - exactly the pre-opensearch-project#5720 behavior - while leaving
SQL's RANK()/DENSE_RANK() OVER (...) handling (and everything else)
completely untouched.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd3ca1c

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestPPLPiped processing language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] eventstats/streamstats reject window functions that grammar accepts

3 participants

@gingeekrishna@dai-chen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Improve error message for unsupported window functions in eventstats/streamstats - #5600

Open
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error
Open

Improve error message for unsupported window functions in eventstats/streamstats#5600
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error

Conversation

@gingeekrishna

Copy link
Copy Markdown
Contributor

Description

Fixes#5168

eventstats/streamstats reject window functions outside WINDOW_FUNC_MAPPING (e.g. rank(), dense_rank(), nth_value()) with a bare "Unexpected window function: X" error.

As confirmed in the issue discussion by @songkant-aws, this is expected behavior, not a bug — rank/dense_rank/nth_value require ORDER BY semantics, but eventstats/streamstats only support partition by. The issue was relabeled error-experience: the fix is to make the error message clearer, not to add support for these functions.

Changes

  • CalciteRexNodeVisitor#visitWindowFunction: replaced the generic "Unexpected window function: X" message with one that names the rejected function and lists the functions eventstats/streamstats do support (sourced from WINDOW_FUNC_MAPPING), so users get actionable guidance instead of a bare error.
  • Updated the existing unit test (UnifiedQueryPlannerTest) and integration tests (CalcitePPLEventstatsIT, CalciteStreamstatsCommandIT) to assert against the new message.
  • Added new integration tests covering rank/dense_rank specifically, since the issue's repro queries used those functions.

Note: this PR builds on top of #5587 (already merged), which fixed the same throw site to return a 4xx instead of a 500. This PR only changes the message text, not the exception type or HTTP status.

Test plan

  • Unit test UnifiedQueryPlannerTest#unsupportedWindowFunctionIsRethrownAsSemanticCheckException passes
  • Integration tests added/updated for eventstats and streamstats (require a live cluster to run in CI)

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dd3ca1c)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

Hardcoded list

The error message hardcodes the list of supported functions as a string literal. If WINDOW_FUNC_MAPPING changes (functions added or removed), this message will become stale and misleading. The list should be generated dynamically from WINDOW_FUNC_MAPPING to stay accurate.

+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Latest suggestions up to dd3ca1c

Explore these optional code suggestions:

CategorySuggestion Impact
Possible issue
Add null check for queryType

Add null check for context.queryType before comparison to prevent potential
NullPointerException. The context object might have a null queryType field in
certain scenarios, which would cause the filter predicate to fail.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [773-777]

 .filter(
functionName ->
- !(context.queryType == QueryType.PPL+ !(context.queryType != null+ && context.queryType == QueryType.PPL
&& (functionName == BuiltinFunctionName.RANK
|| functionName == BuiltinFunctionName.DENSE_RANK)))
Suggestion importance[1-10]: 5

__

Why: While adding a null check for context.queryType is a defensive programming practice, there's no evidence in the PR that queryType can be null. The suggestion is technically valid but may be unnecessary without context showing this is a real issue. This is a standard null-safety suggestion that doesn't address a demonstrated bug.

Low

Previous suggestions

Suggestions up to commit 58fda66
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + ".");
Suggestion importance[1-10]: 7

__

Why: This is a valid maintainability improvement that prevents the hardcoded list from becoming stale when WINDOW_FUNC_MAPPING is updated. However, it's a moderate enhancement rather than a critical fix, as the current implementation is functional and the mapping is unlikely to change frequently.

Medium
Suggestions up to commit cf4cb1b
CategorySuggestion Impact
General
Verify row_number support in error message

The error message lists row_number as a supported function, but the grammar changes
in OpenSearchPPLParser.g4 removed RANK and DENSE_RANK from scalarWindowFunctionName,
leaving only ROW_NUMBER and other functions. Verify that row_number is actually
supported in eventstats/streamstats context, as the test changes suggest ranking
functions are now rejected at parse time.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " latest, max, min, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid concern about the consistency between the error message and grammar changes. However, examining the grammar file shows that ROW_NUMBER is still present in scalarWindowFunctionName, suggesting it remains supported. The suggestion asks for verification rather than identifying a definite error, and the existing_code matches the improved_code, indicating no concrete change is proposed.

Medium
Suggestions up to commit 99c53f5
CategorySuggestion Impact
General
Use String.format for error message

The error message concatenates multiple strings which can impact readability and
maintainability. Consider using String.format() or a text block for better
formatting and easier future modifications of the supported functions list.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
- "Window function '"- + funcName- + "' is not supported in eventstats/streamstats."- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ String.format(+ "Window function '%s' is not supported in eventstats/streamstats."+ + " Supported functions: avg, count, dc, distinct_count, earliest,"+ + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " var_pop, var_samp.",+ funcName));
Suggestion importance[1-10]: 4

__

Why: While using String.format() can improve readability, the current string concatenation approach is perfectly valid and readable. This is a minor style improvement that doesn't significantly impact code quality or functionality.

Low
Suggestions up to commit c16fc0c
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + "."));
Suggestion importance[1-10]: 7

__

Why: This suggestion improves maintainability by dynamically generating the list of supported functions from WINDOW_FUNC_MAPPING.keySet() instead of hardcoding them. This ensures the error message stays accurate when new functions are added, reducing maintenance burden and preventing outdated documentation.

Medium

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 99c53f5

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi, I'm trying to add support for rank and dense_rank function in Calcite for unified SQL for analytics engine. If we confirm both are not supported by PPL evenstats and streamstats, shall we remove them from PPL grammar directly? I assume that's the only place window function can be used. Otherwise it will be tricky to check language type in Calcite planner.

@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Good question — I dug into this a bit.

Your assumption holds for PPL specifically: in the PPL grammar, windowFunction (the parenthesized call syntax) is only ever invoked from eventstatsAggTerm/streamstatsAggTerm (OpenSearchPPLParser.g4:922-943), so that is the only place a window function can appear in PPL today.

But it's not the only place in the engine overall. SQL has its own windowFunctionClause/overClause grammar (OpenSearchSQLParser.g4:150-159) that already accepts RANK()/DENSE_RANK() in ... OVER (...). Both SQL and PPL build the same WindowFunction AST node and are resolved by the same CalciteRexNodeVisitor#visitWindowFunction — there's even a comment there noting "SQL emits AggregateFunction for aggregate-as-window (e.g., SUM(x) OVER); PPL emits Function." WINDOW_FUNC_MAPPING in BuiltinFunctionName (used by both paths) simply has no rank/dense_rank entries yet, so both languages fail identically right now.

Practical implication: if you add rank/dense_rank to WINDOW_FUNC_MAPPING and implement them in the shared visitor, that enables them for PPL eventstats/streamstats too, since the mapping/visitor is shared — not just SQL.

So yes, I think removing RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule (lines 933-934) is the right move, and it avoids the language-type check you were worried about: PPL's parser would reject the syntax before it ever reaches the AST/Calcite layer, while SQL's grammar (which already accepts it) passes through untouched. That pushes the language separation to parse time instead of planner time.

One side note on this PR itself: the new error message I added ("Window function 'x' is not supported in eventstats/streamstats") is thrown from that same shared visitor, so it would also currently fire — misleadingly — for a plain SQL RANK() OVER (...) query, since the check isn't actually PPL-specific. I may follow up with a tweak to make that message language-agnostic.

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna Thanks for digging in! I've put up PR #5720 for the SQL side. As you confirmed, removing them from grammar should make PPL reject at parse time and leaves my change SQL-only. With both PRs merged, I think we get the language separation at parse time rather than in the planner, which is where it belongs as expected. Thanks!

@dai-chendai-chen added enhancement New feature or request PPL Piped processing language labels Aug 26, 2026
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Nice, thanks for #5720. Pushed da13116 here: removed RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule, so eventstats rank()/streamstats dense_rank() now fail at parse time (SyntaxCheckException) instead of reaching the shared visitor.

Updated the tests this PR added for that case (testRankingWindowFunctionsUnsupportedInEventstats/...InStreamstats) to expect the parse-time rejection, and switched unsupportedWindowFunctionIsRethrownAsSemanticCheckException from rank() to percent_rank() since it needs a token that's still in the grammar but outside WINDOW_FUNC_MAPPING to exercise that path.

One caveat: I don't have a Java toolchain in my current environment, so I couldn't run generateGrammarSource/the actual test suite to confirm the exact ANTLR error message — the assertions only check for the generic "is not a valid term at this part of the query" substring rather than the full expected-tokens list, to stay robust either way, but it'd be good to have CI confirm this once it runs.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit da13116

…streamstats
Window functions outside WINDOW_FUNC_MAPPING (e.g. rank, dense_rank,
nth_value) throw a generic "Unexpected window function: X" from
CalciteRexNodeVisitor#visitWindowFunction. These functions require
ORDER BY semantics that eventstats/streamstats don't have (they only
support partition-by), so they are intentionally unsupported, not a
bug -- but the error message gave users no indication of what to use
instead.
Replace the message with one that names the function and lists the
functions eventstats/streamstats do support, so users get actionable
guidance instead of a bare "unexpected" error.
Fixesopensearch-project#5168
Signed-off-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
WINDOW_FUNC_MAPPING (used by eventstats/streamstats) never supported
rank/dense_rank, but PPL's scalarWindowFunctionName grammar rule still
accepted the tokens, so `eventstats rank()` reached
CalciteRexNodeVisitor#visitWindowFunction and failed there with the
"not supported" message this PR improves. Meanwhile SQL's grammar
already accepts RANK()/DENSE_RANK() OVER (...), and opensearch-project#5720 is adding
real support for them on the SQL side via the same shared visitor.
Remove RANK/DENSE_RANK from scalarWindowFunctionName so PPL rejects
them at parse time instead of falling through to the shared
SQL/PPL visitor - this keeps the language separation at the parser
rather than relying on a WINDOW_FUNC_MAPPING check in shared planner
code, and avoids PPL silently gaining rank/dense_rank as a side effect
of opensearch-project#5720 registering them for SQL.
Updates the eventstats/streamstats tests added earlier in this PR to
expect a SyntaxCheckException (parse-time) instead of the semantic
"not supported" error, and switches the unrelated
visitWindowFunction-rejection unit test from rank() to percent_rank(),
which remains unsupported and still exercises that code path.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna
gingeekrishnaforce-pushed the fix/5168-improve-unsupported-window-function-error branch from da13116 to cf4cb1bCompareAugust 30, 2026 05:23
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit cf4cb1b

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna My PR was already merged. You can rebase and verify yours by CI if you're unable locally. Btw, I recall changes in unsupportedWindowFunctionIsRethrownAsSemanticCheckException is already covered in my PR.

Comment on lines +816 to +818
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe revert this change because this list is dynamic and defined in grammar.

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor comment. Thanks for the changes!

@dai-chen

Copy link
Copy Markdown
Collaborator

I retried Linter CI but it still failed. Probably worth taking another look.

… time"
This reverts commit cf4cb1b.
The "PPL grammar compatibility" CI check failed after that commit:
[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/
eventstats-rank: expected 1, got 0
That check runs OpenSearch-Dashboards' own PPL linter (fetched via
`yarn osd bootstrap`) against this repo's grammar bundle, using test
cases from scripts/ppl-lint/grammar-cases.json. Its
"unsupported-window-function-in-eventstats" rule expects
`eventstats rank()` to parse successfully and then be flagged by a
semantic-layer diagnostic (giving IDE users a specific, friendly
error). Removing RANK/DENSE_RANK from the PPL grammar made the query
fail to parse at all, so that rule never gets a chance to run and the
diagnostic it's supposed to produce disappears - the ppl-lint test
expects the rule to fire (count 1) but the query now dies earlier with
a raw syntax error instead (count 0).
The rule implementation lives in OpenSearch-Dashboards, not this repo,
so fixing this properly would need a coordinated cross-repo change.
Reverting restores parsing (and the linter's diagnostic) while keeping
the actual point of this PR - the improved
"Window function 'x' is not supported in eventstats/streamstats"
message from CalciteRexNodeVisitor - fully intact, since that's a
semantic-layer check unaffected by this revert.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

Found it - pushed 58fda664f to fix it.

The failing check was the linter, specifically:

[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/eventstats-rank: expected 1, got 0

That's OpenSearch-Dashboards' own PPL linter (fetched via yarn osd bootstrap in that job) being run against this repo's grammar bundle, using the cases in scripts/ppl-lint/grammar-cases.json. Its unsupported-window-function-in-eventstats rule expects eventstats rank() to parse successfully and then get flagged by a semantic-layer diagnostic - that's how it surfaces a friendly, specific error in the IDE.

My earlier commit here (cf4cb1bd3, removing RANK/DENSE_RANK from the PPL grammar so eventstats rank() fails at parse time instead of reaching the shared visitor) broke exactly that: the query now dies with a raw syntax error before OSD's semantic rule ever gets a chance to run, so its diagnostic never fires. Since that rule lives in the OpenSearch-Dashboards repo, not here, fixing it properly would need a coordinated cross-repo change - out of scope for this PR.

Reverted that commit. This PR's actual point - the improved "Window function 'x' is not supported in eventstats/streamstats" message in CalciteRexNodeVisitor - is a semantic-layer check, so it's untouched by the revert and still works exactly as intended. The parse-time language-separation idea from our earlier discussion doesn't hold up against the existing linter contract, so I'm dropping it rather than pursuing it further here.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 58fda66

…layer
opensearch-project#5720 added rank/dense_rank to the WINDOW_FUNC_MAPPING shared by both
SQL's RANK()/DENSE_RANK() OVER (...) and PPL's eventstats/streamstats,
which silently enabled them for eventstats/streamstats too:
testRankingWindowFunctionsUnsupportedInEventstats/InStreamstats
(added earlier in this PR) started failing with "expected
ResponseException to be thrown, but nothing was thrown" once opensearch-project#5720
merged, since eventstats rank() now builds a real window call instead
of hitting the "not supported" check.
That's a real gap, not just a test artifact: PPL's eventstats/
streamstats grammar has no ORDER BY syntax at all, so ranking has no
defined ordering to rank by there - unlike SQL's OVER(), which at
least has (optional) ORDER BY in its own clause.
A prior commit on this branch tried fixing this by removing RANK/
DENSE_RANK from the PPL grammar entirely, rejecting them at parse
time. That broke a different, cross-repo contract: OpenSearch-
Dashboards' PPL linter (validated by the "PPL grammar compatibility"
CI check) expects `eventstats rank()` to parse successfully and be
flagged by a semantic-layer diagnostic instead, so it could no longer
produce that diagnostic once the query stopped parsing. That commit
was reverted.
Fix this at the semantic layer instead, where it belongs: PPL only
ever reaches CalciteRexNodeVisitor#visitWindowFunction through
eventstats/streamstats (no other PPL syntax builds a WindowFunction
node), so context.queryType == PPL is an exact, unambiguous signal for
"this is an eventstats/streamstats call". Filter rank/dense_rank out
of the WINDOW_FUNC_MAPPING lookup specifically when queryType is PPL,
so they fall through to the existing "not supported in eventstats/
streamstats" error - exactly the pre-opensearch-project#5720 behavior - while leaving
SQL's RANK()/DENSE_RANK() OVER (...) handling (and everything else)
completely untouched.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd3ca1c

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestPPLPiped processing language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] eventstats/streamstats reject window functions that grammar accepts

3 participants

@gingeekrishna@dai-chen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Improve error message for unsupported window functions in eventstats/streamstats - #5600

Open
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error
Open

Improve error message for unsupported window functions in eventstats/streamstats#5600
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error

Conversation

@gingeekrishna

Copy link
Copy Markdown
Contributor

Description

Fixes#5168

eventstats/streamstats reject window functions outside WINDOW_FUNC_MAPPING (e.g. rank(), dense_rank(), nth_value()) with a bare "Unexpected window function: X" error.

As confirmed in the issue discussion by @songkant-aws, this is expected behavior, not a bug — rank/dense_rank/nth_value require ORDER BY semantics, but eventstats/streamstats only support partition by. The issue was relabeled error-experience: the fix is to make the error message clearer, not to add support for these functions.

Changes

  • CalciteRexNodeVisitor#visitWindowFunction: replaced the generic "Unexpected window function: X" message with one that names the rejected function and lists the functions eventstats/streamstats do support (sourced from WINDOW_FUNC_MAPPING), so users get actionable guidance instead of a bare error.
  • Updated the existing unit test (UnifiedQueryPlannerTest) and integration tests (CalcitePPLEventstatsIT, CalciteStreamstatsCommandIT) to assert against the new message.
  • Added new integration tests covering rank/dense_rank specifically, since the issue's repro queries used those functions.

Note: this PR builds on top of #5587 (already merged), which fixed the same throw site to return a 4xx instead of a 500. This PR only changes the message text, not the exception type or HTTP status.

Test plan

  • Unit test UnifiedQueryPlannerTest#unsupportedWindowFunctionIsRethrownAsSemanticCheckException passes
  • Integration tests added/updated for eventstats and streamstats (require a live cluster to run in CI)

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dd3ca1c)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

Hardcoded list

The error message hardcodes the list of supported functions as a string literal. If WINDOW_FUNC_MAPPING changes (functions added or removed), this message will become stale and misleading. The list should be generated dynamically from WINDOW_FUNC_MAPPING to stay accurate.

+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Latest suggestions up to dd3ca1c

Explore these optional code suggestions:

CategorySuggestion Impact
Possible issue
Add null check for queryType

Add null check for context.queryType before comparison to prevent potential
NullPointerException. The context object might have a null queryType field in
certain scenarios, which would cause the filter predicate to fail.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [773-777]

 .filter(
functionName ->
- !(context.queryType == QueryType.PPL+ !(context.queryType != null+ && context.queryType == QueryType.PPL
&& (functionName == BuiltinFunctionName.RANK
|| functionName == BuiltinFunctionName.DENSE_RANK)))
Suggestion importance[1-10]: 5

__

Why: While adding a null check for context.queryType is a defensive programming practice, there's no evidence in the PR that queryType can be null. The suggestion is technically valid but may be unnecessary without context showing this is a real issue. This is a standard null-safety suggestion that doesn't address a demonstrated bug.

Low

Previous suggestions

Suggestions up to commit 58fda66
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + ".");
Suggestion importance[1-10]: 7

__

Why: This is a valid maintainability improvement that prevents the hardcoded list from becoming stale when WINDOW_FUNC_MAPPING is updated. However, it's a moderate enhancement rather than a critical fix, as the current implementation is functional and the mapping is unlikely to change frequently.

Medium
Suggestions up to commit cf4cb1b
CategorySuggestion Impact
General
Verify row_number support in error message

The error message lists row_number as a supported function, but the grammar changes
in OpenSearchPPLParser.g4 removed RANK and DENSE_RANK from scalarWindowFunctionName,
leaving only ROW_NUMBER and other functions. Verify that row_number is actually
supported in eventstats/streamstats context, as the test changes suggest ranking
functions are now rejected at parse time.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " latest, max, min, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid concern about the consistency between the error message and grammar changes. However, examining the grammar file shows that ROW_NUMBER is still present in scalarWindowFunctionName, suggesting it remains supported. The suggestion asks for verification rather than identifying a definite error, and the existing_code matches the improved_code, indicating no concrete change is proposed.

Medium
Suggestions up to commit 99c53f5
CategorySuggestion Impact
General
Use String.format for error message

The error message concatenates multiple strings which can impact readability and
maintainability. Consider using String.format() or a text block for better
formatting and easier future modifications of the supported functions list.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
- "Window function '"- + funcName- + "' is not supported in eventstats/streamstats."- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ String.format(+ "Window function '%s' is not supported in eventstats/streamstats."+ + " Supported functions: avg, count, dc, distinct_count, earliest,"+ + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " var_pop, var_samp.",+ funcName));
Suggestion importance[1-10]: 4

__

Why: While using String.format() can improve readability, the current string concatenation approach is perfectly valid and readable. This is a minor style improvement that doesn't significantly impact code quality or functionality.

Low
Suggestions up to commit c16fc0c
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + "."));
Suggestion importance[1-10]: 7

__

Why: This suggestion improves maintainability by dynamically generating the list of supported functions from WINDOW_FUNC_MAPPING.keySet() instead of hardcoding them. This ensures the error message stays accurate when new functions are added, reducing maintenance burden and preventing outdated documentation.

Medium

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 99c53f5

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi, I'm trying to add support for rank and dense_rank function in Calcite for unified SQL for analytics engine. If we confirm both are not supported by PPL evenstats and streamstats, shall we remove them from PPL grammar directly? I assume that's the only place window function can be used. Otherwise it will be tricky to check language type in Calcite planner.

@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Good question — I dug into this a bit.

Your assumption holds for PPL specifically: in the PPL grammar, windowFunction (the parenthesized call syntax) is only ever invoked from eventstatsAggTerm/streamstatsAggTerm (OpenSearchPPLParser.g4:922-943), so that is the only place a window function can appear in PPL today.

But it's not the only place in the engine overall. SQL has its own windowFunctionClause/overClause grammar (OpenSearchSQLParser.g4:150-159) that already accepts RANK()/DENSE_RANK() in ... OVER (...). Both SQL and PPL build the same WindowFunction AST node and are resolved by the same CalciteRexNodeVisitor#visitWindowFunction — there's even a comment there noting "SQL emits AggregateFunction for aggregate-as-window (e.g., SUM(x) OVER); PPL emits Function." WINDOW_FUNC_MAPPING in BuiltinFunctionName (used by both paths) simply has no rank/dense_rank entries yet, so both languages fail identically right now.

Practical implication: if you add rank/dense_rank to WINDOW_FUNC_MAPPING and implement them in the shared visitor, that enables them for PPL eventstats/streamstats too, since the mapping/visitor is shared — not just SQL.

So yes, I think removing RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule (lines 933-934) is the right move, and it avoids the language-type check you were worried about: PPL's parser would reject the syntax before it ever reaches the AST/Calcite layer, while SQL's grammar (which already accepts it) passes through untouched. That pushes the language separation to parse time instead of planner time.

One side note on this PR itself: the new error message I added ("Window function 'x' is not supported in eventstats/streamstats") is thrown from that same shared visitor, so it would also currently fire — misleadingly — for a plain SQL RANK() OVER (...) query, since the check isn't actually PPL-specific. I may follow up with a tweak to make that message language-agnostic.

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna Thanks for digging in! I've put up PR #5720 for the SQL side. As you confirmed, removing them from grammar should make PPL reject at parse time and leaves my change SQL-only. With both PRs merged, I think we get the language separation at parse time rather than in the planner, which is where it belongs as expected. Thanks!

@dai-chendai-chen added enhancement New feature or request PPL Piped processing language labels Aug 26, 2026
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Nice, thanks for #5720. Pushed da13116 here: removed RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule, so eventstats rank()/streamstats dense_rank() now fail at parse time (SyntaxCheckException) instead of reaching the shared visitor.

Updated the tests this PR added for that case (testRankingWindowFunctionsUnsupportedInEventstats/...InStreamstats) to expect the parse-time rejection, and switched unsupportedWindowFunctionIsRethrownAsSemanticCheckException from rank() to percent_rank() since it needs a token that's still in the grammar but outside WINDOW_FUNC_MAPPING to exercise that path.

One caveat: I don't have a Java toolchain in my current environment, so I couldn't run generateGrammarSource/the actual test suite to confirm the exact ANTLR error message — the assertions only check for the generic "is not a valid term at this part of the query" substring rather than the full expected-tokens list, to stay robust either way, but it'd be good to have CI confirm this once it runs.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit da13116

…streamstats
Window functions outside WINDOW_FUNC_MAPPING (e.g. rank, dense_rank,
nth_value) throw a generic "Unexpected window function: X" from
CalciteRexNodeVisitor#visitWindowFunction. These functions require
ORDER BY semantics that eventstats/streamstats don't have (they only
support partition-by), so they are intentionally unsupported, not a
bug -- but the error message gave users no indication of what to use
instead.
Replace the message with one that names the function and lists the
functions eventstats/streamstats do support, so users get actionable
guidance instead of a bare "unexpected" error.
Fixesopensearch-project#5168
Signed-off-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
WINDOW_FUNC_MAPPING (used by eventstats/streamstats) never supported
rank/dense_rank, but PPL's scalarWindowFunctionName grammar rule still
accepted the tokens, so `eventstats rank()` reached
CalciteRexNodeVisitor#visitWindowFunction and failed there with the
"not supported" message this PR improves. Meanwhile SQL's grammar
already accepts RANK()/DENSE_RANK() OVER (...), and opensearch-project#5720 is adding
real support for them on the SQL side via the same shared visitor.
Remove RANK/DENSE_RANK from scalarWindowFunctionName so PPL rejects
them at parse time instead of falling through to the shared
SQL/PPL visitor - this keeps the language separation at the parser
rather than relying on a WINDOW_FUNC_MAPPING check in shared planner
code, and avoids PPL silently gaining rank/dense_rank as a side effect
of opensearch-project#5720 registering them for SQL.
Updates the eventstats/streamstats tests added earlier in this PR to
expect a SyntaxCheckException (parse-time) instead of the semantic
"not supported" error, and switches the unrelated
visitWindowFunction-rejection unit test from rank() to percent_rank(),
which remains unsupported and still exercises that code path.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna
gingeekrishnaforce-pushed the fix/5168-improve-unsupported-window-function-error branch from da13116 to cf4cb1bCompareAugust 30, 2026 05:23
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit cf4cb1b

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna My PR was already merged. You can rebase and verify yours by CI if you're unable locally. Btw, I recall changes in unsupportedWindowFunctionIsRethrownAsSemanticCheckException is already covered in my PR.

Comment on lines +816 to +818
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe revert this change because this list is dynamic and defined in grammar.

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor comment. Thanks for the changes!

@dai-chen

Copy link
Copy Markdown
Collaborator

I retried Linter CI but it still failed. Probably worth taking another look.

… time"
This reverts commit cf4cb1b.
The "PPL grammar compatibility" CI check failed after that commit:
[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/
eventstats-rank: expected 1, got 0
That check runs OpenSearch-Dashboards' own PPL linter (fetched via
`yarn osd bootstrap`) against this repo's grammar bundle, using test
cases from scripts/ppl-lint/grammar-cases.json. Its
"unsupported-window-function-in-eventstats" rule expects
`eventstats rank()` to parse successfully and then be flagged by a
semantic-layer diagnostic (giving IDE users a specific, friendly
error). Removing RANK/DENSE_RANK from the PPL grammar made the query
fail to parse at all, so that rule never gets a chance to run and the
diagnostic it's supposed to produce disappears - the ppl-lint test
expects the rule to fire (count 1) but the query now dies earlier with
a raw syntax error instead (count 0).
The rule implementation lives in OpenSearch-Dashboards, not this repo,
so fixing this properly would need a coordinated cross-repo change.
Reverting restores parsing (and the linter's diagnostic) while keeping
the actual point of this PR - the improved
"Window function 'x' is not supported in eventstats/streamstats"
message from CalciteRexNodeVisitor - fully intact, since that's a
semantic-layer check unaffected by this revert.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

Found it - pushed 58fda664f to fix it.

The failing check was the linter, specifically:

[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/eventstats-rank: expected 1, got 0

That's OpenSearch-Dashboards' own PPL linter (fetched via yarn osd bootstrap in that job) being run against this repo's grammar bundle, using the cases in scripts/ppl-lint/grammar-cases.json. Its unsupported-window-function-in-eventstats rule expects eventstats rank() to parse successfully and then get flagged by a semantic-layer diagnostic - that's how it surfaces a friendly, specific error in the IDE.

My earlier commit here (cf4cb1bd3, removing RANK/DENSE_RANK from the PPL grammar so eventstats rank() fails at parse time instead of reaching the shared visitor) broke exactly that: the query now dies with a raw syntax error before OSD's semantic rule ever gets a chance to run, so its diagnostic never fires. Since that rule lives in the OpenSearch-Dashboards repo, not here, fixing it properly would need a coordinated cross-repo change - out of scope for this PR.

Reverted that commit. This PR's actual point - the improved "Window function 'x' is not supported in eventstats/streamstats" message in CalciteRexNodeVisitor - is a semantic-layer check, so it's untouched by the revert and still works exactly as intended. The parse-time language-separation idea from our earlier discussion doesn't hold up against the existing linter contract, so I'm dropping it rather than pursuing it further here.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 58fda66

…layer
opensearch-project#5720 added rank/dense_rank to the WINDOW_FUNC_MAPPING shared by both
SQL's RANK()/DENSE_RANK() OVER (...) and PPL's eventstats/streamstats,
which silently enabled them for eventstats/streamstats too:
testRankingWindowFunctionsUnsupportedInEventstats/InStreamstats
(added earlier in this PR) started failing with "expected
ResponseException to be thrown, but nothing was thrown" once opensearch-project#5720
merged, since eventstats rank() now builds a real window call instead
of hitting the "not supported" check.
That's a real gap, not just a test artifact: PPL's eventstats/
streamstats grammar has no ORDER BY syntax at all, so ranking has no
defined ordering to rank by there - unlike SQL's OVER(), which at
least has (optional) ORDER BY in its own clause.
A prior commit on this branch tried fixing this by removing RANK/
DENSE_RANK from the PPL grammar entirely, rejecting them at parse
time. That broke a different, cross-repo contract: OpenSearch-
Dashboards' PPL linter (validated by the "PPL grammar compatibility"
CI check) expects `eventstats rank()` to parse successfully and be
flagged by a semantic-layer diagnostic instead, so it could no longer
produce that diagnostic once the query stopped parsing. That commit
was reverted.
Fix this at the semantic layer instead, where it belongs: PPL only
ever reaches CalciteRexNodeVisitor#visitWindowFunction through
eventstats/streamstats (no other PPL syntax builds a WindowFunction
node), so context.queryType == PPL is an exact, unambiguous signal for
"this is an eventstats/streamstats call". Filter rank/dense_rank out
of the WINDOW_FUNC_MAPPING lookup specifically when queryType is PPL,
so they fall through to the existing "not supported in eventstats/
streamstats" error - exactly the pre-opensearch-project#5720 behavior - while leaving
SQL's RANK()/DENSE_RANK() OVER (...) handling (and everything else)
completely untouched.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd3ca1c

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestPPLPiped processing language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] eventstats/streamstats reject window functions that grammar accepts

3 participants

@gingeekrishna@dai-chen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Improve error message for unsupported window functions in eventstats/streamstats - #5600

Open
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error
Open

Improve error message for unsupported window functions in eventstats/streamstats#5600
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error

Conversation

@gingeekrishna

Copy link
Copy Markdown
Contributor

Description

Fixes#5168

eventstats/streamstats reject window functions outside WINDOW_FUNC_MAPPING (e.g. rank(), dense_rank(), nth_value()) with a bare "Unexpected window function: X" error.

As confirmed in the issue discussion by @songkant-aws, this is expected behavior, not a bug — rank/dense_rank/nth_value require ORDER BY semantics, but eventstats/streamstats only support partition by. The issue was relabeled error-experience: the fix is to make the error message clearer, not to add support for these functions.

Changes

  • CalciteRexNodeVisitor#visitWindowFunction: replaced the generic "Unexpected window function: X" message with one that names the rejected function and lists the functions eventstats/streamstats do support (sourced from WINDOW_FUNC_MAPPING), so users get actionable guidance instead of a bare error.
  • Updated the existing unit test (UnifiedQueryPlannerTest) and integration tests (CalcitePPLEventstatsIT, CalciteStreamstatsCommandIT) to assert against the new message.
  • Added new integration tests covering rank/dense_rank specifically, since the issue's repro queries used those functions.

Note: this PR builds on top of #5587 (already merged), which fixed the same throw site to return a 4xx instead of a 500. This PR only changes the message text, not the exception type or HTTP status.

Test plan

  • Unit test UnifiedQueryPlannerTest#unsupportedWindowFunctionIsRethrownAsSemanticCheckException passes
  • Integration tests added/updated for eventstats and streamstats (require a live cluster to run in CI)

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dd3ca1c)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

Hardcoded list

The error message hardcodes the list of supported functions as a string literal. If WINDOW_FUNC_MAPPING changes (functions added or removed), this message will become stale and misleading. The list should be generated dynamically from WINDOW_FUNC_MAPPING to stay accurate.

+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Latest suggestions up to dd3ca1c

Explore these optional code suggestions:

CategorySuggestion Impact
Possible issue
Add null check for queryType

Add null check for context.queryType before comparison to prevent potential
NullPointerException. The context object might have a null queryType field in
certain scenarios, which would cause the filter predicate to fail.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [773-777]

 .filter(
functionName ->
- !(context.queryType == QueryType.PPL+ !(context.queryType != null+ && context.queryType == QueryType.PPL
&& (functionName == BuiltinFunctionName.RANK
|| functionName == BuiltinFunctionName.DENSE_RANK)))
Suggestion importance[1-10]: 5

__

Why: While adding a null check for context.queryType is a defensive programming practice, there's no evidence in the PR that queryType can be null. The suggestion is technically valid but may be unnecessary without context showing this is a real issue. This is a standard null-safety suggestion that doesn't address a demonstrated bug.

Low

Previous suggestions

Suggestions up to commit 58fda66
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + ".");
Suggestion importance[1-10]: 7

__

Why: This is a valid maintainability improvement that prevents the hardcoded list from becoming stale when WINDOW_FUNC_MAPPING is updated. However, it's a moderate enhancement rather than a critical fix, as the current implementation is functional and the mapping is unlikely to change frequently.

Medium
Suggestions up to commit cf4cb1b
CategorySuggestion Impact
General
Verify row_number support in error message

The error message lists row_number as a supported function, but the grammar changes
in OpenSearchPPLParser.g4 removed RANK and DENSE_RANK from scalarWindowFunctionName,
leaving only ROW_NUMBER and other functions. Verify that row_number is actually
supported in eventstats/streamstats context, as the test changes suggest ranking
functions are now rejected at parse time.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " latest, max, min, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid concern about the consistency between the error message and grammar changes. However, examining the grammar file shows that ROW_NUMBER is still present in scalarWindowFunctionName, suggesting it remains supported. The suggestion asks for verification rather than identifying a definite error, and the existing_code matches the improved_code, indicating no concrete change is proposed.

Medium
Suggestions up to commit 99c53f5
CategorySuggestion Impact
General
Use String.format for error message

The error message concatenates multiple strings which can impact readability and
maintainability. Consider using String.format() or a text block for better
formatting and easier future modifications of the supported functions list.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
- "Window function '"- + funcName- + "' is not supported in eventstats/streamstats."- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ String.format(+ "Window function '%s' is not supported in eventstats/streamstats."+ + " Supported functions: avg, count, dc, distinct_count, earliest,"+ + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " var_pop, var_samp.",+ funcName));
Suggestion importance[1-10]: 4

__

Why: While using String.format() can improve readability, the current string concatenation approach is perfectly valid and readable. This is a minor style improvement that doesn't significantly impact code quality or functionality.

Low
Suggestions up to commit c16fc0c
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + "."));
Suggestion importance[1-10]: 7

__

Why: This suggestion improves maintainability by dynamically generating the list of supported functions from WINDOW_FUNC_MAPPING.keySet() instead of hardcoding them. This ensures the error message stays accurate when new functions are added, reducing maintenance burden and preventing outdated documentation.

Medium

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 99c53f5

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi, I'm trying to add support for rank and dense_rank function in Calcite for unified SQL for analytics engine. If we confirm both are not supported by PPL evenstats and streamstats, shall we remove them from PPL grammar directly? I assume that's the only place window function can be used. Otherwise it will be tricky to check language type in Calcite planner.

@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Good question — I dug into this a bit.

Your assumption holds for PPL specifically: in the PPL grammar, windowFunction (the parenthesized call syntax) is only ever invoked from eventstatsAggTerm/streamstatsAggTerm (OpenSearchPPLParser.g4:922-943), so that is the only place a window function can appear in PPL today.

But it's not the only place in the engine overall. SQL has its own windowFunctionClause/overClause grammar (OpenSearchSQLParser.g4:150-159) that already accepts RANK()/DENSE_RANK() in ... OVER (...). Both SQL and PPL build the same WindowFunction AST node and are resolved by the same CalciteRexNodeVisitor#visitWindowFunction — there's even a comment there noting "SQL emits AggregateFunction for aggregate-as-window (e.g., SUM(x) OVER); PPL emits Function." WINDOW_FUNC_MAPPING in BuiltinFunctionName (used by both paths) simply has no rank/dense_rank entries yet, so both languages fail identically right now.

Practical implication: if you add rank/dense_rank to WINDOW_FUNC_MAPPING and implement them in the shared visitor, that enables them for PPL eventstats/streamstats too, since the mapping/visitor is shared — not just SQL.

So yes, I think removing RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule (lines 933-934) is the right move, and it avoids the language-type check you were worried about: PPL's parser would reject the syntax before it ever reaches the AST/Calcite layer, while SQL's grammar (which already accepts it) passes through untouched. That pushes the language separation to parse time instead of planner time.

One side note on this PR itself: the new error message I added ("Window function 'x' is not supported in eventstats/streamstats") is thrown from that same shared visitor, so it would also currently fire — misleadingly — for a plain SQL RANK() OVER (...) query, since the check isn't actually PPL-specific. I may follow up with a tweak to make that message language-agnostic.

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna Thanks for digging in! I've put up PR #5720 for the SQL side. As you confirmed, removing them from grammar should make PPL reject at parse time and leaves my change SQL-only. With both PRs merged, I think we get the language separation at parse time rather than in the planner, which is where it belongs as expected. Thanks!

@dai-chendai-chen added enhancement New feature or request PPL Piped processing language labels Aug 26, 2026
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Nice, thanks for #5720. Pushed da13116 here: removed RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule, so eventstats rank()/streamstats dense_rank() now fail at parse time (SyntaxCheckException) instead of reaching the shared visitor.

Updated the tests this PR added for that case (testRankingWindowFunctionsUnsupportedInEventstats/...InStreamstats) to expect the parse-time rejection, and switched unsupportedWindowFunctionIsRethrownAsSemanticCheckException from rank() to percent_rank() since it needs a token that's still in the grammar but outside WINDOW_FUNC_MAPPING to exercise that path.

One caveat: I don't have a Java toolchain in my current environment, so I couldn't run generateGrammarSource/the actual test suite to confirm the exact ANTLR error message — the assertions only check for the generic "is not a valid term at this part of the query" substring rather than the full expected-tokens list, to stay robust either way, but it'd be good to have CI confirm this once it runs.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit da13116

…streamstats
Window functions outside WINDOW_FUNC_MAPPING (e.g. rank, dense_rank,
nth_value) throw a generic "Unexpected window function: X" from
CalciteRexNodeVisitor#visitWindowFunction. These functions require
ORDER BY semantics that eventstats/streamstats don't have (they only
support partition-by), so they are intentionally unsupported, not a
bug -- but the error message gave users no indication of what to use
instead.
Replace the message with one that names the function and lists the
functions eventstats/streamstats do support, so users get actionable
guidance instead of a bare "unexpected" error.
Fixesopensearch-project#5168
Signed-off-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
WINDOW_FUNC_MAPPING (used by eventstats/streamstats) never supported
rank/dense_rank, but PPL's scalarWindowFunctionName grammar rule still
accepted the tokens, so `eventstats rank()` reached
CalciteRexNodeVisitor#visitWindowFunction and failed there with the
"not supported" message this PR improves. Meanwhile SQL's grammar
already accepts RANK()/DENSE_RANK() OVER (...), and opensearch-project#5720 is adding
real support for them on the SQL side via the same shared visitor.
Remove RANK/DENSE_RANK from scalarWindowFunctionName so PPL rejects
them at parse time instead of falling through to the shared
SQL/PPL visitor - this keeps the language separation at the parser
rather than relying on a WINDOW_FUNC_MAPPING check in shared planner
code, and avoids PPL silently gaining rank/dense_rank as a side effect
of opensearch-project#5720 registering them for SQL.
Updates the eventstats/streamstats tests added earlier in this PR to
expect a SyntaxCheckException (parse-time) instead of the semantic
"not supported" error, and switches the unrelated
visitWindowFunction-rejection unit test from rank() to percent_rank(),
which remains unsupported and still exercises that code path.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna
gingeekrishnaforce-pushed the fix/5168-improve-unsupported-window-function-error branch from da13116 to cf4cb1bCompareAugust 30, 2026 05:23
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit cf4cb1b

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna My PR was already merged. You can rebase and verify yours by CI if you're unable locally. Btw, I recall changes in unsupportedWindowFunctionIsRethrownAsSemanticCheckException is already covered in my PR.

Comment on lines +816 to +818
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe revert this change because this list is dynamic and defined in grammar.

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor comment. Thanks for the changes!

@dai-chen

Copy link
Copy Markdown
Collaborator

I retried Linter CI but it still failed. Probably worth taking another look.

… time"
This reverts commit cf4cb1b.
The "PPL grammar compatibility" CI check failed after that commit:
[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/
eventstats-rank: expected 1, got 0
That check runs OpenSearch-Dashboards' own PPL linter (fetched via
`yarn osd bootstrap`) against this repo's grammar bundle, using test
cases from scripts/ppl-lint/grammar-cases.json. Its
"unsupported-window-function-in-eventstats" rule expects
`eventstats rank()` to parse successfully and then be flagged by a
semantic-layer diagnostic (giving IDE users a specific, friendly
error). Removing RANK/DENSE_RANK from the PPL grammar made the query
fail to parse at all, so that rule never gets a chance to run and the
diagnostic it's supposed to produce disappears - the ppl-lint test
expects the rule to fire (count 1) but the query now dies earlier with
a raw syntax error instead (count 0).
The rule implementation lives in OpenSearch-Dashboards, not this repo,
so fixing this properly would need a coordinated cross-repo change.
Reverting restores parsing (and the linter's diagnostic) while keeping
the actual point of this PR - the improved
"Window function 'x' is not supported in eventstats/streamstats"
message from CalciteRexNodeVisitor - fully intact, since that's a
semantic-layer check unaffected by this revert.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

Found it - pushed 58fda664f to fix it.

The failing check was the linter, specifically:

[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/eventstats-rank: expected 1, got 0

That's OpenSearch-Dashboards' own PPL linter (fetched via yarn osd bootstrap in that job) being run against this repo's grammar bundle, using the cases in scripts/ppl-lint/grammar-cases.json. Its unsupported-window-function-in-eventstats rule expects eventstats rank() to parse successfully and then get flagged by a semantic-layer diagnostic - that's how it surfaces a friendly, specific error in the IDE.

My earlier commit here (cf4cb1bd3, removing RANK/DENSE_RANK from the PPL grammar so eventstats rank() fails at parse time instead of reaching the shared visitor) broke exactly that: the query now dies with a raw syntax error before OSD's semantic rule ever gets a chance to run, so its diagnostic never fires. Since that rule lives in the OpenSearch-Dashboards repo, not here, fixing it properly would need a coordinated cross-repo change - out of scope for this PR.

Reverted that commit. This PR's actual point - the improved "Window function 'x' is not supported in eventstats/streamstats" message in CalciteRexNodeVisitor - is a semantic-layer check, so it's untouched by the revert and still works exactly as intended. The parse-time language-separation idea from our earlier discussion doesn't hold up against the existing linter contract, so I'm dropping it rather than pursuing it further here.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 58fda66

…layer
opensearch-project#5720 added rank/dense_rank to the WINDOW_FUNC_MAPPING shared by both
SQL's RANK()/DENSE_RANK() OVER (...) and PPL's eventstats/streamstats,
which silently enabled them for eventstats/streamstats too:
testRankingWindowFunctionsUnsupportedInEventstats/InStreamstats
(added earlier in this PR) started failing with "expected
ResponseException to be thrown, but nothing was thrown" once opensearch-project#5720
merged, since eventstats rank() now builds a real window call instead
of hitting the "not supported" check.
That's a real gap, not just a test artifact: PPL's eventstats/
streamstats grammar has no ORDER BY syntax at all, so ranking has no
defined ordering to rank by there - unlike SQL's OVER(), which at
least has (optional) ORDER BY in its own clause.
A prior commit on this branch tried fixing this by removing RANK/
DENSE_RANK from the PPL grammar entirely, rejecting them at parse
time. That broke a different, cross-repo contract: OpenSearch-
Dashboards' PPL linter (validated by the "PPL grammar compatibility"
CI check) expects `eventstats rank()` to parse successfully and be
flagged by a semantic-layer diagnostic instead, so it could no longer
produce that diagnostic once the query stopped parsing. That commit
was reverted.
Fix this at the semantic layer instead, where it belongs: PPL only
ever reaches CalciteRexNodeVisitor#visitWindowFunction through
eventstats/streamstats (no other PPL syntax builds a WindowFunction
node), so context.queryType == PPL is an exact, unambiguous signal for
"this is an eventstats/streamstats call". Filter rank/dense_rank out
of the WINDOW_FUNC_MAPPING lookup specifically when queryType is PPL,
so they fall through to the existing "not supported in eventstats/
streamstats" error - exactly the pre-opensearch-project#5720 behavior - while leaving
SQL's RANK()/DENSE_RANK() OVER (...) handling (and everything else)
completely untouched.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd3ca1c

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestPPLPiped processing language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] eventstats/streamstats reject window functions that grammar accepts

3 participants

@gingeekrishna@dai-chen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Improve error message for unsupported window functions in eventstats/streamstats - #5600

Open
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error
Open

Improve error message for unsupported window functions in eventstats/streamstats#5600
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error

Conversation

@gingeekrishna

Copy link
Copy Markdown
Contributor

Description

Fixes#5168

eventstats/streamstats reject window functions outside WINDOW_FUNC_MAPPING (e.g. rank(), dense_rank(), nth_value()) with a bare "Unexpected window function: X" error.

As confirmed in the issue discussion by @songkant-aws, this is expected behavior, not a bug — rank/dense_rank/nth_value require ORDER BY semantics, but eventstats/streamstats only support partition by. The issue was relabeled error-experience: the fix is to make the error message clearer, not to add support for these functions.

Changes

  • CalciteRexNodeVisitor#visitWindowFunction: replaced the generic "Unexpected window function: X" message with one that names the rejected function and lists the functions eventstats/streamstats do support (sourced from WINDOW_FUNC_MAPPING), so users get actionable guidance instead of a bare error.
  • Updated the existing unit test (UnifiedQueryPlannerTest) and integration tests (CalcitePPLEventstatsIT, CalciteStreamstatsCommandIT) to assert against the new message.
  • Added new integration tests covering rank/dense_rank specifically, since the issue's repro queries used those functions.

Note: this PR builds on top of #5587 (already merged), which fixed the same throw site to return a 4xx instead of a 500. This PR only changes the message text, not the exception type or HTTP status.

Test plan

  • Unit test UnifiedQueryPlannerTest#unsupportedWindowFunctionIsRethrownAsSemanticCheckException passes
  • Integration tests added/updated for eventstats and streamstats (require a live cluster to run in CI)

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dd3ca1c)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

Hardcoded list

The error message hardcodes the list of supported functions as a string literal. If WINDOW_FUNC_MAPPING changes (functions added or removed), this message will become stale and misleading. The list should be generated dynamically from WINDOW_FUNC_MAPPING to stay accurate.

+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Latest suggestions up to dd3ca1c

Explore these optional code suggestions:

CategorySuggestion Impact
Possible issue
Add null check for queryType

Add null check for context.queryType before comparison to prevent potential
NullPointerException. The context object might have a null queryType field in
certain scenarios, which would cause the filter predicate to fail.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [773-777]

 .filter(
functionName ->
- !(context.queryType == QueryType.PPL+ !(context.queryType != null+ && context.queryType == QueryType.PPL
&& (functionName == BuiltinFunctionName.RANK
|| functionName == BuiltinFunctionName.DENSE_RANK)))
Suggestion importance[1-10]: 5

__

Why: While adding a null check for context.queryType is a defensive programming practice, there's no evidence in the PR that queryType can be null. The suggestion is technically valid but may be unnecessary without context showing this is a real issue. This is a standard null-safety suggestion that doesn't address a demonstrated bug.

Low

Previous suggestions

Suggestions up to commit 58fda66
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + ".");
Suggestion importance[1-10]: 7

__

Why: This is a valid maintainability improvement that prevents the hardcoded list from becoming stale when WINDOW_FUNC_MAPPING is updated. However, it's a moderate enhancement rather than a critical fix, as the current implementation is functional and the mapping is unlikely to change frequently.

Medium
Suggestions up to commit cf4cb1b
CategorySuggestion Impact
General
Verify row_number support in error message

The error message lists row_number as a supported function, but the grammar changes
in OpenSearchPPLParser.g4 removed RANK and DENSE_RANK from scalarWindowFunctionName,
leaving only ROW_NUMBER and other functions. Verify that row_number is actually
supported in eventstats/streamstats context, as the test changes suggest ranking
functions are now rejected at parse time.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " latest, max, min, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid concern about the consistency between the error message and grammar changes. However, examining the grammar file shows that ROW_NUMBER is still present in scalarWindowFunctionName, suggesting it remains supported. The suggestion asks for verification rather than identifying a definite error, and the existing_code matches the improved_code, indicating no concrete change is proposed.

Medium
Suggestions up to commit 99c53f5
CategorySuggestion Impact
General
Use String.format for error message

The error message concatenates multiple strings which can impact readability and
maintainability. Consider using String.format() or a text block for better
formatting and easier future modifications of the supported functions list.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
- "Window function '"- + funcName- + "' is not supported in eventstats/streamstats."- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ String.format(+ "Window function '%s' is not supported in eventstats/streamstats."+ + " Supported functions: avg, count, dc, distinct_count, earliest,"+ + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " var_pop, var_samp.",+ funcName));
Suggestion importance[1-10]: 4

__

Why: While using String.format() can improve readability, the current string concatenation approach is perfectly valid and readable. This is a minor style improvement that doesn't significantly impact code quality or functionality.

Low
Suggestions up to commit c16fc0c
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + "."));
Suggestion importance[1-10]: 7

__

Why: This suggestion improves maintainability by dynamically generating the list of supported functions from WINDOW_FUNC_MAPPING.keySet() instead of hardcoding them. This ensures the error message stays accurate when new functions are added, reducing maintenance burden and preventing outdated documentation.

Medium

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 99c53f5

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi, I'm trying to add support for rank and dense_rank function in Calcite for unified SQL for analytics engine. If we confirm both are not supported by PPL evenstats and streamstats, shall we remove them from PPL grammar directly? I assume that's the only place window function can be used. Otherwise it will be tricky to check language type in Calcite planner.

@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Good question — I dug into this a bit.

Your assumption holds for PPL specifically: in the PPL grammar, windowFunction (the parenthesized call syntax) is only ever invoked from eventstatsAggTerm/streamstatsAggTerm (OpenSearchPPLParser.g4:922-943), so that is the only place a window function can appear in PPL today.

But it's not the only place in the engine overall. SQL has its own windowFunctionClause/overClause grammar (OpenSearchSQLParser.g4:150-159) that already accepts RANK()/DENSE_RANK() in ... OVER (...). Both SQL and PPL build the same WindowFunction AST node and are resolved by the same CalciteRexNodeVisitor#visitWindowFunction — there's even a comment there noting "SQL emits AggregateFunction for aggregate-as-window (e.g., SUM(x) OVER); PPL emits Function." WINDOW_FUNC_MAPPING in BuiltinFunctionName (used by both paths) simply has no rank/dense_rank entries yet, so both languages fail identically right now.

Practical implication: if you add rank/dense_rank to WINDOW_FUNC_MAPPING and implement them in the shared visitor, that enables them for PPL eventstats/streamstats too, since the mapping/visitor is shared — not just SQL.

So yes, I think removing RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule (lines 933-934) is the right move, and it avoids the language-type check you were worried about: PPL's parser would reject the syntax before it ever reaches the AST/Calcite layer, while SQL's grammar (which already accepts it) passes through untouched. That pushes the language separation to parse time instead of planner time.

One side note on this PR itself: the new error message I added ("Window function 'x' is not supported in eventstats/streamstats") is thrown from that same shared visitor, so it would also currently fire — misleadingly — for a plain SQL RANK() OVER (...) query, since the check isn't actually PPL-specific. I may follow up with a tweak to make that message language-agnostic.

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna Thanks for digging in! I've put up PR #5720 for the SQL side. As you confirmed, removing them from grammar should make PPL reject at parse time and leaves my change SQL-only. With both PRs merged, I think we get the language separation at parse time rather than in the planner, which is where it belongs as expected. Thanks!

@dai-chendai-chen added enhancement New feature or request PPL Piped processing language labels Aug 26, 2026
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Nice, thanks for #5720. Pushed da13116 here: removed RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule, so eventstats rank()/streamstats dense_rank() now fail at parse time (SyntaxCheckException) instead of reaching the shared visitor.

Updated the tests this PR added for that case (testRankingWindowFunctionsUnsupportedInEventstats/...InStreamstats) to expect the parse-time rejection, and switched unsupportedWindowFunctionIsRethrownAsSemanticCheckException from rank() to percent_rank() since it needs a token that's still in the grammar but outside WINDOW_FUNC_MAPPING to exercise that path.

One caveat: I don't have a Java toolchain in my current environment, so I couldn't run generateGrammarSource/the actual test suite to confirm the exact ANTLR error message — the assertions only check for the generic "is not a valid term at this part of the query" substring rather than the full expected-tokens list, to stay robust either way, but it'd be good to have CI confirm this once it runs.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit da13116

…streamstats
Window functions outside WINDOW_FUNC_MAPPING (e.g. rank, dense_rank,
nth_value) throw a generic "Unexpected window function: X" from
CalciteRexNodeVisitor#visitWindowFunction. These functions require
ORDER BY semantics that eventstats/streamstats don't have (they only
support partition-by), so they are intentionally unsupported, not a
bug -- but the error message gave users no indication of what to use
instead.
Replace the message with one that names the function and lists the
functions eventstats/streamstats do support, so users get actionable
guidance instead of a bare "unexpected" error.
Fixesopensearch-project#5168
Signed-off-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
WINDOW_FUNC_MAPPING (used by eventstats/streamstats) never supported
rank/dense_rank, but PPL's scalarWindowFunctionName grammar rule still
accepted the tokens, so `eventstats rank()` reached
CalciteRexNodeVisitor#visitWindowFunction and failed there with the
"not supported" message this PR improves. Meanwhile SQL's grammar
already accepts RANK()/DENSE_RANK() OVER (...), and opensearch-project#5720 is adding
real support for them on the SQL side via the same shared visitor.
Remove RANK/DENSE_RANK from scalarWindowFunctionName so PPL rejects
them at parse time instead of falling through to the shared
SQL/PPL visitor - this keeps the language separation at the parser
rather than relying on a WINDOW_FUNC_MAPPING check in shared planner
code, and avoids PPL silently gaining rank/dense_rank as a side effect
of opensearch-project#5720 registering them for SQL.
Updates the eventstats/streamstats tests added earlier in this PR to
expect a SyntaxCheckException (parse-time) instead of the semantic
"not supported" error, and switches the unrelated
visitWindowFunction-rejection unit test from rank() to percent_rank(),
which remains unsupported and still exercises that code path.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna
gingeekrishnaforce-pushed the fix/5168-improve-unsupported-window-function-error branch from da13116 to cf4cb1bCompareAugust 30, 2026 05:23
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit cf4cb1b

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna My PR was already merged. You can rebase and verify yours by CI if you're unable locally. Btw, I recall changes in unsupportedWindowFunctionIsRethrownAsSemanticCheckException is already covered in my PR.

Comment on lines +816 to +818
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe revert this change because this list is dynamic and defined in grammar.

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor comment. Thanks for the changes!

@dai-chen

Copy link
Copy Markdown
Collaborator

I retried Linter CI but it still failed. Probably worth taking another look.

… time"
This reverts commit cf4cb1b.
The "PPL grammar compatibility" CI check failed after that commit:
[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/
eventstats-rank: expected 1, got 0
That check runs OpenSearch-Dashboards' own PPL linter (fetched via
`yarn osd bootstrap`) against this repo's grammar bundle, using test
cases from scripts/ppl-lint/grammar-cases.json. Its
"unsupported-window-function-in-eventstats" rule expects
`eventstats rank()` to parse successfully and then be flagged by a
semantic-layer diagnostic (giving IDE users a specific, friendly
error). Removing RANK/DENSE_RANK from the PPL grammar made the query
fail to parse at all, so that rule never gets a chance to run and the
diagnostic it's supposed to produce disappears - the ppl-lint test
expects the rule to fire (count 1) but the query now dies earlier with
a raw syntax error instead (count 0).
The rule implementation lives in OpenSearch-Dashboards, not this repo,
so fixing this properly would need a coordinated cross-repo change.
Reverting restores parsing (and the linter's diagnostic) while keeping
the actual point of this PR - the improved
"Window function 'x' is not supported in eventstats/streamstats"
message from CalciteRexNodeVisitor - fully intact, since that's a
semantic-layer check unaffected by this revert.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

Found it - pushed 58fda664f to fix it.

The failing check was the linter, specifically:

[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/eventstats-rank: expected 1, got 0

That's OpenSearch-Dashboards' own PPL linter (fetched via yarn osd bootstrap in that job) being run against this repo's grammar bundle, using the cases in scripts/ppl-lint/grammar-cases.json. Its unsupported-window-function-in-eventstats rule expects eventstats rank() to parse successfully and then get flagged by a semantic-layer diagnostic - that's how it surfaces a friendly, specific error in the IDE.

My earlier commit here (cf4cb1bd3, removing RANK/DENSE_RANK from the PPL grammar so eventstats rank() fails at parse time instead of reaching the shared visitor) broke exactly that: the query now dies with a raw syntax error before OSD's semantic rule ever gets a chance to run, so its diagnostic never fires. Since that rule lives in the OpenSearch-Dashboards repo, not here, fixing it properly would need a coordinated cross-repo change - out of scope for this PR.

Reverted that commit. This PR's actual point - the improved "Window function 'x' is not supported in eventstats/streamstats" message in CalciteRexNodeVisitor - is a semantic-layer check, so it's untouched by the revert and still works exactly as intended. The parse-time language-separation idea from our earlier discussion doesn't hold up against the existing linter contract, so I'm dropping it rather than pursuing it further here.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 58fda66

…layer
opensearch-project#5720 added rank/dense_rank to the WINDOW_FUNC_MAPPING shared by both
SQL's RANK()/DENSE_RANK() OVER (...) and PPL's eventstats/streamstats,
which silently enabled them for eventstats/streamstats too:
testRankingWindowFunctionsUnsupportedInEventstats/InStreamstats
(added earlier in this PR) started failing with "expected
ResponseException to be thrown, but nothing was thrown" once opensearch-project#5720
merged, since eventstats rank() now builds a real window call instead
of hitting the "not supported" check.
That's a real gap, not just a test artifact: PPL's eventstats/
streamstats grammar has no ORDER BY syntax at all, so ranking has no
defined ordering to rank by there - unlike SQL's OVER(), which at
least has (optional) ORDER BY in its own clause.
A prior commit on this branch tried fixing this by removing RANK/
DENSE_RANK from the PPL grammar entirely, rejecting them at parse
time. That broke a different, cross-repo contract: OpenSearch-
Dashboards' PPL linter (validated by the "PPL grammar compatibility"
CI check) expects `eventstats rank()` to parse successfully and be
flagged by a semantic-layer diagnostic instead, so it could no longer
produce that diagnostic once the query stopped parsing. That commit
was reverted.
Fix this at the semantic layer instead, where it belongs: PPL only
ever reaches CalciteRexNodeVisitor#visitWindowFunction through
eventstats/streamstats (no other PPL syntax builds a WindowFunction
node), so context.queryType == PPL is an exact, unambiguous signal for
"this is an eventstats/streamstats call". Filter rank/dense_rank out
of the WINDOW_FUNC_MAPPING lookup specifically when queryType is PPL,
so they fall through to the existing "not supported in eventstats/
streamstats" error - exactly the pre-opensearch-project#5720 behavior - while leaving
SQL's RANK()/DENSE_RANK() OVER (...) handling (and everything else)
completely untouched.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd3ca1c

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestPPLPiped processing language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] eventstats/streamstats reject window functions that grammar accepts

3 participants

@gingeekrishna@dai-chen
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Improve error message for unsupported window functions in eventstats/streamstats - #5600

Open
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error
Open

Improve error message for unsupported window functions in eventstats/streamstats#5600
gingeekrishna wants to merge 4 commits into
opensearch-project:mainfrom
gingeekrishna:fix/5168-improve-unsupported-window-function-error

Conversation

@gingeekrishna

Copy link
Copy Markdown
Contributor

Description

Fixes#5168

eventstats/streamstats reject window functions outside WINDOW_FUNC_MAPPING (e.g. rank(), dense_rank(), nth_value()) with a bare "Unexpected window function: X" error.

As confirmed in the issue discussion by @songkant-aws, this is expected behavior, not a bug — rank/dense_rank/nth_value require ORDER BY semantics, but eventstats/streamstats only support partition by. The issue was relabeled error-experience: the fix is to make the error message clearer, not to add support for these functions.

Changes

  • CalciteRexNodeVisitor#visitWindowFunction: replaced the generic "Unexpected window function: X" message with one that names the rejected function and lists the functions eventstats/streamstats do support (sourced from WINDOW_FUNC_MAPPING), so users get actionable guidance instead of a bare error.
  • Updated the existing unit test (UnifiedQueryPlannerTest) and integration tests (CalcitePPLEventstatsIT, CalciteStreamstatsCommandIT) to assert against the new message.
  • Added new integration tests covering rank/dense_rank specifically, since the issue's repro queries used those functions.

Note: this PR builds on top of #5587 (already merged), which fixed the same throw site to return a 4xx instead of a 500. This PR only changes the message text, not the exception type or HTTP status.

Test plan

  • Unit test UnifiedQueryPlannerTest#unsupportedWindowFunctionIsRethrownAsSemanticCheckException passes
  • Integration tests added/updated for eventstats and streamstats (require a live cluster to run in CI)

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit dd3ca1c)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ Recommended focus areas for review

Hardcoded list

The error message hardcodes the list of supported functions as a string literal. If WINDOW_FUNC_MAPPING changes (functions added or removed), this message will become stale and misleading. The list should be generated dynamically from WINDOW_FUNC_MAPPING to stay accurate.

+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Latest suggestions up to dd3ca1c

Explore these optional code suggestions:

CategorySuggestion Impact
Possible issue
Add null check for queryType

Add null check for context.queryType before comparison to prevent potential
NullPointerException. The context object might have a null queryType field in
certain scenarios, which would cause the filter predicate to fail.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [773-777]

 .filter(
functionName ->
- !(context.queryType == QueryType.PPL+ !(context.queryType != null+ && context.queryType == QueryType.PPL
&& (functionName == BuiltinFunctionName.RANK
|| functionName == BuiltinFunctionName.DENSE_RANK)))
Suggestion importance[1-10]: 5

__

Why: While adding a null check for context.queryType is a defensive programming practice, there's no evidence in the PR that queryType can be null. The suggestion is technically valid but may be unnecessary without context showing this is a real issue. This is a standard null-safety suggestion that doesn't address a demonstrated bug.

Low

Previous suggestions

Suggestions up to commit 58fda66
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + ".");
Suggestion importance[1-10]: 7

__

Why: This is a valid maintainability improvement that prevents the hardcoded list from becoming stale when WINDOW_FUNC_MAPPING is updated. However, it's a moderate enhancement rather than a critical fix, as the current implementation is functional and the mapping is unlikely to change frequently.

Medium
Suggestions up to commit cf4cb1b
CategorySuggestion Impact
General
Verify row_number support in error message

The error message lists row_number as a supported function, but the grammar changes
in OpenSearchPPLParser.g4 removed RANK and DENSE_RANK from scalarWindowFunctionName,
leaving only ROW_NUMBER and other functions. Verify that row_number is actually
supported in eventstats/streamstats context, as the test changes suggest ranking
functions are now rejected at parse time.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [812-818]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " latest, max, min, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid concern about the consistency between the error message and grammar changes. However, examining the grammar file shows that ROW_NUMBER is still present in scalarWindowFunctionName, suggesting it remains supported. The suggestion asks for verification rather than identifying a definite error, and the existing_code matches the improved_code, indicating no concrete change is proposed.

Medium
Suggestions up to commit 99c53f5
CategorySuggestion Impact
General
Use String.format for error message

The error message concatenates multiple strings which can impact readability and
maintainability. Consider using String.format() or a text block for better
formatting and easier future modifications of the supported functions list.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
- "Window function '"- + funcName- + "' is not supported in eventstats/streamstats."- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ String.format(+ "Window function '%s' is not supported in eventstats/streamstats."+ + " Supported functions: avg, count, dc, distinct_count, earliest,"+ + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"+ + " var_pop, var_samp.",+ funcName));
Suggestion importance[1-10]: 4

__

Why: While using String.format() can improve readability, the current string concatenation approach is perfectly valid and readable. This is a minor style improvement that doesn't significantly impact code quality or functionality.

Low
Suggestions up to commit c16fc0c
CategorySuggestion Impact
General
Dynamically generate supported functions list

The hardcoded list of supported functions in the error message may become outdated
if new functions are added to WINDOW_FUNC_MAPPING. Consider dynamically generating
this list from the mapping keys to ensure accuracy and maintainability.

core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java [709-715]

 new CalciteUnsupportedException(
"Window function '"
+ funcName
+ "' is not supported in eventstats/streamstats."
- + " Supported functions: avg, count, dc, distinct_count, earliest,"- + " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"- + " var_pop, var_samp."));+ + " Supported functions: "+ + String.join(", ", WINDOW_FUNC_MAPPING.keySet())+ + "."));
Suggestion importance[1-10]: 7

__

Why: This suggestion improves maintainability by dynamically generating the list of supported functions from WINDOW_FUNC_MAPPING.keySet() instead of hardcoding them. This ensures the error message stays accurate when new functions are added, reducing maintenance burden and preventing outdated documentation.

Medium

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 99c53f5

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hi, I'm trying to add support for rank and dense_rank function in Calcite for unified SQL for analytics engine. If we confirm both are not supported by PPL evenstats and streamstats, shall we remove them from PPL grammar directly? I assume that's the only place window function can be used. Otherwise it will be tricky to check language type in Calcite planner.

@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Good question — I dug into this a bit.

Your assumption holds for PPL specifically: in the PPL grammar, windowFunction (the parenthesized call syntax) is only ever invoked from eventstatsAggTerm/streamstatsAggTerm (OpenSearchPPLParser.g4:922-943), so that is the only place a window function can appear in PPL today.

But it's not the only place in the engine overall. SQL has its own windowFunctionClause/overClause grammar (OpenSearchSQLParser.g4:150-159) that already accepts RANK()/DENSE_RANK() in ... OVER (...). Both SQL and PPL build the same WindowFunction AST node and are resolved by the same CalciteRexNodeVisitor#visitWindowFunction — there's even a comment there noting "SQL emits AggregateFunction for aggregate-as-window (e.g., SUM(x) OVER); PPL emits Function." WINDOW_FUNC_MAPPING in BuiltinFunctionName (used by both paths) simply has no rank/dense_rank entries yet, so both languages fail identically right now.

Practical implication: if you add rank/dense_rank to WINDOW_FUNC_MAPPING and implement them in the shared visitor, that enables them for PPL eventstats/streamstats too, since the mapping/visitor is shared — not just SQL.

So yes, I think removing RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule (lines 933-934) is the right move, and it avoids the language-type check you were worried about: PPL's parser would reject the syntax before it ever reaches the AST/Calcite layer, while SQL's grammar (which already accepts it) passes through untouched. That pushes the language separation to parse time instead of planner time.

One side note on this PR itself: the new error message I added ("Window function 'x' is not supported in eventstats/streamstats") is thrown from that same shared visitor, so it would also currently fire — misleadingly — for a plain SQL RANK() OVER (...) query, since the check isn't actually PPL-specific. I may follow up with a tweak to make that message language-agnostic.

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna Thanks for digging in! I've put up PR #5720 for the SQL side. As you confirmed, removing them from grammar should make PPL reject at parse time and leaves my change SQL-only. With both PRs merged, I think we get the language separation at parse time rather than in the planner, which is where it belongs as expected. Thanks!

@dai-chendai-chen added enhancement New feature or request PPL Piped processing language labels Aug 26, 2026
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

@dai-chen Nice, thanks for #5720. Pushed da13116 here: removed RANK/DENSE_RANK from PPL's scalarWindowFunctionName rule, so eventstats rank()/streamstats dense_rank() now fail at parse time (SyntaxCheckException) instead of reaching the shared visitor.

Updated the tests this PR added for that case (testRankingWindowFunctionsUnsupportedInEventstats/...InStreamstats) to expect the parse-time rejection, and switched unsupportedWindowFunctionIsRethrownAsSemanticCheckException from rank() to percent_rank() since it needs a token that's still in the grammar but outside WINDOW_FUNC_MAPPING to exercise that path.

One caveat: I don't have a Java toolchain in my current environment, so I couldn't run generateGrammarSource/the actual test suite to confirm the exact ANTLR error message — the assertions only check for the generic "is not a valid term at this part of the query" substring rather than the full expected-tokens list, to stay robust either way, but it'd be good to have CI confirm this once it runs.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit da13116

…streamstats
Window functions outside WINDOW_FUNC_MAPPING (e.g. rank, dense_rank,
nth_value) throw a generic "Unexpected window function: X" from
CalciteRexNodeVisitor#visitWindowFunction. These functions require
ORDER BY semantics that eventstats/streamstats don't have (they only
support partition-by), so they are intentionally unsupported, not a
bug -- but the error message gave users no indication of what to use
instead.
Replace the message with one that names the function and lists the
functions eventstats/streamstats do support, so users get actionable
guidance instead of a bare "unexpected" error.
Fixesopensearch-project#5168
Signed-off-by: Radhakrishnan Pachyappan <gingeekrishna@gmail.com>
WINDOW_FUNC_MAPPING (used by eventstats/streamstats) never supported
rank/dense_rank, but PPL's scalarWindowFunctionName grammar rule still
accepted the tokens, so `eventstats rank()` reached
CalciteRexNodeVisitor#visitWindowFunction and failed there with the
"not supported" message this PR improves. Meanwhile SQL's grammar
already accepts RANK()/DENSE_RANK() OVER (...), and opensearch-project#5720 is adding
real support for them on the SQL side via the same shared visitor.
Remove RANK/DENSE_RANK from scalarWindowFunctionName so PPL rejects
them at parse time instead of falling through to the shared
SQL/PPL visitor - this keeps the language separation at the parser
rather than relying on a WINDOW_FUNC_MAPPING check in shared planner
code, and avoids PPL silently gaining rank/dense_rank as a side effect
of opensearch-project#5720 registering them for SQL.
Updates the eventstats/streamstats tests added earlier in this PR to
expect a SyntaxCheckException (parse-time) instead of the semantic
"not supported" error, and switches the unrelated
visitWindowFunction-rejection unit test from rank() to percent_rank(),
which remains unsupported and still exercises that code path.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna
gingeekrishnaforce-pushed the fix/5168-improve-unsupported-window-function-error branch from da13116 to cf4cb1bCompareAugust 30, 2026 05:23
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit cf4cb1b

@dai-chen

Copy link
Copy Markdown
Collaborator

@gingeekrishna My PR was already merged. You can rebase and verify yours by CI if you're unable locally. Btw, I recall changes in unsupportedWindowFunctionIsRethrownAsSemanticCheckException is already covered in my PR.

Comment on lines +816 to +818
+ " Supported functions: avg, count, dc, distinct_count, earliest,"
+ " latest, max, min, row_number, stddev_pop, stddev_samp, sum,"
+ " var_pop, var_samp."));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe revert this change because this list is dynamic and defined in grammar.

@dai-chendai-chen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor comment. Thanks for the changes!

@dai-chen

Copy link
Copy Markdown
Collaborator

I retried Linter CI but it still failed. Probably worth taking another look.

… time"
This reverts commit cf4cb1b.
The "PPL grammar compatibility" CI check failed after that commit:
[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/
eventstats-rank: expected 1, got 0
That check runs OpenSearch-Dashboards' own PPL linter (fetched via
`yarn osd bootstrap`) against this repo's grammar bundle, using test
cases from scripts/ppl-lint/grammar-cases.json. Its
"unsupported-window-function-in-eventstats" rule expects
`eventstats rank()` to parse successfully and then be flagged by a
semantic-layer diagnostic (giving IDE users a specific, friendly
error). Removing RANK/DENSE_RANK from the PPL grammar made the query
fail to parse at all, so that rule never gets a chance to run and the
diagnostic it's supposed to produce disappears - the ppl-lint test
expects the rule to fire (count 1) but the query now dies earlier with
a raw syntax error instead (count 0).
The rule implementation lives in OpenSearch-Dashboards, not this repo,
so fixing this properly would need a coordinated cross-repo change.
Reverting restores parsing (and the linter's diagnostic) while keeping
the actual point of this PR - the improved
"Window function 'x' is not supported in eventstats/streamstats"
message from CalciteRexNodeVisitor - fully intact, since that's a
semantic-layer check unaffected by this revert.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@gingeekrishna

Copy link
Copy Markdown
ContributorAuthor

Found it - pushed 58fda664f to fix it.

The failing check was the linter, specifically:

[ppl-lint-grammar] FAILED unsupported-window-function-in-eventstats/eventstats-rank: expected 1, got 0

That's OpenSearch-Dashboards' own PPL linter (fetched via yarn osd bootstrap in that job) being run against this repo's grammar bundle, using the cases in scripts/ppl-lint/grammar-cases.json. Its unsupported-window-function-in-eventstats rule expects eventstats rank() to parse successfully and then get flagged by a semantic-layer diagnostic - that's how it surfaces a friendly, specific error in the IDE.

My earlier commit here (cf4cb1bd3, removing RANK/DENSE_RANK from the PPL grammar so eventstats rank() fails at parse time instead of reaching the shared visitor) broke exactly that: the query now dies with a raw syntax error before OSD's semantic rule ever gets a chance to run, so its diagnostic never fires. Since that rule lives in the OpenSearch-Dashboards repo, not here, fixing it properly would need a coordinated cross-repo change - out of scope for this PR.

Reverted that commit. This PR's actual point - the improved "Window function 'x' is not supported in eventstats/streamstats" message in CalciteRexNodeVisitor - is a semantic-layer check, so it's untouched by the revert and still works exactly as intended. The parse-time language-separation idea from our earlier discussion doesn't hold up against the existing linter contract, so I'm dropping it rather than pursuing it further here.

@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 58fda66

…layer
opensearch-project#5720 added rank/dense_rank to the WINDOW_FUNC_MAPPING shared by both
SQL's RANK()/DENSE_RANK() OVER (...) and PPL's eventstats/streamstats,
which silently enabled them for eventstats/streamstats too:
testRankingWindowFunctionsUnsupportedInEventstats/InStreamstats
(added earlier in this PR) started failing with "expected
ResponseException to be thrown, but nothing was thrown" once opensearch-project#5720
merged, since eventstats rank() now builds a real window call instead
of hitting the "not supported" check.
That's a real gap, not just a test artifact: PPL's eventstats/
streamstats grammar has no ORDER BY syntax at all, so ranking has no
defined ordering to rank by there - unlike SQL's OVER(), which at
least has (optional) ORDER BY in its own clause.
A prior commit on this branch tried fixing this by removing RANK/
DENSE_RANK from the PPL grammar entirely, rejecting them at parse
time. That broke a different, cross-repo contract: OpenSearch-
Dashboards' PPL linter (validated by the "PPL grammar compatibility"
CI check) expects `eventstats rank()` to parse successfully and be
flagged by a semantic-layer diagnostic instead, so it could no longer
produce that diagnostic once the query stopped parsing. That commit
was reverted.
Fix this at the semantic layer instead, where it belongs: PPL only
ever reaches CalciteRexNodeVisitor#visitWindowFunction through
eventstats/streamstats (no other PPL syntax builds a WindowFunction
node), so context.queryType == PPL is an exact, unambiguous signal for
"this is an eventstats/streamstats call". Filter rank/dense_rank out
of the WINDOW_FUNC_MAPPING lookup specifically when queryType is PPL,
so they fall through to the existing "not supported in eventstats/
streamstats" error - exactly the pre-opensearch-project#5720 behavior - while leaving
SQL's RANK()/DENSE_RANK() OVER (...) handling (and everything else)
completely untouched.
Signed-off-by: Radhakrishnan P <gingeekrishna@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit dd3ca1c

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementNew feature or requestPPLPiped processing language

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] eventstats/streamstats reject window functions that grammar accepts

3 participants

@gingeekrishna@dai-chen