Skip to content

fix: Apply six confirmed fixes from the open-issue code review - #880

Merged
jeffjensen merged 8 commits into
mainfrom
jj-apply-issue-codes-fixes
Aug 2, 2026
Merged

fix: Apply six confirmed fixes from the open-issue code review#880
jeffjensen merged 8 commits into
mainfrom
jj-apply-issue-codes-fixes

Conversation

@jeffjensen

@jeffjensen jeffjensen commented Aug 1, 2026

Copy link
Copy Markdown
Member

Summary

Six independent fixes selected from plan-docs/apply-issue-codes-plan.adoc's review of open GitHub issues that contain a concrete, still-applicable code suggestion:

  • Refs: 492AbstractDatabaseConnection.getRowCount() now applies DatabaseConfig.PROPERTY_ESCAPE_PATTERN, mirroring createTable().
  • Refs: 628DatabaseTableMetaData.getPrimaryKeys() now falls back to the database-declared primary key when a configured PROPERTY_PRIMARY_KEY_FILTER matches zero columns for a table.
  • Refs: 460DatabaseDataSet.initialize() now queries driver/database info for debug logging before opening the table-metadata ResultSet, not after, avoiding a single-cursor-driver hazard.
  • Refs: 171 — New opt-in DatabaseConfig.FEATURE_SORT_ALL_COLUMNS_WHEN_NO_PRIMARY_KEY sorts a primary-key-less table's SELECT by all non-LOB columns instead of leaving row order database-defined.
  • Refs: 542FlatDtdWriter now emits valid <!ELEMENT dataset ANY> instead of an invalid, unparseable empty content model for a zero-table dataset.
  • Refs: 533 — New MultiSchemaMySqlMetadataHandler works around MySQL Connector/J's nullCatalogMeansCurrent default, which otherwise silently hides every catalog but one for a connection not restricted to a single schema.

Each fix has its own commit with an accompanying test and changes.xml entry.

Test plan

  • ./mvnw test — full unit suite, 1936 tests, 0 failures
  • ./mvnw verify -Ph2-1-4 — targeted IT runs for the DB-touching fixes (492, 628, 460, 171)
  • ./mvnw verify -Pmysql-9-20 (Docker) — full regression pass, 347 tests, 0 failures, validating the new MySQL handler and confirming no regressions from the other five fixes
  • ./mvnw install site — confirms the package builds and the two updated doc pages (properties.adoc, databases/mysql.adoc) render correctly
  • For fixes 460 and 542, manually reverted the production change and confirmed the new test fails with the exact originally-reported symptom, then restored the fix

🤖 Generated with Claude Code

https://claude.ai/code/session_01P8mZjBXrYpB3zWNpN1wdC9

Summary by CodeRabbit

  • New Features
    • Added optional sorting of non-LOB columns for tables without primary keys.
    • Added MySQL metadata discovery across multiple schemas.
  • Bug Fixes
    • Improved identifier escaping in row-count queries.
    • Restored primary-key metadata when filters return no matches.
    • Improved metadata cursor handling.
    • Fixed DTD generation for empty datasets.
  • Documentation
    • Documented the new sorting option and multi-schema MySQL configuration.
  • Tests
    • Added regression and integration coverage for these improvements.

…RowCount()

getRowCount(String, String) built its QualifiedTableName with the
2-arg constructor, which never applies
DatabaseConfig.PROPERTY_ESCAPE_PATTERN, so a configured escape
pattern was silently dropped from the generated SQL. createTable()
already looks up and applies the escape pattern; getRowCount() now
does the same.

Refs: 492
…umns

DatabaseTableMetaData.getPrimaryKeys() returned an empty array
whenever a configured PROPERTY_PRIMARY_KEY_FILTER matched zero
columns for a table (e.g. a naming-convention filter that doesn't
recognize that table's PK column), instead of falling back to the
table's actual database-declared primary key. Add that fallback,
matching the no-filter-configured branch's existing behavior.

Behavior change: this makes the fallback unconditional whenever a
filter yields zero columns, which now overrides a filter deliberately
configured to declare that a table has no PK.

Refs: 628
…seDataSet.initialize()

The debug-only SQLHelper.getDatabaseInfo() call ran after
metadataHandler.getTables() had already opened the table metadata
ResultSet. On JDBC drivers that allow only a single active cursor per
connection (e.g. SQL Anywhere, some legacy Sybase drivers), those
intervening DatabaseMetaData calls can silently invalidate the
still-open ResultSet. Move the call above ResultSet creation, reusing
the already-held databaseMetaData variable instead of calling
jdbcConnection.getMetaData() again. None of this project's 9 CI
database profiles have the single-cursor constraint, so this was not
reproducible locally; verified instead via a mocked IMetadataHandler/
DatabaseMetaData test asserting call order.

Refs: 460
…ry key

DatabaseDataSet.getSelectStatement() emitted no ORDER BY clause for a
table with no primary key, leaving row order database-defined and
thus nondeterministic. Add DatabaseConfig.FEATURE_SORT_ALL_COLUMNS_WHEN_NO_PRIMARY_KEY,
defaulting to off to preserve existing behavior; when enabled, such a
table is sorted by all of its non-LOB columns instead. CLOB/BLOB
columns are always excluded from that fallback sort since some
databases (notably Oracle) reject LOB columns in ORDER BY outright.

Refs: 171
FlatDtdWriter.write() emitted "<!ELEMENT dataset (\n)>" for a
zero-table dataset - an empty parenthesized content model, which is
not valid DTD syntax. FlatDtdProducer then failed reading it back
with a SAXParseException ("A '(' character or an element type is
required...").

Emit "<!ELEMENT dataset ANY>" instead when there are no tables. ANY is
preferred over EMPTY because a pretty-printed empty dataset file
typically contains whitespace between <dataset> and </dataset>, and
EMPTY rejects any content including whitespace, while ANY tolerates
both.

Refs: 542
…a connections

MySqlMetadataHandler.getTables()/getColumns()/getPrimaryKeys() pass a
null schema straight through as the JDBC catalog argument. Per the
JDBC spec catalog=null means "search every catalog", but MySQL
Connector/J's default nullCatalogMeansCurrent setting instead treats
it as "the connection's current catalog only", so a connection not
restricted to a single schema (e.g. connecting as "root" specifically
to work across several schemas, with FEATURE_QUALIFIED_TABLE_NAMES
enabled) silently sees only one catalog's tables and gets
NoSuchTableException for tables in every other one.

Add MultiSchemaMySqlMetadataHandler: whenever no single schema is
configured, it enumerates the connection's visible catalogs (skipping
information_schema/mysql/performance_schema/sys) and unions the
per-catalog getTables()/getColumns()/getPrimaryKeys()/tableExists()
results itself instead of ever passing a null catalog to the driver.
The union is backed by a minimal in-memory ResultSet/ResultSetMetaData
Proxy supporting only the handful of methods dbunit itself calls
against a metadata-handler result, copied out of and closing each
per-catalog result set eagerly.

The original reported fix was only ever a SourceForge file attachment
and was not retrievable; this is a fresh implementation built from the
confirmed diagnosis, verified via mocked multi-catalog DatabaseMetaData
unit tests and a full mysql-9-20 regression run (347 tests, all
green) rather than a recovered, untested patch.

Refs: 533
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jeffjensen, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b8d49356-e071-4a73-b5ff-3596281171f7

📥 Commits

Reviewing files that changed from the base of the PR and between c52b575 and 646eafa.

📒 Files selected for processing (8)
  • src/main/java/org/dbunit/database/DatabaseConfig.java
  • src/main/java/org/dbunit/database/DatabaseDataSet.java
  • src/main/java/org/dbunit/dataset/xml/FlatDtdWriter.java
  • src/main/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandler.java
  • src/test/java/org/dbunit/database/DatabaseDataSetIT.java
  • src/test/java/org/dbunit/dataset/xml/FlatDtdProducerTest.java
  • src/test/java/org/dbunit/dataset/xml/FlatDtdWriterTest.java
  • src/test/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandlerTest.java
📝 Walkthrough

Walkthrough

Changes

Database query and metadata behavior

Layer / File(s) Summary
Query configuration and fallback sorting
src/main/java/org/dbunit/database/*, src/main/java/org/dbunit/database/AbstractDatabaseConnection.java, src/test/java/org/dbunit/database/*, src/site/asciidoc/properties.adoc
Adds opt-in non-LOB sorting for tables without primary keys and applies configured escape patterns to row-count SQL.
Metadata fallback and lookup ordering
src/main/java/org/dbunit/database/DatabaseTableMetaData.java, src/main/java/org/dbunit/database/DatabaseDataSet.java, src/test/java/org/dbunit/database/*
Falls back to database-declared primary keys and performs database information lookup before opening table metadata.
Changelog entries
src/changes/changes.xml
Records the database query and metadata changes.

MySQL multi-schema metadata

Layer / File(s) Summary
Catalog enumeration and metadata merging
src/main/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandler.java
Adds catalog discovery, system-catalog filtering, merged metadata result sets, and cross-catalog table existence checks.
Handler validation and usage documentation
src/test/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandlerTest.java, src/site/asciidoc/databases/mysql.adoc, src/changes/changes.xml
Tests multi-catalog behavior and documents handler configuration and behavior.

Empty dataset DTD output

Layer / File(s) Summary
Empty dataset DTD generation
src/main/java/org/dbunit/dataset/xml/FlatDtdWriter.java, src/test/java/org/dbunit/dataset/xml/*, src/changes/changes.xml
Emits <!ELEMENT dataset ANY> for empty datasets and validates writer output through direct and round-trip tests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DatabaseConfig
  participant AbstractResultSetTable
  participant DatabaseDataSet
  DatabaseConfig->>AbstractResultSetTable: provide sorting feature
  AbstractResultSetTable->>DatabaseDataSet: request select statement
  DatabaseDataSet->>DatabaseDataSet: select non-LOB columns when no primary key
Loading
sequenceDiagram
  participant DatabaseMetaData
  participant MultiSchemaMySqlMetadataHandler
  participant MetadataResultSetMerger
  MultiSchemaMySqlMetadataHandler->>DatabaseMetaData: enumerate visible catalogs
  MultiSchemaMySqlMetadataHandler->>DatabaseMetaData: query tables, columns, and primary keys
  MultiSchemaMySqlMetadataHandler->>MetadataResultSetMerger: merge result sets
  MetadataResultSetMerger-->>MultiSchemaMySqlMetadataHandler: return combined metadata
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.32% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the pull request as six fixes from the code review, and it matches the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jj-apply-issue-codes-fixes

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
src/test/java/org/dbunit/dataset/xml/FlatDtdProducerTest.java (1)

222-223: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Split the nested test setup into local variables.

Create separate DefaultDataSet and FlatDtdWriter variables before calling write. This makes the setup easier to inspect and follows the repository Java style rule.

Suggested change
-        new FlatDtdWriter(dtdWriter).write(new DefaultDataSet());
+        final DefaultDataSet dataSet = new DefaultDataSet();
+        final FlatDtdWriter flatDtdWriter = new FlatDtdWriter(dtdWriter);
+        flatDtdWriter.write(dataSet);

As per coding guidelines, use separate local variables and avoid deeply compounded nested calls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/org/dbunit/dataset/xml/FlatDtdProducerTest.java` around lines
222 - 223, In the test setup around FlatDtdWriter.write, create local variables
for the DefaultDataSet and FlatDtdWriter instances before invoking write. Pass
those variables to write instead of nesting constructors inside the call, while
preserving the existing behavior.

Source: Coding guidelines

src/main/java/org/dbunit/dataset/xml/FlatDtdWriter.java (1)

72-87: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a positive condition before the else.

Change if (tableNames.length == 0) to if (tableNames.length > 0). Move the ANY output into the else branch. This preserves the output and follows the repository condition rule.

As per coding guidelines, when an if statement has an else, prefer a positive condition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/dbunit/dataset/xml/FlatDtdWriter.java` around lines 72 -
87, Update the condition guarding the dataset content-model output to check for
tableNames.length > 0, keeping the existing table-listing logic in the if branch
and moving the dataset ANY output into the else branch without changing either
output.

Source: Coding guidelines

src/main/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandler.java (1)

159-184: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider caching the catalog list to avoid repeated enumeration.

listUserCatalogs() re-queries metaData.getCatalogs() every time getTables, getColumns, getPrimaryKeys, or tableExists runs without a single schema. DatabaseTableMetaData calls getColumns/getPrimaryKeys/tableExists once per table (see DatabaseTableMetaData.java context snippets), so for a schema with many tables this handler issues a repeated SHOW DATABASES-style query per table. Cache the catalog list per instance, since the class Javadoc's usage pattern ties one handler instance to one connection.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandler.java`
around lines 159 - 184, Cache the result produced by listUserCatalogs() on the
handler instance so repeated calls from getTables, getColumns, getPrimaryKeys,
and tableExists reuse the same catalog list instead of invoking
metaData.getCatalogs() again. Initialize the cache on the first call, preserve
the existing filtering and returned catalog contents, and keep the per-instance
behavior aligned with the handler’s connection lifecycle.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/org/dbunit/database/DatabaseConfig.java`:
- Around line 91-92: Update the ALL_FEATURES array in DatabaseConfig to include
FEATURE_SORT_ALL_COLUMNS_WHEN_NO_PRIMARY_KEY, preserving the existing feature
identifiers and ordering conventions so clients enumerating ALL_FEATURES can
discover it.

In `@src/main/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandler.java`:
- Around line 90-97: Update getTables, getColumns, and getPrimaryKeys to close
every ResultSet already added to perCatalog when a later super.getX call fails,
while preserving normal merge behavior. In merge, move source cleanup to an
outer finally that closes all input ResultSets, ensuring failures from
getMetaData, next, or getObject cannot leak any source.

In `@src/test/java/org/dbunit/dataset/xml/FlatDtdWriterTest.java`:
- Around line 117-118: Update the assertion in
src/test/java/org/dbunit/dataset/xml/FlatDtdWriterTest.java:117-118 to use the
period-terminated failure description “Generated DTD output.” instead of
“output”. In src/test/java/org/dbunit/dataset/xml/FlatDtdProducerTest.java:233,
add the period-terminated AssertJ description “The empty DTD must produce no
tables.”.

In `@src/test/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandlerTest.java`:
- Around line 73-237: Update every AssertJ .as() failure message in the test
methods, including those in
testGetTables_withSchemaConfigured_delegatesWithoutEnumeratingCatalogs,
testTableExists_withNoSchemaConfigured_returnsFalseWhenNotFoundInAnyUserCatalog,
and the surrounding tests, so each message ends with a trailing period. Preserve
the assertion logic and message wording otherwise.

---

Nitpick comments:
In `@src/main/java/org/dbunit/dataset/xml/FlatDtdWriter.java`:
- Around line 72-87: Update the condition guarding the dataset content-model
output to check for tableNames.length > 0, keeping the existing table-listing
logic in the if branch and moving the dataset ANY output into the else branch
without changing either output.

In `@src/main/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandler.java`:
- Around line 159-184: Cache the result produced by listUserCatalogs() on the
handler instance so repeated calls from getTables, getColumns, getPrimaryKeys,
and tableExists reuse the same catalog list instead of invoking
metaData.getCatalogs() again. Initialize the cache on the first call, preserve
the existing filtering and returned catalog contents, and keep the per-instance
behavior aligned with the handler’s connection lifecycle.

In `@src/test/java/org/dbunit/dataset/xml/FlatDtdProducerTest.java`:
- Around line 222-223: In the test setup around FlatDtdWriter.write, create
local variables for the DefaultDataSet and FlatDtdWriter instances before
invoking write. Pass those variables to write instead of nesting constructors
inside the call, while preserving the existing behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ca1bc80b-2beb-4287-a9a9-f110e08e6c57

📥 Commits

Reviewing files that changed from the base of the PR and between 690270c and c52b575.

📒 Files selected for processing (17)
  • src/changes/changes.xml
  • src/main/java/org/dbunit/database/AbstractDatabaseConnection.java
  • src/main/java/org/dbunit/database/AbstractResultSetTable.java
  • src/main/java/org/dbunit/database/DatabaseConfig.java
  • src/main/java/org/dbunit/database/DatabaseDataSet.java
  • src/main/java/org/dbunit/database/DatabaseTableMetaData.java
  • src/main/java/org/dbunit/dataset/xml/FlatDtdWriter.java
  • src/main/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandler.java
  • src/site/asciidoc/databases/mysql.adoc
  • src/site/asciidoc/properties.adoc
  • src/test/java/org/dbunit/database/AbstractDatabaseConnectionTest.java
  • src/test/java/org/dbunit/database/DatabaseDataSetIT.java
  • src/test/java/org/dbunit/database/DatabaseDataSetTest.java
  • src/test/java/org/dbunit/database/DatabaseTableMetaDataIT.java
  • src/test/java/org/dbunit/dataset/xml/FlatDtdProducerTest.java
  • src/test/java/org/dbunit/dataset/xml/FlatDtdWriterTest.java
  • src/test/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandlerTest.java

Comment thread src/main/java/org/dbunit/database/DatabaseConfig.java
Comment thread src/test/java/org/dbunit/dataset/xml/FlatDtdWriterTest.java Outdated
Comment thread src/test/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandlerTest.java Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c52b575498

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/main/java/org/dbunit/database/DatabaseDataSet.java Outdated
Comment thread src/main/java/org/dbunit/ext/mysql/MultiSchemaMySqlMetadataHandler.java Outdated
…review

CodeRabbit's review of PR #880 found one real bug and several style
gaps in that PR's new code:

* MultiSchemaMySqlMetadataHandler.getTables()/getColumns()/
  getPrimaryKeys() leaked already-opened per-catalog ResultSets when
  a later catalog's metadata call failed, since the failure happened
  before merge() (whose per-source cleanup never got a chance to
  run). merge() itself had the same gap: a mid-loop failure left
  not-yet-reached sources unclosed. Both now close every collected
  source on failure.
* Cache the per-instance catalog list instead of re-querying
  getCatalogs() on every getTables()/getColumns()/getPrimaryKeys()/
  tableExists() call - one handler instance is configured per
  connection, so the visible catalogs aren't expected to change over
  its lifetime.
* Add the new FEATURE_SORT_ALL_COLUMNS_WHEN_NO_PRIMARY_KEY constant
  to DatabaseConfig.ALL_FEATURES, which had drifted out of sync with
  ALL_PROPERTIES.
* FlatDtdWriter: use a positive if-condition paired with its else,
  per this project's own stated code style.
* Split a nested constructor-chain call into local variables in
  FlatDtdProducerTest, and add period-terminated AssertJ .as()
  failure messages across the new test files, per this project's own
  stated test style.

Verified via the full unit suite (1937 tests) and a full mysql-9-20
Docker regression run (347 tests), both green; added a dedicated
regression test proving the leak fix (asserts the first catalog's
ResultSet is closed when the second catalog's query throws).
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@jeffjensen

Copy link
Copy Markdown
Member Author

Addressed CodeRabbit's review in ca979a5 (pushed). Replied inline to the 4 actionable comments; the 3 remaining nitpicks (bundled in the review summary rather than posted as separate threads) are also fixed:

  • FlatDtdProducerTest.java — split new FlatDtdWriter(dtdWriter).write(new DefaultDataSet()) into local variables.
  • FlatDtdWriter.java — flipped to a positive if (tableNames.length > 0) condition paired with its else.
  • MultiSchemaMySqlMetadataHandler.java — cached the per-instance catalog list instead of re-querying getCatalogs() on every table lookup.

Verified with the full unit suite (1937 tests) and a full mysql-9-20 Docker regression run (347 tests), both green, plus a new regression test for the ResultSet-leak fix.

DatabaseDataSet.nonLobColumns() excluded a column from the
FEATURE_SORT_ALL_COLUMNS_WHEN_NO_PRIMARY_KEY fallback sort only when
its DataType was reference-equal to the generic DataType.CLOB/
DataType.BLOB singletons. A vendor data type factory - e.g.
OracleDataTypeFactory, whose CLOB/BLOB columns are typed
OracleClobDataType/OracleBlobDataType - produces distinct DataType
instances that never equal those singletons, so this check missed
them: a no-PK Oracle table with those columns still got them in its
ORDER BY, causing exactly the SQL error the feature exists to avoid.

Check by type instead: OracleClobDataType extends ClobDataType and
OracleBlobDataType/OracleXMLTypeDataType extend BlobDataType, so an
instanceof check catches the generic types, Oracle's vendor types, and
any future subtype without needing a per-vendor identity list.

Found by Codex's automated review of PR #880.

Refs: 171
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@jeffjensen
jeffjensen merged commit a9a8f2a into main Aug 2, 2026
26 checks passed
jeffjensen added a commit that referenced this pull request Aug 2, 2026
…review

CodeRabbit's review of PR #880 found one real bug and several style
gaps in that PR's new code:

* MultiSchemaMySqlMetadataHandler.getTables()/getColumns()/
  getPrimaryKeys() leaked already-opened per-catalog ResultSets when
  a later catalog's metadata call failed, since the failure happened
  before merge() (whose per-source cleanup never got a chance to
  run). merge() itself had the same gap: a mid-loop failure left
  not-yet-reached sources unclosed. Both now close every collected
  source on failure.
* Cache the per-instance catalog list instead of re-querying
  getCatalogs() on every getTables()/getColumns()/getPrimaryKeys()/
  tableExists() call - one handler instance is configured per
  connection, so the visible catalogs aren't expected to change over
  its lifetime.
* Add the new FEATURE_SORT_ALL_COLUMNS_WHEN_NO_PRIMARY_KEY constant
  to DatabaseConfig.ALL_FEATURES, which had drifted out of sync with
  ALL_PROPERTIES.
* FlatDtdWriter: use a positive if-condition paired with its else,
  per this project's own stated code style.
* Split a nested constructor-chain call into local variables in
  FlatDtdProducerTest, and add period-terminated AssertJ .as()
  failure messages across the new test files, per this project's own
  stated test style.

Verified via the full unit suite (1937 tests) and a full mysql-9-20
Docker regression run (347 tests), both green; added a dedicated
regression test proving the leak fix (asserts the first catalog's
ResultSet is closed when the second catalog's query throws).
@jeffjensen
jeffjensen deleted the jj-apply-issue-codes-fixes branch August 2, 2026 00:05
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