diff --git a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEvalMaxMinFunctionIT.java b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEvalMaxMinFunctionIT.java index 27b0343d6ac..8487e06686f 100644 --- a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEvalMaxMinFunctionIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLEvalMaxMinFunctionIT.java @@ -29,6 +29,9 @@ public void init() throws Exception { loadIndex(Index.NULL_MISSING); } + // `new` has no plan-time type, so its reported type is taken from the first result row. Filtering + // to a single row makes that row deterministic under any shard count. Both directions are kept so + // the int-selected and bigint-selected results stay covered. @Test @RequiresCapability( value = EVAL_MAX_MIN_INT_WIDENING, @@ -37,9 +40,21 @@ public void testEvalMaxNumeric() throws Exception { JSONObject result = executeQuery( String.format( - "source=%s | eval new = max(1, 3, age) | fields age, new", TEST_INDEX_DOG)); + "source=%s | where age = 2 | eval new = max(1, 3, age) | fields age, new", + TEST_INDEX_DOG)); verifySchema(result, schema("age", "bigint"), schema("new", "int")); - verifyDataRows(result, rows(2, 3), rows(4, 4)); + verifyDataRows(result, rows(2, 3)); + } + + @Test + public void testEvalMaxNumericWhenFieldSelected() throws Exception { + JSONObject result = + executeQuery( + String.format( + "source=%s | where age = 4 | eval new = max(1, 3, age) | fields age, new", + TEST_INDEX_DOG)); + verifySchema(result, schema("age", "bigint"), schema("new", "bigint")); + verifyDataRows(result, rows(4, 4)); } @Test @@ -76,9 +91,24 @@ public void testEvalMinNumeric() throws Exception { JSONObject result = executeQuery( String.format( - "source=%s | eval new = min(14, 3, age) | fields age, new", TEST_INDEX_DOG)); + "source=%s | where age = 2 | eval new = min(14, 3, age) | fields age, new", + TEST_INDEX_DOG)); verifySchema(result, schema("age", "bigint"), schema("new", "bigint")); - verifyDataRows(result, rows(2, 2), rows(4, 3)); + verifyDataRows(result, rows(2, 2)); + } + + @Test + @RequiresCapability( + value = EVAL_MAX_MIN_INT_WIDENING, + note = "min(14, 3, age) selects an int-valued result; the AE route reports it as bigint.") + public void testEvalMinNumericWhenLiteralSelected() throws Exception { + JSONObject result = + executeQuery( + String.format( + "source=%s | where age = 4 | eval new = min(14, 3, age) | fields age, new", + TEST_INDEX_DOG)); + verifySchema(result, schema("age", "bigint"), schema("new", "int")); + verifyDataRows(result, rows(4, 3)); } @Test @@ -136,11 +166,30 @@ public void testEvalMinIgnoresNulls() throws Exception { JSONObject result = executeQuery( String.format( - "source=%s | eval new = min(dbl, 5) | fields dbl, new", TEST_INDEX_NULL_MISSING)); + "source=%s | where key = 'values' | eval new = min(dbl, 5) | fields dbl, new", + TEST_INDEX_NULL_MISSING)); verifySchema(result, schema("dbl", "double"), schema("new", "double")); + verifyDataRows(result, rows(3.1415, 3.1415)); + } + + // Keeps the null-skipping assertion on its own rows, covering both explicit-null and + // missing-field documents. Every row here selects the int literal, so the reported type no longer + // depends on which row arrives first. + @Test + @RequiresCapability( + value = EVAL_MAX_MIN_INT_WIDENING, + note = + "min(dbl, 5) over null-valued rows selects the int literal; the AE route reports the" + + " column using the wider double type.") + public void testEvalMinIgnoresNullsWhenLiteralSelected() throws Exception { + JSONObject result = + executeQuery( + String.format( + "source=%s | where key != 'values' | eval new = min(dbl, 5) | fields dbl, new", + TEST_INDEX_NULL_MISSING)); + verifySchema(result, schema("dbl", "double"), schema("new", "int")); verifyDataRows( result, - rows(3.1415, 3.1415), rows(null, 5), rows(null, 5), rows(null, 5),