77import threading
88from typing import List , Union
99
10+ from databricks .sql .thrift_api .TCLIService .ttypes import TOperationState
11+
1012try :
1113 import pyarrow
1214except ImportError :
6466# - 900s attempts-duration lines up w ODBC/JDBC drivers (for cluster startup > 10 mins)
6567_retry_policy = { # (type, default, min, max)
6668 "_retry_delay_min" : (float , 1 , 0.1 , 60 ),
67- "_retry_delay_max" : (float , 60 , 5 , 3600 ),
68- "_retry_stop_after_attempts_count" : (int , 30 , 1 , 60 ),
69+ "_retry_delay_max" : (float , 30 , 5 , 3600 ),
70+ "_retry_stop_after_attempts_count" : (int , 5 , 1 , 60 ),
6971 "_retry_stop_after_attempts_duration" : (float , 900 , 1 , 86400 ),
7072 "_retry_delay_default" : (float , 5 , 1 , 60 ),
7173}
@@ -769,6 +771,63 @@ def _results_message_to_execute_response(self, resp, operation_state):
769771 arrow_schema_bytes = schema_bytes ,
770772 )
771773
774+ def get_execution_result (self , op_handle , cursor ):
775+
776+ assert op_handle is not None
777+
778+ req = ttypes .TFetchResultsReq (
779+ operationHandle = ttypes .TOperationHandle (
780+ op_handle .operationId ,
781+ op_handle .operationType ,
782+ False ,
783+ op_handle .modifiedRowCount ,
784+ ),
785+ maxRows = cursor .arraysize ,
786+ maxBytes = cursor .buffer_size_bytes ,
787+ orientation = ttypes .TFetchOrientation .FETCH_NEXT ,
788+ includeResultSetMetadata = True ,
789+ )
790+
791+ resp = self .make_request (self ._client .FetchResults , req )
792+
793+ t_result_set_metadata_resp = resp .resultSetMetadata
794+
795+ lz4_compressed = t_result_set_metadata_resp .lz4Compressed
796+ is_staging_operation = t_result_set_metadata_resp .isStagingOperation
797+ has_more_rows = resp .hasMoreRows
798+ description = self ._hive_schema_to_description (
799+ t_result_set_metadata_resp .schema
800+ )
801+
802+ schema_bytes = (
803+ t_result_set_metadata_resp .arrowSchema
804+ or self ._hive_schema_to_arrow_schema (t_result_set_metadata_resp .schema )
805+ .serialize ()
806+ .to_pybytes ()
807+ )
808+
809+ queue = ResultSetQueueFactory .build_queue (
810+ row_set_type = resp .resultSetMetadata .resultFormat ,
811+ t_row_set = resp .results ,
812+ arrow_schema_bytes = schema_bytes ,
813+ max_download_threads = self .max_download_threads ,
814+ lz4_compressed = lz4_compressed ,
815+ description = description ,
816+ ssl_options = self ._ssl_options ,
817+ )
818+
819+ return ExecuteResponse (
820+ arrow_queue = queue ,
821+ status = resp .status ,
822+ has_been_closed_server_side = False ,
823+ has_more_rows = has_more_rows ,
824+ lz4_compressed = lz4_compressed ,
825+ is_staging_operation = is_staging_operation ,
826+ command_handle = op_handle ,
827+ description = description ,
828+ arrow_schema_bytes = schema_bytes ,
829+ )
830+
772831 def _wait_until_command_done (self , op_handle , initial_operation_status_resp ):
773832 if initial_operation_status_resp :
774833 self ._check_command_not_in_error_or_closed_state (
@@ -787,6 +846,12 @@ def _wait_until_command_done(self, op_handle, initial_operation_status_resp):
787846 self ._check_command_not_in_error_or_closed_state (op_handle , poll_resp )
788847 return operation_state
789848
849+ def get_query_state (self , op_handle ) -> "TOperationState" :
850+ poll_resp = self ._poll_for_status (op_handle )
851+ operation_state = poll_resp .operationState
852+ self ._check_command_not_in_error_or_closed_state (op_handle , poll_resp )
853+ return operation_state
854+
790855 @staticmethod
791856 def _check_direct_results_for_error (t_spark_direct_results ):
792857 if t_spark_direct_results :
@@ -817,6 +882,7 @@ def execute_command(
817882 cursor ,
818883 use_cloud_fetch = True ,
819884 parameters = [],
885+ async_op = False ,
820886 ):
821887 assert session_handle is not None
822888
@@ -846,7 +912,11 @@ def execute_command(
846912 parameters = parameters ,
847913 )
848914 resp = self .make_request (self ._client .ExecuteStatement , req )
849- return self ._handle_execute_response (resp , cursor )
915+
916+ if async_op :
917+ self ._handle_execute_response_async (resp , cursor )
918+ else :
919+ return self ._handle_execute_response (resp , cursor )
850920
851921 def get_catalogs (self , session_handle , max_rows , max_bytes , cursor ):
852922 assert session_handle is not None
@@ -945,6 +1015,10 @@ def _handle_execute_response(self, resp, cursor):
9451015
9461016 return self ._results_message_to_execute_response (resp , final_operation_state )
9471017
1018+ def _handle_execute_response_async (self , resp , cursor ):
1019+ cursor .active_op_handle = resp .operationHandle
1020+ self ._check_direct_results_for_error (resp .directResults )
1021+
9481022 def fetch_results (
9491023 self ,
9501024 op_handle ,
0 commit comments