diff --git a/core/src/main/java/org/opensearch/sql/expression/DSL.java b/core/src/main/java/org/opensearch/sql/expression/DSL.java index 14ed77a60c..439f31e0ba 100644 --- a/core/src/main/java/org/opensearch/sql/expression/DSL.java +++ b/core/src/main/java/org/opensearch/sql/expression/DSL.java @@ -230,8 +230,13 @@ public static FunctionExpression sign(Expression... expressions) { return compile(FunctionProperties.None, BuiltinFunctionName.SIGN, expressions); } + public static FunctionExpression signum(Expression... expressions) { + return compile(FunctionProperties.None, BuiltinFunctionName.SIGNUM, expressions); + } + public static FunctionExpression sinh(Expression... expressions) { return compile(FunctionProperties.None, BuiltinFunctionName.SINH, expressions); + } public static FunctionExpression sqrt(Expression... expressions) { diff --git a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java index 8c014f9325..ca0de55cef 100644 --- a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java @@ -42,6 +42,7 @@ public enum BuiltinFunctionName { RINT(FunctionName.of("rint")), ROUND(FunctionName.of("round")), SIGN(FunctionName.of("sign")), + SIGNUM(FunctionName.of("signum")), SINH(FunctionName.of("sinh")), SQRT(FunctionName.of("sqrt")), CBRT(FunctionName.of("cbrt")), diff --git a/core/src/main/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunction.java b/core/src/main/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunction.java index f81e775641..6bcaed3ec3 100644 --- a/core/src/main/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunction.java @@ -72,6 +72,7 @@ public static void register(BuiltinFunctionRepository repository) { repository.register(rint()); repository.register(round()); repository.register(sign()); + repository.register(signum()); repository.register(sinh()); repository.register(sqrt()); repository.register(truncate()); @@ -489,6 +490,18 @@ private static DefaultFunctionResolver sign() { v -> new ExprIntegerValue(Math.signum(v.doubleValue())), INTEGER); } + /** + * Definition of signum(x) function. + * Returns the sign of the argument as -1.0, 0, or 1.0 + * depending on whether x is negative, zero, or positive + * The supported signature is + * BYTE/SHORT/INTEGER/LONG/FLOAT/DOUBLE -> INTEGER + */ + private static DefaultFunctionResolver signum() { + return baseMathFunction(BuiltinFunctionName.SIGNUM.getName(), + v -> new ExprIntegerValue(Math.signum(v.doubleValue())), INTEGER); + } + /** * Definition of sinh(x) function. * Returns the hyperbolix sine of x, defined as (((e^x) - (e^(-x))) / 2) diff --git a/core/src/test/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunctionTest.java b/core/src/test/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunctionTest.java index 5cf42eb868..77f58d0c02 100644 --- a/core/src/test/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunctionTest.java +++ b/core/src/test/java/org/opensearch/sql/expression/operator/arthmetic/MathematicalFunctionTest.java @@ -1890,6 +1890,84 @@ public void sign_missing_value() { assertTrue(sign.valueOf(valueEnv()).isMissing()); } + /** + * Test signum with byte value. + */ + @ParameterizedTest(name = "signum({0})") + @ValueSource(bytes = {2, 0, -2}) + public void signum_bytes_value(Byte value) { + FunctionExpression signum = DSL.signum(DSL.literal(value)); + assertThat( + signum.valueOf(valueEnv()), + allOf(hasType(INTEGER), hasValue((int) Math.signum(value)))); + assertEquals(String.format("signum(%s)", value), signum.toString()); + } + + /** + * Test signum with short value. + */ + @ParameterizedTest(name = "signum({0})") + @ValueSource(shorts = {2, 0, -2}) + public void signum_short_value(Short value) { + FunctionExpression signum = DSL.signum(DSL.literal(value)); + assertThat( + signum.valueOf(valueEnv()), + allOf(hasType(INTEGER), hasValue((int) Math.signum(value)))); + assertEquals(String.format("signum(%s)", value), signum.toString()); + } + + /** + * Test signum with integer value. + */ + @ParameterizedTest(name = "signum({0})") + @ValueSource(ints = {2, 0, -2}) + public void signum_int_value(Integer value) { + FunctionExpression signum = DSL.signum(DSL.literal(value)); + assertThat( + signum.valueOf(valueEnv()), + allOf(hasType(INTEGER), hasValue((int) Math.signum(value)))); + assertEquals(String.format("signum(%s)", value), signum.toString()); + } + + /** + * Test signum with long value. + */ + @ParameterizedTest(name = "signum({0})") + @ValueSource(longs = {2L, 0L, -2L}) + public void signum_long_value(Long value) { + FunctionExpression signum = DSL.signum(DSL.literal(value)); + assertThat( + signum.valueOf(valueEnv()), + allOf(hasType(INTEGER), hasValue((int) Math.signum(value)))); + assertEquals(String.format("signum(%s)", value), signum.toString()); + } + + /** + * Test signum with float value. + */ + @ParameterizedTest(name = "signum({0})") + @ValueSource(floats = {2F, 0F, -2F}) + public void signum_float_value(Float value) { + FunctionExpression signum = DSL.signum(DSL.literal(value)); + assertThat( + signum.valueOf(valueEnv()), + allOf(hasType(INTEGER), hasValue((int) Math.signum(value)))); + assertEquals(String.format("signum(%s)", value), signum.toString()); + } + + /** + * Test signum with double value. + */ + @ParameterizedTest(name = "signum({0})") + @ValueSource(doubles = {2, 0, -2}) + public void signum_double_value(Double value) { + FunctionExpression signum = DSL.signum(DSL.literal(value)); + assertThat( + signum.valueOf(valueEnv()), + allOf(hasType(INTEGER), hasValue((int) Math.signum(value)))); + assertEquals(String.format("signum(%s)", value), signum.toString()); + } + /** * Test sinh with byte value. */ diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 7dabdcb8ad..ea594e99dd 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -784,9 +784,23 @@ SIGNUM Description >>>>>>>>>>> -Specifications: +Usage: Returns the sign of the argument as -1, 0, or 1, depending on whether the number is negative, zero, or positive + +Argument type: BYTE/SHORT/INTEGER/LONG/FLOAT/DOUBLE + +Return type: INTEGER + +Synonyms: `SIGN`_ -1. SIGNUM(NUMBER T) -> T +Example:: + + os> SELECT SIGNUM(1), SIGNUM(0), SIGNUM(-1.1) + fetched rows / total rows = 1/1 + +-------------+-------------+----------------+ + | SIGNUM(1) | SIGNUM(0) | SIGNUM(-1.1) | + |-------------+-------------+----------------| + | 1 | 0 | -1 | + +-------------+-------------+----------------+ SIN diff --git a/integ-test/src/test/java/org/opensearch/sql/sql/MathematicalFunctionIT.java b/integ-test/src/test/java/org/opensearch/sql/sql/MathematicalFunctionIT.java index fd063bff14..7d5662f65a 100644 --- a/integ-test/src/test/java/org/opensearch/sql/sql/MathematicalFunctionIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/sql/MathematicalFunctionIT.java @@ -167,9 +167,6 @@ public void testRound() throws IOException { verifyDataRows(result, rows(-4.0)); } - /** - * Test sign function with double value. - */ @Test public void testSign() throws IOException { JSONObject result = executeQuery("select sign(1.1)"); @@ -182,6 +179,16 @@ public void testSign() throws IOException { } @Test + public void testSignum() throws IOException { + JSONObject result = executeQuery("select signum(1.1)"); + verifySchema(result, schema("signum(1.1)", null, "integer")); + verifyDataRows(result, rows(1)); + + result = executeQuery("select signum(-1.1)"); + verifySchema(result, schema("signum(-1.1)", null, "integer")); + verifyDataRows(result, rows(-1)); + } + public void testSinh() throws IOException { JSONObject result = executeQuery("select sinh(1)"); verifySchema(result, schema("sinh(1)", null, "double")); diff --git a/sql/src/main/antlr/OpenSearchSQLParser.g4 b/sql/src/main/antlr/OpenSearchSQLParser.g4 index 8ef5b38321..a8ddb5a884 100644 --- a/sql/src/main/antlr/OpenSearchSQLParser.g4 +++ b/sql/src/main/antlr/OpenSearchSQLParser.g4 @@ -419,7 +419,7 @@ aggregationFunctionName mathematicalFunctionName : ABS | CBRT | CEIL | CEILING | CONV | CRC32 | E | EXP | EXPM1 | FLOOR | LN | LOG | LOG10 | LOG2 | MOD | PI | POW | POWER - | RAND | RINT | ROUND | SIGN | SQRT | TRUNCATE + | RAND | RINT | ROUND | SIGN | SIGNUM | SQRT | TRUNCATE | trigonometricFunctionName ;