Skip to content

Commit

Permalink
JDBC-462 Fix FBBigDecimal, unsupported field sqltype: 481 with large …
Browse files Browse the repository at this point in the history
…numeric in dialect 1
  • Loading branch information
mrotteveel committed Nov 28, 2016
1 parent fe9a9ba commit c9497c0
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 30 deletions.
25 changes: 22 additions & 3 deletions src/main/org/firebirdsql/jdbc/field/FBBigDecimalField.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/*
* $Id$
*
* Firebird Open Source JavaEE Connector - JDBC Driver
*
* Distributable under LGPL license.
Expand Down Expand Up @@ -44,6 +42,9 @@ final class FBBigDecimalField extends FBField {
private static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
private static final BigInteger MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE);

private static final BigDecimal BD_MAX_DOUBLE = new BigDecimal(MAX_DOUBLE_VALUE);
private static final BigDecimal BD_MIN_DOUBLE = new BigDecimal(MIN_DOUBLE_VALUE);

private final FieldDataSize fieldDataSize;

FBBigDecimalField(FieldDescriptor fieldDescriptor, FieldDataProvider dataProvider, int requiredType)
Expand Down Expand Up @@ -248,6 +249,23 @@ protected byte[] encode(FieldDescriptor fieldDescriptor, BigDecimal value) throw
}
return fieldDescriptor.getDatatypeCoder().encodeLong(unscaledValue.longValue());
}
},
DOUBLE {
@Override
protected BigDecimal decode(FieldDescriptor fieldDescriptor, byte[] fieldData) {
BigDecimal value = new BigDecimal(fieldDescriptor.getDatatypeCoder().decodeDouble(fieldData));
return value.setScale(Math.abs(fieldDescriptor.getScale()), BigDecimal.ROUND_HALF_EVEN);
}

@Override
protected byte[] encode(FieldDescriptor fieldDescriptor, BigDecimal value) throws SQLException {
// check if value is within bounds
if (value.compareTo(BD_MAX_DOUBLE) > 0 ||
value.compareTo(BD_MIN_DOUBLE) < 0)
throw new TypeConversionException(DOUBLE_CONVERSION_ERROR + " " + value);

return fieldDescriptor.getDatatypeCoder().encodeDouble(value.doubleValue());
}
};

/**
Expand Down Expand Up @@ -303,8 +321,9 @@ protected static FieldDataSize getFieldDataSize(FieldDescriptor fieldDescriptor)
return INTEGER;
case ISCConstants.SQL_INT64:
return LONG;
case ISCConstants.SQL_DOUBLE:
return DOUBLE;
default:
// TODO Handle type double (dialect 1)
// TODO Throw exception
return null;
}
Expand Down
19 changes: 2 additions & 17 deletions src/main/org/firebirdsql/jdbc/field/FBDoubleField.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,28 +109,13 @@ public float getFloat() throws SQLException {
public double getDouble() throws SQLException {
if (isNull()) return DOUBLE_NULL_VALUE;

double result = getDatatypeCoder().decodeDouble(getFieldData());

// TODO Is this even possible? Wouldn't it be seen as a FBBigDecimalField ?
// TODO Mismatch with all other getters
if (fieldDescriptor.getScale() != 0) {
BigDecimal tempValue = new BigDecimal(result);
tempValue = tempValue.setScale(Math.abs(fieldDescriptor.getScale()), BigDecimal.ROUND_HALF_EVEN);
result = tempValue.doubleValue();
}

return result;
return getDatatypeCoder().decodeDouble(getFieldData());
}

public BigDecimal getBigDecimal() throws SQLException {
if (isNull()) return null;

BigDecimal result = new BigDecimal(getDatatypeCoder().decodeDouble(getFieldData()));
// TODO Is this even possible? Wouldn't it be seen as a FBBigDecimalField ?
if (fieldDescriptor.getScale() != 0)
result = result.setScale(Math.abs(fieldDescriptor.getScale()), BigDecimal.ROUND_HALF_EVEN);

return result;
return new BigDecimal(getDatatypeCoder().decodeDouble(getFieldData()));
}

public boolean getBoolean() throws SQLException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,29 @@
*/
package org.firebirdsql.jdbc;

import org.firebirdsql.common.FBJUnit4TestBase;
import org.firebirdsql.common.DdlHelper;
import org.firebirdsql.gds.ISCConstants;
import org.firebirdsql.gds.impl.GDSType;
import org.firebirdsql.management.FBManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.math.BigDecimal;
import java.sql.*;
import java.util.Properties;

import static org.firebirdsql.common.DdlHelper.executeCreateTable;
import static org.firebirdsql.common.FBTestProperties.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;

/**
* Tests for updatable result sets with a dialect 1 database.
* Tests for specific behavior in dialect 1 databases.
*
* @author <a href="mailto:[email protected]">Mark Rotteveel</a>
* @since 2.2
*/
public class TestResultSetDialect1 extends FBJUnit4TestBase {
public class TestDialect1Specifics {

//@formatter:off
public static final String CREATE_TABLE_STATEMENT =
Expand All @@ -54,10 +54,10 @@ public class TestResultSetDialect1 extends FBJUnit4TestBase {
public static final String INSERT_INTO_TABLE_STATEMENT = "INSERT INTO test_table (id, str) VALUES(?, ?)";
//@formatter:on

private FBManager fbManager;
private Connection connection;

@Before
@Override
public void basicSetUp() throws Exception {
fbManager = createFBManager();

Expand All @@ -74,12 +74,9 @@ public void basicSetUp() throws Exception {
final Properties properties = getDefaultPropertiesForConnection();
properties.setProperty("sql_dialect", String.valueOf(ISCConstants.SQL_DIALECT_V5));
connection = DriverManager.getConnection(getUrl(), properties);

executeCreateTable(connection, CREATE_TABLE_STATEMENT);
}

@After
@Override
public void basicTearDown() throws Exception {
try {
connection.close();
Expand Down Expand Up @@ -164,7 +161,35 @@ public void testDeleteRow() throws Exception {
}
}

@Test
public void testGetDoubleNumeric() throws Exception {
DdlHelper.executeCreateTable(connection, "create table testnumeric (id integer primary key, numericvalue numeric(18,2))");
try (Statement stmt = connection.createStatement()) {
stmt.executeUpdate("insert into testnumeric(id, numericvalue) values(1, 34.01)");
try (ResultSet rs = stmt.executeQuery("select * from testnumeric")) {
assertTrue("Expected a row", rs.next());
assertEquals(new BigDecimal("34.01"), rs.getBigDecimal("numericvalue"));
}
}
}

@Test
public void testSetDoubleNumeric() throws Exception {
DdlHelper.executeCreateTable(connection, "create table testnumeric (id integer primary key, numericvalue numeric(18,2))");
try (PreparedStatement pstmt = connection.prepareStatement("insert into testnumeric(id, numericvalue) values(1, ?)")) {
pstmt.setBigDecimal(1, new BigDecimal("34.01242323234"));
pstmt.executeUpdate();
}

try (Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("select cast(numericvalue as varchar(50)) as numericvalue from testnumeric")) {
assertTrue("Expected a row", rs.next());
assertEquals("34.01", rs.getString("numericvalue"));
}
}

private void createTestData(int recordCount) throws Exception {
executeCreateTable(connection, CREATE_TABLE_STATEMENT);
connection.setAutoCommit(false);
try (PreparedStatement ps = connection.prepareStatement(INSERT_INTO_TABLE_STATEMENT)) {
for (int i = 0; i < recordCount; i++) {
Expand Down

0 comments on commit c9497c0

Please sign in to comment.