diff --git a/core/lib/Drupal/Core/Config/DatabaseStorage.php b/core/lib/Drupal/Core/Config/DatabaseStorage.php index c40e70ee224cc4704e550e0f0e4380cc51615b08..4430298da39ed91119d22da0384ac73c8ac9a719 100644 --- a/core/lib/Drupal/Core/Config/DatabaseStorage.php +++ b/core/lib/Drupal/Core/Config/DatabaseStorage.php @@ -72,8 +72,11 @@ public function exists($name) { ], $this->options)->fetchField(); } catch (\Exception $e) { - // If we attempt a read without actually having the database or the table - // available, just return FALSE so the caller can handle it. + if ($this->connection->schema()->tableExists($this->table)) { + throw $e; + } + // If we attempt a read without actually having the table available, + // return false so the caller can handle it. return FALSE; } } @@ -90,8 +93,11 @@ public function read($name) { } } catch (\Exception $e) { - // If we attempt a read without actually having the database or the table - // available, just return FALSE so the caller can handle it. + if ($this->connection->schema()->tableExists($this->table)) { + throw $e; + } + // If we attempt a read without actually having the table available, + // return false so the caller can handle it. } return $data; } @@ -108,8 +114,11 @@ public function readMultiple(array $names) { } } catch (\Exception $e) { - // If we attempt a read without actually having the database or the table - // available, just return an empty array so the caller can handle it. + if ($this->connection->schema()->tableExists($this->table)) { + throw $e; + } + // If we attempt a read without actually having the table available, + // return an empty array so the caller can handle it. } return $list; } @@ -277,6 +286,11 @@ public function listAll($prefix = '') { return $query->execute()->fetchCol(); } catch (\Exception $e) { + if ($this->connection->schema()->tableExists($this->table)) { + throw $e; + } + // If we attempt a read without actually having the table available, + // return an empty array so the caller can handle it. return []; } } @@ -295,6 +309,11 @@ public function deleteAll($prefix = '') { ->execute(); } catch (\Exception $e) { + if ($this->connection->schema()->tableExists($this->table)) { + throw $e; + } + // If we attempt a delete without actually having the table available, + // return false so the caller can handle it. return FALSE; } } @@ -328,6 +347,11 @@ public function getAllCollectionNames() { ])->fetchCol(); } catch (\Exception $e) { + if ($this->connection->schema()->tableExists($this->table)) { + throw $e; + } + // If we attempt a read without actually having the table available, + // return an empty array so the caller can handle it. return []; } } diff --git a/core/tests/Drupal/KernelTests/Core/Config/Storage/DatabaseStorageTest.php b/core/tests/Drupal/KernelTests/Core/Config/Storage/DatabaseStorageTest.php index 11e827bf73a4e68cbfe0d1dda47d59756dd7b537..5f6e787c41d0dca6a22dd33f1cde6174c74338b0 100644 --- a/core/tests/Drupal/KernelTests/Core/Config/Storage/DatabaseStorageTest.php +++ b/core/tests/Drupal/KernelTests/Core/Config/Storage/DatabaseStorageTest.php @@ -4,6 +4,7 @@ use Drupal\Core\Config\DatabaseStorage; use Drupal\Core\Database\Database; +use Drupal\Core\Database\DatabaseExceptionWrapper; /** * Tests DatabaseStorage operations. @@ -39,4 +40,87 @@ protected function delete($name) { Database::getConnection()->delete('config')->condition('name', $name)->execute(); } + /** + * Tests that operations throw exceptions if the query fails. + */ + public function testExceptionIsThrownIfQueryFails() { + $connection = Database::getConnection(); + if ($connection->databaseType() === 'sqlite') { + // See: https://www.drupal.org/project/drupal/issues/3349286 + $this->markTestSkipped('SQLite cannot allow detection of exceptions due to double quoting.'); + return; + } + + Database::getConnection()->schema()->dropTable('config'); + // In order to simulate database issue create a table with an incorrect + // specification. + $table_specification = [ + 'fields' => [ + 'id' => [ + 'type' => 'int', + 'default' => NULL, + ], + ], + ]; + Database::getConnection()->schema()->createTable('config', $table_specification); + + try { + $this->storage->exists('config.settings'); + $this->fail('Expected exception not thrown from exists()'); + } + catch (DatabaseExceptionWrapper $e) { + // Exception was expected + } + + try { + $this->storage->read('config.settings'); + $this->fail('Expected exception not thrown from read()'); + } + catch (DatabaseExceptionWrapper $e) { + // Exception was expected + } + + try { + $this->storage->readMultiple(['config.settings', 'config.settings2']); + $this->fail('Expected exception not thrown from readMultiple()'); + } + catch (DatabaseExceptionWrapper $e) { + // Exception was expected + } + + try { + $this->storage->write('config.settings', ['data' => '']); + $this->fail('Expected exception not thrown from deleteAll()'); + } + catch (DatabaseExceptionWrapper $e) { + // Exception was expected + } + + try { + $this->storage->listAll(); + $this->fail('Expected exception not thrown from listAll()'); + } + catch (DatabaseExceptionWrapper $e) { + // Exception was expected + } + + try { + $this->storage->deleteAll(); + $this->fail('Expected exception not thrown from deleteAll()'); + } + catch (DatabaseExceptionWrapper $e) { + // Exception was expected + } + + try { + $this->storage->getAllCollectionNames(); + $this->fail('Expected exception not thrown from getAllCollectionNames()'); + } + catch (DatabaseExceptionWrapper $e) { + // Exception was expected + } + + $this->assertTrue(TRUE); + } + }