diff --git a/api/src/test/java/org/opensearch/sql/api/UnifiedQueryPlannerTest.java b/api/src/test/java/org/opensearch/sql/api/UnifiedQueryPlannerTest.java index f8cc834dee8..00bceba9fe2 100644 --- a/api/src/test/java/org/opensearch/sql/api/UnifiedQueryPlannerTest.java +++ b/api/src/test/java/org/opensearch/sql/api/UnifiedQueryPlannerTest.java @@ -171,7 +171,8 @@ public void unsupportedWindowFunctionIsRethrownAsSemanticCheckException() { givenInvalidQuery("source = catalog.employees | eventstats percent_rank()") .assertErrorType(SemanticCheckException.class) .assertCauseType(CalciteUnsupportedException.class) - .assertErrorMessageContains("Unexpected window function: percent_rank"); + .assertErrorMessageContains( + "Window function 'percent_rank' is not supported in eventstats/streamstats"); } @Test diff --git a/core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java b/core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java index b6500dd8087..b554cb82227 100644 --- a/core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java +++ b/core/src/main/java/org/opensearch/sql/calcite/CalciteRexNodeVisitor.java @@ -808,7 +808,14 @@ public RexNode visitWindowFunction(WindowFunction node, CalcitePlanContext conte node.getWindowFrame()); }) .orElseThrow( - () -> new CalciteUnsupportedException("Unexpected window function: " + funcName)); + () -> + 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.")); } private List translateOrderKeys( diff --git a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEventstatsIT.java b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEventstatsIT.java index a2d1e4af086..9c0bd5422c5 100644 --- a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEventstatsIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEventstatsIT.java @@ -12,6 +12,7 @@ import java.util.List; import org.json.JSONObject; import org.junit.jupiter.api.Test; +import org.opensearch.sql.common.antlr.SyntaxCheckException; import org.opensearch.sql.ppl.PPLIntegTestCase; public class CalcitePPLEventstatsIT extends PPLIntegTestCase { @@ -329,7 +330,23 @@ public void testUnsupportedWindowFunctions() { executeQuery( String.format( "source=%s | eventstats %s(age)", TEST_INDEX_STATE_COUNTRY, u))); - verifyErrorMessageContains(e, "Unexpected window function: " + u); + verifyErrorMessageContains(e, "is not supported in eventstats/streamstats"); + } + } + + @Test + public void testRankingWindowFunctionsUnsupportedInEventstats() { + // rank/dense_rank aren't in eventstats/streamstats' windowFunctionName grammar rule, so this + // is now a parse-time rejection rather than a semantic one. + for (String func : List.of("rank", "dense_rank")) { + Throwable e = + assertThrowsWithReplace( + SyntaxCheckException.class, + () -> + executeQuery( + String.format( + "source=%s | eventstats %s() by state", TEST_INDEX_STATE_COUNTRY, func))); + verifyErrorMessageContains(e, "is not a valid term at this part of the query"); } } diff --git a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalciteStreamstatsCommandIT.java b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalciteStreamstatsCommandIT.java index e70812e3c3b..81c653b0742 100644 --- a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalciteStreamstatsCommandIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalciteStreamstatsCommandIT.java @@ -16,6 +16,7 @@ import org.json.JSONObject; import org.junit.jupiter.api.Test; import org.opensearch.client.Request; +import org.opensearch.sql.common.antlr.SyntaxCheckException; import org.opensearch.sql.ppl.PPLIntegTestCase; import org.opensearch.sql.util.RequiresCapability; @@ -846,7 +847,24 @@ public void testUnsupportedWindowFunctions() { executeQuery( String.format( "source=%s | streamstats %s(age)", TEST_INDEX_STATE_COUNTRY, u))); - verifyErrorMessageContains(e, "Unexpected window function: " + u); + verifyErrorMessageContains(e, "is not supported in eventstats/streamstats"); + } + } + + @Test + public void testRankingWindowFunctionsUnsupportedInStreamstats() { + // rank/dense_rank aren't in eventstats/streamstats' windowFunctionName grammar rule, so this + // is now a parse-time rejection rather than a semantic one. + for (String func : List.of("rank", "dense_rank")) { + Throwable e = + assertThrowsWithReplace( + SyntaxCheckException.class, + () -> + executeQuery( + String.format( + "source=%s | streamstats %s() by state", + TEST_INDEX_STATE_COUNTRY, func))); + verifyErrorMessageContains(e, "is not a valid term at this part of the query"); } } diff --git a/ppl/src/main/antlr/OpenSearchPPLParser.g4 b/ppl/src/main/antlr/OpenSearchPPLParser.g4 index ce949f8534b..b8280043aeb 100644 --- a/ppl/src/main/antlr/OpenSearchPPLParser.g4 +++ b/ppl/src/main/antlr/OpenSearchPPLParser.g4 @@ -930,8 +930,6 @@ windowFunctionName scalarWindowFunctionName : ROW_NUMBER - | RANK - | DENSE_RANK | PERCENT_RANK | CUME_DIST | FIRST