AMashenkov commented on a change in pull request #284: URL: https://github.com/apache/ignite-3/pull/284#discussion_r700122449
########## File path: modules/client/src/main/java/org/apache/ignite/jdbc/JdbcResultSet.java ########## @@ -0,0 +1,1876 @@ +/* + * 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.ignite.jdbc; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.Date; +import java.sql.NClob; +import java.sql.Ref; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.RowId; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLWarning; +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.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.ignite.client.proto.query.IgniteQueryErrorCode; +import org.apache.ignite.client.proto.query.JdbcQueryEventHandler; +import org.apache.ignite.client.proto.query.SqlStateCode; +import org.apache.ignite.client.proto.query.event.JdbcQueryCloseRequest; +import org.apache.ignite.client.proto.query.event.JdbcQueryCloseResult; +import org.apache.ignite.client.proto.query.event.JdbcQueryFetchRequest; +import org.apache.ignite.client.proto.query.event.JdbcQueryFetchResult; +import org.apache.ignite.client.proto.query.event.JdbcResponse; + +/** + * Jdbc result set implementation. + */ +public class JdbcResultSet implements ResultSet { + /** Decimal format to convert string to decimal. */ + private static final ThreadLocal<DecimalFormat> decimalFormat = new ThreadLocal<>() { + /** {@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 JdbcStatement stmt; + + /** Cursor ID. */ + private final Long cursorId; + + /** Rows. */ + private List<List<Object>> rows; + + /** Rows iterator. */ + private Iterator<List<Object>> rowsIter; + + /** Current row. */ + private List<Object> curRow; + + /** Current position. */ + private int curPos; + + /** Finished flag. */ + private boolean finished; + + /** Closed flag. */ + private boolean closed; + + /** Was {@code NULL} flag. */ + private boolean wasNull; + + /** Fetch size. */ + private int fetchSize; + + /** Is query flag. */ + private boolean isQuery; + + /** Auto close server cursors flag. */ + private boolean autoClose; + + /** Update count. */ + private long updCnt; + + /** Close statement after close result set count. */ + private boolean closeStmt; + + /** Query request handler. */ + private JdbcQueryEventHandler qryHandler; + + /** + * Creates new result set. + * + * @param stmt Statement. + * @param cursorId Cursor ID. + * @param fetchSize Fetch size. + * @param finished Finished flag. + * @param rows Rows. + * @param isQry Is Result ser for Select query. + * @param autoClose Is automatic close of server cursors enabled. + * @param updCnt Update count. + * @param closeStmt Close statement on the result set close. + * @param qryHandler QueryEventHandler (local or remote). + */ + JdbcResultSet(JdbcStatement stmt, long cursorId, int fetchSize, boolean finished, + List<List<Object>> rows, boolean isQry, boolean autoClose, long updCnt, boolean closeStmt, JdbcQueryEventHandler qryHandler) { + assert stmt != null; + assert fetchSize > 0; + + this.qryHandler = qryHandler; + this.stmt = stmt; + this.cursorId = cursorId; + this.fetchSize = fetchSize; + this.finished = finished; + this.isQuery = isQry; + this.autoClose = autoClose; + this.closeStmt = closeStmt; + + if (isQuery) { + this.rows = rows; + + rowsIter = rows != null ? rows.iterator() : null; + } + else + this.updCnt = updCnt; + } + + /** {@inheritDoc} */ + @Override public boolean next() throws SQLException { + ensureNotClosed(); + + if ((rowsIter == null || !rowsIter.hasNext()) && !finished) { + JdbcQueryFetchResult res = qryHandler.fetch(new JdbcQueryFetchRequest(cursorId, fetchSize)); + + if (res.status() != JdbcResponse.STATUS_SUCCESS) + throw IgniteQueryErrorCode.createJdbcSqlException(res.err(), res.status()); + + rows = res.items(); + finished = res.last(); + + rowsIter = rows.iterator(); + } + + if (rowsIter != null) { + if (rowsIter.hasNext()) { + curRow = rowsIter.next(); + + curPos++; + + return true; + } + else { + rowsIter = null; + curRow = null; + + return false; + } + } + else + return false; + } + + /** {@inheritDoc} */ + @Override public void close() throws SQLException { + close0(); + + if (closeStmt) + stmt.closeIfAllResultsClosed(); + } + + /** + * Close result set. + * + * @throws SQLException On error. + */ + void close0() throws SQLException { + if (isClosed()) + return; + + try { + if (stmt != null && (!finished || (isQuery && !autoClose))) { + JdbcQueryCloseResult res = qryHandler.close(new JdbcQueryCloseRequest(cursorId)); + + if (res.status() != JdbcResponse.STATUS_SUCCESS) + throw IgniteQueryErrorCode.createJdbcSqlException(res.err(), res.status()); + } + } + finally { + closed = true; + } + } + + /** {@inheritDoc} */ + @Override public boolean wasNull() throws SQLException { + ensureNotClosed(); + ensureHasCurrentRow(); + + return wasNull; + } + + /** {@inheritDoc} */ + @Override public String getString(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + return val == null ? null : String.valueOf(val); + } + + /** {@inheritDoc} */ + @Override public boolean getBoolean(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return false; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to boolean: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public byte getByte(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to byte: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public short getShort(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to short: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public int getInt(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to int: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public long getLong(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + if (val instanceof Number) + return ((Number)val).longValue(); + else if (cls == Boolean.class) + return ((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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to long: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public float getFloat(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to float: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public double getDouble(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0d; + + Class<?> cls = val.getClass(); + + if (val instanceof Number) + return ((Number) val).doubleValue(); + else if (cls == Boolean.class) + return ((Boolean) val ? 1d : 0d); + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to double: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public BigDecimal getBigDecimal(int colIdx, int scale) throws SQLException { + BigDecimal val = getBigDecimal(colIdx); + + return val == null ? null : val.setScale(scale, RoundingMode.HALF_UP); + } + + /** {@inheritDoc} */ + @Override public byte[] getBytes(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return null; + + Class<?> cls = val.getClass(); + + 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; + + return new byte[] {(byte)(x >> 8), (byte)x}; + } + else if (cls == Integer.class) { + int x = (int)val; + + return new byte[] { (byte) (x >> 24), (byte) (x >> 16), (byte) (x >> 8), (byte) x}; + } + 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, SqlStateCode.CONVERSION_FAILED); + } + + /** {@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, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public Time getTime(int colIdx) throws SQLException { + 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, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public Timestamp getTimestamp(int colIdx) throws SQLException { + 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, SqlStateCode.CONVERSION_FAILED); Review comment: We don't support legacy temporal types natively. We use Java Time API instead. ########## File path: modules/client/src/main/java/org/apache/ignite/jdbc/JdbcResultSet.java ########## @@ -0,0 +1,1876 @@ +/* + * 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.ignite.jdbc; + +import java.io.InputStream; +import java.io.Reader; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.MalformedURLException; +import java.net.URL; +import java.sql.Array; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.Date; +import java.sql.NClob; +import java.sql.Ref; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.RowId; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLWarning; +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.Iterator; +import java.util.List; +import java.util.Map; +import org.apache.ignite.client.proto.query.IgniteQueryErrorCode; +import org.apache.ignite.client.proto.query.JdbcQueryEventHandler; +import org.apache.ignite.client.proto.query.SqlStateCode; +import org.apache.ignite.client.proto.query.event.JdbcQueryCloseRequest; +import org.apache.ignite.client.proto.query.event.JdbcQueryCloseResult; +import org.apache.ignite.client.proto.query.event.JdbcQueryFetchRequest; +import org.apache.ignite.client.proto.query.event.JdbcQueryFetchResult; +import org.apache.ignite.client.proto.query.event.JdbcResponse; + +/** + * Jdbc result set implementation. + */ +public class JdbcResultSet implements ResultSet { + /** Decimal format to convert string to decimal. */ + private static final ThreadLocal<DecimalFormat> decimalFormat = new ThreadLocal<>() { + /** {@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 JdbcStatement stmt; + + /** Cursor ID. */ + private final Long cursorId; + + /** Rows. */ + private List<List<Object>> rows; + + /** Rows iterator. */ + private Iterator<List<Object>> rowsIter; + + /** Current row. */ + private List<Object> curRow; + + /** Current position. */ + private int curPos; + + /** Finished flag. */ + private boolean finished; + + /** Closed flag. */ + private boolean closed; + + /** Was {@code NULL} flag. */ + private boolean wasNull; + + /** Fetch size. */ + private int fetchSize; + + /** Is query flag. */ + private boolean isQuery; + + /** Auto close server cursors flag. */ + private boolean autoClose; + + /** Update count. */ + private long updCnt; + + /** Close statement after close result set count. */ + private boolean closeStmt; + + /** Query request handler. */ + private JdbcQueryEventHandler qryHandler; + + /** + * Creates new result set. + * + * @param stmt Statement. + * @param cursorId Cursor ID. + * @param fetchSize Fetch size. + * @param finished Finished flag. + * @param rows Rows. + * @param isQry Is Result ser for Select query. + * @param autoClose Is automatic close of server cursors enabled. + * @param updCnt Update count. + * @param closeStmt Close statement on the result set close. + * @param qryHandler QueryEventHandler (local or remote). + */ + JdbcResultSet(JdbcStatement stmt, long cursorId, int fetchSize, boolean finished, + List<List<Object>> rows, boolean isQry, boolean autoClose, long updCnt, boolean closeStmt, JdbcQueryEventHandler qryHandler) { + assert stmt != null; + assert fetchSize > 0; + + this.qryHandler = qryHandler; + this.stmt = stmt; + this.cursorId = cursorId; + this.fetchSize = fetchSize; + this.finished = finished; + this.isQuery = isQry; + this.autoClose = autoClose; + this.closeStmt = closeStmt; + + if (isQuery) { + this.rows = rows; + + rowsIter = rows != null ? rows.iterator() : null; + } + else + this.updCnt = updCnt; + } + + /** {@inheritDoc} */ + @Override public boolean next() throws SQLException { + ensureNotClosed(); + + if ((rowsIter == null || !rowsIter.hasNext()) && !finished) { + JdbcQueryFetchResult res = qryHandler.fetch(new JdbcQueryFetchRequest(cursorId, fetchSize)); + + if (res.status() != JdbcResponse.STATUS_SUCCESS) + throw IgniteQueryErrorCode.createJdbcSqlException(res.err(), res.status()); + + rows = res.items(); + finished = res.last(); + + rowsIter = rows.iterator(); + } + + if (rowsIter != null) { + if (rowsIter.hasNext()) { + curRow = rowsIter.next(); + + curPos++; + + return true; + } + else { + rowsIter = null; + curRow = null; + + return false; + } + } + else + return false; + } + + /** {@inheritDoc} */ + @Override public void close() throws SQLException { + close0(); + + if (closeStmt) + stmt.closeIfAllResultsClosed(); + } + + /** + * Close result set. + * + * @throws SQLException On error. + */ + void close0() throws SQLException { + if (isClosed()) + return; + + try { + if (stmt != null && (!finished || (isQuery && !autoClose))) { + JdbcQueryCloseResult res = qryHandler.close(new JdbcQueryCloseRequest(cursorId)); + + if (res.status() != JdbcResponse.STATUS_SUCCESS) + throw IgniteQueryErrorCode.createJdbcSqlException(res.err(), res.status()); + } + } + finally { + closed = true; + } + } + + /** {@inheritDoc} */ + @Override public boolean wasNull() throws SQLException { + ensureNotClosed(); + ensureHasCurrentRow(); + + return wasNull; + } + + /** {@inheritDoc} */ + @Override public String getString(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + return val == null ? null : String.valueOf(val); + } + + /** {@inheritDoc} */ + @Override public boolean getBoolean(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return false; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to boolean: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public byte getByte(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to byte: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public short getShort(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to short: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public int getInt(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to int: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public long getLong(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + if (val instanceof Number) + return ((Number)val).longValue(); + else if (cls == Boolean.class) + return ((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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to long: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public float getFloat(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0; + + Class<?> cls = val.getClass(); + + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to float: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public double getDouble(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return 0d; + + Class<?> cls = val.getClass(); + + if (val instanceof Number) + return ((Number) val).doubleValue(); + else if (cls == Boolean.class) + return ((Boolean) val ? 1d : 0d); + 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, SqlStateCode.CONVERSION_FAILED, e); + } + } + else + throw new SQLException("Cannot convert to double: " + val, SqlStateCode.CONVERSION_FAILED); + } + + /** {@inheritDoc} */ + @Override public BigDecimal getBigDecimal(int colIdx, int scale) throws SQLException { + BigDecimal val = getBigDecimal(colIdx); + + return val == null ? null : val.setScale(scale, RoundingMode.HALF_UP); + } + + /** {@inheritDoc} */ + @Override public byte[] getBytes(int colIdx) throws SQLException { + Object val = getValue(colIdx); + + if (val == null) + return null; + + Class<?> cls = val.getClass(); + + 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; + + return new byte[] {(byte)(x >> 8), (byte)x}; + } + else if (cls == Integer.class) { + int x = (int)val; + + return new byte[] { (byte) (x >> 24), (byte) (x >> 16), (byte) (x >> 8), (byte) x}; + } + 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, SqlStateCode.CONVERSION_FAILED); + } + + /** {@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, SqlStateCode.CONVERSION_FAILED); Review comment: We don't support legacy temporal types natively. We use Java Time API instead. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@ignite.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org