diff --git a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLAggregationIT.java b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLAggregationIT.java index 0cd5269a706..80fbfae8b07 100644 --- a/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLAggregationIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalcitePPLAggregationIT.java @@ -8,6 +8,7 @@ import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BANK; import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_BANK_WITH_NULL_VALUES; import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_CALCS; +import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_DATATYPE_NUMERIC; import static org.opensearch.sql.legacy.TestsConstants.TEST_INDEX_DATE_FORMATS; import static org.opensearch.sql.util.MatcherUtils.assertJsonEquals; import static org.opensearch.sql.util.MatcherUtils.rows; @@ -37,6 +38,7 @@ public void init() throws Exception { loadIndex(Index.BANK_WITH_NULL_VALUES); loadIndex(Index.CALCS); loadIndex(Index.DATE_FORMATS); + loadIndex(Index.DATA_TYPE_NUMERIC); } @Test @@ -806,4 +808,14 @@ public void testAggWithFunction() throws IOException { schema("gender", null, "string")); verifyDataRows(response, rows(121764, 1, "F"), rows(65909, 1, "M")); } + + @Test + public void testAggByByteNumberWithScript() throws IOException { + JSONObject response = + executeQuery( + String.format( + "source=%s | eval a = abs(byte_number) | stats count() by a", + TEST_INDEX_DATATYPE_NUMERIC)); + verifyDataRows(response, rows(1, 4)); + } } diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/Content.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/Content.java index bc50683c6dc..182ba4b6d10 100644 --- a/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/Content.java +++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/Content.java @@ -29,6 +29,12 @@ public interface Content { /** Is double value. */ boolean isDouble(); + /** Is short value. */ + boolean isShort(); + + /** Is byte value. */ + boolean isByte(); + /** Is int value. */ boolean isInt(); diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/ObjectContent.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/ObjectContent.java index 643d1425a72..9ca3deadddd 100644 --- a/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/ObjectContent.java +++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/ObjectContent.java @@ -104,6 +104,16 @@ public boolean isNumber() { return value instanceof Number; } + @Override + public boolean isShort() { + return value instanceof Short; + } + + @Override + public boolean isByte() { + return value instanceof Byte; + } + @Override public boolean isInt() { return value instanceof Integer; diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/OpenSearchJsonContent.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/OpenSearchJsonContent.java index 41b8c68e0c9..85a82ccd8b5 100644 --- a/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/OpenSearchJsonContent.java +++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/data/utils/OpenSearchJsonContent.java @@ -92,6 +92,16 @@ public boolean isNumber() { return value().isNumber(); } + @Override + public boolean isShort() { + return value.isShort(); + } + + @Override + public boolean isByte() { + return false; + } + @Override public boolean isInt() { return value.isInt(); diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/data/value/OpenSearchExprValueFactory.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/data/value/OpenSearchExprValueFactory.java index 2a5642c0f08..c3d3a23945f 100644 --- a/opensearch/src/main/java/org/opensearch/sql/opensearch/data/value/OpenSearchExprValueFactory.java +++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/data/value/OpenSearchExprValueFactory.java @@ -216,6 +216,10 @@ private ExprValue parseContent(Content content) { if (content.isNumber()) { if (content.isInt()) { return new ExprIntegerValue(content.intValue()); + } else if (content.isShort()) { + return new ExprShortValue(content.shortValue()); + } else if (content.isByte()) { + return new ExprByteValue(content.byteValue()); } else if (content.isLong()) { return new ExprLongValue(content.longValue()); } else if (content.isFloat()) { diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/request/PredicateAnalyzer.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/request/PredicateAnalyzer.java index fffc9cef298..b4a60c6df73 100644 --- a/opensearch/src/main/java/org/opensearch/sql/opensearch/request/PredicateAnalyzer.java +++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/request/PredicateAnalyzer.java @@ -1479,7 +1479,7 @@ private NamedFieldExpression(RexLiteral literal) { this.type = null; } - String getRootName() { + public String getRootName() { return name; } diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/CalciteScriptEngine.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/CalciteScriptEngine.java index cebaf8c0418..20f1d4ceed4 100644 --- a/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/CalciteScriptEngine.java +++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/CalciteScriptEngine.java @@ -27,6 +27,7 @@ package org.opensearch.sql.opensearch.storage.script; +import static org.opensearch.sql.data.type.ExprCoreType.BYTE; import static org.opensearch.sql.data.type.ExprCoreType.FLOAT; import static org.opensearch.sql.data.type.ExprCoreType.INTEGER; import static org.opensearch.sql.data.type.ExprCoreType.SHORT; @@ -211,6 +212,7 @@ private Expression tryConvertDocValue(Expression docValueExpr, ExprType exprType switch (type) { case INTEGER: case SHORT: + case BYTE: docValue = EnumUtils.convert(docValueExpr, Long.class); break; case FLOAT: @@ -360,7 +362,7 @@ private static Pair getValidatedReferenceNameAndType( String referenceField = expression.getReferenceForTermQuery(); if (StringUtils.isEmpty(referenceField)) { throw new UnsupportedScriptException( - "Field name cannot be empty for expression: " + expression); + "Field name cannot be empty for expression: " + expression.getRootName()); } return Pair.of(referenceField, exprType); } diff --git a/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/serde/RelJsonSerializer.java b/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/serde/RelJsonSerializer.java index f698aad3b76..5d394942638 100644 --- a/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/serde/RelJsonSerializer.java +++ b/opensearch/src/main/java/org/opensearch/sql/opensearch/storage/serde/RelJsonSerializer.java @@ -108,11 +108,12 @@ public String serialize( * @return map of RexNode, RelDataType and OpenSearch field types */ public Map deserialize(String struct) { + Map objectMap = null; try { // Recover Map object from bytes ByteArrayInputStream input = new ByteArrayInputStream(Base64.getDecoder().decode(struct)); ObjectInputStream objectInput = new ObjectInputStream(input); - Map objectMap = (Map) objectInput.readObject(); + objectMap = (Map) objectInput.readObject(); // PPL Expr types are all serializable Map fieldTypes = (Map) objectMap.get(FIELD_TYPES); @@ -127,8 +128,12 @@ public Map deserialize(String struct) { return Map.of(EXPR, rexNode, FIELD_TYPES, fieldTypes, ROW_TYPE, rowType); } catch (Exception e) { + if (objectMap == null) { + throw new IllegalStateException( + "Failed to deserialize RexNode due to object map is null", e); + } throw new IllegalStateException( - "Failed to deserialize RexNode and its required structure: " + struct, e); + "Failed to deserialize RexNode and its required structure: " + objectMap.get(EXPR), e); } } }