http://git-wip-us.apache.org/repos/asf/ignite/blob/e92707b6/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
new file mode 100644
index 0000000..0b1cad8
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java
@@ -0,0 +1,461 @@
+/*
+ * 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.internal.jdbc.thin;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+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.ParameterMetaData;
+import java.sql.PreparedStatement;
+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.SQLXML;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Calendar;
+import org.apache.ignite.internal.processors.odbc.SqlListenerUtils;
+
+/**
+ * JDBC prepared statement implementation.
+ */
+public class JdbcThinPreparedStatement extends JdbcThinStatement implements 
PreparedStatement {
+    /** SQL query. */
+    private final String sql;
+
+    /**
+     * Creates new prepared statement.
+     *
+     * @param conn Connection.
+     * @param sql SQL query.
+     */
+    JdbcThinPreparedStatement(JdbcThinConnection conn, String sql) {
+        super(conn);
+
+        this.sql = sql;
+    }
+
+    /** {@inheritDoc} */
+    @Override public ResultSet executeQuery() throws SQLException {
+        ResultSet rs = super.executeQuery(sql);
+
+        args = null;
+
+        return rs;
+    }
+
+    /** {@inheritDoc} */
+    @Override public ResultSet executeQuery(String sql) throws SQLException {
+        throw new SQLException("The method 'executeQuery(String)' is called on 
PreparedStatement instance.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int executeUpdate() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int executeUpdate(String sql) throws SQLException {
+        throw new SQLException("The method 'executeUpdate(String)' is called 
on PreparedStatement instance.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setNull(int paramIdx, int sqlType) throws 
SQLException {
+        setArgument(paramIdx, null);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setBoolean(int paramIdx, boolean x) throws 
SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setByte(int paramIdx, byte x) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setShort(int paramIdx, short x) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setInt(int paramIdx, int x) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setLong(int paramIdx, long x) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setFloat(int paramIdx, float x) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setDouble(int paramIdx, double x) throws 
SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setBigDecimal(int paramIdx, BigDecimal x) throws 
SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setString(int paramIdx, String x) throws 
SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setBytes(int paramIdx, byte[] x) throws SQLException 
{
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setDate(int paramIdx, Date x) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setTime(int paramIdx, Time x) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setTimestamp(int paramIdx, Timestamp x) throws 
SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setAsciiStream(int paramIdx, InputStream x, int 
length) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setUnicodeStream(int paramIdx, InputStream x, int 
length) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setBinaryStream(int paramIdx, InputStream x, int 
length) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void clearParameters() throws SQLException {
+        ensureNotClosed();
+
+        args = null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setObject(int paramIdx, Object x, int targetSqlType) 
throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setObject(int paramIdx, Object x) throws 
SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean execute() throws SQLException {
+        return super.execute(sql);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean execute(String sql) throws SQLException {
+        throw new SQLException("The method 'execute(String)' is called on 
PreparedStatement instance.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void addBatch() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setCharacterStream(int paramIdx, Reader x, int 
length) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setRef(int paramIdx, Ref x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setBlob(int paramIdx, Blob x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setClob(int paramIdx, Clob x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setArray(int paramIdx, Array x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public ResultSetMetaData getMetaData() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Meta data for prepared 
statement is not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setDate(int paramIdx, Date x, Calendar cal) throws 
SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setTime(int paramIdx, Time x, Calendar cal) throws 
SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setTimestamp(int paramIdx, Timestamp x, Calendar 
cal) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setNull(int paramIdx, int sqlType, String typeName) 
throws SQLException {
+        if (!JdbcThinUtils.isPlainJdbcType(sqlType)) {
+            throw new SQLFeatureNotSupportedException("The SQL type is 
unsupported. [type=" + sqlType + "typeName="
+                + typeName + ']');
+        }
+
+        setNull(paramIdx, sqlType);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setURL(int paramIdx, URL x) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public ParameterMetaData getParameterMetaData() throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Meta data for prepared 
statement is not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setRowId(int paramIdx, RowId x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setNString(int paramIdx, String val) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setNCharacterStream(int paramIdx, Reader val, long 
length) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setNClob(int paramIdx, NClob val) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setClob(int paramIdx, Reader reader, long length) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setBlob(int paramIdx, InputStream inputStream, long 
length) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setNClob(int paramIdx, Reader reader, long length) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setSQLXML(int paramIdx, SQLXML xmlObj) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setObject(int paramIdx, Object x, int targetSqlType, 
int scaleOrLength) throws SQLException {
+        setArgument(paramIdx, x);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setAsciiStream(int paramIdx, InputStream x, long 
length) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setBinaryStream(int paramIdx, InputStream x, long 
length) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setCharacterStream(int paramIdx, Reader x, long 
length) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setAsciiStream(int paramIdx, InputStream x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setBinaryStream(int paramIdx, InputStream x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setCharacterStream(int paramIdx, Reader x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setNCharacterStream(int paramIdx, Reader val) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setClob(int paramIdx, Reader reader) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setBlob(int paramIdx, InputStream inputStream) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setNClob(int paramIdx, Reader reader) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T unwrap(Class<T> iface) throws SQLException {
+        if (!isWrapperFor(iface))
+            throw new SQLException("Prepared statement is not a wrapper for " 
+ iface.getName());
+
+        return (T)this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return iface != null && 
iface.isAssignableFrom(JdbcThinPreparedStatement.class);
+    }
+
+    /**
+     * Sets query argument value.
+     *
+     * @param paramIdx Index.
+     * @param val Value.
+     * @throws SQLException If index is invalid.
+     */
+    private void setArgument(int paramIdx, Object val) throws SQLException {
+        ensureNotClosed();
+
+        if (val != null && !SqlListenerUtils.isPlainType(val.getClass()))
+            throw new SQLException("Parameter type is unsupported. [cls=" + 
val.getClass() + ']');
+
+        if (paramIdx < 1)
+            throw new SQLException("Parameter index is invalid: " + paramIdx);
+
+        if (args == null)
+            args = new ArrayList<>(paramIdx);
+
+        while (args.size() < paramIdx)
+            args.add(null);
+
+        args.set(paramIdx - 1, val);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/e92707b6/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
new file mode 100644
index 0000000..f4ab444
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java
@@ -0,0 +1,1698 @@
+/*
+ * 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.internal.jdbc.thin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+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.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcColumnMeta;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryFetchResult;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryMetadataResult;
+
+/**
+ * JDBC result set implementation.
+ */
+public class JdbcThinResultSet implements ResultSet {
+    /** Statement. */
+    private final JdbcThinStatement stmt;
+
+    /** Query ID. */
+    private final Long qryId;
+
+    /** Metadata. */
+    private List<JdbcColumnMeta> meta;
+
+    /** Column order map. */
+    private Map<String, Integer> colOrder;
+
+    /** Metadata initialization flag. */
+    private boolean metaInit;
+
+    /** 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;
+
+    /** Update count. */
+    private long updCnt;
+
+    /**
+     * Creates new result set.
+     *
+     * @param stmt Statement.
+     * @param qryId Query ID.
+     * @param fetchSize Fetch size.
+     * @param finished Finished flag.
+     * @param rows Rows.
+     * @param isQuery Is Result ser for Select query
+     */
+    @SuppressWarnings("OverlyStrongTypeCast") 
JdbcThinResultSet(JdbcThinStatement stmt, long qryId, int fetchSize, boolean 
finished,
+        List<List<Object>> rows, boolean isQuery) {
+        assert stmt != null;
+        assert fetchSize > 0;
+
+        this.stmt = stmt;
+        this.qryId = qryId;
+        this.fetchSize = fetchSize;
+        this.rows = rows;
+        this.finished = finished;
+
+        rowsIter = rows.iterator();
+
+        this.isQuery = isQuery;
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override public boolean next() throws SQLException {
+        ensureNotClosed();
+
+        if (rowsIter == null && !finished) {
+            try {
+                JdbcQueryFetchResult res = 
stmt.connection().cliIo().queryFetch(qryId, fetchSize);
+
+                rows = res.items();
+                finished = res.last();
+
+                rowsIter = rows.iterator();
+            }
+            catch (IOException e) {
+                stmt.connection().close();
+
+                throw new SQLException("Failed to query Ignite.", e);
+            }
+            catch (IgniteCheckedException e) {
+                throw new SQLException("Failed to query Ignite.", e);
+            }
+        }
+
+        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 {
+        if (closed || stmt.connection().isClosed())
+            return;
+
+        try {
+            stmt.connection().cliIo().queryClose(qryId);
+
+            closed = true;
+        }
+        catch (IOException e) {
+            stmt.connection().close();
+
+            throw new SQLException("Failed to close Ignite query.", e);
+        }
+        catch (IgniteCheckedException e) {
+            throw new SQLException("Failed to close Ignite query.", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean wasNull() throws SQLException {
+        return wasNull;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getString(int colIdx) throws SQLException {
+        ensureNotClosed();
+        ensureHasCurrentRow();
+
+        try {
+            Object val = curRow.get(colIdx - 1);
+
+            wasNull = val == null;
+
+            if (val == null)
+                return null;
+            else
+                return String.valueOf(val);
+        }
+        catch (IndexOutOfBoundsException e) {
+            throw new SQLException("Invalid column index: " + colIdx, e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean getBoolean(int colIdx) throws SQLException {
+        try {
+            Object val = curRow.get(colIdx - 1);
+
+            wasNull = val == null;
+
+            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");
+            }
+        }
+        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);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte getByte(int colIdx) throws SQLException {
+        Byte val = getTypedValue(colIdx, Byte.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public short getShort(int colIdx) throws SQLException {
+        Short val = getTypedValue(colIdx, Short.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getInt(int colIdx) throws SQLException {
+        Integer val = getTypedValue(colIdx, Integer.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLong(int colIdx) throws SQLException {
+        Long val = getTypedValue(colIdx, Long.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getFloat(int colIdx) throws SQLException {
+        Float val = getTypedValue(colIdx, Float.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public double getDouble(int colIdx) throws SQLException {
+        Double val = getTypedValue(colIdx, Double.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public BigDecimal getBigDecimal(int colIdx, int scale) throws 
SQLException {
+        return getTypedValue(colIdx, BigDecimal.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] getBytes(int colIdx) throws SQLException {
+        return getTypedValue(colIdx, byte[].class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Date getDate(int colIdx) 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 java.sql.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);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public Time getTime(int colIdx) throws SQLException {
+        return getTypedValue(colIdx, Time.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Timestamp getTimestamp(int colIdx) throws SQLException {
+        return getTypedValue(colIdx, Timestamp.class);
+    }
+
+    /** {@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);
+
+        assert colIdx > 0;
+
+        return getString(colIdx);
+    }
+
+    /** {@inheritDoc} */
+    @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);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public short getShort(String colLb) throws SQLException {
+        Short val = getTypedValue(colLb, Short.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getInt(String colLb) throws SQLException {
+        Integer val = getTypedValue(colLb, Integer.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLong(String colLb) throws SQLException {
+        Long val = getTypedValue(colLb, Long.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getFloat(String colLb) throws SQLException {
+        Float val = getTypedValue(colLb, Float.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public double getDouble(String colLb) throws SQLException {
+        Double val = getTypedValue(colLb, Double.class);
+
+        return val != null ? val : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public BigDecimal getBigDecimal(String colLb, int scale) throws 
SQLException {
+        return getTypedValue(colLb, BigDecimal.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public byte[] getBytes(String colLb) throws SQLException {
+        return getTypedValue(colLb, byte[].class);
+    }
+
+    /** {@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);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Timestamp getTimestamp(String colLb) throws SQLException {
+        return getTypedValue(colLb, Timestamp.class);
+    }
+
+    /** {@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();
+
+        return new JdbcThinResultSetMetadata(meta());
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object getObject(int colIdx) throws SQLException {
+        return getTypedValue(colIdx, Object.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object getObject(String colLb) throws SQLException {
+        return getTypedValue(colLb, Object.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int findColumn(final String colLb) throws SQLException {
+        ensureNotClosed();
+
+        Integer order = columnOrder().get(colLb.toUpperCase());
+
+        if (order == null)
+            throw new SQLException("Column not found: " + colLb);
+
+        return order + 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Reader getCharacterStream(int colIdx) throws SQLException 
{
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Reader getCharacterStream(String colLb) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Streams are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public BigDecimal getBigDecimal(int colIdx) throws SQLException {
+        return getTypedValue(colIdx, BigDecimal.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public BigDecimal getBigDecimal(String colLb) throws 
SQLException {
+        return getTypedValue(colLb, BigDecimal.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isBeforeFirst() throws SQLException {
+        ensureNotClosed();
+
+        return curPos == 0 && rowsIter != null && rowsIter.hasNext();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isAfterLast() throws SQLException {
+        ensureNotClosed();
+
+        return finished && rowsIter == null && curRow == null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isFirst() throws SQLException {
+        ensureNotClosed();
+
+        return curPos == 1;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isLast() throws SQLException {
+        ensureNotClosed();
+
+        return finished && rowsIter != null && !rowsIter.hasNext() && curRow 
!= null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void beforeFirst() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLException("Result set is forward-only.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void afterLast() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLException("Result set is forward-only.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean first() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLException("Result set is forward-only.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean last() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLException("Result set is forward-only.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getRow() throws SQLException {
+        ensureNotClosed();
+
+        return isAfterLast() ? 0 : curPos;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean absolute(int row) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLException("Result set is forward-only.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean relative(int rows) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLException("Result set is forward-only.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean previous() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLException("Result set is forward-only.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setFetchDirection(int direction) throws SQLException 
{
+        ensureNotClosed();
+
+        if (direction != FETCH_FORWARD)
+            throw new SQLFeatureNotSupportedException("Only forward direction 
is supported");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getFetchDirection() throws SQLException {
+        ensureNotClosed();
+
+        return FETCH_FORWARD;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setFetchSize(int fetchSize) throws SQLException {
+        ensureNotClosed();
+
+        if (fetchSize <= 0)
+            throw new SQLException("Fetch size must be greater than zero.");
+
+        this.fetchSize = fetchSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getFetchSize() throws SQLException {
+        ensureNotClosed();
+
+        return fetchSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getType() throws SQLException {
+        ensureNotClosed();
+
+        return stmt.getResultSetType();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getConcurrency() throws SQLException {
+        ensureNotClosed();
+
+        return CONCUR_READ_ONLY;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean rowUpdated() throws SQLException {
+        ensureNotClosed();
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean rowInserted() throws SQLException {
+        ensureNotClosed();
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean rowDeleted() throws SQLException {
+        ensureNotClosed();
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNull(int colIdx) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBoolean(int colIdx, boolean x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateByte(int colIdx, byte x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateShort(int colIdx, short x) throws SQLException 
{
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateInt(int colIdx, int x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateLong(int colIdx, long x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateFloat(int colIdx, float x) throws SQLException 
{
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateDouble(int colIdx, double x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBigDecimal(int colIdx, BigDecimal x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateString(int colIdx, String x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBytes(int colIdx, byte[] x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateDate(int colIdx, Date x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateTime(int colIdx, Time x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateTimestamp(int colIdx, Timestamp x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateAsciiStream(int colIdx, InputStream x, int 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBinaryStream(int colIdx, InputStream x, int 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateCharacterStream(int colIdx, Reader x, int len) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateObject(int colIdx, Object x, int scaleOrLen) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateObject(int colIdx, Object x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNull(String colLb) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBoolean(String colLb, boolean x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateByte(String colLb, byte x) throws SQLException 
{
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateShort(String colLb, short x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateInt(String colLb, int x) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateLong(String colLb, long x) throws SQLException 
{
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateFloat(String colLb, float x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateDouble(String colLb, double x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBigDecimal(String colLb, BigDecimal x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateString(String colLb, String x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBytes(String colLb, byte[] x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateDate(String colLb, Date x) throws SQLException 
{
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateTime(String colLb, Time x) throws SQLException 
{
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateTimestamp(String colLb, Timestamp x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateAsciiStream(String colLb, InputStream x, int 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBinaryStream(String colLb, InputStream x, int 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateCharacterStream(String colLb, Reader reader, 
int len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateObject(String colLb, Object x, int scaleOrLen) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateObject(String colLb, Object x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void insertRow() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateRow() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void deleteRow() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void refreshRow() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Row refreshing is not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void cancelRowUpdates() throws SQLException {
+        ensureNotClosed();
+
+        if (getConcurrency() == CONCUR_READ_ONLY)
+            throw new SQLException("The result set concurrency is 
CONCUR_READ_ONLY");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void moveToInsertRow() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void moveToCurrentRow() throws SQLException {
+        ensureNotClosed();
+
+        if (getConcurrency() == CONCUR_READ_ONLY)
+            throw new SQLException("The result set concurrency is 
CONCUR_READ_ONLY");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Statement getStatement() throws SQLException {
+        ensureNotClosed();
+
+        return stmt;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object getObject(int colIdx, Map<String, Class<?>> map) 
throws SQLException {
+        throw new SQLFeatureNotSupportedException("SQL structured type are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Ref getRef(int colIdx) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Blob getBlob(int colIdx) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Clob getClob(int colIdx) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Array getArray(int colIdx) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object getObject(String colLb, Map<String, Class<?>> map) 
throws SQLException {
+        throw new SQLFeatureNotSupportedException("SQL structured type are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Ref getRef(String colLb) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Blob getBlob(String colLb) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Clob getClob(String colLb) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Array getArray(String colLb) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@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);
+        }
+    }
+
+    /** {@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);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Time getTime(String colLb, Calendar cal) throws 
SQLException {
+        return getTypedValue(colLb, Time.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Timestamp getTimestamp(int colIdx, Calendar cal) throws 
SQLException {
+        return getTypedValue(colIdx, Timestamp.class);
+    }
+
+    /** {@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 {
+        return getTypedValue(colIdx, URL.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public URL getURL(String colLb) throws SQLException {
+        return getTypedValue(colLb, URL.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateRef(int colIdx, Ref x) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateRef(String colLb, Ref x) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBlob(int colIdx, Blob x) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBlob(String colLb, Blob x) throws SQLException 
{
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateClob(int colIdx, Clob x) throws SQLException {
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateClob(String colLb, Clob x) throws SQLException 
{
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateArray(int colIdx, Array x) throws SQLException 
{
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateArray(String colLb, Array x) throws 
SQLException {
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public RowId getRowId(int colIdx) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public RowId getRowId(String colLb) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateRowId(int colIdx, RowId x) throws SQLException 
{
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateRowId(String colLb, RowId x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getHoldability() throws SQLException {
+        ensureNotClosed();
+
+        return HOLD_CURSORS_OVER_COMMIT;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isClosed() throws SQLException {
+        return stmt.isClosed() || closed;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNString(int colIdx, String nStr) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNString(String colLb, String nStr) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNClob(int colIdx, NClob nClob) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNClob(String colLb, NClob nClob) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public NClob getNClob(int colIdx) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public NClob getNClob(String colLb) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public SQLXML getSQLXML(int colIdx) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public SQLXML getSQLXML(String colLb) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateSQLXML(int colIdx, SQLXML xmlObj) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateSQLXML(String colLb, SQLXML xmlObj) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getNString(int colIdx) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getNString(String colLb) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Reader getNCharacterStream(int colIdx) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Reader getNCharacterStream(String colLb) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNCharacterStream(int colIdx, Reader x, long 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNCharacterStream(String colLb, Reader reader, 
long len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateAsciiStream(int colIdx, InputStream x, long 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBinaryStream(int colIdx, InputStream x, long 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateCharacterStream(int colIdx, Reader x, long 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateAsciiStream(String colLb, InputStream x, long 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBinaryStream(String colLb, InputStream x, long 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateCharacterStream(String colLb, Reader reader, 
long len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBlob(int colIdx, InputStream inputStream, long 
len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBlob(String colLb, InputStream inputStream, 
long len) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateClob(int colIdx, Reader reader, long len) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateClob(String colLb, Reader reader, long len) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNClob(int colIdx, Reader reader, long len) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNClob(String colLb, Reader reader, long len) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNCharacterStream(int colIdx, Reader x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNCharacterStream(String colLb, Reader reader) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateAsciiStream(int colIdx, InputStream x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBinaryStream(int colIdx, InputStream x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateCharacterStream(int colIdx, Reader x) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateAsciiStream(String colLb, InputStream x) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBinaryStream(String colLb, InputStream x) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateCharacterStream(String colLb, Reader reader) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBlob(int colIdx, InputStream inputStream) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateBlob(String colLb, InputStream inputStream) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateClob(int colIdx, Reader reader) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateClob(String colLb, Reader reader) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNClob(int colIdx, Reader reader) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void updateNClob(String colLb, Reader reader) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T unwrap(Class<T> iface) throws SQLException {
+        if (!isWrapperFor(iface))
+            throw new SQLException("Result set is not a wrapper for " + 
iface.getName());
+
+        return (T)this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return iface != null && 
iface.isAssignableFrom(JdbcThinResultSet.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T getObject(int colIdx, Class<T> type) throws 
SQLException {
+        return getTypedValue(colIdx, type);
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T getObject(String colLb, Class<T> type) throws 
SQLException {
+        return getTypedValue(colLb, 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.
+     */
+    private <T> T getTypedValue(String colLb, Class<T> cls) throws 
SQLException {
+        ensureNotClosed();
+        ensureHasCurrentRow();
+
+        int colIdx = findColumn(colLb);
+
+        assert colIdx > 0;
+
+        return getTypedValue(colIdx, cls);
+    }
+
+    /**
+     * Gets casted field value by index.
+     *
+     * @param colIdx Column index.
+     * @param cls Value class.
+     * @return Casted field value.
+     * @throws SQLException In case of error.
+     */
+    @SuppressWarnings("unchecked")
+    private <T> T getTypedValue(int colIdx, Class<T> cls) throws SQLException {
+        ensureNotClosed();
+        ensureHasCurrentRow();
+
+        try {
+            Object val = curRow.get(colIdx - 1);
+
+            wasNull = val == null;
+
+            if (val == null)
+                return null;
+            else
+                return (T)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);
+        }
+    }
+
+    /**
+     * Ensures that result set is not closed.
+     *
+     * @throws SQLException If result set is closed.
+     */
+    private void ensureNotClosed() throws SQLException {
+        if (closed)
+            throw new SQLException("Result set is closed.");
+    }
+
+    /**
+     * Ensures that result set is positioned on a row.
+     *
+     * @throws SQLException If result set is not positioned on a row.
+     */
+    private void ensureHasCurrentRow() throws SQLException {
+        if (curRow == null)
+            throw new SQLException("Result set is not positioned on a row.");
+    }
+
+    /**
+     * @return Results metadata.
+     * @throws SQLException On error.
+     */
+    private List<JdbcColumnMeta> meta() throws SQLException {
+        if (!metaInit) {
+            try {
+                JdbcQueryMetadataResult res = 
stmt.connection().cliIo().queryMeta(qryId);
+
+                meta = res.meta();
+
+                metaInit = true;
+            }
+            catch (IOException e) {
+                stmt.connection().close();
+
+                throw new SQLException("Failed to get query metadata.", e);
+            }
+            catch (IgniteCheckedException e) {
+                throw new SQLException("Failed to get query metadata.", e);
+            }
+        }
+
+        return meta;
+    }
+
+    /**
+     * Init column order map.
+     * @throws SQLException On error.
+     * @return Column order map.
+     */
+    private Map<String, Integer> columnOrder() throws SQLException {
+        if(colOrder != null)
+            return colOrder;
+
+        if(!metaInit)
+            meta();
+
+        colOrder = new HashMap<>(meta.size());
+
+        for (int i = 0; i < meta.size(); ++i) {
+            String colName = meta.get(i).columnName().toUpperCase();
+
+            if(!colOrder.containsKey(colName))
+                colOrder.put(colName, i);
+        }
+
+        return colOrder;
+    }
+
+    /**
+     * @return Is query flag.
+     */
+    boolean isQuery() {
+        return isQuery;
+    }
+
+    /**
+     * @return Update count for no-SELECT queries.
+     */
+    long updatedCount() {
+        return updCnt;
+    }
+
+    /**
+     * @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

http://git-wip-us.apache.org/repos/asf/ignite/blob/e92707b6/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSetMetadata.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSetMetadata.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSetMetadata.java
new file mode 100644
index 0000000..4c560bc
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSetMetadata.java
@@ -0,0 +1,161 @@
+/*
+ * 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.internal.jdbc.thin;
+
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.List;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcColumnMeta;
+
+/**
+ * JDBC result set metadata implementation.
+ */
+public class JdbcThinResultSetMetadata implements ResultSetMetaData {
+    /** Column width. */
+    private static final int COL_WIDTH = 30;
+
+    /** Table names. */
+    private final List<JdbcColumnMeta> meta;
+
+    /**
+     * @param meta Metadata.
+     */
+    JdbcThinResultSetMetadata(List<JdbcColumnMeta> meta) {
+        assert meta != null;
+
+        this.meta = meta;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getColumnCount() throws SQLException {
+        return meta.size();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isAutoIncrement(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isCaseSensitive(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isSearchable(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isCurrency(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int isNullable(int col) throws SQLException {
+        return columnNullable;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isSigned(int col) throws SQLException {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getColumnDisplaySize(int col) throws SQLException {
+        return COL_WIDTH;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getColumnLabel(int col) throws SQLException {
+        return meta.get(col - 1).columnName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getColumnName(int col) throws SQLException {
+        return meta.get(col - 1).columnName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getSchemaName(int col) throws SQLException {
+        return meta.get(col - 1).schemaName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getPrecision(int col) throws SQLException {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getScale(int col) throws SQLException {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getTableName(int col) throws SQLException {
+        return meta.get(col - 1).tableName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getCatalogName(int col) throws SQLException {
+        return "";
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getColumnType(int col) throws SQLException {
+        return meta.get(col - 1).dataType();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getColumnTypeName(int col) throws SQLException {
+        return meta.get(col - 1).dataTypeName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isReadOnly(int col) throws SQLException {
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isWritable(int col) throws SQLException {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isDefinitelyWritable(int col) throws SQLException 
{
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getColumnClassName(int col) throws SQLException {
+        return meta.get(col - 1).dataTypeClass();
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T unwrap(Class<T> iface) throws SQLException {
+        if (!isWrapperFor(iface))
+            throw new SQLException("Result set meta data is not a wrapper for 
" + iface.getName());
+
+        return (T)this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return iface != null && 
iface.isAssignableFrom(JdbcThinResultSetMetadata.class);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/e92707b6/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
 
b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
new file mode 100644
index 0000000..2bcd4d1
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
@@ -0,0 +1,475 @@
+/*
+ * 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.internal.jdbc.thin;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.sql.SQLWarning;
+import java.sql.Statement;
+import java.util.ArrayList;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cache.query.SqlQuery;
+import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult;
+
+import static java.sql.ResultSet.CONCUR_READ_ONLY;
+import static java.sql.ResultSet.FETCH_FORWARD;
+import static java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
+import static java.sql.ResultSet.TYPE_FORWARD_ONLY;
+
+/**
+ * JDBC statement implementation.
+ */
+public class JdbcThinStatement implements Statement {
+    /** Default queryPage size. */
+    private static final int DFLT_PAGE_SIZE = SqlQuery.DFLT_PAGE_SIZE;
+
+    /** Ignite endpoint and I/O protocol implementation. */
+    private JdbcThinConnection conn;
+
+    /** Closed flag. */
+    private boolean closed;
+
+    /** Rows limit. */
+    private int maxRows;
+
+    /** Query timeout. */
+    private int timeout;
+
+    /** Current result set. */
+    private JdbcThinResultSet rs;
+
+    /** Query arguments. */
+    protected ArrayList<Object> args;
+
+    /** Fetch size. */
+    private int pageSize = DFLT_PAGE_SIZE;
+
+    private boolean alreadyRead;
+
+    /**
+     * Creates new statement.
+     *
+     * @param conn JDBC connection.
+     */
+    JdbcThinStatement(JdbcThinConnection conn) {
+        assert conn != null;
+
+        this.conn = conn;
+    }
+
+    /** {@inheritDoc} */
+    @Override public ResultSet executeQuery(String sql) throws SQLException {
+        JdbcThinResultSet rs = execute0(sql);
+
+        if (!rs.isQuery())
+            throw new SQLException("The query isn't SELECT query: [sql=" + sql 
+']');
+
+        return rs;
+    }
+
+    /**
+     * @param sql Sql query.
+     * @return Result set.
+     * @throws SQLException Onj error.
+     */
+    protected JdbcThinResultSet execute0(String sql) throws SQLException {
+        ensureNotClosed();
+
+        if (rs != null) {
+            rs.close();
+
+            rs = null;
+        }
+
+        alreadyRead = false;
+
+        if (sql == null || sql.isEmpty())
+            throw new SQLException("SQL query is empty.");
+
+        try {
+            JdbcQueryExecuteResult res = 
conn.cliIo().queryExecute(conn.getSchema(), pageSize, maxRows,
+                sql, args);
+
+            assert res != null;
+
+            rs = new JdbcThinResultSet(this, res.getQueryId(), pageSize, 
res.last(), res.items(), res.isQuery());
+
+            return rs;
+        }
+        catch (IOException e) {
+            conn.close();
+
+            throw new SQLException("Failed to query Ignite.", e);
+        }
+        catch (IgniteCheckedException e) {
+            throw new SQLException("Failed to query Ignite.", e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public int executeUpdate(String sql) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void close() throws SQLException {
+        if (isClosed())
+            return;
+
+        if (rs != null)
+            rs.close();
+
+        closed = true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getMaxFieldSize() throws SQLException {
+        ensureNotClosed();
+
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setMaxFieldSize(int max) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Field size limitation is 
not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getMaxRows() throws SQLException {
+        ensureNotClosed();
+
+        return maxRows;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setMaxRows(int maxRows) throws SQLException {
+        ensureNotClosed();
+
+        this.maxRows = maxRows;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setEscapeProcessing(boolean enable) throws 
SQLException {
+        ensureNotClosed();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getQueryTimeout() throws SQLException {
+        ensureNotClosed();
+
+        return timeout / 1000;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setQueryTimeout(int timeout) throws SQLException {
+        ensureNotClosed();
+
+        this.timeout = timeout * 1000;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void cancel() throws SQLException {
+        ensureNotClosed();
+    }
+
+    /** {@inheritDoc} */
+    @Override public SQLWarning getWarnings() throws SQLException {
+        ensureNotClosed();
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void clearWarnings() throws SQLException {
+        ensureNotClosed();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setCursorName(String name) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean execute(String sql) throws SQLException {
+        ensureNotClosed();
+
+        rs = execute0(sql);
+
+        return rs.isQuery();
+    }
+
+    /** {@inheritDoc} */
+    @Override public ResultSet getResultSet() throws SQLException {
+        ensureNotClosed();
+
+        if (rs == null || !rs.isQuery() || alreadyRead)
+            return null;
+
+        alreadyRead = true;
+
+        return rs;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getUpdateCount() throws SQLException {
+        ensureNotClosed();
+
+        if (rs == null || rs.isQuery() || alreadyRead)
+            return -1;
+
+        alreadyRead = true;
+
+        return (int)rs.updatedCount();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean getMoreResults() throws SQLException {
+        ensureNotClosed();
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setFetchDirection(int direction) throws SQLException 
{
+        ensureNotClosed();
+
+        if (direction != FETCH_FORWARD)
+            throw new SQLFeatureNotSupportedException("Only forward direction 
is supported");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getFetchDirection() throws SQLException {
+        ensureNotClosed();
+
+        return FETCH_FORWARD;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setFetchSize(int fetchSize) throws SQLException {
+        ensureNotClosed();
+
+        if (fetchSize <= 0)
+            throw new SQLException("Fetch size must be greater than zero.");
+
+        this.pageSize = fetchSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getFetchSize() throws SQLException {
+        ensureNotClosed();
+
+        return pageSize;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getResultSetConcurrency() throws SQLException {
+        ensureNotClosed();
+
+        return CONCUR_READ_ONLY;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getResultSetType() throws SQLException {
+        ensureNotClosed();
+
+        return TYPE_FORWARD_ONLY;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void addBatch(String sql) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void clearBatch() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int[] executeBatch() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Connection getConnection() throws SQLException {
+        ensureNotClosed();
+
+        return conn;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean getMoreResults(int curr) throws SQLException {
+        ensureNotClosed();
+
+        if (curr == KEEP_CURRENT_RESULT || curr == CLOSE_ALL_RESULTS)
+            throw new SQLFeatureNotSupportedException("Multiple open results 
are not supported.");
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public ResultSet getGeneratedKeys() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int executeUpdate(String sql, int autoGeneratedKeys) 
throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int executeUpdate(String sql, int[] colIndexes) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public int executeUpdate(String sql, String[] colNames) throws 
SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean execute(String sql, int autoGeneratedKeys) throws 
SQLException {
+        ensureNotClosed();
+
+        if (autoGeneratedKeys == RETURN_GENERATED_KEYS)
+            throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+
+        return execute(sql);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean execute(String sql, int[] colIndexes) throws 
SQLException {
+        ensureNotClosed();
+
+        if (colIndexes != null && colIndexes.length > 0)
+            throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+
+        return execute(sql);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean execute(String sql, String[] colNames) throws 
SQLException {
+        ensureNotClosed();
+
+        if (colNames != null && colNames.length > 0)
+            throw new SQLFeatureNotSupportedException("Updates are not 
supported.");
+
+        return execute(sql);
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getResultSetHoldability() throws SQLException {
+        ensureNotClosed();
+
+        return HOLD_CURSORS_OVER_COMMIT;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isClosed() throws SQLException {
+        return conn.isClosed() || closed;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setPoolable(boolean poolable) throws SQLException {
+        ensureNotClosed();
+
+        if (poolable)
+            throw new SQLFeatureNotSupportedException("Pooling is not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isPoolable() throws SQLException {
+        ensureNotClosed();
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public <T> T unwrap(Class<T> iface) throws SQLException {
+        if (!isWrapperFor(iface))
+            throw new SQLException("Statement is not a wrapper for " + 
iface.getName());
+
+        return (T)this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return iface != null && 
iface.isAssignableFrom(JdbcThinStatement.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void closeOnCompletion() throws SQLException {
+        throw new SQLFeatureNotSupportedException("closeOnCompletion is not 
supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isCloseOnCompletion() throws SQLException {
+        ensureNotClosed();
+
+        return false;
+    }
+
+    /**
+     * Sets timeout in milliseconds.
+     *
+     * @param timeout Timeout.
+     */
+    void timeout(int timeout) {
+        this.timeout = timeout;
+    }
+
+    /**
+     * @return Connection.
+     */
+    JdbcThinConnection connection() {
+        return conn;
+    }
+
+    /**
+     * Ensures that statement is not closed.
+     *
+     * @throws SQLException If statement is closed.
+     */
+    protected void ensureNotClosed() throws SQLException {
+        if (isClosed())
+            throw new SQLException("Statement is closed.");
+    }
+}

Reply via email to