diff --git a/jdbc/src/java/org/apache/hive/jdbc/HiveStatement.java b/jdbc/src/java/org/apache/hive/jdbc/HiveStatement.java index 2912ece..4429605 100644 --- a/jdbc/src/java/org/apache/hive/jdbc/HiveStatement.java +++ b/jdbc/src/java/org/apache/hive/jdbc/HiveStatement.java @@ -181,7 +181,6 @@ public void closeOnCompletion() throws SQLException { * * @see java.sql.Statement#execute(java.lang.String) */ - public boolean execute(String sql) throws SQLException { if (isClosed) { throw new SQLException("Can't execute after statement has been closed"); @@ -193,9 +192,16 @@ public boolean execute(String sql) throws SQLException { } TExecuteStatementReq execReq = new TExecuteStatementReq(sessHandle, sql); + // Run asynchronously whenever possible + // Currently, only a SQLOperation can be run asynchronously in a background operation thread + // Compilation is synchronous and execution is asynchronous + execReq.setRunAsync(true); execReq.setConfOverlay(sessConf); TExecuteStatementResp execResp = client.ExecuteStatement(execReq); Utils.verifySuccessWithInfo(execResp.getStatus()); + // hasResultSet is determined from the query plan + // Since compilation is synchronous, hasResultSet is set to a valid value + // when the stmtHandle is returned first stmtHandle = execResp.getOperationHandle(); } catch (SQLException eS) { throw eS; @@ -203,47 +209,52 @@ public boolean execute(String sql) throws SQLException { throw new SQLException(ex.toString(), "08S01", ex); } - if (!stmtHandle.isHasResultSet()) { - // Poll until the query has completed one way or another. DML queries will not return a result - // set, but we should not return from this method until the query has completed to avoid - // racing with possible subsequent session shutdown, or queries that depend on the results - // materialised here. - TGetOperationStatusReq statusReq = new TGetOperationStatusReq(stmtHandle); - boolean requestComplete = false; - while (!requestComplete) { - try { - TGetOperationStatusResp statusResp = client.GetOperationStatus(statusReq); - Utils.verifySuccessWithInfo(statusResp.getStatus()); - if (statusResp.isSetOperationState()) { - switch (statusResp.getOperationState()) { - case CLOSED_STATE: - case FINISHED_STATE: - return false; - case CANCELED_STATE: - // 01000 -> warning - throw new SQLException("Query was cancelled", "01000"); - case ERROR_STATE: - // HY000 -> general error - throw new SQLException("Query failed", "HY000"); - case UKNOWN_STATE: - throw new SQLException("Unknown query", "HY000"); - case INITIALIZED_STATE: - case RUNNING_STATE: - break; - } + // Get operation status + TGetOperationStatusReq statusReq = new TGetOperationStatusReq(stmtHandle); + boolean operationComplete = false; + TGetOperationStatusResp statusResp; + // Poll on the operation status, till the operation is complete + while (!operationComplete) { + try { + // For an async SQLOperation, GetOperationStatus will use the long polling approach + // It will essentially return after the HIVE_SERVER2_LONG_POLLING_TIMEOUT (a server config) expires + // Check SQLOperation#getState for details + statusResp = client.GetOperationStatus(statusReq); + Utils.verifySuccessWithInfo(statusResp.getStatus()); + if (statusResp.isSetOperationState()) { + switch (statusResp.getOperationState()) { + case CLOSED_STATE: + operationComplete = true; + break; + case FINISHED_STATE: + operationComplete = true; + break; + case CANCELED_STATE: + // 01000 -> warning + throw new SQLException("Query was cancelled", "01000"); + case ERROR_STATE: + // HY000 -> general error + throw new SQLException("Query failed", "HY000"); + case UKNOWN_STATE: + throw new SQLException("Unknown query", "HY000"); + case INITIALIZED_STATE: + break; + case PENDING_STATE: + break; + case RUNNING_STATE: + break; } - } catch (Exception ex) { - throw new SQLException(ex.toString(), "08S01", ex); - } - - try { - Thread.sleep(100); - } catch (InterruptedException ex) { - // Ignore } + } catch (Exception ex) { + throw new SQLException(ex.toString(), "08S01", ex); } + } + + // The query should be completed by now + if (!stmtHandle.isHasResultSet()) { return false; } + resultSet = new HiveQueryResultSet.Builder().setClient(client).setSessionHandle(sessHandle) .setStmtHandle(stmtHandle).setHiveStatement(this).setMaxRows(maxRows).setFetchSize(fetchSize) .build();