這里我們從BeeLine.execute講起。
接下來來到BeeLine.dispatch,這里的入參就是sql語句。方法的最后調用了Commands.sql,然后調用到了Commands.execute。
如下圖所示,這里是Commands.execute中的關鍵邏輯。
1.調用BeeLine.createStatement,該方法間接調用了HiveConnection.createStatement。在后面的方法中構建了HiveStatement。
2.調用了Commands.createLogRunnable,在該方法中循環調用HiveStatement.hasMoreLogs。並且將方法HiveStatement.getQueryLog中獲取到的數據使用BeeLine.info輸出到控制台。該方法封裝為Runnable然后返回,后面使用線程封裝並調用。
3.調用HiveStatement.execute,該方法首先調用closeClientOperation與initFlags重置了部分成員變量,以便下一次調用。
4.然后調用Client.ExecuteStatement,獲取返回的operationHandle,並為下一次調用做准備。
5.遍歷調用Client.GetOperationStatus,直到獲取的狀態為CLOSED_STATE或FINISHED_STATE,此時就可以將變量operationComplete置為true,跳出循環。
6.構造結果集HiveQueryResultSet並返回。在構造期間我們需要注意這里會調用到HiveQueryResultSet.retrieveSchema。這里間接調用了Client.GetResultSetMetadata。
7.后面調用了showRemainingLogsIfAny,該方法間接調用到了HiveStatement.getQueryLog,該方法內部就調用了Client.FetchResults。
這里有一個令人疑惑的地方——構造了logThread線程后,調用其start方法,然后調用HiveStatement.execute,接着又調用了線程的interrupt與join方法。這里更多的是在服務端需要跑MR任務時獲取相關的任務狀態。
1.首先調用logThread.start,此時是為了前期對於任務的監聽。在logThread中循環的布爾條件,也就是HiveStatement.isLogBeingGenerated此時一直為true,也就是該線程一直在運行。
2.然后調用了HiveStatement.execute,該方法在執行完Client.ExecuteStatement后調用Client.GetOperationStatus來獲取語句的執行情況,如果語句的執行狀態變更為FINISHED_STATE,則更新上面的變量值HiveStatement.isLogBeingGenerated為false。
3.調用logThread.interrupt,也就是說,將logThread的中斷值置為true。如果logThread此時處於sleep狀態,那么會拋出InterruptedException異常,執行showRemainingLogsIfAny方法繼續調用方法hiveStatement.getQueryLog來獲取job狀態信息。如果logThread不處於休眠狀態,則會等到其下一次休眠時(如果有的話),同樣會來到方法showRemainingLogsIfAny,繼續查詢job的狀態。
4.調用了logThread.join,其入參值為10s,也就是說,如果10s后logThread仍然運行,那么會停止監控。

在BufferedRows的構造方法中就已經將所有的數據取回。這里主要調用了兩個方法——HiveQueryResultSet.next與Row的構造方法。
1.如下圖所示,這里是HiveQueryResultSet.next方法中比較重要的邏輯部分。這里首先調用Client.FetchResults從服務端獲取結果集,然后通過方法RowSetFactory.create構造了ColumnBasedSet(由於我們這里的版本號是HIVE_CLI_SERVICE_PROTOCOL_V7,因此構造的類是ColumnBasedSet,並且在該構造方法中完成了將返回的數據集封裝到類型內成員變量的流程)。另外ColumnBasedSet覆寫了接口Iterable中的iterator方法。用於后面迭代將數據取出。
這里的next方法中的條件判斷保證了只要有數據取回,便會一直返回true,只有從服務端取回的數據為空時,這里的返回結果才為false。

2.Row的構造方法,如下圖所示:
下圖框選出該構造方法中的重點方法——HiveBaseResultSet.getString。這里會將上面方法中對成員變量row賦予的值取出為一行。

這里簡單總結一下,客戶端調用TCLIService.thrift協議中的完成接口流程:
1.OpenSession
2.FetchResults
3.CloseOperation
4.ExecuteStatement
5.GetOperationStatus
6.GetResultSetMetadata
7.FetchResults
8.CloseOperation
9.CloseSession
如果連接已經建立后,這里只會調用上面中的2-8流程。