Issue #2999569 by mondrake, Hardik_Patel_12, ravi.shankar, vsujeetkumar, mrinalini9, daffie: MySql driver throws a generic DatabaseExceptionWrapper for integrity violation at insertion when column has no default

merge-requests/2/head
catch 2020-08-07 14:46:22 +01:00
parent a32afce132
commit bacf782e30
3 changed files with 50 additions and 14 deletions

View File

@ -3,6 +3,7 @@
namespace Drupal\Core\Database\Driver\mysql;
use Drupal\Core\Database\DatabaseAccessDeniedException;
use Drupal\Core\Database\IntegrityConstraintViolationException;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Database\Database;
@ -87,6 +88,24 @@ class Connection extends DatabaseConnection {
}
}
/**
* {@inheritdoc}
*/
protected function handleQueryException(\PDOException $e, $query, array $args = [], $options = []) {
// In case of attempted INSERT of a record with an undefined column and no
// default value indicated in schema, MySql returns a 1364 error code.
// Throw an IntegrityConstraintViolationException here like the other
// drivers do, to avoid the parent class to throw a generic
// DatabaseExceptionWrapper instead.
if (!empty($e->errorInfo[1]) && $e->errorInfo[1] === 1364) {
$query_string = ($query instanceof StatementInterface) ? $query->getQueryString() : $query;
$message = $e->getMessage() . ": " . $query_string . "; " . print_r($args, TRUE);
throw new IntegrityConstraintViolationException($message, is_int($e->getCode()) ? $e->getCode() : 0, $e);
}
parent::handleQueryException($e, $query, $args, $options);
}
/**
* {@inheritdoc}
*/

View File

@ -2,6 +2,8 @@
namespace Drupal\KernelTests\Core\Database;
use Drupal\Core\Database\IntegrityConstraintViolationException;
/**
* Tests the insert builder.
*
@ -208,4 +210,26 @@ class InsertTest extends DatabaseTestBase {
$this->assertEquals('Update value 2', $saved_value);
}
/**
* Tests insertion integrity violation with no default value for a column.
*/
public function testInsertIntegrityViolation() {
// Remove the default from the 'age' column, so that inserting a record
// without its value specified will lead to integrity failure.
$this->connection->schema()->changeField('test', 'age', 'age', [
'description' => "The person's age",
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
]);
// Try inserting a record that misses the value for the 'age' column,
// should raise an IntegrityConstraintViolationException.
$this->expectException(IntegrityConstraintViolationException::class);
$this->connection->insert('test')
->fields(['name'])
->values(['name' => 'Elvis'])
->execute();
}
}

View File

@ -4,7 +4,6 @@ namespace Drupal\KernelTests\Core\Entity;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Database\Database;
use Drupal\Core\Database\DatabaseExceptionWrapper;
use Drupal\Core\Database\IntegrityConstraintViolationException;
use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Entity\EntityStorageException;
@ -482,19 +481,13 @@ class EntityDefinitionUpdateTest extends EntityKernelTestBase {
->execute();
$this->fail($message);
}
catch (\RuntimeException $e) {
if ($e instanceof DatabaseExceptionWrapper || $e instanceof IntegrityConstraintViolationException) {
// Now provide a value for the 'not null' column. This is expected to
// succeed.
$values['new_bundle_field_shape'] = $this->randomString();
$this->database->insert('entity_test_update__new_bundle_field')
->fields($values)
->execute();
}
else {
// Keep throwing it.
throw $e;
}
catch (IntegrityConstraintViolationException $e) {
// Now provide a value for the 'not null' column. This is expected to
// succeed.
$values['new_bundle_field_shape'] = $this->randomString();
$this->database->insert('entity_test_update__new_bundle_field')
->fields($values)
->execute();
}
}