blob: 65e6b9b29f2d55a24884d0d08069328924ef133e [file] [log] [blame]
/*
* 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();
}
}