| /* |
| * 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.exception; |
| |
| import com.google.common.collect.Maps; |
| import org.apache.commons.logging.Log; |
| import org.apache.hadoop.util.StringUtils; |
| import org.apache.tajo.TajoConstants; |
| import org.apache.tajo.error.Errors; |
| import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.ReturnState; |
| |
| import java.lang.reflect.Constructor; |
| import java.util.Map; |
| |
| import static org.apache.tajo.error.Errors.ResultCode.*; |
| import static org.apache.tajo.exception.ReturnStateUtil.isError; |
| |
| public class ExceptionUtil { |
| |
| static Map<Errors.ResultCode, Class<? extends DefaultTajoException>> EXCEPTIONS = Maps.newHashMap(); |
| |
| static { |
| |
| // General Errors |
| ADD_EXCEPTION(INTERNAL_ERROR, TajoInternalError.class); |
| ADD_EXCEPTION(FEATURE_NOT_SUPPORTED, UnsupportedException.class); |
| ADD_EXCEPTION(NOT_IMPLEMENTED, NotImplementedException.class); |
| |
| // Query Management and Scheduler |
| ADD_EXCEPTION(QUERY_NOT_FOUND, QueryNotFoundException.class); |
| |
| // Session |
| ADD_EXCEPTION(INVALID_SESSION, InvalidSessionException.class); |
| ADD_EXCEPTION(NO_SUCH_SESSION_VARIABLE, NoSuchSessionVariableException.class); |
| ADD_EXCEPTION(INVALID_SESSION_VARIABLE, InvalidSessionVariableException.class); |
| |
| // Data Exception (SQLState Class - 22) |
| ADD_EXCEPTION(DIVISION_BY_ZERO, DividedByZeroException.class); |
| ADD_EXCEPTION(INVALID_URL, InvalidURLException.class); |
| ADD_EXCEPTION(INVALID_VALUE_FOR_CAST, InvalidValueForCastException.class); |
| |
| // Syntax Error or Access Rule Violation |
| ADD_EXCEPTION(SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION, SQLSyntaxError.class); |
| ADD_EXCEPTION(SYNTAX_ERROR, SQLSyntaxError.class); |
| ADD_EXCEPTION(INSUFFICIENT_PRIVILEGE, InsufficientPrivilegeException.class); |
| ADD_EXCEPTION(CANNOT_DROP_CURRENT_DATABASE, CannotDropCurrentDatabaseException.class); |
| |
| ADD_EXCEPTION(UNDEFINED_TABLESPACE, UndefinedTablespaceException.class); |
| ADD_EXCEPTION(UNDEFINED_DATABASE, UndefinedDatabaseException.class); |
| // ADD_EXCEPTION(UNDEFINED_SCHEMA, ); |
| ADD_EXCEPTION(UNDEFINED_TABLE, UndefinedTableException.class); |
| ADD_EXCEPTION(UNDEFINED_COLUMN, UndefinedColumnException.class); |
| ADD_EXCEPTION(UNDEFINED_FUNCTION, UndefinedFunctionException.class); |
| ADD_EXCEPTION(UNDEFINED_PARTITION, UndefinedPartitionException.class); |
| ADD_EXCEPTION(UNDEFINED_PARTITION_KEY, UndefinedPartitionKeyException.class); |
| ADD_EXCEPTION(UNDEFINED_OPERATOR, UndefinedOperatorException.class); |
| ADD_EXCEPTION(UNDEFINED_INDEX_NAME, UndefinedIndexException.class); |
| ADD_EXCEPTION(UNDEFINED_TABLESPACE_HANDLER, UndefinedTablespaceHandlerException.class); |
| |
| ADD_EXCEPTION(DUPLICATE_TABLESPACE, DuplicateTablespaceException.class); |
| ADD_EXCEPTION(DUPLICATE_DATABASE, DuplicateDatabaseException.class); |
| // ADD_EXCEPTION(DUPLICATE_SCHEMA, ); |
| ADD_EXCEPTION(DUPLICATE_TABLE, DuplicateTableException.class); |
| ADD_EXCEPTION(DUPLICATE_COLUMN, DuplicateColumnException.class); |
| // ADD_EXCEPTION(DUPLICATE_ALIAS, ); |
| ADD_EXCEPTION(DUPLICATE_INDEX, DuplicateIndexException.class); |
| ADD_EXCEPTION(DUPLICATE_PARTITION, DuplicatePartitionException.class); |
| |
| ADD_EXCEPTION(AMBIGUOUS_TABLE, AmbiguousTableException.class); |
| ADD_EXCEPTION(AMBIGUOUS_COLUMN, AmbiguousColumnException.class); |
| ADD_EXCEPTION(AMBIGUOUS_FUNCTION, AmbiguousFunctionException.class); |
| |
| // Expressions |
| ADD_EXCEPTION(DATATYPE_MISMATCH, DataTypeMismatchException.class); |
| |
| ADD_EXCEPTION(UNAVAILABLE_TABLE_LOCATION, UnavailableTableLocationException.class); |
| ADD_EXCEPTION(UNKNOWN_DATAFORMAT, UnknownDataFormatException.class); |
| ADD_EXCEPTION(UNSUPPORTED_DATATYPE, UnsupportedDataTypeException.class); |
| ADD_EXCEPTION(INVALID_DATATYPE, InvalidDataTypeException.class); |
| ADD_EXCEPTION(INVALID_TABLE_PROPERTY, InvalidTablePropertyException.class); |
| ADD_EXCEPTION(MISSING_TABLE_PROPERTY, MissingTablePropertyException.class); |
| |
| ADD_EXCEPTION(TOO_LARGE_INPUT_FOR_CROSS_JOIN, TooLargeInputForCrossJoinException.class); |
| ADD_EXCEPTION(INVALID_INPUTS_FOR_CROSS_JOIN, InvalidInputsForCrossJoin.class); |
| |
| ADD_EXCEPTION(CAT_UNSUPPORTED_CATALOG_STORE, UnsupportedCatalogStore.class); |
| } |
| |
| private static void ADD_EXCEPTION(Errors.ResultCode code, Class<? extends DefaultTajoException> cls) { |
| EXCEPTIONS.put(code, cls); |
| } |
| |
| /** |
| * If the exception is equivalent to the error corresponding to the expected exception, throws the exception. |
| * It is used to throw an exception for a error. |
| * |
| * @param state ReturnState |
| * @param clazz Exception class corresponding to the expected |
| * @param <T> Exception class |
| * @throws T Exception |
| */ |
| public static <T extends TajoException> void throwsIfThisError(ReturnState state, Class<T> clazz) throws T { |
| if (isError(state)) { |
| T exception = (T) toTajoException(state); |
| if (exception.getClass().equals(clazz)) { |
| throw exception; |
| } |
| } |
| } |
| |
| /** |
| * It can throw any TajoException if any error occurs. |
| * |
| * @param state |
| * @throws TajoException |
| */ |
| public static void throwIfError(ReturnState state) throws TajoException { |
| if (isError(state)) { |
| throw toTajoException(state); |
| } |
| } |
| |
| public static DefaultTajoException toTajoExceptionCommon(ReturnState state) { |
| if (state.getReturnCode() == Errors.ResultCode.INTERNAL_ERROR) { |
| return new TajoInternalError(state); |
| |
| } else if (EXCEPTIONS.containsKey(state.getReturnCode())) { |
| Object exception; |
| try { |
| Class clazz = EXCEPTIONS.get(state.getReturnCode()); |
| Constructor c = clazz.getConstructor(ReturnState.class); |
| exception = c.newInstance(new Object[]{state}); |
| } catch (Throwable t) { |
| throw new TajoInternalError(t); |
| } |
| |
| if (exception instanceof TajoException) { |
| return (TajoException) exception; |
| } else if (exception instanceof TajoRuntimeException) { |
| return ((TajoRuntimeException) exception); |
| } else { |
| return ((TajoError) exception); |
| } |
| |
| } else { |
| throw new TajoInternalError( |
| "Cannot restore the exception for [" + state.getReturnCode().name() +"] '" + state.getMessage() +"'"); |
| } |
| } |
| |
| public static TajoException toTajoException(ReturnState state) throws TajoRuntimeException, TajoError { |
| DefaultTajoException e = toTajoExceptionCommon(state); |
| |
| if (e instanceof TajoException) { |
| return (TajoException) e; |
| } else if (e instanceof TajoRuntimeException) { |
| throw ((TajoRuntimeException) e); |
| } else { |
| throw ((TajoError) e); |
| } |
| } |
| |
| /** |
| * Determine if a Throwable has Tajo's ReturnCode and error message. |
| * |
| * @param t Throwable |
| * @return true if a Throwable has Tajo's ReturnCode and error message. |
| */ |
| public static boolean isExceptionWithResultCode(Throwable t) { |
| return t instanceof DefaultTajoException; |
| } |
| |
| /** |
| * Determine if a Throwable is caused by user's wrong input and invalid data instead of a bug. |
| * |
| * @param t Throwable |
| * @return true if a Throwable has Tajo's ReturnCode and error message. |
| */ |
| public static boolean isManagedException(Throwable t) { |
| return t instanceof TajoException || t instanceof TajoRuntimeException; |
| } |
| |
| private static void printStackTrace(Log log, Throwable t) { |
| log.error("\nStack Trace:\n" + StringUtils.stringifyException(t)); |
| } |
| |
| public static void printStackTraceIfError(Log log, Throwable t) { |
| // if this runs as an actual cluster instance or a debug mode, it will print all stacktraces. |
| // In other cases (i.e., run as a test mode and not debug mode), it will print stacktraces |
| // if the query is managed mode. |
| if (!TajoConstants.IS_TEST_MODE || TajoConstants.IS_DEBUG_MODE || !ExceptionUtil.isManagedException(t)) { |
| ExceptionUtil.printStackTrace(log, t); |
| } |
| } |
| |
| public static UnsupportedException makeNotSupported(String feature) { |
| return new UnsupportedException(feature); |
| } |
| |
| /** |
| * Return the string about the exception line ; e.g.,) |
| * <code>Line 195 in JdbcTablespace.java</code> |
| * |
| * @return A string representing the line number and source file name at which the exception occurs. |
| */ |
| @SuppressWarnings("unused") |
| public static String getExceptionLine() { |
| StackTraceElement stack = Thread.currentThread().getStackTrace()[3]; |
| return "Line " + stack.getLineNumber() + " in " + stack.getFileName(); |
| } |
| |
| /** |
| * Return the string about the exception point; e.g.,) |
| * <code>org.apache.tajo.storage.mysql.JdbcTablespace::createTable</code> |
| * |
| * @return A string representing the class and method names at which the exception occurs. |
| */ |
| public static String getExceptionPoint() { |
| StackTraceElement stack = Thread.currentThread().getStackTrace()[3]; |
| return stack.getClassName() + "::" + stack.getMethodName(); |
| } |
| } |