Skip to content

refactor(jdbc): extract TableMetadataResolver - #223

Merged
magnusp merged 1 commit into
mainfrom
refactor/i205-table-metadata-resolver
Oct 24, 2026
Merged

magnusp merged 1 commit into
mainfrom
refactor/i205-table-metadata-resolver

Conversation

@magnusp

@magnusp magnusp commented Oct 24, 2026

Copy link
Copy Markdown
Owner

Fixes #205

What moved

Package-private TableMetadataResolver now owns the connection, the SQL, the column count, the lazy resolution state, and the LinkedHashMap table cache. tableForColumn(int) is the single entry point for the three callers (isAutoIncrement, isNullable, getTableName).

  • LibsqlResultSetMetaData.java: 375 → 227 lines (limit: 300).
  • TableMetadataResolver.java: 174 lines.
  • Diff: 2 files changed, 182 insertions(+), 156 deletions(-).

Verbatim move

Normalized diff of the moved region (strip private on moved members, cols.size() → columnCount). The only difference is the entry point's bounds check, which replaces getCol(column) because the resolver holds the column count rather than the Col list:

@@ -1,5 +1,7 @@
     TableInfo tableForColumn(int column) throws SQLException {
-        getCol(column);
+        if (column < 1 || column > columnCount) {
+            throw new SQLException("Invalid column index: " + column + ", must be between 1 and " + columnCount);
+        }
         SqlTableReference.TableRef reference = originTable(column);
         return reference != null ? tableInfo(reference) : null;
     }

Everything else is byte-identical after normalization, including the tableContextResolved / columnOrigins fields, the containsKey / put negative cache, the temp-before-main fallback, both SQL strings (hidden != 1, COLLATE NOCASE), the lowercased cache key with the original-case name returned, and the new ArrayList<>(info.columns().keySet()) list copy in the SqlTableReference.resolve callback. toTableInfo and text moved with their only callers.

The attached-schema and ghost-schema tests in LibsqlResultSetMetaDataTest are unedited and green.

Probe

No repository test models pragma_table_xinfo hidden = 1 columns (virtual-table hidden columns), so the mutation was checked with a scratch FTS5 star-width probe against the pinned sqld (ghcr.io/tursodatabase/libsql-server:v0.24.33), not committed:

  1. Clean: CREATE VIRTUAL TABLE docs USING fts5(title, body), then SELECT * FROM docs → getTableName(1) == "docs" → PASS.
  2. Mutation: deleted AND p.hidden != 1 from the main/temp loadTableInfo(String, String) query → resolver column map width 4 vs protocol star width 2 → getTableName(1) == "" → AssertionError.
  3. Reverted: PASS, and git status --short shows only the two intended files.

The attached-schema query keeps the same predicate and was left intact during the probe.

tableContextResolved vs columnOrigins == null

No existing test distinguishes the two. The observable difference is only that a resolved-null state would re-run resolution on every call instead of once, and no test counts or observes resolution calls. The separate boolean is preserved by inspection.

Lanes

Lane Result
./mvnw -pl libsql-jdbc -am test 392 tests, 0 failures, 0 errors
./mvnw spotless:apply then ./mvnw spotless:check BUILD SUCCESS
./mvnw -pl libsql-conformance -am verify 272 tests, 0 failures, 7 skipped

@magnusp
magnusp merged commit 4f5b191 into main Oct 24, 2026
6 checks passed
@magnusp
magnusp deleted the refactor/i205-table-metadata-resolver branch October 24, 2026 15:32
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.

Extract TableMetadataResolver from LibsqlResultSetMetaData

1 participant