Skip to content

Commit

Permalink
fix dropping inuse databases on SQL Server
Browse files Browse the repository at this point in the history
  • Loading branch information
deeky666 committed Feb 6, 2017
1 parent aec4faf commit 10a12b5
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 7 deletions.
18 changes: 15 additions & 3 deletions lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@

namespace Doctrine\DBAL\Driver\SQLSrv;

use Doctrine\DBAL\DBALException;

class SQLSrvException extends DBALException
use Doctrine\DBAL\Driver\AbstractDriverException;

class SQLSrvException extends AbstractDriverException
{
/**
* Helper method to turn sql server errors into exception.
Expand All @@ -32,13 +33,24 @@ static public function fromSqlSrvErrors()
{
$errors = sqlsrv_errors(SQLSRV_ERR_ERRORS);
$message = "";
$sqlState = null;
$errorCode = null;

foreach ($errors as $error) {
$message .= "SQLSTATE [".$error['SQLSTATE'].", ".$error['code']."]: ". $error['message']."\n";

if (null === $sqlState) {
$sqlState = $error['SQLSTATE'];
}

if (null === $errorCode) {
$errorCode = $error['code'];
}
}
if ( ! $message) {
$message = "SQL Server error occurred but no error message was retrieved from driver.";
}

return new self(rtrim($message));
return new self(rtrim($message), $sqlState, $errorCode);
}
}
16 changes: 16 additions & 0 deletions lib/Doctrine/DBAL/Platforms/SQLServerPlatform.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,22 @@ public function getDropDatabaseSQL($name)
return 'DROP DATABASE ' . $name;
}

/**
* Returns the SQL statement for closing currently active connections on the given database.
*
* This is useful to force DROP DATABASE operations which could fail because of active connections.
*
* @param string $database The name of the database to close currently active connections for.
*
* @return string
*/
public function getCloseActiveDatabaseConnectionsSQL($database)
{
$database = new Identifier($database);

return 'ALTER DATABASE ' . $database->getQuotedName($this) . ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE';
}

/**
* {@inheritDoc}
*/
Expand Down
29 changes: 27 additions & 2 deletions lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

namespace Doctrine\DBAL\Schema;

use Doctrine\DBAL\Driver\SQLSrv\SQLSrvException;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Types\Type;

/**
Expand All @@ -34,6 +34,31 @@
*/
class SQLServerSchemaManager extends AbstractSchemaManager
{
/**
* {@inheritdoc}
*/
public function dropDatabase($database)
{
try {
parent::dropDatabase($database);
} catch (DBALException $exception) {
/** @var \Doctrine\DBAL\Driver\DriverException $exception */
$exception = $exception->getPrevious();

// If we have a error code 3702, the drop database operation failed
// because of active connections on the database.
// To force dropping the database, we first have to close all active connections
// on that database and issue the drop database operation again.
if ($exception->getErrorCode() !== 3702) {
throw $exception;
}

$this->_execSql($this->_platform->getCloseActiveDatabaseConnectionsSQL($database));

parent::dropDatabase($database);
}
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -212,7 +237,7 @@ public function listTableIndexes($table)
} else {
throw $e;
}
} catch (SQLSrvException $e) {
} catch (DBALException $e) {
if (strpos($e->getMessage(), 'SQLSTATE [01000, 15472]') === 0) {
return array();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ public function testDropsDatabaseWithActiveConnections()

$this->assertInstanceOf('Doctrine\DBAL\Driver\Connection', $connection);

unset($connection);

$this->_sm->dropDatabase('test_drop_database');

$this->assertNotContains('test_drop_database', $this->_sm->listDatabases());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,30 @@ public function testSupportsCreateDropDatabase()
$this->assertTrue($this->_platform->supportsCreateDropDatabase());
}

public function testReturnsCloseActiveDatabaseConnectionsSQL()
{
$this->assertSame(
'ALTER DATABASE foo SET SINGLE_USER WITH ROLLBACK IMMEDIATE',
$this->_platform->getCloseActiveDatabaseConnectionsSQL('foo')
);
}

public function testReturnsCloseActiveDatabaseConnectionsSQLForReservedKeyword()
{
$this->assertSame(
'ALTER DATABASE [select] SET SINGLE_USER WITH ROLLBACK IMMEDIATE',
$this->_platform->getCloseActiveDatabaseConnectionsSQL('select')
);
}

public function testReturnsCloseActiveDatabaseConnectionsSQLForQuotedDatabaseName()
{
$this->assertSame(
'ALTER DATABASE [foo] SET SINGLE_USER WITH ROLLBACK IMMEDIATE',
$this->_platform->getCloseActiveDatabaseConnectionsSQL('`foo`')
);
}

public function testSupportsSchemas()
{
$this->assertTrue($this->_platform->supportsSchemas());
Expand Down

0 comments on commit 10a12b5

Please sign in to comment.