This is an automated email from the ASF dual-hosted git repository.
SbloodyS pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new c70003c2aa [Fix-18713] Preserve numeric precision and normalize long
out parameters in sql task (#18716)
c70003c2aa is described below
commit c70003c2aa325a143e033e6b753ac7de30ec31a9
Author: xiangzihao <[email protected]>
AuthorDate: Fri Oct 16 20:51:22 2026 +0800
[Fix-18713] Preserve numeric precision and normalize long out parameters in
sql task (#18716)
---
.../plugin/task/api/parameters/SqlParameters.java | 25 ++++++--
.../task/api/parameters/SqlParametersTest.java | 75 ++++++++++++++++++++++
2 files changed, 95 insertions(+), 5 deletions(-)
diff --git
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java
index 32b110255c..6485658e85 100644
---
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java
+++
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParameters.java
@@ -19,6 +19,7 @@ package
org.apache.dolphinscheduler.plugin.task.api.parameters;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.plugin.task.api.SQLTaskExecutionContext;
+import org.apache.dolphinscheduler.plugin.task.api.TaskException;
import org.apache.dolphinscheduler.plugin.task.api.enums.DataType;
import org.apache.dolphinscheduler.plugin.task.api.enums.ResourceType;
import org.apache.dolphinscheduler.plugin.task.api.enums.SqlSourceType;
@@ -31,6 +32,7 @@ import
org.apache.dolphinscheduler.plugin.task.api.utils.VarPoolUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -38,12 +40,12 @@ import java.util.Map;
import java.util.Set;
import lombok.Data;
+import lombok.EqualsAndHashCode;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
-/**
- * Sql/Hql parameter
- */
+@EqualsAndHashCode(callSuper = true)
@Data
public class SqlParameters extends AbstractParameters {
@@ -131,7 +133,11 @@ public class SqlParameters extends AbstractParameters {
varPool = VarPoolUtils.mergeVarPool(Lists.newArrayList(varPool,
outProperty));
return;
}
- List<Map<String, String>> sqlResult = getListMapByString(result);
+ // Read numeric tokens directly as strings: a JsonNode round-trip can
convert
+ // scientific notation to double and lose precision before OUT type
conversion.
+ List<Map<String, String>> sqlResult = JSONUtils.parseObject(result,
+ new TypeReference<List<Map<String, String>>>() {
+ });
if (CollectionUtils.isEmpty(sqlResult)) {
return;
}
@@ -157,7 +163,16 @@ public class SqlParameters extends AbstractParameters {
// result only one line
Map<String, String> firstRow = sqlResult.get(0);
for (Property info : outProperty) {
- info.setValue(String.valueOf(firstRow.get(info.getProp())));
+ String value = String.valueOf(firstRow.get(info.getProp()));
+ if (info.getType() == DataType.LONG) {
+ try {
+ value = Long.toString(new
BigDecimal(value).longValueExact());
+ } catch (NumberFormatException | ArithmeticException e) {
+ throw new TaskException("Invalid SQL OUT parameter '"
+ info.getProp()
+ + "' of type LONG: '" + value + "' must be an
integer within the LONG range", e);
+ }
+ }
+ info.setValue(value);
}
}
varPool = VarPoolUtils.mergeVarPool(Lists.newArrayList(varPool,
outProperty));
diff --git
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParametersTest.java
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParametersTest.java
index b9388b3ba5..c7ee2de7ac 100644
---
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParametersTest.java
+++
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/test/java/org/apache/dolphinscheduler/plugin/task/api/parameters/SqlParametersTest.java
@@ -17,7 +17,9 @@
package org.apache.dolphinscheduler.plugin.task.api.parameters;
+import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.plugin.task.api.SQLTaskExecutionContext;
+import org.apache.dolphinscheduler.plugin.task.api.TaskException;
import org.apache.dolphinscheduler.plugin.task.api.enums.DataType;
import org.apache.dolphinscheduler.plugin.task.api.enums.Direct;
import org.apache.dolphinscheduler.plugin.task.api.enums.ResourceType;
@@ -28,11 +30,19 @@ import org.apache.dolphinscheduler.spi.enums.DbType;
import org.apache.commons.collections4.CollectionUtils;
+import java.math.BigDecimal;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
public class SqlParametersTest {
@@ -99,6 +109,71 @@ public class SqlParametersTest {
Assertions.assertFalse(CollectionUtils.isEmpty(sqlParameters.getResourceFilesList()));
}
+ @Test
+ public void testBigDecimalQueryResultProducesExactLongOutParameter() {
+ Property property = new Property();
+ property.setProp("SRC_CNT");
+ property.setDirect(Direct.OUT);
+ property.setType(DataType.LONG);
+ SqlParameters parameters = new SqlParameters();
+ parameters.setLocalParams(Collections.singletonList(property));
+
+ ArrayNode result = JSONUtils.createArrayNode();
+ ObjectNode row = JSONUtils.createObjectNode();
+ // This integer cannot be represented exactly as a double and becomes
+ // scientific notation after BigDecimal node normalization.
+ row.set("SRC_CNT", JSONUtils.toJsonNode(new
BigDecimal("90071992547409930")));
+ result.add(row);
+ parameters.dealOutParam(JSONUtils.toJsonString(result));
+
+ String value = parameters.getVarPool().get(0).getValue();
+ Assertions.assertEquals("90071992547409930", value);
+ Assertions.assertEquals(90071992547409930L, Long.parseLong(value));
+ }
+
+ @ParameterizedTest
+ @CsvSource({
+ "11423000,11423000",
+ "1.1423E+7,11423000",
+ "11423000.0,11423000",
+ "0,0",
+ "-1.1423E+7,-11423000",
+ "9.223372036854775807E+18,9223372036854775807",
+ "-9.223372036854775808E+18,-9223372036854775808",
+ "\"1.1423E7\",11423000"
+ })
+ public void testLongOutParameterNormalizesExactInteger(String jsonValue,
String expected) {
+ Property property = new Property();
+ property.setProp("SRC_CNT");
+ property.setDirect(Direct.OUT);
+ property.setType(DataType.LONG);
+ SqlParameters parameters = new SqlParameters();
+ parameters.setLocalParams(Collections.singletonList(property));
+
+ parameters.dealOutParam("[{\"SRC_CNT\":" + jsonValue + "}]");
+
+ Assertions.assertEquals(expected,
parameters.getVarPool().get(0).getValue());
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"1.5", "9223372036854775808",
"-9223372036854775809", "\"invalid\"", "null"})
+ public void testLongOutParameterRejectsInvalidValue(String jsonValue) {
+ Property property = new Property();
+ property.setProp("SRC_CNT");
+ property.setDirect(Direct.OUT);
+ property.setType(DataType.LONG);
+ SqlParameters parameters = new SqlParameters();
+ parameters.setLocalParams(Collections.singletonList(property));
+
+ TaskException exception = Assertions.assertThrows(TaskException.class,
+ () -> parameters.dealOutParam("[{\"SRC_CNT\":" + jsonValue +
"}]"));
+
+ Assertions.assertTrue(exception.getMessage().contains("SRC_CNT"));
+ Assertions.assertTrue(exception.getMessage().contains("LONG"));
+ Assertions.assertNotNull(exception.getCause());
+ Assertions.assertTrue(parameters.getVarPool().isEmpty());
+ }
+
@Test
public void testCheckParameters_variants() {
SqlParameters p = new SqlParameters();