diff --git jdbc/src/java/org/apache/hive/jdbc/Utils.java jdbc/src/java/org/apache/hive/jdbc/Utils.java
index f0834bd..32daa2a 100644
--- jdbc/src/java/org/apache/hive/jdbc/Utils.java
+++ jdbc/src/java/org/apache/hive/jdbc/Utils.java
@@ -25,6 +25,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.hive.service.cli.HiveSQLException;
import org.apache.hive.service.cli.thrift.TStatus;
import org.apache.hive.service.cli.thrift.TStatusCode;
@@ -117,9 +118,8 @@ public static void verifySuccess(TStatus status) throws SQLException {
public static void verifySuccess(TStatus status, boolean withInfo) throws SQLException {
if ((status.getStatusCode() != TStatusCode.SUCCESS_STATUS) &&
(withInfo && (status.getStatusCode() != TStatusCode.SUCCESS_WITH_INFO_STATUS))) {
- throw new SQLException(status.getErrorMessage(),
- status.getSqlState(), status.getErrorCode());
- }
+ throw new HiveSQLException(status);
+ }
}
/**
diff --git ql/src/java/org/apache/hadoop/hive/ql/Driver.java ql/src/java/org/apache/hadoop/hive/ql/Driver.java
index 401e639..12fdfdc 100644
--- ql/src/java/org/apache/hadoop/hive/ql/Driver.java
+++ ql/src/java/org/apache/hadoop/hive/ql/Driver.java
@@ -1,4 +1,3 @@
-
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -952,8 +951,7 @@ public CommandProcessorResponse run(String command, boolean alreadyCompiled)
}
public CommandProcessorResponse compileAndRespond(String command) {
- return new CommandProcessorResponse(compileInternal(command),
- errorMessage, SQLState);
+ return createProcessorResponse(compileInternal(command));
}
private int compileInternal(String command) {
@@ -979,7 +977,7 @@ private CommandProcessorResponse runInternal(String command, boolean alreadyComp
downstreamError = null;
if (!validateConfVariables()) {
- return new CommandProcessorResponse(12, errorMessage, SQLState);
+ return createProcessorResponse(12);
}
HiveDriverRunHookContext hookContext = new HiveDriverRunHookContextImpl(conf, command);
@@ -997,7 +995,7 @@ private CommandProcessorResponse runInternal(String command, boolean alreadyComp
downstreamError = e;
console.printError(errorMessage + "\n"
+ org.apache.hadoop.util.StringUtils.stringifyException(e));
- return new CommandProcessorResponse(12, errorMessage, SQLState);
+ return createProcessorResponse(12);
}
// Reset the perf logger
@@ -1005,7 +1003,6 @@ private CommandProcessorResponse runInternal(String command, boolean alreadyComp
perfLogger.PerfLogBegin(CLASS_NAME, PerfLogger.DRIVER_RUN);
perfLogger.PerfLogBegin(CLASS_NAME, PerfLogger.TIME_TO_SUBMIT);
- int ret;
boolean requireLock = false;
boolean ckLock = false;
try {
@@ -1017,16 +1014,17 @@ private CommandProcessorResponse runInternal(String command, boolean alreadyComp
downstreamError = e;
console.printError(errorMessage, "\n"
+ org.apache.hadoop.util.StringUtils.stringifyException(e));
- ret = 10;
- return new CommandProcessorResponse(ret, errorMessage, SQLState);
+ return createProcessorResponse(10);
+ }
+ int ret = recordValidTxns();
+ if (ret != 0) {
+ return createProcessorResponse(ret);
}
- ret = recordValidTxns();
- if (ret != 0) return new CommandProcessorResponse(ret, errorMessage, SQLState);
if (!alreadyCompiled) {
ret = compileInternal(command);
if (ret != 0) {
- return new CommandProcessorResponse(ret, errorMessage, SQLState);
+ return createProcessorResponse(ret);
}
}
@@ -1068,7 +1066,7 @@ private CommandProcessorResponse runInternal(String command, boolean alreadyComp
} catch (LockException e) {
// Not much to do here
}
- return new CommandProcessorResponse(ret, errorMessage, SQLState);
+ return createProcessorResponse(ret);
}
}
@@ -1080,7 +1078,7 @@ private CommandProcessorResponse runInternal(String command, boolean alreadyComp
} catch (LockException e) {
// Nothing to do here
}
- return new CommandProcessorResponse(ret, errorMessage, SQLState);
+ return createProcessorResponse(ret);
}
//if needRequireLock is false, the release here will do nothing because there is no lock
@@ -1092,7 +1090,7 @@ private CommandProcessorResponse runInternal(String command, boolean alreadyComp
downstreamError = e;
console.printError(errorMessage + "\n"
+ org.apache.hadoop.util.StringUtils.stringifyException(e));
- return new CommandProcessorResponse(12, errorMessage, SQLState);
+ return createProcessorResponse(12);
}
perfLogger.PerfLogEnd(CLASS_NAME, PerfLogger.DRIVER_RUN);
@@ -1109,10 +1107,14 @@ private CommandProcessorResponse runInternal(String command, boolean alreadyComp
downstreamError = e;
console.printError(errorMessage + "\n"
+ org.apache.hadoop.util.StringUtils.stringifyException(e));
- return new CommandProcessorResponse(12, errorMessage, SQLState);
+ return createProcessorResponse(12);
}
- return new CommandProcessorResponse(ret);
+ return createProcessorResponse(ret);
+ }
+
+ private CommandProcessorResponse createProcessorResponse(int ret) {
+ return new CommandProcessorResponse(ret, errorMessage, SQLState, downstreamError);
}
/**
@@ -1431,6 +1433,7 @@ public int execute() throws CommandNeedRetryException {
return (0);
}
+
private void setErrorMsgAndDetail(int exitVal, Throwable downstreamError, Task tsk) {
this.downstreamError = downstreamError;
errorMessage = "FAILED: Execution Error, return code " + exitVal + " from " + tsk.getClass().getName();
diff --git ql/src/java/org/apache/hadoop/hive/ql/processors/CommandProcessorResponse.java ql/src/java/org/apache/hadoop/hive/ql/processors/CommandProcessorResponse.java
index 2eb4438..f29a409 100644
--- ql/src/java/org/apache/hadoop/hive/ql/processors/CommandProcessorResponse.java
+++ ql/src/java/org/apache/hadoop/hive/ql/processors/CommandProcessorResponse.java
@@ -22,7 +22,7 @@
/**
* Encapsulates the basic response info returned by classes the implement the
- * CommandProcessor interfaace. Typically errorMessage
+ * CommandProcessor interface. Typically errorMessage
* and SQLState will only be set if the responseCode
* is not 0.
*/
@@ -32,23 +32,36 @@
private String SQLState;
private Schema resSchema;
+ private Throwable exception;
+
public CommandProcessorResponse(int responseCode) {
- this(responseCode, null, null);
+ this(responseCode, null, null, null, null);
}
public CommandProcessorResponse(int responseCode, String errorMessage, String SQLState) {
- this(responseCode, errorMessage, SQLState, null);
+ this(responseCode, errorMessage, SQLState, null, null);
+ }
+
+ public CommandProcessorResponse(int responseCode, String errorMessage, String SQLState, Throwable exception) {
+ this(responseCode, errorMessage, SQLState, null, exception);
}
public CommandProcessorResponse(int responseCode, String errorMessage, String SQLState, Schema schema) {
+ this(responseCode, errorMessage, SQLState, schema, null);
+ }
+
+ public CommandProcessorResponse(int responseCode, String errorMessage, String SQLState,
+ Schema schema, Throwable exception) {
this.responseCode = responseCode;
this.errorMessage = errorMessage;
this.SQLState = SQLState;
this.resSchema = schema;
+ this.exception = exception;
}
public int getResponseCode() { return responseCode; }
public String getErrorMessage() { return errorMessage; }
public String getSQLState() { return SQLState; }
public Schema getSchema() { return resSchema; }
+ public Throwable getException() { return exception; }
}
diff --git service/src/java/org/apache/hive/service/cli/HiveSQLException.java service/src/java/org/apache/hive/service/cli/HiveSQLException.java
index 8c9496e..c72cba3 100644
--- service/src/java/org/apache/hive/service/cli/HiveSQLException.java
+++ service/src/java/org/apache/hive/service/cli/HiveSQLException.java
@@ -19,6 +19,8 @@
package org.apache.hive.service.cli;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.hive.service.cli.thrift.TStatus;
import org.apache.hive.service.cli.thrift.TStatusCode;
@@ -101,7 +103,10 @@ public HiveSQLException(String reason, String sqlState, int vendorCode, Throwabl
public HiveSQLException(TStatus status) {
// TODO: set correct vendorCode field
- super(status.getErrorMessage(), status.getSqlState(), 1);
+ super(status.getErrorMessage(), status.getSqlState(), status.getErrorCode());
+ if (status.getInfoMessages() != null) {
+ initCause(toCause(status.getInfoMessages()));
+ }
}
public TStatus toTStatus() {
@@ -110,6 +115,7 @@ public TStatus toTStatus() {
tStatus.setSqlState(getSQLState());
tStatus.setErrorCode(getErrorCode());
tStatus.setErrorMessage(getMessage());
+ tStatus.setInfoMessages(toString(this));
return tStatus;
}
@@ -119,7 +125,101 @@ public static TStatus toTStatus(Exception e) {
}
TStatus tStatus = new TStatus(TStatusCode.ERROR_STATUS);
tStatus.setErrorMessage(e.getMessage());
+ tStatus.setInfoMessages(toString(e));
return tStatus;
}
+ public static List toString(Throwable ex) {
+ return toString(ex, null);
+ }
+
+ static List toString(Throwable cause, StackTraceElement[] parent) {
+ StackTraceElement[] trace = cause.getStackTrace();
+ int m = trace.length - 1;
+ if (parent != null) {
+ int n = parent.length - 1;
+ while (m >= 0 && n >= 0 && trace[m].equals(parent[n])) {
+ m--; n--;
+ }
+ }
+ List detail = enroll(cause, trace, m);
+ cause = cause.getCause();
+ if (cause != null) {
+ detail.addAll(toString(cause, trace));
+ }
+ return detail;
+ }
+
+ static List enroll(Throwable ex, StackTraceElement[] trace, int max) {
+ List details = new ArrayList();
+ StringBuilder builder = new StringBuilder();
+ builder.append('*').append(ex.getClass().getName()).append(':');
+ builder.append(ex.getMessage()).append(':');
+ builder.append(trace.length).append(':').append(max);
+ details.add(builder.toString());
+ for (int i = 0; i <= max; i++) {
+ builder.setLength(0);
+ builder.append(trace[i].getClassName()).append(':');
+ builder.append(trace[i].getMethodName()).append(':');
+ String fileName = trace[i].getFileName();
+ builder.append(fileName == null ? "" : fileName).append(':');
+ builder.append(trace[i].getLineNumber());
+ details.add(builder.toString());
+ }
+ return details;
+ }
+
+ public static Throwable toCause(List details) {
+ return toStackTrace(details, null, 0);
+ }
+
+ static Throwable toStackTrace(List details, StackTraceElement[] parent, int index) {
+ String detail = details.get(index++);
+ if (!detail.startsWith("*")) {
+ return null; // should not be happened. ignore remaining
+ }
+ int i1 = detail.indexOf(':');
+ int i3 = detail.lastIndexOf(':');
+ int i2 = detail.substring(0, i3).lastIndexOf(':');
+ String exceptionClass = detail.substring(1, i1);
+ String exceptionMessage = detail.substring(i1 + 1, i2);
+ Throwable ex = newInstance(exceptionClass, exceptionMessage);
+
+ Integer length = Integer.valueOf(detail.substring(i2 + 1, i3));
+ Integer unique = Integer.valueOf(detail.substring(i3 + 1));
+
+ int i = 0;
+ StackTraceElement[] trace = new StackTraceElement[length];
+ for (; i <= unique; i++) {
+ detail = details.get(index++);
+ int j1 = detail.indexOf(':');
+ int j3 = detail.lastIndexOf(':');
+ int j2 = detail.substring(0, j3).lastIndexOf(':');
+ String className = detail.substring(0, j1);
+ String methodName = detail.substring(j1 + 1, j2);
+ String fileName = detail.substring(j2 + 1, j3);
+ if (fileName.isEmpty()) {
+ fileName = null;
+ }
+ int lineNumber = Integer.valueOf(detail.substring(j3 + 1));
+ trace[i] = new StackTraceElement(className, methodName, fileName, lineNumber);
+ }
+ int common = trace.length - i;
+ if (common > 0) {
+ System.arraycopy(parent, parent.length - common, trace, trace.length - common, common);
+ }
+ if (details.size() > index) {
+ ex.initCause(toStackTrace(details, trace, index));
+ }
+ ex.setStackTrace(trace);
+ return ex;
+ }
+
+ private static Throwable newInstance(String className, String message) {
+ try {
+ return (Throwable)Class.forName(className).getConstructor(String.class).newInstance(message);
+ } catch (Exception e) {
+ return new RuntimeException(className + ":" + message);
+ }
+ }
}
diff --git service/src/java/org/apache/hive/service/cli/operation/HiveCommandOperation.java service/src/java/org/apache/hive/service/cli/operation/HiveCommandOperation.java
index f708650..85a0f9e 100644
--- service/src/java/org/apache/hive/service/cli/operation/HiveCommandOperation.java
+++ service/src/java/org/apache/hive/service/cli/operation/HiveCommandOperation.java
@@ -109,8 +109,7 @@ public void run() throws HiveSQLException {
response = commandProcessor.run(commandArgs);
int returnCode = response.getResponseCode();
if (returnCode != 0) {
- throw new HiveSQLException("Error while processing statement: "
- + response.getErrorMessage(), response.getSQLState(), response.getResponseCode());
+ throw toSQLException("Error while processing statement", response);
}
Schema schema = response.getSchema();
if (schema != null) {
diff --git service/src/java/org/apache/hive/service/cli/operation/Operation.java service/src/java/org/apache/hive/service/cli/operation/Operation.java
index d6651ba..45fbd61 100644
--- service/src/java/org/apache/hive/service/cli/operation/Operation.java
+++ service/src/java/org/apache/hive/service/cli/operation/Operation.java
@@ -23,6 +23,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.ql.processors.CommandProcessorResponse;
import org.apache.hive.service.cli.FetchOrientation;
import org.apache.hive.service.cli.HiveSQLException;
import org.apache.hive.service.cli.OperationHandle;
@@ -178,4 +179,13 @@ protected void validateFetchOrientation(FetchOrientation orientation,
" is not supported for this resultset", "HY106");
}
}
+
+ protected HiveSQLException toSQLException(String prefix, CommandProcessorResponse response) {
+ HiveSQLException ex = new HiveSQLException(prefix + ": " + response.getErrorMessage(),
+ response.getSQLState(), response.getResponseCode());
+ if (response.getException() != null) {
+ ex.initCause(response.getException());
+ }
+ return ex;
+ }
}
diff --git service/src/java/org/apache/hive/service/cli/operation/SQLOperation.java service/src/java/org/apache/hive/service/cli/operation/SQLOperation.java
index 5e7ee93..de54ca1 100644
--- service/src/java/org/apache/hive/service/cli/operation/SQLOperation.java
+++ service/src/java/org/apache/hive/service/cli/operation/SQLOperation.java
@@ -98,8 +98,7 @@ public void prepare(HiveConf sqlOperationConf) throws HiveSQLException {
String subStatement = new VariableSubstitution().substitute(sqlOperationConf, statement);
response = driver.compileAndRespond(subStatement);
if (0 != response.getResponseCode()) {
- throw new HiveSQLException("Error while compiling statement: "
- + response.getErrorMessage(), response.getSQLState(), response.getResponseCode());
+ throw toSQLException("Error while compiling statement", response);
}
mResultSchema = driver.getSchema();
@@ -143,8 +142,7 @@ private void runInternal(HiveConf sqlOperationConf) throws HiveSQLException {
driver.setTryCount(Integer.MAX_VALUE);
response = driver.run();
if (0 != response.getResponseCode()) {
- throw new HiveSQLException("Error while processing statement: "
- + response.getErrorMessage(), response.getSQLState(), response.getResponseCode());
+ throw toSQLException("Error while processing statement", response);
}
} catch (HiveSQLException e) {
// If the operation was cancelled by another thread,
diff --git service/src/test/org/apache/hive/service/cli/TestHiveSQLException.java service/src/test/org/apache/hive/service/cli/TestHiveSQLException.java
new file mode 100644
index 0000000..586f595
--- /dev/null
+++ service/src/test/org/apache/hive/service/cli/TestHiveSQLException.java
@@ -0,0 +1,44 @@
+/**
+ * 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.hive.service.cli;
+
+import junit.framework.Assert;
+import org.junit.Test;
+
+public class TestHiveSQLException {
+
+ @Test
+ public void testExceptionMarshalling() throws Exception {
+ Exception ex1 = ex1();
+ ex1.initCause(ex2());
+ Throwable ex = HiveSQLException.toCause(HiveSQLException.toString(ex1));
+ Assert.assertSame(RuntimeException.class, ex.getClass());
+ Assert.assertEquals("exception1", ex.getMessage());
+ Assert.assertSame(UnsupportedOperationException.class, ex.getCause().getClass());
+ Assert.assertEquals("exception2", ex.getCause().getMessage());
+ }
+
+ private static Exception ex1() {
+ return new RuntimeException("exception1");
+ }
+
+ private static Exception ex2() {
+ return new UnsupportedOperationException("exception2");
+ }
+}