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);
+ }
+}