Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
103 commits
Select commit Hold shift + click to select a range
0ed23de
PPL tostring() implementation issue #4492
asifabashar Oct 16, 2025
5a5b778
removed sql changes
asifabashar Oct 16, 2025
9d71a95
doc changes
asifabashar Oct 16, 2025
be2c2e2
docs changes
asifabashar Oct 16, 2025
fc763a4
reverted string doc changes
asifabashar Oct 16, 2025
a04eb14
removed extra word
asifabashar Oct 16, 2025
590a8e6
added any type
asifabashar Oct 16, 2025
6938e2c
doc formatting fixes
asifabashar Oct 16, 2025
314fccd
description for boolean example
asifabashar Oct 16, 2025
0ee17b9
added format_time call from calcite , added duration_millis as splunk…
asifabashar Oct 17, 2025
6e24aa3
added doc update to specifically set 2nd argument as optional
asifabashar Oct 17, 2025
454cfc8
mentioned as value instead of number specifically
asifabashar Oct 17, 2025
b221e8c
fixed wrong bullet point
asifabashar Oct 17, 2025
a0a89c4
issue #4514 tonumber function as part of roadmap #4287
asifabashar Oct 20, 2025
ea9ba0f
added more unit tests
asifabashar Oct 20, 2025
370b9bc
Update docs/user/ppl/functions/conversion.rst
asifabashar Oct 22, 2025
f070684
fix per recommendation
asifabashar Oct 22, 2025
a2accf5
updated recommended changes
asifabashar Oct 22, 2025
3adda5d
updated recommended changes
asifabashar Oct 22, 2025
17b1d86
updated recommended changes
asifabashar Oct 22, 2025
eca7d13
updated recommended changes
asifabashar Oct 22, 2025
e780c15
updated recommended changes
asifabashar Oct 22, 2025
e3884b0
updated recommended changes
asifabashar Oct 22, 2025
042d3e8
spotless apply
asifabashar Oct 22, 2025
38ce420
merge conflict fix
asifabashar Oct 28, 2025
58d8e1b
merge conflict fix
asifabashar Oct 28, 2025
34f8635
added recommended changes
asifabashar Nov 2, 2025
8279bf3
fixed doctest for conversion.rst and applied spotless
asifabashar Nov 5, 2025
b5346a6
removed decimal point from hex
asifabashar Nov 5, 2025
7cf867b
added doctest fixes
asifabashar Nov 5, 2025
8d9db4e
fixed merged conflicts
asifabashar Nov 6, 2025
46f010b
removed unused variables
asifabashar Nov 6, 2025
b7afa17
spotless
asifabashar Nov 6, 2025
0f0125a
made recommended changes to simply parse to number, null when malformed
asifabashar Nov 6, 2025
804db79
hex max limit doc and unit tests
asifabashar Nov 9, 2025
7588397
fix to spotless
asifabashar Nov 9, 2025
016f8f8
Support script pushdown in sort-on-measure pushdown rewriting (#4749)
LantaoJin Nov 6, 2025
663049d
Support `chart` command in PPL (#4579)
yuancu Nov 7, 2025
b839904
Support push down sort on aggregation measure for more than one agg …
LantaoJin Nov 10, 2025
5211d70
Adding IT suite for PPL-based dashboards in Neo for CloudWatch Lake (…
aalva500-prog Nov 10, 2025
1da0ff4
[Maintenance] Enforce PR label of 'bugFix' instead of 'bug' (#4773)
RyanL1997 Nov 10, 2025
5935ef8
Update github workflows to move from macos-13 to 14 (#4779)
ykmr1224 Nov 11, 2025
8875371
Fix binning udf resolution / Add type coercion support for binning UD…
ahkcs Nov 11, 2025
efec652
Support `appendpipe`command in PPL (#4602)
xinyual Nov 12, 2025
226d685
Add `regexp_replace()` function as alias of `replace()` (#4765)
LantaoJin Nov 12, 2025
0050b31
Translate SAFE_CAST to TRY_CAST in Spark SQL (#4788)
LantaoJin Nov 12, 2025
772e4b6
Merge the implementation of `timechart` and `chart` (#4755)
yuancu Nov 12, 2025
31a74a4
added IT , add null cases, fixed format for integer/big integer
asifabashar Nov 19, 2025
a42d6aa
added IT , add null cases, fixed format for integer/big integer
asifabashar Nov 19, 2025
1ecbbbb
added IT , add null cases, fixed format for integer/big integer
asifabashar Nov 19, 2025
188a28e
spotless apply
asifabashar Nov 20, 2025
c26261b
spotless apply
asifabashar Nov 20, 2025
f30488a
fix javadoc
asifabashar Nov 25, 2025
1ae5665
fix doc to add null value return condition details
asifabashar Nov 25, 2025
dde1996
spotless
asifabashar Nov 25, 2025
b7985fe
Revert "added IT , add null cases, fixed format for integer/big integer"
asifabashar Dec 9, 2025
740dc90
for all cases, return double
asifabashar Dec 9, 2025
aac7a10
unit test
asifabashar Dec 9, 2025
f442d87
Fix bug that `Streamstats` command incorrectly treats null as a valid…
ishaoxy Nov 13, 2025
62849d5
Support using decimal as span literals (#4717)
yuancu Nov 13, 2025
16281d7
Support mvindex eval function (#4794)
ahkcs Nov 13, 2025
2fc072d
Fix function identify problem in converting to sql dialect (#4793)
LantaoJin Nov 14, 2025
4766b93
Reduce RelCompositeTrait of RelCollation to a single collation when c…
yuancu Nov 14, 2025
9fabc44
Fix UT failure and Linkchecker failure (#4809)
LantaoJin Nov 14, 2025
7cd911e
doc update (#4803)
ahkcs Nov 14, 2025
09af1b2
Pushdown sort by complex expressions to scan (#4750)
songkant-aws Nov 18, 2025
b45b9f5
Support escaped field names in SPath parsing (#4813)
Swiddis Nov 18, 2025
0263d58
Perform RexNode expression standardization for script push down. (#4795)
qianheng-aws Nov 19, 2025
b47b7d6
Update PPL Command Documentation (#4562)
ritvibhatt Nov 19, 2025
780e6c3
add bucket_nullable for eventstats (#4817)
ishaoxy Nov 19, 2025
f0cba5a
added missing expected output for explain test
asifabashar Dec 6, 2025
39cbebe
Revert "added missing expected output for explain test"
asifabashar Dec 6, 2025
34eeb4a
[3.4.0] Bump Gradle to 9.2.0 and GitHub Action JDK to 25 (#4824)
LantaoJin Nov 20, 2025
cdb15fa
Execute yamlRestTest in integration job (#4838)
ykmr1224 Nov 21, 2025
53d9299
Fix search anoymizer only (#4783)
xinyual Nov 21, 2025
dc98a90
Fix the flaky CalcitePPLTcphIT (#4846)
LantaoJin Nov 24, 2025
dee22bb
Remove redundant push-down-filters derived for bucket-non-null agg (#…
qianheng-aws Nov 24, 2025
18d506a
Grouping key field type can only be overwritten when the ExprCoreType…
LantaoJin Nov 24, 2025
a85c343
Support `mvdedup` eval function (#4828)
ahkcs Nov 24, 2025
2b8992a
Update syntax: like(string, PATTERN[, case_sensitive]) (#4837)
LantaoJin Nov 25, 2025
9ecd4a9
Add `bucket_nullable` argument for `Streamstats` command (#4831)
ishaoxy Nov 26, 2025
5c2f50b
Specify timestamp field with `timefield` in timechart command (#4784)
yuancu Nov 26, 2025
9f30669
Convert `dedup` pushdown to composite + top_hits (#4844)
LantaoJin Nov 26, 2025
f348e99
fix clickbench query 43 (#4861)
xinyual Nov 26, 2025
16b0e9b
Remove count aggregation for sort on aggregate measure (#4867)
LantaoJin Nov 27, 2025
b366994
Fix wrong parameter and return result logic for LogPatternAggFunction…
songkant-aws Nov 27, 2025
12af315
Remove unnecessary filter for DateHistogram aggregation (#4877)
LantaoJin Nov 28, 2025
aa4bfa8
Refactor alias type field by adding another project with alias (#4881)
qianheng-aws Nov 28, 2025
8e24881
Implement one-batch lookahead for index enumerators (#4345)
Swiddis Dec 1, 2025
b69d8de
Add hashCode() and equals() to the implmentation classes of ExprJavaT…
LantaoJin Dec 2, 2025
2682804
Add config for CodeRabbit review (#4890)
ykmr1224 Dec 2, 2025
a85aead
Support timeouts for Calcite queries (#4857)
Swiddis Dec 2, 2025
6bd6b50
[BugFix] Fix Memory Exhaustion for Multiple Filtering Operations in P…
RyanL1997 Dec 2, 2025
7ace206
Adjust CodeRabbit review config (#4901)
ykmr1224 Dec 4, 2025
58025be
Remove access controller step in Calcite script (#4900)
Swiddis Dec 4, 2025
e9700d5
Error handling for dot-containing field names (#4907)
ahkcs Dec 5, 2025
37a0256
Support composite aggregation paginating (#4884)
LantaoJin Dec 8, 2025
e4b5d93
Add unified query transpiler API (#4871)
dai-chen Dec 8, 2025
01527f0
Support `split` eval function (#4814)
ahkcs Dec 8, 2025
2943826
Add workflow for SQL CLI integration tests (#4770)
Swiddis Dec 9, 2025
3ffd8eb
Migrate PPL Documentation from RST to Markdown (#4912)
kylehounslow Dec 9, 2025
b34e374
merged main branch
asifabashar Dec 10, 2025
e5edbad
Merge branch 'main' into feature_tonumber
asifabashar Dec 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ private PPLOperandTypes() {}
UDFOperandMetadata.wrap(
OperandTypes.family(
SqlTypeFamily.CHARACTER, SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER));

public static final UDFOperandMetadata STRING_OR_STRING_INTEGER =
UDFOperandMetadata.wrap(
(CompositeOperandTypeChecker)
OperandTypes.family(SqlTypeFamily.CHARACTER)
.or(OperandTypes.family(SqlTypeFamily.CHARACTER, SqlTypeFamily.INTEGER)));

public static final UDFOperandMetadata STRING_STRING_INTEGER_INTEGER =
UDFOperandMetadata.wrap(
OperandTypes.family(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public enum BuiltinFunctionName {

/** Text Functions. */
TOSTRING(FunctionName.of("tostring")),
TONUMBER(FunctionName.of("tonumber")),

/** IP Functions. */
CIDRMATCH(FunctionName.of("cidrmatch")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
import org.opensearch.sql.expression.function.udf.RexExtractMultiFunction;
import org.opensearch.sql.expression.function.udf.RexOffsetFunction;
import org.opensearch.sql.expression.function.udf.SpanFunction;
import org.opensearch.sql.expression.function.udf.ToNumberFunction;
import org.opensearch.sql.expression.function.udf.ToStringFunction;
import org.opensearch.sql.expression.function.udf.condition.EarliestFunction;
import org.opensearch.sql.expression.function.udf.condition.EnhancedCoalesceFunction;
Expand Down Expand Up @@ -412,6 +413,7 @@ public class PPLBuiltinOperators extends ReflectiveSqlOperatorTable {
RELEVANCE_QUERY_FUNCTION_INSTANCE.toUDF("multi_match", false);
public static final SqlOperator NUMBER_TO_STRING =
new NumberToStringFunction().toUDF("NUMBER_TO_STRING");
public static final SqlOperator TONUMBER = new ToNumberFunction().toUDF("TONUMBER");
public static final SqlOperator TOSTRING = new ToStringFunction().toUDF("TOSTRING");
public static final SqlOperator WIDTH_BUCKET =
new org.opensearch.sql.expression.function.udf.binning.WidthBucketFunction()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@
import static org.opensearch.sql.expression.function.BuiltinFunctionName.TIMESTAMPDIFF;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.TIME_FORMAT;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.TIME_TO_SEC;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.TONUMBER;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.TOSTRING;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.TO_DAYS;
import static org.opensearch.sql.expression.function.BuiltinFunctionName.TO_SECONDS;
Expand Down Expand Up @@ -974,6 +975,7 @@ void populate() {
registerOperator(WEEKOFYEAR, PPLBuiltinOperators.WEEK);

registerOperator(INTERNAL_PATTERN_PARSER, PPLBuiltinOperators.PATTERN_PARSER);
registerOperator(TONUMBER, PPLBuiltinOperators.TONUMBER);
registerOperator(TOSTRING, PPLBuiltinOperators.TOSTRING);
register(
TOSTRING,
Expand Down Expand Up @@ -1191,7 +1193,6 @@ void populate() {
SqlTypeFamily.INTEGER,
SqlTypeFamily.INTEGER)),
false));

register(
LOG,
(FunctionImp2)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* 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;

/**
* The following usage options are available, depending on the parameter types and the number of
* parameters.
*
* <p><b>Usage:</b> {@code tonumber(string, [base])} converts the value in the first argument. The
* second argument describes the base of the first argument. If the second argument is not provided,
* the value is converted using base 10.
*
* <p><b>Return type:</b> Number
*
* <p>You can use this function with the eval commands and as part of eval expressions.
*
* <p>Base values can range from 2 to 36. The maximum value supported for base 10 is {@code +(2 −
* 2^-52) · 2^1023} and the minimum is {@code −(2 − 2^-52) · 2^1023}.
*
* <p>The maximum for other supported bases is {@code 2^63 − 1} (or {@code 7FFFFFFFFFFFFFFF}) and
* the minimum is {@code -2^63} (or {@code -7FFFFFFFFFFFFFFF}).
*/
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();
}
} catch (Exception e) {

}
return result;
}
}
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));
}
}
Loading
Loading