IGNITE-6130 JDBC thin driver: implemented type conversions. This closes #2510.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/74f8638a Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/74f8638a Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/74f8638a Branch: refs/heads/ignite-3478 Commit: 74f8638a18c365e0adbfe62c94dd941fb7eb35ff Parents: adec3e7 Author: tledkov-gridgain <[email protected]> Authored: Wed Sep 6 18:42:22 2017 +0300 Committer: devozerov <[email protected]> Committed: Wed Sep 6 18:42:22 2017 +0300 ---------------------------------------------------------------------- .../thin/JdbcThinPreparedStatementSelfTest.java | 6 - .../jdbc/thin/JdbcThinResultSetSelfTest.java | 278 +++++++-- .../jdbc/thin/JdbcThinPreparedStatement.java | 4 +- .../internal/jdbc/thin/JdbcThinResultSet.java | 575 ++++++++++++------- 4 files changed, 602 insertions(+), 261 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/74f8638a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java index 64aafd3..85eb1d3 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinPreparedStatementSelfTest.java @@ -925,12 +925,6 @@ public class JdbcThinPreparedStatementSelfTest extends JdbcThinAbstractSelfTest checkNotSupported(new RunnableX() { @Override public void run() throws Exception { - stmt.setNString(1, ""); - } - }); - - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { stmt.setRowId(1, null); } }); http://git-wip-us.apache.org/repos/asf/ignite/blob/74f8638a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java index 3fb8f0e..76eb5bc 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java @@ -156,7 +156,7 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { o.floatVal = 1.0f; o.doubleVal = 1.0d; o.bigVal = new BigDecimal(1); - o.strVal = "str"; + o.strVal = "1.0"; o.arrVal = new byte[] {1}; o.dateVal = new Date(1, 1, 1); o.timeVal = new Time(1, 1, 1); @@ -178,6 +178,24 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { if (cnt == 0) { assert rs.getBoolean("boolVal"); assert rs.getBoolean(2); + assert rs.getByte(2) == 1; + assert rs.getInt(2) == 1; + assert rs.getShort(2) == 1; + assert rs.getLong(2) == 1; + assert rs.getDouble(2) == 1.0; + assert rs.getFloat(2) == 1.0f; + assert rs.getBigDecimal(2).equals(new BigDecimal(1)); + assert rs.getString(2).equals("true"); + + assert rs.getObject(2, Boolean.class); + assert rs.getObject(2, Byte.class) == 1; + assert rs.getObject(2, Short.class) == 1; + assert rs.getObject(2, Integer.class) == 1; + assert rs.getObject(2, Long.class) == 1; + assert rs.getObject(2, Float.class) == 1.f; + assert rs.getObject(2, Double.class) == 1; + assert rs.getObject(2, BigDecimal.class).equals(new BigDecimal(1)); + assert rs.getObject(2, String.class).equals("true"); } cnt++; @@ -185,7 +203,6 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { assert cnt == 1; - ResultSet rs0 = stmt.executeQuery("select 1"); assert rs0.next(); @@ -208,28 +225,6 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { @Override public Void call() throws Exception { - ResultSet rs0 = stmt.executeQuery("select 10"); - - assert rs0.next(); - assert rs0.getBoolean(1); - - return null; - } - }, ClassCastException.class, "Cannot cast java.lang.Integer [val=10] to boolean"); - - GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { - @Override public Void call() throws Exception { - ResultSet rs0 = stmt.executeQuery("select '10'"); - - assert rs0.next(); - assert rs0.getBoolean(1); - - return null; - } - }, ClassCastException.class, "Cannot cast java.lang.Integer [val=10] to boolean"); - - GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { - @Override public Void call() throws Exception { ResultSet rs0 = stmt.executeQuery("select ''"); assert rs0.next(); @@ -237,7 +232,7 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { return null; } - }, ClassCastException.class, "Cannot cast [val=] to boolean"); + }, SQLException.class, "Cannot convert to boolean: "); GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() { @Override public Void call() throws Exception { @@ -248,7 +243,7 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { return null; } - }, ClassCastException.class, "Cannot cast [val=qwe] to boolean"); + }, SQLException.class, "Cannot convert to boolean: qwe"); } /** @@ -262,7 +257,26 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getByte("byteVal") == 1; + + assert rs.getBoolean(3); assert rs.getByte(3) == 1; + assert rs.getInt(3) == 1; + assert rs.getShort(3) == 1; + assert rs.getLong(3) == 1; + assert rs.getDouble(3) == 1.0; + assert rs.getFloat(3) == 1.0f; + assert rs.getBigDecimal(3).equals(new BigDecimal(1)); + assert rs.getString(3).equals("1"); + + assert rs.getObject(3, Boolean.class); + assert rs.getObject(3, Byte.class) == 1; + assert rs.getObject(3, Short.class) == 1; + assert rs.getObject(3, Integer.class) == 1; + assert rs.getObject(3, Long.class) == 1; + assert rs.getObject(3, Float.class) == 1.f; + assert rs.getObject(3, Double.class) == 1; + assert rs.getObject(3, BigDecimal.class).equals(new BigDecimal(1)); + assert rs.getObject(3, String.class).equals("1"); } cnt++; @@ -282,7 +296,26 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getShort("shortVal") == 1; + + assert rs.getBoolean(4); + assert rs.getByte(4) == 1; assert rs.getShort(4) == 1; + assert rs.getInt(4) == 1; + assert rs.getLong(4) == 1; + assert rs.getDouble(4) == 1.0; + assert rs.getFloat(4) == 1.0f; + assert rs.getBigDecimal(4).equals(new BigDecimal(1)); + assert rs.getString(4).equals("1"); + + assert rs.getObject(4, Boolean.class); + assert rs.getObject(4, Byte.class) == 1; + assert rs.getObject(4, Short.class) == 1; + assert rs.getObject(4, Integer.class) == 1; + assert rs.getObject(4, Long.class) == 1; + assert rs.getObject(4, Float.class) == 1.f; + assert rs.getObject(4, Double.class) == 1; + assert rs.getObject(4, BigDecimal.class).equals(new BigDecimal(1)); + assert rs.getObject(4, String.class).equals("1"); } cnt++; @@ -302,7 +335,26 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getInt("intVal") == 1; + + assert rs.getBoolean(5); + assert rs.getByte(5) == 1; + assert rs.getShort(5) == 1; assert rs.getInt(5) == 1; + assert rs.getLong(5) == 1; + assert rs.getDouble(5) == 1.0; + assert rs.getFloat(5) == 1.0f; + assert rs.getBigDecimal(5).equals(new BigDecimal(1)); + assert rs.getString(5).equals("1"); + + assert rs.getObject(5, Boolean.class); + assert rs.getObject(5, Byte.class) == 1; + assert rs.getObject(5, Short.class) == 1; + assert rs.getObject(5, Integer.class) == 1; + assert rs.getObject(5, Long.class) == 1; + assert rs.getObject(5, Float.class) == 1.f; + assert rs.getObject(5, Double.class) == 1; + assert rs.getObject(5, BigDecimal.class).equals(new BigDecimal(1)); + assert rs.getObject(5, String.class).equals("1"); } cnt++; @@ -322,7 +374,26 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getLong("longVal") == 1; + + assert rs.getBoolean(6); + assert rs.getByte(6) == 1; + assert rs.getShort(6) == 1; + assert rs.getInt(6) == 1; assert rs.getLong(6) == 1; + assert rs.getDouble(6) == 1.0; + assert rs.getFloat(6) == 1.0f; + assert rs.getBigDecimal(6).equals(new BigDecimal(1)); + assert rs.getString(6).equals("1"); + + assert rs.getObject(6, Boolean.class); + assert rs.getObject(6, Byte.class) == 1; + assert rs.getObject(6, Short.class) == 1; + assert rs.getObject(6, Integer.class) == 1; + assert rs.getObject(6, Long.class) == 1; + assert rs.getObject(6, Float.class) == 1.f; + assert rs.getObject(6, Double.class) == 1; + assert rs.getObject(6, BigDecimal.class).equals(new BigDecimal(1)); + assert rs.getObject(6, String.class).equals("1"); } cnt++; @@ -342,7 +413,26 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getFloat("floatVal") == 1.0; - assert rs.getFloat(7) == 1.0; + + assert rs.getBoolean(7); + assert rs.getByte(7) == 1; + assert rs.getShort(7) == 1; + assert rs.getInt(7) == 1; + assert rs.getLong(7) == 1; + assert rs.getDouble(7) == 1.0; + assert rs.getFloat(7) == 1.0f; + assert rs.getBigDecimal(7).equals(new BigDecimal(1)); + assert rs.getString(7).equals("1.0"); + + assert rs.getObject(7, Boolean.class); + assert rs.getObject(7, Byte.class) == 1; + assert rs.getObject(7, Short.class) == 1; + assert rs.getObject(7, Integer.class) == 1; + assert rs.getObject(7, Long.class) == 1; + assert rs.getObject(7, Float.class) == 1.f; + assert rs.getObject(7, Double.class) == 1; + assert rs.getObject(7, BigDecimal.class).equals(new BigDecimal(1)); + assert rs.getObject(7, String.class).equals("1.0"); } cnt++; @@ -362,7 +452,26 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getDouble("doubleVal") == 1.0; + + assert rs.getBoolean(8); + assert rs.getByte(8) == 1; + assert rs.getShort(8) == 1; + assert rs.getInt(8) == 1; + assert rs.getLong(8) == 1; assert rs.getDouble(8) == 1.0; + assert rs.getFloat(8) == 1.0f; + assert rs.getBigDecimal(8).equals(new BigDecimal(1)); + assert rs.getString(8).equals("1.0"); + + assert rs.getObject(8, Boolean.class); + assert rs.getObject(8, Byte.class) == 1; + assert rs.getObject(8, Short.class) == 1; + assert rs.getObject(8, Integer.class) == 1; + assert rs.getObject(8, Long.class) == 1; + assert rs.getObject(8, Float.class) == 1.f; + assert rs.getObject(8, Double.class) == 1; + assert rs.getObject(8, BigDecimal.class).equals(new BigDecimal(1)); + assert rs.getObject(8, String.class).equals("1.0"); } cnt++; @@ -382,7 +491,26 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getBigDecimal("bigVal").intValue() == 1; - assert rs.getBigDecimal(9).intValue() == 1; + + assert rs.getBoolean(9); + assert rs.getByte(9) == 1; + assert rs.getShort(9) == 1; + assert rs.getInt(9) == 1; + assert rs.getLong(9) == 1; + assert rs.getDouble(9) == 1.0; + assert rs.getFloat(9) == 1.0f; + assert rs.getBigDecimal(9).equals(new BigDecimal(1)); + assert rs.getString(9).equals("1"); + + assert rs.getObject(9, Boolean.class); + assert rs.getObject(9, Byte.class) == 1; + assert rs.getObject(9, Short.class) == 1; + assert rs.getObject(9, Integer.class) == 1; + assert rs.getObject(9, Long.class) == 1; + assert rs.getObject(9, Float.class) == 1.f; + assert rs.getObject(9, Double.class) == 1; + assert rs.getObject(9, BigDecimal.class).equals(new BigDecimal(1)); + assert rs.getObject(9, String.class).equals("1"); } cnt++; @@ -394,6 +522,30 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { /** * @throws Exception If failed. */ + public void testBigDecimalScale() throws Exception { + assert "0.12".equals(convertStringToBigDecimalViaJdbc("0.1234", 2).toString()); + assert "1.001".equals(convertStringToBigDecimalViaJdbc("1.0005", 3).toString()); + assert "1E+3".equals(convertStringToBigDecimalViaJdbc("1205.5", -3).toString()); + assert "1.3E+4".equals(convertStringToBigDecimalViaJdbc("12505.5", -3).toString()); + } + + /** + * @param strDec String representation of a decimal value. + * @param scale Scale. + * @return BigDecimal object. + * @throws SQLException On error. + */ + private BigDecimal convertStringToBigDecimalViaJdbc(String strDec, int scale) throws SQLException { + try(ResultSet rs = stmt.executeQuery("select '" + strDec + "'")) { + assert rs.next(); + + return rs.getBigDecimal(1, scale); + } + } + + /** + * @throws Exception If failed. + */ public void testString() throws Exception { ResultSet rs = stmt.executeQuery(SQL); @@ -401,8 +553,27 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { - assert "str".equals(rs.getString("strVal")); - assert "str".equals(rs.getString(10)); + assert "1.0".equals(rs.getString("strVal")); + + assert rs.getBoolean(7); + assert rs.getByte(7) == 1; + assert rs.getShort(7) == 1; + assert rs.getInt(7) == 1; + assert rs.getLong(7) == 1; + assert rs.getDouble(7) == 1.0; + assert rs.getFloat(7) == 1.0f; + assert rs.getBigDecimal(7).equals(new BigDecimal(1)); + assert rs.getString(7).equals("1.0"); + + assert rs.getObject(7, Boolean.class); + assert rs.getObject(7, Byte.class) == 1; + assert rs.getObject(7, Short.class) == 1; + assert rs.getObject(7, Integer.class) == 1; + assert rs.getObject(7, Long.class) == 1; + assert rs.getObject(7, Float.class) == 1.f; + assert rs.getObject(7, Double.class) == 1; + assert rs.getObject(7, BigDecimal.class).equals(new BigDecimal(1)); + assert rs.getObject(7, String.class).equals("1.0"); } cnt++; @@ -443,7 +614,14 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getDate("dateVal").equals(new Date(1, 1, 1)); + assert rs.getDate(12).equals(new Date(1, 1, 1)); + assert rs.getTime(12).equals(new Time(new Date(1, 1, 1).getTime())); + assert rs.getTimestamp(12).equals(new Timestamp(new Date(1, 1, 1).getTime())); + + assert rs.getObject(12, Date.class).equals(new Date(1, 1, 1)); + assert rs.getObject(12, Time.class).equals(new Time(new Date(1, 1, 1).getTime())); + assert rs.getObject(12, Timestamp.class).equals(new Timestamp(new Date(1, 1, 1).getTime())); } cnt++; @@ -464,7 +642,14 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getTime("timeVal").equals(new Time(1, 1, 1)); + + assert rs.getDate(13).equals(new Date(new Time(1, 1, 1).getTime())); assert rs.getTime(13).equals(new Time(1, 1, 1)); + assert rs.getTimestamp(13).equals(new Timestamp(new Time(1, 1, 1).getTime())); + + assert rs.getObject(13, Date.class).equals(new Date(new Time(1, 1, 1).getTime())); + assert rs.getObject(13, Time.class).equals(new Time(1, 1, 1)); + assert rs.getObject(13, Timestamp.class).equals(new Timestamp(new Time(1, 1, 1).getTime())); } cnt++; @@ -484,7 +669,14 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { while (rs.next()) { if (cnt == 0) { assert rs.getTimestamp("tsVal").getTime() == 1; - assert rs.getTimestamp(14).getTime() == 1; + + assert rs.getDate(14).equals(new Date(new Timestamp(1).getTime())); + assert rs.getTime(14).equals(new Time(new Timestamp(1).getTime())); + assert rs.getTimestamp(14).equals(new Timestamp(1)); + + assert rs.getObject(14, Date.class).equals(new Date(new Timestamp(1).getTime())); + assert rs.getObject(14, Time.class).equals(new Time(new Timestamp(1).getTime())); + assert rs.getObject(14, Timestamp.class).equals(new Timestamp(1)); } cnt++; @@ -678,18 +870,6 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { checkNotSupported(new RunnableX() { @Override public void run() throws Exception { - rs.getNString(1); - } - }); - - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { - rs.getNString("id"); - } - }); - - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { rs.getRef(1); } }); @@ -723,18 +903,6 @@ public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest { rs.getSQLXML("id"); } }); - - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { - rs.getURL(1); - } - }); - - checkNotSupported(new RunnableX() { - @Override public void run() throws Exception { - rs.getURL("id"); - } - }); } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/74f8638a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java index d0c85b6..49a1029 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java @@ -95,7 +95,7 @@ public class JdbcThinPreparedStatement extends JdbcThinStatement implements Prep int res = getUpdateCount(); if (res == -1) - throw new SQLException("The query is not DML statememt: " + sql); + throw new SQLException("The query is not DML statement: " + sql); return res; } @@ -378,7 +378,7 @@ public class JdbcThinPreparedStatement extends JdbcThinStatement implements Prep @Override public void setNString(int paramIdx, String val) throws SQLException { ensureNotClosed(); - throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + setString(paramIdx, val); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/74f8638a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java index 1b7e87c..0a0c978 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; +import java.net.MalformedURLException; import java.net.URL; import java.sql.Array; import java.sql.Blob; @@ -38,6 +39,9 @@ import java.sql.SQLXML; import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.ParseException; import java.util.Calendar; import java.util.HashMap; import java.util.Iterator; @@ -52,6 +56,25 @@ import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryMetadataResult; * JDBC result set implementation. */ public class JdbcThinResultSet implements ResultSet { + /** Decimal format to convert streing to decimal. */ + private static final ThreadLocal<DecimalFormat> decimalFormat = new ThreadLocal<DecimalFormat>() { + /** {@inheritDoc} */ + @Override protected DecimalFormat initialValue() { + DecimalFormatSymbols symbols = new DecimalFormatSymbols(); + + symbols.setGroupingSeparator(','); + symbols.setDecimalSeparator('.'); + + String ptrn = "#,##0.0#"; + + DecimalFormat decimalFormat = new DecimalFormat(ptrn, symbols); + + decimalFormat.setParseBigDecimal(true); + + return decimalFormat; + } + }; + /** Statement. */ private final JdbcThinStatement stmt; @@ -120,7 +143,7 @@ public class JdbcThinResultSet implements ResultSet { isQuery = true; updCnt = -1; - this.rows = fields; + rows = fields; rowsIter = fields.iterator(); @@ -252,147 +275,304 @@ public class JdbcThinResultSet implements ResultSet { /** {@inheritDoc} */ @Override public String getString(int colIdx) throws SQLException { - ensureNotClosed(); - ensureHasCurrentRow(); - - try { - Object val = curRow.get(colIdx - 1); - - wasNull = val == null; + Object val = getValue(colIdx); - if (val == null) - return null; - else - return String.valueOf(val); - } - catch (IndexOutOfBoundsException e) { - throw new SQLException("Invalid column index: " + colIdx, e); - } + return val == null ? null : String.valueOf(val); } /** {@inheritDoc} */ @Override public boolean getBoolean(int colIdx) throws SQLException { - ensureNotClosed(); - ensureHasCurrentRow(); + Object val = getValue(colIdx); - try { - Object val = curRow.get(colIdx - 1); + if (val == null) + return false; - wasNull = val == null; + Class<?> cls = val.getClass(); - if (val == null) - return false; - else if (val.getClass() == Boolean.class) - return (Boolean)val; - else { - if (val.getClass() == Byte.class - || val.getClass() == Short.class - || val.getClass() == Integer.class - || val.getClass() == Long.class) - return castToBoolean((Number)val); - else if (val.getClass() == Character.class - || val.getClass() == String.class) - return castToBoolean(val.toString()); - else - throw new ClassCastException("Cannot cast " + val.getClass().getName() + " to boolean"); + if (cls == Boolean.class) + return ((Boolean)val); + else if (val instanceof Number) + return ((Number)val).intValue() != 0; + else if (cls == String.class || cls == Character.class) { + try { + return Integer.parseInt(val.toString()) != 0; + } + catch (NumberFormatException e) { + throw new SQLException("Cannot convert to boolean: " + val, e); } } - catch (IndexOutOfBoundsException e) { - throw new SQLException("Invalid column index: " + colIdx, e); - } - catch (ClassCastException e) { - throw new SQLException("Value is an not instance of " + Boolean.class.getName(), e); - } + else + throw new SQLException("Cannot convert to boolean: " + val); } /** {@inheritDoc} */ @Override public byte getByte(int colIdx) throws SQLException { - Byte val = getTypedValue(colIdx, Byte.class); + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); - return val != null ? val : 0; + if (val instanceof Number) + return ((Number)val).byteValue(); + else if (cls == Boolean.class) + return (Boolean) val ? (byte) 1 : (byte) 0; + else if (cls == String.class || cls == Character.class) { + try { + return Byte.parseByte(val.toString()); + } + catch (NumberFormatException e) { + throw new SQLException("Cannot convert to byte: " + val, e); + } + } + else + throw new SQLException("Cannot convert to byte: " + val); } /** {@inheritDoc} */ @Override public short getShort(int colIdx) throws SQLException { - Short val = getTypedValue(colIdx, Short.class); + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); - return val != null ? val : 0; + if (val instanceof Number) + return ((Number) val).shortValue(); + else if (cls == Boolean.class) + return (Boolean) val ? (short) 1 : (short) 0; + else if (cls == String.class || cls == Character.class) { + try { + return Short.parseShort(val.toString()); + } + catch (NumberFormatException e) { + throw new SQLException("Cannot convert to short: " + val, e); + } + } + else + throw new SQLException("Cannot convert to short: " + val); } /** {@inheritDoc} */ @Override public int getInt(int colIdx) throws SQLException { - Integer val = getTypedValue(colIdx, Integer.class); + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); - return val != null ? val : 0; + if (val instanceof Number) + return ((Number) val).intValue(); + else if (cls == Boolean.class) + return (Boolean) val ? 1 : 0; + else if (cls == String.class || cls == Character.class) { + try { + return Integer.parseInt(val.toString()); + } + catch (NumberFormatException e) { + throw new SQLException("Cannot convert to int: " + val, e); + } + } + else + throw new SQLException("Cannot convert to int: " + val); } /** {@inheritDoc} */ @Override public long getLong(int colIdx) throws SQLException { - Long val = getTypedValue(colIdx, Long.class); + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); - return val != null ? val : 0; + if (val instanceof Number) + return ((Number)val).longValue(); + else if (cls == Boolean.class) + return (long) ((Boolean) val ? 1 : 0); + else if (cls == String.class || cls == Character.class) { + try { + return Long.parseLong(val.toString()); + } + catch (NumberFormatException e) { + throw new SQLException("Cannot convert to long: " + val, e); + } + } + else + throw new SQLException("Cannot convert to long: " + val); } /** {@inheritDoc} */ @Override public float getFloat(int colIdx) throws SQLException { - Float val = getTypedValue(colIdx, Float.class); + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); - return val != null ? val : 0; + if (val instanceof Number) + return ((Number) val).floatValue(); + else if (cls == Boolean.class) + return (float) ((Boolean) val ? 1 : 0); + else if (cls == String.class || cls == Character.class) { + try { + return Float.parseFloat(val.toString()); + } + catch (NumberFormatException e) { + throw new SQLException("Cannot convert to float: " + val, e); + } + } + else + throw new SQLException("Cannot convert to float: " + val); } /** {@inheritDoc} */ @Override public double getDouble(int colIdx) throws SQLException { - Double val = getTypedValue(colIdx, Double.class); + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); - return val != null ? val : 0; + if (val instanceof Number) + return ((Number) val).doubleValue(); + else if (cls == Boolean.class) + return (double)((Boolean) val ? 1 : 0); + else if (cls == String.class || cls == Character.class) { + try { + return Double.parseDouble(val.toString()); + } + catch (NumberFormatException e) { + throw new SQLException("Cannot convert to double: " + val, e); + } + } + else + throw new SQLException("Cannot convert to double: " + val); } /** {@inheritDoc} */ @Override public BigDecimal getBigDecimal(int colIdx, int scale) throws SQLException { - return getTypedValue(colIdx, BigDecimal.class); + BigDecimal val = getBigDecimal(colIdx); + + return val == null ? null : val.setScale(scale, BigDecimal.ROUND_HALF_UP); } /** {@inheritDoc} */ @Override public byte[] getBytes(int colIdx) throws SQLException { - return getTypedValue(colIdx, byte[].class); - } + Object val = getValue(colIdx); - /** {@inheritDoc} */ - @Override public Date getDate(int colIdx) throws SQLException { - ensureNotClosed(); - ensureHasCurrentRow(); + if (val == null) + return null; - try { - Object val = curRow.get(colIdx - 1); + Class<?> cls = val.getClass(); - wasNull = val == null; + if (cls == byte[].class) + return (byte[])val; + else if (cls == Byte.class) + return new byte[] {(byte)val}; + else if (cls == Short.class) { + short x = (short)val; - if (val == null) - return null; - else if (val.getClass() == java.util.Date.class) - return new java.sql.Date(((java.util.Date)val).getTime()); - else - return (Date)val; + return new byte[] {(byte)(x >> 8), (byte)x}; } - catch (IndexOutOfBoundsException e) { - throw new SQLException("Invalid column index: " + colIdx, e); + else if (cls == Integer.class) { + int x = (int)val; + + return new byte[] { (byte) (x >> 24), (byte) (x >> 16), (byte) (x >> 8), (byte) x}; } - catch (ClassCastException e) { - throw new SQLException("Value is an not instance of Date", e); + else if (cls == Long.class) { + long x = (long)val; + + return new byte[] {(byte) (x >> 56), (byte) (x >> 48), (byte) (x >> 40), (byte) (x >> 32), + (byte) (x >> 24), (byte) (x >> 16), (byte) (x >> 8), (byte) x}; } + else if (cls == String.class) + return ((String)val).getBytes(); + else + throw new SQLException("Cannot convert to byte[]: " + val); + } + + /** {@inheritDoc} */ + @Override public Date getDate(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return null; + + Class<?> cls = val.getClass(); + + if (cls == Date.class) + return (Date)val; + else if (cls == java.util.Date.class || cls == Time.class || cls == Timestamp.class) + return new Date(((java.util.Date)val).getTime()); + else + throw new SQLException("Cannot convert to date: " + val); } /** {@inheritDoc} */ @Override public Time getTime(int colIdx) throws SQLException { - return getTypedValue(colIdx, Time.class); + Object val = getValue(colIdx); + + if (val == null) + return null; + + Class<?> cls = val.getClass(); + + if (cls == Time.class) + return (Time)val; + else if (cls == java.util.Date.class || cls == Date.class || cls == Timestamp.class) + return new Time(((java.util.Date)val).getTime()); + else + throw new SQLException("Cannot convert to time: " + val); } /** {@inheritDoc} */ @Override public Timestamp getTimestamp(int colIdx) throws SQLException { - return getTypedValue(colIdx, Timestamp.class); + Object val = getValue(colIdx); + + if (val == null) + return null; + + Class<?> cls = val.getClass(); + + if (cls == Timestamp.class) + return (Timestamp)val; + else if (cls == java.util.Date.class || cls == Date.class || cls == Time.class) + return new Timestamp(((java.util.Date)val).getTime()); + else + throw new SQLException("Cannot convert to timestamp: " + val); } /** {@inheritDoc} */ + @Override public URL getURL(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return null; + + Class<?> cls = val.getClass(); + + if (cls == URL.class) + return (URL)val; + else if (cls == String.class) { + try { + return new URL(val.toString()); + } + catch (MalformedURLException e) { + throw new SQLException("Cannot convert to URL: " + val, e); + } + } + else + throw new SQLException("Cannot convert to URL: " + val); + } + + + /** {@inheritDoc} */ @Override public InputStream getAsciiStream(int colIdx) throws SQLException { ensureNotClosed(); @@ -417,8 +597,6 @@ public class JdbcThinResultSet implements ResultSet { @Override public String getString(String colLb) throws SQLException { int colIdx = findColumn(colLb); - assert colIdx > 0; - return getString(colIdx); } @@ -426,80 +604,84 @@ public class JdbcThinResultSet implements ResultSet { @Override public boolean getBoolean(String colLb) throws SQLException { int colIdx = findColumn(colLb); - assert colIdx > 0; - return getBoolean(colIdx); } /** {@inheritDoc} */ @Override public byte getByte(String colLb) throws SQLException { - Byte val = getTypedValue(colLb, Byte.class); + int colIdx = findColumn(colLb); - return val != null ? val : 0; + return getByte(colIdx); } /** {@inheritDoc} */ @Override public short getShort(String colLb) throws SQLException { - Short val = getTypedValue(colLb, Short.class); + int colIdx = findColumn(colLb); - return val != null ? val : 0; + return getShort(colIdx); } /** {@inheritDoc} */ @Override public int getInt(String colLb) throws SQLException { - Integer val = getTypedValue(colLb, Integer.class); + int colIdx = findColumn(colLb); - return val != null ? val : 0; + return getInt(colIdx); } /** {@inheritDoc} */ @Override public long getLong(String colLb) throws SQLException { - Long val = getTypedValue(colLb, Long.class); + int colIdx = findColumn(colLb); - return val != null ? val : 0; + return getLong(colIdx); } /** {@inheritDoc} */ @Override public float getFloat(String colLb) throws SQLException { - Float val = getTypedValue(colLb, Float.class); + int colIdx = findColumn(colLb); - return val != null ? val : 0; + return getFloat(colIdx); } /** {@inheritDoc} */ @Override public double getDouble(String colLb) throws SQLException { - Double val = getTypedValue(colLb, Double.class); + int colIdx = findColumn(colLb); - return val != null ? val : 0; + return getDouble(colIdx); } /** {@inheritDoc} */ @Override public BigDecimal getBigDecimal(String colLb, int scale) throws SQLException { - return getTypedValue(colLb, BigDecimal.class); + int colIdx = findColumn(colLb); + + return getBigDecimal(colIdx, scale); } /** {@inheritDoc} */ @Override public byte[] getBytes(String colLb) throws SQLException { - return getTypedValue(colLb, byte[].class); + int colIdx = findColumn(colLb); + + return getBytes(colIdx); } /** {@inheritDoc} */ @Override public Date getDate(String colLb) throws SQLException { int colIdx = findColumn(colLb); - assert colIdx > 0; - return getDate(colIdx); } /** {@inheritDoc} */ @Override public Time getTime(String colLb) throws SQLException { - return getTypedValue(colLb, Time.class); + int colIdx = findColumn(colLb); + + return getTime(colIdx); } /** {@inheritDoc} */ @Override public Timestamp getTimestamp(String colLb) throws SQLException { - return getTypedValue(colLb, Timestamp.class); + int colIdx = findColumn(colLb); + + return getTimestamp(colIdx); } /** {@inheritDoc} */ @@ -554,12 +736,14 @@ public class JdbcThinResultSet implements ResultSet { /** {@inheritDoc} */ @Override public Object getObject(int colIdx) throws SQLException { - return getTypedValue(colIdx, Object.class); + return getValue(colIdx); } /** {@inheritDoc} */ @Override public Object getObject(String colLb) throws SQLException { - return getTypedValue(colLb, Object.class); + int colIdx = findColumn(colLb); + + return getValue(colIdx); } /** {@inheritDoc} */ @@ -571,6 +755,8 @@ public class JdbcThinResultSet implements ResultSet { if (order == null) throw new SQLException("Column not found: " + colLb); + assert order >= 0; + return order + 1; } @@ -590,12 +776,36 @@ public class JdbcThinResultSet implements ResultSet { /** {@inheritDoc} */ @Override public BigDecimal getBigDecimal(int colIdx) throws SQLException { - return getTypedValue(colIdx, BigDecimal.class); + Object val = getValue(colIdx); + + if (val == null) + return null; + + Class<?> cls = val.getClass(); + + if (cls == BigDecimal.class) + return (BigDecimal)val; + else if (val instanceof Number) + return new BigDecimal(((Number)val).doubleValue()); + else if (cls == Boolean.class) + return new BigDecimal((Boolean)val ? 1 : 0); + else if (cls == String.class || cls == Character.class) { + try { + return (BigDecimal)decimalFormat.get().parse(val.toString()); + } + catch (ParseException e) { + throw new SQLException("Cannot convert to BigDecimal: " + val, e); + } + } + else + throw new SQLException("Cannot convert to BigDecimal: " + val); } /** {@inheritDoc} */ @Override public BigDecimal getBigDecimal(String colLb) throws SQLException { - return getTypedValue(colLb, BigDecimal.class); + int colIdx = findColumn(colLb); + + return getBigDecimal(colIdx); } /** {@inheritDoc} */ @@ -1140,72 +1350,45 @@ public class JdbcThinResultSet implements ResultSet { /** {@inheritDoc} */ @Override public Date getDate(int colIdx, Calendar cal) throws SQLException { - ensureNotClosed(); - ensureHasCurrentRow(); - - try { - Object val = curRow.get(colIdx - 1); - - wasNull = val == null; - - if (val == null) - return null; - else if (val.getClass() == java.util.Date.class) - return new Date(((java.util.Date)val).getTime()); - else - return (Date)val; - } - catch (IndexOutOfBoundsException e) { - throw new SQLException("Invalid column index: " + colIdx, e); - } - catch (ClassCastException e) { - throw new SQLException("Value is an not instance of Date", e); - } + return getDate(colIdx); } /** {@inheritDoc} */ @Override public Date getDate(String colLb, Calendar cal) throws SQLException { int colIdx = findColumn(colLb); - assert colIdx > 0; - return getDate(colIdx, cal); } /** {@inheritDoc} */ @Override public Time getTime(int colIdx, Calendar cal) throws SQLException { - return getTypedValue(colIdx, Time.class); + return getTime(colIdx); } /** {@inheritDoc} */ @Override public Time getTime(String colLb, Calendar cal) throws SQLException { - return getTypedValue(colLb, Time.class); + int colIdx = findColumn(colLb); + + return getTime(colIdx); } /** {@inheritDoc} */ @Override public Timestamp getTimestamp(int colIdx, Calendar cal) throws SQLException { - return getTypedValue(colIdx, Timestamp.class); + return getTimestamp(colIdx); } /** {@inheritDoc} */ @Override public Timestamp getTimestamp(String colLb, Calendar cal) throws SQLException { - return getTypedValue(colLb, Timestamp.class); - } - - /** {@inheritDoc} */ - @Override public URL getURL(int colIdx) throws SQLException { - ensureNotClosed(); - ensureHasCurrentRow(); + int colIdx = findColumn(colLb); - throw new SQLFeatureNotSupportedException("URL type is not supported."); + return getTimestamp(colIdx); } /** {@inheritDoc} */ @Override public URL getURL(String colLb) throws SQLException { - ensureNotClosed(); - ensureHasCurrentRow(); + int colIdx = findColumn(colLb); - throw new SQLFeatureNotSupportedException("URL type is not supported."); + return getURL(colIdx); } /** {@inheritDoc} */ @@ -1360,16 +1543,12 @@ public class JdbcThinResultSet implements ResultSet { /** {@inheritDoc} */ @Override public String getNString(int colIdx) throws SQLException { - ensureNotClosed(); - - throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + return getString(colIdx); } /** {@inheritDoc} */ @Override public String getNString(String colLb) throws SQLException { - ensureNotClosed(); - - throw new SQLFeatureNotSupportedException("SQL-specific types are not supported."); + return getString(colLb); } /** {@inheritDoc} */ @@ -1597,44 +1776,77 @@ public class JdbcThinResultSet implements ResultSet { } /** {@inheritDoc} */ - @Override public <T> T getObject(int colIdx, Class<T> type) throws SQLException { - return getTypedValue(colIdx, type); + @SuppressWarnings("unchecked") + @Override public <T> T getObject(int colIdx, Class<T> targetCls) throws SQLException { + return (T)getObject0(colIdx, targetCls); } /** {@inheritDoc} */ @Override public <T> T getObject(String colLb, Class<T> type) throws SQLException { - return getTypedValue(colLb, type); + int colIdx = findColumn(colLb); + + return getObject(colIdx, type); } /** - * Gets casted field value by label. - * - * @param colLb Column label. - * @param cls Value class. - * @return Casted field value. - * @throws SQLException In case of error. + * @param colIdx Column index. + * @param targetCls Class representing the Java data type to convert the designated column to. + * @return Converted object. + * @throws SQLException On error. */ - private <T> T getTypedValue(String colLb, Class<T> cls) throws SQLException { - ensureNotClosed(); - ensureHasCurrentRow(); + private Object getObject0(int colIdx, Class<?> targetCls) throws SQLException { + if (targetCls == Boolean.class) + return getBoolean(colIdx); + else if (targetCls == Byte.class) + return getByte(colIdx); + else if (targetCls == Short.class) + return getShort(colIdx); + else if (targetCls == Integer.class) + return getInt(colIdx); + else if (targetCls == Long.class) + return getLong(colIdx); + else if (targetCls == Float.class) + return getFloat(colIdx); + else if (targetCls == Double.class) + return getDouble(colIdx); + else if (targetCls == String.class) + return getString(colIdx); + else if (targetCls == BigDecimal.class) + return getBigDecimal(colIdx); + else if (targetCls == Date.class) + return getDate(colIdx); + else if (targetCls == Time.class) + return getTime(colIdx); + else if (targetCls == Timestamp.class) + return getTimestamp(colIdx); + else if (targetCls == byte[].class) + return getBytes(colIdx); + else if (targetCls == URL.class) + return getURL(colIdx); + else { + Object val = getValue(colIdx); - int colIdx = findColumn(colLb); + if (val == null) + return null; - assert colIdx > 0; + Class<?> cls = val.getClass(); - return getTypedValue(colIdx, cls); + if (targetCls == cls) + return val; + else + throw new SQLException("Cannot convert to " + targetCls.getName() + ": " + val); + } } /** - * Gets casted field value by index. + * Gets object field value by index. * * @param colIdx Column index. - * @param cls Value class. - * @return Casted field value. + * @return Object field value. * @throws SQLException In case of error. */ @SuppressWarnings("unchecked") - private <T> T getTypedValue(int colIdx, Class<T> cls) throws SQLException { + private Object getValue(int colIdx) throws SQLException { ensureNotClosed(); ensureHasCurrentRow(); @@ -1643,17 +1855,11 @@ public class JdbcThinResultSet implements ResultSet { wasNull = val == null; - if (val == null) - return null; - else - return (T)val; + return val; } catch (IndexOutOfBoundsException e) { throw new SQLException("Invalid column index: " + colIdx, e); } - catch (ClassCastException e) { - throw new SQLException("Value is an not instance of " + cls.getName(), e); - } } /** @@ -1755,31 +1961,4 @@ public class JdbcThinResultSet implements ResultSet { void closeStatement(boolean closeStmt) { this.closeStmt = closeStmt; } - - /** - * @param val Number value. - * @return Boolean value. - */ - private static boolean castToBoolean(Number val) { - if (val.intValue() == 1) - return true; - else if (val.intValue() == 0) - return false; - else - throw new ClassCastException("Cannot cast " + val.getClass().getName() - + " [val=" + val +"] to boolean"); - } - - /** - * @param str String value. - * @return Boolean value. - */ - private static boolean castToBoolean(String str) { - try { - return castToBoolean(Integer.parseInt(str)); - } - catch (NumberFormatException e) { - throw new ClassCastException("Cannot cast [val=" + str +"] to boolean"); - } - } } \ No newline at end of file
