Repository navigation
fix(jdbc): close metadata statements through closeStatementOnClose (#119) - #127
Merged
Merged
Conversation
) Metadata result sets used to close their statement only because executeMetadataQuery set closeOnCompletion, which made the closeStatementOnClose flag in LibsqlResultSet dead code. Set the flag at the single result-set construction site instead, and drop the closeOnCompletion call so the close contract no longer depends on it. getColumns now builds its result set through the same statement-backed path, so every metadata result set exposes the statement that produced it and carries the flag. Fixes #119
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Metadata result sets now close their statement through
closeStatementOnCloseinstead of relying oncloseOnCompletion.executeMetadataQueryno longer setscloseOnCompletion. It builds the result set with the flag set and attaches it to the statement.getColumnsuses the same path, so every metadata result set exposes the statement that produced it and releases it when the caller closes the result set.Contract basis. Hrana 3 is the source of truth for transport, values, and metadata,
java.sqlis the source of truth for the JDBC surface, and xerial/sqlite-jdbc is a behavioral reference only. This change is protocol-neutral. Metadata rows still come fromexecuteresponses, and JDBC owns the statement and result-set close contract.Why
#91 closed metadata statements only because
closeOnCompletionauto-closes when the result set closes.LibsqlResultSet.closeStatementOnClosealready existed but no caller set it, so it was dead code. A metadata result set closed without that flag leaks its statement, and onlyMetadataLeakTestwould notice, which exercisesgetTablesalone.#86 is resolved with the JDBC-first contract, so
closeOnCompletionkeeps its JDBC auto-close and is not changed to xerial's track-only behavior. This PR is about explicit statement ownership in the metadata code, not about defending against a #86 change that will not happen. The explicit flag is still the right contract because metadata code should not depend on a flag another class may set.Metadata methods covered
Each method below has its own leak-count case in
LibsqlDatabaseMetaDataTest. Every case asserts that the result set exposes aLibsqlStatement, thatisCloseOnCompletion()is false, and that closing the result set closes the statement.getTables,getColumns,getPrimaryKeys,getTableTypes,getSchemas,getSchemas(catalog, schemaPattern),getCatalogs,getImportedKeys,getExportedKeys,getCrossReference,getTypeInfo,getIndexInfo.LibsqlDatabaseMetaDatanow has one result-set construction site,new LibsqlResultSet(statement, result, originSql, true), and all twelve methods reach it throughexecuteMetadataQuery.Red and green
Red at base
766e4c5with only the new test file applied. Each method fails for the intended reason, eleven onmust not rely on closeOnCompletionandgetColumnsonmust expose the statement that produced it.Green at head
d95594b.Verification
Base
766e4c5, headd95594b4d90b8e41b6c0c449f48ba4f7234ad24a../mvnw -pl libsql-jdbc test -Dtest=LibsqlDatabaseMetaDataTestat base and head./mvnw -pl libsql-conformance -am verify -Dit.test=MetadataLeakTestcloseOnCompletion./mvnw -pl libsql-jdbc test -Dtest='LibsqlDatabaseMetaDataTest#closesStatementWithoutCloseOnCompletion'isCloseOnCompletion()is false and counts return to baseline./mvnw -pl libsql-jdbc test./mvnw -pl libsql-conformance -am verify./mvnw -pl libsql-conformance -am -Pxerial-control verify./mvnw spotless:check./mvnw testgrep -n "new LibsqlResultSet" LibsqlDatabaseMetaData.javacloseOnCompletionreferences./mvnw -pl libsql-jdbc -am package -DskipTests./mvnw -pl libsql-jdbc testthree times per side, interleavedDivergences and scope
No protocol divergence. The protocol has no statement lifecycle field, so JDBC defines it.
The product-version statement in
resolveDatabaseProductVersionstill opens a statement and closes only its result set. The queue plan scopes that fix to #92, so it is not part of this PR and has no leak-count case here.getColumnspreviously built its result set with no statement, sogetStatement()returned null. It now has a statement like the other metadata methods. Its result set still passes a null origin SQL because the column labels are synthesized and must not drive column-origin resolution.Files
libsql-jdbc/src/main/java/com/github/magnusp/libsql/jdbc/LibsqlDatabaseMetaData.java,libsql-jdbc/src/test/java/com/github/magnusp/libsql/jdbc/LibsqlDatabaseMetaDataTest.java.Fixes #119