ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sboi...@apache.org
Subject [11/50] [abbrv] ignite git commit: IGNITE-5176: JDBC thin driver: implemented query execution. This closes #1994. This closes #2040.
Date Tue, 06 Jun 2017 08:59:29 GMT
http://git-wip-us.apache.org/repos/asf/ignite/blob/e92707b6/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java
new file mode 100644
index 0000000..418b5fc
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinResultSetSelfTest.java
@@ -0,0 +1,762 @@
+/*
+ * 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.thin;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.binary.BinaryMarshaller;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ * Result set test.
+ */
+@SuppressWarnings("FloatingPointEquality")
+public class JdbcThinResultSetSelfTest extends JdbcThinAbstractSelfTest {
+    /** IP finder. */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** URL. */
+    private static final String URL = "jdbc:ignite:thin://127.0.0.1/";
+
+    /** SQL query. */
+    private static final String SQL =
+        "select id, boolVal, byteVal, shortVal, intVal, longVal, floatVal, " +
+            "doubleVal, bigVal, strVal, arrVal, dateVal, timeVal, tsVal " +
+            "from TestObject where id = 1";
+
+    /** Statement. */
+    private Statement stmt;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        CacheConfiguration<?,?> cache = defaultCacheConfiguration();
+
+        cache.setCacheMode(PARTITIONED);
+        cache.setBackups(1);
+        cache.setWriteSynchronizationMode(FULL_SYNC);
+        cache.setIndexedTypes(
+            Integer.class, TestObject.class
+        );
+
+        cfg.setCacheConfiguration(cache);
+
+        TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+        disco.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(disco);
+
+        cfg.setMarshaller(new BinaryMarshaller());
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGridsMultiThreaded(3);
+
+        IgniteCache<Integer, TestObject> cache = grid(0).cache(DEFAULT_CACHE_NAME);
+
+        assert cache != null;
+
+        TestObject o = createObjectWithData(1);
+
+        cache.put(1, o);
+        cache.put(2, new TestObject(2));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        Connection conn = DriverManager.getConnection(URL);
+
+        conn.setSchema(DEFAULT_CACHE_NAME);
+
+        stmt = conn.createStatement();
+
+        assert stmt != null;
+        assert !stmt.isClosed();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        if (stmt != null) {
+            stmt.getConnection().close();
+
+            stmt.close();
+
+            assert stmt.isClosed();
+        }
+    }
+
+    /**
+     * @param id ID.
+     * @return Object.
+     * @throws MalformedURLException If URL in incorrect.
+     */
+    @SuppressWarnings("deprecation")
+    private TestObject createObjectWithData(int id) throws MalformedURLException {
+        TestObject o = new TestObject(id);
+
+        o.boolVal = true;
+        o.byteVal = 1;
+        o.shortVal = 1;
+        o.intVal = 1;
+        o.longVal = 1L;
+        o.floatVal = 1.0f;
+        o.doubleVal = 1.0d;
+        o.bigVal = new BigDecimal(1);
+        o.strVal = "str";
+        o.arrVal = new byte[] {1};
+        o.dateVal = new Date(1, 1, 1);
+        o.timeVal = new Time(1, 1, 1);
+        o.tsVal = new Timestamp(1);
+        o.urlVal = new URL("http://abc.com/");
+
+        return o;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testBoolean() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getBoolean("boolVal");
+                assert rs.getBoolean(2);
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+
+
+        ResultSet rs0 = stmt.executeQuery("select 1");
+
+        assert rs0.next();
+        assert rs0.getBoolean(1);
+
+        rs0 = stmt.executeQuery("select 0");
+
+        assert rs0.next();
+        assert !rs0.getBoolean(1);
+
+        rs0 = stmt.executeQuery("select '1'");
+
+        assert rs0.next();
+        assert rs0.getBoolean(1);
+
+        rs0 = stmt.executeQuery("select '0'");
+
+        assert rs0.next();
+        assert !rs0.getBoolean(1);
+
+        GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                ResultSet rs0 = stmt.executeQuery("select 10");
+
+                assert rs0.next();
+                assert rs0.getBoolean(1);
+
+                return null;
+            }
+        }, ClassCastException.class, "Cannot cast java.lang.Integer [val=10] to boolean");
+
+        GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                ResultSet rs0 = stmt.executeQuery("select '10'");
+
+                assert rs0.next();
+                assert rs0.getBoolean(1);
+
+                return null;
+            }
+        }, ClassCastException.class, "Cannot cast java.lang.Integer [val=10] to boolean");
+
+        GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                ResultSet rs0 = stmt.executeQuery("select ''");
+
+                assert rs0.next();
+                assert rs0.getBoolean(1);
+
+                return null;
+            }
+        }, ClassCastException.class, "Cannot cast [val=] to boolean");
+
+        GridTestUtils.assertThrowsAnyCause(log, new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                ResultSet rs0 = stmt.executeQuery("select 'qwe'");
+
+                assert rs0.next();
+                assert rs0.getBoolean(1);
+
+                return null;
+            }
+        }, ClassCastException.class, "Cannot cast [val=qwe] to boolean");
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testByte() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getByte("byteVal") == 1;
+                assert rs.getByte(3) == 1;
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testShort() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getShort("shortVal") == 1;
+                assert rs.getShort(4) == 1;
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testInteger() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getInt("intVal") == 1;
+                assert rs.getInt(5) == 1;
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testLong() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getLong("longVal") == 1;
+                assert rs.getLong(6) == 1;
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testFloat() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getFloat("floatVal") == 1.0;
+                assert rs.getFloat(7) == 1.0;
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testDouble() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getDouble("doubleVal") == 1.0;
+                assert rs.getDouble(8) == 1.0;
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testBigDecimal() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getBigDecimal("bigVal").intValue() == 1;
+                assert rs.getBigDecimal(9).intValue() == 1;
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testString() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert "str".equals(rs.getString("strVal"));
+                assert "str".equals(rs.getString(10));
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testArray() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert Arrays.equals(rs.getBytes("arrVal"), new byte[] {1});
+                assert Arrays.equals(rs.getBytes(11), new byte[] {1});
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @SuppressWarnings("deprecation")
+    public void testDate() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getDate("dateVal").equals(new Date(1, 1, 1));
+                assert rs.getDate(12).equals(new Date(1, 1, 1));
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @SuppressWarnings("deprecation")
+    public void testTime() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getTime("timeVal").equals(new Time(1, 1, 1));
+                assert rs.getTime(13).equals(new Time(1, 1, 1));
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testTimestamp() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            if (cnt == 0) {
+                assert rs.getTimestamp("tsVal").getTime() == 1;
+                assert rs.getTimestamp(14).getTime() == 1;
+            }
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testObjectNotSupported() throws Exception {
+        GridTestUtils.assertThrowsAnyCause(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                stmt.executeQuery("select f1 from TestObject where id = 1");
+
+                return null;
+            }
+        }, IgniteCheckedException.class, "Custom objects are not supported");
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testNavigation() throws Exception {
+        ResultSet rs = stmt.executeQuery("select id from TestObject where id > 0");
+
+        assert rs.isBeforeFirst();
+        assert !rs.isAfterLast();
+        assert !rs.isFirst();
+        assert !rs.isLast();
+        assert rs.getRow() == 0;
+
+        assert rs.next();
+
+        assert !rs.isBeforeFirst();
+        assert !rs.isAfterLast();
+        assert rs.isFirst();
+        assert !rs.isLast();
+        assert rs.getRow() == 1;
+
+        assert rs.next();
+
+        assert !rs.isBeforeFirst();
+        assert !rs.isAfterLast();
+        assert !rs.isFirst();
+        assert rs.isLast();
+        assert rs.getRow() == 2;
+
+        assert !rs.next();
+
+        assert !rs.isBeforeFirst();
+        assert rs.isAfterLast();
+        assert !rs.isFirst();
+        assert !rs.isLast();
+        assert rs.getRow() == 0;
+
+        rs = stmt.executeQuery("select id from TestObject where id < 0");
+
+        assert !rs.isBeforeFirst();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testFindColumn() throws Exception {
+        final ResultSet rs = stmt.executeQuery(SQL);
+
+        assert rs != null;
+        assert rs.next();
+
+        assert rs.findColumn("id") == 1;
+
+        GridTestUtils.assertThrows(
+            log,
+            new Callable<Object>() {
+                @Override public Object call() throws Exception {
+                    rs.findColumn("wrong");
+
+                    return null;
+                }
+            },
+            SQLException.class,
+            "Column not found: wrong"
+        );
+    }
+
+    /**
+     * Test object.
+     */
+    @SuppressWarnings("UnusedDeclaration")
+    private static class TestObject implements Serializable {
+        /** */
+        @QuerySqlField
+        private final int id;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Boolean boolVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Byte byteVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Short shortVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Integer intVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Long longVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Float floatVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Double doubleVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private BigDecimal bigVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private String strVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private byte[] arrVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Date dateVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Time timeVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private Timestamp tsVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private URL urlVal;
+
+        /** */
+        @QuerySqlField(index = false)
+        private TestObjectField f1 = new TestObjectField(100, "AAAA");
+
+        /** */
+        @QuerySqlField(index = false)
+        private TestObjectField f2 = new TestObjectField(500, "BBBB");
+
+        /** */
+        @QuerySqlField(index = false)
+        private TestObjectField f3;
+
+        /**
+         * @param id ID.
+         */
+        private TestObject(int id) {
+            this.id = id;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(TestObject.class, this);
+        }
+
+        /** {@inheritDoc} */
+        @SuppressWarnings({"BigDecimalEquals", "EqualsHashCodeCalledOnUrl", "RedundantIfStatement"})
+        @Override public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            TestObject that = (TestObject)o;
+
+            if (id != that.id) return false;
+            if (!Arrays.equals(arrVal, that.arrVal)) return false;
+            if (bigVal != null ? !bigVal.equals(that.bigVal) : that.bigVal != null) return false;
+            if (boolVal != null ? !boolVal.equals(that.boolVal) : that.boolVal != null) return false;
+            if (byteVal != null ? !byteVal.equals(that.byteVal) : that.byteVal != null) return false;
+            if (dateVal != null ? !dateVal.equals(that.dateVal) : that.dateVal != null) return false;
+            if (doubleVal != null ? !doubleVal.equals(that.doubleVal) : that.doubleVal != null) return false;
+            if (f1 != null ? !f1.equals(that.f1) : that.f1 != null) return false;
+            if (f2 != null ? !f2.equals(that.f2) : that.f2 != null) return false;
+            if (f3 != null ? !f3.equals(that.f3) : that.f3 != null) return false;
+            if (floatVal != null ? !floatVal.equals(that.floatVal) : that.floatVal != null) return false;
+            if (intVal != null ? !intVal.equals(that.intVal) : that.intVal != null) return false;
+            if (longVal != null ? !longVal.equals(that.longVal) : that.longVal != null) return false;
+            if (shortVal != null ? !shortVal.equals(that.shortVal) : that.shortVal != null) return false;
+            if (strVal != null ? !strVal.equals(that.strVal) : that.strVal != null) return false;
+            if (timeVal != null ? !timeVal.equals(that.timeVal) : that.timeVal != null) return false;
+            if (tsVal != null ? !tsVal.equals(that.tsVal) : that.tsVal != null) return false;
+            if (urlVal != null ? !urlVal.equals(that.urlVal) : that.urlVal != null) return false;
+
+            return true;
+        }
+
+        /** {@inheritDoc} */
+        @SuppressWarnings("EqualsHashCodeCalledOnUrl")
+        @Override public int hashCode() {
+            int res = id;
+
+            res = 31 * res + (boolVal != null ? boolVal.hashCode() : 0);
+            res = 31 * res + (byteVal != null ? byteVal.hashCode() : 0);
+            res = 31 * res + (shortVal != null ? shortVal.hashCode() : 0);
+            res = 31 * res + (intVal != null ? intVal.hashCode() : 0);
+            res = 31 * res + (longVal != null ? longVal.hashCode() : 0);
+            res = 31 * res + (floatVal != null ? floatVal.hashCode() : 0);
+            res = 31 * res + (doubleVal != null ? doubleVal.hashCode() : 0);
+            res = 31 * res + (bigVal != null ? bigVal.hashCode() : 0);
+            res = 31 * res + (strVal != null ? strVal.hashCode() : 0);
+            res = 31 * res + (arrVal != null ? Arrays.hashCode(arrVal) : 0);
+            res = 31 * res + (dateVal != null ? dateVal.hashCode() : 0);
+            res = 31 * res + (timeVal != null ? timeVal.hashCode() : 0);
+            res = 31 * res + (tsVal != null ? tsVal.hashCode() : 0);
+            res = 31 * res + (urlVal != null ? urlVal.hashCode() : 0);
+            res = 31 * res + (f1 != null ? f1.hashCode() : 0);
+            res = 31 * res + (f2 != null ? f2.hashCode() : 0);
+            res = 31 * res + (f3 != null ? f3.hashCode() : 0);
+
+            return res;
+        }
+    }
+
+    /**
+     * Test object field.
+     */
+    @SuppressWarnings("PackageVisibleField")
+    private static class TestObjectField implements Serializable {
+        /** */
+        final int a;
+
+        /** */
+        final String b;
+
+        /**
+         * @param a A.
+         * @param b B.
+         */
+        private TestObjectField(int a, String b) {
+            this.a = a;
+            this.b = b;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            TestObjectField that = (TestObjectField)o;
+
+            return a == that.a && !(b != null ? !b.equals(that.b) : that.b != null);
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            int res = a;
+
+            res = 31 * res + (b != null ? b.hashCode() : 0);
+
+            return res;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(TestObjectField.class, this);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/e92707b6/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java
new file mode 100644
index 0000000..a9a7e7b
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java
@@ -0,0 +1,343 @@
+/*
+ * 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.thin;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.cache.query.annotations.QuerySqlField;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.OdbcConfiguration;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
+import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
+
+/**
+ * Statement test.
+ */
+public class JdbcThinStatementSelfTest extends JdbcThinAbstractSelfTest {
+    /** IP finder. */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** URL. */
+    private static final String URL = "jdbc:ignite:thin://127.0.0.1/";
+
+    /** SQL query. */
+    private static final String SQL = "select * from Person where age > 30";
+
+    /** Connection. */
+    private Connection conn;
+
+    /** Statement. */
+    private Statement stmt;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        CacheConfiguration<?,?> cache = defaultCacheConfiguration();
+
+        cache.setCacheMode(PARTITIONED);
+        cache.setBackups(1);
+        cache.setWriteSynchronizationMode(FULL_SYNC);
+        cache.setIndexedTypes(
+            String.class, Person.class
+        );
+
+        cfg.setCacheConfiguration(cache);
+
+        TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+        disco.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(disco);
+
+        cfg.setOdbcConfiguration(new OdbcConfiguration());
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGridsMultiThreaded(3);
+
+        IgniteCache<String, Person> cache = grid(0).cache(DEFAULT_CACHE_NAME);
+
+        assert cache != null;
+
+        cache.put("p1", new Person(1, "John", "White", 25));
+        cache.put("p2", new Person(2, "Joe", "Black", 35));
+        cache.put("p3", new Person(3, "Mike", "Green", 40));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        conn = DriverManager.getConnection(URL);
+
+        conn.setSchema(DEFAULT_CACHE_NAME);
+
+        stmt = conn.createStatement();
+
+        assert stmt != null;
+        assert !stmt.isClosed();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        if (stmt != null && !stmt.isClosed()) {
+            stmt.close();
+
+            assert stmt.isClosed();
+        }
+
+        conn.close();
+
+        assert stmt.isClosed();
+        assert conn.isClosed();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testExecuteQuery() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        assert rs != null;
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            int id = rs.getInt("id");
+
+            if (id == 2) {
+                assert "Joe".equals(rs.getString("firstName"));
+                assert "Black".equals(rs.getString("lastName"));
+                assert rs.getInt("age") == 35;
+            }
+            else if (id == 3) {
+                assert "Mike".equals(rs.getString("firstName"));
+                assert "Green".equals(rs.getString("lastName"));
+                assert rs.getInt("age") == 40;
+            }
+            else
+                assert false : "Wrong ID: " + id;
+
+            cnt++;
+        }
+
+        assert cnt == 2;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testExecute() throws Exception {
+        assert stmt.execute(SQL);
+
+        assert stmt.getUpdateCount() == -1 : "Update count must be -1 for SELECT query";
+
+        ResultSet rs = stmt.getResultSet();
+
+        assert rs != null;
+
+        assert stmt.getResultSet() == null;
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            int id = rs.getInt("id");
+
+            if (id == 2) {
+                assert "Joe".equals(rs.getString("firstName"));
+                assert "Black".equals(rs.getString("lastName"));
+                assert rs.getInt("age") == 35;
+            }
+            else if (id == 3) {
+                assert "Mike".equals(rs.getString("firstName"));
+                assert "Green".equals(rs.getString("lastName"));
+                assert rs.getInt("age") == 40;
+            }
+            else
+                assert false : "Wrong ID: " + id;
+
+            cnt++;
+        }
+
+        assert cnt == 2;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMaxRows() throws Exception {
+        stmt.setMaxRows(1);
+
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        assert rs != null;
+
+        int cnt = 0;
+
+        while (rs.next()) {
+            int id = rs.getInt("id");
+
+            if (id == 2) {
+                assert "Joe".equals(rs.getString("firstName"));
+                assert "Black".equals(rs.getString("lastName"));
+                assert rs.getInt("age") == 35;
+            }
+            else if (id == 3) {
+                assert "Mike".equals(rs.getString("firstName"));
+                assert "Green".equals(rs.getString("lastName"));
+                assert rs.getInt("age") == 40;
+            }
+            else
+                assert false : "Wrong ID: " + id;
+
+            cnt++;
+        }
+
+        assert cnt == 1;
+
+        stmt.setMaxRows(0);
+
+        rs = stmt.executeQuery(SQL);
+
+        assert rs != null;
+
+        cnt = 0;
+
+        while (rs.next()) {
+            int id = rs.getInt("id");
+
+            if (id == 2) {
+                assert "Joe".equals(rs.getString("firstName"));
+                assert "Black".equals(rs.getString("lastName"));
+                assert rs.getInt("age") == 35;
+            }
+            else if (id == 3) {
+                assert "Mike".equals(rs.getString("firstName"));
+                assert "Green".equals(rs.getString("lastName"));
+                assert rs.getInt("age") == 40;
+            }
+            else
+                assert false : "Wrong ID: " + id;
+
+            cnt++;
+        }
+
+        assert cnt == 2;
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testCloseResultSet0() throws Exception {
+        ResultSet rs0 = stmt.executeQuery(SQL);
+        ResultSet rs1 = stmt.executeQuery(SQL);
+        ResultSet rs2 = stmt.executeQuery(SQL);
+
+        assert rs0.isClosed() : "ResultSet must be implicitly closed after re-execute statement";
+        assert rs1.isClosed() : "ResultSet must be implicitly closed after re-execute statement";
+
+        assert !rs2.isClosed() : "Last result set must be available";
+
+        stmt.close();
+
+        assert rs2.isClosed() : "ResultSet must be explicitly closed after close statement";
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testCloseResultSet1() throws Exception {
+        stmt.execute(SQL);
+
+        ResultSet rs = stmt.getResultSet();
+
+        stmt.close();
+
+        assert rs.isClosed() : "ResultSet must be explicitly closed after close statement";
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testCloseResultSetByConnectionClose() throws Exception {
+        ResultSet rs = stmt.executeQuery(SQL);
+
+        conn.close();
+
+        assert stmt.isClosed() : "Statement must be implicitly closed after close connection";
+        assert rs.isClosed() : "ResultSet must be implicitly closed after close connection";
+    }
+
+    /**
+     * Person.
+     */
+    @SuppressWarnings("UnusedDeclaration")
+    private static class Person implements Serializable {
+        /** ID. */
+        @QuerySqlField
+        private final int id;
+
+        /** First name. */
+        @QuerySqlField(index = false)
+        private final String firstName;
+
+        /** Last name. */
+        @QuerySqlField(index = false)
+        private final String lastName;
+
+        /** Age. */
+        @QuerySqlField
+        private final int age;
+
+        /**
+         * @param id ID.
+         * @param firstName First name.
+         * @param lastName Last name.
+         * @param age Age.
+         */
+        private Person(int id, String firstName, String lastName, int age) {
+            assert !F.isEmpty(firstName);
+            assert !F.isEmpty(lastName);
+            assert age > 0;
+
+            this.id = id;
+            this.firstName = firstName;
+            this.lastName = lastName;
+            this.age = age;
+        }
+    }
+}
\ 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/IgniteJdbcDriver.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java
index df4929c..345bbc3 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java
@@ -385,6 +385,9 @@ public class IgniteJdbcDriver implements Driver {
 
     /** {@inheritDoc} */
     @Override public Connection connect(String url, Properties props) throws SQLException {
+        if (!acceptsURL(url))
+            return null;
+
         if (!parseUrl(url, props))
             throw new SQLException("URL is invalid: " + url);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e92707b6/modules/core/src/main/java/org/apache/ignite/IgniteJdbcThinDriver.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteJdbcThinDriver.java b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcThinDriver.java
index 19e1edd..5c04701 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteJdbcThinDriver.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcThinDriver.java
@@ -31,7 +31,7 @@ import org.apache.ignite.cache.affinity.AffinityKey;
 import org.apache.ignite.configuration.OdbcConfiguration;
 import org.apache.ignite.internal.IgniteVersionUtils;
 import org.apache.ignite.internal.jdbc.JdbcDriverPropertyInfo;
-import org.apache.ignite.internal.jdbc.thin.JdbcConnection;
+import org.apache.ignite.internal.jdbc.thin.JdbcThinConnection;
 
 /**
  * JDBC driver thin implementation for In-Memory Data Grid.
@@ -179,10 +179,13 @@ public class IgniteJdbcThinDriver implements Driver {
 
     /** {@inheritDoc} */
     @Override public Connection connect(String url, Properties props) throws SQLException {
+        if (!acceptsURL(url))
+            return null;
+
         if (!parseUrl(url, props))
             throw new SQLException("URL is invalid: " + url);
 
-        return new JdbcConnection(url, props);
+        return new JdbcThinConnection(url, props);
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/e92707b6/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcConnection.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcConnection.java
deleted file mode 100644
index 25d62b4..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcConnection.java
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * 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.Array;
-import java.sql.Blob;
-import java.sql.CallableStatement;
-import java.sql.Clob;
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.NClob;
-import java.sql.PreparedStatement;
-import java.sql.SQLClientInfoException;
-import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
-import java.sql.SQLWarning;
-import java.sql.SQLXML;
-import java.sql.Savepoint;
-import java.sql.Statement;
-import java.sql.Struct;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.Executor;
-import java.util.logging.Logger;
-
-import static java.sql.ResultSet.CONCUR_READ_ONLY;
-import static java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
-import static java.sql.ResultSet.TYPE_FORWARD_ONLY;
-import static org.apache.ignite.IgniteJdbcThinDriver.PROP_DISTRIBUTED_JOINS;
-import static org.apache.ignite.IgniteJdbcThinDriver.PROP_ENFORCE_JOIN_ORDER;
-import static org.apache.ignite.IgniteJdbcThinDriver.PROP_HOST;
-import static org.apache.ignite.IgniteJdbcThinDriver.PROP_PORT;
-
-/**
- * JDBC connection implementation.
- *
- * See documentation of {@link org.apache.ignite.IgniteJdbcThinDriver} for details.
- */
-public class JdbcConnection implements Connection {
-    /** Logger. */
-    private static final Logger LOG = Logger.getLogger(JdbcConnection.class.getName());
-
-    /** Cache name. */
-    private String schemaName;
-
-    /** Closed flag. */
-    private boolean closed;
-
-    /** Current transaction isolation. */
-    private int txIsolation;
-
-    /** Auto commit flag. */
-    private boolean autoCommit;
-
-    /** Current transaction holdability. */
-    private int holdability;
-
-    /** Timeout. */
-    private int timeout;
-
-    /** Ignite endpoint. */
-    private JdbcTcpIo cliIo;
-
-    /**
-     * Creates new connection.
-     *
-     * @param url Connection URL.
-     * @param props Additional properties.
-     * @throws SQLException In case Ignite client failed to start.
-     */
-    public JdbcConnection(String url, Properties props) throws SQLException {
-        assert url != null;
-        assert props != null;
-
-        holdability = HOLD_CURSORS_OVER_COMMIT;
-        autoCommit = true;
-        txIsolation = Connection.TRANSACTION_NONE;
-
-        boolean distributedJoins = Boolean.parseBoolean(props.getProperty(PROP_DISTRIBUTED_JOINS, "false"));
-        boolean enforceJoinOrder = Boolean.parseBoolean(props.getProperty(PROP_ENFORCE_JOIN_ORDER, "false"));
-
-        String host = props.getProperty(PROP_HOST);
-        String portStr = props.getProperty(PROP_PORT);
-
-        try {
-            int port = Integer.parseInt(portStr);
-
-            if (port <= 0 || port > 0xFFFF)
-                throw new SQLException("Invalid port: " + portStr);
-        }
-        catch (NumberFormatException e) {
-            throw new SQLException("Invalid port: " + portStr, e);
-        }
-
-        if (host == null || host.trim().isEmpty())
-            throw new SQLException("Host name is empty.");
-
-        String endpoint = host.trim() + ":" + portStr.trim();
-
-        try {
-            cliIo = new JdbcTcpIo(endpoint, distributedJoins, enforceJoinOrder);
-
-            cliIo.start();
-        }
-        catch (Exception e) {
-            cliIo.close();
-
-            throw new SQLException("Failed to connect to Ignite cluster [host=" + host + ", port=" + portStr + ']', e);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override public Statement createStatement() throws SQLException {
-        return createStatement(TYPE_FORWARD_ONLY, CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT);
-    }
-
-    /** {@inheritDoc} */
-    @Override public Statement createStatement(int resSetType, int resSetConcurrency) throws SQLException {
-        return createStatement(resSetType, resSetConcurrency, HOLD_CURSORS_OVER_COMMIT);
-    }
-
-    /** {@inheritDoc} */
-    @Override public Statement createStatement(int resSetType, int resSetConcurrency,
-        int resSetHoldability) throws SQLException {
-        ensureNotClosed();
-
-        checkCursorOptions(resSetType, resSetConcurrency, resSetHoldability);
-
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    @Override public PreparedStatement prepareStatement(String sql) throws SQLException {
-        return prepareStatement(sql, TYPE_FORWARD_ONLY, CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT);
-    }
-
-    /** {@inheritDoc} */
-    @Override public PreparedStatement prepareStatement(String sql, int resSetType,
-        int resSetConcurrency) throws SQLException {
-        return prepareStatement(sql, resSetType, resSetConcurrency, HOLD_CURSORS_OVER_COMMIT);
-    }
-
-    /** {@inheritDoc} */
-    @Override public PreparedStatement prepareStatement(String sql, int resSetType, int resSetConcurrency,
-        int resSetHoldability) throws SQLException {
-        ensureNotClosed();
-
-        checkCursorOptions(resSetType, resSetConcurrency, resSetHoldability);
-
-        return null;
-    }
-
-    /**
-     * @param resSetType Cursor option.
-     * @param resSetConcurrency Cursor option.
-     * @param resSetHoldability Cursor option.
-     * @throws SQLException If options unsupported.
-     */
-    private void checkCursorOptions(int resSetType, int resSetConcurrency,
-        int resSetHoldability) throws SQLException {
-        if (resSetType != TYPE_FORWARD_ONLY)
-            throw new SQLFeatureNotSupportedException("Invalid result set type (only forward is supported.)");
-
-        if (resSetConcurrency != CONCUR_READ_ONLY)
-            throw new SQLFeatureNotSupportedException("Invalid concurrency (updates are not supported).");
-
-        if (resSetHoldability != HOLD_CURSORS_OVER_COMMIT)
-            LOG.warning("Transactions are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public CallableStatement prepareCall(String sql) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Callable functions are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public CallableStatement prepareCall(String sql, int resSetType, int resSetConcurrency)
-        throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Callable functions are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public String nativeSQL(String sql) throws SQLException {
-        ensureNotClosed();
-
-        return sql;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setAutoCommit(boolean autoCommit) throws SQLException {
-        ensureNotClosed();
-
-        this.autoCommit = autoCommit;
-
-        if (!autoCommit)
-            LOG.warning("Transactions are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean getAutoCommit() throws SQLException {
-        ensureNotClosed();
-
-        if (!autoCommit)
-            LOG.warning("Transactions are not supported.");
-
-        return autoCommit;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void commit() throws SQLException {
-        ensureNotClosed();
-
-        LOG.warning("Transactions are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public void rollback() throws SQLException {
-        ensureNotClosed();
-
-        LOG.warning("Transactions are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public void close() throws SQLException {
-        if (closed)
-            return;
-
-        closed = true;
-
-        cliIo.close();
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean isClosed() throws SQLException {
-        return closed;
-    }
-
-    /** {@inheritDoc} */
-    @Override public DatabaseMetaData getMetaData() throws SQLException {
-        ensureNotClosed();
-
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setReadOnly(boolean readOnly) throws SQLException {
-        ensureNotClosed();
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean isReadOnly() throws SQLException {
-        ensureNotClosed();
-
-        return true;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setCatalog(String catalog) throws SQLException {
-        ensureNotClosed();
-    }
-
-    /** {@inheritDoc} */
-    @Override public String getCatalog() throws SQLException {
-        ensureNotClosed();
-
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setTransactionIsolation(int level) throws SQLException {
-        ensureNotClosed();
-
-        LOG.warning("Transactions are not supported.");
-
-        txIsolation = level;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int getTransactionIsolation() throws SQLException {
-        ensureNotClosed();
-
-        LOG.warning("Transactions are not supported.");
-
-        return txIsolation;
-    }
-
-    /** {@inheritDoc} */
-    @Override public SQLWarning getWarnings() throws SQLException {
-        ensureNotClosed();
-
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void clearWarnings() throws SQLException {
-        ensureNotClosed();
-    }
-
-    /** {@inheritDoc} */
-    @Override public Map<String, Class<?>> getTypeMap() throws SQLException {
-        throw new SQLFeatureNotSupportedException("Types mapping is not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Types mapping is not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setHoldability(int holdability) throws SQLException {
-        ensureNotClosed();
-
-        if (holdability != HOLD_CURSORS_OVER_COMMIT)
-            LOG.warning("Transactions are not supported.");
-
-        this.holdability = holdability;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int getHoldability() throws SQLException {
-        ensureNotClosed();
-
-        return holdability;
-    }
-
-    /** {@inheritDoc} */
-    @Override public Savepoint setSavepoint() throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Savepoints are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public Savepoint setSavepoint(String name) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Savepoints are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public void rollback(Savepoint savepoint) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Savepoints are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Savepoints are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public CallableStatement prepareCall(String sql, int resSetType, int resSetConcurrency,
-        int resSetHoldability) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Callable functions are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Auto generated keys are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public PreparedStatement prepareStatement(String sql, int[] colIndexes) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Auto generated keys are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public PreparedStatement prepareStatement(String sql, String[] colNames) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("Auto generated keys are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public Clob createClob() throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public Blob createBlob() throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public NClob createNClob() throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public SQLXML createSQLXML() throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean isValid(int timeout) throws SQLException {
-        if (timeout < 0)
-            throw new SQLException("Invalid timeout: " + timeout);
-
-        return !closed;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setClientInfo(String name, String val) throws SQLClientInfoException {
-        throw new UnsupportedOperationException("Client info is not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setClientInfo(Properties props) throws SQLClientInfoException {
-        throw new UnsupportedOperationException("Client info is not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public String getClientInfo(String name) throws SQLException {
-        ensureNotClosed();
-
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    @Override public Properties getClientInfo() throws SQLException {
-        ensureNotClosed();
-
-        return new Properties();
-    }
-
-    /** {@inheritDoc} */
-    @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @Override public Struct createStruct(String typeName, Object[] attrs) throws SQLException {
-        ensureNotClosed();
-
-        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
-    }
-
-    /** {@inheritDoc} */
-    @SuppressWarnings("unchecked")
-    @Override public <T> T unwrap(Class<T> iface) throws SQLException {
-        if (!isWrapperFor(iface))
-            throw new SQLException("Connection is not a wrapper for " + iface.getName());
-
-        return (T)this;
-    }
-
-    /** {@inheritDoc} */
-    @Override public boolean isWrapperFor(Class<?> iface) throws SQLException {
-        return iface != null && iface == Connection.class;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setSchema(String schema) throws SQLException {
-        schemaName = schema;
-    }
-
-    /** {@inheritDoc} */
-    @Override public String getSchema() throws SQLException {
-        return schemaName;
-    }
-
-    /** {@inheritDoc} */
-    @Override public void abort(Executor executor) throws SQLException {
-        close();
-    }
-
-    /** {@inheritDoc} */
-    @Override public void setNetworkTimeout(Executor executor, int ms) throws SQLException {
-        if (ms < 0)
-            throw new IllegalArgumentException("Timeout is below zero: " + ms);
-
-        timeout = ms;
-    }
-
-    /** {@inheritDoc} */
-    @Override public int getNetworkTimeout() throws SQLException {
-        return timeout;
-    }
-
-    /**
-     * Ensures that connection is not closed.
-     *
-     * @throws SQLException If connection is closed.
-     */
-    private void ensureNotClosed() throws SQLException {
-        if (closed)
-            throw new SQLException("Connection is closed.");
-    }
-}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e92707b6/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcTcpIo.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcTcpIo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcTcpIo.java
deleted file mode 100644
index 4946b41..0000000
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcTcpIo.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * 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.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.util.logging.Logger;
-import org.apache.ignite.IgniteCheckedException;
-import org.apache.ignite.internal.binary.BinaryReaderExImpl;
-import org.apache.ignite.internal.binary.BinaryWriterExImpl;
-import org.apache.ignite.internal.binary.streams.BinaryHeapInputStream;
-import org.apache.ignite.internal.binary.streams.BinaryHeapOutputStream;
-import org.apache.ignite.internal.processors.odbc.SqlListenerProtocolVersion;
-import org.apache.ignite.internal.processors.odbc.SqlListenerRequest;
-import org.apache.ignite.internal.processors.odbc.SqlListenerNioListener;
-import org.apache.ignite.internal.util.ipc.IpcEndpoint;
-import org.apache.ignite.internal.util.ipc.IpcEndpointFactory;
-import org.apache.ignite.internal.util.typedef.internal.U;
-
-/**
- * JDBC IO layer implementation based on blocking IPC streams.
- */
-public class JdbcTcpIo {
-    /** Current version. */
-    private static final SqlListenerProtocolVersion CURRENT_VER = SqlListenerProtocolVersion.create(2, 1, 0);
-
-    /** Initial output stream capacity. */
-    private static final int HANDSHAKE_MSG_SIZE = 10;
-
-    /** Logger. */
-    private static final Logger log = Logger.getLogger(JdbcTcpIo.class.getName());
-
-    /** Server endpoint address. */
-    private final String endpointAddr;
-
-    /** Endpoint. */
-    private IpcEndpoint endpoint;
-
-    /** Output stream. */
-    private BufferedOutputStream out;
-
-    /** Input stream. */
-    private BufferedInputStream in;
-
-    /** Distributed joins. */
-    private boolean distributedJoins;
-
-    /** Enforce join order. */
-    private boolean enforceJoinOrder;
-
-    /** Closed flag. */
-    private boolean closed;
-
-    /**
-     * @param endpointAddr Endpoint.
-     * @param distributedJoins Distributed joins flag.
-     * @param enforceJoinOrder Enforce join order flag.
-     */
-    JdbcTcpIo(String endpointAddr, boolean distributedJoins, boolean enforceJoinOrder) {
-        assert endpointAddr != null;
-
-        this.endpointAddr = endpointAddr;
-        this.distributedJoins = distributedJoins;
-        this.enforceJoinOrder= enforceJoinOrder;
-    }
-
-    /**
-     * @throws IgniteCheckedException On error.
-     * @throws IOException On IO error in handshake.
-     */
-    public void start() throws IgniteCheckedException, IOException {
-        endpoint = IpcEndpointFactory.connectEndpoint(endpointAddr, null);
-
-        out = new BufferedOutputStream(endpoint.outputStream());
-        in = new BufferedInputStream(endpoint.inputStream());
-
-        handshake();
-    }
-
-    /**
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public void handshake() throws IOException, IgniteCheckedException {
-        BinaryWriterExImpl writer = new BinaryWriterExImpl(null, new BinaryHeapOutputStream(HANDSHAKE_MSG_SIZE),
-            null, null);
-
-        writer.writeByte((byte)SqlListenerRequest.HANDSHAKE);
-
-        writer.writeShort(CURRENT_VER.major());
-        writer.writeShort(CURRENT_VER.minor());
-        writer.writeShort(CURRENT_VER.maintenance());
-
-        writer.writeByte(SqlListenerNioListener.JDBC_CLIENT);
-
-        writer.writeBoolean(distributedJoins);
-        writer.writeBoolean(enforceJoinOrder);
-
-        send(writer.array());
-
-        BinaryReaderExImpl reader = new BinaryReaderExImpl(null, new BinaryHeapInputStream(read()),
-            null, null, false);
-
-        boolean accepted = reader.readBoolean();
-
-        if (accepted)
-            return;
-
-        short maj = reader.readShort();
-        short min = reader.readShort();
-        short maintenance = reader.readShort();
-
-        String err = reader.readString();
-
-        SqlListenerProtocolVersion ver = SqlListenerProtocolVersion.create(maj, min, maintenance);
-
-        throw new IgniteCheckedException("Handshake failed [driverProtocolVer=" + CURRENT_VER +
-            ", remoteNodeProtocolVer=" + ver + ", err=" + err + ']');
-    }
-
-    /**
-     * @param req ODBC request.
-     * @throws IOException On error.
-     */
-    private void send(byte[] req) throws IOException {
-        int size = req.length;
-
-        out.write(size & 0xFF);
-        out.write((size >> 8) & 0xFF);
-        out.write((size >> 16) & 0xFF);
-        out.write((size >> 24) & 0xFF);
-
-        out.write(req);
-
-        out.flush();
-    }
-
-    /**
-     * @return Bytes of a response from server.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    private byte[] read() throws IOException, IgniteCheckedException {
-        byte[] sizeBytes = read(4);
-
-        int msgSize  = (((0xFF & sizeBytes[3]) << 24) | ((0xFF & sizeBytes[2]) << 16)
-            | ((0xFF & sizeBytes[1]) << 8) + (0xFF & sizeBytes[0]));
-
-        return read(msgSize);
-    }
-
-    /**
-     * @param size Count of bytes to read from stream.
-     * @return Read bytes.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    private byte [] read(int size) throws IOException, IgniteCheckedException {
-        int off = 0;
-
-        byte[] data = new byte[size];
-
-        while (off != size) {
-            int res = in.read(data, off, size - off);
-
-            if (res == -1)
-                throw new IgniteCheckedException("Failed to read incoming message (not enough data).");
-
-            off += res;
-        }
-
-        return data;
-    }
-
-    /**
-     * Close the client IO.
-     */
-    public void close() {
-        if (closed)
-            return;
-
-        // Clean up resources.
-        U.closeQuiet(out);
-        U.closeQuiet(in);
-
-        if (endpoint != null)
-            endpoint.close();
-
-        closed = true;
-    }
-}
\ 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/JdbcThinConnection.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
new file mode 100644
index 0000000..4ba7557
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
@@ -0,0 +1,545 @@
+/*
+ * 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.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+import java.util.logging.Logger;
+
+import static java.sql.ResultSet.CONCUR_READ_ONLY;
+import static java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
+import static java.sql.ResultSet.TYPE_FORWARD_ONLY;
+import static org.apache.ignite.IgniteJdbcThinDriver.PROP_DISTRIBUTED_JOINS;
+import static org.apache.ignite.IgniteJdbcThinDriver.PROP_ENFORCE_JOIN_ORDER;
+import static org.apache.ignite.IgniteJdbcThinDriver.PROP_HOST;
+import static org.apache.ignite.IgniteJdbcThinDriver.PROP_PORT;
+
+/**
+ * JDBC connection implementation.
+ *
+ * See documentation of {@link org.apache.ignite.IgniteJdbcThinDriver} for details.
+ */
+public class JdbcThinConnection implements Connection {
+    /** Logger. */
+    private static final Logger LOG = Logger.getLogger(JdbcThinConnection.class.getName());
+
+    /** Schema name. */
+    private String schemaName;
+
+    /** Closed flag. */
+    private boolean closed;
+
+    /** Current transaction isolation. */
+    private int txIsolation;
+
+    /** Auto commit flag. */
+    private boolean autoCommit;
+
+    /** Current transaction holdability. */
+    private int holdability;
+
+    /** Timeout. */
+    private int timeout;
+
+    /** Ignite endpoint. */
+    private JdbcThinTcpIo cliIo;
+
+    /**
+     * Creates new connection.
+     *
+     * @param url Connection URL.
+     * @param props Additional properties.
+     * @throws SQLException In case Ignite client failed to start.
+     */
+    public JdbcThinConnection(String url, Properties props) throws SQLException {
+        assert url != null;
+        assert props != null;
+
+        holdability = HOLD_CURSORS_OVER_COMMIT;
+        autoCommit = true;
+        txIsolation = Connection.TRANSACTION_NONE;
+
+        boolean distributedJoins = Boolean.parseBoolean(props.getProperty(PROP_DISTRIBUTED_JOINS, "false"));
+        boolean enforceJoinOrder = Boolean.parseBoolean(props.getProperty(PROP_ENFORCE_JOIN_ORDER, "false"));
+
+        String host = props.getProperty(PROP_HOST);
+        String portStr = props.getProperty(PROP_PORT);
+
+        try {
+            int port = Integer.parseInt(portStr);
+
+            if (port <= 0 || port > 0xFFFF)
+                throw new SQLException("Invalid port: " + portStr);
+        }
+        catch (NumberFormatException e) {
+            throw new SQLException("Invalid port: " + portStr, e);
+        }
+
+        if (host == null || host.trim().isEmpty())
+            throw new SQLException("Host name is empty.");
+
+        String endpoint = host.trim() + ":" + portStr.trim();
+
+        try {
+            cliIo = new JdbcThinTcpIo(endpoint, distributedJoins, enforceJoinOrder);
+
+            cliIo.start();
+        }
+        catch (Exception e) {
+            cliIo.close();
+
+            throw new SQLException("Failed to connect to Ignite cluster [host=" + host + ", port=" + portStr + ']', e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public Statement createStatement() throws SQLException {
+        return createStatement(TYPE_FORWARD_ONLY, CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Statement createStatement(int resSetType, int resSetConcurrency) throws SQLException {
+        return createStatement(resSetType, resSetConcurrency, HOLD_CURSORS_OVER_COMMIT);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Statement createStatement(int resSetType, int resSetConcurrency,
+        int resSetHoldability) throws SQLException {
+        ensureNotClosed();
+
+        checkCursorOptions(resSetType, resSetConcurrency, resSetHoldability);
+
+        JdbcThinStatement stmt  = new JdbcThinStatement(this);
+
+        if (timeout > 0)
+            stmt.timeout(timeout);
+
+        return stmt;
+    }
+
+    /** {@inheritDoc} */
+    @Override public PreparedStatement prepareStatement(String sql) throws SQLException {
+        return prepareStatement(sql, TYPE_FORWARD_ONLY, CONCUR_READ_ONLY, HOLD_CURSORS_OVER_COMMIT);
+    }
+
+    /** {@inheritDoc} */
+    @Override public PreparedStatement prepareStatement(String sql, int resSetType,
+        int resSetConcurrency) throws SQLException {
+        return prepareStatement(sql, resSetType, resSetConcurrency, HOLD_CURSORS_OVER_COMMIT);
+    }
+
+    /** {@inheritDoc} */
+    @Override public PreparedStatement prepareStatement(String sql, int resSetType, int resSetConcurrency,
+        int resSetHoldability) throws SQLException {
+        ensureNotClosed();
+
+        checkCursorOptions(resSetType, resSetConcurrency, resSetHoldability);
+
+        JdbcThinPreparedStatement stmt = new JdbcThinPreparedStatement(this, sql);
+
+        if (timeout > 0)
+            stmt.timeout(timeout);
+
+        return stmt;
+    }
+
+    /**
+     * @param resSetType Cursor option.
+     * @param resSetConcurrency Cursor option.
+     * @param resSetHoldability Cursor option.
+     * @throws SQLException If options unsupported.
+     */
+    private void checkCursorOptions(int resSetType, int resSetConcurrency,
+        int resSetHoldability) throws SQLException {
+        if (resSetType != TYPE_FORWARD_ONLY)
+            throw new SQLFeatureNotSupportedException("Invalid result set type (only forward is supported.)");
+
+        if (resSetConcurrency != CONCUR_READ_ONLY)
+            throw new SQLFeatureNotSupportedException("Invalid concurrency (updates are not supported).");
+
+        if (resSetHoldability != HOLD_CURSORS_OVER_COMMIT)
+            LOG.warning("Transactions are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public CallableStatement prepareCall(String sql) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Callable functions are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public CallableStatement prepareCall(String sql, int resSetType, int resSetConcurrency)
+        throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Callable functions are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public String nativeSQL(String sql) throws SQLException {
+        ensureNotClosed();
+
+        return sql;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setAutoCommit(boolean autoCommit) throws SQLException {
+        ensureNotClosed();
+
+        this.autoCommit = autoCommit;
+
+        if (!autoCommit)
+            LOG.warning("Transactions are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean getAutoCommit() throws SQLException {
+        ensureNotClosed();
+
+        if (!autoCommit)
+            LOG.warning("Transactions are not supported.");
+
+        return autoCommit;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void commit() throws SQLException {
+        ensureNotClosed();
+
+        LOG.warning("Transactions are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void rollback() throws SQLException {
+        ensureNotClosed();
+
+        LOG.warning("Transactions are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void close() throws SQLException {
+        if (isClosed())
+            return;
+
+        closed = true;
+
+        cliIo.close();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isClosed() throws SQLException {
+        return closed;
+    }
+
+    /** {@inheritDoc} */
+    @Override public DatabaseMetaData getMetaData() throws SQLException {
+        ensureNotClosed();
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setReadOnly(boolean readOnly) throws SQLException {
+        ensureNotClosed();
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isReadOnly() throws SQLException {
+        ensureNotClosed();
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setCatalog(String catalog) throws SQLException {
+        ensureNotClosed();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getCatalog() throws SQLException {
+        ensureNotClosed();
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setTransactionIsolation(int level) throws SQLException {
+        ensureNotClosed();
+
+        LOG.warning("Transactions are not supported.");
+
+        txIsolation = level;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getTransactionIsolation() throws SQLException {
+        ensureNotClosed();
+
+        LOG.warning("Transactions are not supported.");
+
+        return txIsolation;
+    }
+
+    /** {@inheritDoc} */
+    @Override public SQLWarning getWarnings() throws SQLException {
+        ensureNotClosed();
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void clearWarnings() throws SQLException {
+        ensureNotClosed();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Map<String, Class<?>> getTypeMap() throws SQLException {
+        throw new SQLFeatureNotSupportedException("Types mapping is not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Types mapping is not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setHoldability(int holdability) throws SQLException {
+        ensureNotClosed();
+
+        if (holdability != HOLD_CURSORS_OVER_COMMIT)
+            LOG.warning("Transactions are not supported.");
+
+        this.holdability = holdability;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getHoldability() throws SQLException {
+        ensureNotClosed();
+
+        return holdability;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Savepoint setSavepoint() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Savepoints are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Savepoint setSavepoint(String name) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Savepoints are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void rollback(Savepoint savepoint) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Savepoints are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Savepoints are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public CallableStatement prepareCall(String sql, int resSetType, int resSetConcurrency,
+        int resSetHoldability) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Callable functions are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Auto generated keys are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public PreparedStatement prepareStatement(String sql, int[] colIndexes) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Auto generated keys are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public PreparedStatement prepareStatement(String sql, String[] colNames) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("Auto generated keys are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Clob createClob() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Blob createBlob() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public NClob createNClob() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public SQLXML createSQLXML() throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isValid(int timeout) throws SQLException {
+        if (timeout < 0)
+            throw new SQLException("Invalid timeout: " + timeout);
+
+        return !closed;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setClientInfo(String name, String val) throws SQLClientInfoException {
+        throw new UnsupportedOperationException("Client info is not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setClientInfo(Properties props) throws SQLClientInfoException {
+        throw new UnsupportedOperationException("Client info is not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getClientInfo(String name) throws SQLException {
+        ensureNotClosed();
+
+        return null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public Properties getClientInfo() throws SQLException {
+        ensureNotClosed();
+
+        return new Properties();
+    }
+
+    /** {@inheritDoc} */
+    @Override public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+        ensureNotClosed();
+
+        throw new SQLFeatureNotSupportedException("SQL-specific types are not supported.");
+    }
+
+    /** {@inheritDoc} */
+    @Override public Struct createStruct(String typeName, Object[] attrs) 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("Connection is not a wrapper for " + iface.getName());
+
+        return (T)this;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return iface != null && iface.isAssignableFrom(JdbcThinConnection.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setSchema(String schema) throws SQLException {
+        schemaName = schema;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getSchema() throws SQLException {
+        return schemaName;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void abort(Executor executor) throws SQLException {
+        close();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setNetworkTimeout(Executor executor, int ms) throws SQLException {
+        if (ms < 0)
+            throw new IllegalArgumentException("Timeout is below zero: " + ms);
+
+        timeout = ms;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getNetworkTimeout() throws SQLException {
+        return timeout;
+    }
+
+    /**
+     * Ensures that connection is not closed.
+     *
+     * @throws SQLException If connection is closed.
+     */
+    private void ensureNotClosed() throws SQLException {
+        if (closed)
+            throw new SQLException("Connection is closed.");
+    }
+
+    /**
+     * @return Ignite endpoint and I/O protocol.
+     */
+    JdbcThinTcpIo cliIo() {
+        return cliIo;
+    }
+}


Mime
View raw message