Skip to content

Commit

Permalink
fix: avoid double precision in getBigDecimal
Browse files Browse the repository at this point in the history
If a column has the real type affinity and the value can be represented with the limited accuracy of a double, the function safeGetColumnType(checkCol(col)) evalutes to SQLITE_FLOAT. Getting the value using safeGetDoubleCol(col) causes an implicit conversion to a double. Since version 3.43.0 the sqlite source doesn't round the value anymore, but returned the value including the 8-byte IEEE floating point number inaccuracies. Somehow different operating systems behave differently. This explains, why the test only failed on Windows.
Using safeGetColumnText(col) avoids this lossy conversion.

Closes: xerial#1002
Co-authored-by: Gauthier Roebroeck <gauthier.roebroeck@gmail.com>
  • Loading branch information
InitFlo and gotson authored Oct 30, 2023
1 parent 4dba62c commit 8880c33
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/main/java/org/sqlite/jdbc3/JDBC3ResultSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,10 @@ public BigDecimal getBigDecimal(int col) throws SQLException {
switch (safeGetColumnType(checkCol(col))) {
case SQLITE_NULL:
return null;
case SQLITE_FLOAT:
return BigDecimal.valueOf(safeGetDoubleCol(col));
case SQLITE_INTEGER:
return BigDecimal.valueOf(safeGetLongCol(col));
case SQLITE_FLOAT:
// avoid double precision
default:
final String stringValue = safeGetColumnText(col);
try {
Expand Down
43 changes: 43 additions & 0 deletions src/test/java/org/sqlite/PrepStmtTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static org.assertj.core.data.Offset.offset;

import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.Date;
Expand Down Expand Up @@ -830,4 +831,46 @@ public void gh914_reuseExecute() throws SQLException {
assertThat(rs2).isNotNull();
}
}

@Test
public void gh1002_pi() throws SQLException {
BigDecimal pi = new BigDecimal("3.14");
stat.executeUpdate("create table gh1002(nr number(10,2))");

try (PreparedStatement ps = conn.prepareStatement("insert into gh1002 values (?)")) {
ps.setBigDecimal(1, pi);
ps.execute();
}

ResultSet rs = stat.executeQuery("select nr from gh1002");
assertThat(rs.getBigDecimal(1)).isEqualTo(pi);
}

@Test
public void gh1002_pi_real() throws SQLException {
BigDecimal pi = new BigDecimal("3.14");
stat.executeUpdate("create table gh1002(nr REAL)");

try (PreparedStatement ps = conn.prepareStatement("insert into gh1002 values (?)")) {
ps.setBigDecimal(1, pi);
ps.execute();
}

ResultSet rs = stat.executeQuery("select nr from gh1002");
assertThat(rs.getBigDecimal(1)).isEqualTo(pi);
}

@Test
public void gh1002_pi_text() throws SQLException {
BigDecimal pi = new BigDecimal("3.14");
stat.executeUpdate("create table gh1002(nr TEXT)");

try (PreparedStatement ps = conn.prepareStatement("insert into gh1002 values (?)")) {
ps.setBigDecimal(1, pi);
ps.execute();
}

ResultSet rs = stat.executeQuery("select nr from gh1002");
assertThat(rs.getBigDecimal(1)).isEqualTo(pi);
}
}

0 comments on commit 8880c33

Please sign in to comment.