From c29fb03b6ed3405c30b63561a2a3d5798e9912d0 Mon Sep 17 00:00:00 2001 From: Cory Rivera Date: Wed, 20 Sep 2023 17:17:54 -0700 Subject: [PATCH] Remove redundant usage of object URNs in database handler (#2245) --- .../Contracts/DetachDatabaseRequest.cs | 4 --- .../Contracts/DropDatabaseRequest.cs | 4 --- .../Contracts/PurgeQueryStoreDataRequest.cs | 4 --- .../ObjectTypes/Database/DatabaseHandler.cs | 30 +++++++++++-------- .../ObjectManagement/DatabaseHandlerTests.cs | 17 ++++++----- 5 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/DetachDatabaseRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/DetachDatabaseRequest.cs index 244671ea..47b03dc3 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/DetachDatabaseRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/DetachDatabaseRequest.cs @@ -11,10 +11,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts { public class DetachDatabaseRequestParams : GeneralRequestDetails { - /// - /// SFC (SMO) URN identifying the object - /// - public string ObjectUrn { get; set; } /// /// The target database name. /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/DropDatabaseRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/DropDatabaseRequest.cs index 28f47f93..63a2b9aa 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/DropDatabaseRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/DropDatabaseRequest.cs @@ -11,10 +11,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts { public class DropDatabaseRequestParams : GeneralRequestDetails { - /// - /// SFC (SMO) URN identifying the object - /// - public string ObjectUrn { get; set; } /// /// The target database name. /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/PurgeQueryStoreDataRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/PurgeQueryStoreDataRequest.cs index 968a59ab..72ab2350 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/PurgeQueryStoreDataRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/Contracts/PurgeQueryStoreDataRequest.cs @@ -11,10 +11,6 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts { public class PurgeQueryStoreDataRequestParams : GeneralRequestDetails { - /// - /// SFC (SMO) URN identifying the object - /// - public string ObjectUrn { get; set; } /// /// The target database name. /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs index 0c7b1439..818abe1e 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs @@ -24,6 +24,7 @@ using System.Collections.Specialized; using Microsoft.SqlTools.SqlCore.Utility; using System.Collections.Concurrent; using Microsoft.Data.SqlClient; +using Microsoft.SqlServer.Management.Sdk.Sfc; namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement { @@ -196,7 +197,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement public override Task InitializeObjectView(InitializeViewRequestParams requestParams) { // create a default data context and database object - using (var dataContainer = CreateDatabaseDataContainer(requestParams.ConnectionUri, requestParams.ObjectUrn, requestParams.IsNewObject, requestParams.Database)) + using (var dataContainer = CreateDatabaseDataContainer(requestParams.ConnectionUri, requestParams.IsNewObject, requestParams.Database)) { if (dataContainer.Server == null) { @@ -418,7 +419,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement public string Detach(DetachDatabaseRequestParams detachParams) { var sqlScript = string.Empty; - using (var dataContainer = CreateDatabaseDataContainer(detachParams.ConnectionUri, detachParams.ObjectUrn, false, detachParams.Database)) + using (var dataContainer = CreateDatabaseDataContainer(detachParams.ConnectionUri, false, detachParams.Database)) { var smoDatabase = dataContainer.SqlDialogSubject as Database; if (smoDatabase != null) @@ -465,7 +466,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement } else { - throw new InvalidOperationException($"Provided URN '{detachParams.ObjectUrn}' did not correspond to an existing database."); + throw new InvalidOperationException($"Could not find database '{detachParams.Database}'."); } } return sqlScript; @@ -496,7 +497,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement { var sqlScript = string.Empty; ConnectionInfo connectionInfo = this.GetConnectionInfo(attachParams.ConnectionUri); - using (var dataContainer = CreateDatabaseDataContainer(attachParams.ConnectionUri, null, true, null)) + using (var dataContainer = CreateDatabaseDataContainer(attachParams.ConnectionUri, true, string.Empty)) { var server = dataContainer.Server!; var originalExecuteMode = server.ConnectionContext.SqlExecutionModes; @@ -552,7 +553,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement public string Drop(DropDatabaseRequestParams dropParams) { var sqlScript = string.Empty; - using (var dataContainer = CreateDatabaseDataContainer(dropParams.ConnectionUri, dropParams.ObjectUrn, false, dropParams.Database)) + using (var dataContainer = CreateDatabaseDataContainer(dropParams.ConnectionUri, false, dropParams.Database)) { var smoDatabase = dataContainer.SqlDialogSubject as Database; if (smoDatabase != null) @@ -624,7 +625,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement } else { - throw new InvalidOperationException($"Provided URN '{dropParams.ObjectUrn}' did not correspond to an existing database."); + throw new InvalidOperationException($"Could not find database '{dropParams.Database}'."); } } return sqlScript; @@ -636,7 +637,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement /// public void PurgeQueryStoreData(PurgeQueryStoreDataRequestParams purgeParams) { - using (var dataContainer = CreateDatabaseDataContainer(purgeParams.ConnectionUri, purgeParams.ObjectUrn, false, purgeParams.Database)) + using (var dataContainer = CreateDatabaseDataContainer(purgeParams.ConnectionUri, false, purgeParams.Database)) { var smoDatabase = dataContainer.SqlDialogSubject as Database; if (smoDatabase != null) @@ -646,25 +647,28 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement } } - private CDataContainer CreateDatabaseDataContainer(string connectionUri, string? objectURN, bool isNewDatabase, string? databaseName) + private CDataContainer CreateDatabaseDataContainer(string connectionUri, bool isNewDatabase, string databaseName) { ConnectionInfo connectionInfo = this.GetConnectionInfo(connectionUri); var originalDatabaseName = connectionInfo.ConnectionDetails.DatabaseName; try { + string objectURN; if (!isNewDatabase && !string.IsNullOrEmpty(databaseName)) { connectionInfo.ConnectionDetails.DatabaseName = databaseName; + objectURN = string.Format(System.Globalization.CultureInfo.InvariantCulture, "Server/Database[@Name='{0}']", Urn.EscapeString(databaseName)); + } + else + { + objectURN = "Server"; } CDataContainer dataContainer = CDataContainer.CreateDataContainer(connectionInfo, databaseExists: !isNewDatabase); if (dataContainer.Server == null) { throw new InvalidOperationException(serverNotExistsError); } - if (string.IsNullOrEmpty(objectURN)) - { - objectURN = string.Format(System.Globalization.CultureInfo.InvariantCulture, "Server"); - } + dataContainer.SqlDialogSubject = dataContainer.Server.GetSmoObject(objectURN); return dataContainer; } @@ -681,7 +685,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement throw new ArgumentException("Database name not provided."); } - using (var dataContainer = CreateDatabaseDataContainer(viewParams.ConnectionUri, viewParams.ObjectUrn, viewParams.IsNewObject, viewParams.Database)) + using (var dataContainer = CreateDatabaseDataContainer(viewParams.ConnectionUri, viewParams.IsNewObject, viewParams.Database)) { if (dataContainer.Server == null) { diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs index 0892a90c..4cc54648 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs @@ -65,11 +65,11 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement try { // create and update - var parametersForCreation = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Database, "", ""); + var parametersForCreation = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, testDatabase.Name, true, SqlObjectType.Database, "", ""); await ObjectManagementTestUtils.SaveObject(parametersForCreation, testDatabase); Assert.That(DatabaseExists(testDatabase.Name!, server), $"Expected database '{testDatabase.Name}' was not created succesfully"); - var parametersForUpdate = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", false, SqlObjectType.Database, "", objUrn); + var parametersForUpdate = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, testDatabase.Name, false, SqlObjectType.Database, "", objUrn); await ObjectManagementTestUtils.SaveObject(parametersForUpdate, testDatabase); // cleanup @@ -532,7 +532,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement var detachParams = new DetachDatabaseRequestParams() { ConnectionUri = connectionUri, - ObjectUrn = objUrn, + Database = testDatabase.Name, DropConnections = true, UpdateStatistics = true, GenerateScript = false @@ -596,7 +596,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement var detachParams = new DetachDatabaseRequestParams() { ConnectionUri = connectionUri, - ObjectUrn = objUrn, + Database = testDatabase.Name, DropConnections = false, UpdateStatistics = false, GenerateScript = true @@ -759,7 +759,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement var deleteParams = new DropDatabaseRequestParams() { ConnectionUri = connectionUri, - ObjectUrn = objUrn, + Database = testDatabase.Name, DropConnections = false, DeleteBackupHistory = false, GenerateScript = false @@ -802,7 +802,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement var deleteParams = new DropDatabaseRequestParams() { ConnectionUri = connectionUri, - ObjectUrn = objUrn, + Database = testDatabase.Name, DropConnections = false, DeleteBackupHistory = false, GenerateScript = true @@ -863,7 +863,10 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement { if (db.Name == databaseName) { - db.DropIfExists(); + // Set database to single user mode to close any active connections + db.DatabaseOptions.UserAccess = SqlServer.Management.Smo.DatabaseUserAccess.Single; + db.Alter(TerminationClause.RollbackTransactionsImmediately); + db.Drop(); break; } }