This is an automated email from the ASF dual-hosted git repository.

corgy pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new 6e11285bf6 [Fix] [connector-jdbc] prevent precision loss in Float to 
BigDecimal conversion (#9670)
6e11285bf6 is described below

commit 6e11285bf63b03f802b56b4f7556e84b9e55a980
Author: zhenyue-xu <[email protected]>
AuthorDate: Mon Aug 11 01:09:48 2025 +0800

    [Fix] [connector-jdbc] prevent precision loss in Float to BigDecimal 
conversion (#9670)
---
 .../seatunnel/jdbc/source/FixedChunkSplitter.java  |  2 +-
 .../seatunnel/jdbc/utils/ObjectUtils.java          |  4 +-
 .../jdbc/source/FixedChunkSplitterTest.java        | 86 ++++++++++++++++++++++
 .../seatunnel/jdbc/utils/ObjectUtilsTest.java      | 66 +++++++++++++++++
 4 files changed, 155 insertions(+), 3 deletions(-)

diff --git 
a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/source/FixedChunkSplitter.java
 
b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/source/FixedChunkSplitter.java
index 1509bdfc2b..dfc147cb38 100644
--- 
a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/source/FixedChunkSplitter.java
+++ 
b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/source/FixedChunkSplitter.java
@@ -387,7 +387,7 @@ public class FixedChunkSplitter extends ChunkSplitter {
         } else if (o instanceof Boolean) {
             return BigDecimal.valueOf((Boolean) o ? 1 : 0);
         } else if (o instanceof Float) {
-            return BigDecimal.valueOf((Float) o);
+            return new BigDecimal(o.toString());
         } else if (o instanceof Byte) {
             return BigDecimal.valueOf((Byte) o);
         } else if (o instanceof Short) {
diff --git 
a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/utils/ObjectUtils.java
 
b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/utils/ObjectUtils.java
index f178a83ea2..8c0c2e7068 100644
--- 
a/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/utils/ObjectUtils.java
+++ 
b/seatunnel-connectors-v2/connector-jdbc/src/main/java/org/apache/seatunnel/connectors/seatunnel/jdbc/utils/ObjectUtils.java
@@ -67,8 +67,8 @@ public class ObjectUtils {
             return BigDecimal.valueOf((long) minuend)
                     .subtract(BigDecimal.valueOf((long) subtrahend));
         } else if (minuend instanceof Float) {
-            return BigDecimal.valueOf((float) minuend)
-                    .subtract(BigDecimal.valueOf((float) subtrahend));
+            return new BigDecimal(minuend.toString())
+                    .subtract(new BigDecimal(subtrahend.toString()));
         } else if (minuend instanceof Double) {
             return BigDecimal.valueOf((double) minuend)
                     .subtract(BigDecimal.valueOf((double) subtrahend));
diff --git 
a/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/source/FixedChunkSplitterTest.java
 
b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/source/FixedChunkSplitterTest.java
new file mode 100644
index 0000000000..d36e8aaa1f
--- /dev/null
+++ 
b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/source/FixedChunkSplitterTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.source;
+
+import 
org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcConnectionConfig;
+import org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcSourceConfig;
+
+import org.junit.jupiter.api.Test;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+@Slf4j
+public class FixedChunkSplitterTest {
+
+    @Test
+    public void testConvertFloat() throws Exception {
+        JdbcSourceConfig config =
+                JdbcSourceConfig.builder()
+                        .jdbcConnectionConfig(
+                                JdbcConnectionConfig.builder()
+                                        
.url("jdbc:postgresql://localhost:5432/test")
+                                        .driverName("org.postgresql.Driver")
+                                        .build())
+                        .build();
+
+        FixedChunkSplitter splitter = new FixedChunkSplitter(config);
+
+        // Use reflection to access private method
+        Method convertToBigDecimalMethod =
+                
FixedChunkSplitter.class.getDeclaredMethod("convertToBigDecimal", Object.class);
+        convertToBigDecimalMethod.setAccessible(true);
+
+        // Test precision-sensitive Float values
+        Float testFloat = 123.456f;
+        BigDecimal result = (BigDecimal) 
convertToBigDecimalMethod.invoke(splitter, testFloat);
+
+        // Verify that using toString() method prevents precision loss
+        BigDecimal expected = new BigDecimal(testFloat.toString());
+        assertEquals(expected, result);
+
+        // Verify the difference from the old method (this test should 
demonstrate the fix
+        // necessity)
+        BigDecimal oldWay = BigDecimal.valueOf(testFloat);
+        assertNotEquals(oldWay, result);
+
+        // Test boundary values
+        Float maxFloat = Float.MAX_VALUE;
+        BigDecimal maxResult = (BigDecimal) 
convertToBigDecimalMethod.invoke(splitter, maxFloat);
+        assertEquals(new BigDecimal(maxFloat.toString()), maxResult);
+
+        Float minFloat = Float.MIN_VALUE;
+        BigDecimal minResult = (BigDecimal) 
convertToBigDecimalMethod.invoke(splitter, minFloat);
+        assertEquals(new BigDecimal(minFloat.toString()), minResult);
+
+        // Test values that better demonstrate precision issues
+        Float precisionTestFloat = 0.1f;
+        BigDecimal precisionResult =
+                (BigDecimal) convertToBigDecimalMethod.invoke(splitter, 
precisionTestFloat);
+        assertEquals(new BigDecimal("0.1"), precisionResult);
+
+        // Verify that the old method indeed has precision issues
+        BigDecimal oldPrecisionWay = BigDecimal.valueOf(precisionTestFloat);
+        assertNotEquals(new BigDecimal("0.1"), oldPrecisionWay);
+    }
+}
diff --git 
a/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/utils/ObjectUtilsTest.java
 
b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/utils/ObjectUtilsTest.java
new file mode 100644
index 0000000000..a6153d1b00
--- /dev/null
+++ 
b/seatunnel-connectors-v2/connector-jdbc/src/test/java/org/apache/seatunnel/connectors/seatunnel/jdbc/utils/ObjectUtilsTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.seatunnel.connectors.seatunnel.jdbc.utils;
+
+import org.junit.jupiter.api.Test;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.math.BigDecimal;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+@Slf4j
+public class ObjectUtilsTest {
+    @Test
+    public void testObjectUtilsMinusWithFloat() throws Exception {
+        // Test precision-sensitive Float values
+        Float minuend = 123.456f;
+        Float subtrahend = 23.456f;
+
+        BigDecimal result = ObjectUtils.minus(minuend, subtrahend);
+
+        // Verify that using toString() method prevents precision loss
+        BigDecimal expected =
+                new BigDecimal(minuend.toString()).subtract(new 
BigDecimal(subtrahend.toString()));
+        assertEquals(expected, result);
+
+        // Verify the difference from the old method (this test should 
demonstrate the fix
+        // necessity)
+        BigDecimal oldMinuend = BigDecimal.valueOf(minuend);
+        BigDecimal oldSubtrahend = BigDecimal.valueOf(subtrahend);
+        BigDecimal oldWay = oldMinuend.subtract(oldSubtrahend);
+        assertNotEquals(oldWay, result);
+
+        // Test values that better demonstrate precision issues
+        Float precisionMinuend = 0.3f;
+        Float precisionSubtrahend = 0.1f;
+        BigDecimal precisionResult = ObjectUtils.minus(precisionMinuend, 
precisionSubtrahend);
+        BigDecimal precisionExpected =
+                new BigDecimal(precisionMinuend.toString())
+                        .subtract(new 
BigDecimal(precisionSubtrahend.toString()));
+        assertEquals(precisionExpected, precisionResult);
+
+        // Verify that the old method indeed has precision issues
+        BigDecimal oldPrecisionWay =
+                BigDecimal.valueOf(precisionMinuend)
+                        .subtract(BigDecimal.valueOf(precisionSubtrahend));
+        assertNotEquals(oldPrecisionWay, precisionResult);
+    }
+}

Reply via email to