Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
doctrine-dbal
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tomáš Trávníček
doctrine-dbal
Commits
c13ee0cc
Commit
c13ee0cc
authored
Feb 08, 2017
by
Marco Pivetta
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'fix/#2636-fix-dropping-in-use-databases-on-sql-server-and-oracledb' into 2.5
Backport #2636 to 2.5.x
parents
d153ef03
50937291
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
136 additions
and
6 deletions
+136
-6
SQLSrvException.php
lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php
+15
-3
OracleSchemaManager.php
lib/Doctrine/DBAL/Schema/OracleSchemaManager.php
+69
-1
SQLServerSchemaManager.php
lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php
+52
-2
No files found.
lib/Doctrine/DBAL/Driver/SQLSrv/SQLSrvException.php
View file @
c13ee0cc
...
...
@@ -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.
...
...
@@ -32,13 +33,24 @@ class SQLSrvException extends DBALException
{
$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
);
}
}
lib/Doctrine/DBAL/Schema/OracleSchemaManager.php
View file @
c13ee0cc
...
...
@@ -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#'
]
)
);
}
}
}
lib/Doctrine/DBAL/Schema/SQLServerSchemaManager.php
View file @
c13ee0cc
...
...
@@ -19,7 +19,8 @@
namespace
Doctrine\DBAL\Schema
;
use
Doctrine\DBAL\Driver\SQLSrv\SQLSrvException
;
use
Doctrine\DBAL\DBALException
;
use
Doctrine\DBAL\Driver\DriverException
;
use
Doctrine\DBAL\Types\Type
;
/**
...
...
@@ -34,6 +35,34 @@ use Doctrine\DBAL\Types\Type;
*/
class
SQLServerSchemaManager
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 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
->
closeActiveDatabaseConnections
(
$database
);
parent
::
dropDatabase
(
$database
);
}
}
/**
* {@inheritdoc}
*/
...
...
@@ -212,7 +241,7 @@ class SQLServerSchemaManager extends AbstractSchemaManager
}
else
{
throw
$e
;
}
}
catch
(
SQLSrv
Exception
$e
)
{
}
catch
(
DBAL
Exception
$e
)
{
if
(
strpos
(
$e
->
getMessage
(),
'SQLSTATE [01000, 15472]'
)
===
0
)
{
return
array
();
}
else
{
...
...
@@ -258,4 +287,25 @@ class SQLServerSchemaManager extends AbstractSchemaManager
WHERE Col.[Name] = "
.
$this
->
_conn
->
quote
(
$column
)
.
" AND Tab.[Name] = "
.
$this
->
_conn
->
quote
(
$table
)
.
"
ORDER BY Col.[Name]"
;
}
/**
* Closes 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 void
*/
private
function
closeActiveDatabaseConnections
(
$database
)
{
$database
=
new
Identifier
(
$database
);
$this
->
_execSql
(
sprintf
(
'ALTER DATABASE %s SET SINGLE_USER WITH ROLLBACK IMMEDIATE'
,
$database
->
getQuotedName
(
$this
->
_platform
)
)
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment