Repository: tajo Updated Branches: refs/heads/master 3e8f4a030 -> 688bc5c11
TAJO-1749: Refine JDBC exceptions to better handle exceptional cases. Closes #722 Project: http://git-wip-us.apache.org/repos/asf/tajo/repo Commit: http://git-wip-us.apache.org/repos/asf/tajo/commit/688bc5c1 Tree: http://git-wip-us.apache.org/repos/asf/tajo/tree/688bc5c1 Diff: http://git-wip-us.apache.org/repos/asf/tajo/diff/688bc5c1 Branch: refs/heads/master Commit: 688bc5c1111054cb486cdc915edc8fc0097add4a Parents: 3e8f4a0 Author: Hyunsik Choi <[email protected]> Authored: Thu Sep 3 22:08:08 2015 +0900 Committer: Hyunsik Choi <[email protected]> Committed: Thu Sep 3 22:08:08 2015 +0900 ---------------------------------------------------------------------- CHANGES | 3 + .../apache/tajo/client/SessionConnection.java | 4 +- .../org/apache/tajo/client/TajoClientImpl.java | 6 +- .../v2/exception/ClientConnectionException.java | 5 +- .../org/apache/tajo/jdbc/TajoSQLException.java | 43 +++++ .../org/apache/tajo/jdbc/WaitingResultSet.java | 10 +- .../apache/tajo/exception/ErrorMessages.java | 7 +- .../apache/tajo/exception/SQLExceptionUtil.java | 94 ++++++++++- .../apache/tajo/exception/TajoException.java | 5 + tajo-common/src/main/proto/errors.proto | 49 +++--- .../tajo/master/exec/CreateTableExecutor.java | 1 + .../apache/tajo/master/exec/DDLExecutor.java | 3 +- .../org/apache/tajo/jdbc/JdbcConnection.java | 25 ++- .../apache/tajo/jdbc/TajoPreparedStatement.java | 20 +-- .../org/apache/tajo/jdbc/TajoStatement.java | 39 ++--- .../java/org/apache/tajo/jdbc/TestTajoJdbc.java | 6 - .../apache/tajo/jdbc/TestTajoJdbcNegative.java | 156 +++++++++++++++++++ .../org/apache/tajo/rpc/NettyClientBase.java | 13 +- 18 files changed, 396 insertions(+), 93 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/CHANGES ---------------------------------------------------------------------- diff --git a/CHANGES b/CHANGES index 32cf77f..d3d47be 100644 --- a/CHANGES +++ b/CHANGES @@ -549,6 +549,9 @@ Release 0.11.0 - unreleased SUB TASKS + TAJO-1749: Refine JDBC exceptions to better handle exceptional + cases. (hyunsik) + TAJO-1737: Implement SQL Parser rule for Map type. (hyunsik) TAJO-1787: Remove unused and legacy exceptions. (hyunsik) http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-client/src/main/java/org/apache/tajo/client/SessionConnection.java ---------------------------------------------------------------------- diff --git a/tajo-client/src/main/java/org/apache/tajo/client/SessionConnection.java b/tajo-client/src/main/java/org/apache/tajo/client/SessionConnection.java index 7f33fdd..b63d35b 100644 --- a/tajo-client/src/main/java/org/apache/tajo/client/SessionConnection.java +++ b/tajo-client/src/main/java/org/apache/tajo/client/SessionConnection.java @@ -19,6 +19,7 @@ package org.apache.tajo.client; import com.google.protobuf.ServiceException; +import io.netty.channel.ConnectTimeoutException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.tajo.SessionVars; @@ -46,6 +47,7 @@ import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.StringResponse; import org.apache.tajo.service.ServiceTracker; import org.apache.tajo.util.CommonTestingUtil; import org.apache.tajo.util.KeyValueSet; +import org.apache.tajo.util.NetUtils; import org.apache.tajo.util.ProtoUtil; import java.io.Closeable; @@ -136,7 +138,7 @@ public class SessionConnection implements Closeable { connections.incrementAndGet(); } catch (Throwable t) { - throw new ClientConnectionException(t); + throw new TajoRuntimeException(new ClientConnectionException(t)); } return client; http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-client/src/main/java/org/apache/tajo/client/TajoClientImpl.java ---------------------------------------------------------------------- diff --git a/tajo-client/src/main/java/org/apache/tajo/client/TajoClientImpl.java b/tajo-client/src/main/java/org/apache/tajo/client/TajoClientImpl.java index a6c07ea..5a689a1 100644 --- a/tajo-client/src/main/java/org/apache/tajo/client/TajoClientImpl.java +++ b/tajo-client/src/main/java/org/apache/tajo/client/TajoClientImpl.java @@ -57,8 +57,7 @@ public class TajoClientImpl extends SessionConnection implements TajoClient, Que * @param properties configurations * @throws java.io.IOException */ - public TajoClientImpl(ServiceTracker tracker, @Nullable String baseDatabase, KeyValueSet properties) - throws SQLException { + public TajoClientImpl(ServiceTracker tracker, @Nullable String baseDatabase, KeyValueSet properties) { super(tracker, baseDatabase, properties); @@ -75,8 +74,7 @@ public class TajoClientImpl extends SessionConnection implements TajoClient, Que * @param properties configurations * @throws java.io.IOException */ - public TajoClientImpl(InetSocketAddress addr, @Nullable String baseDatabase, KeyValueSet properties) - throws SQLException { + public TajoClientImpl(InetSocketAddress addr, @Nullable String baseDatabase, KeyValueSet properties) { this(new DummyServiceTracker(addr), baseDatabase, properties); } http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-client/src/main/java/org/apache/tajo/client/v2/exception/ClientConnectionException.java ---------------------------------------------------------------------- diff --git a/tajo-client/src/main/java/org/apache/tajo/client/v2/exception/ClientConnectionException.java b/tajo-client/src/main/java/org/apache/tajo/client/v2/exception/ClientConnectionException.java index a7fb08a..fcbbfe3 100644 --- a/tajo-client/src/main/java/org/apache/tajo/client/v2/exception/ClientConnectionException.java +++ b/tajo-client/src/main/java/org/apache/tajo/client/v2/exception/ClientConnectionException.java @@ -19,10 +19,11 @@ package org.apache.tajo.client.v2.exception; import org.apache.tajo.error.Errors; +import org.apache.tajo.exception.TajoException; import org.apache.tajo.exception.TajoRuntimeException; -public class ClientConnectionException extends TajoRuntimeException { +public class ClientConnectionException extends TajoException { public ClientConnectionException(Throwable t) { - super(Errors.ResultCode.CLIENT_CONNECTION_EXCEPTION, t.getMessage()); + super(Errors.ResultCode.CLIENT_CONNECTION_EXCEPTION, t, t.getMessage()); } } http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-client/src/main/java/org/apache/tajo/jdbc/TajoSQLException.java ---------------------------------------------------------------------- diff --git a/tajo-client/src/main/java/org/apache/tajo/jdbc/TajoSQLException.java b/tajo-client/src/main/java/org/apache/tajo/jdbc/TajoSQLException.java new file mode 100644 index 0000000..53d39cb --- /dev/null +++ b/tajo-client/src/main/java/org/apache/tajo/jdbc/TajoSQLException.java @@ -0,0 +1,43 @@ +/* + * 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.tajo.jdbc; + +import org.apache.tajo.error.Errors; +import org.apache.tajo.exception.ErrorMessages; +import org.apache.tajo.exception.ExceptionUtil; +import org.apache.tajo.exception.SQLExceptionUtil; +import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos; + +import java.sql.SQLException; + +public class TajoSQLException extends SQLException { + + public TajoSQLException(PrimitiveProtos.ReturnState returnState) { + super(returnState.getMessage(), SQLExceptionUtil.toSQLState(returnState.getReturnCode()), + ExceptionUtil.toTajoException(returnState)); + } + + public TajoSQLException(Errors.ResultCode code, String...args) { + super(ErrorMessages.getMessage(code, args), SQLExceptionUtil.toSQLState(code)); + } + + public TajoSQLException(Errors.ResultCode code, Throwable t, String...args) { + super(ErrorMessages.getMessage(code, args), SQLExceptionUtil.toSQLState(code), t); + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-client/src/main/java/org/apache/tajo/jdbc/WaitingResultSet.java ---------------------------------------------------------------------- diff --git a/tajo-client/src/main/java/org/apache/tajo/jdbc/WaitingResultSet.java b/tajo-client/src/main/java/org/apache/tajo/jdbc/WaitingResultSet.java index 68cc2fc..aa26027 100644 --- a/tajo-client/src/main/java/org/apache/tajo/jdbc/WaitingResultSet.java +++ b/tajo-client/src/main/java/org/apache/tajo/jdbc/WaitingResultSet.java @@ -18,7 +18,6 @@ package org.apache.tajo.jdbc; -import com.google.protobuf.ServiceException; import org.apache.tajo.QueryId; import org.apache.tajo.TajoProtos; import org.apache.tajo.catalog.CatalogUtil; @@ -27,6 +26,7 @@ import org.apache.tajo.catalog.TableDesc; import org.apache.tajo.client.QueryClient; import org.apache.tajo.client.QueryStatus; import org.apache.tajo.client.TajoClientUtil; +import org.apache.tajo.error.Errors.ResultCode; import org.apache.tajo.exception.SQLExceptionUtil; import org.apache.tajo.exception.TajoException; import org.apache.tajo.ipc.ClientProtos; @@ -59,15 +59,13 @@ public class WaitingResultSet extends FetchResultSet { QueryStatus status = TajoClientUtil.waitCompletion(tajoClient, queryId); if (status.getState() != TajoProtos.QueryState.QUERY_SUCCEEDED) { - throw new ServiceException(status.getErrorMessage() != null ? status.getErrorMessage() : - status.getErrorTrace() != null ? status.getErrorTrace() : - "Failed to execute query by unknown reason"); + throw new SQLException(status.getErrorMessage() != null ? status.getErrorMessage() : "unknown error", + SQLExceptionUtil.toSQLState(ResultCode.INTERNAL_ERROR), ResultCode.INTERNAL_ERROR.getNumber()); } + ClientProtos.GetQueryResultResponse response = tajoClient.getResultResponse(queryId); TableDesc tableDesc = CatalogUtil.newTableDesc(response.getTableDesc()); return tableDesc.getLogicalSchema(); - } catch (ServiceException e) { - throw new SQLException(e); } catch (TajoException e) { throw SQLExceptionUtil.toSQLException(e); } http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java ---------------------------------------------------------------------- diff --git a/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java b/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java index 3b11eab..a3f18e3 100644 --- a/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java +++ b/tajo-common/src/main/java/org/apache/tajo/exception/ErrorMessages.java @@ -116,8 +116,9 @@ public class ErrorMessages { ADD_MESSAGE(INVALID_INPUTS_FOR_CROSS_JOIN, "At least one of both inputs for the cross join must be a simple " + "relation."); - ADD_MESSAGE(CLIENT_CONNECTION_EXCEPTION, "Client connection to '%s' has error: %s", 2); + ADD_MESSAGE(CLIENT_CONNECTION_EXCEPTION, "%s", 1); ADD_MESSAGE(CLIENT_UNABLE_TO_ESTABLISH_CONNECTION, "Client is unable to establish connection to '%s'", 1); + ADD_MESSAGE(CLIENT_CONNECTION_DOES_NOT_EXIST, "This connection has been closed."); } private static void ADD_MESSAGE(ResultCode code, String msgFormat) { @@ -169,7 +170,9 @@ public class ErrorMessages { } } else { - throw new TajoInternalError("Argument mismatch: code=" + code.name() + ", args=" + concat(args)); + throw new TajoInternalError( + "Error message arguments are invalid: code=" + code.name() + ", args=" + concat(args) + + ". Please report this bug to https://issues.apache.org/jira/browse/TAJO."); } } } http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-common/src/main/java/org/apache/tajo/exception/SQLExceptionUtil.java ---------------------------------------------------------------------- diff --git a/tajo-common/src/main/java/org/apache/tajo/exception/SQLExceptionUtil.java b/tajo-common/src/main/java/org/apache/tajo/exception/SQLExceptionUtil.java index e326ae2..0e22a87 100644 --- a/tajo-common/src/main/java/org/apache/tajo/exception/SQLExceptionUtil.java +++ b/tajo-common/src/main/java/org/apache/tajo/exception/SQLExceptionUtil.java @@ -32,11 +32,79 @@ public class SQLExceptionUtil { private static final Map<ResultCode, String> SQLSTATES = Maps.newHashMap(); static { - // TODO - All SQLState should be be filled - SQLSTATES.put(ResultCode.FEATURE_NOT_SUPPORTED, "0A000"); - SQLSTATES.put(ResultCode.NOT_IMPLEMENTED, "0A000"); - - SQLSTATES.put(ResultCode.SYNTAX_ERROR, "42601"); + SQLSTATES.put(ResultCode.INTERNAL_ERROR, "XX000"); + SQLSTATES.put(ResultCode.NOT_IMPLEMENTED, "0A000"); + SQLSTATES.put(ResultCode.FEATURE_NOT_SUPPORTED, "0A000"); + SQLSTATES.put(ResultCode.INVALID_RPC_CALL, "08P01"); // Protocol violation + + + // Class 61 - Query Management and Scheduler + SQLSTATES.put(ResultCode.QUERY_FAILED, "61T01"); + SQLSTATES.put(ResultCode.QUERY_KILLED, "61T02"); + SQLSTATES.put(ResultCode.QUERY_TIMEOUT, "61T03"); + SQLSTATES.put(ResultCode.QUERY_NOT_FOUND, "61T04"); + SQLSTATES.put(ResultCode.NO_DATA, "61T05"); + SQLSTATES.put(ResultCode.INCOMPLETE_QUERY, "61T06"); + + + // Class 62 - Session + SQLSTATES.put(ResultCode.INVALID_SESSION, "62T01"); + SQLSTATES.put(ResultCode.NO_SUCH_SESSION_VARIABLE, "62T02"); + SQLSTATES.put(ResultCode.INVALID_SESSION_VARIABLE, "62T03"); + + + // Data Exception (SQLState Class - 22) + SQLSTATES.put(ResultCode.DIVISION_BY_ZERO, "22012"); + + + // Section: Class 42 - Syntax Error or Access Rule Violation + SQLSTATES.put(ResultCode.SYNTAX_ERROR, "42601"); + + SQLSTATES.put(ResultCode.UNDEFINED_DATABASE, "42T01"); + SQLSTATES.put(ResultCode.UNDEFINED_SCHEMA, "42T02"); + SQLSTATES.put(ResultCode.UNDEFINED_TABLE, "42P01"); + SQLSTATES.put(ResultCode.UNDEFINED_COLUMN, "42703"); + SQLSTATES.put(ResultCode.UNDEFINED_FUNCTION, "42883"); + SQLSTATES.put(ResultCode.UNDEFINED_INDEX_FOR_TABLE, "42T03"); + SQLSTATES.put(ResultCode.UNDEFINED_INDEX_FOR_COLUMNS, "42T04"); + SQLSTATES.put(ResultCode.UNDEFINED_PARTITION, "42T05"); + SQLSTATES.put(ResultCode.UNDEFINED_PARTITION_METHOD, "42T06"); + SQLSTATES.put(ResultCode.UNDEFINED_OPERATOR, "42883"); // == UNDEFINED_FUNCTION + SQLSTATES.put(ResultCode.UNDEFINED_PARTITION_KEY, "42T07"); + + SQLSTATES.put(ResultCode.DUPLICATE_TABLESPACE, "42T08"); + SQLSTATES.put(ResultCode.DUPLICATE_DATABASE, "42P04"); + SQLSTATES.put(ResultCode.DUPLICATE_SCHEMA, "42P06"); + SQLSTATES.put(ResultCode.DUPLICATE_TABLE, "42P07"); + SQLSTATES.put(ResultCode.DUPLICATE_COLUMN, "42701"); + SQLSTATES.put(ResultCode.DUPLICATE_ALIAS, "42712"); + SQLSTATES.put(ResultCode.DUPLICATE_FUNCTION, "42723"); + SQLSTATES.put(ResultCode.DUPLICATE_INDEX, "42710"); + SQLSTATES.put(ResultCode.DUPLICATE_PARTITION, "42T09"); + + SQLSTATES.put(ResultCode.AMBIGUOUS_TABLE, "42723"); + SQLSTATES.put(ResultCode.AMBIGUOUS_COLUMN, "42723"); + SQLSTATES.put(ResultCode.AMBIGUOUS_FUNCTION, "42723"); + SQLSTATES.put(ResultCode.AMBIGUOUS_PARTITION_DIRECTORY, "42T10"); + + SQLSTATES.put(ResultCode.CANNOT_CAST, "42846"); + SQLSTATES.put(ResultCode.GROUPING_ERROR, "42803"); + SQLSTATES.put(ResultCode.WINDOWING_ERROR, "42P20"); + SQLSTATES.put(ResultCode.INVALID_RECURSION, "42P19"); + SQLSTATES.put(ResultCode.SET_OPERATION_SCHEMA_MISMATCH, "42601"); + SQLSTATES.put(ResultCode.SET_OPERATION_DATATYPE_MISMATCH, "42601"); + SQLSTATES.put(ResultCode.INVALID_FOREIGN_KEY, "42830"); + SQLSTATES.put(ResultCode.INVALID_NAME, "42602"); + SQLSTATES.put(ResultCode.INVALID_COLUMN_DEFINITION, "42611"); + SQLSTATES.put(ResultCode.NAME_TOO_LONG, "42622"); + SQLSTATES.put(ResultCode.RESERVED_NAME, "42939"); + SQLSTATES.put(ResultCode.DATATYPE_MISMATCH, "42804"); + SQLSTATES.put(ResultCode.INDETERMINATE_DATATYPE, "42P18"); + + // Client Connection + SQLSTATES.put(ResultCode.CLIENT_CONNECTION_EXCEPTION, "08001"); + SQLSTATES.put(ResultCode.CLIENT_UNABLE_TO_ESTABLISH_CONNECTION, "08002"); + SQLSTATES.put(ResultCode.CLIENT_CONNECTION_DOES_NOT_EXIST, "08003"); } public static boolean isThisError(SQLException e, ResultCode code) { @@ -73,8 +141,20 @@ public class SQLExceptionUtil { } } - public static SQLException toSQLException(TajoException e) throws SQLException { - return toSQLException(e.getErrorCode(), e.getMessage()); + public static String toSQLState(ResultCode code) { + if (SQLSTATES.containsKey(code)) { + return SQLSTATES.get(code); + } else { + return "42000"; + } + } + + public static SQLException toSQLException(DefaultTajoException e) throws SQLException { + if (e instanceof TajoRuntimeException) { + return toSQLException(e.getErrorCode(), ((TajoRuntimeException) e).getCause().getMessage()); + } else { + return toSQLException(e.getErrorCode(), e.getMessage()); + } } public static SQLException toSQLException(ReturnState state) throws SQLException { http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-common/src/main/java/org/apache/tajo/exception/TajoException.java ---------------------------------------------------------------------- diff --git a/tajo-common/src/main/java/org/apache/tajo/exception/TajoException.java b/tajo-common/src/main/java/org/apache/tajo/exception/TajoException.java index b5d236e..df74072 100644 --- a/tajo-common/src/main/java/org/apache/tajo/exception/TajoException.java +++ b/tajo-common/src/main/java/org/apache/tajo/exception/TajoException.java @@ -43,6 +43,11 @@ public class TajoException extends Exception implements DefaultTajoException { this.code = code; } + public TajoException(ResultCode code, Throwable t, String ... args) { + super(ErrorMessages.getMessage(code, args), t); + this.code = code; + } + public TajoException(ResultCode code, String ... args) { super(ErrorMessages.getMessage(code, args)); this.code = code; http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-common/src/main/proto/errors.proto ---------------------------------------------------------------------- diff --git a/tajo-common/src/main/proto/errors.proto b/tajo-common/src/main/proto/errors.proto index 21746f3..f830b11 100644 --- a/tajo-common/src/main/proto/errors.proto +++ b/tajo-common/src/main/proto/errors.proto @@ -68,31 +68,31 @@ import "stacktrace.proto"; enum ResultCode { // Class // 00 - Successful Completion - OK = 0; + OK = 0; - WARNING = 100; // Warning + WARNING = 100; // Warning // General Errors - INTERNAL_ERROR = 201; // Error caused by internal bugs (See also TajoInternalException.java) - NOT_IMPLEMENTED = 202; // Planned, but not implemented yet. - FEATURE_NOT_SUPPORTED = 203; // SQLState: 0A000 - Unsupported feature (usually for unreasonable feature) - INVALID_RPC_CALL = 204; // When invalid RPC call is invoked (e.g., wrong message and absent fields) + INTERNAL_ERROR = 201; // SQLState: XX000 - Error caused by internal bugs (See TajoInternalException) + NOT_IMPLEMENTED = 202; // SQLState: 0A000 - Not implemented yet, but planned. + FEATURE_NOT_SUPPORTED = 203; // SQLState: 0A000 - Unsupported feature (usually for unreasonable feature) + INVALID_RPC_CALL = 204; // SQLState: 08P01 - When invalid RPC call is invoked (e.g., wrong message and absent fields) // Query Management and Scheduler - QUERY_FAILED = 301; // SQLState: ? - Query failed - QUERY_KILLED = 302; // SQLState: ? - Query killed - QUERY_TIMEOUT = 303; // SQLState: ? - Timeout for the query - QUERY_NOT_FOUND = 304; // No such query in TajoMaster - NO_DATA = 305; // No data due to query fail or error - INCOMPLETE_QUERY = 306; // It occurs when a client requests something of a completed query. + QUERY_FAILED = 301; // SQLState: 61T01 - Query failed + QUERY_KILLED = 302; // SQLState: 61T02 - Query killed + QUERY_TIMEOUT = 303; // SQLState: 61T03 - Timeout for the query + QUERY_NOT_FOUND = 304; // SQLState: 61T04 - No such query in TajoMaster + NO_DATA = 305; // SQLState: 61T05 - No data due to query fail or error + INCOMPLETE_QUERY = 306; // SQLState: 61T06 - It occurs when a client requests something of a completed query. // Session - INVALID_SESSION = 401; // Session already was invalid - NO_SUCH_SESSION_VARIABLE = 402; // Session variable not found - INVALID_SESSION_VARIABLE = 403; // Session variable is invalid (type mismatch or out of range) + INVALID_SESSION = 401; // SQLState: 62T01 - Session already was invalid + NO_SUCH_SESSION_VARIABLE = 402; // SQLState: 62T01 - Session variable not found + INVALID_SESSION_VARIABLE = 403; // SQLState: 62T01 - Session variable is invalid (type mismatch or out of range) // Data Exception (SQLState Class - 22) - DIVISION_BY_ZERO = 451; // SQLState: 22012 - Division by zero + DIVISION_BY_ZERO = 451; // SQLState: 22012 - Division by zero // Section: Class 42 - Syntax Error or Access Rule Violation @@ -101,9 +101,9 @@ enum ResultCode { INSUFFICIENT_PRIVILEGE = 503; // SQLState: 42501 UNDEFINED_TABLESPACE = 511; // ? - UNDEFINED_DATABASE = 512; // ? - UNDEFINED_SCHEMA = 513; // ? - UNDEFINED_TABLE = 514; // ? + UNDEFINED_DATABASE = 512; // SQLState: 42T01 + UNDEFINED_SCHEMA = 513; // SQLState: + UNDEFINED_TABLE = 514; // SQLState: 42P01 UNDEFINED_COLUMN = 515; // SQLState: 42703 UNDEFINED_FUNCTION = 516; // SQLState: 42883 UNDEFINED_INDEX_FOR_TABLE = 517; // ? @@ -121,10 +121,10 @@ enum ResultCode { DUPLICATE_COLUMN = 535; // SQLState: 42701 DUPLICATE_ALIAS = 536; // SQLState: 42712 DUPLICATE_FUNCTION = 537; // SQLState: 42723 - DUPLICATE_INDEX = 538; // SQLState: ? - DUPLICATE_PARTITION = 539; // SQLState: ? + DUPLICATE_INDEX = 538; // SQLState: 42T07 + DUPLICATE_PARTITION = 539; // SQLState: 42T08 - AMBIGUOUS_TABLE = 541; // ? + AMBIGUOUS_TABLE = 541; // SQLState: 42P09 AMBIGUOUS_COLUMN = 542; // SQLState: 42702; AMBIGUOUS_FUNCTION = 543; // SQLState: 42725; AMBIGUOUS_PARTITION_DIRECTORY = 544; // ? @@ -170,10 +170,11 @@ enum ResultCode { INVALID_TABLE_PROPERTY = 1004; // SQLState: ? - Invalid Table Property MISSING_TABLE_PROPERTY = 1005; // SQLState: ? - Missing table property - + // Client Connection CLIENT_CONNECTION_EXCEPTION = 1101; // SQLState: 08000 - Client connection error CLIENT_UNABLE_TO_ESTABLISH_CONNECTION = 1102; // SQLState: 08001 - - CLIENT_PROTOCOL_PROTOCOL_VIOLATION = 1103; // SQLState: ? + CLIENT_CONNECTION_DOES_NOT_EXIST = 1103; // SQLState: 08003 - Client connection has been closed. + CLIENT_PROTOCOL_PROTOCOL_VIOLATION = 1104; // SQLState: ? // 53 - Invalid Operand or Inconsistent Specification INSUFFICIENT_RESOURCE = 53000; http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-core/src/main/java/org/apache/tajo/master/exec/CreateTableExecutor.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/master/exec/CreateTableExecutor.java b/tajo-core/src/main/java/org/apache/tajo/master/exec/CreateTableExecutor.java index 38f722d..24f420c 100644 --- a/tajo-core/src/main/java/org/apache/tajo/master/exec/CreateTableExecutor.java +++ b/tajo-core/src/main/java/org/apache/tajo/master/exec/CreateTableExecutor.java @@ -108,6 +108,7 @@ public class CreateTableExecutor { tableSpace.createTable(desc, ifNotExists); catalog.createTable(desc); + LOG.info("relation '" + qualifiedName + "' created."); return desc; } http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-core/src/main/java/org/apache/tajo/master/exec/DDLExecutor.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/master/exec/DDLExecutor.java b/tajo-core/src/main/java/org/apache/tajo/master/exec/DDLExecutor.java index e3d91bb..a0f9adc 100644 --- a/tajo-core/src/main/java/org/apache/tajo/master/exec/DDLExecutor.java +++ b/tajo-core/src/main/java/org/apache/tajo/master/exec/DDLExecutor.java @@ -251,11 +251,12 @@ public class DDLExecutor { } } - catalog.createDatabase(databaseName, tablespaceName); String normalized = databaseName; Path databaseDir = StorageUtil.concatPath(context.getConf().getVar(TajoConf.ConfVars.WAREHOUSE_DIR), normalized); FileSystem fs = databaseDir.getFileSystem(context.getConf()); fs.mkdirs(databaseDir); + catalog.createDatabase(databaseName, tablespaceName); + LOG.info("database \"" + databaseName + "\" created."); } public void dropDatabase(QueryContext queryContext, String databaseName, boolean ifExists) http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/JdbcConnection.java ---------------------------------------------------------------------- diff --git a/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/JdbcConnection.java b/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/JdbcConnection.java index b098b16..85dbdbe 100644 --- a/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/JdbcConnection.java +++ b/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/JdbcConnection.java @@ -27,14 +27,17 @@ import org.apache.tajo.client.CatalogAdminClient; import org.apache.tajo.client.QueryClient; import org.apache.tajo.client.TajoClient; import org.apache.tajo.client.TajoClientImpl; +import org.apache.tajo.client.v2.exception.ClientConnectionException; import org.apache.tajo.conf.TajoConf; -import org.apache.tajo.exception.SQLExceptionUtil; -import org.apache.tajo.exception.TajoException; +import org.apache.tajo.error.Errors; +import org.apache.tajo.error.Errors.ResultCode; +import org.apache.tajo.exception.*; import org.apache.tajo.jdbc.util.QueryStringDecoder; import org.apache.tajo.rpc.RpcUtils; import org.apache.tajo.util.KeyValueSet; import java.io.IOException; +import java.net.ConnectException; import java.net.URI; import java.sql.*; import java.util.List; @@ -66,17 +69,19 @@ public class JdbcConnection implements Connection { this.properties = properties; try { + if (!rawURI.startsWith(TajoDriver.TAJO_JDBC_URL_PREFIX)) { - throw new SQLException("Invalid URL: " + rawURI, "TAJO-001"); + // its impossible case + throw new TajoInternalError("Invalid URL: " + rawURI); } // URI form: jdbc:tajo://hostname:port/databasename int startIdx = rawURI.indexOf(":"); if (startIdx < 0) { - throw new SQLException("Invalid URL: " + rawURI, "TAJO-001"); + throw new TajoInternalError("Invalid URL: " + rawURI); } - String uri = rawURI.substring(startIdx+1, rawURI.length()); + String uri = rawURI.substring(startIdx + 1, rawURI.length()); try { this.uri = URI.create(uri); } catch (IllegalArgumentException iae) { @@ -116,8 +121,12 @@ public class JdbcConnection implements Connection { try { tajoClient = new TajoClientImpl(RpcUtils.createSocketAddr(hostName, port), databaseName, clientProperties); - } catch (Exception e) { - throw new SQLException("Cannot create TajoClient instance:" + e.getMessage(), "TAJO-002"); + } catch (Throwable t) { + if (t instanceof DefaultTajoException) { + throw SQLExceptionUtil.toSQLException((DefaultTajoException) t); + } else { + throw new TajoSQLException(ResultCode.INTERNAL_ERROR, t, t.getMessage()); + } } closed.set(false); } @@ -182,7 +191,7 @@ public class JdbcConnection implements Connection { @Override public Statement createStatement() throws SQLException { if (isClosed()) { - throw new SQLException("Can't create Statement, connection is closed"); + throw new TajoSQLException(ResultCode.CLIENT_CONNECTION_DOES_NOT_EXIST); } return new TajoStatement(this, tajoClient); } http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoPreparedStatement.java ---------------------------------------------------------------------- diff --git a/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoPreparedStatement.java b/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoPreparedStatement.java index 0574bf9..6b47f97 100644 --- a/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoPreparedStatement.java +++ b/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoPreparedStatement.java @@ -61,7 +61,7 @@ public class TajoPreparedStatement extends TajoStatement implements PreparedStat @Override public void clearParameters() throws SQLException { - checkConnection("Can't clear parameters"); + checkConnection(); this.parameters.clear(); } @@ -83,7 +83,7 @@ public class TajoPreparedStatement extends TajoStatement implements PreparedStat } protected TajoResultSetBase executeImmediate(String sql) throws SQLException { - checkConnection("Can't execute"); + checkConnection(); try { if (sql.contains("?")) { @@ -152,7 +152,7 @@ public class TajoPreparedStatement extends TajoStatement implements PreparedStat @Override public ResultSetMetaData getMetaData() throws SQLException { - checkConnection("Can't get metadata"); + checkConnection(); if(resultSet != null) { return resultSet.getMetaData(); } else { @@ -223,7 +223,7 @@ public class TajoPreparedStatement extends TajoStatement implements PreparedStat @Override public void setBoolean(int parameterIndex, boolean x) throws SQLException { - checkConnection("Can't set parameters"); + checkConnection(); this.parameters.put(parameterIndex, "" + x); } @@ -281,25 +281,25 @@ public class TajoPreparedStatement extends TajoStatement implements PreparedStat @Override public void setDouble(int parameterIndex, double x) throws SQLException { - checkConnection("Can't set parameters"); + checkConnection(); this.parameters.put(parameterIndex,"" + x); } @Override public void setFloat(int parameterIndex, float x) throws SQLException { - checkConnection("Can't set parameters"); + checkConnection(); this.parameters.put(parameterIndex,"" + x); } @Override public void setInt(int parameterIndex, int x) throws SQLException { - checkConnection("Can't set parameters"); + checkConnection(); this.parameters.put(parameterIndex,"" + x); } @Override public void setLong(int parameterIndex, long x) throws SQLException { - checkConnection("Can't set parameters"); + checkConnection(); this.parameters.put(parameterIndex,"" + x); } @@ -378,13 +378,13 @@ public class TajoPreparedStatement extends TajoStatement implements PreparedStat @Override public void setShort(int parameterIndex, short x) throws SQLException { - checkConnection("Can't set parameters"); + checkConnection(); this.parameters.put(parameterIndex,"" + x); } @Override public void setString(int parameterIndex, String x) throws SQLException { - checkConnection("Can't set parameters"); + checkConnection(); x=x.replace("'", "\\'"); this.parameters.put(parameterIndex,"'" + x +"'"); } http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java ---------------------------------------------------------------------- diff --git a/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java b/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java index 5354e60..6039e9c 100644 --- a/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java +++ b/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java @@ -17,19 +17,16 @@ */ package org.apache.tajo.jdbc; -import com.google.common.collect.Lists; import org.apache.tajo.QueryId; import org.apache.tajo.SessionVars; import org.apache.tajo.client.TajoClient; import org.apache.tajo.client.TajoClientUtil; +import org.apache.tajo.error.Errors.ResultCode; import org.apache.tajo.exception.SQLExceptionUtil; +import org.apache.tajo.exception.TajoException; import org.apache.tajo.ipc.ClientProtos; import java.sql.*; -import java.util.HashMap; -import java.util.Map; - -import static org.apache.tajo.client.TajoClientUtil.NULL_RESULT_SET; public class TajoStatement implements Statement { protected JdbcConnection conn; @@ -79,7 +76,7 @@ public class TajoStatement implements Statement { @Override public void cancel() throws SQLException { - checkConnection("Can't cancel query"); + checkConnection(); if (resultSet == null || resultSet.getQueryId().isNull()) { return; } @@ -99,7 +96,7 @@ public class TajoStatement implements Statement { @Override public void clearWarnings() throws SQLException { - checkConnection("Can't clear warnings"); + checkConnection(); warningChain = null; } @@ -146,7 +143,7 @@ public class TajoStatement implements Statement { @Override public ResultSet executeQuery(String sql) throws SQLException { - checkConnection("Can't execute"); + checkConnection(); return executeSQL(sql); } @@ -173,16 +170,20 @@ public class TajoStatement implements Statement { } } - protected void checkConnection(String errorMsg) throws SQLException { - if (isClosed) { - throw new SQLException(errorMsg + " after statement has been closed"); + protected void checkConnection() throws SQLException { + if (isClosed || conn.isClosed()) { + throw new TajoSQLException(ResultCode.CLIENT_CONNECTION_DOES_NOT_EXIST); } } @Override public int executeUpdate(String sql) throws SQLException { - checkConnection("Can't execute update"); - tajoClient.executeQuery(sql); + checkConnection(); + try { + tajoClient.updateQuery(sql); + } catch (TajoException e) { + throw SQLExceptionUtil.toSQLException(e); + } return 1; } @@ -203,19 +204,19 @@ public class TajoStatement implements Statement { @Override public Connection getConnection() throws SQLException { - checkConnection("Can't get connection"); + checkConnection(); return conn; } @Override public int getFetchDirection() throws SQLException { - checkConnection("Can't get fetch direction"); + checkConnection(); return ResultSet.FETCH_FORWARD; } @Override public int getFetchSize() throws SQLException { - checkConnection("Can't get fetch size"); + checkConnection(); return fetchSize; } @@ -252,7 +253,7 @@ public class TajoStatement implements Statement { @Override public ResultSet getResultSet() throws SQLException { - checkConnection("Can't get result set"); + checkConnection(); return resultSet; } @@ -282,7 +283,7 @@ public class TajoStatement implements Statement { @Override public SQLWarning getWarnings() throws SQLException { - checkConnection("Can't get warnings"); + checkConnection(); return warningChain; } @@ -321,7 +322,7 @@ public class TajoStatement implements Statement { @Override public void setFetchSize(int rows) throws SQLException { - checkConnection("Can't set fetch size"); + checkConnection(); fetchSize = rows; } http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-jdbc/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java ---------------------------------------------------------------------- diff --git a/tajo-jdbc/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java b/tajo-jdbc/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java index e6d01fe..40d7e58 100644 --- a/tajo-jdbc/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java +++ b/tajo-jdbc/src/test/java/org/apache/tajo/jdbc/TestTajoJdbc.java @@ -61,12 +61,6 @@ public class TestTajoJdbc extends QueryTestCaseBase { assertFalse(driver.acceptsURL("jdbc:taju:")); } - @Test(expected = SQLException.class) - public void testGetConnection() throws SQLException { - DriverManager.getConnection("jdbc:taju://" + tajoMasterAddress.getHostName() + ":" + tajoMasterAddress.getPort() - + "/default"); - } - @Test public void testStatement() throws Exception { String connUri = buildConnectionUri(tajoMasterAddress.getHostName(), tajoMasterAddress.getPort(), http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-jdbc/src/test/java/org/apache/tajo/jdbc/TestTajoJdbcNegative.java ---------------------------------------------------------------------- diff --git a/tajo-jdbc/src/test/java/org/apache/tajo/jdbc/TestTajoJdbcNegative.java b/tajo-jdbc/src/test/java/org/apache/tajo/jdbc/TestTajoJdbcNegative.java new file mode 100644 index 0000000..232292b --- /dev/null +++ b/tajo-jdbc/src/test/java/org/apache/tajo/jdbc/TestTajoJdbcNegative.java @@ -0,0 +1,156 @@ +/* + * 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.tajo.jdbc; + +import org.apache.tajo.IntegrationTest; +import org.apache.tajo.QueryTestCaseBase; +import org.apache.tajo.error.Errors.ResultCode; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.sql.*; + +import static org.apache.tajo.TajoConstants.DEFAULT_DATABASE_NAME; +import static org.apache.tajo.exception.SQLExceptionUtil.toSQLState; +import static org.apache.tajo.jdbc.TestTajoJdbc.buildConnectionUri; +import static org.junit.Assert.*; + +@Category(IntegrationTest.class) +public class TestTajoJdbcNegative extends QueryTestCaseBase { + private static InetSocketAddress tajoMasterAddress; + + @BeforeClass + public static void setUp() throws Exception { + tajoMasterAddress = testingCluster.getMaster().getTajoMasterClientService().getBindAddress(); + Class.forName("org.apache.tajo.jdbc.TajoDriver").newInstance(); + } + + @AfterClass + public static void tearDown() throws Exception { + } + + @Test(expected = SQLException.class) + public void testGetConnection() throws SQLException { + DriverManager.getConnection("jdbc:taju://" + tajoMasterAddress.getHostName() + ":" + tajoMasterAddress.getPort() + + "/default"); + } + + @Test + public void testUnresolvedError() throws SQLException { + try { + DriverManager.getConnection("jdbc:tajo://tajo-unknown-asdnkl213.asd:2002/default"); + } catch (SQLException s) { + assertEquals(toSQLState(ResultCode.CLIENT_CONNECTION_EXCEPTION), s.getSQLState()); + assertEquals("Can't resolve host name: tajo-unknown-asdnkl213.asd:2002", s.getMessage()); + } + } + + @Test + public void testConnectionRefused() throws SQLException, IOException { + Integer port = null; + try { + ServerSocket s = new ServerSocket(0); + port = s.getLocalPort(); + s.close(); + DriverManager.getConnection("jdbc:tajo://localhost:" + port + "/default"); + fail("Must be failed."); + } catch (SQLException s) { + assertEquals(toSQLState(ResultCode.CLIENT_CONNECTION_EXCEPTION), s.getSQLState()); + assertEquals("Connection refused: localhost/127.0.0.1:" + port, s.getMessage()); + } + } + + @Test + public void testConnectionClosedAtCreateStmt() throws SQLException, IOException { + String connUri = buildConnectionUri(tajoMasterAddress.getHostName(), tajoMasterAddress.getPort(), + DEFAULT_DATABASE_NAME); + Connection conn = DriverManager.getConnection(connUri); + assertTrue(conn.isValid(100)); + + conn.close(); + try (Statement stmt = conn.createStatement()) { + fail("Must be failed."); + stmt.isClosed(); + } catch (SQLException s) { + assertEquals(toSQLState(ResultCode.CLIENT_CONNECTION_DOES_NOT_EXIST), s.getSQLState()); + assertEquals("This connection has been closed.", s.getMessage()); + } + } + + @Test + public void testConnectionClosed() throws SQLException, IOException { + String connUri = buildConnectionUri(tajoMasterAddress.getHostName(), tajoMasterAddress.getPort(), + DEFAULT_DATABASE_NAME); + Connection conn = DriverManager.getConnection(connUri); + assertTrue(conn.isValid(100)); + + try (Statement stmt = conn.createStatement()) { + conn.close(); + stmt.executeUpdate("SELECT 1;"); + fail("Must be failed."); + } catch (SQLException s) { + assertEquals(toSQLState(ResultCode.CLIENT_CONNECTION_DOES_NOT_EXIST), s.getSQLState()); + assertEquals("This connection has been closed.", s.getMessage()); + } + } + + @Test + public void testImmediateException() throws Exception { + String connUri = buildConnectionUri(tajoMasterAddress.getHostName(), tajoMasterAddress.getPort(), + DEFAULT_DATABASE_NAME); + Connection conn = DriverManager.getConnection(connUri); + assertTrue(conn.isValid(100)); + + try (Statement stmt = conn.createStatement()) { + stmt.executeUpdate("CREATE DATABASE IF NOT EXISTS TestTajoJdbcNegative"); + stmt.executeUpdate("CREATE TABLE TestTajoJdbcNegative.table123u8sd ( name RECORD(last TEXT, first TEXT) )"); + + try (ResultSet resultSet = stmt.executeQuery("select name FROM TestTajoJdbcNegative.table123u8sd")) { + fail("Getting a record type field must be failed"); + } catch (SQLException s) { + assertEquals(toSQLState(ResultCode.NOT_IMPLEMENTED), s.getSQLState()); + } finally { + stmt.executeUpdate("DROP TABLE IF EXISTS TestTajoJdbcNegative.table12u79"); + stmt.executeUpdate("DROP DATABASE IF EXISTS TestTajoJdbcNegative"); + } + } + } + + @Test + public void testExceptionDuringProcessing() throws Exception { + String connUri = buildConnectionUri(tajoMasterAddress.getHostName(), tajoMasterAddress.getPort(), + DEFAULT_DATABASE_NAME); + Connection conn = DriverManager.getConnection(connUri); + assertTrue(conn.isValid(100)); + + try (Statement stmt = conn.createStatement()) { + try (ResultSet resultSet = + stmt.executeQuery("select fail(3, l_orderkey, 'testQueryFailure') from default.lineitem")) { + fail("Failure must occur here."); + } catch (SQLException s) { + assertEquals(toSQLState(ResultCode.INTERNAL_ERROR), s.getSQLState()); + } + } + } +} http://git-wip-us.apache.org/repos/asf/tajo/blob/688bc5c1/tajo-rpc/tajo-rpc-protobuf/src/main/java/org/apache/tajo/rpc/NettyClientBase.java ---------------------------------------------------------------------- diff --git a/tajo-rpc/tajo-rpc-protobuf/src/main/java/org/apache/tajo/rpc/NettyClientBase.java b/tajo-rpc/tajo-rpc-protobuf/src/main/java/org/apache/tajo/rpc/NettyClientBase.java index 0d86527..5f76bfc 100644 --- a/tajo-rpc/tajo-rpc-protobuf/src/main/java/org/apache/tajo/rpc/NettyClientBase.java +++ b/tajo-rpc/tajo-rpc-protobuf/src/main/java/org/apache/tajo/rpc/NettyClientBase.java @@ -39,6 +39,8 @@ import java.lang.reflect.Method; import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.net.UnknownHostException; +import java.nio.channels.UnresolvedAddressException; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -195,7 +197,7 @@ public abstract class NettyClientBase<T> implements ProtoDeclaration, Closeable if (maxRetries > retries) { retries++; - LOG.warn(getErrorMessage(ExceptionUtils.getMessage(future.cause())) + " Try to reconnect : " + getKey().addr); + LOG.warn(getErrorMessage(ExceptionUtils.getMessage(future.cause())) + "\nTry to reconnect : " + getKey().addr); try { Thread.sleep(RpcConstants.DEFAULT_PAUSE); } catch (InterruptedException e) { @@ -206,8 +208,13 @@ public abstract class NettyClientBase<T> implements ProtoDeclaration, Closeable break; } } else { - throw new ConnectTimeoutException("Max retry count has been exceeded. attempts=" + retries - + " caused by: " + future.cause()); + LOG.error("Max retry count has been exceeded. attempts=" + retries + " caused by: " + future.cause()); + + if (future.cause() instanceof UnresolvedAddressException) { + throw new ConnectException("Can't resolve host name: " + address.toString()); + } else { + throw new ConnectTimeoutException(future.cause().getMessage()); + } } } }
