diff --git a/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/function/RoundFunction.java b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/function/RoundFunction.java new file mode 100644 index 00000000000..ecad4196352 --- /dev/null +++ b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/function/RoundFunction.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.inlong.sdk.transform.process.function; + +import org.apache.inlong.sdk.transform.decode.SourceData; +import org.apache.inlong.sdk.transform.process.Context; +import org.apache.inlong.sdk.transform.process.operator.OperatorTools; +import org.apache.inlong.sdk.transform.process.parser.ValueParser; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.expression.Function; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; + +/** + * RoundFunction + * description: ROUND(x [,y]) -- Return the nearest integer to x, with optional parameter y indicating the number of decimal places to be rounded. If omitted, return the integer. + */ +public class RoundFunction implements ValueParser { + + private ValueParser numberParser; + private ValueParser reservedDigitsParser; + + public RoundFunction(Function expr) { + List expressions = expr.getParameters().getExpressions(); + numberParser = OperatorTools.buildParser(expressions.get(0)); + if (expressions.size() == 2) { + reservedDigitsParser = OperatorTools.buildParser(expressions.get(1)); + } + } + + @Override + public Object parse(SourceData sourceData, int rowIndex, Context context) { + Object numberObj = numberParser.parse(sourceData, rowIndex, context); + BigDecimal number = OperatorTools.parseBigDecimal(numberObj); + if (reservedDigitsParser != null) { + Object reservedDigitsObj = reservedDigitsParser.parse(sourceData, rowIndex, context); + int reservedDigits = OperatorTools.parseBigDecimal(reservedDigitsObj).intValue(); + return number.setScale(reservedDigits, RoundingMode.HALF_UP).doubleValue(); + } + return Math.round(number.doubleValue()); + } +} diff --git a/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/OperatorTools.java b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/OperatorTools.java index 200c5b9d176..c9b0e1387b3 100644 --- a/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/OperatorTools.java +++ b/inlong-sdk/transform-sdk/src/main/java/org/apache/inlong/sdk/transform/process/operator/OperatorTools.java @@ -33,6 +33,7 @@ import org.apache.inlong.sdk.transform.process.function.LogFunction; import org.apache.inlong.sdk.transform.process.function.NowFunction; import org.apache.inlong.sdk.transform.process.function.PowerFunction; +import org.apache.inlong.sdk.transform.process.function.RoundFunction; import org.apache.inlong.sdk.transform.process.function.SinFunction; import org.apache.inlong.sdk.transform.process.function.SinhFunction; import org.apache.inlong.sdk.transform.process.function.SqrtFunction; @@ -127,6 +128,7 @@ public class OperatorTools { functionMap.put("second", func -> new TimestampExtractFunction(TimestampExtractFunction.TimestampExtractFunctionType.SECOND, func)); + functionMap.put("round", RoundFunction::new); functionMap.put("from_unixtime", FromUnixTimeFunction::new); functionMap.put("unix_timestamp", UnixTimestampFunction::new); functionMap.put("to_timestamp", ToTimestampFunction::new); diff --git a/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/TestTransformArithmeticFunctionsProcessor.java b/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/TestTransformArithmeticFunctionsProcessor.java index b8431460e5f..b55e76ec6f7 100644 --- a/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/TestTransformArithmeticFunctionsProcessor.java +++ b/inlong-sdk/transform-sdk/src/test/java/org/apache/inlong/sdk/transform/process/TestTransformArithmeticFunctionsProcessor.java @@ -41,6 +41,7 @@ public class TestTransformArithmeticFunctionsProcessor { private static final List dstFields = new ArrayList<>(); private static final CsvSourceInfo csvSource; private static final KvSinkInfo kvSink; + static { for (int i = 1; i < 5; i++) { FieldInfo field = new FieldInfo(); @@ -54,6 +55,36 @@ public class TestTransformArithmeticFunctionsProcessor { kvSink = new KvSinkInfo("UTF-8", dstFields); } + @Test + public void testRoundFunction() throws Exception { + String transformSql = "select round(numeric1) from source"; + TransformConfig config = new TransformConfig(transformSql); + // case1: round(3.14159265358979323846) + TransformProcessor processor = TransformProcessor + .create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + List output1 = processor.transform("3.14159265358979323846|4|6|8"); + Assert.assertEquals(1, output1.size()); + Assert.assertEquals(output1.get(0), "result=3"); + // case2: round(3.5) + List output2 = processor.transform("3.5|4|6|8"); + Assert.assertEquals(1, output2.size()); + Assert.assertEquals(output2.get(0), "result=4"); + + transformSql = "select round(numeric1,numeric2) from source"; + config = new TransformConfig(transformSql); + // case3: round(3.14159265358979323846,10) + processor = TransformProcessor.create(config, SourceDecoderFactory.createCsvDecoder(csvSource), + SinkEncoderFactory.createKvEncoder(kvSink)); + List output3 = processor.transform("3.14159265358979323846|10|6|8"); + Assert.assertEquals(1, output3.size()); + Assert.assertEquals(output3.get(0), "result=3.1415926536"); + // case4: round(13.14159265358979323846,-1) + List output4 = processor.transform("13.14159265358979323846|-1|6|8"); + Assert.assertEquals(1, output4.size()); + Assert.assertEquals(output4.get(0), "result=10.0"); + } + @Test public void testPowerFunction() throws Exception { String transformSql = "select power(numeric1, numeric2) from source";