You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/06/06 08:59:29 UTC
[11/50] [abbrv] ignite git commit: IGNITE-5176: JDBC thin driver:
implemented query execution. This closes #1994. This closes #2040.
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;
+ }
+}