Skip to content

Scope table and index lookups to the connection catalog on MySQL (fixes #489) - #559

Open
iacsha wants to merge 3 commits into
OpenIntegrationEngine:mainfrom
iacsha:fix/489-mysql-catalog-scope
Open

iacsha wants to merge 3 commits into
OpenIntegrationEngine:mainfrom
iacsha:fix/489-mysql-catalog-scope

Conversation

@iacsha

@iacsha iacsha commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Scope table and index lookups to the connection catalog on MySQL (fixes #489)

Problem

The engine's "does this table exist?" and "does this index exist?" checks call DatabaseMetaData with a null catalog. On MySQL, Connector/J then searches every database the login can see, not just the one in the URL. When one login has rights on more than one OIE database on the same server, an engine finds another database's tables or indexes and skips creating or repairing its own:

  • First startup fails. ServerMigrator.initDatabase calls DatabaseUtil.tableExists(conn, "CONFIGURATION"), finds the other database's CONFIGURATION, skips mysql-database.sql, and getCurrentVersion then fails on the missing SCHEMA_INFO.
  • Per-channel message tables aren't recreated. JdbcDao.checkAndCreateChannelTables lists tables across all visible databases, so a missing D_MC<n> looks present when another database has a table of that name. Messages then fail with Table 'oie_b.D_MC1' doesn't exist.
  • Missing indexes aren't offered for repair. DatabaseUtil.indexExists finds another database's index of the same name (for example D_MM1_INDEX3), so the "Add Metadata Index" database task never appears.

Fix

Only MySQL (and MariaDB) changes behaviour. Every other database keeps the existing null-catalog lookup.

  • Server side (DatabaseUtil). A new lookupCatalog returns connection.getCatalog() when the database product is MySQL or MariaDB, and null otherwise. tableExists and indexExists both use it, for their upper- and lower-case lookups.
  • Donkey side (JdbcDao). There is no MySQL-specific DAO class, so this follows the existing setQuoteChar pattern. JdbcDao gets setScopeTablesToCatalog(boolean), off by default, which MysqlDaoFactory turns on. checkAndCreateChannelTables and tableExists pass the catalog only when it is enabled.

This has the same effect as the reporter's ?nullDatabaseMeansCurrent=true URL workaround, applied in code.

Tests

  • DatabaseUtilTest (4 tests):
    • On MySQL, tableExists and indexExists pass the connection's catalog ("oie_b").
    • On PostgreSQL, both keep a null catalog and never call getCatalog().
    • The MySQL indexExists test fails without the latest commit.
  • JdbcDaoTest:
    • testTableLookupUnscopedByDefault
    • testTableLookupScopedToCatalogWhenEnabled

gradle :server:test --tests "*DatabaseUtilTest*": 4 tests, 0 failures.

End-to-end on MySQL 8.4 with Connector/J 8.4.0, two engines on one login: @pacmano1 confirmed in review that the startup and message-table cases are fixed and that engine D with ?nullDatabaseMeansCurrent=true still works.

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Test Results

  143 files  + 2    143 suites  +2   3m 8s ⏱️ +9s
  943 tests +24    943 ✅ +24  0 💤 ±0  0 ❌ ±0 
1 105 runs  +54  1 099 ✅ +54  6 💤 ±0  0 ❌ ±0 

Results for commit 39711c5. ± Comparison against base commit 892e33f.

♻️ This comment has been updated with latest results.

@mgaffigan mgaffigan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add missing DCO.

Also: if this is a mysql specific thing, it should live in the MySQL DAO - not in JdbcDao.

…egrationEngine#489)

DatabaseUtil.tableExists and JdbcDao.checkAndCreateChannelTables/tableExists called DatabaseMetaData.getTables with a null catalog, so on MySQL a login with access to other databases matched their tables and a second OIE database was never migrated and missing message tables were not recreated. Pass connection.getCatalog() so each engine only sees its own database; null-catalog behaviour is unchanged on databases where getCatalog() returns null.

Signed-off-by: iacsha <122627209+iacsha@users.noreply.github.com>
@iacsha
iacsha force-pushed the fix/489-mysql-catalog-scope branch from dc2c0a6 to 06407c5 Compare November 6, 2026 19:47
Move the catalog scoping behind a JdbcDao flag that MysqlDaoFactory enables, and limit DatabaseUtil.tableExists scoping to MySQL/MariaDB, so other databases keep the existing null-catalog lookup.

Signed-off-by: iacsha <122627209+iacsha@users.noreply.github.com>
@iacsha

iacsha commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @mgaffigan, good call. Moved it so only MySQL changes behaviour (DCO is fixed too). There isn't a MySQL-specific DAO class today, so I followed the existing setQuoteChar pattern in MysqlDaoFactory:

  • JdbcDao gets a setScopeTablesToCatalog(boolean) flag, off by default. With it off, both table lookups pass a null catalog exactly as main does, so Derby, Postgres, SQL Server and Oracle are unchanged.
  • MysqlDaoFactory.getDao() turns it on, next to setQuoteChar('')`.
  • DatabaseUtil.tableExists is a static helper with no DAO behind it, so it scopes to connection.getCatalog() only when the driver reports MySQL or MariaDB as the product name, and keeps the null catalog otherwise.

Tests: JdbcDaoTest checks the default lookup still uses a null catalog and that the flag scopes it to the connection's catalog. DatabaseUtilTest checks MySQL scopes and PostgreSQL keeps null. I also switched that test's header to Open Integration Engine Contributors to match #562.

@iacsha

iacsha commented Nov 11, 2026

Copy link
Copy Markdown
Contributor Author

@mgaffigan the changes you requested are in: the table scoping is now MySQL-only (set by MysqlDaoFactory, following the setQuoteChar pattern), and DCO is fixed. Could you take another look when you have a moment?

@pacmano1 pacmano1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Tested on MySQL 8.4 with the bundled Connector/J 8.4.0, the PR head against its base, following the steps in #489.

Both effects are fixed. On the base, engine B still fails to start with Table '…SCHEMA_INFO' doesn't exist, and if B's D_MC1 is dropped while B is stopped, B doesn't recreate it on restart, so the next message gets a 500. With the PR, B starts and builds its schema, recreates D_MC1 and takes the message. Engine D with ?nullDatabaseMeansCurrent=true still works with the PR, and engine C on its own login behaves the same on both builds.

DatabaseUtil.indexExists has the same bug. It still calls getIndexInfo(null, null, …). With the PR, after dropping B's own D_MM1_INDEX3, B isn't offered the "Add Metadata Index" database task, because it finds A's index. Drop A's too, with B still running, and the task shows up. Can you scope it the same way?

The description still describes the first version (every database, the old test name, "1 test").

Co-authored with Claude Code.

DatabaseUtil.indexExists still called getIndexInfo with a null catalog,
so on MySQL an engine that had lost one of its own indexes found another
database's index of the same name and was never offered the task that
recreates it. Move the catalog choice into lookupCatalog and use it in
both tableExists and indexExists. Adds two DatabaseUtilTest cases; the
MySQL one fails without this change.

Signed-off-by: iacsha <122627209+iacsha@users.noreply.github.com>
@iacsha iacsha changed the title Scope table-existence checks to the connection catalog (fixes #489) Scope table and index lookups to the connection catalog on MySQL (fixes #489) Nov 12, 2026
@iacsha

iacsha commented Nov 12, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @pacmano1, that's a thorough test, and good catch on indexExists.

  • indexExists: fixed in 39711c5. The catalog choice is now one helper, lookupCatalog, and tableExists and indexExists both use it, so they stay in step. I added two DatabaseUtilTest cases (MySQL scoped, PostgreSQL unchanged), and the MySQL one fails without the change.
  • Description: rewritten for the MySQL-only version. It covers the index case, the current test names and the counts.

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.

[BUG] On MySQL, table checks see other databases on the same login, so a second OIE database never gets its schema

3 participants