From 93c62d78db7847078727eafd3d8e40836a575cec Mon Sep 17 00:00:00 2001
From: Morris Jobke <hey@morrisjobke.de>
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 <hey@morrisjobke.de>
---
 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 007bccf0a54..1cb11c70a40 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.');
 		}
 	}
 
-- 
GitLab