Skip to content

Commit bd29d17

Browse files
committed
Remove the functionality of dropping client connections when dropping a database
1 parent 4aa632a commit bd29d17

File tree

9 files changed

+6
-282
lines changed

9 files changed

+6
-282
lines changed

UPGRADE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Upgrade to 3.0
22

3+
## BC BREAK: change in the behavior of `SchemaManager::dropDatabase()`
4+
5+
When dropping a database, the DBAL no longer attempts to kill the client sessions that use the database.
6+
It's the responsibility of the operator to make sure that the database is not being used.
7+
38
## BC BREAK: removed `Synchronizer` package
49

510
The `Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer` interface and all its implementations have been removed.
@@ -157,6 +162,7 @@ The `Doctrine\DBAL\Driver::getName()` has been removed.
157162
* Removed `Connection::TRANSACTION_*` constants.
158163
* Removed `AbstractPlatform::DATE_INTERVAL_UNIT_*` and `AbstractPlatform::TRIM_*` constants.
159164
* Removed `AbstractPlatform::getSQLResultCasing()`, `::prefersSequences()` and `::supportsForeignKeyOnUpdate()` methods.
165+
* Removed `PostgreSqlPlatform::getDisallowDatabaseConnectionsSQL()` and `::getCloseActiveDatabaseConnectionsSQL()` methods.
160166
* Removed `MysqlSessionInit` listener.
161167
* Removed `MysqlPlatform::getCollationFieldDeclaration()`.
162168
* Removed `AbstractPlatform::getIdentityColumnNullInsertSQL()`.

src/Platforms/PostgreSQL94Platform.php

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -431,39 +431,6 @@ public function getCreateDatabaseSQL($name)
431431
return 'CREATE DATABASE ' . $name;
432432
}
433433

434-
/**
435-
* Returns the SQL statement for disallowing new connections on the given database.
436-
*
437-
* This is useful to force DROP DATABASE operations which could fail because of active connections.
438-
*
439-
* @deprecated
440-
*
441-
* @param string $database The name of the database to disallow new connections for.
442-
*
443-
* @return string
444-
*/
445-
public function getDisallowDatabaseConnectionsSQL($database)
446-
{
447-
return "UPDATE pg_database SET datallowconn = 'false' WHERE datname = " . $this->quoteStringLiteral($database);
448-
}
449-
450-
/**
451-
* Returns the SQL statement for closing currently active connections on the given database.
452-
*
453-
* This is useful to force DROP DATABASE operations which could fail because of active connections.
454-
*
455-
* @deprecated
456-
*
457-
* @param string $database The name of the database to close currently active connections for.
458-
*
459-
* @return string
460-
*/
461-
public function getCloseActiveDatabaseConnectionsSQL($database)
462-
{
463-
return 'SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '
464-
. $this->quoteStringLiteral($database);
465-
}
466-
467434
/**
468435
* {@inheritDoc}
469436
*/

src/Schema/OracleSchemaManager.php

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,16 @@
33
namespace Doctrine\DBAL\Schema;
44

55
use Doctrine\DBAL\DBALException;
6-
use Doctrine\DBAL\Driver\Exception;
76
use Doctrine\DBAL\Platforms\OraclePlatform;
87
use Doctrine\DBAL\Types\Type;
9-
use Throwable;
108

119
use function array_change_key_case;
1210
use function array_values;
1311
use function assert;
1412
use function preg_match;
15-
use function sprintf;
1613
use function str_replace;
1714
use function strpos;
1815
use function strtolower;
19-
use function strtoupper;
2016
use function trim;
2117

2218
use const CASE_LOWER;
@@ -26,35 +22,6 @@
2622
*/
2723
class OracleSchemaManager extends AbstractSchemaManager
2824
{
29-
/**
30-
* {@inheritdoc}
31-
*/
32-
public function dropDatabase($database)
33-
{
34-
try {
35-
parent::dropDatabase($database);
36-
} catch (DBALException $exception) {
37-
$exception = $exception->getPrevious();
38-
assert($exception instanceof Throwable);
39-
40-
if (! $exception instanceof Exception) {
41-
throw $exception;
42-
}
43-
44-
// If we have a error code 1940 (ORA-01940), the drop database operation failed
45-
// because of active connections on the database.
46-
// To force dropping the database, we first have to close all active connections
47-
// on that database and issue the drop database operation again.
48-
if ($exception->getCode() !== 1940) {
49-
throw $exception;
50-
}
51-
52-
$this->killUserSessions($database);
53-
54-
parent::dropDatabase($database);
55-
}
56-
}
57-
5825
/**
5926
* {@inheritdoc}
6027
*/
@@ -341,46 +308,6 @@ private function getQuotedIdentifierName($identifier)
341308
return $identifier;
342309
}
343310

344-
/**
345-
* Kills sessions connected with the given user.
346-
*
347-
* This is useful to force DROP USER operations which could fail because of active user sessions.
348-
*
349-
* @param string $user The name of the user to kill sessions for.
350-
*
351-
* @return void
352-
*
353-
* @throws DBALException
354-
*/
355-
private function killUserSessions($user)
356-
{
357-
$sql = <<<SQL
358-
SELECT
359-
s.sid,
360-
s.serial#
361-
FROM
362-
gv\$session s,
363-
gv\$process p
364-
WHERE
365-
s.username = ?
366-
AND p.addr(+) = s.paddr
367-
SQL;
368-
369-
$activeUserSessions = $this->_conn->fetchAllAssociative($sql, [strtoupper($user)]);
370-
371-
foreach ($activeUserSessions as $activeUserSession) {
372-
$activeUserSession = array_change_key_case($activeUserSession, CASE_LOWER);
373-
374-
$this->_execSql(
375-
sprintf(
376-
"ALTER SYSTEM KILL SESSION '%s, %s' IMMEDIATE",
377-
$activeUserSession['sid'],
378-
$activeUserSession['serial#']
379-
)
380-
);
381-
}
382-
}
383-
384311
/**
385312
* {@inheritdoc}
386313
*/

src/Schema/PostgreSqlSchemaManager.php

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Doctrine\DBAL\Schema;
44

55
use Doctrine\DBAL\DBALException;
6-
use Doctrine\DBAL\Exception\DriverException;
76
use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
87
use Doctrine\DBAL\Types\Type;
98
use Doctrine\DBAL\Types\Types;
@@ -98,35 +97,6 @@ public function determineExistingSchemaSearchPaths()
9897
});
9998
}
10099

101-
/**
102-
* {@inheritdoc}
103-
*/
104-
public function dropDatabase($database)
105-
{
106-
try {
107-
parent::dropDatabase($database);
108-
} catch (DriverException $exception) {
109-
// If we have a SQLSTATE 55006, the drop database operation failed
110-
// because of active connections on the database.
111-
// To force dropping the database, we first have to close all active connections
112-
// on that database and issue the drop database operation again.
113-
if ($exception->getSQLState() !== '55006') {
114-
throw $exception;
115-
}
116-
117-
assert($this->_platform instanceof PostgreSQL94Platform);
118-
119-
$this->_execSql(
120-
[
121-
$this->_platform->getDisallowDatabaseConnectionsSQL($database),
122-
$this->_platform->getCloseActiveDatabaseConnectionsSQL($database),
123-
]
124-
);
125-
126-
parent::dropDatabase($database);
127-
}
128-
}
129-
130100
/**
131101
* {@inheritdoc}
132102
*/

src/Schema/SQLServerSchemaManager.php

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@
33
namespace Doctrine\DBAL\Schema;
44

55
use Doctrine\DBAL\DBALException;
6-
use Doctrine\DBAL\Driver\Exception;
76
use Doctrine\DBAL\Platforms\SQLServer2012Platform;
87
use Doctrine\DBAL\Types\Type;
98
use PDOException;
10-
use Throwable;
119

1210
use function assert;
1311
use function count;
@@ -23,35 +21,6 @@
2321
*/
2422
class SQLServerSchemaManager extends AbstractSchemaManager
2523
{
26-
/**
27-
* {@inheritdoc}
28-
*/
29-
public function dropDatabase($database)
30-
{
31-
try {
32-
parent::dropDatabase($database);
33-
} catch (DBALException $exception) {
34-
$exception = $exception->getPrevious();
35-
assert($exception instanceof Throwable);
36-
37-
if (! $exception instanceof Exception) {
38-
throw $exception;
39-
}
40-
41-
// If we have a error code 3702, the drop database operation failed
42-
// because of active connections on the database.
43-
// To force dropping the database, we first have to close all active connections
44-
// on that database and issue the drop database operation again.
45-
if ($exception->getCode() !== 3702) {
46-
throw $exception;
47-
}
48-
49-
$this->closeActiveDatabaseConnections($database);
50-
51-
parent::dropDatabase($database);
52-
}
53-
}
54-
5524
/**
5625
* {@inheritdoc}
5726
*/
@@ -313,29 +282,6 @@ private function getColumnConstraintSQL($table, $column)
313282
ORDER BY Col.[Name]';
314283
}
315284

316-
/**
317-
* Closes currently active connections on the given database.
318-
*
319-
* This is useful to force DROP DATABASE operations which could fail because of active connections.
320-
*
321-
* @param string $database The name of the database to close currently active connections for.
322-
*
323-
* @return void
324-
*
325-
* @throws DBALException
326-
*/
327-
private function closeActiveDatabaseConnections($database)
328-
{
329-
$database = new Identifier($database);
330-
331-
$this->_execSql(
332-
sprintf(
333-
'ALTER DATABASE %s SET SINGLE_USER WITH ROLLBACK IMMEDIATE',
334-
$database->getQuotedName($this->_platform)
335-
)
336-
);
337-
}
338-
339285
/**
340286
* @param string $name
341287
*

tests/Functional/Schema/SchemaManagerFunctionalTestCase.php

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44

55
use Doctrine\Common\EventManager;
66
use Doctrine\DBAL\DBALException;
7-
use Doctrine\DBAL\Driver\Connection;
87
use Doctrine\DBAL\Events;
9-
use Doctrine\DBAL\Platforms\OraclePlatform;
108
use Doctrine\DBAL\Schema\AbstractAsset;
119
use Doctrine\DBAL\Schema\AbstractSchemaManager;
1210
use Doctrine\DBAL\Schema\Column;
@@ -92,43 +90,6 @@ protected function tearDown(): void
9290
}
9391
}
9492

95-
public function testDropsDatabaseWithActiveConnections(): void
96-
{
97-
$platform = $this->schemaManager->getDatabasePlatform();
98-
99-
if (! $platform->supportsCreateDropDatabase()) {
100-
self::markTestSkipped('Cannot drop Database client side with this Driver.');
101-
}
102-
103-
if ($platform instanceof OraclePlatform) {
104-
$this->markTestIncomplete('This functionality is not properly implemented in the Oracle platform.');
105-
}
106-
107-
$this->schemaManager->dropAndCreateDatabase('test_drop_database');
108-
109-
$knownDatabases = $this->schemaManager->listDatabases();
110-
if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
111-
self::assertContains('TEST_DROP_DATABASE', $knownDatabases);
112-
} else {
113-
self::assertContains('test_drop_database', $knownDatabases);
114-
}
115-
116-
$params = $this->connection->getParams();
117-
if ($this->connection->getDatabasePlatform() instanceof OraclePlatform) {
118-
$params['user'] = 'test_drop_database';
119-
} else {
120-
$params['dbname'] = 'test_drop_database';
121-
}
122-
123-
$connection = $this->connection->getDriver()->connect($params);
124-
125-
self::assertInstanceOf(Connection::class, $connection);
126-
127-
$this->schemaManager->dropDatabase('test_drop_database');
128-
129-
self::assertNotContains('test_drop_database', $this->schemaManager->listDatabases());
130-
}
131-
13293
public function testDropAndCreateSequence(): void
13394
{
13495
$platform = $this->connection->getDatabasePlatform();

tests/Functional/Schema/SqliteSchemaManagerTest.php

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Doctrine\DBAL\Tests\Functional\Schema;
44

55
use Doctrine\DBAL\DBALException;
6-
use Doctrine\DBAL\Driver\Connection;
76
use Doctrine\DBAL\Schema;
87
use Doctrine\DBAL\Schema\Table;
98
use Doctrine\DBAL\Types\BlobType;
@@ -34,26 +33,6 @@ public function testCreateAndDropDatabase(): void
3433
self::assertFileDoesNotExist($path);
3534
}
3635

37-
public function testDropsDatabaseWithActiveConnections(): void
38-
{
39-
$this->schemaManager->dropAndCreateDatabase('test_drop_database');
40-
41-
self::assertFileExists('test_drop_database');
42-
43-
$params = $this->connection->getParams();
44-
$params['dbname'] = 'test_drop_database';
45-
46-
$connection = $this->connection->getDriver()->connect($params);
47-
48-
self::assertInstanceOf(Connection::class, $connection);
49-
50-
$this->schemaManager->dropDatabase('test_drop_database');
51-
52-
self::assertFileDoesNotExist('test_drop_database');
53-
54-
unset($connection);
55-
}
56-
5736
public function testRenameTable(): void
5837
{
5938
$this->createTestTable('oldname');

0 commit comments

Comments
 (0)