AMashenkov commented on a change in pull request #284:
URL: https://github.com/apache/ignite-3/pull/284#discussion_r700123987



##########
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);
+    }
+
+    /** {@inheritDoc} */
+    @Override public InputStream getAsciiStream(int colIdx) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public InputStream getUnicodeStream(int colIdx) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public InputStream getBinaryStream(int colIdx) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Stream are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getString(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getString(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean getBoolean(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getBoolean(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte getByte(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getByte(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public short getShort(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getShort(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getInt(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getInt(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLong(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getLong(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getFloat(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getFloat(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public double getDouble(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getDouble(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public BigDecimal getBigDecimal(String colLb, int scale) throws 
SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getBigDecimal(colIdx, scale);
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] getBytes(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getBytes(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Date getDate(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getDate(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Time getTime(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getTime(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Timestamp getTimestamp(String colLb) throws SQLException {
+        int colIdx = findColumn(colLb);
+
+        return getTimestamp(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public InputStream getAsciiStream(String colLb) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public InputStream getUnicodeStream(String colLb) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public InputStream getBinaryStream(String colLb) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public SQLWarning getWarnings() throws SQLException {
+        ensureNotClosed();
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void clearWarnings() throws SQLException {
+        ensureNotClosed();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getCursorName() throws SQLException {
+        ensureNotClosed();
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public ResultSetMetaData getMetaData() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("ResultSetMetaData are not 
supported.");
+
+    }
+
+    /** {@inheritDoc} */
+    @Override public int findColumn(String colLb) throws SQLException {
+        ensureNotClosed();
+

Review comment:
       ```suggestion
   
           Objects.requireNonNull(columnName)
   ```




-- 
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


Reply via email to