From d5cfc52ca75c2fda279cb374e84c62f0b0ea61ea Mon Sep 17 00:00:00 2001 From: Cory Rivera Date: Wed, 31 May 2023 12:55:12 -0700 Subject: [PATCH] Add object management handler for creating a database (#2071) --- .../Localization/sr.cs | 1507 +++++++++++++++++ .../Localization/sr.resx | 548 ++++++ .../Localization/sr.strings | 140 ++ .../Localization/sr.xlf | 685 ++++++++ .../ObjectTypes/Database/DatabaseActions.cs | 38 + .../ObjectTypes/Database/DatabaseHandler.cs | 557 +++++- .../ObjectTypes/Database/DatabaseViewInfo.cs | 18 + .../ObjectManagement/DatabaseHandlerTests.cs | 193 +++ .../ObjectManagementTestUtils.cs | 34 +- 9 files changed, 3712 insertions(+), 8 deletions(-) create mode 100644 src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseActions.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseViewInfo.cs create mode 100644 test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs index 13638cff..0fee0153 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs @@ -11341,6 +11341,1102 @@ namespace Microsoft.SqlTools.ServiceLayer } } + public static string autogrowth_dialog_title + { + get + { + return Keys.GetString(Keys.autogrowth_dialog_title); + } + } + + public static string autogrowth_dialog_filestreamtitle + { + get + { + return Keys.GetString(Keys.autogrowth_dialog_filestreamtitle); + } + } + + public static string autogrowth_dialog_defaulttitle + { + get + { + return Keys.GetString(Keys.autogrowth_dialog_defaulttitle); + } + } + + public static string autogrowth_dialog_defaultfilestreamtitle + { + get + { + return Keys.GetString(Keys.autogrowth_dialog_defaultfilestreamtitle); + } + } + + public static string createDatabase_title + { + get + { + return Keys.GetString(Keys.createDatabase_title); + } + } + + public static string error_60compatibility + { + get + { + return Keys.GetString(Keys.error_60compatibility); + } + } + + public static string error_cantModifyExistingFilePath + { + get + { + return Keys.GetString(Keys.error_cantModifyExistingFilePath); + } + } + + public static string error_databaseAlreadyExists + { + get + { + return Keys.GetString(Keys.error_databaseAlreadyExists); + } + } + + public static string error_databaseProperties_title + { + get + { + return Keys.GetString(Keys.error_databaseProperties_title); + } + } + + public static string error_emptyFileName + { + get + { + return Keys.GetString(Keys.error_emptyFileName); + } + } + + public static string error_fileNameContainsIllegalCharacter + { + get + { + return Keys.GetString(Keys.error_fileNameContainsIllegalCharacter); + } + } + + public static string error_fileNameStartsWithSpace + { + get + { + return Keys.GetString(Keys.error_fileNameStartsWithSpace); + } + } + + public static string error_whitespaceDatabaseName + { + get + { + return Keys.GetString(Keys.error_whitespaceDatabaseName); + } + } + + public static string filegroup_dialog_defaultFilegroup + { + get + { + return Keys.GetString(Keys.filegroup_dialog_defaultFilegroup); + } + } + + public static string filegroup_dialog_title + { + get + { + return Keys.GetString(Keys.filegroup_dialog_title); + } + } + + public static string filegroups_default + { + get + { + return Keys.GetString(Keys.filegroups_default); + } + } + + public static string filegroups_files + { + get + { + return Keys.GetString(Keys.filegroups_files); + } + } + + public static string filegroups_name + { + get + { + return Keys.GetString(Keys.filegroups_name); + } + } + + public static string filegroups_readonly + { + get + { + return Keys.GetString(Keys.filegroups_readonly); + } + } + + public static string filegroups_autogrowAllFiles + { + get + { + return Keys.GetString(Keys.filegroups_autogrowAllFiles); + } + } + + public static string general_autogrowth + { + get + { + return Keys.GetString(Keys.general_autogrowth); + } + } + + public static string general_builderText + { + get + { + return Keys.GetString(Keys.general_builderText); + } + } + + public static string general_default + { + get + { + return Keys.GetString(Keys.general_default); + } + } + + public static string general_fileGroup + { + get + { + return Keys.GetString(Keys.general_fileGroup); + } + } + + public static string general_fileName + { + get + { + return Keys.GetString(Keys.general_fileName); + } + } + + public static string general_fileType + { + get + { + return Keys.GetString(Keys.general_fileType); + } + } + + public static string general_initialSize + { + get + { + return Keys.GetString(Keys.general_initialSize); + } + } + + public static string general_currentSize + { + get + { + return Keys.GetString(Keys.general_currentSize); + } + } + + public static string general_newFilegroup + { + get + { + return Keys.GetString(Keys.general_newFilegroup); + } + } + + public static string general_path + { + get + { + return Keys.GetString(Keys.general_path); + } + } + + public static string general_physicalFileName + { + get + { + return Keys.GetString(Keys.general_physicalFileName); + } + } + + public static string general_rawDevice + { + get + { + return Keys.GetString(Keys.general_rawDevice); + } + } + + public static string general_recoveryModel_bulkLogged + { + get + { + return Keys.GetString(Keys.general_recoveryModel_bulkLogged); + } + } + + public static string general_recoveryModel_full + { + get + { + return Keys.GetString(Keys.general_recoveryModel_full); + } + } + + public static string general_recoveryModel_simple + { + get + { + return Keys.GetString(Keys.general_recoveryModel_simple); + } + } + + public static string general_titleSearchOwner + { + get + { + return Keys.GetString(Keys.general_titleSearchOwner); + } + } + + public static string leftPane_extendedPropertiesNode_name + { + get + { + return Keys.GetString(Keys.leftPane_extendedPropertiesNode_name); + } + } + + public static string leftPane_filegroupsNode_name + { + get + { + return Keys.GetString(Keys.leftPane_filegroupsNode_name); + } + } + + public static string leftPane_generalNode_name + { + get + { + return Keys.GetString(Keys.leftPane_generalNode_name); + } + } + + public static string leftPane_optionsNode_name + { + get + { + return Keys.GetString(Keys.leftPane_optionsNode_name); + } + } + + public static string leftPane_capabilitiesNode_name + { + get + { + return Keys.GetString(Keys.leftPane_capabilitiesNode_name); + } + } + + public static string leftPane_topNode_name + { + get + { + return Keys.GetString(Keys.leftPane_topNode_name); + } + } + + public static string prototype_autogrowth_disabled + { + get + { + return Keys.GetString(Keys.prototype_autogrowth_disabled); + } + } + + public static string prototype_autogrowth_restrictedGrowthByMB + { + get + { + return Keys.GetString(Keys.prototype_autogrowth_restrictedGrowthByMB); + } + } + + public static string prototype_autogrowth_restrictedGrowthByPercent + { + get + { + return Keys.GetString(Keys.prototype_autogrowth_restrictedGrowthByPercent); + } + } + + public static string prototype_autogrowth_unrestrictedGrowthByMB + { + get + { + return Keys.GetString(Keys.prototype_autogrowth_unrestrictedGrowthByMB); + } + } + + public static string prototype_autogrowth_unrestrictedGrowthByPercent + { + get + { + return Keys.GetString(Keys.prototype_autogrowth_unrestrictedGrowthByPercent); + } + } + + public static string prototype_autogrowth_unlimitedfilestream + { + get + { + return Keys.GetString(Keys.prototype_autogrowth_unlimitedfilestream); + } + } + + public static string prototype_autogrowth_limitedfilestream + { + get + { + return Keys.GetString(Keys.prototype_autogrowth_limitedfilestream); + } + } + + public static string prototype_db_category_automatic + { + get + { + return Keys.GetString(Keys.prototype_db_category_automatic); + } + } + + public static string prototype_db_category_servicebroker + { + get + { + return Keys.GetString(Keys.prototype_db_category_servicebroker); + } + } + + public static string prototype_db_category_collation + { + get + { + return Keys.GetString(Keys.prototype_db_category_collation); + } + } + + public static string prototype_db_category_cursor + { + get + { + return Keys.GetString(Keys.prototype_db_category_cursor); + } + } + + public static string prototype_db_category_misc + { + get + { + return Keys.GetString(Keys.prototype_db_category_misc); + } + } + + public static string prototype_db_category_recovery + { + get + { + return Keys.GetString(Keys.prototype_db_category_recovery); + } + } + + public static string prototype_db_category_state + { + get + { + return Keys.GetString(Keys.prototype_db_category_state); + } + } + + public static string prototype_db_prop_ansiNullDefault + { + get + { + return Keys.GetString(Keys.prototype_db_prop_ansiNullDefault); + } + } + + public static string prototype_db_prop_ansiNulls + { + get + { + return Keys.GetString(Keys.prototype_db_prop_ansiNulls); + } + } + + public static string prototype_db_prop_ansiPadding + { + get + { + return Keys.GetString(Keys.prototype_db_prop_ansiPadding); + } + } + + public static string prototype_db_prop_ansiWarnings + { + get + { + return Keys.GetString(Keys.prototype_db_prop_ansiWarnings); + } + } + + public static string prototype_db_prop_arithabort + { + get + { + return Keys.GetString(Keys.prototype_db_prop_arithabort); + } + } + + public static string prototype_db_prop_autoClose + { + get + { + return Keys.GetString(Keys.prototype_db_prop_autoClose); + } + } + + public static string prototype_db_prop_autoCreateStatistics + { + get + { + return Keys.GetString(Keys.prototype_db_prop_autoCreateStatistics); + } + } + + public static string prototype_db_prop_autoShrink + { + get + { + return Keys.GetString(Keys.prototype_db_prop_autoShrink); + } + } + + public static string prototype_db_prop_autoUpdateStatistics + { + get + { + return Keys.GetString(Keys.prototype_db_prop_autoUpdateStatistics); + } + } + + public static string prototype_db_prop_autoUpdateStatisticsAsync + { + get + { + return Keys.GetString(Keys.prototype_db_prop_autoUpdateStatisticsAsync); + } + } + + public static string prototype_db_prop_caseSensitive + { + get + { + return Keys.GetString(Keys.prototype_db_prop_caseSensitive); + } + } + + public static string prototype_db_prop_closeCursorOnCommit + { + get + { + return Keys.GetString(Keys.prototype_db_prop_closeCursorOnCommit); + } + } + + public static string prototype_db_prop_collation + { + get + { + return Keys.GetString(Keys.prototype_db_prop_collation); + } + } + + public static string prototype_db_prop_concatNullYieldsNull + { + get + { + return Keys.GetString(Keys.prototype_db_prop_concatNullYieldsNull); + } + } + + public static string prototype_db_prop_databaseCompatibilityLevel + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseCompatibilityLevel); + } + } + + public static string prototype_db_prop_databaseState + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState); + } + } + + public static string prototype_db_prop_defaultCursor + { + get + { + return Keys.GetString(Keys.prototype_db_prop_defaultCursor); + } + } + + public static string prototype_db_prop_fullTextIndexing + { + get + { + return Keys.GetString(Keys.prototype_db_prop_fullTextIndexing); + } + } + + public static string prototype_db_prop_numericRoundAbort + { + get + { + return Keys.GetString(Keys.prototype_db_prop_numericRoundAbort); + } + } + + public static string prototype_db_prop_pageVerify + { + get + { + return Keys.GetString(Keys.prototype_db_prop_pageVerify); + } + } + + public static string prototype_db_prop_quotedIdentifier + { + get + { + return Keys.GetString(Keys.prototype_db_prop_quotedIdentifier); + } + } + + public static string prototype_db_prop_readOnly + { + get + { + return Keys.GetString(Keys.prototype_db_prop_readOnly); + } + } + + public static string prototype_db_prop_recursiveTriggers + { + get + { + return Keys.GetString(Keys.prototype_db_prop_recursiveTriggers); + } + } + + public static string prototype_db_prop_restrictAccess + { + get + { + return Keys.GetString(Keys.prototype_db_prop_restrictAccess); + } + } + + public static string prototype_db_prop_selectIntoBulkCopy + { + get + { + return Keys.GetString(Keys.prototype_db_prop_selectIntoBulkCopy); + } + } + + public static string prototype_db_prop_honorBrokerPriority + { + get + { + return Keys.GetString(Keys.prototype_db_prop_honorBrokerPriority); + } + } + + public static string prototype_db_prop_serviceBrokerGuid + { + get + { + return Keys.GetString(Keys.prototype_db_prop_serviceBrokerGuid); + } + } + + public static string prototype_db_prop_brokerEnabled + { + get + { + return Keys.GetString(Keys.prototype_db_prop_brokerEnabled); + } + } + + public static string prototype_db_prop_truncateLogOnCheckpoint + { + get + { + return Keys.GetString(Keys.prototype_db_prop_truncateLogOnCheckpoint); + } + } + + public static string prototype_db_prop_dbChaining + { + get + { + return Keys.GetString(Keys.prototype_db_prop_dbChaining); + } + } + + public static string prototype_db_prop_trustworthy + { + get + { + return Keys.GetString(Keys.prototype_db_prop_trustworthy); + } + } + + public static string prototype_db_prop_dateCorrelationOptimization + { + get + { + return Keys.GetString(Keys.prototype_db_prop_dateCorrelationOptimization); + } + } + + public static string prototype_db_prop_parameterization + { + get + { + return Keys.GetString(Keys.prototype_db_prop_parameterization); + } + } + + public static string prototype_db_prop_parameterization_value_forced + { + get + { + return Keys.GetString(Keys.prototype_db_prop_parameterization_value_forced); + } + } + + public static string prototype_db_prop_parameterization_value_simple + { + get + { + return Keys.GetString(Keys.prototype_db_prop_parameterization_value_simple); + } + } + + public static string prototype_file_dataFile + { + get + { + return Keys.GetString(Keys.prototype_file_dataFile); + } + } + + public static string prototype_file_logFile + { + get + { + return Keys.GetString(Keys.prototype_file_logFile); + } + } + + public static string prototype_file_filestreamFile + { + get + { + return Keys.GetString(Keys.prototype_file_filestreamFile); + } + } + + public static string prototype_file_noFileGroup + { + get + { + return Keys.GetString(Keys.prototype_file_noFileGroup); + } + } + + public static string prototype_file_defaultpathstring + { + get + { + return Keys.GetString(Keys.prototype_file_defaultpathstring); + } + } + + public static string title_openConnectionsMustBeClosed + { + get + { + return Keys.GetString(Keys.title_openConnectionsMustBeClosed); + } + } + + public static string warning_openConnectionsMustBeClosed + { + get + { + return Keys.GetString(Keys.warning_openConnectionsMustBeClosed); + } + } + + public static string prototype_db_prop_databaseState_value_autoClosed + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_autoClosed); + } + } + + public static string prototype_db_prop_databaseState_value_emergency + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_emergency); + } + } + + public static string prototype_db_prop_databaseState_value_inaccessible + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_inaccessible); + } + } + + public static string prototype_db_prop_databaseState_value_normal + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_normal); + } + } + + public static string prototype_db_prop_databaseState_value_offline + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_offline); + } + } + + public static string prototype_db_prop_databaseState_value_recovering + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_recovering); + } + } + + public static string prototype_db_prop_databaseState_value_recoveryPending + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_recoveryPending); + } + } + + public static string prototype_db_prop_databaseState_value_restoring + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_restoring); + } + } + + public static string prototype_db_prop_databaseState_value_shutdown + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_shutdown); + } + } + + public static string prototype_db_prop_databaseState_value_standby + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_standby); + } + } + + public static string prototype_db_prop_databaseState_value_suspect + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databaseState_value_suspect); + } + } + + public static string prototype_db_prop_defaultCursor_value_global + { + get + { + return Keys.GetString(Keys.prototype_db_prop_defaultCursor_value_global); + } + } + + public static string prototype_db_prop_defaultCursor_value_local + { + get + { + return Keys.GetString(Keys.prototype_db_prop_defaultCursor_value_local); + } + } + + public static string prototype_db_prop_restrictAccess_value_multiple + { + get + { + return Keys.GetString(Keys.prototype_db_prop_restrictAccess_value_multiple); + } + } + + public static string prototype_db_prop_restrictAccess_value_restricted + { + get + { + return Keys.GetString(Keys.prototype_db_prop_restrictAccess_value_restricted); + } + } + + public static string prototype_db_prop_restrictAccess_value_single + { + get + { + return Keys.GetString(Keys.prototype_db_prop_restrictAccess_value_single); + } + } + + public static string prototype_db_prop_pageVerify_value_checksum + { + get + { + return Keys.GetString(Keys.prototype_db_prop_pageVerify_value_checksum); + } + } + + public static string prototype_db_prop_pageVerify_value_none + { + get + { + return Keys.GetString(Keys.prototype_db_prop_pageVerify_value_none); + } + } + + public static string prototype_db_prop_pageVerify_value_tornPageDetection + { + get + { + return Keys.GetString(Keys.prototype_db_prop_pageVerify_value_tornPageDetection); + } + } + + public static string prototype_db_prop_varDecimalEnabled + { + get + { + return Keys.GetString(Keys.prototype_db_prop_varDecimalEnabled); + } + } + + public static string prototype_db_prop_encryptionEnabled + { + get + { + return Keys.GetString(Keys.prototype_db_prop_encryptionEnabled); + } + } + + public static string prototype_db_prop_databasescopedconfig_value_off + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databasescopedconfig_value_off); + } + } + + public static string prototype_db_prop_databasescopedconfig_value_on + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databasescopedconfig_value_on); + } + } + + public static string prototype_db_prop_databasescopedconfig_value_primary + { + get + { + return Keys.GetString(Keys.prototype_db_prop_databasescopedconfig_value_primary); + } + } + + public static string error_db_prop_invalidleadingColumns + { + get + { + return Keys.GetString(Keys.error_db_prop_invalidleadingColumns); + } + } + + public static string compatibilityLevel_sphinx + { + get + { + return Keys.GetString(Keys.compatibilityLevel_sphinx); + } + } + + public static string compatibilityLevel_shiloh + { + get + { + return Keys.GetString(Keys.compatibilityLevel_shiloh); + } + } + + public static string compatibilityLevel_yukon + { + get + { + return Keys.GetString(Keys.compatibilityLevel_yukon); + } + } + + public static string compatibilityLevel_katmai + { + get + { + return Keys.GetString(Keys.compatibilityLevel_katmai); + } + } + + public static string compatibilityLevel_denali + { + get + { + return Keys.GetString(Keys.compatibilityLevel_denali); + } + } + + public static string compatibilityLevel_sql14 + { + get + { + return Keys.GetString(Keys.compatibilityLevel_sql14); + } + } + + public static string compatibilityLevel_sql15 + { + get + { + return Keys.GetString(Keys.compatibilityLevel_sql15); + } + } + + public static string compatibilityLevel_sql2017 + { + get + { + return Keys.GetString(Keys.compatibilityLevel_sql2017); + } + } + + public static string compatibilityLevel_sqlv150 + { + get + { + return Keys.GetString(Keys.compatibilityLevel_sqlv150); + } + } + + public static string compatibilityLevel_sqlv160 + { + get + { + return Keys.GetString(Keys.compatibilityLevel_sqlv160); + } + } + + public static string general_containmentType_None + { + get + { + return Keys.GetString(Keys.general_containmentType_None); + } + } + + public static string general_containmentType_Partial + { + get + { + return Keys.GetString(Keys.general_containmentType_Partial); + } + } + + public static string filegroups_filestreamFiles + { + get + { + return Keys.GetString(Keys.filegroups_filestreamFiles); + } + } + + public static string prototype_file_noApplicableFileGroup + { + get + { + return Keys.GetString(Keys.prototype_file_noApplicableFileGroup); + } + } + public static string ConnectionServiceListDbErrorNotConnected(string uri) { return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri); @@ -16287,6 +17383,417 @@ namespace Microsoft.SqlTools.ServiceLayer public const string ServiceNotFound = "ServiceNotFound"; + public const string autogrowth_dialog_title = "autogrowth_dialog_title"; + + + public const string autogrowth_dialog_filestreamtitle = "autogrowth_dialog_filestreamtitle"; + + + public const string autogrowth_dialog_defaulttitle = "autogrowth_dialog_defaulttitle"; + + + public const string autogrowth_dialog_defaultfilestreamtitle = "autogrowth_dialog_defaultfilestreamtitle"; + + + public const string createDatabase_title = "createDatabase_title"; + + + public const string error_60compatibility = "error_60compatibility"; + + + public const string error_cantModifyExistingFilePath = "error_cantModifyExistingFilePath"; + + + public const string error_databaseAlreadyExists = "error_databaseAlreadyExists"; + + + public const string error_databaseProperties_title = "error_databaseProperties_title"; + + + public const string error_emptyFileName = "error_emptyFileName"; + + + public const string error_fileNameContainsIllegalCharacter = "error_fileNameContainsIllegalCharacter"; + + + public const string error_fileNameStartsWithSpace = "error_fileNameStartsWithSpace"; + + + public const string error_whitespaceDatabaseName = "error_whitespaceDatabaseName"; + + + public const string filegroup_dialog_defaultFilegroup = "filegroup_dialog_defaultFilegroup"; + + + public const string filegroup_dialog_title = "filegroup_dialog_title"; + + + public const string filegroups_default = "filegroups_default"; + + + public const string filegroups_files = "filegroups_files"; + + + public const string filegroups_name = "filegroups_name"; + + + public const string filegroups_readonly = "filegroups_readonly"; + + + public const string filegroups_autogrowAllFiles = "filegroups_autogrowAllFiles"; + + + public const string general_autogrowth = "general_autogrowth"; + + + public const string general_builderText = "general_builderText"; + + + public const string general_default = "general_default"; + + + public const string general_fileGroup = "general_fileGroup"; + + + public const string general_fileName = "general_fileName"; + + + public const string general_fileType = "general_fileType"; + + + public const string general_initialSize = "general_initialSize"; + + + public const string general_currentSize = "general_currentSize"; + + + public const string general_newFilegroup = "general_newFilegroup"; + + + public const string general_path = "general_path"; + + + public const string general_physicalFileName = "general_physicalFileName"; + + + public const string general_rawDevice = "general_rawDevice"; + + + public const string general_recoveryModel_bulkLogged = "general_recoveryModel_bulkLogged"; + + + public const string general_recoveryModel_full = "general_recoveryModel_full"; + + + public const string general_recoveryModel_simple = "general_recoveryModel_simple"; + + + public const string general_titleSearchOwner = "general_titleSearchOwner"; + + + public const string leftPane_extendedPropertiesNode_name = "leftPane_extendedPropertiesNode_name"; + + + public const string leftPane_filegroupsNode_name = "leftPane_filegroupsNode_name"; + + + public const string leftPane_generalNode_name = "leftPane_generalNode_name"; + + + public const string leftPane_optionsNode_name = "leftPane_optionsNode_name"; + + + public const string leftPane_capabilitiesNode_name = "leftPane_capabilitiesNode_name"; + + + public const string leftPane_topNode_name = "leftPane_topNode_name"; + + + public const string prototype_autogrowth_disabled = "prototype_autogrowth_disabled"; + + + public const string prototype_autogrowth_restrictedGrowthByMB = "prototype_autogrowth_restrictedGrowthByMB"; + + + public const string prototype_autogrowth_restrictedGrowthByPercent = "prototype_autogrowth_restrictedGrowthByPercent"; + + + public const string prototype_autogrowth_unrestrictedGrowthByMB = "prototype_autogrowth_unrestrictedGrowthByMB"; + + + public const string prototype_autogrowth_unrestrictedGrowthByPercent = "prototype_autogrowth_unrestrictedGrowthByPercent"; + + + public const string prototype_autogrowth_unlimitedfilestream = "prototype_autogrowth_unlimitedfilestream"; + + + public const string prototype_autogrowth_limitedfilestream = "prototype_autogrowth_limitedfilestream"; + + + public const string prototype_db_category_automatic = "prototype_db_category_automatic"; + + + public const string prototype_db_category_servicebroker = "prototype_db_category_servicebroker"; + + + public const string prototype_db_category_collation = "prototype_db_category_collation"; + + + public const string prototype_db_category_cursor = "prototype_db_category_cursor"; + + + public const string prototype_db_category_misc = "prototype_db_category_misc"; + + + public const string prototype_db_category_recovery = "prototype_db_category_recovery"; + + + public const string prototype_db_category_state = "prototype_db_category_state"; + + + public const string prototype_db_prop_ansiNullDefault = "prototype_db_prop_ansiNullDefault"; + + + public const string prototype_db_prop_ansiNulls = "prototype_db_prop_ansiNulls"; + + + public const string prototype_db_prop_ansiPadding = "prototype_db_prop_ansiPadding"; + + + public const string prototype_db_prop_ansiWarnings = "prototype_db_prop_ansiWarnings"; + + + public const string prototype_db_prop_arithabort = "prototype_db_prop_arithabort"; + + + public const string prototype_db_prop_autoClose = "prototype_db_prop_autoClose"; + + + public const string prototype_db_prop_autoCreateStatistics = "prototype_db_prop_autoCreateStatistics"; + + + public const string prototype_db_prop_autoShrink = "prototype_db_prop_autoShrink"; + + + public const string prototype_db_prop_autoUpdateStatistics = "prototype_db_prop_autoUpdateStatistics"; + + + public const string prototype_db_prop_autoUpdateStatisticsAsync = "prototype_db_prop_autoUpdateStatisticsAsync"; + + + public const string prototype_db_prop_caseSensitive = "prototype_db_prop_caseSensitive"; + + + public const string prototype_db_prop_closeCursorOnCommit = "prototype_db_prop_closeCursorOnCommit"; + + + public const string prototype_db_prop_collation = "prototype_db_prop_collation"; + + + public const string prototype_db_prop_concatNullYieldsNull = "prototype_db_prop_concatNullYieldsNull"; + + + public const string prototype_db_prop_databaseCompatibilityLevel = "prototype_db_prop_databaseCompatibilityLevel"; + + + public const string prototype_db_prop_databaseState = "prototype_db_prop_databaseState"; + + + public const string prototype_db_prop_defaultCursor = "prototype_db_prop_defaultCursor"; + + + public const string prototype_db_prop_fullTextIndexing = "prototype_db_prop_fullTextIndexing"; + + + public const string prototype_db_prop_numericRoundAbort = "prototype_db_prop_numericRoundAbort"; + + + public const string prototype_db_prop_pageVerify = "prototype_db_prop_pageVerify"; + + + public const string prototype_db_prop_quotedIdentifier = "prototype_db_prop_quotedIdentifier"; + + + public const string prototype_db_prop_readOnly = "prototype_db_prop_readOnly"; + + + public const string prototype_db_prop_recursiveTriggers = "prototype_db_prop_recursiveTriggers"; + + + public const string prototype_db_prop_restrictAccess = "prototype_db_prop_restrictAccess"; + + + public const string prototype_db_prop_selectIntoBulkCopy = "prototype_db_prop_selectIntoBulkCopy"; + + + public const string prototype_db_prop_honorBrokerPriority = "prototype_db_prop_honorBrokerPriority"; + + + public const string prototype_db_prop_serviceBrokerGuid = "prototype_db_prop_serviceBrokerGuid"; + + + public const string prototype_db_prop_brokerEnabled = "prototype_db_prop_brokerEnabled"; + + + public const string prototype_db_prop_truncateLogOnCheckpoint = "prototype_db_prop_truncateLogOnCheckpoint"; + + + public const string prototype_db_prop_dbChaining = "prototype_db_prop_dbChaining"; + + + public const string prototype_db_prop_trustworthy = "prototype_db_prop_trustworthy"; + + + public const string prototype_db_prop_dateCorrelationOptimization = "prototype_db_prop_dateCorrelationOptimization"; + + + public const string prototype_db_prop_parameterization = "prototype_db_prop_parameterization"; + + + public const string prototype_db_prop_parameterization_value_forced = "prototype_db_prop_parameterization_value_forced"; + + + public const string prototype_db_prop_parameterization_value_simple = "prototype_db_prop_parameterization_value_simple"; + + + public const string prototype_file_dataFile = "prototype_file_dataFile"; + + + public const string prototype_file_logFile = "prototype_file_logFile"; + + + public const string prototype_file_filestreamFile = "prototype_file_filestreamFile"; + + + public const string prototype_file_noFileGroup = "prototype_file_noFileGroup"; + + + public const string prototype_file_defaultpathstring = "prototype_file_defaultpathstring"; + + + public const string title_openConnectionsMustBeClosed = "title_openConnectionsMustBeClosed"; + + + public const string warning_openConnectionsMustBeClosed = "warning_openConnectionsMustBeClosed"; + + + public const string prototype_db_prop_databaseState_value_autoClosed = "prototype_db_prop_databaseState_value_autoClosed"; + + + public const string prototype_db_prop_databaseState_value_emergency = "prototype_db_prop_databaseState_value_emergency"; + + + public const string prototype_db_prop_databaseState_value_inaccessible = "prototype_db_prop_databaseState_value_inaccessible"; + + + public const string prototype_db_prop_databaseState_value_normal = "prototype_db_prop_databaseState_value_normal"; + + + public const string prototype_db_prop_databaseState_value_offline = "prototype_db_prop_databaseState_value_offline"; + + + public const string prototype_db_prop_databaseState_value_recovering = "prototype_db_prop_databaseState_value_recovering"; + + + public const string prototype_db_prop_databaseState_value_recoveryPending = "prototype_db_prop_databaseState_value_recoveryPending"; + + + public const string prototype_db_prop_databaseState_value_restoring = "prototype_db_prop_databaseState_value_restoring"; + + + public const string prototype_db_prop_databaseState_value_shutdown = "prototype_db_prop_databaseState_value_shutdown"; + + + public const string prototype_db_prop_databaseState_value_standby = "prototype_db_prop_databaseState_value_standby"; + + + public const string prototype_db_prop_databaseState_value_suspect = "prototype_db_prop_databaseState_value_suspect"; + + + public const string prototype_db_prop_defaultCursor_value_global = "prototype_db_prop_defaultCursor_value_global"; + + + public const string prototype_db_prop_defaultCursor_value_local = "prototype_db_prop_defaultCursor_value_local"; + + + public const string prototype_db_prop_restrictAccess_value_multiple = "prototype_db_prop_restrictAccess_value_multiple"; + + + public const string prototype_db_prop_restrictAccess_value_restricted = "prototype_db_prop_restrictAccess_value_restricted"; + + + public const string prototype_db_prop_restrictAccess_value_single = "prototype_db_prop_restrictAccess_value_single"; + + + public const string prototype_db_prop_pageVerify_value_checksum = "prototype_db_prop_pageVerify_value_checksum"; + + + public const string prototype_db_prop_pageVerify_value_none = "prototype_db_prop_pageVerify_value_none"; + + + public const string prototype_db_prop_pageVerify_value_tornPageDetection = "prototype_db_prop_pageVerify_value_tornPageDetection"; + + + public const string prototype_db_prop_varDecimalEnabled = "prototype_db_prop_varDecimalEnabled"; + + + public const string prototype_db_prop_encryptionEnabled = "prototype_db_prop_encryptionEnabled"; + + + public const string prototype_db_prop_databasescopedconfig_value_off = "prototype_db_prop_databasescopedconfig_value_off"; + + + public const string prototype_db_prop_databasescopedconfig_value_on = "prototype_db_prop_databasescopedconfig_value_on"; + + + public const string prototype_db_prop_databasescopedconfig_value_primary = "prototype_db_prop_databasescopedconfig_value_primary"; + + + public const string error_db_prop_invalidleadingColumns = "error_db_prop_invalidleadingColumns"; + + + public const string compatibilityLevel_sphinx = "compatibilityLevel_sphinx"; + + + public const string compatibilityLevel_shiloh = "compatibilityLevel_shiloh"; + + + public const string compatibilityLevel_yukon = "compatibilityLevel_yukon"; + + + public const string compatibilityLevel_katmai = "compatibilityLevel_katmai"; + + + public const string compatibilityLevel_denali = "compatibilityLevel_denali"; + + + public const string compatibilityLevel_sql14 = "compatibilityLevel_sql14"; + + + public const string compatibilityLevel_sql15 = "compatibilityLevel_sql15"; + + + public const string compatibilityLevel_sql2017 = "compatibilityLevel_sql2017"; + + + public const string compatibilityLevel_sqlv150 = "compatibilityLevel_sqlv150"; + + + public const string compatibilityLevel_sqlv160 = "compatibilityLevel_sqlv160"; + + + public const string general_containmentType_None = "general_containmentType_None"; + + + public const string general_containmentType_Partial = "general_containmentType_Partial"; + + + public const string filegroups_filestreamFiles = "filegroups_filestreamFiles"; + + + public const string prototype_file_noApplicableFileGroup = "prototype_file_noApplicableFileGroup"; + + private Keys() { } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx index 026379e7..c0834cff 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx @@ -6212,4 +6212,552 @@ The Query Processor estimates that implementing the following index could improv . Parameters: 0 - serviceName (string) + + Change Autogrowth for {0} + + + + Change Maxsize for {0} + + + + Change Autogrowth + + + + Change Maxsize + + + + New Database + + + + Database properties cannot be set or viewed for databases in 6.0 or 6.5 compatibility mode. + + + + You cannot modify the path for existing database files. + + + + There is already a database named "{0}" on the server. + + + + Database Properties + + + + File name was empty. Provide a file name for the file. + + + + Cannot create a file with name '{0}' because it contains the invalid character '{1}'. + + + + Cannot create a file with name '{0}' because it begins with a space character. + + + + A database name cannot consist of all whitespace characters. + + + + Current default filegroup: {0} + + + + New Filegroup for {0} + + + + Default + + + + Files + + + + Name + + + + Read-Only + + + + Autogrow All Files + + + + Autogrowth / Maxsize + + + + ... + + + + <default> + + + + Filegroup + + + + Logical Name + + + + File Type + + + + Initial Size (MB) + + + + Size (MB) + + + + <new filegroup> + + + + Path + + + + File Name + + + + <raw device> + + + + Bulk-logged + + + + Full + + + + Simple + + + + Select Database Owner + + + + Extended Properties + + + + Filegroups + + + + General + + + + Options + + + + Configure SLO + + + + New Database + + + + None + + + + By {0} MB, Limited to {1} MB + + + + By {0} percent, Limited to {1} MB + + + + By {0} MB, Unlimited + + + + By {0} percent, Unlimited + + + + Unlimited + + + + Limited to {0} MB + + + + Automatic + + + + Service Broker + + + + Collation + + + + Cursor + + + + Miscellaneous + + + + Recovery + + + + State + + + + ANSI NULL Default + + + + ANSI NULLS Enabled + + + + ANSI Padding Enabled + + + + ANSI Warnings Enabled + + + + Arithmetic Abort Enabled + + + + Auto Close + + + + Auto Create Statistics + + + + Auto Shrink + + + + Auto Update Statistics + + + + Auto Update Statistics Asynchronously + + + + Case Sensitive + + + + Close Cursor on Commit Enabled + + + + Collation + + + + Concatenate Null Yields Null + + + + Database Compatibility Level + + + + Database State + + + + Default Cursor + + + + Full-Text Indexing Enabled + + + + Numeric Round-Abort + + + + Page Verify + + + + Quoted Identifiers Enabled + + + + Database Read-Only + + + + Recursive Triggers Enabled + + + + Restrict Access + + + + Select Into/Bulk Copy + + + + Honor Broker Priority + + + + Service Broker Identifier + + + + Broker Enabled + + + + Truncate Log on Checkpoint + + + + Cross-database Ownership Chaining Enabled + + + + Trustworthy + + + + Date Correlation Optimization Enabled + + + + Parameterization + + + + Forced + + + + Simple + + + + ROWS Data + + + + LOG + + + + FILESTREAM Data + + + + Not Applicable + + + + <default path> + + + + Open Connections + + + + To change the database properties, SQL Server must close all other connections to the database. Are you sure you want to change the properties and close all other connections? + + + + AUTO_CLOSED + + + + EMERGENCY + + + + INACCESSIBLE + + + + NORMAL + + + + OFFLINE + + + + RECOVERING + + + + RECOVERY PENDING + + + + RESTORING + + + + SHUTDOWN + + + + STANDBY + + + + SUSPECT + + + + GLOBAL + + + + LOCAL + + + + MULTI_USER + + + + RESTRICTED_USER + + + + SINGLE_USER + + + + CHECKSUM + + + + NONE + + + + TORN_PAGE_DETECTION + + + + VarDecimal Storage Format Enabled + + + + Encryption Enabled + + + + OFF + + + + ON + + + + PRIMARY + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + + + + SQL Server 7.0 (70) + + + + SQL Server 2000 (80) + + + + SQL Server 2005 (90) + + + + SQL Server 2008 (100) + + + + SQL Server 2012 (110) + + + + SQL Server 2014 (120) + + + + SQL Server 2016 (130) + + + + SQL Server 2017 (140) + + + + SQL Server 2019 (150) + + + + SQL Server 2022 (160) + + + + None + + + + Partial + + + + FILESTREAM Files + + + + No Applicable Filegroup + + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings index 225b4928..cea89ec4 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings @@ -2662,3 +2662,143 @@ Permission_ImpersonateAnyLogin = Impersonate Any Login ServiceProviderNotSet = SetServiceProvider() was not called to establish the required service provider ServiceNotFound(string serviceName) = Service {0} was not found in the service provider + +############################################################################ +# Create Database +autogrowth_dialog_title = Change Autogrowth for {0} +autogrowth_dialog_filestreamtitle = Change Maxsize for {0} +autogrowth_dialog_defaulttitle = Change Autogrowth +autogrowth_dialog_defaultfilestreamtitle = Change Maxsize +createDatabase_title = New Database +error_60compatibility = Database properties cannot be set or viewed for databases in 6.0 or 6.5 compatibility mode. +error_cantModifyExistingFilePath = You cannot modify the path for existing database files. +error_databaseAlreadyExists = There is already a database named "{0}" on the server. +error_databaseProperties_title = Database Properties +error_emptyFileName = File name was empty. Provide a file name for the file. +error_fileNameContainsIllegalCharacter = Cannot create a file with name '{0}' because it contains the invalid character '{1}'. +error_fileNameStartsWithSpace = Cannot create a file with name '{0}' because it begins with a space character. +error_whitespaceDatabaseName = A database name cannot consist of all whitespace characters. +filegroup_dialog_defaultFilegroup = Current default filegroup: {0} +filegroup_dialog_title = New Filegroup for {0} +filegroups_default = Default +filegroups_files = Files +filegroups_name = Name +filegroups_readonly = Read-Only +filegroups_autogrowAllFiles = Autogrow All Files +general_autogrowth = Autogrowth / Maxsize +general_builderText = ... +general_default = +general_fileGroup = Filegroup +general_fileName = Logical Name +general_fileType = File Type +general_initialSize = Initial Size (MB) +general_currentSize = Size (MB) +general_newFilegroup = +general_path = Path +general_physicalFileName = File Name +general_rawDevice = +general_recoveryModel_bulkLogged = Bulk-logged +general_recoveryModel_full = Full +general_recoveryModel_simple = Simple +general_titleSearchOwner = Select Database Owner +leftPane_extendedPropertiesNode_name = Extended Properties +leftPane_filegroupsNode_name = Filegroups +leftPane_generalNode_name = General +leftPane_optionsNode_name = Options +leftPane_capabilitiesNode_name = Configure SLO +leftPane_topNode_name = New Database +prototype_autogrowth_disabled = None +prototype_autogrowth_restrictedGrowthByMB = By {0} MB, Limited to {1} MB +prototype_autogrowth_restrictedGrowthByPercent = By {0} percent, Limited to {1} MB +prototype_autogrowth_unrestrictedGrowthByMB = By {0} MB, Unlimited +prototype_autogrowth_unrestrictedGrowthByPercent = By {0} percent, Unlimited +prototype_autogrowth_unlimitedfilestream = Unlimited +prototype_autogrowth_limitedfilestream = Limited to {0} MB +prototype_db_category_automatic = Automatic +prototype_db_category_servicebroker = Service Broker +prototype_db_category_collation = Collation +prototype_db_category_cursor = Cursor +prototype_db_category_misc = Miscellaneous +prototype_db_category_recovery = Recovery +prototype_db_category_state = State +prototype_db_prop_ansiNullDefault = ANSI NULL Default +prototype_db_prop_ansiNulls = ANSI NULLS Enabled +prototype_db_prop_ansiPadding = ANSI Padding Enabled +prototype_db_prop_ansiWarnings = ANSI Warnings Enabled +prototype_db_prop_arithabort = Arithmetic Abort Enabled +prototype_db_prop_autoClose = Auto Close +prototype_db_prop_autoCreateStatistics = Auto Create Statistics +prototype_db_prop_autoShrink = Auto Shrink +prototype_db_prop_autoUpdateStatistics = Auto Update Statistics +prototype_db_prop_autoUpdateStatisticsAsync = Auto Update Statistics Asynchronously +prototype_db_prop_caseSensitive = Case Sensitive +prototype_db_prop_closeCursorOnCommit = Close Cursor on Commit Enabled +prototype_db_prop_collation = Collation +prototype_db_prop_concatNullYieldsNull = Concatenate Null Yields Null +prototype_db_prop_databaseCompatibilityLevel = Database Compatibility Level +prototype_db_prop_databaseState = Database State +prototype_db_prop_defaultCursor = Default Cursor +prototype_db_prop_fullTextIndexing = Full-Text Indexing Enabled +prototype_db_prop_numericRoundAbort = Numeric Round-Abort +prototype_db_prop_pageVerify = Page Verify +prototype_db_prop_quotedIdentifier = Quoted Identifiers Enabled +prototype_db_prop_readOnly = Database Read-Only +prototype_db_prop_recursiveTriggers = Recursive Triggers Enabled +prototype_db_prop_restrictAccess = Restrict Access +prototype_db_prop_selectIntoBulkCopy = Select Into/Bulk Copy +prototype_db_prop_honorBrokerPriority = Honor Broker Priority +prototype_db_prop_serviceBrokerGuid = Service Broker Identifier +prototype_db_prop_brokerEnabled = Broker Enabled +prototype_db_prop_truncateLogOnCheckpoint = Truncate Log on Checkpoint +prototype_db_prop_dbChaining = Cross-database Ownership Chaining Enabled +prototype_db_prop_trustworthy = Trustworthy +prototype_db_prop_dateCorrelationOptimization = Date Correlation Optimization Enabled +prototype_db_prop_parameterization = Parameterization +prototype_db_prop_parameterization_value_forced = Forced +prototype_db_prop_parameterization_value_simple = Simple +prototype_file_dataFile = ROWS Data +prototype_file_logFile = LOG +prototype_file_filestreamFile = FILESTREAM Data +prototype_file_noFileGroup = Not Applicable +prototype_file_defaultpathstring = +title_openConnectionsMustBeClosed = Open Connections +warning_openConnectionsMustBeClosed = To change the database properties, SQL Server must close all other connections to the database. Are you sure you want to change the properties and close all other connections? +prototype_db_prop_databaseState_value_autoClosed = AUTO_CLOSED +prototype_db_prop_databaseState_value_emergency = EMERGENCY +prototype_db_prop_databaseState_value_inaccessible = INACCESSIBLE +prototype_db_prop_databaseState_value_normal = NORMAL +prototype_db_prop_databaseState_value_offline = OFFLINE +prototype_db_prop_databaseState_value_recovering = RECOVERING +prototype_db_prop_databaseState_value_recoveryPending = RECOVERY PENDING +prototype_db_prop_databaseState_value_restoring = RESTORING +prototype_db_prop_databaseState_value_shutdown = SHUTDOWN +prototype_db_prop_databaseState_value_standby = STANDBY +prototype_db_prop_databaseState_value_suspect = SUSPECT +prototype_db_prop_defaultCursor_value_global = GLOBAL +prototype_db_prop_defaultCursor_value_local = LOCAL +prototype_db_prop_restrictAccess_value_multiple = MULTI_USER +prototype_db_prop_restrictAccess_value_restricted = RESTRICTED_USER +prototype_db_prop_restrictAccess_value_single = SINGLE_USER +prototype_db_prop_pageVerify_value_checksum = CHECKSUM +prototype_db_prop_pageVerify_value_none = NONE +prototype_db_prop_pageVerify_value_tornPageDetection = TORN_PAGE_DETECTION +prototype_db_prop_varDecimalEnabled = VarDecimal Storage Format Enabled +prototype_db_prop_encryptionEnabled = Encryption Enabled +prototype_db_prop_databasescopedconfig_value_off = OFF +prototype_db_prop_databasescopedconfig_value_on = ON +prototype_db_prop_databasescopedconfig_value_primary = PRIMARY +error_db_prop_invalidleadingColumns = For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns +compatibilityLevel_sphinx = SQL Server 7.0 (70) +compatibilityLevel_shiloh = SQL Server 2000 (80) +compatibilityLevel_yukon = SQL Server 2005 (90) +compatibilityLevel_katmai = SQL Server 2008 (100) +compatibilityLevel_denali = SQL Server 2012 (110) +compatibilityLevel_sql14 = SQL Server 2014 (120) +compatibilityLevel_sql15 = SQL Server 2016 (130) +compatibilityLevel_sql2017 = SQL Server 2017 (140) +compatibilityLevel_sqlv150 = SQL Server 2019 (150) +compatibilityLevel_sqlv160 = SQL Server 2022 (160) +general_containmentType_None = None +general_containmentType_Partial = Partial +filegroups_filestreamFiles = FILESTREAM Files +prototype_file_noApplicableFileGroup = No Applicable Filegroup \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf index 51e74413..123f4e6a 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf @@ -7596,6 +7596,691 @@ The Query Processor estimates that implementing the following index could improv Schema and Data + + Change Autogrowth for {0} + Change Autogrowth for {0} + + + + Change Maxsize for {0} + Change Maxsize for {0} + + + + Change Autogrowth + Change Autogrowth + + + + Change Maxsize + Change Maxsize + + + + SQL Server 2000 (80) + SQL Server 2000 (80) + + + + SQL Server 7.0 (70) + SQL Server 7.0 (70) + + + + SQL Server 2005 (90) + SQL Server 2005 (90) + + + + New Database + New Database + + + + Database properties cannot be set or viewed for databases in 6.0 or 6.5 compatibility mode. + Database properties cannot be set or viewed for databases in 6.0 or 6.5 compatibility mode. + + + + You cannot modify the path for existing database files. + You cannot modify the path for existing database files. + + + + There is already a database named "{0}" on the server. + There is already a database named "{0}" on the server. + + + + Database Properties + Database Properties + + + + File name was empty. Provide a file name for the file. + File name was empty. Provide a file name for the file. + + + + Cannot create a file with name '{0}' because it contains the invalid character '{1}'. + Cannot create a file with name '{0}' because it contains the invalid character '{1}'. + + + + Cannot create a file with name '{0}' because it begins with a space character. + Cannot create a file with name '{0}' because it begins with a space character. + + + + A database name cannot consist of all whitespace characters. + A database name cannot consist of all whitespace characters. + + + + Current default filegroup: {0} + Current default filegroup: {0} + + + + New Filegroup for {0} + New Filegroup for {0} + + + + Default + Default + + + + Files + Files + + + + Name + Name + + + + Read-Only + Read-Only + + + + Autogrow All Files + Autogrow All Files + + + + Autogrowth / Maxsize + Autogrowth / Maxsize + + + + ... + ... + + + + <default> + <default> + + + + Filegroup + Filegroup + + + + Logical Name + Logical Name + + + + File Type + File Type + + + + Initial Size (MB) + Initial Size (MB) + + + + Size (MB) + Size (MB) + + + + <new filegroup> + <new filegroup> + + + + Path + Path + + + + File Name + File Name + + + + <raw device> + <raw device> + + + + Bulk-logged + Bulk-logged + + + + Full + Full + + + + Simple + Simple + + + + Select Database Owner + Select Database Owner + + + + Extended Properties + Extended Properties + + + + Filegroups + Filegroups + + + + General + General + + + + Options + Options + + + + Configure SLO + Configure SLO + + + + New Database + New Database + + + + None + None + + + + By {0} MB, Limited to {1} MB + By {0} MB, Limited to {1} MB + + + + By {0} percent, Limited to {1} MB + By {0} percent, Limited to {1} MB + + + + By {0} MB, Unlimited + By {0} MB, Unlimited + + + + By {0} percent, Unlimited + By {0} percent, Unlimited + + + + Unlimited + Unlimited + + + + Limited to {0} MB + Limited to {0} MB + + + + Automatic + Automatic + + + + Service Broker + Service Broker + + + + Collation + Collation + + + + Cursor + Cursor + + + + Miscellaneous + Miscellaneous + + + + Recovery + Recovery + + + + State + State + + + + ANSI NULL Default + ANSI NULL Default + + + + ANSI NULLS Enabled + ANSI NULLS Enabled + + + + ANSI Padding Enabled + ANSI Padding Enabled + + + + ANSI Warnings Enabled + ANSI Warnings Enabled + + + + Arithmetic Abort Enabled + Arithmetic Abort Enabled + + + + Auto Close + Auto Close + + + + Auto Create Statistics + Auto Create Statistics + + + + Auto Shrink + Auto Shrink + + + + Auto Update Statistics + Auto Update Statistics + + + + Auto Update Statistics Asynchronously + Auto Update Statistics Asynchronously + + + + Case Sensitive + Case Sensitive + + + + Close Cursor on Commit Enabled + Close Cursor on Commit Enabled + + + + Collation + Collation + + + + Concatenate Null Yields Null + Concatenate Null Yields Null + + + + Database Compatibility Level + Database Compatibility Level + + + + Database State + Database State + + + + Default Cursor + Default Cursor + + + + Full-Text Indexing Enabled + Full-Text Indexing Enabled + + + + Numeric Round-Abort + Numeric Round-Abort + + + + Page Verify + Page Verify + + + + Quoted Identifiers Enabled + Quoted Identifiers Enabled + + + + Database Read-Only + Database Read-Only + + + + Recursive Triggers Enabled + Recursive Triggers Enabled + + + + Restrict Access + Restrict Access + + + + Select Into/Bulk Copy + Select Into/Bulk Copy + + + + Honor Broker Priority + Honor Broker Priority + + + + Service Broker Identifier + Service Broker Identifier + + + + Broker Enabled + Broker Enabled + + + + Truncate Log on Checkpoint + Truncate Log on Checkpoint + + + + Cross-database Ownership Chaining Enabled + Cross-database Ownership Chaining Enabled + + + + Trustworthy + Trustworthy + + + + Date Correlation Optimization Enabled + Date Correlation Optimization Enabled + + + + Parameterization + Parameterization + + + + Forced + Forced + + + + Simple + Simple + + + + ROWS Data + ROWS Data + + + + LOG + LOG + + + + FILESTREAM Data + FILESTREAM Data + + + + Not Applicable + Not Applicable + + + + <default path> + <default path> + + + + Open Connections + Open Connections + + + + To change the database properties, SQL Server must close all other connections to the database. Are you sure you want to change the properties and close all other connections? + To change the database properties, SQL Server must close all other connections to the database. Are you sure you want to change the properties and close all other connections? + + + + AUTO_CLOSED + AUTO_CLOSED + + + + EMERGENCY + EMERGENCY + + + + INACCESSIBLE + INACCESSIBLE + + + + NORMAL + NORMAL + + + + OFFLINE + OFFLINE + + + + RECOVERING + RECOVERING + + + + RECOVERY PENDING + RECOVERY PENDING + + + + RESTORING + RESTORING + + + + SHUTDOWN + SHUTDOWN + + + + STANDBY + STANDBY + + + + SUSPECT + SUSPECT + + + + GLOBAL + GLOBAL + + + + LOCAL + LOCAL + + + + MULTI_USER + MULTI_USER + + + + RESTRICTED_USER + RESTRICTED_USER + + + + SINGLE_USER + SINGLE_USER + + + + CHECKSUM + CHECKSUM + + + + NONE + NONE + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + VarDecimal Storage Format Enabled + VarDecimal Storage Format Enabled + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + Encryption Enabled + Encryption Enabled + + + + OFF + OFF + + + + ON + ON + + + + PRIMARY + PRIMARY + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + SQL Server 2017 (140) + SQL Server 2017 (140) + + + + SQL Server 2019 (150) + SQL Server 2019 (150) + + + + SQL Server 2022 (160) + SQL Server 2022 (160) + + + + None + None + + + + Partial + Partial + + + + FILESTREAM Files + FILESTREAM Files + + + + No Applicable Filegroup + No Applicable Filegroup + + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseActions.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseActions.cs new file mode 100644 index 00000000..b97e8f41 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseActions.cs @@ -0,0 +1,38 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.ServiceLayer.Admin; +using Microsoft.SqlTools.ServiceLayer.Management; + +namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement +{ + internal class DatabaseActions : ManagementActionBase + { + private ConfigAction configAction; + + private DatabasePrototype prototype; + + /// + /// Handle Database create and update actions + /// + public DatabaseActions(CDataContainer dataContainer, ConfigAction configAction, DatabasePrototype prototype) + { + this.DataContainer = dataContainer; + this.configAction = configAction; + this.prototype = prototype; + } + + /// + /// Called by the management actions framework to execute the action + /// + public override void OnRunNow(object sender) + { + if (this.configAction != ConfigAction.Drop) + { + prototype.ApplyChanges(); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs index e4ae92ca..2c46c21a 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseHandler.cs @@ -4,8 +4,19 @@ // using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Globalization; +using System.Linq; using System.Threading.Tasks; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlServer.Management.Sdk.Sfc; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlTools.ServiceLayer.Admin; +using static Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper; using Microsoft.SqlTools.ServiceLayer.Connection; +using Microsoft.SqlTools.ServiceLayer.Management; using Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts; namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement @@ -15,8 +26,53 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement /// public class DatabaseHandler : ObjectTypeHandler { + private const int minimumVersionForWritableCollation = 8; + private const int minimumVersionForRecoveryModel = 8; + private const string serverNotExistsError = "Server was not created for data container"; + + private readonly Dictionary displayCompatLevels = new Dictionary(); + private readonly Dictionary displayContainmentTypes = new Dictionary(); + private readonly Dictionary displayRecoveryModels = new Dictionary(); + + private readonly Dictionary compatLevelEnums = new Dictionary(); + private readonly Dictionary containmentTypeEnums = new Dictionary(); + private readonly Dictionary recoveryModelEnums = new Dictionary(); + + private readonly HashSet illegalFilenameCharacters = new HashSet(new char[] { '\\', '/', ':', '*', '?', '"', '<', '>', '|' }); + public DatabaseHandler(ConnectionService connectionService) : base(connectionService) { + displayCompatLevels.Add(CompatibilityLevel.Version70, SR.compatibilityLevel_sphinx); + displayCompatLevels.Add(CompatibilityLevel.Version80, SR.compatibilityLevel_shiloh); + displayCompatLevels.Add(CompatibilityLevel.Version90, SR.compatibilityLevel_yukon); + displayCompatLevels.Add(CompatibilityLevel.Version100, SR.compatibilityLevel_katmai); + displayCompatLevels.Add(CompatibilityLevel.Version110, SR.compatibilityLevel_denali); + displayCompatLevels.Add(CompatibilityLevel.Version120, SR.compatibilityLevel_sql14); + displayCompatLevels.Add(CompatibilityLevel.Version130, SR.compatibilityLevel_sql15); + displayCompatLevels.Add(CompatibilityLevel.Version140, SR.compatibilityLevel_sql2017); + displayCompatLevels.Add(CompatibilityLevel.Version150, SR.compatibilityLevel_sqlv150); + displayCompatLevels.Add(CompatibilityLevel.Version160, SR.compatibilityLevel_sqlv160); + + displayContainmentTypes.Add(ContainmentType.None, SR.general_containmentType_None); + displayContainmentTypes.Add(ContainmentType.Partial, SR.general_containmentType_Partial); + + displayRecoveryModels.Add(RecoveryModel.Full, SR.general_recoveryModel_full); + displayRecoveryModels.Add(RecoveryModel.BulkLogged, SR.general_recoveryModel_bulkLogged); + displayRecoveryModels.Add(RecoveryModel.Simple, SR.general_recoveryModel_simple); + + // Set up maps from displayName to enum type so we can retrieve the equivalent enum types later. + // We can't use a simple Enum.Parse for that since the displayNames get localized. + foreach (CompatibilityLevel key in displayCompatLevels.Keys) + { + compatLevelEnums.Add(displayCompatLevels[key], key); + } + + containmentTypeEnums.Add(displayContainmentTypes[ContainmentType.None], ContainmentType.None); + containmentTypeEnums.Add(displayContainmentTypes[ContainmentType.Partial], ContainmentType.Partial); + + recoveryModelEnums.Add(displayRecoveryModels[RecoveryModel.Full], RecoveryModel.Full); + recoveryModelEnums.Add(displayRecoveryModels[RecoveryModel.BulkLogged], RecoveryModel.BulkLogged); + recoveryModelEnums.Add(displayRecoveryModels[RecoveryModel.Simple], RecoveryModel.Simple); } public override bool CanHandleType(SqlObjectType objectType) @@ -26,17 +82,512 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement public override Task InitializeObjectView(InitializeViewRequestParams requestParams) { - throw new NotImplementedException(); + // create a default data context and database object + using (var dataContainer = CreateDatabaseDataContainer(requestParams.ConnectionUri, ConfigAction.Create)) + { + if (dataContainer.Server == null) + { + throw new InvalidOperationException(serverNotExistsError); + } + try + { + using (var taskHelper = new DatabaseTaskHelper(dataContainer)) + using (var context = new DatabaseViewContext(requestParams)) + { + var prototype = taskHelper.Prototype; + var azurePrototype = prototype as DatabasePrototypeAzure; + bool isDw = azurePrototype != null && azurePrototype.AzureEdition == AzureEdition.DataWarehouse; + + var databaseViewInfo = new DatabaseViewInfo() + { + ObjectInfo = new DatabaseInfo() + }; + + // azure sql db doesn't have a sysadmin fixed role + var compatibilityLevelEnabled = !isDw && + (dataContainer.LoggedInUserIsSysadmin || + dataContainer.Server.ServerType == + DatabaseEngineType.SqlAzureDatabase); + if (dataContainer.Server.ServerType == DatabaseEngineType.SqlAzureDatabase) + { + // Azure doesn't allow modifying the collation after DB creation + bool collationEnabled = !prototype.Exists; + if (isDw) + { + if (collationEnabled) + { + databaseViewInfo.CollationNames = GetCollationsWithPrototypeCollation(prototype); + } + databaseViewInfo.CompatibilityLevels = GetCompatibilityLevelsAzure(prototype); + } + else + { + if (collationEnabled) + { + databaseViewInfo.CollationNames = GetCollations(dataContainer.Server, prototype, dataContainer.IsNewObject); + } + if (compatibilityLevelEnabled) + { + databaseViewInfo.CompatibilityLevels = GetCompatibilityLevels(dataContainer.SqlServerVersion, prototype); + } + } + } + else + { + databaseViewInfo.CollationNames = GetCollations(dataContainer.Server, prototype, dataContainer.IsNewObject); + if (compatibilityLevelEnabled) + { + databaseViewInfo.CompatibilityLevels = GetCompatibilityLevels(dataContainer.SqlServerVersion, prototype); + } + + // These aren't visible when the target DB is on Azure so only populate if it's not an Azure DB + databaseViewInfo.RecoveryModels = GetRecoveryModels(dataContainer.Server, prototype); + databaseViewInfo.ContainmentTypes = GetContainmentTypes(dataContainer.Server, prototype); + } + + // Skip adding logins for the Owner field if running against an Azure SQL DB + if (dataContainer.Server.ServerType != DatabaseEngineType.SqlAzureDatabase) + { + var logins = new List(); + logins.Add(SR.general_default); + foreach (Login login in dataContainer.Server.Logins) + { + logins.Add(login.Name); + } + databaseViewInfo.LoginNames = logins.ToArray(); + } + + return Task.FromResult(new InitializeViewResult { ViewInfo = databaseViewInfo, Context = context }); + } + } + finally + { + ServerConnection serverConnection = dataContainer.Server.ConnectionContext; + if (serverConnection.IsOpen) + { + serverConnection.Disconnect(); + } + } + } } public override Task Save(DatabaseViewContext context, DatabaseInfo obj) { - throw new NotImplementedException(); + ConfigureDatabase( + context.Parameters.ConnectionUri, + obj, + context.Parameters.IsNewObject ? ConfigAction.Create : ConfigAction.Update, + RunType.RunNow); + return Task.CompletedTask; } public override Task Script(DatabaseViewContext context, DatabaseInfo obj) { - throw new NotImplementedException(); + var script = ConfigureDatabase( + context.Parameters.ConnectionUri, + obj, + context.Parameters.IsNewObject ? ConfigAction.Create : ConfigAction.Update, + RunType.ScriptToWindow); + return Task.FromResult(script); + } + + private CDataContainer CreateDatabaseDataContainer(string connectionUri, ConfigAction configAction, DatabaseInfo? database = null) + { + ConnectionInfo connectionInfo = this.GetConnectionInfo(connectionUri); + CDataContainer dataContainer = CDataContainer.CreateDataContainer(connectionInfo, databaseExists: configAction != ConfigAction.Create); + if (dataContainer.Server == null) + { + throw new InvalidOperationException(serverNotExistsError); + } + string objectUrn = (configAction != ConfigAction.Create && database != null) + ? string.Format(System.Globalization.CultureInfo.InvariantCulture, + "Server/Database[@Name='{0}']", + Urn.EscapeString(database.Name)) + : string.Format(System.Globalization.CultureInfo.InvariantCulture, + "Server"); + dataContainer.SqlDialogSubject = dataContainer.Server.GetSmoObject(objectUrn); + return dataContainer; + } + + private string ConfigureDatabase(string connectionUri, DatabaseInfo database, ConfigAction configAction, RunType runType) + { + if (database.Name == null) + { + throw new ArgumentException("Database name not provided."); + } + + using (var dataContainer = CreateDatabaseDataContainer(connectionUri, configAction, database)) + { + if (dataContainer.Server == null) + { + throw new InvalidOperationException(serverNotExistsError); + } + try + { + using (var taskHelper = new DatabaseTaskHelper(dataContainer)) + { + DatabasePrototype prototype = taskHelper.Prototype; + prototype.Name = database.Name; + + // Update database file names now that we have a database name + if (!prototype.HideFileSettings) + { + var sanitizedName = SanitizeFileName(prototype.Name); + + var dataFile = prototype.Files[0]; + Debug.Assert(dataFile.DatabaseFileType == FileType.Data, "Expected first database file to be a data file for new database prototype."); + dataFile.Name = sanitizedName; + + if (prototype.NumberOfLogFiles > 0) + { + var logFile = prototype.Files[1]; + Debug.Assert(dataFile.DatabaseFileType == FileType.Log, "Expected first database file to be a log file for new database prototype"); + logFile.Name = $"{sanitizedName}_log"; + } + } + + if (database.Owner != null && database.Owner != SR.general_default) + { + prototype.Owner = database.Owner; + } + if (database.CollationName != null && database.CollationName != SR.general_default) + { + prototype.Collation = database.CollationName; + } + if (database.RecoveryModel != null) + { + prototype.RecoveryModel = recoveryModelEnums[database.RecoveryModel]; + } + if (database.CompatibilityLevel != null) + { + prototype.DatabaseCompatibilityLevel = compatLevelEnums[database.CompatibilityLevel]; + } + if (prototype is DatabasePrototype110 db110 && database.ContainmentType != null) + { + db110.DatabaseContainmentType = containmentTypeEnums[database.ContainmentType]; + } + + string sqlScript = string.Empty; + using (var actions = new DatabaseActions(dataContainer, configAction, prototype)) + using (var executionHandler = new ExecutonHandler(actions)) + { + executionHandler.RunNow(runType, this); + if (executionHandler.ExecutionResult == ExecutionMode.Failure) + { + throw executionHandler.ExecutionFailureException; + } + + if (runType == RunType.ScriptToWindow) + { + sqlScript = executionHandler.ScriptTextFromLastRun; + } + } + + return sqlScript; + } + } + finally + { + ServerConnection serverConnection = dataContainer.Server.ConnectionContext; + if (serverConnection.IsOpen) + { + serverConnection.Disconnect(); + } + } + } + } + + /// + /// Removes invalid characters from a filename string, replacing each invalid character with an underscore. + /// + private string SanitizeFileName(string fileName) + { + char[] nameChars = fileName.ToCharArray(); + for (int i = 0; i < nameChars.Length; i++) + { + if (illegalFilenameCharacters.Contains(nameChars[i])) + { + nameChars[i] = '_'; + } + } + return new string(nameChars); + } + + private bool IsManagedInstance(Server server) + { + return server?.Information?.DatabaseEngineEdition == DatabaseEngineEdition.SqlManagedInstance; + } + + private bool IsArcEnabledManagedInstance(Server server) + { + return server?.Information?.DatabaseEngineEdition == DatabaseEngineEdition.SqlAzureArcManagedInstance; + } + + private bool IsAnyManagedInstance(Server server) + { + return (IsManagedInstance(server) || IsArcEnabledManagedInstance(server)); + } + + private string[] GetCollations(Server server, DatabasePrototype prototype, bool isNewObject) + { + var collationItems = new List(); + bool isSphinxServer = (server.VersionMajor < minimumVersionForWritableCollation); + + // if we're creating a new database or this is a Sphinx Server, add "" to the dropdown + if (isNewObject || isSphinxServer) + { + collationItems.Add(SR.general_default); + } + + // if the server is shiloh or later, add specific collations to the dropdown + if (!isSphinxServer) + { + DataTable serverCollationsTable = server.EnumCollations(); + if (serverCollationsTable != null) + { + foreach (DataRow serverCollation in serverCollationsTable.Rows) + { + string collationName = (string)serverCollation["Name"]; + collationItems.Add(collationName); + } + } + } + + if (prototype.Exists) + { + System.Diagnostics.Debug.Assert(((prototype.Collation != null) && (prototype.Collation.Length != 0)), + "prototype.Collation is null"); + System.Diagnostics.Debug.Assert(collationItems.Contains(prototype.Collation), + "prototype.Collation is not in the collation list"); + + int index = collationItems.FindIndex(collation => collation.Equals(prototype.Collation, StringComparison.InvariantCultureIgnoreCase)); + if (index > 0) + { + collationItems.RemoveAt(index); + collationItems.Insert(0, prototype.Collation); + } + } + return collationItems.ToArray(); + } + + private string[] GetCollationsWithPrototypeCollation(DatabasePrototype prototype) + { + return new string[] { prototype.Collation }; + } + + private string[] GetContainmentTypes(Server server, DatabasePrototype prototype) + { + if (!(SqlMgmtUtils.IsSql11OrLater(server.ServerVersion)) || IsAnyManagedInstance(server)) + { + return Array.Empty(); + } + + var containmentTypes = new List(); + ContainmentType dbContainmentType = ContainmentType.None; + DatabasePrototype110? dp110 = prototype as DatabasePrototype110; + + if (dp110 != null) + { + dbContainmentType = dp110.DatabaseContainmentType; + } + + containmentTypes.Add(displayContainmentTypes[ContainmentType.None]); + containmentTypes.Add(displayContainmentTypes[ContainmentType.Partial]); + + var swapIndex = 0; + switch (dbContainmentType) + { + case ContainmentType.None: + break; + case ContainmentType.Partial: + swapIndex = 1; + break; + default: + Debug.Fail(string.Format(CultureInfo.InvariantCulture, "Unexpected containment type '{0}'", dbContainmentType)); + break; + } + if (swapIndex > 0) + { + var value = containmentTypes[swapIndex]; + containmentTypes.RemoveAt(swapIndex); + containmentTypes.Insert(0, value); + } + + return containmentTypes.ToArray(); + } + + private string[] GetRecoveryModels(Server server, DatabasePrototype prototype) + { + // if the server is shiloh or later, but not Managed Instance, enable the dropdown + var recoveryModelEnabled = (minimumVersionForRecoveryModel <= server.VersionMajor) && !IsAnyManagedInstance(server); + if (server.GetDisabledProperties().Contains("RecoveryModel") || !recoveryModelEnabled) + { + return Array.Empty(); + } + + var recoveryModels = new List(); + // Note: we still discriminate on IsAnyManagedInstance(server) because GetDisabledProperties() + // was not updated to handle SQL Managed Instance. + if (!IsAnyManagedInstance(server)) + { + + // add recovery model options to the dropdown + recoveryModels.Add(displayRecoveryModels[RecoveryModel.Full]); + recoveryModels.Add(displayRecoveryModels[RecoveryModel.BulkLogged]); + recoveryModels.Add(displayRecoveryModels[RecoveryModel.Simple]); + } + else + { + if (prototype.OriginalName.Equals("tempdb", StringComparison.CurrentCultureIgnoreCase) && prototype.IsSystemDB) + { + // tempdb supports 'simple recovery' only + recoveryModels.Add(displayRecoveryModels[RecoveryModel.Simple]); + } + else + { + // non-tempdb supports only 'full recovery' model + recoveryModels.Add(displayRecoveryModels[RecoveryModel.Full]); + } + } + + if (recoveryModelEnabled) + { + var swapIndex = 0; + switch (prototype.RecoveryModel) + { + case RecoveryModel.BulkLogged: + swapIndex = 1; + break; + + case RecoveryModel.Simple: + swapIndex = 2; + break; + + default: + Debug.Assert(RecoveryModel.Full == prototype.RecoveryModel, string.Format(CultureInfo.InvariantCulture, "Unknown recovery model '{0}'", prototype.RecoveryModel)); + break; + } + if (swapIndex > 0) + { + var value = recoveryModels[swapIndex]; + recoveryModels.RemoveAt(swapIndex); + recoveryModels.Insert(0, value); + } + } + return recoveryModels.ToArray(); + } + + private string[] GetCompatibilityLevelsAzure(DatabasePrototype prototype) + { + // For Azure we loop through all of the possible compatibility levels. We do this because there's only one compat level active on a + // version at a time, but that can change at any point so in order to reduce maintenance required when that happens we'll just find + // the one that matches the current set level and display that + foreach (var level in this.displayCompatLevels.Keys) + { + if (level == prototype.DatabaseCompatibilityLevel) + { + // Azure can't change the compat level so we only populate the current version + return new string[] { this.displayCompatLevels[level] }; + } + } + + Debug.Fail(string.Format(CultureInfo.InvariantCulture, "Unknown compatibility level '{0}'", prototype.DatabaseCompatibilityLevel)); + return Array.Empty(); + } + + private string[] GetCompatibilityLevels(int sqlServerVersion, DatabasePrototype prototype) + { + // Unlikely that we are hitting such an old SQL Server, but leaving to preserve + // the original semantic of this method. + if (sqlServerVersion < 8) + { + // we do not know this version number, we do not know the possible compatibility levels for the server + return Array.Empty(); + } + + var compatibilityLevels = new List(); + switch (sqlServerVersion) + { + case 8: // Shiloh + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version70]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version80]); + break; + case 9: // Yukon + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version70]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version80]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version90]); + break; + case 10: // Katmai + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version80]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version90]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version100]); + break; + case 11: // Denali + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version90]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version100]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version110]); + break; + case 12: // SQL2014 + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version100]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version110]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version120]); + break; + case 13: // SQL2016 + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version100]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version110]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version120]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version130]); + break; + case 14: // SQL2017 + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version100]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version110]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version120]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version130]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version140]); + break; + case 15: // SQL2019 + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version100]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version110]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version120]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version130]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version140]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version150]); + break; + /* SQL_VBUMP_REVIEW */ + default: + // It is either the latest SQL we know about, or some future version of SQL we + // do not know about. We play conservative and only add the compat level we know + // about so far. + // At vBump, add a new case and move the 'default' label there. + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version100]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version110]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version120]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version130]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version140]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version150]); + compatibilityLevels.Add(this.displayCompatLevels[CompatibilityLevel.Version160]); + break; + } + + // set the compatability level for this combo box based on the prototype + for (var i = 0; i < compatibilityLevels.Count; i++) + { + var level = compatibilityLevels[i]; + var prototypeLevel = this.displayCompatLevels[prototype.DatabaseCompatibilityLevel]; + if (level == prototypeLevel) + { + if (i > 0) + { + compatibilityLevels.RemoveAt(i); + compatibilityLevels.Insert(0, level); + } + return compatibilityLevels.ToArray(); + } + } + + // previous loop did not find the prototype compatibility level in this server's compatability options + // disable the compatability level option + return Array.Empty(); } } } \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseViewInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseViewInfo.cs new file mode 100644 index 00000000..ee1eca49 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/ObjectManagement/ObjectTypes/Database/DatabaseViewInfo.cs @@ -0,0 +1,18 @@ + +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +#nullable disable + +namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement +{ + public class DatabaseViewInfo : SqlObjectViewInfo + { + public string[] LoginNames { get; set; } + public string[] CollationNames { get; set; } + public string[] CompatibilityLevels { get; set; } + public string[] ContainmentTypes { get; set; } + public string[] RecoveryModels { get; set; } + } +} \ No newline at end of file diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs new file mode 100644 index 00000000..f0b9b6fa --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/DatabaseHandlerTests.cs @@ -0,0 +1,193 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Threading.Tasks; +using Microsoft.Data.SqlClient; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlTools.ServiceLayer.Connection; +using Microsoft.SqlTools.ServiceLayer.IntegrationTests.Utility; +using Microsoft.SqlTools.ServiceLayer.ObjectManagement; +using Microsoft.SqlTools.ServiceLayer.Test.Common; +using NUnit.Framework; + +namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement +{ + /// + /// Tests for the Database management component + /// + public class DatabaseHandlerTests + { + /// + /// Test the basic Create Database method handler by creating, updating, and then deleting a database. + /// + [Test] + public async Task DatabaseCreateAndUpdateTest_OnPrem() + { + await RunDatabaseCreateAndUpdateTest(TestServerType.OnPrem); + } + + /// + /// Test the Create Database method handler functionality against an Azure SQL database. + /// + [Test] + [Ignore("Test is not supported in the integration test pipeline.")] + public async Task DatabaseCreateAndUpdateTest_Azure() + { + await RunDatabaseCreateAndUpdateTest(TestServerType.Azure); + } + + private async Task RunDatabaseCreateAndUpdateTest(TestServerType serverType) + { + // setup, drop database if exists. + var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", serverType: serverType); + using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo)) + { + var server = new Server(new ServerConnection(sqlConn)); + + var testDatabase = ObjectManagementTestUtils.GetTestDatabaseInfo(); + var objUrn = ObjectManagementTestUtils.GetDatabaseURN(testDatabase.Name); + await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn); + + try + { + // create and update + var parametersForCreation = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Database, "", ""); + await ObjectManagementTestUtils.SaveObject(parametersForCreation, testDatabase); + Assert.True(databaseExists(testDatabase.Name!, server), $"Expected database '{testDatabase.Name}' was not created succesfully"); + + var parametersForUpdate = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", false, SqlObjectType.Database, "", objUrn); + await ObjectManagementTestUtils.SaveObject(parametersForUpdate, testDatabase); + + // cleanup + await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn, throwIfNotExist: true); + Assert.False(databaseExists(testDatabase.Name!, server), $"Database '{testDatabase.Name}' was not dropped succesfully"); + } + finally + { + // Cleanup using SMO if Drop didn't work + dropDatabase(server, testDatabase.Name!); + } + } + } + + /// + /// Test that the handler can export the Create Database operation to a SQL script. + /// + [Test] + public async Task DatabaseScriptTest() + { + var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master"); + using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo)) + { + var server = new Server(new ServerConnection(sqlConn)); + + var testDatabase = ObjectManagementTestUtils.GetTestDatabaseInfo(); + var objUrn = ObjectManagementTestUtils.GetDatabaseURN(testDatabase.Name); + await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn); + + try + { + var parametersForCreation = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Database, "", ""); + var script = await ObjectManagementTestUtils.ScriptObject(parametersForCreation, testDatabase); + Assert.True(!databaseExists(testDatabase.Name!, server), $"Database should not have been created for scripting operation"); + Assert.True(script.ToLowerInvariant().Contains($"create database [{testDatabase.Name!.ToLowerInvariant()}]")); + } + finally + { + // Cleanup database on the off-chance that scripting somehow created the database + dropDatabase(server, testDatabase.Name!); + } + } + } + + /// + /// Test that the handler correctly throws an error when trying to drop a database that doesn't exist. + /// + [Test] + public async Task DatabaseNotExistsErrorTest() + { + var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master"); + var testDatabase = ObjectManagementTestUtils.GetTestDatabaseInfo(); + var objUrn = ObjectManagementTestUtils.GetDatabaseURN(testDatabase.Name); + try + { + await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn, throwIfNotExist: true); + Assert.Fail("Did not throw an exception when trying to drop non-existent database."); + } + catch (FailedOperationException ex) + { + Assert.NotNull(ex.InnerException, "Expected inner exception was null."); + Assert.True(ex.InnerException is MissingObjectException, $"Received unexpected inner exception type: {ex.InnerException!.GetType()}"); + } + } + + /// + /// Test that the handler correctly throws an error when trying to create a database with the same name as an existing database. + /// + [Test] + public async Task DatabaseAlreadyExistsErrorTest() + { + var connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master"); + using (SqlConnection sqlConn = ConnectionService.OpenSqlConnection(connectionResult.ConnectionInfo)) + { + var server = new Server(new ServerConnection(sqlConn)); + + var testDatabase = ObjectManagementTestUtils.GetTestDatabaseInfo(); + var objUrn = ObjectManagementTestUtils.GetDatabaseURN(testDatabase.Name); + await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn); + + try + { + var parametersForCreation = ObjectManagementTestUtils.GetInitializeViewRequestParams(connectionResult.ConnectionInfo.OwnerUri, "master", true, SqlObjectType.Database, "", ""); + await ObjectManagementTestUtils.SaveObject(parametersForCreation, testDatabase); + Assert.True(databaseExists(testDatabase.Name!, server), $"Expected database '{testDatabase.Name}' was not created succesfully"); + + await ObjectManagementTestUtils.SaveObject(parametersForCreation, testDatabase); + Assert.Fail("Did not throw an exception when trying to create database with same name."); + } + catch (FailedOperationException ex) + { + Assert.NotNull(ex.InnerException, "Expected inner exception was null."); + Assert.True(ex.InnerException is ExecutionFailureException, $"Received unexpected inner exception type: {ex.InnerException!.GetType()}"); + Assert.NotNull(ex.InnerException.InnerException, "Expected inner-inner exception was null."); + Assert.True(ex.InnerException.InnerException is SqlException, $"Received unexpected inner-inner exception type: {ex.InnerException.InnerException!.GetType()}"); + } + finally + { + dropDatabase(server, testDatabase.Name!); + } + } + } + + private bool databaseExists(string dbName, Server server) + { + server.Databases.Refresh(); + bool dbFound = false; + foreach (Database db in server.Databases) + { + if (db.Name == dbName) + { + dbFound = true; + break; + } + } + return dbFound; + } + + private void dropDatabase(Server server, string databaseName) + { + server.Databases.Refresh(); + foreach (Database db in server.Databases) + { + if (db.Name == databaseName) + { + db.DropIfExists(); + break; + } + } + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs index d2244fea..05a90dcd 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/ObjectManagement/ObjectManagementTestUtils.cs @@ -41,6 +41,11 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement return string.Format(@"{0}\{1}", Environment.UserDomainName, Environment.UserName); } + internal static string GetDatabaseURN(string name) + { + return string.Format("Server/Database[@Name='{0}']", name); + } + internal static string GetLoginURN(string name) { return string.Format("Server/Login[@Name='{0}']", name); @@ -56,6 +61,19 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement return string.Format("Server/Credential[@Name = '{0}']", name); } + internal static DatabaseInfo GetTestDatabaseInfo() + { + return new DatabaseInfo() + { + Name = "TestDatabaseName_" + new Random().NextInt64(10000000, 90000000).ToString(), + Owner = "", + CollationName = "SQL_Latin1_General_CP1_CI_AS", + CompatibilityLevel = "SQL Server 2022 (160)", + ContainmentType = "None", + RecoveryModel = "Full" + }; + } + internal static LoginInfo GetTestLoginInfo() { return new LoginInfo() @@ -134,7 +152,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement await Service.HandleDisposeViewRequest(new DisposeViewRequestParams { ContextId = parameters.ContextId }, disposeViewRequestContext.Object); } - internal static async Task ScriptObject(InitializeViewRequestParams parameters, SqlObject obj) + internal static async Task ScriptObject(InitializeViewRequestParams parameters, SqlObject obj) { // Initialize the view var initViewRequestContext = new Mock>(); @@ -143,9 +161,12 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement await Service.HandleInitializeViewRequest(parameters, initViewRequestContext.Object); // Script the object + string script = string.Empty; var scriptObjectRequestContext = new Mock>(); - scriptObjectRequestContext.Setup(x => x.SendResult(It.IsAny())) - .Returns(Task.FromResult("")); + scriptObjectRequestContext + .Setup(x => x.SendResult(It.IsAny())) + .Returns(Task.FromResult("")) + .Callback(scriptResult => script = scriptResult); await Service.HandleScriptObjectRequest(new ScriptObjectRequestParams { ContextId = parameters.ContextId, Object = JToken.FromObject(obj) }, scriptObjectRequestContext.Object); // Dispose the view @@ -153,14 +174,17 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement disposeViewRequestContext.Setup(x => x.SendResult(It.IsAny())) .Returns(Task.FromResult(new DisposeViewRequestResponse())); await Service.HandleDisposeViewRequest(new DisposeViewRequestParams { ContextId = parameters.ContextId }, disposeViewRequestContext.Object); + + return script; } - internal static async Task DropObject(string connectionUri, string objectUrn) + internal static async Task DropObject(string connectionUri, string objectUrn, bool throwIfNotExist = false) { var dropParams = new DropRequestParams { ConnectionUri = connectionUri, - ObjectUrn = objectUrn + ObjectUrn = objectUrn, + ThrowIfNotExist = throwIfNotExist }; var dropRequestContext = new Mock>();