generated from amazon-archives/__template_Custom
-
Notifications
You must be signed in to change notification settings - Fork 178
issue #4514 tonumber function as part of roadmap #4287 #4605
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
asifabashar
wants to merge
37
commits into
opensearch-project:main
Choose a base branch
from
asifabashar:feature_tonumber
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
0ed23de
PPL tostring() implementation issue #4492
asifabashar 5a5b778
removed sql changes
asifabashar 9d71a95
doc changes
asifabashar be2c2e2
docs changes
asifabashar fc763a4
reverted string doc changes
asifabashar a04eb14
removed extra word
asifabashar 590a8e6
added any type
asifabashar 6938e2c
doc formatting fixes
asifabashar 314fccd
description for boolean example
asifabashar 0ee17b9
added format_time call from calcite , added duration_millis as splunk…
asifabashar 6e24aa3
added doc update to specifically set 2nd argument as optional
asifabashar 454cfc8
mentioned as value instead of number specifically
asifabashar b221e8c
fixed wrong bullet point
asifabashar a0a89c4
issue #4514 tonumber function as part of roadmap #4287
asifabashar ea9ba0f
added more unit tests
asifabashar 370b9bc
Update docs/user/ppl/functions/conversion.rst
asifabashar f070684
fix per recommendation
asifabashar a2accf5
updated recommended changes
asifabashar 3adda5d
updated recommended changes
asifabashar 17b1d86
updated recommended changes
asifabashar eca7d13
updated recommended changes
asifabashar e780c15
updated recommended changes
asifabashar e3884b0
updated recommended changes
asifabashar 042d3e8
spotless apply
asifabashar 38ce420
merge conflict fix
asifabashar 58d8e1b
merge conflict fix
asifabashar 34f8635
added recommended changes
asifabashar 8279bf3
fixed doctest for conversion.rst and applied spotless
asifabashar b5346a6
removed decimal point from hex
asifabashar 7cf867b
added doctest fixes
asifabashar 8d9db4e
fixed merged conflicts
asifabashar 46f010b
removed unused variables
asifabashar b7afa17
spotless
asifabashar 0f0125a
made recommended changes to simply parse to number, null when malformed
asifabashar 804db79
hex max limit doc and unit tests
asifabashar 7588397
fix to spotless
asifabashar 04a5564
Merge branch 'main' into feature_tonumber
asifabashar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
core/src/main/java/org/opensearch/sql/expression/function/udf/ToNumberFunction.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| /* | ||
| * Copyright OpenSearch Contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.opensearch.sql.expression.function.udf; | ||
|
|
||
| import java.math.BigInteger; | ||
| import java.util.List; | ||
| import org.apache.calcite.adapter.enumerable.NotNullImplementor; | ||
| import org.apache.calcite.adapter.enumerable.NullPolicy; | ||
| import org.apache.calcite.adapter.enumerable.RexToLixTranslator; | ||
| import org.apache.calcite.linq4j.function.Strict; | ||
| import org.apache.calcite.linq4j.tree.Expression; | ||
| import org.apache.calcite.linq4j.tree.Expressions; | ||
| import org.apache.calcite.rex.RexCall; | ||
| import org.apache.calcite.sql.type.ReturnTypes; | ||
| import org.apache.calcite.sql.type.SqlReturnTypeInference; | ||
| import org.opensearch.sql.calcite.utils.PPLOperandTypes; | ||
| import org.opensearch.sql.expression.function.ImplementorUDF; | ||
| import org.opensearch.sql.expression.function.UDFOperandMetadata; | ||
|
|
||
| /** | ||
| * A custom implementation of number/boolean to string . | ||
| * | ||
| * <p>This operator is necessary because tostring has following requirements "binary" Converts a | ||
| * number to a binary value. "hex" Converts the number to a hexadecimal value. "commas" Formats the | ||
| * number with commas. If the number includes a decimal, the function rounds the number to nearest | ||
| * two decimal places. "duration" Converts the value in seconds to the readable time format | ||
| * HH:MM:SS. if not format parameter provided, then consider value as boolean | ||
| */ | ||
| public class ToNumberFunction extends ImplementorUDF { | ||
| public ToNumberFunction() { | ||
| super( | ||
| new org.opensearch.sql.expression.function.udf.ToNumberFunction.ToNumberImplementor(), | ||
| NullPolicy.ANY); | ||
| } | ||
|
|
||
| @Override | ||
| public SqlReturnTypeInference getReturnTypeInference() { | ||
| return ReturnTypes.DOUBLE_FORCE_NULLABLE; | ||
| } | ||
|
|
||
| @Override | ||
| public UDFOperandMetadata getOperandMetadata() { | ||
| return PPLOperandTypes.STRING_OR_STRING_INTEGER; | ||
| } | ||
|
|
||
| public static class ToNumberImplementor implements NotNullImplementor { | ||
|
|
||
| @Override | ||
| public Expression implement( | ||
| RexToLixTranslator translator, RexCall call, List<Expression> translatedOperands) { | ||
| Expression fieldValue = translatedOperands.get(0); | ||
| int base = 10; | ||
| if (translatedOperands.size() > 1) { | ||
| Expression baseExpr = translatedOperands.get(1); | ||
| return Expressions.call(ToNumberFunction.class, "toNumber", fieldValue, baseExpr); | ||
| } else { | ||
| return Expressions.call(ToNumberFunction.class, "toNumber", fieldValue); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Strict | ||
| public static Number toNumber(String numStr) { | ||
| return toNumber(numStr, 10); | ||
| } | ||
|
|
||
| @Strict | ||
| public static Number toNumber(String numStr, int base) { | ||
| if (base < 2 || base > 36) { | ||
| throw new IllegalArgumentException("Base has to be between 2 and 36."); | ||
| } | ||
| Number result = null; | ||
| try { | ||
| if (base == 10) { | ||
| if (numStr.contains(".")) { | ||
| result = Double.parseDouble(numStr); | ||
| } else { | ||
| result = Long.parseLong(numStr); | ||
| } | ||
| } else { | ||
| BigInteger bigInteger = new BigInteger(numStr, base); | ||
| result = bigInteger.longValue(); | ||
asifabashar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } catch (Exception e) { | ||
|
|
||
| } | ||
| return result; | ||
| } | ||
| } | ||
176 changes: 176 additions & 0 deletions
176
core/src/test/java/org/opensearch/sql/expression/function/udf/ToNumberFunctionTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| /* | ||
| * Copyright OpenSearch Contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| package org.opensearch.sql.expression.function.udf; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| import org.apache.calcite.sql.type.ReturnTypes; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.opensearch.sql.calcite.utils.PPLOperandTypes; | ||
|
|
||
| public class ToNumberFunctionTest { | ||
|
|
||
| private final ToNumberFunction function = new ToNumberFunction(); | ||
|
|
||
| @Test | ||
| void testGetReturnTypeInference() { | ||
| assertEquals(ReturnTypes.DOUBLE_FORCE_NULLABLE, function.getReturnTypeInference()); | ||
| } | ||
|
|
||
| @Test | ||
| void testGetOperandMetadata() { | ||
| assertEquals(PPLOperandTypes.STRING_OR_STRING_INTEGER, function.getOperandMetadata()); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithDefaultBase() { | ||
| assertEquals(123L, ToNumberFunction.toNumber("123")); | ||
| assertEquals(0L, ToNumberFunction.toNumber("0")); | ||
| assertEquals(-456L, ToNumberFunction.toNumber("-456")); | ||
| assertEquals(123.45, ToNumberFunction.toNumber("123.45")); | ||
| assertEquals(-123.45, ToNumberFunction.toNumber("-123.45")); | ||
| assertEquals(0.5, ToNumberFunction.toNumber("0.5")); | ||
| assertEquals(-0.5, ToNumberFunction.toNumber("-0.5")); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithBase10() { | ||
| assertEquals(123L, ToNumberFunction.toNumber("123", 10)); | ||
| assertEquals(0L, ToNumberFunction.toNumber("0", 10)); | ||
| assertEquals(-456L, ToNumberFunction.toNumber("-456", 10)); | ||
| assertEquals(123.45, ToNumberFunction.toNumber("123.45", 10)); | ||
| assertEquals(-123.45, ToNumberFunction.toNumber("-123.45", 10)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithBase2() { | ||
| assertEquals(5L, ToNumberFunction.toNumber("101", 2)); | ||
| assertEquals(0L, ToNumberFunction.toNumber("0", 2)); | ||
| assertEquals(1L, ToNumberFunction.toNumber("1", 2)); | ||
| assertEquals(7L, ToNumberFunction.toNumber("111", 2)); | ||
| assertEquals(10L, ToNumberFunction.toNumber("1010", 2)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithBase8() { | ||
| assertEquals(64L, ToNumberFunction.toNumber("100", 8)); | ||
| assertEquals(8L, ToNumberFunction.toNumber("10", 8)); | ||
| assertEquals(83L, ToNumberFunction.toNumber("123", 8)); | ||
| assertEquals(511L, ToNumberFunction.toNumber("777", 8)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithBase16() { | ||
| assertEquals(255L, ToNumberFunction.toNumber("FF", 16)); | ||
| assertEquals(16L, ToNumberFunction.toNumber("10", 16)); | ||
| assertEquals(171L, ToNumberFunction.toNumber("AB", 16)); | ||
| assertEquals(291L, ToNumberFunction.toNumber("123", 16)); | ||
| assertEquals(4095L, ToNumberFunction.toNumber("FFF", 16)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithBase36() { | ||
| assertEquals(35L, ToNumberFunction.toNumber("Z", 36)); | ||
| assertEquals(1295L, ToNumberFunction.toNumber("ZZ", 36)); | ||
| assertEquals(46655L, ToNumberFunction.toNumber("ZZZ", 36)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithDecimalBase2() { | ||
| assertEquals(2L, ToNumberFunction.toNumber("10", 2)); | ||
| assertEquals(1L, ToNumberFunction.toNumber("1", 2)); | ||
| assertEquals(3L, ToNumberFunction.toNumber("11", 2)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithDecimalBase16() { | ||
| assertEquals(255L, ToNumberFunction.toNumber("FF", 16)); | ||
| assertEquals(16L, ToNumberFunction.toNumber("10", 16)); | ||
| assertEquals(171L, ToNumberFunction.toNumber("AB", 16)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithNegativeDecimal() { | ||
| assertEquals(-2L, ToNumberFunction.toNumber("-10", 2)); | ||
| assertEquals(-255L, ToNumberFunction.toNumber("-FF", 16)); | ||
| assertEquals(-123.45, ToNumberFunction.toNumber("-123.45", 10)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithEmptyFractionalPart() { | ||
| assertEquals(123.0, ToNumberFunction.toNumber("123.", 10)); | ||
| assertEquals(255L, ToNumberFunction.toNumber("FF", 16)); | ||
| assertEquals(5L, ToNumberFunction.toNumber("101", 2)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberWithZeroIntegerPart() { | ||
| assertEquals(0.5, ToNumberFunction.toNumber("0.5", 10)); | ||
| assertEquals(0L, ToNumberFunction.toNumber("0", 2)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberInvalidBase() { | ||
| assertThrows( | ||
| IllegalArgumentException.class, | ||
| () -> { | ||
| ToNumberFunction.toNumber("123", 1); | ||
| }); | ||
|
|
||
| assertThrows( | ||
| IllegalArgumentException.class, | ||
| () -> { | ||
| ToNumberFunction.toNumber("123", 37); | ||
| }); | ||
|
|
||
| assertThrows( | ||
| IllegalArgumentException.class, | ||
| () -> { | ||
| ToNumberFunction.toNumber("123", 0); | ||
| }); | ||
|
|
||
| assertThrows( | ||
| IllegalArgumentException.class, | ||
| () -> { | ||
| ToNumberFunction.toNumber("123", -1); | ||
| }); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberInvalidDigits() { | ||
| assertEquals(null, ToNumberFunction.toNumber("12A", 10)); | ||
| assertEquals(null, ToNumberFunction.toNumber("102", 2)); | ||
| assertEquals(null, ToNumberFunction.toNumber("101.101", 2)); | ||
| assertEquals(null, ToNumberFunction.toNumber("189", 8)); | ||
| assertEquals(null, ToNumberFunction.toNumber("GHI", 16)); | ||
| assertEquals(null, ToNumberFunction.toNumber("FF.8", 16)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberEdgeCases() { | ||
| assertEquals(0L, ToNumberFunction.toNumber("0", 2)); | ||
| assertEquals(0L, ToNumberFunction.toNumber("0", 36)); | ||
| assertEquals(0.0, ToNumberFunction.toNumber("0.0", 10)); | ||
| assertEquals(0.0, ToNumberFunction.toNumber("0.000", 10)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberLargeNumbers() { | ||
| assertEquals( | ||
| (long) Integer.MAX_VALUE, ToNumberFunction.toNumber(String.valueOf(Integer.MAX_VALUE), 10)); | ||
| assertEquals( | ||
| (long) Integer.MIN_VALUE, ToNumberFunction.toNumber(String.valueOf(Integer.MIN_VALUE), 10)); | ||
| } | ||
|
|
||
| @Test | ||
| void testToNumberCaseInsensitivity() { | ||
| assertEquals(255L, ToNumberFunction.toNumber("ff", 16)); | ||
| assertEquals(255L, ToNumberFunction.toNumber("FF", 16)); | ||
| assertEquals(255L, ToNumberFunction.toNumber("fF", 16)); | ||
| assertEquals(171L, ToNumberFunction.toNumber("ab", 16)); | ||
| assertEquals(171L, ToNumberFunction.toNumber("AB", 16)); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.