Skip to content

Conversation

@madhav-db
Copy link
Collaborator

@madhav-db madhav-db commented Nov 26, 2025

Description

Close statements based on Execute Statement Response SEA

Flow:

  1. User calls executeQuery
  2. executeInternal in DatabricksStatement is called, and creates direct same thread executor
  3. Runs on same thread, calls getResultFromClient
  4. After execution, server responds with status: CLOSED, we detect the state and call markAsClosed which soft closes the statement (does not shut down the executor)
  5. We return result set to user
  6. User calls statement.close()
  7. DatabricksStatement sees isClosed=true, skips the server close (since it's already closed), closes result set and shuts down the executor.

Testing

Additional Notes to the Reviewer

@madhav-db madhav-db requested a review from gopalldb November 26, 2025 05:07
@gopalldb
Copy link
Collaborator

Description

Close statements based on Execute Statement Response SEA

Testing

Additional Notes to the Reviewer

Add testing section

@madhav-db madhav-db requested a review from gopalldb November 27, 2025 06:38
@madhav-db madhav-db enabled auto-merge (squash) December 3, 2025 10:30
Copilot AI review requested due to automatic review settings December 3, 2025 14:57
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements server-side statement closure detection for Databricks JDBC connections. When the server returns a CLOSED status in the Execute Statement Response, the driver now soft-closes the statement locally without attempting to close it again on the server.

Key changes:

  • Added markAsClosed() method to mark statements as closed when server indicates closure
  • Modified statement close logic to skip server-side close calls for already-closed statements
  • Added detection of CLOSED status in execute statement responses

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
DatabricksStatement.java Added markAsClosed() method and updated close() to handle pre-closed statements
DatabricksSdkClient.java Added detection of CLOSED status in execute responses to trigger markAsClosed()
DatabricksStatementTest.java Added comprehensive test coverage for markAsClosed() scenarios
DatabricksSdkClientTest.java Added tests for execute statement with closed status responses

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if (resultSet != null) {
this.resultSet.close();
this.resultSet = null;
}
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The early return path for isClosed doesn't shut down the executor or remove the statement from session. This creates inconsistent cleanup behavior compared to the normal close path. Consider calling shutdownExecutor() and handling session removal in this branch as well to ensure complete resource cleanup.

Suggested change
}
}
if (removeFromSession) {
this.connection.closeStatement(this);
}
shutDownExecutor();
this.isClosed = true;
return;

Copilot uses AI. Check for mistakes.
Comment on lines +112 to +113
this.resultSet.close();
this.resultSet = null;
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When resultSet.close() throws an exception in the isClosed branch, the exception propagates without setting isClosed flag or logging. The normal close path has better error handling. Consider wrapping this in a try-catch to ensure the statement remains in a consistent state even if result set closure fails.

Suggested change
this.resultSet.close();
this.resultSet = null;
try {
this.resultSet.close();
} catch (Exception e) {
LOGGER.warn("Exception while closing resultSet in already closed statement", e);
warnings = WarningUtil.addWarning(warnings, "Exception while closing resultSet: " + e.getMessage());
} finally {
this.resultSet = null;
this.isClosed = true;
}

Copilot uses AI. Check for mistakes.
Comment on lines +835 to +840
public void markAsClosed() {
LOGGER.debug("Marking statement {} as closed (server already closed)", statementId);
this.connection.closeStatement(this);
DatabricksThreadContextHolder.clearStatementInfo();
this.isClosed = true;
}
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The markAsClosed() method is not synchronized, but it modifies shared state (isClosed) and calls methods that may have concurrency implications. If this method can be called from multiple threads (e.g., during statement execution and timeout handling), it could lead to race conditions. Consider adding synchronization or documenting thread-safety assumptions.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants