Catch UniqueConstraintViolationException inside insertIfNotExist
This is the most common case for the usage of this method. See also https://github.com/nextcloud/server/issues/12369 and the linked tickets. Signed-off-by: Morris Jobke <hey@morrisjobke.de>
This commit is contained in:
parent
da57aaf814
commit
230e93f575
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
namespace OC\DB;
|
namespace OC\DB;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This handles the way we use to write queries, into something that can be
|
* This handles the way we use to write queries, into something that can be
|
||||||
* handled by the database abstraction layer.
|
* handled by the database abstraction layer.
|
||||||
|
@ -79,7 +81,9 @@ class Adapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a row if the matching row does not exists.
|
* Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
|
||||||
|
* it is needed that there is also a unique constraint on the values. Then this method will
|
||||||
|
* catch the exception and return 0.
|
||||||
*
|
*
|
||||||
* @param string $table The table name (will replace *PREFIX* with the actual prefix)
|
* @param string $table The table name (will replace *PREFIX* with the actual prefix)
|
||||||
* @param array $input data that should be inserted into the table (column name => value)
|
* @param array $input data that should be inserted into the table (column name => value)
|
||||||
|
@ -111,6 +115,14 @@ class Adapter {
|
||||||
$query = substr($query, 0, -5);
|
$query = substr($query, 0, -5);
|
||||||
$query .= ' HAVING COUNT(*) = 0';
|
$query .= ' HAVING COUNT(*) = 0';
|
||||||
|
|
||||||
|
try {
|
||||||
return $this->conn->executeUpdate($query, $inserts);
|
return $this->conn->executeUpdate($query, $inserts);
|
||||||
|
} catch (UniqueConstraintViolationException $e) {
|
||||||
|
// if this is thrown then a concurrent insert happened between the insert and the sub-select in the insert, that should have avoided it
|
||||||
|
// it's fine to ignore this then
|
||||||
|
//
|
||||||
|
// more discussions about this can be found at https://github.com/nextcloud/server/pull/12315
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
namespace OC\DB;
|
namespace OC\DB;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||||
|
|
||||||
class AdapterSqlite extends Adapter {
|
class AdapterSqlite extends Adapter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +52,9 @@ class AdapterSqlite extends Adapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a row if the matching row does not exists.
|
* Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
|
||||||
|
* it is needed that there is also a unique constraint on the values. Then this method will
|
||||||
|
* catch the exception and return 0.
|
||||||
*
|
*
|
||||||
* @param string $table The table name (will replace *PREFIX* with the actual prefix)
|
* @param string $table The table name (will replace *PREFIX* with the actual prefix)
|
||||||
* @param array $input data that should be inserted into the table (column name => value)
|
* @param array $input data that should be inserted into the table (column name => value)
|
||||||
|
@ -82,6 +86,14 @@ class AdapterSqlite extends Adapter {
|
||||||
$query = substr($query, 0, -5);
|
$query = substr($query, 0, -5);
|
||||||
$query .= ')';
|
$query .= ')';
|
||||||
|
|
||||||
|
try {
|
||||||
return $this->conn->executeUpdate($query, $inserts);
|
return $this->conn->executeUpdate($query, $inserts);
|
||||||
|
} catch (UniqueConstraintViolationException $e) {
|
||||||
|
// if this is thrown then a concurrent insert happened between the insert and the sub-select in the insert, that should have avoided it
|
||||||
|
// it's fine to ignore this then
|
||||||
|
//
|
||||||
|
// more discussions about this can be found at https://github.com/nextcloud/server/pull/12315
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,7 +240,9 @@ class Connection extends ReconnectWrapper implements IDBConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a row if the matching row does not exists.
|
* Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
|
||||||
|
* it is needed that there is also a unique constraint on the values. Then this method will
|
||||||
|
* catch the exception and return 0.
|
||||||
*
|
*
|
||||||
* @param string $table The table name (will replace *PREFIX* with the actual prefix)
|
* @param string $table The table name (will replace *PREFIX* with the actual prefix)
|
||||||
* @param array $input data that should be inserted into the table (column name => value)
|
* @param array $input data that should be inserted into the table (column name => value)
|
||||||
|
|
|
@ -104,7 +104,9 @@ interface IDBConnection {
|
||||||
public function lastInsertId($table = null);
|
public function lastInsertId($table = null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert a row if the matching row does not exists.
|
* Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
|
||||||
|
* it is needed that there is also a unique constraint on the values. Then this method will
|
||||||
|
* catch the exception and return 0.
|
||||||
*
|
*
|
||||||
* @param string $table The table name (will replace *PREFIX* with the actual prefix)
|
* @param string $table The table name (will replace *PREFIX* with the actual prefix)
|
||||||
* @param array $input data that should be inserted into the table (column name => value)
|
* @param array $input data that should be inserted into the table (column name => value)
|
||||||
|
|
Loading…
Reference in New Issue