Skip to content

fix: PostgreSQL transaction aborts when caching user mounts#58798

Open
AIlkiv wants to merge 1 commit intonextcloud:masterfrom
AIlkiv:fix-UserMountCache-for-postgresql
Open

fix: PostgreSQL transaction aborts when caching user mounts#58798
AIlkiv wants to merge 1 commit intonextcloud:masterfrom
AIlkiv:fix-UserMountCache-for-postgresql

Conversation

@AIlkiv
Copy link
Contributor

@AIlkiv AIlkiv commented Mar 9, 2026

Summary

On PostgreSQL, the current implementation of UserMountCache::registerMounts() / addToCache() is not transaction‑safe. When a duplicate entry hits the unique index on mounts, the code catches the unique-constraint exception but the surrounding transaction on PostgreSQL remains in the aborted state. All subsequent statements in that transaction then fail with SQLSTATE[25P02]: current transaction is aborted, commands ignored until end of transaction block when mounts are registered.

Why this matters:

  1. Not PostgreSQL-compatible: Silently swallowing the unique-constraint exception works on MySQL/SQLite, but breaks transaction semantics on PostgreSQL.
  2. Potentially fixes [Bug]: Update failes to 32.0.4 / "mounts_user_root_path_index" does not exist on table "oc_mounts" #57572, which is related to the new mount_point_hash / mounts_user_root_path_index migration and mount cache.
  3. Cleaner solution: Using IDBConnection::insertIgnoreConflict('mounts', [...]) (which maps to INSERT ... ON CONFLICT DO NOTHING on PostgreSQL) is more idiomatic, avoids exceptions entirely, and keeps the transaction valid across all supported databases.

TODO

  • ...

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

@AIlkiv AIlkiv requested a review from a team as a code owner March 9, 2026 09:55
@AIlkiv AIlkiv requested review from artonge, nfebe, salmart-dev and sorbaugh and removed request for a team March 9, 2026 09:55
Signed-off-by: ailkiv <a.ilkiv.ye@gmail.com>
@AIlkiv AIlkiv force-pushed the fix-UserMountCache-for-postgresql branch from db56a35 to e958fa0 Compare March 9, 2026 10:03
Copy link
Member

@provokateurin provokateurin left a comment

Choose a reason for hiding this comment

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

The problem might exist, but this code change doesn't fix it. See

public function insertIgnoreConflict(string $table, array $values) : int {
try {
$builder = $this->conn->getQueryBuilder();
$builder->insert($table);
foreach ($values as $key => $value) {
$builder->setValue($key, $builder->createNamedParameter($value));
}
return $builder->executeStatement();
} catch (DbalException $e) {
if ($e->getReason() === \OCP\DB\Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
return 0;
}
throw $e;
}
}
, it does exactly the same as the existing code.

@AIlkiv
Copy link
Contributor Author

AIlkiv commented Mar 9, 2026

The problem might exist, but this code change doesn't fix it. See

public function insertIgnoreConflict(string $table, array $values) : int {
try {
$builder = $this->conn->getQueryBuilder();
$builder->insert($table);
foreach ($values as $key => $value) {
$builder->setValue($key, $builder->createNamedParameter($value));
}
return $builder->executeStatement();
} catch (DbalException $e) {
if ($e->getReason() === \OCP\DB\Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
return 0;
}
throw $e;
}
}

, it does exactly the same as the existing code.

@provokateurin This problem arises specifically for PostgreSQL.
Therefore, you need to look in AdapterPgSql.

public function insertIgnoreConflict(string $table, array $values) : int {
// "upsert" is only available since PgSQL 9.5, but the generic way
// would leave error logs in the DB.
$builder = $this->conn->getQueryBuilder();
$builder->insert($table);
foreach ($values as $key => $value) {
$builder->setValue($key, $builder->createNamedParameter($value));
}
$queryString = $builder->getSQL() . ' ON CONFLICT DO NOTHING';
return $this->conn->executeUpdate($queryString, $builder->getParameters(), $builder->getParameterTypes());
}

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]: Update failes to 32.0.4 / "mounts_user_root_path_index" does not exist on table "oc_mounts"

2 participants