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();

Reply via email to