Issue #1376778 by c960657 | andypost: Added Consistent 'duplicate key' detection in core.

8.0.x
catch 2012-11-28 11:38:42 +00:00
parent ffa989f8a3
commit 7e8d99b5b6
6 changed files with 42 additions and 10 deletions

View File

@ -495,13 +495,14 @@ abstract class Connection extends PDO {
* @return Drupal\Core\Database\StatementInterface
* This method will return one of: the executed statement, the number of
* rows affected by the query (not the number matched), or the generated
* insert IT of the last query, depending on the value of
* insert ID of the last query, depending on the value of
* $options['return']. Typically that value will be set by default or a
* query builder and should not be set by a user. If there is an error,
* this method will return NULL and may throw an exception if
* $options['throw_exception'] is TRUE.
*
* @throws PDOException
* @throws Drupal\Core\Database\IntegrityConstraintViolationException
*/
public function query($query, array $args = array(), $options = array()) {
@ -545,7 +546,13 @@ abstract class Connection extends PDO {
// debug information.
$query_string = ($query instanceof DatabaseStatementInterface) ? $stmt->getQueryString() : $query;
$message = $e->getMessage() . ": " . $query_string . "; " . print_r($args, TRUE);
$exception = new DatabaseExceptionWrapper($message, 0, $e);
// Match all SQLSTATE 23xxx errors.
if (substr($e->getCode(), -6, -3) == '23') {
$exception = new IntegrityConstraintViolationException($message, $e->getCode(), $e);
}
else {
$exception = new DatabaseExceptionWrapper($message, 0, $e);
}
throw $exception;
}

View File

@ -11,6 +11,7 @@ use Drupal\Core\Database\Database;
use Drupal\Core\Database\Connection as DatabaseConnection;
use Drupal\Core\Database\DatabaseNotFoundException;
use Drupal\Core\Database\StatementInterface;
use Drupal\Core\Database\IntegrityConstraintViolationException;
use Locale;
use PDO;
@ -132,6 +133,10 @@ class Connection extends DatabaseConnection {
}
catch (PDOException $e) {
if ($options['throw_exception']) {
// Match all SQLSTATE 23xxx errors.
if (substr($e->getCode(), -6, -3) == '23') {
$e = new IntegrityConstraintViolationException($e->getMessage(), $e->getCode(), $e);
}
// Add additional debug information.
if ($query instanceof StatementInterface) {
$e->query_string = $stmt->getQueryString();

View File

@ -0,0 +1,18 @@
<?php
/**
* @file
* Definition of Drupal\Core\Database\IntegrityConstraintViolationException
*/
namespace Drupal\Core\Database;
use RuntimeException;
/**
* Exception thrown if a query would violate an integrity constraint.
*
* This exception is thrown e.g. when trying to insert a row that would violate
* a unique key constraint.
*/
class IntegrityConstraintViolationException extends RuntimeException implements DatabaseException { }

View File

@ -9,6 +9,7 @@ namespace Drupal\Core\Database\Query;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\IntegrityConstraintViolationException;
use Exception;
@ -423,7 +424,7 @@ class Merge extends Query implements ConditionInterface {
$insert->execute();
return self::STATUS_INSERT;
}
catch (Exception $e) {
catch (IntegrityConstraintViolationException $e) {
// The insert query failed, maybe it's because a racing insert query
// beat us in inserting the same row. Retry the select query, if it
// returns a row, ignore the error and continue with the update

View File

@ -7,7 +7,7 @@
namespace Drupal\Core\Lock;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Database\IntegrityConstraintViolationException;
/**
* Defines the database lock backend. This is the default backend in Drupal.
@ -53,12 +53,12 @@ class DatabaseLockBackend extends LockBackendAbstract {
// We never need to try again.
$retry = FALSE;
}
catch (DatabaseExceptionWrapper $e) {
catch (IntegrityConstraintViolationException $e) {
// Suppress the error. If this is our first pass through the loop,
// then $retry is FALSE. In this case, the insert must have failed
// meaning some other request acquired the lock but did not release it.
// We decide whether to retry by checking lock_may_be_available()
// Since this will break the lock in case it is expired.
// then $retry is FALSE. In this case, the insert failed because some
// other request acquired the lock but did not release it. We decide
// whether to retry by checking lockMayBeAvailable(). This will clear
// the offending row from the database table in case it has expired.
$retry = $retry ? FALSE : $this->lockMayBeAvailable($name);
}
// We only retry in case the first attempt failed, but we then broke

View File

@ -7,6 +7,7 @@
namespace Drupal\system\Tests\Database;
use Drupal\Core\Database\IntegrityConstraintViolationException;
use Exception;
/**
@ -46,7 +47,7 @@ class InvalidDataTest extends DatabaseTestBase {
->execute();
$this->fail('Insert succeedded when it should not have.');
}
catch (Exception $e) {
catch (IntegrityConstraintViolationException $e) {
// Check if the first record was inserted.
$name = db_query('SELECT name FROM {test} WHERE age = :age', array(':age' => 63))->fetchField();