diff --git a/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php index 4bcda15a07d026d782b922daa2fd109d9c4eb132..2894517fd4a002b58ee399992e31c1c1397714b8 100644 --- a/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php +++ b/core/lib/Drupal/Core/Database/Driver/mysql/Connection.php @@ -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 @@ public function query($query, array $args = [], $options = []) { } } + /** + * {@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} */ diff --git a/core/tests/Drupal/KernelTests/Core/Database/InsertTest.php b/core/tests/Drupal/KernelTests/Core/Database/InsertTest.php index ea66ed47a7fe721e792347577c2c9b91d82c880e..1c18d5fadf22388e750b631cf87612e52cb42eac 100644 --- a/core/tests/Drupal/KernelTests/Core/Database/InsertTest.php +++ b/core/tests/Drupal/KernelTests/Core/Database/InsertTest.php @@ -2,6 +2,8 @@ namespace Drupal\KernelTests\Core\Database; +use Drupal\Core\Database\IntegrityConstraintViolationException; + /** * Tests the insert builder. * @@ -208,4 +210,26 @@ public function testSpecialColumnInsert() { $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(); + } + } diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php index 400037adf0fbb06c341d98bdb14bd65308d66a5c..234c256e485935c5d6b8e654e6dba9a81d9f3a08 100644 --- a/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php +++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php @@ -4,7 +4,6 @@ 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 @@ public function testBundleFieldCreateDeleteWithExistingEntities() { ->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(); } }