From 93c62d78db7847078727eafd3d8e40836a575cec Mon Sep 17 00:00:00 2001 From: Morris Jobke Date: Mon, 12 Nov 2018 13:43:46 +0100 Subject: [PATCH] Fix UniqueConstraintViolationException while insert into oc_filecache * fixes #6160 by not being prone to the race condition in insertIfNotExists * fixes #12228 by not using a query that can result in a deadlock * replaces the insertIfNotExists call with an insert which is wrapped into a try-catch block Signed-off-by: Morris Jobke --- lib/private/Files/Cache/Cache.php | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index 007bccf0a5..1cb11c70a4 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -37,6 +37,7 @@ namespace OC\Files\Cache; +use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use OCP\DB\QueryBuilder\IQueryBuilder; use Doctrine\DBAL\Driver\Statement; use OCP\Files\Cache\ICache; @@ -238,6 +239,8 @@ class Cache implements ICache { * * @return int file id * @throws \RuntimeException + * + * @suppress SqlInjectionChecker */ public function insert($file, array $data) { // normalize file @@ -268,12 +271,20 @@ class Cache implements ICache { return trim($item, "`"); }, $queryParts); $values = array_combine($queryParts, $params); - if (\OC::$server->getDatabaseConnection()->insertIfNotExist('*PREFIX*filecache', $values, [ - 'storage', - 'path_hash', - ]) - ) { - return (int)$this->connection->lastInsertId('*PREFIX*filecache'); + + try { + $builder = $this->connection->getQueryBuilder(); + $builder->insert('filecache'); + + foreach ($values as $column => $value) { + $builder->setValue($column, $builder->createNamedParameter($value)); + } + + if ($builder->execute()) { + return (int)$this->connection->lastInsertId('*PREFIX*filecache'); + } + } catch(UniqueConstraintViolationException $e) { + // entry exists already } // The file was created in the mean time @@ -281,7 +292,7 @@ class Cache implements ICache { $this->update($id, $data); return $id; } else { - throw new \RuntimeException('File entry could not be inserted with insertIfNotExist() but could also not be selected with getId() in order to perform an update. Please try again.'); + throw new \RuntimeException('File entry could not be inserted but could also not be selected with getId() in order to perform an update. Please try again.'); } }