Skip to content

fix(monitoring): send the table's container with the maintenance target - #1091

Open
sloemo01 wants to merge 2 commits into
libredb:mainfrom
sloemo01:fix/maintenance-container
Open

sloemo01 wants to merge 2 commits into
libredb:mainfrom
sloemo01:fix/maintenance-container

Conversation

@sloemo01

Copy link
Copy Markdown
Contributor

What

Clicking Analyze, Vacuum or Reindex on the monitoring page answered

relation "public.Mytable" does not exist

for every table outside the public schema. The row already rendered schemaName beside the table name, and the call dropped it, so PostgreSQL's qualifier fell back to public.

Closes #772.

How

runMaintenance takes the container as a third argument, and the two call sites pass the schemaName their row already holds.

Engine What the container does
PostgreSQL qualifies the target, quoted whole; the name is never re-split
SQL Server bracket-qualifies through escapeIdentifier
DuckDB qualifies the target
MySQL qualifies only when the container is not the connected database
ClickHouse replaces the database half of the name
Oracle owner-aware catalog reads, rebuildIndexes takes the owner
Couchbase scopes the keyspace
SQLite, libSQL, MongoDB ignore it, with a note saying why the operation cannot name one
Trino refuses, since its maintenance has no container form

kill is untouched everywhere, because its "target" is a PID rather than a table.

Two of these were found while building rather than reported: Oracle's index rebuild answered ORA-01418 for a table name, and ClickHouse's parts listing read the wrong database, both because the schema never arrived.

Not a behaviour change for existing callers

The container is optional and the old readings stay when it is absent: a bare name still defaults to public, and schema.table is still quoted per-part.

Tests

Three provider tests pin the qualifier at the layer that builds the SQL:

  • a container qualifies the target, and the target name is not re-split
  • a container that itself contains a dot survives the qualifier (the old split-on-name reading could not survive this, which is the reason the parameter exists)
  • without a container the old readings stay

Checking the container by splitting the name cannot work, since a schema may contain a dot, and that case is the one the third test above separates.

Verified by reverting the fix in postgres.ts and watching exactly the two container tests fail while the no-container one stays green, then mutating the qualifier to re-split the container on its dots and watching only the dot case fail.

Existing assertions in TablesTab.test.tsx and OperationsTab.test.tsx are updated to the three-argument call. 501 tests pass across the four touched files, tsc --noEmit is clean, and bun run lint reports 0 errors. The 13 pre-existing failures elsewhere in bun run test are identical on a clean base.

@codecov

codecov Bot commented Sep 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@sloemo01
sloemo01 force-pushed the fix/maintenance-container branch from ba68151 to d856797 Compare September 23, 2026 02:36
@cevheri cevheri added the bug Something isn't working label Sep 23, 2026

@cevheri cevheri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for this. The PostgreSQL half is right: I ran all three buttons against a live PostgreSQL 17 with tables in app and in a dotted odd.schema, and both now succeed where they answered relation "public.Mytable" does not exist. It also merges cleanly with main and the full suite passes.

Three providers need a fix before I merge:

  • MongoDB: assertContainerIsBound compares with config.database, but the row sends getDatabaseName(). On a connection-string connection every per-collection button now fails with bound to the database "". Compare with getDatabaseName().
  • Couchbase: the Tables row carries the bucket in schemaName, not a scope, so Analyze builds travel.travel.travel.
  • Oracle: with an owner, the index list comes from ALL_INDEXES, but ALTER INDEX "X" REBUILD is unqualified and rebuilds in the connected user's schema. Qualify it with the owner.

The #772 acceptance also asked for per-provider tests (non-default container, bare target, a name needing quoting) and the docs/providers/ maintenance sections, and only PostgreSQL has them so far. A test that the route and the hook pass container through is missing too. Those tests would have caught all three issues above.

…et (libredb#772)

Clicking Vacuum, Analyze or Reindex on a table outside the public schema
answered `relation "public.Mytable" does not exist`, because the row already
rendered `schemaName` beside the table and the call dropped it, so the
provider fell back to `public`.

`runMaintenance` now takes the container as a third argument, and the two
call sites pass `table.schemaName`. PostgreSQL, SQL Server, DuckDB, MySQL,
ClickHouse and Oracle qualify with it (Oracle switching to owner-aware
catalog reads), and the engines whose operation cannot name a container say
so instead of pretending the target qualified: SQLite, libSQL and MongoDB
ignore it with a comment, Couchbase scopes the keyspace, Trino refuses.

Docs in providers/postgres.md and DATABASE_PROVIDERS.md carry the new
signature. Three provider tests pin the qualification, including a container
that itself contains a dot, which the old split-on-name reading could not
survive.
…er-provider tests and docs it owed (libredb#772)

MongoDB's refuse-other-database check compared config.database, which a
connection-string connection never sets - so it refused the very database
the provider is bound to, and every per-collection button answered
'bound to the database ""'. It compares getDatabaseName() now.

Couchbase's Tables row is the bucket-level one, and reading its bucket back
as a scope built travel.travel.travel, no keyspace at all. A bucket
container is placed at the default collection, the same placement every
bucket-level catalog row gets; any other container is the scope outright.

Oracle read the index list from ALL_INDEXES when an owner arrived, but the
rebuild was unqualified - ALTER INDEX "X" REBUILD acts on the CONNECTED
schema, which is not where the list came from. The rebuild names the owner.

Tests: container arms for MSSQL, MySQL, DuckDB, ClickHouse, SQLite, libSQL
and Trino beside the three fixed providers, plus the route and hook
pass-through tests the review asked for. Docs: the container's meaning is
stated in every touched provider section.
@sloemo01
sloemo01 force-pushed the fix/maintenance-container branch from d856797 to afdb791 Compare September 25, 2026 23:02
@sloemo01

Copy link
Copy Markdown
Contributor Author

All three fixed in afdb7919, with the tests the acceptance asked for.

MongoDB now compares getDatabaseName() instead of config.database. You were right about the reading, and the consequence was worse than a wrong sentence: a connection-string connection sets no config.database, so the check refused the database the provider is bound to and every per-collection button on that connection failed. Two arms pin it: the bound name is accepted, and a different one is still refused with the name in the sentence.

Couchbase places a bucket container at the default collection. That row is the only Tables row this provider has (getTableStats() reports the bucket under both schemaName and tableName), and it is the same placement every bucket-level catalog row already gets from resolveKeyspaceOf(): _default._default, not travel.travel.travel. Any other container is the scope, used as one rather than parsed back out of the display name, and the bare no-container reading is unchanged. Three arms cover the three readings plus one for quoting.

Oracle qualifies the rebuild. The list came from ALL_INDEXES with the owner bound, and ALTER INDEX "X" REBUILD was acting on the connected schema, which is not where the list came from. Each rebuild is now ALTER INDEX "<owner>"."<index>" REBUILD, and an arm asserts the unqualified spelling never appears.

Tests. The per-provider arms are in: MSSQL, MySQL, DuckDB and ClickHouse get container, bare and quoting arms each, and SQLite, libSQL and Trino get one pinning that the container is ignored with the reason. The route arm asserts the container reaches runMaintenance and that its absence arrives as undefined; the hook arm asserts the request body carries it.

Docs. Every touched provider section now states what the container means for that engine, in docs/providers/.

Verified on the touched files under bun 1.4.2 (the CI pin): 12 spec files, 1921 tests, all passing; typecheck, format, lint, security:check and readme:check clean; 0 uncovered lines across the three changed providers.

One note on scope: the earlier push of this branch was rebased onto current main (d44250e0) to keep it mergeable, so the head moved from d8567977 to afdb7919.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] on the monitoring page, the 3 action buttons show "Relation does not exist"

2 participants