Commit 50937291 authored by Steve Müller's avatar Steve Müller Committed by Marco Pivetta

fix dropping inuse databases on Oracle

parent 9e00fec3
......@@ -19,6 +19,8 @@
namespace Doctrine\DBAL\Schema;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Driver\DriverException;
use Doctrine\DBAL\Types\Type;
/**
......@@ -31,6 +33,34 @@ use Doctrine\DBAL\Types\Type;
*/
class OracleSchemaManager extends AbstractSchemaManager
{
/**
* {@inheritdoc}
*/
public function dropDatabase($database)
{
try {
parent::dropDatabase($database);
} catch (DBALException $exception) {
$exception = $exception->getPrevious();
if (! $exception instanceof DriverException) {
throw $exception;
}
// If we have a error code 1940 (ORA-01940), 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() !== 1940) {
throw $exception;
}
$this->killUserSessions($database);
parent::dropDatabase($database);
}
}
/**
* {@inheritdoc}
*/
......@@ -305,7 +335,7 @@ class OracleSchemaManager extends AbstractSchemaManager
$query = 'CREATE USER ' . $username . ' IDENTIFIED BY ' . $password;
$this->_conn->executeUpdate($query);
$query = 'GRANT CREATE SESSION, CREATE TABLE, UNLIMITED TABLESPACE, CREATE SEQUENCE, CREATE TRIGGER TO ' . $username;
$query = 'GRANT DBA TO ' . $username;
$this->_conn->executeUpdate($query);
return true;
......@@ -354,4 +384,42 @@ class OracleSchemaManager extends AbstractSchemaManager
return $identifier;
}
/**
* Kills sessions connected with the given user.
*
* This is useful to force DROP USER operations which could fail because of active user sessions.
*
* @param string $user The name of the user to kill sessions for.
*
* @return void
*/
private function killUserSessions($user)
{
$sql = <<<SQL
SELECT
s.sid,
s.serial#
FROM
gv\$session s,
gv\$process p
WHERE
s.username = ?
AND p.addr(+) = s.paddr
SQL;
$activeUserSessions = $this->_conn->fetchAll($sql, array(strtoupper($user)));
foreach ($activeUserSessions as $activeUserSession) {
$activeUserSession = array_change_key_case($activeUserSession, \CASE_LOWER);
$this->_execSql(
sprintf(
"ALTER SYSTEM KILL SESSION '%s, %s' IMMEDIATE",
$activeUserSession['sid'],
$activeUserSession['serial#']
)
);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment