Skip to content

Fix statement close behavior for direct results in SEA#1400

Open
gopalldb wants to merge 18 commits intodatabricks:mainfrom
gopalldb:statement-fix-close
Open

Fix statement close behavior for direct results in SEA#1400
gopalldb wants to merge 18 commits intodatabricks:mainfrom
gopalldb:statement-fix-close

Conversation

@gopalldb
Copy link
Copy Markdown
Collaborator

Summary

For direct results in SEA, the server returns CLOSED state with inline results. Previously, markAsClosed() set isClosed=true on the JDBC Statement, preventing re-execution and getResultSet() calls. Per JDBC spec, a Statement should remain open until the user explicitly calls close().

Problem

  • executeQuery() then getResultSet() threw "Statement is closed"
  • Re-executing a Statement/PreparedStatement after direct results threw "Statement is closed"
  • getExecutionResult() (async path) made an RPC that returned "not found" since the server already closed the operation
  • PreparedStatement parameters were lost (couldn't re-execute with new params)

Fix

Replace markAsClosed() with markDirectResultsReceived() which sets a new directResultsReceived flag WITHOUT closing the JDBC Statement:

  • Statement remains open for re-execution after direct results
  • Re-execution implicitly closes the previous ResultSet (per JDBC spec) and resets the flag
  • close() skips server-side closeStatement when directResultsReceived (server already cleaned up)
  • getExecutionResult() returns cached result for direct results instead of an RPC
  • PreparedStatement params stay sticky across re-executions (unchanged, already correct)

Test plan

  • DatabricksStatementTest -- 85 tests pass (3 updated for new behavior)
  • DatabricksSdkClientTest -- 28 tests pass (1 updated for method rename)
  • Full core suite -- 3188 tests, 0 failures

gopalldb and others added 16 commits April 8, 2026 11:49
- Drop Windows from cache warmer matrix — Windows runners in
  databricks-protected-runner-group lack bash (command not found)
- Remove runner.os from cache key — Maven JARs/POMs are platform-
  independent, so one cache entry serves both Linux and Windows
- Cache key is now: maven-deps-{hash(pom.xml)}

Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Co-authored-by: Isaac
Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
For direct results in SEA, the server returns CLOSED state with inline
results. Previously, markAsClosed() set isClosed=true on the JDBC
Statement, preventing re-execution and getResultSet() calls. Per JDBC
spec, a Statement should remain open until the user explicitly closes it.

Changes:
- Replace markAsClosed() with markDirectResultsReceived() which sets a
  new directResultsReceived flag WITHOUT closing the JDBC Statement
- Statement remains open for re-execution after direct results
- Re-execution implicitly closes the previous ResultSet (per JDBC spec)
- close() skips server-side closeStatement when directResultsReceived
  (server already cleaned up the operation handle)
- getExecutionResult() returns cached result for direct results instead
  of making an RPC that would fail with "not found"
- directResultsReceived resets on each new execution

Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Co-authored-by: Isaac
Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Fix corner cases and add missing tests:

1. executeAsync() now resets directResultsReceived and closes previous
   ResultSet before async execution (was missing, causing stale flag)
2. cancel() skips server RPC when directResultsReceived (server already
   closed the operation, cancel would fail with "not found")
3. getExecutionResult() throws clear error when directResultsReceived
   but resultSet is null (defensive, unlikely but possible)
4. Added test: getExecutionResult returns cached result for direct
   results without making an RPC
5. Added test: cancel after direct results is a no-op
6. Added test: re-execution explicitly closes previous ResultSet

Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Co-authored-by: Isaac
Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Thrift also receives direct results when TSparkGetDirectResults is set.
After the server returns inline results, the operation handle is done —
subsequent closeOperation RPCs would fail with "invalid handle".

Changes:
- DatabricksThriftAccessor.execute(): call markDirectResultsReceived()
  when direct results are detected (hasResultDataInDirectResults)
- Safe instanceof check before casting to DatabricksStatement (test
  mocks use java.sql.Statement interface)
- DatabricksStatement: executeAsync resets directResultsReceived and
  closes previous ResultSet; cancel() skips RPC for direct results;
  getExecutionResult() throws clear error if result is null

Note: Thrift executeAsync does NOT request direct results (uses
runAsync=true), so the async path is unaffected.

Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Co-authored-by: Isaac
Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Even with waitTimeout=0s, the server may complete instantly and return
CLOSED state with inline results in executeStatementAsync. Added the
same markDirectResultsReceived guard to the SEA async path so that
getExecutionResult() returns the cached result instead of making
an RPC that fails with "not found".

Also includes the Thrift direct results fix from the previous commit.

Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Co-authored-by: Isaac
Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
@gopalldb gopalldb requested a review from vikrantpuppala April 10, 2026 09:22
Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Co-authored-by: Isaac
Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
SEA async execution (waitTimeout=0s) never returns direct results —
the server always returns PENDING/RUNNING state. Removed the
unnecessary CLOSED state check and markDirectResultsReceived call
from executeStatementAsync in DatabricksSdkClient.

The reset of directResultsReceived in DatabricksStatement.executeAsync()
is still needed to clear a stale flag from a previous sync execution.

Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
Co-authored-by: Isaac
Signed-off-by: Gopal Lal <gopal.lal@databricks.com>
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.

1 participant