11package com .databricks .jdbc .dbclient .impl .thrift ;
22
3- import static com .databricks .jdbc .common .DatabricksJdbcConstants .IS_FAKE_SERVICE_TEST_PROP ;
43import static com .databricks .jdbc .common .EnvironmentVariables .*;
54import static com .databricks .jdbc .common .util .DatabricksThriftUtil .*;
6- import static com .databricks .jdbc .model .client .thrift .generated .TStatusCode .*;
75
86import com .databricks .jdbc .api .IDatabricksConnectionContext ;
97import com .databricks .jdbc .api .IDatabricksSession ;
108import com .databricks .jdbc .api .impl .*;
119import com .databricks .jdbc .api .internal .IDatabricksStatementInternal ;
1210import com .databricks .jdbc .common .StatementType ;
11+ import com .databricks .jdbc .common .util .DriverUtil ;
1312import com .databricks .jdbc .dbclient .impl .common .ClientConfigurator ;
1413import com .databricks .jdbc .dbclient .impl .common .StatementId ;
1514import com .databricks .jdbc .dbclient .impl .http .DatabricksHttpClientFactory ;
@@ -47,9 +46,7 @@ final class DatabricksThriftAccessor {
4746 Map <String , String > authHeaders = databricksConfig .authenticate ();
4847 String endPointUrl = connectionContext .getEndpointURL ();
4948
50- final boolean isFakeServiceTest =
51- Boolean .parseBoolean (System .getProperty (IS_FAKE_SERVICE_TEST_PROP ));
52- if (!isFakeServiceTest ) {
49+ if (!DriverUtil .isRunningAgainstFake ()) {
5350 // Create a new thrift client for each thread as client state is not thread safe. Note that
5451 // the underlying protocol uses the same http client which is thread safe
5552 this .thriftClient =
@@ -127,7 +124,7 @@ TFetchResultsResp getResultSetResp(TOperationHandle operationHandle, String cont
127124 throws DatabricksHttpException {
128125 refreshHeadersIfRequired ();
129126 return getResultSetResp (
130- new TStatus ().setStatusCode (SUCCESS_STATUS ),
127+ new TStatus ().setStatusCode (TStatusCode . SUCCESS_STATUS ),
131128 operationHandle ,
132129 context ,
133130 DEFAULT_ROW_LIMIT ,
@@ -170,7 +167,7 @@ TFetchResultsResp getMoreResults(IDatabricksStatementInternal parentStatement)
170167 parentStatement .getStatementId ().toSQLExecStatementId ());
171168 int maxRows = (parentStatement == null ) ? DEFAULT_ROW_LIMIT : parentStatement .getMaxRows ();
172169 return getResultSetResp (
173- new TStatus ().setStatusCode (SUCCESS_STATUS ),
170+ new TStatus ().setStatusCode (TStatusCode . SUCCESS_STATUS ),
174171 getOperationHandle (parentStatement .getStatementId ()),
175172 context ,
176173 maxRows ,
@@ -213,50 +210,53 @@ private TFetchResultsResp getResultSetResp(
213210 return response ;
214211 }
215212
216- private void longPolling (TOperationHandle operationHandle )
217- throws TException , InterruptedException , DatabricksHttpException {
218- TGetOperationStatusReq request =
219- new TGetOperationStatusReq ()
220- .setOperationHandle (operationHandle )
221- .setGetProgressUpdate (false );
222- TGetOperationStatusResp response ;
223- TStatus status ;
224- do {
225- response = getThriftClient ().GetOperationStatus (request );
226- status = response .getStatus ();
227- if (status .getStatusCode () == TStatusCode .STILL_EXECUTING_STATUS ) {
228- Thread .sleep (DEFAULT_SLEEP_DELAY );
229- }
230- } while (status .getStatusCode () == TStatusCode .STILL_EXECUTING_STATUS );
231- verifySuccessStatus (status , String .format ("Request {%s}, Response {%s}" , request , response ));
232- }
233-
234213 DatabricksResultSet execute (
235214 TExecuteStatementReq request ,
236215 IDatabricksStatementInternal parentStatement ,
237216 IDatabricksSession session ,
238217 StatementType statementType )
239218 throws SQLException {
240219 refreshHeadersIfRequired ();
220+
221+ // Set direct result configuration
241222 int maxRows = (parentStatement == null ) ? DEFAULT_ROW_LIMIT : parentStatement .getMaxRows ();
242223 if (enableDirectResults ) {
243224 TSparkGetDirectResults directResults =
244225 new TSparkGetDirectResults ().setMaxBytes (DEFAULT_BYTE_LIMIT ).setMaxRows (maxRows );
245226 request .setGetDirectResults (directResults );
246227 }
228+
247229 TExecuteStatementResp response ;
248- TFetchResultsResp resultSet = null ;
230+ TFetchResultsResp resultSet ;
231+
249232 try {
250233 response = getThriftClient ().ExecuteStatement (request );
251- if ( Arrays . asList ( ERROR_STATUS , INVALID_HANDLE_STATUS ). contains ( response . status . statusCode )) {
252- throw new DatabricksSQLException ( response . status . errorMessage , response . status . sqlState );
253- }
234+ checkResponseForErrors ( response );
235+
236+ TGetOperationStatusResp statusResp = null ;
254237 if (response .isSetDirectResults ()) {
255238 checkDirectResultsForErrorStatus (response .getDirectResults (), response .toString ());
239+ statusResp = response .getDirectResults ().getOperationStatus ();
240+ checkOperationStatusForErrors (statusResp );
241+ }
242+
243+ // Polling until query operation state is finished
244+ TGetOperationStatusReq statusReq =
245+ new TGetOperationStatusReq ()
246+ .setOperationHandle (response .getOperationHandle ())
247+ .setGetProgressUpdate (false );
248+ while (shouldContinuePolling (statusResp )) {
249+ statusResp = getThriftClient ().GetOperationStatus (statusReq );
250+ checkOperationStatusForErrors (statusResp );
251+ }
252+
253+ if (hasResultDataInDirectResults (response )) {
254+ // The first response has result data
255+ // There is no polling in this case as status was already finished
256256 resultSet = response .getDirectResults ().getResultSet ();
257257 resultSet .setResultSetMetadata (response .getDirectResults ().getResultSetMetadata ());
258258 } else {
259- longPolling ( response . getOperationHandle ());
259+ // Fetch the result data after polling
260260 resultSet =
261261 getResultSetResp (
262262 response .getStatus (),
@@ -265,11 +265,11 @@ DatabricksResultSet execute(
265265 maxRows ,
266266 true );
267267 }
268- } catch (TException | InterruptedException e ) {
268+ } catch (TException e ) {
269269 String errorMessage =
270270 String .format (
271271 "Error while receiving response from Thrift server. Request {%s}, Error {%s}" ,
272- request . toString () , e .getMessage ());
272+ request , e .getMessage ());
273273 LOGGER .error (e , errorMessage );
274274 throw new DatabricksHttpException (errorMessage , e );
275275 }
@@ -288,12 +288,11 @@ DatabricksResultSet executeAsync(
288288 StatementType statementType )
289289 throws SQLException {
290290 refreshHeadersIfRequired ();
291- TExecuteStatementResp response = null ;
292- DatabricksHttpTTransport transport =
293- (DatabricksHttpTTransport ) getThriftClient ().getInputProtocol ().getTransport ();
291+ TExecuteStatementResp response ;
294292 try {
295293 response = getThriftClient ().ExecuteStatement (request );
296- if (Arrays .asList (ERROR_STATUS , INVALID_HANDLE_STATUS ).contains (response .status .statusCode )) {
294+ if (Arrays .asList (TStatusCode .ERROR_STATUS , TStatusCode .INVALID_HANDLE_STATUS )
295+ .contains (response .status .statusCode )) {
297296 LOGGER .error (
298297 "Received error response {%s} from Thrift Server for request {%s}" ,
299298 response , request .toString ());
@@ -335,7 +334,8 @@ DatabricksResultSet getStatementResult(
335334 try {
336335 response = getThriftClient ().GetOperationStatus (request );
337336 statusCode = response .getStatus ().getStatusCode ();
338- if (statusCode == SUCCESS_STATUS || statusCode == SUCCESS_WITH_INFO_STATUS ) {
337+ if (statusCode == TStatusCode .SUCCESS_STATUS
338+ || statusCode == TStatusCode .SUCCESS_WITH_INFO_STATUS ) {
339339 resultSet =
340340 getResultSetResp (response .getStatus (), operationHandle , response .toString (), -1 , true );
341341 }
@@ -512,4 +512,48 @@ private TCLIService.Client createThriftClient(
512512
513513 return new TCLIService .Client (protocol );
514514 }
515+
516+ private void checkResponseForErrors (TExecuteStatementResp response ) throws SQLException {
517+ if (!response .isSetOperationHandle ()) {
518+ throw new DatabricksSQLException ("Operation handle not set" );
519+ }
520+ if (isErrorStatusCode (response .status .statusCode )) {
521+ throw new DatabricksSQLException (
522+ response .status .getErrorMessage (), response .status .getSqlState ());
523+ }
524+ }
525+
526+ private void checkOperationStatusForErrors (TGetOperationStatusResp statusResp )
527+ throws SQLException {
528+ if (statusResp != null
529+ && statusResp .isSetOperationState ()
530+ && isErrorOperationState (statusResp .getOperationState ())) {
531+ throw new DatabricksSQLException ("Operation state erroneous" );
532+ }
533+ }
534+
535+ private boolean shouldContinuePolling (TGetOperationStatusResp statusResp ) {
536+ return statusResp == null
537+ || !statusResp .isSetOperationState ()
538+ || isPendingOperationState (statusResp .getOperationState ());
539+ }
540+
541+ private boolean hasResultDataInDirectResults (TExecuteStatementResp response ) {
542+ return response .isSetDirectResults ()
543+ && response .getDirectResults ().isSetResultSet ()
544+ && response .getDirectResults ().isSetResultSetMetadata ();
545+ }
546+
547+ private boolean isErrorStatusCode (TStatusCode statusCode ) {
548+ return statusCode == TStatusCode .ERROR_STATUS
549+ || statusCode == TStatusCode .INVALID_HANDLE_STATUS ;
550+ }
551+
552+ private boolean isErrorOperationState (TOperationState state ) {
553+ return state == TOperationState .ERROR_STATE || state == TOperationState .CLOSED_STATE ;
554+ }
555+
556+ private boolean isPendingOperationState (TOperationState state ) {
557+ return state == TOperationState .RUNNING_STATE || state == TOperationState .PENDING_STATE ;
558+ }
515559}
0 commit comments