Repository: ignite Updated Branches: refs/heads/master af4796423 -> f9955fd73
IGNITE-6317: JDBC driver: SQLSTATE support. This closes #2682. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/f9955fd7 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/f9955fd7 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/f9955fd7 Branch: refs/heads/master Commit: f9955fd7371a999cdaef3ad40c784a8c9ad4a16c Parents: af47964 Author: tledkov-gridgain <tled...@gridgain.com> Authored: Mon Sep 18 16:01:34 2017 +0300 Committer: devozerov <voze...@gridgain.com> Committed: Mon Sep 18 16:01:34 2017 +0300 ---------------------------------------------------------------------- .../internal/jdbc2/JdbcErrorsSelfTest.java | 67 +++ .../ignite/jdbc/JdbcErrorsAbstractSelfTest.java | 415 ++++++++++++++++++ .../jdbc/suite/IgniteJdbcDriverTestSuite.java | 1 + .../jdbc/thin/JdbcThinErrorsSelfTest.java | 417 ------------------- .../internal/jdbc2/JdbcBatchUpdateTask.java | 20 +- .../ignite/internal/jdbc2/JdbcConnection.java | 40 +- .../internal/jdbc2/JdbcDatabaseMetadata.java | 6 +- .../ignite/internal/jdbc2/JdbcResultSet.java | 15 +- .../ignite/internal/jdbc2/JdbcStatement.java | 31 +- .../apache/ignite/internal/jdbc2/JdbcUtils.java | 42 ++ 10 files changed, 582 insertions(+), 472 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcErrorsSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcErrorsSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcErrorsSelfTest.java new file mode 100644 index 0000000..d33e3a5 --- /dev/null +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcErrorsSelfTest.java @@ -0,0 +1,67 @@ +/* + * 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.jdbc2; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import org.apache.ignite.jdbc.JdbcErrorsAbstractSelfTest; +import org.apache.ignite.lang.IgniteCallable; + +/** + * Test SQLSTATE codes propagation with thin client driver. + */ +public class JdbcErrorsSelfTest extends JdbcErrorsAbstractSelfTest { + /** Path to JDBC configuration for node that is to start. */ + private static final String CFG_PATH = "modules/clients/src/test/config/jdbc-config.xml"; + + /** {@inheritDoc} */ + @Override protected Connection getConnection() throws SQLException { + return DriverManager.getConnection("jdbc:ignite:cfg://cache=test@" + CFG_PATH); + } + + /** + * Test error code for the case when connection string is fine but client can't reach server + * due to <b>communication problems</b> (not due to clear misconfiguration). + * @throws SQLException if failed. + */ + public void testConnectionError() throws SQLException { + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + DriverManager.getConnection("jdbc:ignite:Ñfg://cache=test@/unknown/path"); + + return null; + } + }, "08001"); + } + + /** + * Test error code for the case when connection string is a mess. + * @throws SQLException if failed. + */ + public void testInvalidConnectionStringFormat() throws SQLException { + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + // Empty config path yields an error. + DriverManager.getConnection("jdbc:ignite:cfg://cache="); + + return null; + } + }, "08001"); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java index f600e73..78020cf 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/JdbcErrorsAbstractSelfTest.java @@ -17,10 +17,18 @@ package org.apache.ignite.jdbc; +import java.net.URL; import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.Date; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; import java.util.Collections; +import java.util.List; import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.lang.IgniteCallable; @@ -90,6 +98,413 @@ public abstract class JdbcErrorsAbstractSelfTest extends GridCommonAbstractTest } /** + * Test error code for the case when user attempts to use a closed connection. + * @throws SQLException if failed. + */ + public void testConnectionClosed() throws SQLException { + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + Connection conn = getConnection(); + + conn.close(); + + conn.prepareStatement("SELECT 1"); + + return null; + } + }, "08003"); + + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + Connection conn = getConnection(); + + conn.close(); + + conn.createStatement(); + + return null; + } + }, "08003"); + + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + Connection conn = getConnection(); + + conn.close(); + + conn.getMetaData(); + + return null; + } + }, "08003"); + + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + Connection conn = getConnection(); + + DatabaseMetaData meta = conn.getMetaData(); + + conn.close(); + + meta.getIndexInfo(null, null, null, false, false); + + return null; + } + }, "08003"); + + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + Connection conn = getConnection(); + + DatabaseMetaData meta = conn.getMetaData(); + + conn.close(); + + meta.getColumns(null, null, null, null); + + return null; + } + }, "08003"); + + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + Connection conn = getConnection(); + + DatabaseMetaData meta = conn.getMetaData(); + + conn.close(); + + meta.getPrimaryKeys(null, null, null); + + return null; + } + }, "08003"); + + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + Connection conn = getConnection(); + + DatabaseMetaData meta = conn.getMetaData(); + + conn.close(); + + meta.getSchemas(null, null); + + return null; + } + }, "08003"); + + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + Connection conn = getConnection(); + + DatabaseMetaData meta = conn.getMetaData(); + + conn.close(); + + meta.getTables(null, null, null, null); + + return null; + } + }, "08003"); + } + + /** + * Test error code for the case when user attempts to use a closed result set. + * @throws SQLException if failed. + */ + public void testResultSetClosed() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 1")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.close(); + + rs.getInt(1); + } + } + }, "24000"); + } + + /** + * Test error code for the case when user attempts to get {@code int} value + * from column whose value can't be converted to an {@code int}. + * @throws SQLException if failed. + */ + public void testInvalidIntFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getLong(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@code long} value + * from column whose value can't be converted to an {@code long}. + * @throws SQLException if failed. + */ + public void testInvalidLongFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getLong(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@code float} value + * from column whose value can't be converted to an {@code float}. + * @throws SQLException if failed. + */ + public void testInvalidFloatFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getFloat(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@code double} value + * from column whose value can't be converted to an {@code double}. + * @throws SQLException if failed. + */ + public void testInvalidDoubleFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getDouble(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@code byte} value + * from column whose value can't be converted to an {@code byte}. + * @throws SQLException if failed. + */ + public void testInvalidByteFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getByte(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@code short} value + * from column whose value can't be converted to an {@code short}. + * @throws SQLException if failed. + */ + public void testInvalidShortFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getShort(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@code BigDecimal} value + * from column whose value can't be converted to an {@code BigDecimal}. + * @throws SQLException if failed. + */ + public void testInvalidBigDecimalFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getBigDecimal(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@code boolean} value + * from column whose value can't be converted to an {@code boolean}. + * @throws SQLException if failed. + */ + public void testInvalidBooleanFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getBoolean(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@code boolean} value + * from column whose value can't be converted to an {@code boolean}. + * @throws SQLException if failed. + */ + public void testInvalidObjectFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getObject(1, List.class); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@link Date} value + * from column whose value can't be converted to a {@link Date}. + * @throws SQLException if failed. + */ + public void testInvalidDateFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getDate(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@link Time} value + * from column whose value can't be converted to a {@link Time}. + * @throws SQLException if failed. + */ + public void testInvalidTimeFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getTime(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@link Timestamp} value + * from column whose value can't be converted to a {@link Timestamp}. + * @throws SQLException if failed. + */ + public void testInvalidTimestampFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getTimestamp(1); + } + } + }, "0700B"); + } + + /** + * Test error code for the case when user attempts to get {@link URL} value + * from column whose value can't be converted to a {@link URL}. + * @throws SQLException if failed. + */ + public void testInvalidUrlFormat() throws SQLException { + checkErrorState(new ConnClosure() { + @Override public void run(Connection conn) throws Exception { + try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { + ResultSet rs = stmt.executeQuery(); + + rs.next(); + + rs.getURL(1); + } + } + }, "0700B"); + } + + /** + * Check error code for the case null value is inserted into table field declared as NOT NULL. + * + * @throws SQLException if failed. + */ + public void testNotNullViolation() throws SQLException { + try (Connection conn = getConnection()) { + conn.setSchema("PUBLIC"); + + try (Statement stmt = conn.createStatement()) { + stmt.execute("CREATE TABLE nulltest(id INT PRIMARY KEY, name CHAR NOT NULL)"); + + try { + checkErrorState(new IgniteCallable<Void>() { + @Override public Void call() throws Exception { + stmt.execute("INSERT INTO nulltest(id, name) VALUES (1, NULLIF('a', 'a'))"); + + return null; + } + }, "22004"); + } + finally { + stmt.execute("DROP TABLE nulltest"); + } + } + } + } + + /** * @return Connection to execute statements on. * @throws SQLException if failed. */ http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java index 424ec21..9b37ba3 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java @@ -103,6 +103,7 @@ public class IgniteJdbcDriverTestSuite extends TestSuite { suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcBinaryMarshallerInsertStatementSelfTest.class)); suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcDeleteStatementSelfTest.class)); suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcStatementBatchingSelfTest.class)); + suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcErrorsSelfTest.class)); suite.addTest(new TestSuite(JdbcBlobTest.class)); suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcStreamingSelfTest.class)); http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinErrorsSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinErrorsSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinErrorsSelfTest.java index 7796948..afd06ed 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinErrorsSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinErrorsSelfTest.java @@ -17,18 +17,9 @@ package org.apache.ignite.jdbc.thin; -import java.net.URL; import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.Date; import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Time; -import java.sql.Timestamp; -import java.util.List; import org.apache.ignite.jdbc.JdbcErrorsAbstractSelfTest; import org.apache.ignite.lang.IgniteCallable; @@ -71,141 +62,6 @@ public class JdbcThinErrorsSelfTest extends JdbcErrorsAbstractSelfTest { }, "08001"); } - /* ALL TESTS PAST THIS POINT MUST BE MOVED TO PARENT CLASS JdbcErrorsAbstractSelfTest - * ONCE ERROR CODES RELATED WORK ON JDBC2 DRIVER IS FINISHED */ - - /** - * Test error code for the case when user attempts to use a closed connection. - * @throws SQLException if failed. - */ - public void testConnectionClosed() throws SQLException { - checkErrorState(new IgniteCallable<Void>() { - @Override public Void call() throws Exception { - Connection conn = getConnection(); - - conn.close(); - - conn.prepareStatement("SELECT 1"); - - return null; - } - }, "08003"); - - checkErrorState(new IgniteCallable<Void>() { - @Override public Void call() throws Exception { - Connection conn = getConnection(); - - conn.close(); - - conn.createStatement(); - - return null; - } - }, "08003"); - - checkErrorState(new IgniteCallable<Void>() { - @Override public Void call() throws Exception { - Connection conn = getConnection(); - - conn.close(); - - conn.getMetaData(); - - return null; - } - }, "08003"); - - checkErrorState(new IgniteCallable<Void>() { - @Override public Void call() throws Exception { - Connection conn = getConnection(); - - DatabaseMetaData meta = conn.getMetaData(); - - conn.close(); - - meta.getIndexInfo(null, null, null, false, false); - - return null; - } - }, "08003"); - - checkErrorState(new IgniteCallable<Void>() { - @Override public Void call() throws Exception { - Connection conn = getConnection(); - - DatabaseMetaData meta = conn.getMetaData(); - - conn.close(); - - meta.getColumns(null, null, null, null); - - return null; - } - }, "08003"); - - checkErrorState(new IgniteCallable<Void>() { - @Override public Void call() throws Exception { - Connection conn = getConnection(); - - DatabaseMetaData meta = conn.getMetaData(); - - conn.close(); - - meta.getPrimaryKeys(null, null, null); - - return null; - } - }, "08003"); - - checkErrorState(new IgniteCallable<Void>() { - @Override public Void call() throws Exception { - Connection conn = getConnection(); - - DatabaseMetaData meta = conn.getMetaData(); - - conn.close(); - - meta.getSchemas(null, null); - - return null; - } - }, "08003"); - - checkErrorState(new IgniteCallable<Void>() { - @Override public Void call() throws Exception { - Connection conn = getConnection(); - - DatabaseMetaData meta = conn.getMetaData(); - - conn.close(); - - meta.getTables(null, null, null, null); - - return null; - } - }, "08003"); - } - - /** - * Test error code for the case when user attempts to use a closed result set. - * @throws SQLException if failed. - */ - public void testResultSetClosed() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 1")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.close(); - - rs.getInt(1); - } - } - }, "24000"); - } - /** * Test error code for the case when user attempts to set an invalid isolation level to a connection. * @throws SQLException if failed. @@ -218,277 +74,4 @@ public class JdbcThinErrorsSelfTest extends JdbcErrorsAbstractSelfTest { } }, "0700E"); } - - /** - * Test error code for the case when user attempts to get {@code int} value - * from column whose value can't be converted to an {@code int}. - * @throws SQLException if failed. - */ - public void testInvalidIntFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getLong(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@code long} value - * from column whose value can't be converted to an {@code long}. - * @throws SQLException if failed. - */ - public void testInvalidLongFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getLong(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@code float} value - * from column whose value can't be converted to an {@code float}. - * @throws SQLException if failed. - */ - public void testInvalidFloatFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getFloat(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@code double} value - * from column whose value can't be converted to an {@code double}. - * @throws SQLException if failed. - */ - public void testInvalidDoubleFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getDouble(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@code byte} value - * from column whose value can't be converted to an {@code byte}. - * @throws SQLException if failed. - */ - public void testInvalidByteFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getByte(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@code short} value - * from column whose value can't be converted to an {@code short}. - * @throws SQLException if failed. - */ - public void testInvalidShortFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getShort(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@code BigDecimal} value - * from column whose value can't be converted to an {@code BigDecimal}. - * @throws SQLException if failed. - */ - public void testInvalidBigDecimalFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getBigDecimal(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@code boolean} value - * from column whose value can't be converted to an {@code boolean}. - * @throws SQLException if failed. - */ - public void testInvalidBooleanFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getBoolean(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@code boolean} value - * from column whose value can't be converted to an {@code boolean}. - * @throws SQLException if failed. - */ - public void testInvalidObjectFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getObject(1, List.class); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@link Date} value - * from column whose value can't be converted to a {@link Date}. - * @throws SQLException if failed. - */ - public void testInvalidDateFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getDate(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@link Time} value - * from column whose value can't be converted to a {@link Time}. - * @throws SQLException if failed. - */ - public void testInvalidTimeFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getTime(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@link Timestamp} value - * from column whose value can't be converted to a {@link Timestamp}. - * @throws SQLException if failed. - */ - public void testInvalidTimestampFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getTimestamp(1); - } - } - }, "0700B"); - } - - /** - * Test error code for the case when user attempts to get {@link URL} value - * from column whose value can't be converted to a {@link URL}. - * @throws SQLException if failed. - */ - public void testInvalidUrlFormat() throws SQLException { - checkErrorState(new ConnClosure() { - @Override public void run(Connection conn) throws Exception { - try (PreparedStatement stmt = conn.prepareStatement("SELECT 'zzz'")) { - ResultSet rs = stmt.executeQuery(); - - rs.next(); - - rs.getURL(1); - } - } - }, "0700B"); - } - - /** - * Check error code for the case null value is inserted into table field declared as NOT NULL. - * - * @throws SQLException if failed. - */ - public void testNotNullViolation() throws SQLException { - try (Connection conn = getConnection()) { - try (Statement stmt = conn.createStatement()) { - stmt.execute("CREATE TABLE nulltest(id INT PRIMARY KEY, name CHAR NOT NULL)"); - - try { - checkErrorState(new IgniteCallable<Void>() { - @Override public Void call() throws Exception { - stmt.execute("INSERT INTO nulltest(id, name) VALUES (1, NULLIF('a', 'a'))"); - - return null; - } - }, "22004"); - } - finally { - stmt.execute("DROP TABLE nulltest"); - } - } - } - } } http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcBatchUpdateTask.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcBatchUpdateTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcBatchUpdateTask.java index 7b4846c..e4916f7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcBatchUpdateTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcBatchUpdateTask.java @@ -28,11 +28,13 @@ import org.apache.ignite.IgniteLogger; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; +import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.lang.IgniteCallable; import org.apache.ignite.resources.IgniteInstanceResource; import static java.sql.Statement.SUCCESS_NO_INFO; +import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.createJdbcSqlException; /** * Task for SQL batched update statements execution through {@link IgniteJdbcDriver}. @@ -117,10 +119,14 @@ class JdbcBatchUpdateTask implements IgniteCallable<int[]> { cache = ((IgniteKernal)ignite).context().cache().getOrStartPublicCache(start, !loc && locQry); if (cache == null) { - if (cacheName == null) - throw new SQLException("Failed to execute query. No suitable caches found."); - else - throw new SQLException("Cache not found [cacheName=" + cacheName + ']'); + if (cacheName == null) { + throw createJdbcSqlException("Failed to execute query. No suitable caches found.", + IgniteQueryErrorCode.CACHE_NOT_FOUND); + } + else { + throw createJdbcSqlException("Cache not found [cacheName=" + cacheName + ']', + IgniteQueryErrorCode.CACHE_NOT_FOUND); + } } int batchSize = F.isEmpty(sql) ? sqlBatch.size() : batchArgs.size(); @@ -167,8 +173,10 @@ class JdbcBatchUpdateTask implements IgniteCallable<int[]> { QueryCursorImpl<List<?>> qryCursor = (QueryCursorImpl<List<?>>)cache.withKeepBinary().query(qry); - if (qryCursor.isQuery()) - throw new SQLException(getError("Query produced result set", qry)); + if (qryCursor.isQuery()) { + throw createJdbcSqlException(getError("Query produced result set", qry), + IgniteQueryErrorCode.STMT_TYPE_MISMATCH); + } List<List<?>> rows = qryCursor.getAll(); http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java index 1c37fe2..fde16ff 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java @@ -58,8 +58,8 @@ import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.IgnitionEx; import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor; import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; +import org.apache.ignite.internal.processors.odbc.SqlStateCode; import org.apache.ignite.internal.processors.query.GridQueryIndexing; -import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.QueryUtils; import org.apache.ignite.internal.processors.resource.GridSpringResourceContext; import org.apache.ignite.internal.util.future.GridFutureAdapter; @@ -87,6 +87,8 @@ import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING_ALLOW_OVERWRITE; import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING_FLUSH_FREQ; import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING_PER_NODE_BUF_SIZE; import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING_PER_NODE_PAR_OPS; +import static org.apache.ignite.internal.jdbc2.JdbcUtils.convertToSqlException; +import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.createJdbcSqlException; /** * JDBC connection implementation. @@ -189,8 +191,10 @@ public class JdbcConnection implements Connection { stream = Boolean.parseBoolean(props.getProperty(PROP_STREAMING)); - if (stream && cacheName == null) - throw new SQLException("Cache name cannot be null when streaming is enabled."); + if (stream && cacheName == null) { + throw new SQLException("Cache name cannot be null when streaming is enabled.", + SqlStateCode.CLIENT_CONNECTION_FAILED); + } streamAllowOverwrite = Boolean.parseBoolean(props.getProperty(PROP_STREAMING_ALLOW_OVERWRITE)); streamFlushTimeout = Long.parseLong(props.getProperty(PROP_STREAMING_FLUSH_FREQ, "0")); @@ -212,14 +216,18 @@ public class JdbcConnection implements Connection { ignite = getIgnite(cfg); - if (!isValid(2)) - throw new SQLException("Client is invalid. Probably cache name is wrong."); + if (!isValid(2)) { + throw new SQLException("Client is invalid. Probably cache name is wrong.", + SqlStateCode.CLIENT_CONNECTION_FAILED); + } if (cacheName != null) { DynamicCacheDescriptor cacheDesc = ignite().context().cache().cacheDescriptor(cacheName); - if (cacheDesc == null) - throw new SQLException("Cache doesn't exist: " + cacheName); + if (cacheDesc == null) { + throw createJdbcSqlException("Cache doesn't exist: " + cacheName, + IgniteQueryErrorCode.CACHE_NOT_FOUND); + } schemaName = QueryUtils.normalizeSchemaName(cacheName, cacheDesc.cacheConfiguration().getSqlSchema()); } @@ -229,15 +237,14 @@ public class JdbcConnection implements Connection { catch (Exception e) { close(); - if (e instanceof SQLException) - throw (SQLException)e; - else - throw new SQLException("Failed to start Ignite node.", e); + throw convertToSqlException(e, "Failed to start Ignite node.", SqlStateCode.CLIENT_CONNECTION_FAILED); } } /** * @param cfgUrl Config url. + * @return Ignite client node. + * @throws IgniteCheckedException On error. */ private Ignite getIgnite(String cfgUrl) throws IgniteCheckedException { while (true) { @@ -594,9 +601,11 @@ public class JdbcConnection implements Connection { PreparedStatement nativeStmt = prepareNativeStatement(sql); - if (!idx.isInsertStatement(nativeStmt)) - throw new IgniteSQLException("Only INSERT operations are supported in streaming mode", + if (!idx.isInsertStatement(nativeStmt)) { + throw new SQLException("Only INSERT operations are supported in streaming mode", + SqlStateCode.INTERNAL_ERROR, IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + } IgniteDataStreamer streamer = ignite().dataStreamer(cacheName); @@ -704,7 +713,7 @@ public class JdbcConnection implements Connection { return task.call(); } catch (IgniteClientDisconnectedException | ComputeTaskTimeoutException e) { - throw new SQLException("Failed to establish connection.", e); + throw new SQLException("Failed to establish connection.", SqlStateCode.CONNECTION_FAILURE, e); } catch (IgniteException ignored) { return false; @@ -873,7 +882,7 @@ public class JdbcConnection implements Connection { */ private void ensureNotClosed() throws SQLException { if (closed) - throw new SQLException("Connection is closed."); + throw new SQLException("Connection is closed.", SqlStateCode.CONNECTION_CLOSED); } /** @@ -887,6 +896,7 @@ public class JdbcConnection implements Connection { /** * @param sql Query. * @return {@link PreparedStatement} from underlying engine to supply metadata to Prepared - most likely H2. + * @throws SQLException On error. */ PreparedStatement prepareNativeStatement(String sql) throws SQLException { return ignite().context().query().prepareNativeStatement(schemaName(), sql); http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java index f4bb799..4c21cbd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java @@ -36,6 +36,7 @@ import org.apache.ignite.internal.IgniteVersionUtils; import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; import org.apache.ignite.internal.processors.cache.query.GridCacheSqlIndexMetadata; import org.apache.ignite.internal.processors.cache.query.GridCacheSqlMetadata; +import org.apache.ignite.internal.processors.odbc.SqlStateCode; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteCallable; @@ -45,6 +46,7 @@ import static java.sql.Connection.TRANSACTION_NONE; import static java.sql.ResultSet.CONCUR_READ_ONLY; import static java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT; import static java.sql.RowIdLifetime.ROWID_UNSUPPORTED; +import static org.apache.ignite.internal.jdbc2.JdbcUtils.convertToSqlException; /** * JDBC database metadata implementation. @@ -1334,7 +1336,7 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { @SuppressWarnings("unchecked") private void updateMetaData() throws SQLException { if (conn.isClosed()) - throw new SQLException("Connection is closed."); + throw new SQLException("Connection is closed.", SqlStateCode.CONNECTION_CLOSED); try { Ignite ignite = conn.ignite(); @@ -1378,7 +1380,7 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { } } catch (Exception e) { - throw new SQLException("Failed to get meta data from Ignite.", e); + throw convertToSqlException(e, "Failed to get meta data from Ignite."); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java index baddb88..04b4041 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java @@ -45,9 +45,11 @@ import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.ignite.Ignite; -import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.internal.processors.odbc.SqlStateCode; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.jdbc2.JdbcUtils.convertToSqlException; + /** * JDBC result set implementation. */ @@ -161,11 +163,8 @@ public class JdbcResultSet implements ResultSet { return next(); } - catch (IgniteSQLException e) { - throw e.toJdbcException(); - } catch (Exception e) { - throw new SQLException("Failed to query Ignite.", e); + throw convertToSqlException(e, "Failed to query Ignite."); } } @@ -1495,13 +1494,13 @@ public class JdbcResultSet implements ResultSet { else if (cls == String.class) return (T)String.valueOf(val); else - return (T)val; + return cls.cast(val); } catch (IndexOutOfBoundsException ignored) { throw new SQLException("Invalid column index: " + colIdx); } catch (ClassCastException ignored) { - throw new SQLException("Value is an not instance of " + cls.getName()); + throw new SQLException("Value is an not instance of " + cls.getName(), SqlStateCode.CONVERSION_FAILED); } } @@ -1512,7 +1511,7 @@ public class JdbcResultSet implements ResultSet { */ private void ensureNotClosed() throws SQLException { if (closed) - throw new SQLException("Result set is closed."); + throw new SQLException("Result set is closed.", SqlStateCode.INVALID_CURSOR_STATE); } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java index 4e05db4..a94b8fd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java @@ -32,13 +32,14 @@ import java.util.Map; import java.util.Set; import java.util.UUID; import org.apache.ignite.Ignite; -import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.internal.processors.odbc.SqlStateCode; import org.apache.ignite.internal.util.typedef.F; import static java.sql.ResultSet.CONCUR_READ_ONLY; import static java.sql.ResultSet.FETCH_FORWARD; import static java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT; import static java.sql.ResultSet.TYPE_FORWARD_ONLY; +import static org.apache.ignite.internal.jdbc2.JdbcUtils.convertToSqlException; /** * JDBC statement implementation. @@ -125,11 +126,8 @@ public class JdbcStatement implements Statement { return rs; } - catch (IgniteSQLException e) { - throw e.toJdbcException(); - } catch (Exception e) { - throw new SQLException("Failed to query Ignite.", e); + throw convertToSqlException(e, "Failed to query Ignite."); } } @@ -176,14 +174,8 @@ public class JdbcStatement implements Statement { return updateCnt = updateCounterFromQueryResult(qryRes.getRows()); } - catch (IgniteSQLException e) { - throw e.toJdbcException(); - } - catch (SQLException e) { - throw e; - } catch (Exception e) { - throw new SQLException("Failed to query Ignite.", e); + throw convertToSqlException(e, "Failed to query Ignite."); } } @@ -358,11 +350,8 @@ public class JdbcStatement implements Statement { return res.isQuery(); } - catch (IgniteSQLException e) { - throw e.toJdbcException(); - } catch (Exception e) { - throw new SQLException("Failed to query Ignite.", e); + throw convertToSqlException(e, "Failed to query Ignite."); } } @@ -510,14 +499,8 @@ public class JdbcStatement implements Statement { return res; } - catch (IgniteSQLException e) { - throw e.toJdbcException(); - } - catch (SQLException e) { - throw e; - } catch (Exception e) { - throw new SQLException("Failed to query Ignite.", e); + throw convertToSqlException(e, "Failed to query Ignite."); } } @@ -672,6 +655,6 @@ public class JdbcStatement implements Statement { */ void ensureNotClosed() throws SQLException { if (closed) - throw new SQLException("Statement is closed."); + throw new SQLException("Connection is closed.", SqlStateCode.CONNECTION_CLOSED); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/f9955fd7/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java index 37304fc..cda6ba0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcUtils.java @@ -18,11 +18,14 @@ package org.apache.ignite.internal.jdbc2; import java.net.URL; +import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; import java.sql.Types; import java.util.Date; +import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; +import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.QueryUtils; import static java.sql.Types.BIGINT; @@ -141,4 +144,43 @@ public class JdbcUtils { static boolean isSqlType(Class<?> cls) { return QueryUtils.isSqlType(cls) || cls == URL.class; } + + + /** + * Convert exception to {@link SQLException}. + * + * @param e Converted Exception. + * @param msgForUnknown Message non-convertable exception. + * @return JDBC {@link SQLException}. + * @see IgniteQueryErrorCode + */ + public static SQLException convertToSqlException(Exception e, String msgForUnknown) { + return convertToSqlException(e, msgForUnknown, null); + } + + /** + * Convert exception to {@link SQLException}. + * + * @param e Converted Exception. + * @param msgForUnknown Message for non-convertable exception. + * @param sqlStateForUnknown SQLSTATE for non-convertable exception. + * @return JDBC {@link SQLException}. + * @see IgniteQueryErrorCode + */ + public static SQLException convertToSqlException(Exception e, String msgForUnknown, String sqlStateForUnknown) { + SQLException sqlEx = null; + + Throwable t = e; + + while (sqlEx == null && t != null) { + if (t instanceof SQLException) + return (SQLException)t; + else if (t instanceof IgniteSQLException) + return ((IgniteSQLException)t).toJdbcException(); + + t = t.getCause(); + } + + return new SQLException(msgForUnknown, sqlStateForUnknown, e); + } }