Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dropping in use databases on SQL Server and Oracle #2636

Merged

Conversation

deeky666
Copy link
Member

@deeky666 deeky666 commented Feb 6, 2017

This patch follows the same approach as for PostgreSQL. If trying to drop a database with active connections, the database server will refuse with:

SQLSTATE [42000, 3702]: [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]Cannot drop database "%s" because it is currently in use.

The schema manager catches that specific error code now, closes all active connections on that database and executes a DROP DATABASE again.

I had to fix the SQLSrvException to carry around the SQLSTATE and error code information.

throw $exception;
}

$this->_execSql($this->_platform->getCloseActiveDatabaseConnectionsSQL($database));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call on a method not defined on the abstract class

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as with PostgreSQL. What shall I do here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@deeky666 one possible solution is to turn the return type into a string[], then have a base method always returning an empty array. array_walk-ing over the result is sufficient to ensure consistency then.

// 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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move it to a constant, please (and document the constant)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree here. It doesn't help anyone and if we start to introduce constants for all error codes and SQL states, we will go crazy. We started with this approach when we implemented driver exception converters and discarded that approach again. This check will disappear as soon as we implement SQL Server driver as driver exception converter drivers (hopefully) as we will be able to catch a dedicated exception type then. Also it is implemented that way for PostgreSQL already and I don't want to do everything that is necessary to make it "perfect" with this PR. First I want to get the SQL Server test suite to be green. We can still improve afterwards. What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works for me, since there is inline documentation. Also, didn't expect you to fix every instance in here.

If/when we move to PHP 7.1, then we should consider private constants.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@@ -37,6 +37,31 @@ class SQLServerSchemaManager extends AbstractSchemaManager
/**
* {@inheritdoc}
*/
public function dropDatabase($database)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code additions here are untested. Can the scenario be replicated?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a test case that covers this issue in SchemaManagerFunctionalTestCase::testDropsDatabaseWithActiveConnections()

*
* @return string
*/
public function getCloseActiveDatabaseConnectionsSQL($database)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should probably land in the parent classes too then (sadly) :-\

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get your point but I do not want to enforce an abstraction here because it probably will be too vendor specific. Another option would be to put the SQL directly into the dropDatabase() method in the schema manager.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly a better solution if the schema manager is platform specific (and won't rely on the platform abstraction anyway).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is a "yes" let's put the SQL directly into the schema manager?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let's stuff it in the schema manager, and add a comment about the decision

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

*/
public function getCloseActiveDatabaseConnectionsSQL($database)
{
return 'ALTER DATABASE ' . $database . ' SET SINGLE_USER WITH ROLLBACK IMMEDIATE';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should $database be quoted?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Identifier now.

@deeky666 deeky666 force-pushed the fix-sqlserver-drop-inuse-database branch from 85a2d60 to 10a12b5 Compare February 6, 2017 18:42
@deeky666 deeky666 force-pushed the fix-sqlserver-drop-inuse-database branch 2 times, most recently from 79b449f to 7b631e7 Compare February 7, 2017 15:31
@deeky666 deeky666 changed the title Fix dropping inuse databases on SQL Server [WIP] Fix dropping inuse databases on SQL Server Feb 7, 2017
@deeky666
Copy link
Member Author

deeky666 commented Feb 7, 2017

@Ocramius marking this as WIP for now as I still need to figure out how to make nasty Oracle pass here. I am testing against version 12 locally and there seem to be some difference to version 11 (CI).

@deeky666
Copy link
Member Author

deeky666 commented Feb 7, 2017

Documented an issue revealed while testing with Orcale 12c in #2643
The issue is unrelated and should not be fixed here.

@deeky666 deeky666 force-pushed the fix-sqlserver-drop-inuse-database branch from ece24a2 to ef736a5 Compare February 7, 2017 20:26
@deeky666 deeky666 changed the title [WIP] Fix dropping inuse databases on SQL Server [WIP] Fix dropping inuse databases on SQL Server ans Oracle Feb 7, 2017
@deeky666 deeky666 changed the title [WIP] Fix dropping inuse databases on SQL Server ans Oracle [WIP] Fix dropping inuse databases on SQL Server and Oracle Feb 7, 2017
@deeky666 deeky666 changed the title [WIP] Fix dropping inuse databases on SQL Server and Oracle Fix dropping inuse databases on SQL Server and Oracle Feb 7, 2017
@deeky666
Copy link
Member Author

deeky666 commented Feb 7, 2017

@Ocramius ok patch is finished from my side now. You can review again. Some remarks:

Obviously I had to fix the exact same issue on Oracle to make the tests pass. Approach is the same. I also had to change the privileges when creating a new database (user) on Oracle so that the user is able to see the views used in killUserSessions() when force dropping a database. That should not be an issue though, as users created by DBAL are not used as users but as databases (that is still confusing after all). Please blame Oracle. Thanks. BYEEEEE!

@Ocramius
Copy link
Member

Ocramius commented Feb 8, 2017

LGTM! 👍

@Ocramius Ocramius added this to the 2.5.12 milestone Feb 8, 2017
@Ocramius Ocramius merged commit 7e0a6cc into doctrine:master Feb 8, 2017
@Ocramius Ocramius changed the title Fix dropping inuse databases on SQL Server and Oracle Fix dropping in use databases on SQL Server and Oracle Feb 8, 2017
Ocramius added a commit that referenced this pull request Feb 8, 2017
@Ocramius
Copy link
Member

Ocramius commented Feb 8, 2017

Backported into 2.5 via c13ee0c

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants