<?php namespace Doctrine\Tests\DBAL\Functional; use Doctrine\DBAL\Driver\ExceptionConverterDriver; use Doctrine\DBAL\Exception; use Doctrine\DBAL\Schema\Table; use function array_merge; use function chmod; use function defined; use function file_exists; use function sprintf; use function sys_get_temp_dir; use function touch; use function unlink; class ExceptionTest extends \Doctrine\Tests\DbalFunctionalTestCase { protected function setUp() { parent::setUp(); if ( !($this->_conn->getDriver() instanceof ExceptionConverterDriver)) { $this->markTestSkipped('Driver does not support special exception handling.'); } } public function testPrimaryConstraintViolationException() { $table = new \Doctrine\DBAL\Schema\Table("duplicatekey_table"); $table->addColumn('id', 'integer', array()); $table->setPrimaryKey(array('id')); $this->_conn->getSchemaManager()->createTable($table); $this->_conn->insert("duplicatekey_table", array('id' => 1)); $this->expectException(Exception\UniqueConstraintViolationException::class); $this->_conn->insert("duplicatekey_table", array('id' => 1)); } public function testTableNotFoundException() { $sql = "SELECT * FROM unknown_table"; $this->expectException(Exception\TableNotFoundException::class); $this->_conn->executeQuery($sql); } public function testTableExistsException() { $schemaManager = $this->_conn->getSchemaManager(); $table = new \Doctrine\DBAL\Schema\Table("alreadyexist_table"); $table->addColumn('id', 'integer', array()); $table->setPrimaryKey(array('id')); $this->expectException(Exception\TableExistsException::class); $schemaManager->createTable($table); $schemaManager->createTable($table); } public function testForeignKeyConstraintViolationExceptionOnInsert() { if ( ! $this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped("Only fails on platforms with foreign key constraints."); } $this->setUpForeignKeyConstraintViolationExceptionTest(); try { $this->_conn->insert("constraint_error_table", array('id' => 1)); $this->_conn->insert("owning_table", array('id' => 1, 'constraint_id' => 1)); } catch (\Exception $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->expectException(Exception\ForeignKeyConstraintViolationException::class); try { $this->_conn->insert('owning_table', array('id' => 2, 'constraint_id' => 2)); } catch (Exception\ForeignKeyConstraintViolationException $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } catch (\Exception $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->tearDownForeignKeyConstraintViolationExceptionTest(); } public function testForeignKeyConstraintViolationExceptionOnUpdate() { if ( ! $this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped("Only fails on platforms with foreign key constraints."); } $this->setUpForeignKeyConstraintViolationExceptionTest(); try { $this->_conn->insert("constraint_error_table", array('id' => 1)); $this->_conn->insert("owning_table", array('id' => 1, 'constraint_id' => 1)); } catch (\Exception $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->expectException(Exception\ForeignKeyConstraintViolationException::class); try { $this->_conn->update('constraint_error_table', array('id' => 2), array('id' => 1)); } catch (Exception\ForeignKeyConstraintViolationException $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } catch (\Exception $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->tearDownForeignKeyConstraintViolationExceptionTest(); } public function testForeignKeyConstraintViolationExceptionOnDelete() { if ( ! $this->_conn->getDatabasePlatform()->supportsForeignKeyConstraints()) { $this->markTestSkipped("Only fails on platforms with foreign key constraints."); } $this->setUpForeignKeyConstraintViolationExceptionTest(); try { $this->_conn->insert("constraint_error_table", array('id' => 1)); $this->_conn->insert("owning_table", array('id' => 1, 'constraint_id' => 1)); } catch (\Exception $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->expectException(Exception\ForeignKeyConstraintViolationException::class); try { $this->_conn->delete('constraint_error_table', array('id' => 1)); } catch (Exception\ForeignKeyConstraintViolationException $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } catch (\Exception $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->tearDownForeignKeyConstraintViolationExceptionTest(); } public function testForeignKeyConstraintViolationExceptionOnTruncate() { $platform = $this->_conn->getDatabasePlatform(); if (!$platform->supportsForeignKeyConstraints()) { $this->markTestSkipped("Only fails on platforms with foreign key constraints."); } $this->setUpForeignKeyConstraintViolationExceptionTest(); try { $this->_conn->insert("constraint_error_table", array('id' => 1)); $this->_conn->insert("owning_table", array('id' => 1, 'constraint_id' => 1)); } catch (\Exception $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->expectException(Exception\ForeignKeyConstraintViolationException::class); try { $this->_conn->executeUpdate($platform->getTruncateTableSQL('constraint_error_table')); } catch (Exception\ForeignKeyConstraintViolationException $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } catch (\Exception $exception) { $this->tearDownForeignKeyConstraintViolationExceptionTest(); throw $exception; } $this->tearDownForeignKeyConstraintViolationExceptionTest(); } public function testNotNullConstraintViolationException() { $schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable("notnull_table"); $table->addColumn('id', 'integer', array()); $table->addColumn('value', 'integer', array('notnull' => true)); $table->setPrimaryKey(array('id')); foreach ($schema->toSql($this->_conn->getDatabasePlatform()) as $sql) { $this->_conn->exec($sql); } $this->expectException(Exception\NotNullConstraintViolationException::class); $this->_conn->insert("notnull_table", array('id' => 1, 'value' => null)); } public function testInvalidFieldNameException() { $schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable("bad_fieldname_table"); $table->addColumn('id', 'integer', array()); foreach ($schema->toSql($this->_conn->getDatabasePlatform()) as $sql) { $this->_conn->exec($sql); } $this->expectException(Exception\InvalidFieldNameException::class); $this->_conn->insert("bad_fieldname_table", array('name' => 5)); } public function testNonUniqueFieldNameException() { $schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable("ambiguous_list_table"); $table->addColumn('id', 'integer'); $table2 = $schema->createTable("ambiguous_list_table_2"); $table2->addColumn('id', 'integer'); foreach ($schema->toSql($this->_conn->getDatabasePlatform()) as $sql) { $this->_conn->exec($sql); } $sql = 'SELECT id FROM ambiguous_list_table, ambiguous_list_table_2'; $this->expectException(Exception\NonUniqueFieldNameException::class); $this->_conn->executeQuery($sql); } public function testUniqueConstraintViolationException() { $schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable("unique_field_table"); $table->addColumn('id', 'integer'); $table->addUniqueIndex(array('id')); foreach ($schema->toSql($this->_conn->getDatabasePlatform()) as $sql) { $this->_conn->exec($sql); } $this->_conn->insert("unique_field_table", array('id' => 5)); $this->expectException(Exception\UniqueConstraintViolationException::class); $this->_conn->insert("unique_field_table", array('id' => 5)); } public function testSyntaxErrorException() { $table = new \Doctrine\DBAL\Schema\Table("syntax_error_table"); $table->addColumn('id', 'integer', array()); $table->setPrimaryKey(array('id')); $this->_conn->getSchemaManager()->createTable($table); $sql = 'SELECT id FRO syntax_error_table'; $this->expectException(Exception\SyntaxErrorException::class); $this->_conn->executeQuery($sql); } /** * @dataProvider getSqLiteOpenConnection */ public function testConnectionExceptionSqLite($mode, $exceptionClass) { if ($this->_conn->getDatabasePlatform()->getName() != 'sqlite') { $this->markTestSkipped("Only fails this way on sqlite"); } $filename = sprintf('%s/%s', sys_get_temp_dir(), 'doctrine_failed_connection_'.$mode.'.db'); if (file_exists($filename)) { chmod($filename, 0200); // make the file writable again, so it can be removed on Windows unlink($filename); } touch($filename); chmod($filename, $mode); $params = array( 'driver' => 'pdo_sqlite', 'path' => $filename, ); $conn = \Doctrine\DBAL\DriverManager::getConnection($params); $schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable("no_connection"); $table->addColumn('id', 'integer'); $this->expectException($exceptionClass); foreach ($schema->toSql($conn->getDatabasePlatform()) as $sql) { $conn->exec($sql); } } public function getSqLiteOpenConnection() { return array( // mode 0 is considered read-only on Windows array(0000, defined('PHP_WINDOWS_VERSION_BUILD') ? Exception\ReadOnlyException::class : Exception\ConnectionException::class), array(0444, Exception\ReadOnlyException::class), ); } /** * @dataProvider getConnectionParams */ public function testConnectionException($params) { if ($this->_conn->getDatabasePlatform()->getName() == 'sqlite') { $this->markTestSkipped("Only skipped if platform is not sqlite"); } if ($this->_conn->getDatabasePlatform()->getName() == 'drizzle') { $this->markTestSkipped("Drizzle does not always support authentication"); } if ($this->_conn->getDatabasePlatform()->getName() == 'postgresql' && isset($params['password'])) { $this->markTestSkipped("Does not work on Travis"); } $defaultParams = $this->_conn->getParams(); $params = array_merge($defaultParams, $params); $conn = \Doctrine\DBAL\DriverManager::getConnection($params); $schema = new \Doctrine\DBAL\Schema\Schema(); $table = $schema->createTable("no_connection"); $table->addColumn('id', 'integer'); $this->expectException(Exception\ConnectionException::class); foreach ($schema->toSql($conn->getDatabasePlatform()) as $sql) { $conn->exec($sql); } } public function getConnectionParams() { return array( array(array('user' => 'not_existing')), array(array('password' => 'really_not')), array(array('host' => 'localnope')), ); } private function setUpForeignKeyConstraintViolationExceptionTest() { $schemaManager = $this->_conn->getSchemaManager(); $table = new Table("constraint_error_table"); $table->addColumn('id', 'integer', array()); $table->setPrimaryKey(array('id')); $owningTable = new Table("owning_table"); $owningTable->addColumn('id', 'integer', array()); $owningTable->addColumn('constraint_id', 'integer', array()); $owningTable->setPrimaryKey(array('id')); $owningTable->addForeignKeyConstraint($table, array('constraint_id'), array('id')); $schemaManager->createTable($table); $schemaManager->createTable($owningTable); } private function tearDownForeignKeyConstraintViolationExceptionTest() { $schemaManager = $this->_conn->getSchemaManager(); $schemaManager->dropTable('owning_table'); $schemaManager->dropTable('constraint_error_table'); } }