Repository: drill Updated Branches: refs/heads/master 31e51832d -> 3ba374a53
DRILL-2932: Fix: Error reported via System.out rather than exception message Main: - Removed the System.out.println(...) from submissionFailed(...). - Put UserException's message text in SQLException's message (didn't just wrap). - Added undoing of extra wrapping by AvaticaStatement.execute...(...). - Created unit test for execute...(...) exceptions. - Refined related exception handling (handled cases separately, narrowed throws declarations and catches). JDBC cleanup: - Renamed ex -> executionFailureException - Added getNext() method doc. comment. - Removed some obsolete alignment spaces. Added "review this" TODOs re DRILL-2933 (probably-obsolete SchemaChangeException): - DrillCursor; - MergingRecordBatch, ParquetResultListener, PrintingResultsListener, QueryWrapper, RecordBatchLoader, UnorderedReceiverBatch; - TestDrillbitResilience, TestTextColumn, BaseTestQuery, DrillTestWrapper. Project: http://git-wip-us.apache.org/repos/asf/drill/repo Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/c4d864d7 Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/c4d864d7 Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/c4d864d7 Branch: refs/heads/master Commit: c4d864d7c84dbb1fb9e2cff8da0bdf9899a0720b Parents: 31e5183 Author: dbarclay <dbarc...@maprtech.com> Authored: Thu Apr 30 23:34:03 2015 -0700 Committer: Parth Chandra <par...@apache.org> Committed: Wed May 6 21:41:19 2015 -0700 ---------------------------------------------------------------------- .../exec/client/PrintingResultsListener.java | 2 + .../impl/mergereceiver/MergingRecordBatch.java | 6 + .../UnorderedReceiverBatch.java | 2 + .../drill/exec/record/RecordBatchLoader.java | 5 +- .../drill/exec/rpc/user/QueryResultHandler.java | 2 +- .../drill/exec/server/rest/QueryWrapper.java | 2 + .../java/org/apache/drill/BaseTestQuery.java | 2 + .../java/org/apache/drill/DrillTestWrapper.java | 4 + .../exec/server/TestDrillbitResilience.java | 2 + .../store/parquet/ParquetResultListener.java | 2 + .../drill/exec/store/text/TestTextColumn.java | 2 + .../java/org/apache/drill/jdbc/DrillCursor.java | 36 +++- .../org/apache/drill/jdbc/DrillStatement.java | 38 +++- .../drill/jdbc/impl/DrillResultSetImpl.java | 23 ++- .../test/TestExecutionExceptionsToClient.java | 186 +++++++++++++++++++ 15 files changed, 295 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java b/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java index 64e7266..875160b 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/client/PrintingResultsListener.java @@ -76,6 +76,8 @@ public class PrintingResultsListener implements UserResultsListener { count.addAndGet(header.getRowCount()); try { loader.load(header.getDef(), data); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean catch clause below. } catch (SchemaChangeException e) { submissionFailed(UserException.systemError(e).build()); } http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/mergereceiver/MergingRecordBatch.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/mergereceiver/MergingRecordBatch.java b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/mergereceiver/MergingRecordBatch.java index c36b0d3..ce683cb 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/mergereceiver/MergingRecordBatch.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/mergereceiver/MergingRecordBatch.java @@ -243,6 +243,8 @@ public class MergingRecordBatch extends AbstractRecordBatch<MergingReceiverPOP> final UserBitShared.RecordBatchDef rbd = batch.getHeader().getDef(); try { batchLoaders[i].load(rbd, batch.getBody()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean catch clause below. } catch(final SchemaChangeException e) { logger.error("MergingReceiver failed to load record batch from remote host. {}", e); context.fail(e); @@ -313,6 +315,8 @@ public class MergingRecordBatch extends AbstractRecordBatch<MergingReceiverPOP> incomingBatches[b] = batch; if (batch != null) { batchLoaders[b].load(batch.getHeader().getDef(), batch.getBody()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean catch clause below. } else { batchLoaders[b].clear(); batchLoaders[b] = null; @@ -399,6 +403,8 @@ public class MergingRecordBatch extends AbstractRecordBatch<MergingReceiverPOP> final UserBitShared.RecordBatchDef rbd = incomingBatches[node.batchId].getHeader().getDef(); try { batchLoaders[node.batchId].load(rbd, incomingBatches[node.batchId].getBody()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean catch clause below. } catch(final SchemaChangeException ex) { context.fail(ex); return IterOutcome.STOP; http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/unorderedreceiver/UnorderedReceiverBatch.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/unorderedreceiver/UnorderedReceiverBatch.java b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/unorderedreceiver/UnorderedReceiverBatch.java index 09cb7ad..c9d9c11 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/unorderedreceiver/UnorderedReceiverBatch.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/physical/impl/unorderedreceiver/UnorderedReceiverBatch.java @@ -169,6 +169,8 @@ public class UnorderedReceiverBatch implements CloseableRecordBatch { final RecordBatchDef rbd = batch.getHeader().getDef(); final boolean schemaChanged = batchLoader.load(rbd, batch.getBody()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean catch clause below. stats.addLongStat(Metric.BYTES_RECEIVED, batch.getByteCount()); batch.release(); http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/main/java/org/apache/drill/exec/record/RecordBatchLoader.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/record/RecordBatchLoader.java b/exec/java-exec/src/main/java/org/apache/drill/exec/record/RecordBatchLoader.java index 088630c..1b8b7ce 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/record/RecordBatchLoader.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/record/RecordBatchLoader.java @@ -54,9 +54,10 @@ public class RecordBatchLoader implements VectorAccessible, Iterable<VectorWrapp * @param def * The definition for the record batch. * @param buf - * The buffer that holds the data associated with the record batch - * @return Whether or not the schema changed since the previous load. + * The buffer that holds the data associated with the record batch. + * @return Whether the schema changed since the previous load. * @throws SchemaChangeException + * TODO: Clean: DRILL-2933 load(...) never actually throws SchemaChangeException. */ public boolean load(RecordBatchDef def, DrillBuf buf) throws SchemaChangeException { // logger.debug("Loading record batch with def {} and data {}", def, buf); http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java index 3beae89..5e3e937 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/rpc/user/QueryResultHandler.java @@ -81,7 +81,7 @@ public class QueryResultHandler { assert queryResult.hasQueryState() : "received query result without QueryState"; - final boolean isFailureResult = QueryState.FAILED == queryState; + final boolean isFailureResult = QueryState.FAILED == queryState; // CANCELED queries are handled the same way as COMPLETED final boolean isTerminalResult; switch ( queryState ) { http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java index aa43aa9..4629dd0 100644 --- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java +++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/QueryWrapper.java @@ -148,6 +148,8 @@ public class QueryWrapper { if (result.hasData()) { final RecordBatchLoader loader = new RecordBatchLoader(allocator); loader.load(result.getHeader().getDef(), result.getData()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean catch clause below. for (int i = 0; i < loader.getSchema().getFieldCount(); ++i) { columns.add(loader.getSchema().getColumn(i).getPath().getAsUnescapedPath()); } http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java b/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java index d6e6d08..200bbc6 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java +++ b/exec/java-exec/src/test/java/org/apache/drill/BaseTestQuery.java @@ -423,6 +423,8 @@ public class BaseTestQuery extends ExecTest { for(QueryDataBatch result : results) { rowCount += result.getHeader().getRowCount(); loader.load(result.getHeader().getDef(), result.getData()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean throw clause above. if (loader.getRecordCount() <= 0) { continue; } http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/test/java/org/apache/drill/DrillTestWrapper.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/DrillTestWrapper.java b/exec/java-exec/src/test/java/org/apache/drill/DrillTestWrapper.java index 856dfa5..d4e7ed6 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/DrillTestWrapper.java +++ b/exec/java-exec/src/test/java/org/apache/drill/DrillTestWrapper.java @@ -225,6 +225,8 @@ public class DrillTestWrapper { for (int i = 0; i < size; i++) { batch = records.get(0); loader.load(batch.getHeader().getDef(), batch.getData()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean throws clause above. if (schema == null) { schema = loader.getSchema(); for (MaterializedField mf : schema) { @@ -410,6 +412,8 @@ public class DrillTestWrapper { for (int i = 0; i < size; i++) { batch = records.get(0); loader.load(batch.getHeader().getDef(), batch.getData()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean throws clause above. if (schema == null) { schema = loader.getSchema(); } http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/test/java/org/apache/drill/exec/server/TestDrillbitResilience.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/server/TestDrillbitResilience.java b/exec/java-exec/src/test/java/org/apache/drill/exec/server/TestDrillbitResilience.java index 2698701..da69e9e 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/server/TestDrillbitResilience.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/server/TestDrillbitResilience.java @@ -208,6 +208,8 @@ public class TestDrillbitResilience { final QueryData queryData = queryResultBatch.getHeader(); try { loader.load(queryData.getDef(), queryResultBatch.getData()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean catch clause below. } catch (final SchemaChangeException e) { fail(e.toString()); } http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/test/java/org/apache/drill/exec/store/parquet/ParquetResultListener.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/store/parquet/ParquetResultListener.java b/exec/java-exec/src/test/java/org/apache/drill/exec/store/parquet/ParquetResultListener.java index 0e80f91..6326478 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/store/parquet/ParquetResultListener.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/store/parquet/ParquetResultListener.java @@ -109,6 +109,8 @@ public class ParquetResultListener implements UserResultsListener { RecordBatchLoader batchLoader = new RecordBatchLoader(allocator); try { schemaChanged = batchLoader.load(result.getHeader().getDef(), result.getData()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean catch clause below. } catch (SchemaChangeException e) { throw new RuntimeException(e); } http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/java-exec/src/test/java/org/apache/drill/exec/store/text/TestTextColumn.java ---------------------------------------------------------------------- diff --git a/exec/java-exec/src/test/java/org/apache/drill/exec/store/text/TestTextColumn.java b/exec/java-exec/src/test/java/org/apache/drill/exec/store/text/TestTextColumn.java index 3c1a38a..f07cf3b 100644 --- a/exec/java-exec/src/test/java/org/apache/drill/exec/store/text/TestTextColumn.java +++ b/exec/java-exec/src/test/java/org/apache/drill/exec/store/text/TestTextColumn.java @@ -75,6 +75,8 @@ public class TestTextColumn extends BaseTestQuery{ int rows = batch.getHeader().getRowCount(); if(batch.getData() != null) { loader.load(batch.getHeader().getDef(), batch.getData()); + // TODO: Clean: DRILL-2933: That load(...) no longer throws + // SchemaChangeException, so check/clean throws clause above. for (int i = 0; i < rows; ++i) { output.add(new ArrayList<String>()); for (VectorWrapper<?> vw: loader) { http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillCursor.java ---------------------------------------------------------------------- diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillCursor.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillCursor.java index 6bad3ce..30c85eb 100644 --- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillCursor.java +++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillCursor.java @@ -25,6 +25,9 @@ import net.hydromatic.avatica.ArrayImpl.Factory; import net.hydromatic.avatica.ColumnMetaData; import net.hydromatic.avatica.Cursor; +import org.apache.drill.common.exceptions.DrillRuntimeException; +import org.apache.drill.common.exceptions.UserException; +import org.apache.drill.exec.exception.SchemaChangeException; import org.apache.drill.exec.record.BatchSchema; import org.apache.drill.exec.record.RecordBatchLoader; import org.apache.drill.exec.rpc.user.QueryDataBatch; @@ -132,8 +135,13 @@ public class DrillCursor implements Cursor { return false; } else { currentRecordNumber = 0; - boolean changed = currentBatch.load(qrb.getHeader().getDef(), qrb.getData()); - qrb.release(); + final boolean changed; + try { + changed = currentBatch.load(qrb.getHeader().getDef(), qrb.getData()); + } + finally { + qrb.release(); + } schema = currentBatch.getSchema(); if (changed) { updateColumns(); @@ -143,8 +151,28 @@ public class DrillCursor implements Cursor { } return true; } - } catch (Exception e) { - throw new SQLException("Failure while executing query.", e); + } + catch ( UserException e ) { + // A normally expected case--for any server-side error (e.g., syntax + // error in SQL statement). + // Contruct SQLException with message text from the UserException. + // TODO: Map UserException error type to SQLException subclass (once + // error type is accessible, of course. :-( ) + throw new SQLException( e.getMessage(), e ); + } + catch ( InterruptedException e ) { + // Not normally expected--Drill doesn't interrupt in this area (right?)-- + // but JDBC client certainly could. + throw new SQLException( "Interrupted.", e ); + } + catch ( SchemaChangeException e ) { + // TODO: Clean: DRILL-2933: RecordBatchLoader.load(...) no longer + // throws SchemaChangeException, so check/clean catch clause. + throw new SQLException( + "Unexpected SchemaChangeException from RecordBatchLoader.load(...)" ); + } + catch ( RuntimeException e ) { + throw new SQLException( "Unexpected exception: " + e.toString(), e ); } } http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillStatement.java ---------------------------------------------------------------------- diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillStatement.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillStatement.java index 7fc79be..a609bb1 100644 --- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillStatement.java +++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/DrillStatement.java @@ -47,23 +47,53 @@ public abstract class DrillStatement extends AvaticaStatement return (DrillConnectionImpl) connection; } + // WORKAROUND: Work around AvaticaStatement's code that wraps _any_ exception, + // even if SQLException, by unwrapping to get cause exception so caller can + // throw it directly if it's a SQLException: + // TODO: Any ideas for a better name? + private SQLException unwrapIfExtra( final SQLException superMethodException ) { + final SQLException result; + final Throwable cause = superMethodException.getCause(); + if ( null != cause && cause instanceof SQLException ) { + result = (SQLException) cause; + } + else { + result = superMethodException; + } + return result; + } @Override public boolean execute( String sql ) throws SQLException { checkNotClosed(); - return super.execute( sql ); + try { + return super.execute( sql ); + } + catch ( final SQLException possiblyExtraWrapperException ) { + throw unwrapIfExtra( possiblyExtraWrapperException ); + } } @Override public ResultSet executeQuery( String sql ) throws SQLException { - checkNotClosed(); - return super.executeQuery( sql ); + try { + checkNotClosed(); + return super.executeQuery( sql ); + } + catch ( final SQLException possiblyExtraWrapperException ) { + throw unwrapIfExtra( possiblyExtraWrapperException ); + } } @Override public int executeUpdate( String sql ) throws SQLException { checkNotClosed(); - return super.executeUpdate( sql ); + try { + return super.executeUpdate( sql ); + } + catch ( final SQLException possiblyExtraWrapperException ) { + throw unwrapIfExtra( possiblyExtraWrapperException ); + } } @Override http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java ---------------------------------------------------------------------- diff --git a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java index a7cc0c1..8ef2af3 100644 --- a/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java +++ b/exec/jdbc/src/main/java/org/apache/drill/jdbc/impl/DrillResultSetImpl.java @@ -155,12 +155,12 @@ public class DrillResultSetImpl extends AvaticaResultSet implements DrillResultS // TODO: Revisit: Why reaching directly into ResultsListener rather than // calling some wait method? resultsListener.latch.await(); - cursor.next(); - } catch (InterruptedException e) { - // TODO: Check: Should this call Thread.currentThread.interrupt()? If - // not, at least document why this is empty. - // TODO: Check: Does anything ever interrupt this? (Is catch needed?) + } catch ( InterruptedException e ) { + // Not normally expected--Drill doesn't interrupt in this area (right?)-- + // but JDBC client certainly could. + throw new SQLException( "Interrupted", e ); } + cursor.next(); return this; } @@ -181,7 +181,6 @@ public class DrillResultSetImpl extends AvaticaResultSet implements DrillResultS private volatile QueryId queryId; - private volatile UserException executionFailureException; volatile boolean completed = false; private volatile boolean autoread = true; @@ -259,8 +258,16 @@ public class DrillResultSetImpl extends AvaticaResultSet implements DrillResultS } - // TODO: Doc.: Specify whether result can be null and what that means. - public QueryDataBatch getNext() throws Exception { + /** + * Gets the next batch of query results from the queue. + * @return the next batch, or {@code null} after last batch has been returned + * @throws UserException + * if the query failed + * @throws InterruptedException + * if waiting on the queue was interrupted + */ + public QueryDataBatch getNext() throws UserException, + InterruptedException { while (true) { if (executionFailureException != null) { logger.debug( "Dequeued query failure exception: {}.", executionFailureException ); http://git-wip-us.apache.org/repos/asf/drill/blob/c4d864d7/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/TestExecutionExceptionsToClient.java ---------------------------------------------------------------------- diff --git a/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/TestExecutionExceptionsToClient.java b/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/TestExecutionExceptionsToClient.java new file mode 100644 index 0000000..d845a38 --- /dev/null +++ b/exec/jdbc/src/test/java/org/apache/drill/jdbc/test/TestExecutionExceptionsToClient.java @@ -0,0 +1,186 @@ +/** + * 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.drill.jdbc.test; + +import static org.junit.Assert.fail; +import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.*; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.apache.drill.common.exceptions.UserException; +import org.apache.drill.common.exceptions.UserRemoteException; +import org.apache.drill.jdbc.Driver; +import org.apache.drill.jdbc.JdbcTestBase; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + + +public class TestExecutionExceptionsToClient extends JdbcTestBase { + + private static Connection connection; + + @BeforeClass + public static void setUpConnection() throws Exception { + connection = new Driver().connect( "jdbc:drill:zk=local", null ); + } + + @AfterClass + public static void tearDownConnection() throws SQLException { + connection.close(); + } + + @Test + public void testExecuteQueryThrowsRight1() throws Exception { + final Statement statement = connection.createStatement(); + try { + statement.executeQuery( "SELECT one case of syntax error" ); + } + catch ( SQLException e ) { + assertThat( "Null getCause(); missing expected wrapped exception", + e.getCause(), notNullValue() ); + + assertThat( "Unexpectedly wrapped another SQLException", + e.getCause(), not( instanceOf( SQLException.class ) ) ); + + assertThat( "getCause() not UserRemoteException as expected", + e.getCause(), instanceOf( UserRemoteException.class ) ); + + assertThat( "No expected current \"SYSTEM ERROR\"/eventual \"PARSE ERROR\"", + e.getMessage(), anyOf( startsWith( "SYSTEM ERROR" ), + startsWith( "PARSE ERROR" ) ) ); + } + } + + @Test + public void testExecuteThrowsRight1() throws Exception { + final Statement statement = connection.createStatement(); + try { + statement.execute( "SELECT one case of syntax error" ); + } + catch ( SQLException e ) { + assertThat( "Null getCause(); missing expected wrapped exception", + e.getCause(), notNullValue() ); + + assertThat( "Unexpectedly wrapped another SQLException", + e.getCause(), not( instanceOf( SQLException.class ) ) ); + + assertThat( "getCause() not UserRemoteException as expected", + e.getCause(), instanceOf( UserRemoteException.class ) ); + + assertThat( "No expected current \"SYSTEM ERROR\"/eventual \"PARSE ERROR\"", + e.getMessage(), anyOf( startsWith( "SYSTEM ERROR" ), + startsWith( "PARSE ERROR" ) ) ); + } + } + + @Test + public void testExecuteUpdateThrowsRight1() throws Exception { + final Statement statement = connection.createStatement(); + try { + statement.executeUpdate( "SELECT one case of syntax error" ); + } + catch ( SQLException e ) { + assertThat( "Null getCause(); missing expected wrapped exception", + e.getCause(), notNullValue() ); + + assertThat( "Unexpectedly wrapped another SQLException", + e.getCause(), not( instanceOf( SQLException.class ) ) ); + + assertThat( "getCause() not UserRemoteException as expected", + e.getCause(), instanceOf( UserRemoteException.class ) ); + + assertThat( "No expected current \"SYSTEM ERROR\"/eventual \"PARSE ERROR\"", + e.getMessage(), anyOf( startsWith( "SYSTEM ERROR" ), + startsWith( "PARSE ERROR" ) ) ); + } + } + + @Test + public void testExecuteQueryThrowsRight2() throws Exception { + final Statement statement = connection.createStatement(); + try { + statement.executeQuery( "BAD QUERY 1" ); + } + catch ( SQLException e ) { + assertThat( "Null getCause(); missing expected wrapped exception", + e.getCause(), notNullValue() ); + + assertThat( "Unexpectedly wrapped another SQLException", + e.getCause(), not( instanceOf( SQLException.class ) ) ); + + assertThat( "getCause() not UserRemoteException as expected", + e.getCause(), instanceOf( UserRemoteException.class ) ); + + assertThat( "No expected current \"SYSTEM ERROR\"/eventual \"PARSE ERROR\"", + e.getMessage(), anyOf( startsWith( "SYSTEM ERROR" ), + startsWith( "PARSE ERROR" ) ) ); + } + } + + @Test + public void testExecuteThrowsRight2() throws Exception { + final Statement statement = connection.createStatement(); + try { + statement.execute( "worse query 2" ); + } + catch ( SQLException e ) { + assertThat( "Null getCause(); missing expected wrapped exception", + e.getCause(), notNullValue() ); + + assertThat( "Unexpectedly wrapped another SQLException", + e.getCause(), not( instanceOf( SQLException.class ) ) ); + + assertThat( "getCause() not UserRemoteException as expected", + e.getCause(), instanceOf( UserRemoteException.class ) ); + + assertThat( "No expected current \"SYSTEM ERROR\"/eventual \"PARSE ERROR\"", + e.getMessage(), anyOf( startsWith( "SYSTEM ERROR" ), + startsWith( "PARSE ERROR" ) ) ); + } + } + + @Test + public void testExecuteUpdateThrowsRight2() throws Exception { + final Statement statement = connection.createStatement(); + try { + statement.executeUpdate( "naughty, naughty query 3" ); + } + catch ( SQLException e ) { + assertThat( "Null getCause(); missing expected wrapped exception", + e.getCause(), notNullValue() ); + + assertThat( "Unexpectedly wrapped another SQLException", + e.getCause(), not( instanceOf( SQLException.class ) ) ); + + assertThat( "getCause() not UserRemoteException as expected", + e.getCause(), instanceOf( UserRemoteException.class ) ); + + assertThat( "No expected current \"SYSTEM ERROR\"/eventual \"PARSE ERROR\"", + e.getMessage(), anyOf( startsWith( "SYSTEM ERROR" ), + startsWith( "PARSE ERROR" ) ) ); + } + } + +}