Repository: ignite Updated Branches: refs/heads/master 9fd82212e -> 7c4d0bc2a
http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java index 27b9407..70cf00e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java @@ -22,7 +22,7 @@ import java.io.BufferedOutputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; -import java.util.List; +import java.sql.SQLException; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.binary.BinaryReaderExImpl; import org.apache.ignite.internal.binary.BinaryWriterExImpl; @@ -31,33 +31,13 @@ import org.apache.ignite.internal.binary.streams.BinaryHeapOutputStream; import org.apache.ignite.internal.processors.odbc.ClientListenerNioListener; import org.apache.ignite.internal.processors.odbc.ClientListenerProtocolVersion; import org.apache.ignite.internal.processors.odbc.ClientListenerRequest; -import org.apache.ignite.internal.processors.odbc.ClientListenerResponse; +import org.apache.ignite.internal.processors.odbc.SqlStateCode; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcBatchExecuteRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcBatchExecuteResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaColumnsRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaColumnsResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaIndexesRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaIndexesResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaParamsRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaParamsResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaPrimaryKeysRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaPrimaryKeysResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaSchemasRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaSchemasResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaTablesRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaTablesResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQuery; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryCloseRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryFetchRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryFetchResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryMetadataRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryMetadataResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResponse; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementType; import org.apache.ignite.internal.util.ipc.loopback.IpcClientTcpEndpoint; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteProductVersion; @@ -173,10 +153,10 @@ public class JdbcThinTcpIo { } /** - * @throws IgniteCheckedException On error. + * @throws SQLException On connection error or reject. * @throws IOException On IO error in handshake. */ - public void start() throws IgniteCheckedException, IOException { + public void start() throws SQLException, IOException { Socket sock = new Socket(); if (sockSndBuf != 0) @@ -189,24 +169,25 @@ public class JdbcThinTcpIo { try { sock.connect(new InetSocketAddress(host, port)); - } - catch (IOException e) { - throw new IgniteCheckedException("Failed to connect to server [host=" + host + ", port=" + port + ']', e); - } - endpoint = new IpcClientTcpEndpoint(sock); + endpoint = new IpcClientTcpEndpoint(sock); - out = new BufferedOutputStream(endpoint.outputStream()); - in = new BufferedInputStream(endpoint.inputStream()); + out = new BufferedOutputStream(endpoint.outputStream()); + in = new BufferedInputStream(endpoint.inputStream()); + } + catch (IOException | IgniteCheckedException e) { + throw new SQLException("Failed to connect to server [host=" + host + ", port=" + port + ']', + SqlStateCode.CLIENT_CONNECTION_FAILED, e); + } handshake(); } /** - * @throws IOException On error. - * @throws IgniteCheckedException On error. + * @throws IOException On IO error. + * @throws SQLException On connection reject. */ - public void handshake() throws IOException, IgniteCheckedException { + public void handshake() throws IOException, SQLException { BinaryWriterExImpl writer = new BinaryWriterExImpl(null, new BinaryHeapOutputStream(HANDSHAKE_MSG_SIZE), null, null); @@ -262,8 +243,9 @@ public class JdbcThinTcpIo { if (VER_2_1_0.equals(srvProtocolVer)) handshake_2_1_0(); else { - throw new IgniteCheckedException("Handshake failed [driverProtocolVer=" + CURRENT_VER + - ", remoteNodeProtocolVer=" + srvProtocolVer + ", err=" + err + ']'); + throw new SQLException("Handshake failed [driverProtocolVer=" + CURRENT_VER + + ", remoteNodeProtocolVer=" + srvProtocolVer + ", err=" + err + ']', + SqlStateCode.CONNECTION_REJECTED); } } } @@ -271,10 +253,10 @@ public class JdbcThinTcpIo { /** * Compatibility handshake for server version 2.1.0 * - * @throws IOException On error. - * @throws IgniteCheckedException On error. + * @throws IOException On IO error. + * @throws SQLException On connection reject. */ - public void handshake_2_1_0() throws IOException, IgniteCheckedException { + private void handshake_2_1_0() throws IOException, SQLException { BinaryWriterExImpl writer = new BinaryWriterExImpl(null, new BinaryHeapOutputStream(HANDSHAKE_MSG_SIZE), null, null); @@ -310,38 +292,20 @@ public class JdbcThinTcpIo { ClientListenerProtocolVersion ver = ClientListenerProtocolVersion.create(maj, min, maintenance); - throw new IgniteCheckedException("Handshake failed [driverProtocolVer=" + CURRENT_VER + - ", remoteNodeProtocolVer=" + ver + ", err=" + err + ']'); + throw new SQLException("Handshake failed [driverProtocolVer=" + CURRENT_VER + + ", remoteNodeProtocolVer=" + ver + ", err=" + err + ']', SqlStateCode.CONNECTION_REJECTED); } } /** - * @param stmtType Expected statement type. - * @param cache Cache name. - * @param fetchSize Fetch size. - * @param maxRows Max rows. - * @param sql SQL statement. - * @param args Query parameters. - * @return Execute query results. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public JdbcQueryExecuteResult queryExecute(JdbcStatementType stmtType, String cache, int fetchSize, int maxRows, - String sql, List<Object> args) - throws IOException, IgniteCheckedException { - return sendRequest(new JdbcQueryExecuteRequest(stmtType, cache, fetchSize, maxRows, sql, - args == null ? null : args.toArray(new Object[args.size()])), DYNAMIC_SIZE_MSG_CAP); - } - - /** * @param req Request. - * @param cap Initial ouput stream capacity. * @return Server response. - * @throws IOException On IO error. - * @throws IgniteCheckedException On error. + * @throws IOException In case of IO error. */ @SuppressWarnings("unchecked") - public <R extends JdbcResult> R sendRequest(JdbcRequest req, int cap) throws IOException, IgniteCheckedException { + JdbcResponse sendRequest(JdbcRequest req) throws IOException { + int cap = guessCapacity(req); + BinaryWriterExImpl writer = new BinaryWriterExImpl(null, new BinaryHeapOutputStream(cap), null, null); req.writeBinary(writer); @@ -354,125 +318,33 @@ public class JdbcThinTcpIo { res.readBinary(reader); - if (res.status() != ClientListenerResponse.STATUS_SUCCESS) - throw new IgniteCheckedException("Error server response: [req=" + req + ", resp=" + res + ']'); - - return (R)res.response(); + return res; } /** - * @param qryId Query ID. - * @param pageSize pageSize. - * @return Fetch results. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public JdbcQueryFetchResult queryFetch(Long qryId, int pageSize) - throws IOException, IgniteCheckedException { - return sendRequest(new JdbcQueryFetchRequest(qryId, pageSize), QUERY_FETCH_MSG_SIZE); - } - - - /** - * @param qryId Query ID. - * @return Fetch results. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public JdbcQueryMetadataResult queryMeta(Long qryId) - throws IOException, IgniteCheckedException { - return sendRequest(new JdbcQueryMetadataRequest(qryId), QUERY_META_MSG_SIZE); - } - - /** - * @param qryId Query ID. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public void queryClose(long qryId) throws IOException, IgniteCheckedException { - sendRequest(new JdbcQueryCloseRequest(qryId), QUERY_CLOSE_MSG_SIZE); - } - - /** - * @param schemaName Schema. - * @param batch Batch queries. - * @return Result. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public JdbcBatchExecuteResult batchExecute(String schemaName, List<JdbcQuery> batch) - throws IOException, IgniteCheckedException { - int cnt = Math.min(MAX_BATCH_QRY_CNT, batch.size()); - - return sendRequest(new JdbcBatchExecuteRequest(schemaName, batch), DYNAMIC_SIZE_MSG_CAP * cnt); - } - - /** - * @param schemaPtrn Schema name pattern. - * @param tablePtrn Table name pattern. - * @return Result. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public JdbcMetaTablesResult tablesMeta(String schemaPtrn, String tablePtrn) - throws IOException, IgniteCheckedException { - return sendRequest(new JdbcMetaTablesRequest(schemaPtrn, tablePtrn), DYNAMIC_SIZE_MSG_CAP); - } - - /** - * @param schemaPtrn Schema name pattern. - * @param tablePtrn Table name pattern. - * @param columnPtrn Column name pattern. - * @return Result. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public JdbcMetaColumnsResult columnsMeta(String schemaPtrn, String tablePtrn, String columnPtrn) - throws IOException, IgniteCheckedException { - return sendRequest(new JdbcMetaColumnsRequest(schemaPtrn, tablePtrn, columnPtrn), DYNAMIC_SIZE_MSG_CAP); - } - - /** - * @param schemaPtrn Schema name pattern. - * @param tablePtrn Table name pattern. - * @return Result. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public JdbcMetaIndexesResult indexMeta(String schemaPtrn, String tablePtrn) throws IOException, IgniteCheckedException { - return sendRequest(new JdbcMetaIndexesRequest(schemaPtrn, tablePtrn), DYNAMIC_SIZE_MSG_CAP); - } - - /** - * @param schemaPtrn Schema name pattern. - * @param sql SQL query. - * @return Result. - * @throws IOException On error. - * @throws IgniteCheckedException On error. + * Try to guess request capacity. + * + * @param req Request. + * @return Expected capacity. */ - public JdbcMetaParamsResult parametersMeta(String schemaPtrn, String sql) throws IOException, IgniteCheckedException { - return sendRequest(new JdbcMetaParamsRequest(schemaPtrn, sql), DYNAMIC_SIZE_MSG_CAP); - } + private static int guessCapacity(JdbcRequest req) { + int cap; - /** - * @param schemaPtrn Schema name pattern. - * @param tablePtrn Table name pattern. - * @return Result. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public JdbcMetaPrimaryKeysResult primaryKeysMeta(String schemaPtrn, String tablePtrn) throws IOException, IgniteCheckedException { - return sendRequest(new JdbcMetaPrimaryKeysRequest(schemaPtrn, tablePtrn), DYNAMIC_SIZE_MSG_CAP); - } + if (req instanceof JdbcBatchExecuteRequest) { + int cnt = Math.min(MAX_BATCH_QRY_CNT, ((JdbcBatchExecuteRequest)req).queries().size()); - /** - * @param schemaPtrn Schema name pattern. - * @return Result. - * @throws IOException On error. - * @throws IgniteCheckedException On error. - */ - public JdbcMetaSchemasResult schemasMeta(String schemaPtrn) throws IOException, IgniteCheckedException { - return sendRequest(new JdbcMetaSchemasRequest(schemaPtrn), DYNAMIC_SIZE_MSG_CAP); + cap = cnt * DYNAMIC_SIZE_MSG_CAP; + } + else if (req instanceof JdbcQueryCloseRequest) + cap = QUERY_CLOSE_MSG_SIZE; + else if (req instanceof JdbcQueryMetadataRequest) + cap = QUERY_META_MSG_SIZE; + else if (req instanceof JdbcQueryFetchRequest) + cap = QUERY_FETCH_MSG_SIZE; + else + cap = DYNAMIC_SIZE_MSG_CAP; + + return cap; } /** @@ -495,9 +367,8 @@ public class JdbcThinTcpIo { /** * @return Bytes of a response from server. * @throws IOException On error. - * @throws IgniteCheckedException On error. */ - private byte[] read() throws IOException, IgniteCheckedException { + private byte[] read() throws IOException { byte[] sizeBytes = read(4); int msgSize = (((0xFF & sizeBytes[3]) << 24) | ((0xFF & sizeBytes[2]) << 16) @@ -510,9 +381,8 @@ public class JdbcThinTcpIo { * @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 { + private byte [] read(int size) throws IOException { int off = 0; byte[] data = new byte[size]; @@ -521,7 +391,7 @@ public class JdbcThinTcpIo { int res = in.read(data, off, size - off); if (res == -1) - throw new IgniteCheckedException("Failed to read incoming message (not enough data)."); + throw new IOException("Failed to read incoming message (not enough data)."); off += res; } @@ -603,7 +473,7 @@ public class JdbcThinTcpIo { } /** - * @return Ignnite server version. + * @return Ignite server version. */ IgniteProductVersion igniteVersion() { return igniteVer; http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java index d05c9fd..8e5af31 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java @@ -20,6 +20,7 @@ package org.apache.ignite.internal.processors.cache.query; import java.sql.SQLException; import javax.cache.processor.EntryProcessor; import org.apache.ignite.IgniteCache; +import org.apache.ignite.internal.processors.odbc.SqlStateCode; /** * Error codes for query operations. @@ -76,6 +77,9 @@ public final class IgniteQueryErrorCode { /** Required column already exists. */ public final static int COLUMN_ALREADY_EXISTS = 3009; + /** Conversion failure. */ + public final static int CONVERSION_FAILED = 3013; + /* 4xxx - cache related runtime errors */ /** Attempt to INSERT a key that is already in cache. */ @@ -102,13 +106,53 @@ public final class IgniteQueryErrorCode { } /** - * Create a {@link SQLException} for given code and message with null state. + * Create a {@link SQLException} for given code and message with detected state. * * @param msg Message. * @param code Ignite status code. * @return {@link SQLException} with given details. */ public static SQLException createJdbcSqlException(String msg, int code) { - return new SQLException(msg, null, code); + return new SQLException(msg, codeToSqlState(code)); + } + + /** + * Map Ignite specific error code to standard SQL state. + * @param statusCode Ignite specific error code. + * @return SQL state string. + * @see <a href="http://en.wikibooks.org/wiki/Structured_Query_Language/SQLSTATE">Wikipedia: SQLSTATE spec.</a> + * @see IgniteQueryErrorCode + */ + public static String codeToSqlState(int statusCode) { + switch (statusCode) { + case DUPLICATE_KEY: + return SqlStateCode.CONSTRAINT_VIOLATION; + + case NULL_KEY: + case NULL_VALUE: + return SqlStateCode.NULL_VALUE; + + case UNSUPPORTED_OPERATION: + return SqlStateCode.UNSUPPORTED_OPERATION; + + case CONVERSION_FAILED: + return SqlStateCode.CONVERSION_FAILED; + + case PARSING: + case TABLE_NOT_FOUND: + case TABLE_ALREADY_EXISTS: + case INDEX_ALREADY_EXISTS: + case INDEX_NOT_FOUND: + case COLUMN_NOT_FOUND: + case COLUMN_ALREADY_EXISTS: + case STMT_TYPE_MISMATCH: + case UNEXPECTED_OPERATION: + case UNEXPECTED_ELEMENT_TYPE: + case KEY_UPDATE: + return SqlStateCode.PARSING_EXCEPTION; + + default: + return SqlStateCode.INTERNAL_ERROR; + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java new file mode 100644 index 0000000..eff680f --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java @@ -0,0 +1,69 @@ +/* + * 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.processors.odbc; + +/** + * SQL state codes. + */ +public final class SqlStateCode { + /** + * No-op constructor to prevent instantiation. + */ + private SqlStateCode() { + // No-op. + } + + /** Client has failed to open connection with specified server. */ + public final static String CLIENT_CONNECTION_FAILED = "08001"; + + /** Connection unexpectedly turned out to be in closed state. */ + public final static String CONNECTION_CLOSED = "08003"; + + /** Connection was rejected by server. */ + public final static String CONNECTION_REJECTED = "08004"; + + /** IO error during communication. */ + public final static String CONNECTION_FAILURE = "08006"; + + /** Null value occurred where it wasn't expected to. */ + public final static String NULL_VALUE = "22004"; + + /** Parameter type is not supported. */ + public final static String INVALID_PARAMETER_VALUE = "22023"; + + /** Data integrity constraint violation. */ + public final static String CONSTRAINT_VIOLATION = "23000"; + + /** Invalid result set state. */ + public final static String INVALID_CURSOR_STATE = "24000"; + + /** Conversion failure. */ + public final static String CONVERSION_FAILED = "0700B"; + + /** Invalid transaction level. */ + public final static String INVALID_TRANSACTION_LEVEL = "0700E"; + + /** Requested operation is not supported. */ + public final static String UNSUPPORTED_OPERATION = "0A000"; + + /** Parsing exception. */ + public final static String PARSING_EXCEPTION = "42000"; + + /** Internal error. */ + public final static String INTERNAL_ERROR = "50000"; // Generic value for custom "50" class. +} http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java index 4250ba5..fe50bb5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -36,12 +36,14 @@ import org.apache.ignite.internal.IgniteVersionUtils; import org.apache.ignite.internal.binary.BinaryWriterExImpl; import org.apache.ignite.internal.jdbc2.JdbcSqlFieldsQuery; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; +import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; import org.apache.ignite.internal.processors.odbc.ClientListenerRequest; import org.apache.ignite.internal.processors.odbc.ClientListenerRequestHandler; import org.apache.ignite.internal.processors.odbc.ClientListenerResponse; import org.apache.ignite.internal.processors.odbc.odbc.OdbcQueryGetColumnsMetaRequest; import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor; import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; +import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.processors.query.QueryUtils; import org.apache.ignite.internal.util.GridSpinBusyLock; import org.apache.ignite.internal.util.typedef.F; @@ -138,7 +140,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { JdbcRequest req = (JdbcRequest)req0; if (!busyLock.enterBusy()) - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, + return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Failed to handle JDBC request because node is stopping."); try { @@ -177,7 +179,8 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { return getSchemas((JdbcMetaSchemasRequest)req); } - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, "Unsupported JDBC request [req=" + req + ']'); + return new JdbcResponse(IgniteQueryErrorCode.UNSUPPORTED_OPERATION, + "Unsupported JDBC request [req=" + req + ']'); } finally { busyLock.leaveBusy(); @@ -186,7 +189,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { /** {@inheritDoc} */ @Override public ClientListenerResponse handleException(Exception e) { - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } /** {@inheritDoc} */ @@ -232,7 +235,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { int cursorCnt = qryCursors.size(); if (maxCursors > 0 && cursorCnt >= maxCursors) - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, "Too many opened cursors (either close other " + + return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Too many opened cursors (either close other " + "opened cursors or increase the limit through OdbcConfiguration.setMaxOpenCursors()) " + "[maximum=" + maxCursors + ", current=" + cursorCnt + ']'); @@ -269,8 +272,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { qry.setLazy(lazy); if (req.pageSize() <= 0) - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, - "Invalid fetch size : [fetchSize=" + req.pageSize() + ']'); + return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Invalid fetch size: " + req.pageSize()); qry.setPageSize(req.pageSize()); @@ -312,7 +314,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { U.error(log, "Failed to execute SQL query [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -327,7 +329,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { JdbcQueryCursor cur = qryCursors.remove(req.queryId()); if (cur == null) - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, + return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Failed to find query cursor with ID: " + req.queryId()); cur.close(); @@ -339,7 +341,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { U.error(log, "Failed to close SQL query [reqId=" + req.requestId() + ", req=" + req.queryId() + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -354,11 +356,11 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { JdbcQueryCursor cur = qryCursors.get(req.queryId()); if (cur == null) - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, + return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Failed to find query cursor with ID: " + req.queryId()); if (req.pageSize() <= 0) - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, + return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Invalid fetch size : [fetchSize=" + req.pageSize() + ']'); cur.pageSize(req.pageSize()); @@ -376,7 +378,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { catch (Exception e) { U.error(log, "Failed to fetch SQL query result [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -389,7 +391,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { JdbcQueryCursor cur = qryCursors.get(req.queryId()); if (cur == null) - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, + return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Failed to find query with ID: " + req.queryId()); JdbcQueryMetadataResult res = new JdbcQueryMetadataResult(req.queryId(), @@ -400,7 +402,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { catch (Exception e) { U.error(log, "Failed to fetch SQL query result [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -451,8 +453,22 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { catch (Exception e) { U.error(log, "Failed to execute batch query [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(new JdbcBatchExecuteResult(Arrays.copyOf(updCnts, successQueries), - ClientListenerResponse.STATUS_FAILED, e.toString())); + int code; + + String msg; + + if (e instanceof IgniteSQLException) { + code = ((IgniteSQLException) e).statusCode(); + + msg = e.getMessage(); + } + else { + code = IgniteQueryErrorCode.UNKNOWN; + + msg = e.getMessage(); + } + + return new JdbcResponse(new JdbcBatchExecuteResult(Arrays.copyOf(updCnts, successQueries), code, msg)); } } @@ -486,7 +502,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { catch (Exception e) { U.error(log, "Failed to get tables metadata [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -528,7 +544,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { catch (Exception e) { U.error(log, "Failed to get columns metadata [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -558,7 +574,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { catch (Exception e) { U.error(log, "Failed to get parameters metadata [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -585,7 +601,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { catch (Exception e) { U.error(log, "Failed to get parameters metadata [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -631,7 +647,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { catch (Exception e) { U.error(log, "Failed to get parameters metadata [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -657,7 +673,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { catch (Exception e) { U.error(log, "Failed to get schemas metadata [reqId=" + req.requestId() + ", req=" + req + ']', e); - return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString()); + return exceptionToResult(e); } } @@ -672,4 +688,18 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler { return str != null && (F.isEmpty(ptrn) || str.matches(ptrn.replace("%", ".*").replace("_", "."))); } + + /** + * Create {@link JdbcResponse} bearing appropriate Ignite specific result code if possible + * from given {@link Exception}. + * + * @param e Exception to convert. + * @return resulting {@link JdbcResponse}. + */ + private JdbcResponse exceptionToResult(Exception e) { + if (e instanceof IgniteSQLException) + return new JdbcResponse(((IgniteSQLException) e).statusCode(), e.getMessage()); + else + return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, e.toString()); + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java index 0666493..2bacc23 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java @@ -22,6 +22,9 @@ import org.apache.ignite.IgniteException; import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.UNKNOWN; +import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.codeToSqlState; + /** * Specific exception bearing information about query processing errors for more detailed * errors in JDBC driver. @@ -38,45 +41,82 @@ public class IgniteSQLException extends IgniteException { /** Code to return as {@link SQLException#vendorCode} */ private final int statusCode; - /** */ + /** + * Constructor. + * + * @param msg Exception message. + */ public IgniteSQLException(String msg) { - this(msg, null, 0); + this(msg, UNKNOWN, (String)null); } /** - * Minimalistic ctor accepting only {@link SQLException} as the cause. + * Constructor. + * + * @param cause Cause to throw this exception. */ public IgniteSQLException(SQLException cause) { super(cause); - this.sqlState = null; - this.statusCode = 0; + + this.sqlState = cause.getSQLState(); + this.statusCode = UNKNOWN; } - /** */ + /** + * Constructor. + * + * @param msg Exception message. + * @param cause Cause to throw this exception. + */ public IgniteSQLException(String msg, @Nullable Throwable cause) { - super(msg, cause); - this.sqlState = null; - this.statusCode = 0; + this(msg, UNKNOWN, cause); } - /** */ + /** + * Constructor. + * + * @param msg Exception message. + * @param statusCode Ignite specific error code. + * @param cause Cause to throw this exception. + * @see IgniteQueryErrorCode + */ public IgniteSQLException(String msg, int statusCode, @Nullable Throwable cause) { - super(msg, cause); - this.sqlState = null; - this.statusCode = statusCode; + this(msg, statusCode, codeToSqlState(statusCode), cause); } - /** */ - public IgniteSQLException(String msg, String sqlState, int statusCode) { - super(msg); - this.sqlState = sqlState; - this.statusCode = statusCode; + /** + * Constructor. + * @param msg Exception message. + * @param statusCode Ignite specific error code. + * @see IgniteQueryErrorCode + */ + public IgniteSQLException(String msg, int statusCode) { + this(msg, statusCode, codeToSqlState(statusCode)); } - /** */ - public IgniteSQLException(String msg, int statusCode) { - super(msg); - this.sqlState = null; + /** + * Constructor. + * @param msg Exception message. + * @param statusCode Ignite specific error code. + * @param sqlState SQLSTATE standard code. + * @see IgniteQueryErrorCode + */ + public IgniteSQLException(String msg, int statusCode, String sqlState) { + this(msg, statusCode, sqlState, null); + } + + /** + * Constructor. + * @param msg Exception message. + * @param statusCode Ignite specific error code. + * @param sqlState SQLSTATE standard code. + * @param cause Cause to throw this exception. + * @see IgniteQueryErrorCode + */ + private IgniteSQLException(String msg, int statusCode, String sqlState, @Nullable Throwable cause) { + super(msg, cause); + + this.sqlState = sqlState; this.statusCode = statusCode; } http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java index 0634a52..cbaa478 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java @@ -49,6 +49,7 @@ import org.apache.ignite.binary.BinaryObjectBuilder; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.processors.odbc.SqlStateCode; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheOperationContext; import org.apache.ignite.internal.processors.cache.GridCacheAdapter; @@ -663,48 +664,56 @@ public class DmlStatementsProcessor { Class<?> currCls = val.getClass(); - if (val instanceof Date && currCls != Date.class && expCls == Date.class) { - // H2 thinks that java.util.Date is always a Timestamp, while binary marshaller expects - // precise Date instance. Let's satisfy it. - return new Date(((Date) val).getTime()); - } + try { + if (val instanceof Date && currCls != Date.class && expCls == Date.class) { + // H2 thinks that java.util.Date is always a Timestamp, while binary marshaller expects + // precise Date instance. Let's satisfy it. + return new Date(((Date) val).getTime()); + } - // User-given UUID is always serialized by H2 to byte array, so we have to deserialize manually - if (type == Value.UUID && currCls == byte[].class) - return U.unmarshal(desc.context().marshaller(), (byte[]) val, - U.resolveClassLoader(desc.context().gridConfig())); + // User-given UUID is always serialized by H2 to byte array, so we have to deserialize manually + if (type == Value.UUID && currCls == byte[].class) + return U.unmarshal(desc.context().marshaller(), (byte[]) val, + U.resolveClassLoader(desc.context().gridConfig())); - if (LocalDateTimeUtils.isJava8DateApiPresent()) { - if (val instanceof Timestamp && LocalDateTimeUtils.isLocalDateTime(expCls)) - return LocalDateTimeUtils.valueToLocalDateTime(ValueTimestamp.get((Timestamp)val)); + if (LocalDateTimeUtils.isJava8DateApiPresent()) { + if (val instanceof Timestamp && LocalDateTimeUtils.isLocalDateTime(expCls)) + return LocalDateTimeUtils.valueToLocalDateTime(ValueTimestamp.get((Timestamp) val)); - if (val instanceof Date && LocalDateTimeUtils.isLocalDate(expCls)) - return LocalDateTimeUtils.valueToLocalDate(ValueDate.fromDateValue( - DateTimeUtils.dateValueFromDate(((Date)val).getTime()))); + if (val instanceof Date && LocalDateTimeUtils.isLocalDate(expCls)) + return LocalDateTimeUtils.valueToLocalDate(ValueDate.fromDateValue( + DateTimeUtils.dateValueFromDate(((Date) val).getTime()))); - if (val instanceof Time && LocalDateTimeUtils.isLocalTime(expCls)) - return LocalDateTimeUtils.valueToLocalTime(ValueTime.get((Time)val)); - } + if (val instanceof Time && LocalDateTimeUtils.isLocalTime(expCls)) + return LocalDateTimeUtils.valueToLocalTime(ValueTime.get((Time) val)); + } - // We have to convert arrays of reference types manually - see https://issues.apache.org/jira/browse/IGNITE-4327 - // Still, we only can convert from Object[] to something more precise. - if (type == Value.ARRAY && currCls != expCls) { - if (currCls != Object[].class) - throw new IgniteCheckedException("Unexpected array type - only conversion from Object[] is assumed"); + // We have to convert arrays of reference types manually - + // see https://issues.apache.org/jira/browse/IGNITE-4327 + // Still, we only can convert from Object[] to something more precise. + if (type == Value.ARRAY && currCls != expCls) { + if (currCls != Object[].class) + throw new IgniteCheckedException("Unexpected array type - only conversion from Object[] " + + "is assumed"); - // Why would otherwise type be Value.ARRAY? - assert expCls.isArray(); + // Why would otherwise type be Value.ARRAY? + assert expCls.isArray(); - Object[] curr = (Object[]) val; + Object[] curr = (Object[]) val; - Object newArr = Array.newInstance(expCls.getComponentType(), curr.length); + Object newArr = Array.newInstance(expCls.getComponentType(), curr.length); - System.arraycopy(curr, 0, newArr, 0, curr.length); + System.arraycopy(curr, 0, newArr, 0, curr.length); - return newArr; - } + return newArr; + } - return H2Utils.convert(val, desc, type); + return H2Utils.convert(val, desc, type); + } + catch (Exception e) { + throw new IgniteSQLException("Value conversion failed [from=" + currCls.getName() + ", to=" + + expCls.getName() +']', IgniteQueryErrorCode.CONVERSION_FAILED, e); + } } /** @@ -839,7 +848,7 @@ public class DmlStatementsProcessor { String msg = "Failed to INSERT some keys because they are already in cache " + "[keys=" + sender.failedKeys() + ']'; - SQLException dupEx = new SQLException(msg, null, IgniteQueryErrorCode.DUPLICATE_KEY); + SQLException dupEx = new SQLException(msg, SqlStateCode.CONSTRAINT_VIOLATION); if (resEx == null) resEx = dupEx; @@ -972,7 +981,8 @@ public class DmlStatementsProcessor { } /** {@inheritDoc} */ - @Override public Boolean process(MutableEntry<Object, Object> entry, Object... arguments) throws EntryProcessorException { + @Override public Boolean process(MutableEntry<Object, Object> entry, Object... arguments) + throws EntryProcessorException { if (entry.exists()) return false; @@ -1000,7 +1010,8 @@ public class DmlStatementsProcessor { } /** {@inheritDoc} */ - @Override public Boolean process(MutableEntry<Object, Object> entry, Object... arguments) throws EntryProcessorException { + @Override public Boolean process(MutableEntry<Object, Object> entry, Object... arguments) + throws EntryProcessorException { if (!entry.exists()) return null; // Someone got ahead of us and removed this entry, let's skip it. http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java index a2de62b..3046c20 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java @@ -941,7 +941,8 @@ public class GridSqlQueryParser { int valColsNum = cols.size() - pkCols.size(); if (valColsNum == 0) - throw new IgniteSQLException("No cache value related columns found"); + throw new IgniteSQLException("Table must have at least one non PRIMARY KEY column.", + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); res.columns(cols); res.primaryKeyColumns(pkCols); @@ -1014,8 +1015,36 @@ public class GridSqlQueryParser { case CommandInterface.ALTER_TABLE_ADD_COLUMN: return parseAddColumn(stmt); - default: - throw new IgniteSQLException("Unsupported operation code: " + stmt.getType()); + default: { + String stmtName = null; + + switch (stmt.getType()) { + case CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE: + case CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT: + case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL: + case CommandInterface.ALTER_TABLE_ALTER_COLUMN_RENAME: + case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL: + case CommandInterface.ALTER_TABLE_ALTER_COLUMN_SELECTIVITY: + case CommandInterface.ALTER_TABLE_ALTER_COLUMN_VISIBILITY: + stmtName = "ALTER COLUMN"; + + break; + + case CommandInterface.ALTER_TABLE_DROP_COLUMN: + stmtName = "DROP COLUMN"; + + break; + } + + if (stmtName == null) { + throw new IgniteSQLException("Unsupported operation: " + stmt.getSQL(), + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + } + else { + throw new IgniteSQLException(stmtName + " is not supported", + IgniteQueryErrorCode.UNSUPPORTED_OPERATION); + } + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java index 6a78df3..61694dd 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java @@ -596,7 +596,7 @@ public class GridQueryParsingTest extends GridCommonAbstractTest { IgniteSQLException.class, "CREATE TABLE ... AS ... syntax is not supported"); assertParseThrows("create table Person (id int primary key)", - IgniteSQLException.class, "No cache value related columns found"); + IgniteSQLException.class, "Table must have at least one non PRIMARY KEY column."); assertParseThrows("create table Person (id int primary key, age int unique) WITH \"template=cache\"", IgniteSQLException.class, "Too many constraints - only PRIMARY KEY is supported for CREATE TABLE");