diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs index 194d6415..5583a837 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/ConnectionService.cs @@ -100,7 +100,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection /// /// Callback for ondisconnect handler /// - public delegate Task OnDisconnectHandler(ConnectionSummary summary, string ownerUri); + public delegate Task OnDisconnectHandler(IConnectionSummary summary, string ownerUri); /// /// List of onconnection handlers @@ -1007,7 +1007,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection // Fire a connection changed event ConnectionChangedParams parameters = new ConnectionChangedParams(); - ConnectionSummary summary = info.ConnectionDetails; + IConnectionSummary summary = info.ConnectionDetails; parameters.Connection = summary.Clone(); parameters.OwnerUri = ownerUri; ServiceHost.SendEvent(ConnectionChangedNotification.Type, parameters); diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetails.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetails.cs index 57312cbf..707ad49f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetails.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionDetails.cs @@ -3,10 +3,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -using System; -using System.Collections.Generic; -using System.Globalization; -using Microsoft.SqlTools.Utility; +using Microsoft.SqlTools.ServiceLayer.Utility; namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts { @@ -16,18 +13,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts /// /// If this contract is ever changed, be sure to update ConnectionDetailsExtensions methods. /// - public class ConnectionDetails : ConnectionSummary + public class ConnectionDetails : GeneralRequestDetails, IConnectionSummary { - public ConnectionDetails() + public ConnectionDetails() : base() { - Options = new Dictionary(); } - /// - /// Gets or Sets the connection options - /// - public Dictionary Options { get; set; } - /// /// Gets or sets the connection password /// @@ -46,7 +37,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts /// /// Gets or sets the connection server name /// - public override string ServerName + public string ServerName { get { @@ -62,7 +53,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts /// /// Gets or sets the connection database name /// - public override string DatabaseName + public string DatabaseName { get { @@ -78,7 +69,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts /// /// Gets or sets the connection user name /// - public override string UserName + public string UserName { get { @@ -459,49 +450,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts } } - private T GetOptionValue(string name) - { - T result = default(T); - if (Options != null && Options.ContainsKey(name)) - { - object value = Options[name]; - try - { - if (value != null && (typeof(T) != value.GetType())) - { - if (typeof(T) == typeof(int) || typeof(T) == typeof(int?)) - { - value = Convert.ToInt32(value); - } - else if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?)) - { - value = Convert.ToBoolean(value); - } - } - result = value != null ? (T)value : default(T); - } - catch - { - result = default(T); - Logger.Write(LogLevel.Warning, string.Format(CultureInfo.InvariantCulture, - "Cannot convert option value {0}:{1} to {2}", name, value ?? "", typeof(T))); - } - } - return result; - } - - private void SetOptionValue(string name, T value) - { - Options = Options ?? new Dictionary(); - if (Options.ContainsKey(name)) - { - Options[name] = value; - } - else - { - Options.Add(name, value); - } - } + public bool IsComparableTo(ConnectionDetails other) { diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionSummary.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionSummary.cs index fa99ab8a..54642c87 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionSummary.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionSummary.cs @@ -3,12 +3,32 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // + namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts { + + public interface IConnectionSummary + { + /// + /// Gets or sets the connection server name + /// + string ServerName { get; set; } + + /// + /// Gets or sets the connection database name + /// + string DatabaseName { get; set; } + + /// + /// Gets or sets the connection user name + /// + string UserName { get; set; } + } + /// /// Provides high level information about a connection. /// - public class ConnectionSummary + public class ConnectionSummary : IConnectionSummary { /// /// Gets or sets the connection server name diff --git a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionSummaryExtensions.cs b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionSummaryExtensions.cs index 02bc7623..bdce9f04 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionSummaryExtensions.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Connection/Contracts/ConnectionSummaryExtensions.cs @@ -13,7 +13,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.Contracts /// /// Create a copy of a ConnectionSummary object /// - public static ConnectionSummary Clone(this ConnectionSummary summary) + public static ConnectionSummary Clone(this IConnectionSummary summary) { return new ConnectionSummary() { diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/DatabaseFileInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/DatabaseFileInfo.cs new file mode 100644 index 00000000..9321655c --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/DatabaseFileInfo.cs @@ -0,0 +1,60 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Linq; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts +{ + /// + /// Class includes information about a file related to a database operation. + /// Can be used for backup set files or restored database files + /// + public class DatabaseFileInfo + { + /// + /// The property name used for ids + /// + public const string IdPropertyName = "Id"; + + public DatabaseFileInfo(LocalizedPropertyInfo[] properties) + { + Validate.IsNotNull("properties", properties); + + this.Properties = properties; + if (this.Properties != null ) + { + var idProperty = this.Properties.FirstOrDefault(x => x.PropertyName == IdPropertyName); + Id = idProperty == null || idProperty.PropertyValue == null ? string.Empty : idProperty.PropertyValue.ToString(); + } + } + + /// + /// Properties + /// + public LocalizedPropertyInfo[] Properties { get; private set; } + + public string GetPropertyValueAsString(string name) + { + string value = string.Empty; + if (Properties != null) + { + var property = Properties.FirstOrDefault(x => x.PropertyName == name); + value = property == null || property.PropertyValue == null ? string.Empty : property.PropertyValue.ToString(); + } + return value; + } + + /// + /// Unique id for this item + /// + public string Id { get; private set; } + + /// + /// Indicates whether the item is selected in client + /// + public bool IsSelected { get; set; } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/LocalizedPropertyInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/LocalizedPropertyInfo.cs new file mode 100644 index 00000000..617b3bd4 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/LocalizedPropertyInfo.cs @@ -0,0 +1,72 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Globalization; + +namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts +{ + public class LocalizedPropertyInfo + { + + private string propertyValueDisplayName; + private string propertyDisplayName; + + /// + /// Property name + /// + public string PropertyName { get; set; } + + + /// + /// Property value + /// + public object PropertyValue { get; set; } + + /// + /// Property display name + /// + public string PropertyDisplayName + { + get + { + return string.IsNullOrEmpty(this.propertyDisplayName) ? PropertyName : this.propertyDisplayName; + } + set + { + this.propertyDisplayName = value; + } + } + + /// + /// Property display name for the value + /// + public string PropertyValueDisplayName + { + get + { + return string.IsNullOrEmpty(propertyValueDisplayName) ? GetLocalizedPropertyValue() : propertyValueDisplayName; + } + set + { + this.propertyValueDisplayName = value; + } + } + + private string GetLocalizedPropertyValue() + { + string displayName = string.Empty; + if(PropertyValue is DateTime) + { + displayName = ((DateTime)PropertyValue) != DateTime.MinValue ? Convert.ToString(PropertyValue, CultureInfo.CurrentCulture) : string.Empty; + } + else + { + displayName = Convert.ToString(PropertyValue, CultureInfo.CurrentCulture); + } + return displayName; + } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/RestoreRequest.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/RestoreRequest.cs index d2e30b55..be5f622b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/RestoreRequest.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/Contracts/RestoreRequest.cs @@ -5,33 +5,106 @@ using System.Collections.Generic; using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.ServiceLayer.Utility; namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts { /// /// Restore request parameters /// - public class RestoreParams + public class RestoreParams : GeneralRequestDetails { + public string SessionId + { + get + { + return GetOptionValue("sessionId"); + } + set + { + SetOptionValue("sessionId", value); + } + } + /// /// The Uri to find the connection to do the restore operations /// public string OwnerUri { get; set; } /// - /// The backup file path + /// Comma delimited list of backup files /// - public string BackupFilePath { get; set; } + public string BackupFilePaths + { + get + { + return GetOptionValue("backupFilePaths"); + } + set + { + SetOptionValue("backupFilePaths", value); + } + } /// /// Target Database name to restore to /// - public string DatabaseName { get; set; } + public string TargetDatabaseName + { + get + { + return GetOptionValue("targetDatabaseName"); + } + set + { + SetOptionValue("targetDatabaseName", value); + } + } + + /// + /// Source Database name to restore from + /// + public string SourceDatabaseName + { + get + { + return GetOptionValue("sourceDatabaseName"); + } + set + { + SetOptionValue("sourceDatabaseName", value); + } + } /// /// If set to true, the db files will be relocated to default data location in the server /// - public bool RelocateDbFiles { get; set; } + public bool RelocateDbFiles + { + get + { + return GetOptionValue("relocateDbFiles"); + } + set + { + SetOptionValue("relocateDbFiles", value); + } + } + + /// + /// Ids of the backup set to restore + /// + public string[] SelectedBackupSets + { + get + { + return GetOptionValue("selectedBackupSets"); + } + set + { + SetOptionValue("selectedBackupSets", value); + } + } } /// @@ -87,10 +160,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts /// public class RestorePlanResponse { - /// - /// The backup file path - /// - public string BackupFilePath { get; set; } + public string RestoreSessionId { get; set; } + + public DatabaseFileInfo[] BackupSetsToRestore { get; set; } /// /// Indicates whether the restore operation is supported @@ -107,6 +179,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts /// public IEnumerable DbFiles { get; set; } + /// + /// Database names extracted from backup sets + /// + public string[] DatabaseNamesFromBackupSets { get; set; } + /// /// Server name /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/DisasterRecoveryService.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/DisasterRecoveryService.cs index d2006a61..e01a7d79 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/DisasterRecoveryService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/DisasterRecoveryService.cs @@ -26,7 +26,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery { private static readonly Lazy instance = new Lazy(() => new DisasterRecoveryService()); private static ConnectionService connectionService = null; - private RestoreDatabaseHelper restoreDatabaseService = new RestoreDatabaseHelper(); + private RestoreDatabaseHelper restoreDatabaseService = RestoreDatabaseHelper.Instance; /// /// Default, parameterless constructor. diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/BackupSetInfo.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/BackupSetInfo.cs index 89787946..bd2e23f4 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/BackupSetInfo.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/BackupSetInfo.cs @@ -3,6 +3,14 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Linq; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts; + namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation { /// @@ -10,14 +18,186 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation /// public class BackupSetInfo { + public const string BackupComponentPropertyName = "Component"; + public const string NamePropertyName = "Name"; + public const string BackupTypePropertyName = "Type"; + public const string ServerNamePropertyName = "Server"; + public const string DatabaseNamePropertyName = "Database"; + public const string PositionPropertyName = "Position"; + public const string FirstLsnPropertyName = "FirstLSN"; + public const string LastLsnPropertyName = "LastLSN"; + public const string CheckpointLsnPropertyName = "CheckpointLSN"; + public const string FullLsnPropertyName = "FullLSN"; + public const string StartDatePropertyName = "StartDate"; + public const string FinishDatePropertyName = "FinishDate"; + public const string SizePropertyName = "Size"; + public const string UserNamePropertyName = "UserName"; + public const string ExpirationPropertyName = "Expiration"; + + private Dictionary properties; + + public BackupSetInfo(Dictionary properties) + { + this.properties = properties; + } + /// /// Backup type (Full, Transaction Log, Differential ...) /// - public string BackupType { get; set; } + public string BackupType + { + get + { + return GetPropertyValueAsString(BackupTypePropertyName); + } + } /// - /// Backup component (Database, File, Log ...) + /// Backup set properties /// - public string BackupComponent { get; set; } + public ReadOnlyDictionary Properties + { + get + { + return new ReadOnlyDictionary(this.properties); + } + } + + /// + /// Convert properties to array + /// + /// + public LocalizedPropertyInfo[] ConvertPropertiesToArray() + { + return this.properties == null ? new LocalizedPropertyInfo[] { } : this.properties.Values.ToArray(); + } + + /// + /// Creates new BackupSet info + /// + /// + public static BackupSetInfo Create(Restore restore, Server server) + { + BackupSet backupSet = restore.BackupSet; + Dictionary properties = new Dictionary(); + + string bkSetComponent; + string bkSetType; + CommonUtilities.GetBackupSetTypeAndComponent(backupSet.BackupSetType, out bkSetType, out bkSetComponent); + + if (server.Version.Major > 8 && backupSet.IsCopyOnly) + { + bkSetType += SR.RestoreCopyOnly; + } + + properties.Add(NamePropertyName, new LocalizedPropertyInfo + { + PropertyName = NamePropertyName, + PropertyValue = backupSet.Name, + PropertyDisplayName = SR.RestoreBackupSetName + }); + properties.Add(BackupComponentPropertyName, new LocalizedPropertyInfo + { + PropertyName = BackupComponentPropertyName, + PropertyValue = bkSetComponent, + PropertyDisplayName = SR.RestoreBackupSetType + }); + properties.Add(BackupTypePropertyName, new LocalizedPropertyInfo + { + PropertyName = BackupTypePropertyName, + PropertyValue = bkSetType, + PropertyDisplayName = SR.RestoreBackupSetComponent + }); + properties.Add(ServerNamePropertyName, new LocalizedPropertyInfo + { + PropertyName = ServerNamePropertyName, + PropertyValue = backupSet.ServerName, + PropertyDisplayName = SR.RestoreBackupSetServer + }); + properties.Add(DatabaseNamePropertyName, new LocalizedPropertyInfo + { + PropertyName = DatabaseNamePropertyName, + PropertyValue = backupSet.DatabaseName, + PropertyDisplayName = SR.RestoreBackupSetDatabase + }); + properties.Add(PositionPropertyName, new LocalizedPropertyInfo + { + PropertyName = PositionPropertyName, + PropertyValueDisplayName = Convert.ToString(backupSet.Position, CultureInfo.CurrentCulture), + PropertyValue = backupSet.Position, + PropertyDisplayName = SR.RestoreBackupSetPosition + }); + properties.Add(FirstLsnPropertyName, new LocalizedPropertyInfo + { + PropertyName = FirstLsnPropertyName, + PropertyValue = backupSet.FirstLsn, + PropertyDisplayName = SR.RestoreBackupSetFirstLsn + }); + properties.Add(LastLsnPropertyName, new LocalizedPropertyInfo + { + PropertyName = LastLsnPropertyName, + PropertyValue = backupSet.LastLsn, + PropertyDisplayName = SR.RestoreBackupSetLastLsn + }); + properties.Add(FullLsnPropertyName, new LocalizedPropertyInfo + { + PropertyName = FullLsnPropertyName, + PropertyValue = backupSet.DatabaseBackupLsn, + PropertyDisplayName = SR.RestoreBackupSetFullLsn + }); + properties.Add(CheckpointLsnPropertyName, new LocalizedPropertyInfo + { + PropertyName = CheckpointLsnPropertyName, + PropertyValue = backupSet.CheckpointLsn, + PropertyDisplayName = SR.RestoreBackupSetCheckpointLsn + }); + properties.Add(StartDatePropertyName, new LocalizedPropertyInfo + { + PropertyName = StartDatePropertyName, + PropertyValue = backupSet.BackupStartDate, + PropertyDisplayName = SR.RestoreBackupSetStartDate + }); + properties.Add(FinishDatePropertyName, new LocalizedPropertyInfo + { + PropertyName = FinishDatePropertyName, + PropertyValue = backupSet.BackupFinishDate, + PropertyDisplayName = SR.RestoreBackupSetFinishDate + }); + properties.Add(SizePropertyName, new LocalizedPropertyInfo + { + PropertyName = SizePropertyName, + PropertyValue = backupSet.BackupSize, + PropertyDisplayName = SR.RestoreBackupSetSize, + }); + properties.Add(UserNamePropertyName, new LocalizedPropertyInfo + { + PropertyName = UserNamePropertyName, + PropertyValue = backupSet.UserName, + PropertyDisplayName = SR.RestoreBackupSetUserName, + }); + properties.Add(ExpirationPropertyName, new LocalizedPropertyInfo + { + PropertyName = ExpirationPropertyName, + PropertyValue = backupSet.ExpirationDate, + PropertyDisplayName = SR.RestoreBackupSetExpiration, + }); + properties.Add(DatabaseFileInfo.IdPropertyName, new LocalizedPropertyInfo + { + PropertyName = DatabaseFileInfo.IdPropertyName, + PropertyValue = backupSet.BackupSetGuid + }); + + return new BackupSetInfo(properties); + } + + public string GetPropertyValueAsString(string propertyName) + { + LocalizedPropertyInfo propertyValue = null; + if(!string.IsNullOrEmpty(propertyName) && Properties != null) + { + Properties.TryGetValue(propertyName, out propertyValue); + } + return propertyValue.PropertyValue != null ? propertyValue.PropertyValue.ToString() : string.Empty; + } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseHelper.cs index e4322c5d..43e0a40a 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseHelper.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseHelper.cs @@ -15,6 +15,7 @@ using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection; using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts; using Microsoft.SqlTools.ServiceLayer.TaskServices; using Microsoft.SqlTools.Utility; +using System.Collections.Concurrent; namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation { @@ -24,6 +25,22 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation public class RestoreDatabaseHelper { + private static RestoreDatabaseHelper instance = new RestoreDatabaseHelper(); + private ConcurrentDictionary restoreSessions = new ConcurrentDictionary(); + + internal RestoreDatabaseHelper() + { + + } + + public static RestoreDatabaseHelper Instance + { + get + { + return instance; + } + } + /// /// Create a backup task for execution and cancellation /// @@ -45,7 +62,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation { if (restoreDataObject.IsValid) { - ExecuteRestore(restoreDataObject); + ExecuteRestore(restoreDataObject, sqlTask); result.TaskStatus = SqlTaskStatus.Succeeded; } else @@ -135,7 +152,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation { RestorePlanResponse response = new RestorePlanResponse() { - DatabaseName = restoreDataObject.RestoreParams.DatabaseName + DatabaseName = restoreDataObject.RestoreParams.TargetDatabaseName }; try { @@ -145,6 +162,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation if (restoreDataObject != null && restoreDataObject.IsValid) { + response.RestoreSessionId = restoreDataObject.SessionId; response.DatabaseName = restoreDataObject.TargetDatabase; response.DbFiles = restoreDataObject.DbFiles.Select(x => new RestoreDatabaseFileInfo { @@ -160,6 +178,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation response.ErrorMessage = SR.RestoreNotSupported; } + response.BackupSetsToRestore = restoreDataObject.GetBackupSetInfo().Select(x => new DatabaseFileInfo(x.ConvertPropertiesToArray())).ToArray(); + var dbNames = restoreDataObject.GetSourceDbNames(); + response.DatabaseNamesFromBackupSets = dbNames == null ? new string[] { } : dbNames.ToArray(); response.RelocateFilesNeeded = !restoreDataObject.DbFilesLocationAreValid(); response.DefaultDataFolder = restoreDataObject.DefaultDataFileFolder; response.DefaultLogFolder = restoreDataObject.DefaultLogFileFolder; @@ -204,7 +225,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation if (restoreDataObject != null) { var backupTypes = restoreDataObject.GetBackupSetInfo(); - return backupTypes.Any(x => x.BackupType.StartsWith(RestoreConstants.TypeFull)); + var selectedBackupSets = restoreDataObject.RestoreParams.SelectedBackupSets; + return backupTypes.Any(x => (selectedBackupSets == null || selectedBackupSets.Contains(x.GetPropertyValueAsString(DatabaseFileInfo.IdPropertyName))) + && x.BackupType.StartsWith(RestoreConstants.TypeFull)); } return false; } @@ -215,6 +238,24 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation /// Restore request parameters /// Restore task object public RestoreDatabaseTaskDataObject CreateRestoreDatabaseTaskDataObject(RestoreParams restoreParams) + { + RestoreDatabaseTaskDataObject restoreTaskObject = null; + if (!string.IsNullOrWhiteSpace(restoreParams.SessionId)) + { + this.restoreSessions.TryGetValue(restoreParams.SessionId, out restoreTaskObject); + } + + if (restoreTaskObject == null) + { + restoreTaskObject = CreateRestoreForNewSession(restoreParams); + string sessionId = string.IsNullOrWhiteSpace(restoreParams.SessionId) ? Guid.NewGuid().ToString() : restoreParams.SessionId; + this.restoreSessions.AddOrUpdate(sessionId, restoreTaskObject, (key, oldSession) => restoreTaskObject); + restoreTaskObject.SessionId = sessionId; + } + return restoreTaskObject; + } + + private RestoreDatabaseTaskDataObject CreateRestoreForNewSession(RestoreParams restoreParams) { ConnectionInfo connInfo; DisasterRecoveryService.ConnectionServiceInstance.TryFindConnection( @@ -242,7 +283,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation } Server server = new Server(new ServerConnection(connection)); - RestoreDatabaseTaskDataObject restoreDataObject = new RestoreDatabaseTaskDataObject(server, restoreParams.DatabaseName); + RestoreDatabaseTaskDataObject restoreDataObject = new RestoreDatabaseTaskDataObject(server, restoreParams.TargetDatabaseName); restoreDataObject.RestoreParams = restoreParams; return restoreDataObject; } @@ -256,35 +297,54 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation /// private void UpdateRestorePlan(RestoreDatabaseTaskDataObject restoreDataObject) { - if (!string.IsNullOrEmpty(restoreDataObject.RestoreParams.BackupFilePath)) + if (restoreDataObject.PlanUpdateRequired) { - restoreDataObject.AddFile(restoreDataObject.RestoreParams.BackupFilePath); - } - restoreDataObject.RestorePlanner.ReadHeaderFromMedia = !string.IsNullOrEmpty(restoreDataObject.RestoreParams.BackupFilePath); - - restoreDataObject.RestorePlanner.DatabaseName = restoreDataObject.DefaultDbName; - restoreDataObject.TargetDatabase = restoreDataObject.RestoreParams.DatabaseName; - //TODO: used for other types of restore - /*bool isTailLogBackupPossible = restoreDataObject.RestorePlanner.IsTailLogBackupPossible(restoreDataObject.RestorePlanner.DatabaseName); - restoreDataObject.RestorePlanner.BackupTailLog = isTailLogBackupPossible; - restoreDataObject.TailLogBackupFile = restoreDataObject.Util.GetDefaultTailLogbackupFile(dbName); - restoreDataObject.RestorePlanner.TailLogBackupFile = restoreDataObject.TailLogBackupFile; - */ + if (!string.IsNullOrEmpty(restoreDataObject.RestoreParams.BackupFilePaths)) + { + restoreDataObject.AddFiles(restoreDataObject.RestoreParams.BackupFilePaths); + } + restoreDataObject.RestorePlanner.ReadHeaderFromMedia = !string.IsNullOrEmpty(restoreDataObject.RestoreParams.BackupFilePaths); - restoreDataObject.UpdateRestorePlan(restoreDataObject.RestoreParams.RelocateDbFiles); + if (string.IsNullOrWhiteSpace(restoreDataObject.RestoreParams.SourceDatabaseName)) + { + restoreDataObject.RestorePlanner.DatabaseName = restoreDataObject.DefaultDbName; + } + else + { + restoreDataObject.RestorePlanner.DatabaseName = restoreDataObject.RestoreParams.SourceDatabaseName; + } + restoreDataObject.TargetDatabase = restoreDataObject.RestoreParams.TargetDatabaseName; + //TODO: used for other types of restore + /*bool isTailLogBackupPossible = restoreDataObject.RestorePlanner.IsTailLogBackupPossible(restoreDataObject.RestorePlanner.DatabaseName); + restoreDataObject.RestorePlanner.BackupTailLog = isTailLogBackupPossible; + restoreDataObject.TailLogBackupFile = restoreDataObject.Util.GetDefaultTailLogbackupFile(dbName); + restoreDataObject.RestorePlanner.TailLogBackupFile = restoreDataObject.TailLogBackupFile; + */ + + restoreDataObject.UpdateRestorePlan(restoreDataObject.RestoreParams.RelocateDbFiles); + } } /// /// Executes the restore operation /// /// - public void ExecuteRestore(RestoreDatabaseTaskDataObject restoreDataObject) + public void ExecuteRestore(RestoreDatabaseTaskDataObject restoreDataObject, SqlTask sqlTask = null) { + // Restore Plan should be already created and updated at this point UpdateRestorePlan(restoreDataObject); if (restoreDataObject != null && CanRestore(restoreDataObject)) { - restoreDataObject.RestorePlan.Execute(); + try + { + restoreDataObject.SqlTask = sqlTask; + restoreDataObject.Execute(); + } + catch(Exception ex) + { + throw ex; + } } else { diff --git a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseTaskDataObject.cs b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseTaskDataObject.cs index 1f6b2351..d746e89a 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseTaskDataObject.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DisasterRecovery/RestoreOperation/RestoreDatabaseTaskDataObject.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts; +using Microsoft.SqlTools.ServiceLayer.TaskServices; namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation { @@ -17,8 +18,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation /// public class RestoreDatabaseTaskDataObject { + + private const char BackupMediaNameSeparator = ','; public RestoreDatabaseTaskDataObject(Server server, String databaseName) { + PlanUpdateRequired = true; this.Server = server; this.Util = new RestoreUtil(server); restorePlanner = new DatabaseRestorePlanner(server); @@ -39,6 +43,16 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation this.restoreOptions.PercentCompleteNotification = 5; } + /// + /// Restore session id + /// + public string SessionId { get; set; } + + /// + /// Sql task assigned to the restore object + /// + public SqlTask SqlTask { get; set; } + public string TargetDatabase { get @@ -86,14 +100,74 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation /// /// Add a backup file to restore plan media list /// - /// - public void AddFile(string filePath) + /// + public void AddFiles(string filePaths) { - this.RestorePlanner.BackupMediaList.Add(new BackupDeviceItem + PlanUpdateRequired = true; + if (!string.IsNullOrWhiteSpace(filePaths)) { - DeviceType = DeviceType.File, - Name = filePath - }); + string[] files = filePaths.Split(BackupMediaNameSeparator); + files = files.Select(x => x.Trim()).ToArray(); + foreach (var file in files) + { + if (!this.RestorePlanner.BackupMediaList.Any(x => x.Name == file)) + { + this.RestorePlanner.BackupMediaList.Add(new BackupDeviceItem + { + DeviceType = DeviceType.File, + Name = file + }); + } + } + + var itemsToRemove = this.RestorePlanner.BackupMediaList.Where(x => !files.Contains(x.Name)); + foreach (var item in itemsToRemove) + { + this.RestorePlanner.BackupMediaList.Remove(item); + } + } + } + + /// + /// Removes the backup sets that are filtered in the request + /// + public void RemoveFilteredBackupSets() + { + var backupSetIdsToRestore = RestoreParams.SelectedBackupSets; + if (backupSetIdsToRestore != null) + { + var ids = backupSetIdsToRestore.Select(x => + { + Guid guid; + Guid.TryParse(x, out guid); + return guid; + } + ); + restorePlan.RestoreOperations.RemoveAll(x => !ids.Contains(x.BackupSet.BackupSetGuid)); + } + } + + /// + /// Executes the restore operations + /// + public void Execute() + { + RestorePlan restorePlan = RestorePlan; + // ssms creates a new restore plan by calling GetRestorePlanForExecutionAndScript and + // Doens't use the plan already created here. not sure why, using the existing restore plan doesn't make + // any issue so far so keeping in it for now but we might want to double check later + if (restorePlan != null && restorePlan.RestoreOperations.Count > 0) + { + RemoveFilteredBackupSets(); + restorePlan.PercentComplete += (object sender, PercentCompleteEventArgs e) => + { + if (SqlTask != null) + { + SqlTask.AddMessage($"{e.Percent}%", SqlTaskStatus.InProgress); + } + }; + restorePlan.Execute(); + } } public RestoreUtil Util { get; set; } @@ -109,7 +183,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation } private string tailLogBackupFile; - private bool planUpdateRequired = false; + public bool PlanUpdateRequired { get; private set; } /// /// File to backup tail log before doing the restore @@ -122,7 +196,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation if (tailLogBackupFile == null || !tailLogBackupFile.Equals(value)) { this.RestorePlanner.TailLogBackupFile = value; - this.planUpdateRequired = true; + this.PlanUpdateRequired = true; this.tailLogBackupFile = value; } } @@ -384,43 +458,6 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation /// internal string ContainerSharedAccessPolicy = string.Empty; - /// - /// Gets RestorePlan to perform restore and to script - /// - public RestorePlan GetRestorePlanForExecutionAndScript() - { - this.ActiveException = null; //Clear any existing exceptions as the plan is getting recreated. - //Clear any existing exceptions as new plan is getting recreated. - this.CreateOrUpdateRestorePlanException = null; - bool tailLogBackup = this.RestorePlanner.BackupTailLog; - if (this.planUpdateRequired) - { - this.RestorePlan = this.RestorePlanner.CreateRestorePlan(this.RestoreOptions); - this.UpdateRestoreSelected(); - this.Util.AddCredentialNameForUrlBackupSet(this.RestorePlan, this.CredentialName); - } - RestorePlan rp = new RestorePlan(this.Server); - rp.RestoreAction = RestoreActionType.Database; - if (this.RestorePlan != null) - { - if (this.RestorePlan.TailLogBackupOperation != null && tailLogBackup) - { - rp.TailLogBackupOperation = this.RestorePlan.TailLogBackupOperation; - } - int i = 0; - foreach (Restore res in this.RestorePlan.RestoreOperations) - { - if (this.RestoreSelected[i] == true) - { - rp.RestoreOperations.Add(res); - } - i++; - } - } - this.SetRestorePlanProperties(rp); - return rp; - } - /// /// Updates the RestoreSelected Array to hold information about updated Restore Plan /// @@ -472,17 +509,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation List result = new List(); foreach (Restore restore in RestorePlan.RestoreOperations) { - BackupSet backupSet = restore.BackupSet; - - String bkSetComponent; - String bkSetType; - CommonUtilities.GetBackupSetTypeAndComponent(backupSet.BackupSetType, out bkSetType, out bkSetComponent); - - if (this.Server.Version.Major > 8 && backupSet.IsCopyOnly) - { - bkSetType += " (Copy Only)"; - } - result.Add(new BackupSetInfo { BackupComponent = bkSetComponent, BackupType = bkSetType }); + result.Add(BackupSetInfo.Create(restore, Server)); } return result; @@ -564,7 +591,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation //Clear any existing exceptions as new plan is getting recreated. this.CreateOrUpdateRestorePlanException = null; this.DbFiles.Clear(); - this.planUpdateRequired = false; + this.PlanUpdateRequired = false; this.restorePlan = null; if (String.IsNullOrEmpty(this.RestorePlanner.DatabaseName)) { @@ -666,7 +693,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation if (this.RestorePlanner.BackupTailLog != value) { this.RestorePlanner.BackupTailLog = value; - this.planUpdateRequired = true; + this.PlanUpdateRequired = true; } } } @@ -685,7 +712,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation if (this.RestorePlanner.TailLogWithNoRecovery != value) { this.RestorePlanner.TailLogWithNoRecovery = value; - this.planUpdateRequired = true; + this.PlanUpdateRequired = true; } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs index c788e734..ed52e61b 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/LanguageServices/LanguageService.cs @@ -729,7 +729,7 @@ namespace Microsoft.SqlTools.ServiceLayer.LanguageServices /// it is the last URI connected to a particular connection, /// then remove the cache. /// - public async Task RemoveAutoCompleteCacheUriReference(ConnectionSummary summary, string ownerUri) + public async Task RemoveAutoCompleteCacheUriReference(IConnectionSummary summary, string ownerUri) { RemoveScriptParseInfo(ownerUri); diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs index 5a2221ea..7491761c 100755 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.cs @@ -3349,6 +3349,134 @@ namespace Microsoft.SqlTools.ServiceLayer } } + public static string RestoreCopyOnly + { + get + { + return Keys.GetString(Keys.RestoreCopyOnly); + } + } + + public static string RestoreBackupSetComponent + { + get + { + return Keys.GetString(Keys.RestoreBackupSetComponent); + } + } + + public static string RestoreBackupSetName + { + get + { + return Keys.GetString(Keys.RestoreBackupSetName); + } + } + + public static string RestoreBackupSetType + { + get + { + return Keys.GetString(Keys.RestoreBackupSetType); + } + } + + public static string RestoreBackupSetServer + { + get + { + return Keys.GetString(Keys.RestoreBackupSetServer); + } + } + + public static string RestoreBackupSetDatabase + { + get + { + return Keys.GetString(Keys.RestoreBackupSetDatabase); + } + } + + public static string RestoreBackupSetPosition + { + get + { + return Keys.GetString(Keys.RestoreBackupSetPosition); + } + } + + public static string RestoreBackupSetFirstLsn + { + get + { + return Keys.GetString(Keys.RestoreBackupSetFirstLsn); + } + } + + public static string RestoreBackupSetLastLsn + { + get + { + return Keys.GetString(Keys.RestoreBackupSetLastLsn); + } + } + + public static string RestoreBackupSetCheckpointLsn + { + get + { + return Keys.GetString(Keys.RestoreBackupSetCheckpointLsn); + } + } + + public static string RestoreBackupSetFullLsn + { + get + { + return Keys.GetString(Keys.RestoreBackupSetFullLsn); + } + } + + public static string RestoreBackupSetStartDate + { + get + { + return Keys.GetString(Keys.RestoreBackupSetStartDate); + } + } + + public static string RestoreBackupSetFinishDate + { + get + { + return Keys.GetString(Keys.RestoreBackupSetFinishDate); + } + } + + public static string RestoreBackupSetSize + { + get + { + return Keys.GetString(Keys.RestoreBackupSetSize); + } + } + + public static string RestoreBackupSetUserName + { + get + { + return Keys.GetString(Keys.RestoreBackupSetUserName); + } + } + + public static string RestoreBackupSetExpiration + { + get + { + return Keys.GetString(Keys.RestoreBackupSetExpiration); + } + } + public static string ConnectionServiceListDbErrorNotConnected(string uri) { return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri); @@ -4714,6 +4842,54 @@ namespace Microsoft.SqlTools.ServiceLayer public const string RestoreTaskName = "RestoreTaskName"; + public const string RestoreCopyOnly = "RestoreCopyOnly"; + + + public const string RestoreBackupSetComponent = "RestoreBackupSetComponent"; + + + public const string RestoreBackupSetName = "RestoreBackupSetName"; + + + public const string RestoreBackupSetType = "RestoreBackupSetType"; + + + public const string RestoreBackupSetServer = "RestoreBackupSetServer"; + + + public const string RestoreBackupSetDatabase = "RestoreBackupSetDatabase"; + + + public const string RestoreBackupSetPosition = "RestoreBackupSetPosition"; + + + public const string RestoreBackupSetFirstLsn = "RestoreBackupSetFirstLsn"; + + + public const string RestoreBackupSetLastLsn = "RestoreBackupSetLastLsn"; + + + public const string RestoreBackupSetCheckpointLsn = "RestoreBackupSetCheckpointLsn"; + + + public const string RestoreBackupSetFullLsn = "RestoreBackupSetFullLsn"; + + + public const string RestoreBackupSetStartDate = "RestoreBackupSetStartDate"; + + + public const string RestoreBackupSetFinishDate = "RestoreBackupSetFinishDate"; + + + public const string RestoreBackupSetSize = "RestoreBackupSetSize"; + + + public const string RestoreBackupSetUserName = "RestoreBackupSetUserName"; + + + public const string RestoreBackupSetExpiration = "RestoreBackupSetExpiration"; + + private Keys() { } diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.de.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.de.resx index 80860aa3..7f3e1dea 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.de.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.de.resx @@ -154,7 +154,7 @@ Abfrage wurde erfolgreich abgebrochen, Fehler beim Abfrage verfügen. Benutzer-URI nicht gefunden. - Abfrage wurde vom Benutzer abgebrochen. + Die Abfrage wurde vom Benutzer abgebrochen. Die Stapelverarbeitung ist noch nicht abgeschlossen @@ -358,7 +358,7 @@ Variable {0} ist nicht definiert. - EN_LOCALIZATION + Test Ersatz einer leeren Zeichenfolge durch eine leere Zeichenfolge. @@ -417,12 +417,24 @@ Spezifizierte URI '{0}' hat keine Standardverbindung + + Eine Commit-Anweisung wird ausgeführt. Bitte warten Sie bis zur Fertigstellung + + + Für die Decimal-Spalte fehlt die Angabe der Genauigkeit und Dezimalstellenanzahl + <TBD> Kann Zeile nicht an Ergebnisbuffer anhängen, da keine Zeilen im Datareader enthalten sind. + + Der Wert für eine Spalte vom Typ TIME muss zwischen 00:00:00.0000000 und 23:59:59.9999999 liegen + + + NULL ist für diese Spalte nicht erlaubt + Es gibt bereits eine Session @@ -453,6 +465,15 @@ Die Metadaten der Tabelle enthält keine erweiterten EIgenschaften. + + Tabelle oder Sicht zur Bearbeitung konnte nicht gefunden werden + + + Fehler beim Erweitern von: {0} + + + Fehler bei der Verbindung zu {0} + Aggregate @@ -897,9 +918,6 @@ Tabellentypindex - - ServerInstance - Selektive XML-Indexe @@ -936,4 +954,437 @@ Spaltenverschlüsselungsschlüssel + + Server + + + Fehler beim Analysieren der Eigenschaft ScriptingParams.ConnectionString. + + + Ungültiges Verzeichnis angeben in der Eigenschaft ScriptingParams.FilePath. + + + Fehler beim Analysieren der Eigenschaft ScriptingListObjectsCompleteParams.ConnectionString + + + {0} ({1}, {2}, {3}) + + + Kein Standard + + + Eingabe + + + Eingabe/Ausgabe + + + Eingabe/schreibgeschützt + + + Eingabe/Ausgabe/schreibgeschützt + + + Standard + + + NULL + + + nicht NULL + + + {0} ({1}, {2}) + + + {0} ({1}) + + + {0} ({1}berechnet, {2}, {3}) + + + {0} ({1}berechnet) + + + {0} (Spaltensatz, {1}) + + + {0} (Spaltensatz, {1} {2}, {3}) + + + {0} (Spaltensatz, {1}, {2}, {3}) + + + Eindeutig + + + Nicht eindeutig + + + Gruppiert + + + Nicht gruppiert + + + Verlauf + + + System-Mit Versionsangabe + + + Nicht verfügbar + + + Aktuelle Standarddateigruppe: {0} + + + Neue Dateigruppe für "{0}" + + + Standard + + + Dateien + + + Name + + + Schreibgeschützt + + + Automatische Vergrößerung/Maximale Größe + + + ... + + + <Standard> + + + Dateigruppe + + + Logischer Name + + + Dateityp + + + Anfangsgröße (MB) + + + <neue Dateigruppe> + + + Pfad + + + Dateiname + + + <unformatiertes Medium> + + + Massenprotokolliert + + + Vollständig + + + Einfach + + + Datenbankbesitzer auswählen + + + Kein(e) + + + Um {0} MB, auf {1} MB beschränkt + + + Um {0} Prozent, auf {1} MB beschränkt + + + Um {0} MB, unbegrenzt + + + Um {0} Prozent, unbegrenzt + + + Unbegrenzt + + + Auf {0} MB beschränkt + + + Automatisch + + + Service Broker + + + Sortierung + + + Cursor + + + Verschiedenes + + + Wiederherstellung + + + Status + + + ANSI NULL Default + + + ANSI NULLS aktiviert + + + ANSI-Auffüllung aktiviert + + + ANSI Warnings aktiviert + + + Abbruch bei arithmetischem Fehler aktiviert + + + Automatisch schließen + + + Statistik automatisch erstellen + + + Automatisch verkleinern + + + Statistiken automatisch aktualisieren + + + Statistik automatisch asynchron aktualisieren + + + Unterscheidung nach Groß-/Kleinschreibung + + + Schließen des Cursors nach Commit aktiviert + + + Sortierung + + + Verketten von NULL-Werten ergibt NULL + + + Datenbank-Kompatibilitätsgrad + + + Datenbankstatus + + + Standardcursor + + + Volltextindizierung aktiviert + + + Abbruch bei numerischem Runden + + + Seitenüberprüfung + + + Bezeichner in Anführungszeichen aktiviert + + + Datenbank schreibgeschützt + + + Rekursive Trigger aktiviert + + + Zugriff beschränken + + + Select Into/Bulk Copy + + + Brokerpriorität berücksichtigen + + + Service Broker-Bezeichner + + + Broker aktiviert + + + Protokoll bei Prüfpunkt abschneiden + + + Datenbankübergreifende Besitzverkettung aktiviert + + + Vertrauenswürdig + + + Optimierung der Datumskorrelation aktiviert: +prototype_db_prop_parameterization = Parameterization + + + Erzwungen + + + Einfach + + + ROWS (Daten) + + + LOG + + + FILESTREAM-Daten + + + Nicht zutreffend + + + <Standardpfad> + + + Geöffnete Verbindungen + + + Zum Ändern der Datenbankeigenschaften muss SQL Server alle anderen Verbindungen mit der Datenbank schließen. Möchten Sie wirklich die Eigenschaften ändern und alle anderen Verbindungen schließen? + + + 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-Speicherformat aktiviert + + + SQL Server 2008 (100) + + + Verschlüsselung aktiviert + + + AUS + + + EIN + + + PRIMÄR + + + Die Anzahl führender Hashspalten ist bei der HASH-Verteilungsrichtlinie optional, sollte aber zwischen 1 und 16 Spalten liegen. + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + Kein(e) + + + Teilweise + + + FILESTREAM-Dateien + + + Keine anwendbare Dateigruppe + + + Auf die Datenbank "{0}" kann nicht zugegriffen werden. + + + Abfrage hat keine Ergebnis zum Zurückgeben + + + Ergebnismenge ist zu groß, um sicher geladen zu werden + + + Datenbank sichern + + + In Bearbeitung + + + Abgeschlossen + + + Parametrisierung + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.es.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.es.resx index 747d97d4..7cd731a3 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.es.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.es.resx @@ -468,6 +468,12 @@ La tabla o vista solicitada para edición no se encuentra + + Error en expansión: {0} + + + Error conectando a {0} + Agregados @@ -520,7 +526,7 @@ Mensajes de error - Pertenencia a rol de servidor + Pertenencia a roles de servidor Opciones de base de datos @@ -583,7 +589,7 @@ Servidores vinculados - Inicios de sesión de servidores vinculados + Inicios de sesión de servidor vinculado Inicios de sesión @@ -625,7 +631,7 @@ Enlaces de servicio remoto - Columnas devueltas + Columnas devueltos Roles @@ -912,9 +918,6 @@ Índices de tipo de tabla - - instanciaDeServidor - Índices XML selectivos @@ -951,4 +954,436 @@ Claves de cifrado de columna + + Servidor + + + Error interpretando la propiedad ScriptingParams.ConnectionString + + + El directorio especificado en la propiedad ScriptingParams.FilePath no es válido + + + Error interpretando la propiedad ScriptingListObjectsCompleteParams.ConnectionString + + + {0} ({1}, {2}, {3}) + + + Sin valores predeterminados + + + Entrada + + + Entrada/salida + + + Entrada/solo lectura + + + Entrada/salida/solo lectura + + + Predeterminado + + + NULL + + + no es NULL + + + {0} ({1}, {2}) + + + {0} ({1}) + + + {0} ({1}calculado, {2}, {3}) + + + {0} ({1}calculado) + + + {0} (Conjunto de columnas, {1}) + + + {0} (Conjunto de columnas, {1}{2}, {3}) + + + {0} (Conjunto de columnas, {1}, {2}, {3}) + + + Único + + + No único + + + Clúster + + + No en clúster + + + Historial + + + Con versión del sistema + + + No disponible + + + Grupo de archivos predeterminado: {0} + + + Grupo de archivos nuevo para: {0} + + + Predeterminado + + + Archivos + + + Nombre + + + Solo lectura + + + Crecimiento automático / tamaño máximo + + + ... + + + <predeterminado> + + + Grupo de archivos + + + Nombre lógico + + + Tipo de archivo + + + Tamaño inicial (MB) + + + <nuevo grupo de archivos> + + + Ruta de acceso + + + Nombre de archivo + + + <dispositivo sin formato> + + + Registro masivo + + + Completo + + + Simple + + + Seleccionar propietario de base de datos + + + Ninguno + + + Por {0} MB, limitado a {1} MB + + + Por {0} porciento, limitado a {1} MB + + + Por {0} MB, sin límite + + + Por {0} porciento, sin límite + + + Sin límite + + + Limitado a {0} MB + + + Automático + + + Service Broker + + + Intercalación + + + Cursor + + + Varios + + + Recuperación + + + Estado + + + ANSI NULL predeterminado + + + ANSI NULLS habilitados + + + Relleno ANSI habilitado + + + Advertencias ANSI habilitadas + + + Anulación aritmética habilitada + + + Cierre automático + + + Crear estadísticas automáticamente + + + Reducir automáticamente + + + Actualizar estadísticas automáticamente + + + Actualizar estadísticas automáticamente de forma asincrónica + + + Sensible a mayúsculas y minúsculas + + + Cierre del cursor al confirmar habilitado + + + Intercalación + + + Concatenar valores NULL produce NULL + + + Nivel de compatibilidad de base de datos + + + Estado de la base de datos + + + Cursor predeterminado + + + Índice de texto completo habilitado + + + Anular redondeo numérico + + + Comprobación de página + + + Identificadores entre comillas habilitados + + + Base de datos de solo lectura + + + Desencadenadores recursivos habilitados + + + Restringir acceso + + + Select Into/Bulk Copy + + + Asignar prioridad de agente + + + Identificador de Service Broker + + + Broker habilitado + + + Truncar registro en el punto de control + + + Encadenamiento de propiedad entre bases de datos habilitado + + + De confianza + + + Optimización de correlación de fechas Enabledprototype_db_prop_parameterization = Parameterization + + + Forzado + + + Simple + + + Datos de ROWS + + + LOG + + + Datos de FILESTREAM + + + No aplicable + + + <ruta predeterminada> + + + Conexiones abiertas + + + Para cambiar las propiedades de la base de datos, SQL Server debe cerrar todas las otras conexiones a la base de datos. ¿Seguro que desea cambiar las propiedades y cerrar todas las otras conexiones? + + + 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 + + + Formato de almacenamiento VarDecimal habilitado + + + SQL Server 2008 (100) + + + Cifrado habilitado + + + OFF + + + ON + + + PRIMARY + + + Para la directiva de distribución HASH, el número de columnas iniciales hash es opcional pero debe de ser entre 1 y 16 columnas + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + Ninguno + + + Parcial + + + Archivos FILESTREAM + + + Grupo de archivos no aplicable + + + La base de datos {0} no es accesible. + + + La consulta no devolvió resultados + + + El conjunto de resultados contiene demasiada filas para cargarlo de forma segura + + + Copia de seguridad de la base de datos + + + En curso + + + Completado + + + Parametrización + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.fr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.fr.resx index 14364185..0568000d 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.fr.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.fr.resx @@ -127,7 +127,7 @@ SpecifiedUri '{0}' n’a pas de connexion existante - Valeur non valide '{0}' pour AuthenticationType. Les valeurs valides sont « Intégré » et « SqlLogin ». + Valeur '{0}' non valide pour AuthenticationType. Les valeurs valides sont 'Integrated' et 'SqlLogin'. Valeur '{0}' non valide pour ApplicationIntent. Les valeurs valides sont 'ReadWrite' et 'ReadOnly'. @@ -145,13 +145,13 @@ ServerName ne peut pas être null ou vide - {0} ne peut pas être null ou vide lors de l’utilisation de l’authentification SqlLogin + {0} ne peut pas être nul ou vide quand l'authentification SqlLogin est utilisée - La requête a déjà terminé, il ne peut pas être annulée + La requête est déjà terminée, elle ne peut pas être annulée. - Requête annulée avec succès, n’a pas pu supprimer la requête. Propriétaire d’URI non trouvé. + Requête annulée avec succès, échec de la libération de la requête. L'URI propriétaire n'a pas été trouvée. La requête a été annulée par l’utilisateur @@ -163,16 +163,16 @@ Index de lot ne peut pas être inférieur à 0 ou supérieur au nombre de lots - Index du jeu de résultats ne peut pas être inférieur à 0 ou supérieur au nombre de jeux de résultats + L'index de résultats ne peut pas être inférieur à 0 ou supérieur au nombre de résultats - Nombre maximal d’octets à renvoyer doit être supérieur à zéro + Le nombre maximal d'octets à renvoyer doit être supérieur à zéro - Nombre maximal de caractères à renvoyer doit être supérieur à zéro + Le nombre maximal de caractères à renvoyer doit être supérieur à zéro - Nombre maximal d’octets XML pour renvoyer doit être supérieur à zéro + Le nombre maximal d’octets XML à renvoyer doit être supérieur à zéro Méthode d’accès ne peut pas être en écriture seule @@ -190,13 +190,13 @@ ({0} lignes affectées) - Commandes s’est terminées correctement. + Commandes terminées avec succès. Msg {0}, au niveau état {2}, {1}, ligne {3} {4} {5} - La requête a échoué : {0} + La requête a échoué : {0} (Aucun nom de colonne) @@ -217,40 +217,40 @@ Impossible d’enregistrer les résultats jusqu'à ce que l’exécution de la requête est terminée. - Une erreur interne s’est produite lors du démarrage d’enregistrement + Une erreur interne s'est produite lors du démarrage de la tâche de sauvegarde. - Une demande vers le même chemin de sauvegarde est en cours + Une requête de sauvegarde vers le même chemin est en cours Impossible d’enregistrer {0} : {1} - Impossible de lire le sous-ensemble, sauf si les résultats ont été lus à partir du serveur + Impossible de lire le sous-élément à moins que les résultats aient été lus depuis le serveur - Début de la ligne ne peut pas être inférieur à 0 ou supérieur au nombre de lignes dans le jeu de résultats + La ligne de début ne peut pas être inférieure à 0 ou supérieure au nombre de lignes de résultats - Nombre de lignes doit être un entier positif + Le nombre de lignes doit être un entier positif - Schéma de colonne de jeu de résultats n’a pas pu être récupérer + Impossible de récupérer le schéma des colonnes pour le jeu de résultats - Impossible de récupérer un plan d’exécution le jeu de résultats + Impossible de récupérer un plan d’exécution pour le jeu de résultats - Cette fonctionnalité n’est actuellement pas pris en charge sur la base de données SQL Azure et entrepôt de données : {0} + Cette fonctionnalité n'est actuellement pas supportée sur Azure SQL DB et Data Warehouse : {0} - Une erreur inattendue s’est produite lors de l’exécution de lire une définition : {0} + Une erreur inattendue s'est produite lors de l'exécution du coup d'oeil à la définition: {0}. - Aucun résultat n’a été trouvé. + Aucun résultat trouvé. - Aucun objet de base de données a été récupérée. + Aucun objet de base de données n'a été récupéré. Veuillez vous connecter à un serveur. @@ -259,113 +259,221 @@ Opération a expiré. - Ce type d’objet n’est actuellement pas pris en charge par cette fonctionnalité. + Ce type d'objet n'est actuellement pas supporté par cette fonctionnalité - Position est en dehors de la plage de ligne de fichier + La position est en dehors de la plage de lignes du fichier - Position est en dehors de la plage de colonnes de la ligne {0} + La position est en dehors de la plage de colonnes pour la ligne {0} Position de début ({0}, {1}) doit précéder ou être égale à la position de fin ({2}, {3}) - Msg {0}, {1}, niveau d’état {2}, ligne {3} + Msg {0}, Niveau {1}, État {2}, Ligne {3} - Msg {0}, {1}, niveau d’état {2}, procédure {3}, ligne {4} + Msg {0}, Niveau {1}, État {2}, Procédure {3}, Ligne {4} - Msg {0}, {1}, niveau d’état {2} + Msg {0}, Niveau {1}, État {2} - Une erreur s’est produite lors du traitement du lot. Le message d’erreur est : {0} + Une erreur s'est produite lors du traitement du lot. Le message d'erreur est : {0} ({0} lignes affectées) - L’exécution précédente n’est pas encore terminée. + L'exécution précédente n'est pas encore terminée. - Une erreur de script s’est produite. + Une erreur de script s'est produite. - Syntaxe incorrecte a été rencontrée pendant {0} était en cours d’analyse. + Une syntaxe incorrecte a été trouvée lors de l'analyse de {0}. - Une erreur irrécupérable s’est produite. + Une erreur irrécupérable s'est produite. - L’exécution effectuée {0} fois... + L'exécution a été effectuée {0} fois... Vous avez annulé la requête. - Une erreur s’est produite pendant le traitement par lots a été exécuté. + Une erreur s'est produite lors de l'exécution du lot. - Une erreur s’est produite pendant le traitement par lots a été exécuté, mais que l’erreur a été ignorée. + Une erreur s'est produite lors de l'exécution du lot, mais elle a été ignorée. - Démarrage de la boucle d’exécution de {0} fois... + Démarrage de la boucle d'exécution pour {0} fois... - La commande {0} n’est pas pris en charge. + La commande {0} n'est pas prise en charge. - La variable {0} est introuvable. + Impossible de trouver la variable {0}. Erreur d’exécution de SQL : {0} - Exécution du wrapper d’Analyseur de lot : {0} trouvé... à la ligne {1} : {2} Description : {3} + Exécution du wrapper de l'analyseur du lot : {0} trouvé... à la ligne {1} : {2} Description : {3} - Lot analyseur wrapper d’exécution moteur lot message reçu : Message : {0} message détaillé : {1} + Message reçu du lot du moteur d'exécution du wrapper de l'analyseur du lot : Message : {0} Message détaillé : {1} - Traitement du moteur par lots ResultSet pour analyseur wrapper d’exécution de lot : DataReader.FieldCount : {0} DataReader.RecordsAffected : {1} + Traitement du ResultSet du lot du moteur d'exécution du wrapper de l'analyseur du lot : DataReader.FieldCount : {0} DataReader.RecordsAffected : {1} - Lot de moteur analyseur wrapper d’exécution terminée de jeu de résultats. + ResultSet du lot du moteur d'exécution du wrapper de l'analyseur du lot terminé. - Annulation de l’exécution par lots wrapper analyseur du lot. + Annulation de l'exécution du lot du wrapper de l'analyseur du lot. - Avertissement pour le script. + Avertissement de script. - Pour plus d’informations sur cette erreur, consultez les rubriques de dépannage dans la documentation du produit. + Pour plus d'informations sur cette erreur, consultez les rubriques de dépannage dans la documentation du produit. - Le fichier '{0}' inclus de manière récursive. + Le fichier '{0}' a été inclus de manière récursive. - Pas de marque de fin de commentaire ' * /'. + La marque de commentaire de fin '*/' est manquante. - Ouvrez les guillemets après la chaîne de caractères. + Guillemets non fermés après la chaîne de caractères. - Syntaxe incorrecte a été rencontrée lors de l’analyse de '{0}'. + Détection d'une syntaxe incorrecte pendant l'analyse de '{0}'. - La variable {0} n’est pas défini. + La variable {0} n'est pas définie. - EN_LOCALIZATION + test Remplacement d’une chaîne vide à une chaîne vide. + + La session d'édition n’existe pas. + + + La requête n’a pas terminé l’exécution + + + La requête n’a pas généré exactement un jeu de résultats + + + Impossible d’ajouter la nouvelle ligne pour mettre à jour le cache + + + L'identifiant de ligne spécifié est en dehors de la plage de lignes dans le cache d’édition + + + Une mise à jour est déjà en attente pour cette ligne et doit être d’abord annulée + + + L'identifiant de la ligne n'a pas de mise à jour en attente + + + Les métadonnées de la table ou de la vue n’ont pas pu être trouvées + + + Format invalide pour une colonne binary + + + Les colonnes booléennes doivent être un numérique 1 ou 0, ou une chaîne true ou false + + + Une valeur de cellule requise est manquante. + + + Une suppression est en attente pour cette ligne, une mise à jour de cellule ne peut pas être appliquée. + + + La colonne Id doit être dans la plage des colonnes de la requête + + + La colonne ne peut pas être éditée + + + Aucune colonne clé n'a été trouvée + + + Un nom de fichier de sortie doit être fourni + + + L'objet de base de données {0} ne peut pas être utilisé pour éditer + + + L'Uri spécifiée '{0}' n’a pas de connexion par défaut + + + Une tâche commit est en cours. Veuillez, s'il vous plaît, attendre la fin. + + + La colonne decimal manque d'une précision numérique + <TBD> + + Impossible d'ajouter une ligne au tampon de résultats, le data reader ne contient aucune ligne + + + Les valeurs de colonne TIME doivent être contenues entre 00:00:00.0000000 et 23:59:59.9999999 + + + NULL n'est pas autorisé pour cette colonne + + + La session d'édition existe déjà. + + + La session d'édition n'a pas été initialisée + + + La session d'édition a déjà été initialisée + + + La session d'édition a déjà été initialisée ou est en cours d'initialisation + + + L'exécution de la requête a échoué, voir les messages pour plus de détails + + + La limite de résultat ne peut pas être négative + + + NULL + + + Un nom d'objet doit être fourni + + + La spécification explicite du serveur ou de la base de données n'est pas pris en charge + + + Les métadonnées de tables n'ont pas de propriétés étendues + + + La table ou la vue demandée pour édition n'a pas pu être trouvée + + + Erreur en développant : {0} + + + Erreur en se connectant à {0} + Agrégats @@ -810,9 +918,6 @@ Index de types de tables - - ServerInstance - Index XML sélectifs @@ -849,4 +954,436 @@ Clés de chiffrement de la colonne + + Serveur + + + Erreur en analysant la propriété ScriptingParams.ConnectionString. + + + Répertoire invalide spécifié pour la propriété ScriptingParams.FilePath. + + + Erreur en analysant la propriété ScriptingListObjectsCompleteParams.ConnectionString. + + + {0} ({1}, {2}, {3}) + + + Pas de valeur par défaut + + + Entrée + + + Entrée/sortie + + + Entrée/ReadOnly + + + Entrée/sortie/ReadOnly + + + Par défaut + + + Null + + + Non Null + + + {0} ({1}, {2}) + + + {0} ({1}) + + + {0} ({1}Calculé, {2}, {3}) + + + {0} ({1}Calculé) + + + {0} (Jeu de colonnes, {1}) + + + {0} (Jeu de colonnes, {1}{2}, {3}) + + + {0} (Jeu de colonnes, {1}, {2}, {3}) + + + Unique + + + Non unique + + + Ordonné en clusters + + + Non-Clustere + + + Historique + + + System-Versioned + + + Indisponible + + + Groupe de fichiers par défaut actuel : {0} + + + Nouveau groupe de fichiers pour {0} + + + Par défaut + + + Fichiers + + + Nom + + + Lecture seule + + + Redimensionnement automatique / Taille max + + + ... + + + <par défaut> + + + Groupe de fichiers + + + Nom logique + + + Type de fichier + + + Taille initiale (Mo) + + + <new filegroup> + + + Chemin d'accès + + + Nom de fichier  + + + <raw device> + + + Bulk-logged + + + Full + + + Simple + + + Sélectionner le propriétaire de base de données + + + Aucune + + + Par {0} Mo, Limité à {1} Mo + + + Par {0} %, Limité à {1} Mo + + + Par {0} Mo, Illimité + + + Par {0} %, Illimité + + + Illimité + + + Limité à {0} Mo + + + Automatique + + + Service Broker + + + Classement + + + Curseur + + + Divers + + + Restauration + + + État + + + Paramètre par défaut ANSI NULL + + + Valeurs ANSI NULLS activées + + + Padding ANSI activé + + + ANSI Warnings activés + + + Annulation arithmétique (Arithmetic Abort) activée + + + Fermeture automatique + + + Création automatique des statistiques + + + Réduction automatique + + + Mise à jour automatique des statistiques + + + Mise à jour automatique des statistiques en mode asynchrone + + + Sensible à la casse + + + Fermeture du curseur lors de la validation activée + + + Classement + + + La concaténation de la valeur Null donne Null + + + Niveau de compatibilité de la base de données + + + État de la base de données + + + Curseur par défaut + + + Indexation de texte intégral activée + + + Abandon en cas d'arrondi numérique + + + Vérification de la page : + + + Identificateurs entre guillemets activés + + + Base de données en lecture seule + + + Déclencheurs récursifs activés + + + Restreindre l'accès + + + Select Into / Bulk Copy + + + Priorité du service Broker respectée + + + Identifant de Service Broker + + + Broker activé + + + Truncate Log on Checkpoint + + + Chaînage des propriétés des bases de données croisées activé + + + Digne de confiance + + + Date Correlation Optimization Enabledprototype_db_prop_parameterization = Parameterization + + + Forcé + + + Simple + + + Données ROWS + + + LOG + + + Données FILESTREAM + + + Non applicable + + + <default path> + + + Ouvrir les connexions + + + Pour changer les propriétés de la base de données, SQL Server doit fermer toutes les autres connexions à la base de données. Etes-vous sûr de vouloir changer les propriétés et fermer toutes les autres connexions ? + + + 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 + + + Format de stockage VarDecimal activé + + + SQL Server 2008 (100) + + + Chiffrement activé + + + OFF + + + ON + + + PRIMARY + + + Pour la politique de distribution HASH, le nombre de colonnes hash qui débutent est optionnel mais devrait être entre 1 et 16 colonnes. + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + Aucun + + + Partiel + + + Fichiers FILESTREAM + + + Aucun groupe de fichiers applicable + + + La base de données {0} est inaccessible. + + + La requête n'a aucun résultat à retourner + + + Le jeu de résultats a trop de lignes pour être chargé en toute sécurité + + + Sauvegarder la base de données + + + En cours + + + Terminé + + + Paramétrage + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.it.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.it.resx index 8a20a2ae..155573af 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.it.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.it.resx @@ -358,7 +358,7 @@ Variabile {0} non è definita. - EN_LOCALIZATION + test Sostituzione di una stringa vuota con una stringa vuota. @@ -468,6 +468,12 @@ Impossibile trovare la Tabella o la Vista necessarie alla modifica + + Errore durante l'espansione dell'oggetto: {0} + + + Errore durante la connessione a {0}' + Aggregazioni @@ -912,9 +918,6 @@ Indici del tipo di tabella - - ServerInstance - Indici XML selettivi @@ -951,4 +954,436 @@ Chiavi di crittografia della colonna + + Server + + + Errore durante l'analisi della proprietà ScriptingParams.ConnectionString. + + + La Directory specificata dalla proprietà ScriptingParams.FilePath non è valida. + + + Errore durante l'analisi della proprietà ScriptingListObjectsCompleteParams.ConnectionString. + + + {0} ({1}, {2}, {3}) + + + Nessun valore predefinito + + + Input + + + Input/Output + + + Input/ReadOnly + + + Input/Output/ReadOnly + + + Predefinito + + + Null + + + non Null + + + {0} ({1}, {2}) + + + {0} ({1}) + + + {0} ({1} calcolato, {2}, {3}) + + + {0} ({1} calcolato) + + + {0} (Set di colonne: {1}) + + + {0} (Set di colonne: {1} {2}, {3}) + + + {0} (Set di colonne: {1}, {2}, {3}) + + + Univoco + + + Non univoco + + + Cluster + + + Non cluster + + + Cronologia + + + Con controllo delle versioni di sistema + + + Non disponibile + + + Filegroup predefinito corrente: {0} + + + Nuovo Filegroup per {0} + + + Predefinito + + + File + + + Nome + + + Sola lettura + + + Aumento automatico / Maxsize + + + ... + + + <predefinito> + + + Filegroup + + + Nome logico + + + Tipo di file + + + Dimensioni iniziali (MB) + + + <nuovo Filegroup> + + + Percorso + + + Nome file + + + <dispositivo RAW> + + + Registrazione delle operazioni bulk + + + Completo + + + Semplice + + + Seleziona il proprietario del Database + + + Nessuno + + + Di {0} MB, limitato a {1} MB + + + Di {0} percento, limitato a {1} MB + + + Di {0} MB, illimitato + + + Di {0} percento, illimitato + + + Senza limiti + + + Limitato a {0} MB + + + Automatico + + + Service Broker + + + Regole di confronto + + + Cursore + + + Varie + + + Recupero + + + Stato + + + Impostazione predefinita ANSI NULL + + + ANSI NULLS abilitati + + + ANSI Padding abilitato + + + Avvisi ANSI abilitati + + + Arithmetic Abort abilitata + + + Chiusura automatica + + + Creazione statistiche automatica + + + Compattazione automatica + + + Aggiornamento statistiche automatico + + + Aggiornamento statistiche asincrono automatico + + + Distinzione maiuscole/minuscole + + + Chiusura cursore in caso di commit abilitata + + + Regole di confronto + + + La concatenazione di valori Null restituisce valori Null + + + Livello di compatibilità del database + + + Stato database + + + Cursore predefinito + + + Indicizzazione full-text + + + Interruzione per perdita di precisione numerica + + + Verifica pagina + + + Identificatori delimitati abilitati + + + Database di sola lettura + + + Trigger ricorsivi abilitati + + + Limitazione accesso + + + Select Into/Bulk Copy + + + Rispetta priorità di Service Broker + + + Identificatore Service Broker + + + Broker abilitato + + + Tronca Log al Checkpoint + + + Concatenamento della proprietà tra database abilitato + + + Trustworthy + + + Ottimizzazione correlazione date Enabledprototype_db_prop_parameterization = parametrizzazione + + + Forzato + + + Semplice + + + Dati RIGHE + + + LOG + + + Dati FILESTREAM + + + Non applicabile + + + <percorso predefinito> + + + Connessioni aperte + + + Per modificare le proprietà del database, SQL Server deve chiudere tutte le altre connessioni al database_ Sei sicuro di voler modificare le proprietà e chiudere tutte le altre connessioni? + + + 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 + + + Formato di archiviazione VarDecimal abilitato + + + SQL Server 2008 (100) + + + Crittografia abilitata + + + OFF + + + ON + + + PRIMARY + + + Per il criterio di distribuzione HASH, il numero di colonne iniziali di hash è facoltativo, ma dovrebbe essere da 1 a 16 colonne + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + Nessuno + + + Parziale + + + File FILESTREAM + + + Nessun Filegroup applicabile + + + Il database {0} non è accessibile. + + + La query non ha risultati da restituire + + + L'insieme di risultati ha troppe righe per essere caricato in modo sicuro + + + Backup database + + + In corso + + + Completato + + + Parametrizzazione + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ja.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ja.resx index 76cad177..b0fb3745 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ja.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ja.resx @@ -358,7 +358,7 @@ 変数 {0} が定義されていません。 - EN_LOCALIZATION + テスト 空の文字列で空の文字列を置換しています。 @@ -468,6 +468,12 @@ 編集を要求したテーブルもしくはビューが見つかりませんでした。 + + '{0}' の拡張中にエラーが発生しました。 + + + {0} への接続中にエラーが発生しました + 集約 @@ -912,9 +918,6 @@ テーブル型インデックス - - ServerInstance - 選択的 XML インデックス @@ -951,4 +954,437 @@ 列暗号化キー + + サーバー + + + ScriptingParams.ConnectionString プロパティの解析エラーです。 + + + ScriptingParams.FilePath プロパティで指定されたディレクトリが無効です。 + + + ScriptingListObjectsCompleteParams.ConnectionString プロパティの解析エラーです。 + + + {0} ({1}、{2}、{3}) + + + 既定値以外 + + + 入力 + + + 入力/出力 + + + 入力/読み取り専用 + + + 入力/出力/読み取り専用 + + + 既定値 + + + NULL + + + NULL 以外 + + + {0} ({1}、{2}) + + + {0} ({1}) + + + {0} ({1} 計算値、{2}、{3}) + + + {0} ({1} 計算値) + + + {0} (列セット、{1}) + + + {0} (列セット、{1}{2}、{3}) + + + {0} (列セット、{1}、{2}、{3}) + + + 一意 + + + 一意でない + + + クラスター化 + + + 非クラスター + + + 履歴 + + + システムバージョン管理 + + + 使用不可 + + + 現在の既定のファイル グループ: {0} + + + 新しいファイルグループ {0} + + + 既定値 + + + ファイル + + + 名前 + + + 読み取り専用 + + + 自動拡張 / 最大容量 + + + ... + + + <既定> + + + ファイル グループ + + + 論理名 + + + ファイルタイプ + + + 初期サイズ (MB) + + + <新しいファイルグループ> + + + パス + + + ファイル名 + + + <RAWデバイス> + + + 一括ログ + + + 完全 + + + 単純 + + + データベース 所有者の選択 + + + なし + + + {0} MBごと、{1} MBを上限 + + + {0} パーセントごと、{1} MBまで + + + {0} MBごと、無制限 + + + {0} パーセントごと、無制限 + + + 無制限 + + + {0} MBまで + + + 自動 + + + Service Broker + + + 照合順序 + + + カーソル + + + その他 + + + 復旧 + + + 状態 + + + ANSI NULL 既定値 + + + ANSI NULLS 有効 + + + ANSI Padding 有効 + + + ANSI 警告有効 + + + 算術アボート有効 + + + 自動クローズ + + + 統計の自動作成 + + + 自動圧縮 + + + 統計の自動更新 + + + 統計の非同期的自動更新 + + + 大文字と小文字を区別する + + + コミットでカーソルを閉じる + + + 照合順序 + + + Nullとの連結をNullとして取り扱う + + + データベース互換性レベル + + + データベース状態 + + + 既定のカーソル + + + フルテキスト インデックス 有効化 + + + 数値丸め処理アボート + + + ページ確認 + + + 引用符で囲まれた識別子が有効 + + + 読み取り専用データベース + + + 再帰トリガー有効 + + + アクセスの制限 + + + Select Into/ バルクコピー + + + Broker の優先度の許可 + + + Service Broker 識別子 + + + ブローカー有効化 + + + チェックポイントでのログの切り捨て + + + 複数データベースの組み合わせ所有権有効 + + + 信頼可能 + + + データ相関性の最適化 +Enabledprototype_db_prop_parameterization = Parameterization + + + 強制 + + + 単純 + + + 列データ + + + ログ + + + FILESTREAM データ + + + 適用不可 + + + <既定のパス> + + + コネクションを開く + + + データベースのプロパティを変更するには、SQL Server はデータベースへの他のすべての接続を閉じる必要があります。プロパティを変更して、他のすべての接続を閉じてよろしいですか? + + + 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 ストレージ形式有効 + + + SQL Server 2008 (100) + + + 暗号化有効 + + + OFF + + + ON + + + PRIMARY + + + 配布ポリシーのハッシュでは、ハッシュの先頭列の番号は任意ですが、1 から 16 個の列にする必要があります + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + なし + + + 部分的 + + + FILESTREAM ファイル + + + 適用不可なファイルグループ + + + データベース {0} にアクセスできません。 + + + クエリーは結果を返しませんでした + + + 結果セットの行数が多すぎるため安全にロードすることはできません + + + データベースをバックアップする + + + 実行中 + + + 完了 + + + パラメーター化 + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ko.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ko.resx index 3f2a0a6c..09a36a29 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ko.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ko.resx @@ -358,7 +358,7 @@ {0} 변수가 정의되지 않았습니다. - EN_LOCALIZATION + 테스트 @@ -422,9 +422,15 @@ votes 커밋 작업이 진행 중입니다. 완료될 때까지 기다리세요. + + Decimal 형식 열에 전체 자릿수 또는 소수 자릿수가 없습니다. + <TBD> + + 결과 버퍼에 새로운 행을 추가할 수 없거나 데이터 리더에 행이 없습니다. + TIME 열의 값은 00:00:00.0000000과 23:59:59.9999999 사이의 값만 허용됩니다. @@ -464,6 +470,12 @@ votes 편집하려는 테이블이나 뷰를 찾을 수 없습니다 + + 오류 확장: {0} + + + {0}에 연결하는 동안 오류가 발생했습니다. + 집계 @@ -908,9 +920,6 @@ votes 테이블 형식 인덱스 - - ServerInstance - 선택적 XML 인덱스 @@ -947,4 +956,436 @@ votes 열 암호화 키 + + 서버 + + + ScriptingParams.ConnectionString 속성 분석을 하는 동안 오류가 발생했습니다. + + + ScriptingParams.FilePath 속성에 잘못된 디렉터리 지정 + + + ScriptingListObjectsCompleteParams.ConnectionSring 속성을 분석할때 오류가 생겼습니다. + + + {0}({1}, {2}, {3}) + + + 기본값 없음 + + + 입력 + + + 입/출력 + + + 입력/읽기 전용 + + + 입/출력/읽기 전용 + + + 기본값 + + + Null + + + Not Null + + + {0}({1}, {2}) + + + {0}({1}) + + + {0}({1}계산됨, {2}, {3}) + + + {0}({1}계산됨) + + + {0}(열 집합, {1}) + + + {0}(열 집합, {1}{2}, {3}) + + + {0}(열 집합, {1}, {2}, {3}) + + + 고유 + + + 고유하지 않음 + + + 클러스터형 + + + 비클러스터형 + + + 기록 + + + 시스템 버전 관리 + + + 사용할 수 없음 + + + 현재 기본 파일 그룹: {0} + + + {0}에 대한 새 파일 그룹 + + + 기본값 + + + 파일 + + + 이름 + + + 읽기 전용 + + + 자동 증가 / 최대 크기 + + + ... + + + <기본값> + + + 파일 그룹 + + + 논리적 이름 + + + 파일 형식 + + + 처음 크기 (MB) + + + <새 파일 그룹> + + + 경로 + + + 파일 이름 + + + <원시 장치> + + + 대량 로그 + + + 전체 + + + 단순 + + + 데이터베이스 소유자 선택 + + + 없음 + + + {0} MB 단위로 {1} MB까지 제한됨 + + + {0} % 단위로 {1} MB까지 제한됨 + + + {0} MB 단위로, 제한 없음 + + + {0} % 단위로, 제한 없음 + + + 제한 없음 + + + {0} MB로 제한됨 + + + 자동 + + + Service Broker + + + 데이터 정렬 + + + 커서 + + + 기타 + + + 복구 + + + 상태 + + + ANSI NULL 기본값 + + + ANSI NULLS 사용 + + + ANSI 패딩 설정 + + + ANSI Warnings 사용 + + + 산술 연산 중단 설정 + + + 자동 닫기 + + + 통계 자동 작성 + + + 자동 축소 + + + 통계 자동 업데이트 + + + 통계를 비동기적으로 자동 업데이트 + + + 대/소문자 구분 + + + 커밋 시 커서 닫기 설정 + + + 데이터 정렬 + + + Null 연결 시 Null 생성 + + + 데이터베이스 호환성 수준 + + + 데이터베이스 상태 + + + 기본 커서 + + + 전체 텍스트 인덱싱 설정 + + + 숫자 반올림 시 중단 + + + 페이지 확인 + + + 따옴표 붙은 식별자 설정 + + + 데이터베이스 읽기 전용 + + + 재귀적 트리거 설정 + + + 액세스 제한 + + + SELECT INTO/대량 복사 + + + Broker 우선 순위 인식 + + + Service Broker 식별자 + + + Broker 활성화 + + + 검사점에서 로그 자름 + + + 데이터베이스 간 소유권 체인 사용 + + + 신뢰 + + + 날짜 상관관계 최적화 설정 + + + 강제 + + + 단순 + + + ROWS 데이터 + + + 로그 + + + FILESTREAM 데이터 + + + 해당 사항 없음 + + + <기본 경로> + + + 연결 열기 + + + 데이터베이스 속성을 변경하기 위해, SQL Server가 database_ 에  다른 연결을 모두 닫아야 합니다. 속성을 변경하고 다른 연결을 모두 닫으시겠습니까? + + + AUTO_CLOSED + + + 긴급 + + + INACCESSIBLE + + + NORMAL + + + 오프라인 + + + 복구 중 + + + 복구 보류 중 + + + RESTORING + + + SHUTDOWN + + + STANDBY + + + SUSPECT + + + GLOBAL + + + LOCAL + + + MULTI_USER + + + RESTRICTED_USER + + + SINGLE_USER + + + CHECKSUM + + + NONE + + + TORN_PAGE_DETECTION + + + VarDecimal 저장소 형식 사용 + + + SQL Server 2008 (100) + + + 암호화 사용 + + + OFF + + + ON + + + PRIMARY + + + 배포 정책이 HASH인 경우 선행 해시 열 수는 선택 사항이지만, 선택할 경우 1개에서 16개 사이의 열로 지정해야 합니다. + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + 없음 + + + 부분 + + + FILESTREAM 파일 + + + 해당 파일 그룹 없음 + + + {0} 데이터베이스에 액세스할 수 없습니다. + + + 쿼리 반환 결과 없음 + + + 결과 집합의 행 수가 너무 많아서 안전하게 불러들일 수 없습니다. + + + 데이터베이스 백업 + + + 진행 중 + + + 완료됨 + + + 매개 변수화 + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.pt-BR.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.pt-BR.resx index 24cd7925..385d2ab1 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.pt-BR.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.pt-BR.resx @@ -358,7 +358,7 @@ A variável {0} não está definida. - EN_LOCALIZATION + teste Substituição de uma sequência vazia por uma cadeia de caracteres vazia. @@ -919,9 +919,6 @@ Índices de Tipos de Tabelas - - ServerInstance - Índices XML Seletivos @@ -958,4 +955,436 @@ Chaves de Criptografia de Colunas + + Servidor + + + Erro ao analisar a propriedade ScriptingParams.ConnectionString. + + + Diretório inválido especificado pela propriedade ScriptingParams.FilePath. + + + Erro ao analisar a propriedade ScriptingListObjectsCompleteParams.ConnectionString. + + + {0} ({1}, {2}, {3}) + + + Nenhum padrão + + + Entrada + + + Entrada/Saída + + + Entrada/SomenteLeitura + + + Entrada/Saída/SomenteLeitura + + + Padrão + + + nulo + + + não nulo + + + {0} ({1}, {2}) + + + {0} ({1}) + + + {0} ({1} Computado, {2}, {3}) + + + {0} ({1}Computado) + + + {0} (Conjunto de Colunas, {1}) + + + {0} (Conjunto de Colunas, {1}{2}, {3}) + + + {0} (Conjunto de Colunas, {1}, {2}, {3}) + + + Exclusivo + + + Não Exclusivo + + + Clusterizado + + + Não Clusterizado + + + Histórico + + + Versionado pelo sistema + + + Indisponível + + + Grupo de arquivos padrão atual: {0} + + + Novo Grupo de Arquivos para {0} + + + Padrão + + + Arquivos + + + Nome + + + Somente Leitura + + + Auto crescimento / Tamanho máximo + + + ... + + + <padrão> + + + Grupo de Arquivos + + + Nome Lógico + + + Tipo de Arquivo + + + Tamanho Inicial (MB) + + + <novo grupo de arquivos> + + + Caminho + + + Nome do Arquivo + + + <dispositivo bruto> + + + Logado em massa + + + Completo + + + Simples + + + Selecionar o proprietário do banco de dados + + + Nenhum + + + Por {0} MB, limitado a {1} MB + + + Por {0}%, Limitado a {1} mb + + + Por {0} MB, Ilimitado + + + Por {0}%, Ilimitado + + + Ilimitado + + + Limitado a {0} MB + + + Automático + + + Service Broker + + + Agrupamento + + + Cursor + + + Diversos + + + Recuperação + + + Estado + + + Padrão ANSI NULL + + + ANSI NULLS Habilitado + + + Preenchimento ANSI habilitado + + + ANSI Warnings Habilitados + + + Arithmetic Abortar habilitado + + + Fechamento automático + + + Criar Estatísticas Automaticamente + + + Reduzir Automaticamente + + + Estatísticas Atualizadas Automaticamente + + + Atualizar estatísticas automaticamente de forma assíncrona + + + Sensível à Caixa + + + Fechar Cursor na Confirmação Habilitado + + + Agrupamento + + + Concatenar Nulo Produz Nulo + + + Nível de Compatibilidade do Banco de Dados + + + Estado do Banco de Dados + + + Cursor Padrão + + + Indexação Full-Text Habilitada + + + Anular arredondamento numérico. + + + Verificação de Página + + + Identificadores Entre Aspas Habilitados + + + Banco de Dados Somente Leitura + + + Gatilhos Recursivos Habilitados + + + Acesso Restrito + + + Selecionar Cópia Into/Em Massa + + + Respeitar a Prioridade do Broker + + + Identificador de agente de serviço + + + Agente habilitado + + + Truncar o Log no Ponto de Verificação + + + Encadeamento de Propriedades de Bancos de Dados Habilitado + + + Confiável + + + Otimizaçao da Correlação de Data Enabledprototype_db_prop_parameterization = Parametrização + + + Forçado + + + Simples + + + Dados ROWS + + + LOG + + + Dados FILESTREAM + + + Não aplicável + + + <caminho padrão> + + + Conexões Abertas + + + Para modificar as propriedades do banco de dados, o SQL Server deve fechar todas as outras conexões ao banco de dados_ Tem certeza que você quer modificar as propriedades e fechar todas as outras conexões? + + + AUTO_CLOSED + + + EMERGÊNCIA + + + INACESSÍVEL + + + NORMAL + + + OFF-LINE + + + RECUPERANDO + + + RECUPERAÇÃO PENDENTE + + + RESTAURANDO + + + DESLIGAMENTO + + + MODO DE ESPERA + + + SUSPEITO + + + GLOBAL + + + LOCAL + + + MULTI_USUÁRIO + + + USUÁRIO_RESTRITO + + + MONO_USUÁRIO + + + SOMA DE VERIFICAÇÃO + + + NENHUM + + + TORN_PAGE_DETECTION + + + Formato de Armazenamento VarDecimal Habilitado + + + SQL Server 2008 (100) + + + Criptografia Habilitada + + + DESLIGADO + + + LIGADO + + + PRIMÁRIO + + + Para a política de distribuição de HASH, o número de colunas hash principais é opcional, mas deve ser de 1 a 16 colunas + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + Nenhum + + + Parcial + + + Arquivos FILESTREAM + + + Nenhum grupo de arquivos aplicável + + + O banco de dados {0} não está acessível. + + + A consulta não tem resultado para retornar + + + Conjunto de resultados tem muitas linhas para ser carregado com segurança + + + Fazer Backup do Banco de Dados + + + Em andamento + + + Concluído + + + Parametrização + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx index 15c5345c..5dcda5ca 100755 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.resx @@ -1847,4 +1847,68 @@ Restore Database + + (Copy Only) + + + + Component + + + + Name + + + + Type + + + + Server + + + + Database + + + + Position + + + + First LSN + + + + Last LSN + + + + Checkpoint LSN + + + + Full LSN + + + + Start Date + + + + Finish Date + + + + Size + + + + User Name + + + + Expiration + + diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ru.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ru.resx index 0600767d..dd814d7c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ru.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.ru.resx @@ -358,7 +358,7 @@ Переменная {0} не определена. - EN_LOCALIZATION + тест Замена пустой строки на пустую строку. @@ -468,6 +468,12 @@ Запрошенная таблица или представление не найдены. + + Ошибка при расширении: {0} + + + Ошибка при подключении к {0} + Статистические выражения @@ -912,9 +918,6 @@ Индексы типов таблиц - - ServerInstance - Селективные XML-индексы @@ -951,4 +954,436 @@ Ключи шифрования столбца + + Сервер + + + Ошибка при анализе свойства ScriptingParams.ConnectionString. + + + Недопустимый каталог указан в свойстве ScriptingParams.FilePath. + + + Ошибка при анализе свойства ScriptingListObjectsCompleteParams.ConnectionString. + + + {0} ({1}, {2}, {3}) + + + Нет значения по умолчанию + + + Входной + + + Входной/выходной + + + Входной/только для чтения + + + Входной/выходной/только для чтения + + + Значение по умолчанию + + + null + + + not null + + + {0} ({1}, {2}) + + + {0} ({1}) + + + {0} (вычислено {1}, {2}, {3}) + + + {0} (вычислено {1}) + + + {0} (набор столбцов, {1}) + + + {0} (набор столбцов, {1}{2}, {3}) + + + {0} (набор столбцов, {1}, {2}, {3}) + + + UNIQUE + + + Неуникальный + + + Кластеризованный + + + Некластеризованный + + + Журнал + + + Системно-версионный + + + Недоступно + + + Текущая файловая группа по умолчанию: {0} + + + Создание файловой группы для {0} + + + Значение по умолчанию + + + Файлы + + + Имя + + + Только для чтения + + + Автоувеличение/максимальный размер + + + ... + + + <по умолчанию> + + + Группа файлов + + + Логическое имя + + + Тип файла + + + Начальный размер (МБ) + + + <создать файловую группу> + + + Путь + + + Имя файла + + + <неформатированный носитель> + + + С неполным протоколированием + + + Полная + + + Простая + + + Выбор владельца базы данных + + + Нет + + + С шагом по {0} МБ до {1} МБ + + + С шагом по {0}% до {1} МБ + + + С шагом по {0} МБ, без ограничений + + + С шагом по {0} %, без ограничений + + + Без ограничений + + + Ограничено {0} МБ + + + Автоматически + + + Service Broker + + + Параметры сортировки + + + Курсор + + + Прочее + + + Восстановление + + + Состояние + + + По умолчанию ANSI NULL + + + Значения ANSI NULLS включены + + + Включено заполнение ANSI + + + Включены предупреждения ANSI + + + Включено прерывание при делении на ноль + + + Auto Close + + + Автоматическое создание статистики + + + Автоматическое сжатие + + + Автоматическое обновление статистики + + + Асинхронное автообновление статистики + + + Case Sensitive + + + Закрывать курсор при разрешении фиксации + + + Параметры сортировки + + + Объединение со значением NULL дает NULL + + + Уровень совместимости базы данных + + + Состояние базы данных + + + Курсор по умолчанию + + + Полнотекстовое индексирование включено + + + Автоокругление чисел + + + Проверка страниц + + + Включены заключенные в кавычки идентификаторы + + + База данных только для чтения + + + Включены рекурсивные триггеры + + + Ограничение доступа + + + Выбор/Массовое копирование + + + Учитывать приоритет компонента Honor Broker + + + Идентификатор компонента Service Broker + + + Включен компонент Broker + + + Усечение журнала на контрольной точке + + + Межбазовые цепочки владения включены + + + Заслуживает доверия + + + Date Correlation Optimization Enabledprototype_db_prop_parameterization = Parameterization + + + Принудительное + + + Простая + + + Данные СТРОК + + + ЖУРНАЛ + + + Данные FILESTREAM + + + Неприменимо + + + <default path> + + + Открытые соединения + + + Чтобы изменить свойства базы данных, SQL Server должен закрыть все остальные соединения с этой базой данных. Изменить свойства и закрыть остальные соединения? + + + AUTO_CLOSED + + + EMERGENCY + + + INACCESSIBLE + + + NORMAL + + + OFFLINE + + + RECOVERING + + + RECOVERY PENDING + + + RESTORING + + + SHUTDOWN + + + STANDBY + + + SUSPECT + + + GLOBAL + + + LOCAL + + + MULTI_USER + + + RESTRICTED_USER + + + SINGLE_USER + + + CHECKSUM + + + Нет + + + TORN_PAGE_DETECTION + + + Включен формат хранения VarDecimal + + + SQL Server 2008 (100) + + + Шифрование включено + + + ОТКЛ. + + + ВКЛ. + + + ПЕРВИЧНЫЙ + + + Для политики распространения HASH количество начальных хэш-столбцов указывать не обязательно. Оно может составлять от 1 до 16 столбцов + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + Нет + + + Частично + + + Файлы FILESTREAM + + + Применимая файловая группа отсутствует + + + База данных {0} недоступна. + + + запрос не имеет результатов + + + Pезультатов слишком много строк для безопасной загрузки + + + Резервное копирование базы данных + + + Выполняется + + + Завершен + + + Параметризация + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings index 2616a842..f9b8ca62 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.strings @@ -819,4 +819,20 @@ InvalidPathForDatabaseFile = Invalid path for database file: '{0}' Log = Log RestorePlanFailed = Failed to create restore plan RestoreNotSupported = Restore database is not supported -RestoreTaskName = Restore Database \ No newline at end of file +RestoreTaskName = Restore Database +RestoreCopyOnly = (Copy Only) +RestoreBackupSetComponent = Component +RestoreBackupSetName = Name +RestoreBackupSetType = Type +RestoreBackupSetServer = Server +RestoreBackupSetDatabase = Database +RestoreBackupSetPosition = Position +RestoreBackupSetFirstLsn = First LSN +RestoreBackupSetLastLsn = Last LSN +RestoreBackupSetCheckpointLsn = Checkpoint LSN +RestoreBackupSetFullLsn = Full LSN +RestoreBackupSetStartDate = Start Date +RestoreBackupSetFinishDate = Finish Date +RestoreBackupSetSize = Size +RestoreBackupSetUserName = User Name +RestoreBackupSetExpiration = Expiration \ 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 066273ab..d1fa9fab 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.xlf @@ -2159,6 +2159,86 @@ Restore Database + + (Copy Only) + (Copy Only) + + + + Component + Component + + + + Type + Type + + + + Server + Server + + + + Database + Database + + + + Position + Position + + + + First LSN + First LSN + + + + Last LSN + Last LSN + + + + Checkpoint LSN + Checkpoint LSN + + + + Full LSN + Full LSN + + + + Start Date + Start Date + + + + Finish Date + Finish Date + + + + Size + Size + + + + User Name + User Name + + + + Expiration + Expiration + + + + Name + Name + + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.zh-hans.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.zh-hans.resx index 10dc5d5f..3c6f327f 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.zh-hans.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.zh-hans.resx @@ -124,7 +124,7 @@ OwnerUri 不能为 null 或为空 - SpecifiedUri"{0} 没有现有的连接 + SpecifiedUri '{0}' 没有已有的连接 AuthenticationType 值"{0}" 无效。 有效值为 'Integrated' 和 'SqlLogin'。 @@ -358,7 +358,7 @@ 未定义变量 {0}。 - EN_LOCALIZATION + 测试 用空字符串取代空字符串。 @@ -435,6 +435,45 @@ 该列不允许Null 值 + + 编辑会话已存在 + + + 编辑会话尚未初始化 + + + 编辑会话已被初始化 + + + 编辑会话已被初始化或正在初始化中 + + + 执行查询失败,查看消息了解更多详情 + + + 结果集的限制值不能为负数 + + + + + + 必须提供对象名称 + + + 不支持显式指定服务器或者数据库 + + + 数据表的元数据没有扩展属性 + + + 找不到请求编辑的数据表或视图 + + + 扩展数据库时出错: {0} + + + 连接到 {0} 时出错 + 聚合 @@ -879,9 +918,6 @@ 表类型索引 - - ServerInstance - 选择性 XML 索引 @@ -918,4 +954,436 @@ 列加密密钥 + + 服务器 + + + 解析属性 ScriptingParams.ConnectionString 时出错 + + + ScriptingParams.FilePath 属性指定的路径是无效目录 + + + 解析属性 ScriptingListObjectsCompleteParams.ConnectionString 时出错 + + + {0} ({1}, {2}, {3}) + + + 无默认值 + + + 输入 + + + 输入/输出 + + + 输入/只读 + + + 输入/输出/只读 + + + 默认值 + + + Null + + + 非 Null + + + {0} ({1}, {2}) + + + {0} ({1}) + + + {0} ({1}Computed, {2}, {3}) + + + {0} ({1}Computed) + + + {0} (列集,{1}) + + + {0} (列集,{1}{2},{3}) + + + {0} (列集,{1},{2},{3}) + + + 唯一 + + + 非唯一 + + + 聚集 + + + 非聚集 + + + 历史记录 + + + 带有系统版本 + + + 不可用 + + + 当前默认文件组: {0} + + + {0} 的新文件组 + + + 默认值 + + + 文件 + + + 名称 + + + 只读 + + + 自动增长/最大大小 + + + ... + + + <默认值> + + + 文件组 + + + 逻辑名 + + + 文件类型 + + + 初始大小 (MB) + + + <新文件组> + + + 路径 + + + 文件名 + + + <原始设备> + + + 批量记录的 + + + + + + 简单 + + + 选择数据库所有者 + + + + + + 增量为 {0} MB,限制为 {1} MB + + + 增量为 {0}%,限制为 {1} MB + + + 增量为 {0} MB,增长无限制 + + + 增量为 {0}%,增长无限制 + + + 无限制 + + + 不超过{0} MB + + + 自动 + + + Service Broker + + + 排序规则 + + + 游标 + + + 杂项 + + + 恢复 + + + 状态 + + + ANSI NULL 默认值 + + + 启用 ANSI NULLS + + + ANSI 填充已启用 + + + 启用 ANSI 警告 + + + 算术中止已启用 + + + 自动关闭 + + + 自动创建统计信息 + + + 自动收缩 + + + 自动更新统计信息 + + + 自动异步更新统计信息 + + + 区分大小写的 + + + 已启用“提交时关闭游标” + + + 排序规则 + + + 串联 Null 时得到 Null + + + 数据库兼容级别 + + + 数据库状态 + + + 默认游标 + + + 已启用全文索引 + + + 数值舍入 —— 中止 + + + 页验证 + + + 已启用 Quoted Identifiers + + + 数据库为只读的 + + + 已启用 Recursive Triggers + + + 限制访问 + + + Select Into/Bulk Copy + + + 优先处理 Broker 优先级 + + + Service Broker Identifier + + + 已启用 Broker + + + 在检查点删除日志 + + + 启用跨数据库所有权链接 + + + 可信 + + + Date Correlation Optimization 已启用 prototype_db_prop_parameterization = Parameterization + + + 强迫的 + + + 简单 + + + 行数据 + + + 日志 + + + FILESTREAM 数据 + + + 不适用 + + + <默认路径> + + + 开着的连接 + + + SQL Server 需要关闭所有其它连接来改变数据库属性——你确认要改变属性并关闭所有其它连接吗? + + + AUTO_CLOSED + + + 紧急 + + + 不可访问 + + + 一般 + + + 离线 + + + 恢复中 + + + 等待恢复 + + + 恢复中 + + + 关机 + + + 待机 + + + 怀疑 + + + 全局 + + + ju + + + MULTI_USER + + + RESTRICTED_USER + + + SINGLE_USER + + + 校验码 + + + 没有 + + + TORN_PAGE_DETECTION + + + 启用 VarDecimal 存储格式 + + + SQL Server 2008 (100) + + + 启用加密 + + + + + + + + + 首要的 + + + 对于分配政策HASH,开始的哈希列的数量是可选的,但是应在1到16之间 + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + + + + 部分 + + + FILESTREAM 文件 + + + 没有可用的文件组 + + + 数据库 {0} 无法访问。 + + + 无查询结果 + + + 资料行因结果集太长而可能无法加载 + + + 备份数据库 + + + 正在进行 + + + 已完成 + + + 参数化 + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.zh-hant.resx b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.zh-hant.resx index ee8b04a7..4c3bdcf7 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.zh-hant.resx +++ b/src/Microsoft.SqlTools.ServiceLayer/Localization/sr.zh-hant.resx @@ -145,7 +145,7 @@ ServerName 不能是 null 或空白 - {0} 不可為空值或空白,使用 SqlLogin 驗證時 + 使用 SqlLogin 驗證時,{0} 不可為 null 或是空白 查詢已完成,無法取消 @@ -358,7 +358,7 @@ 未定義變數 {0}。 - EN_LOCALIZATION + 測試 用空白字串取代空白字串。 @@ -441,6 +441,9 @@ 編輯工作階段尚未初始化 + + 編輯工作階段已初始化 + 編輯工作階段已完成初始化或正在初始化 @@ -456,6 +459,21 @@ 必須提供物件名稱 + + 不支援明確指定的伺服器或資料庫 + + + 資料表中繼資料無擴充屬性 + + + 找不到要編輯的資料表或檢視表 + + + 擴充資料庫時發生錯誤:{0} + + + 連接到 {0} 時發生錯誤 + 彙總 @@ -900,9 +918,6 @@ 資料表類型索引 - - ServerInstance - 選擇性 XML 索引 @@ -939,4 +954,438 @@ 資料行加密金鑰 + + 伺服器 + + + 剖析屬性 ScriptingParams.ConnectionString 時發生錯誤 + + + ScriptingParams.FilePath 屬性指定的路径是無效目錄 + + + 剖析屬性 ScriptingListObjectsCompleteParams.ConnectionString 時發生錯誤 + + + {0} ({1},{2},{3}) + + + 無預設值 + + + 輸入 + + + 輸入/輸出 + + + 輸入/唯讀 + + + 輸入/輸出/唯讀 + + + 預設值 + + + Null + + + 非 Null + + + {0} ({1},{2}) + + + {0} ({1}) + + + {0} ({1} 已計算,{2},{3}) + + + {0} ({1} 已計算) + + + {0} (資料行集,{1}) + + + {0} (資料行集,{1}{2},{3}) + + + {0} (資料行集,{1},{2},{3}) + + + 唯一 + + + 非唯一 + + + 叢集 + + + 非叢集 + + + 歷程記錄 + + + 系統建立版本 + + + 無法使用 + + + 當前預設檔案群組: {0} + + + {0} 的新檔案群組 + + + 預設值 + + + 檔案 + + + 名稱 + + + 唯讀 + + + 自動成長 / 大小上限 + + + ... + + + <預設> + + + 檔案群組 + + + 邏輯名稱 + + + 檔案類型 + + + 初始大小 (MB) + + + <新增檔案群組> + + + 路徑 + + + 檔案名稱 + + + <未經處理的裝置> + + + 大量記錄 + + + Full + + + Simple + + + 選取資料庫擁有者 + + + + + + 以 {0} MB 為單位,限制為 {1} MB + + + 以百分之 {0} 為單位,限制為 {1} MB + + + 以 {0} MB 為單位,無限制 + + + 以百分之 {0} 為單位,無限制 + + + 無限制 + + + 限制為 {0} MB + + + 自動 + + + Service Broker + + + 定序 + + + 資料指標 + + + 其他 + + + 復原 + + + 狀態 + + + ANSI NULL 預設值 + + + ANSI NULLS 已啟用 + + + +ANSI Padding 已啟用 + + + ANSI Warnings 已啟用 + + + Arithmetic Abort 已啟用 + + + 自動關閉 + + + 自動建立統計資料 + + + 自動壓縮 + + + 自動更新統計資料 + + + 自動非同步更新統計資料 + + + 區分大小寫 + + + 認可時關閉資料指標已啟用 + + + 定序 + + + 串連 Null 產生 Null + + + 資料庫相容性層級 + + + 資料庫狀態 + + + 預設資料指標 + + + 全文檢索索引已啟用 + + + 數值捨入中止 + + + 頁面確認 + + + 引號識別碼已啟用 + + + 資料庫唯讀 + + + 遞迴觸發程序已啟用 + + + 限制存取 + + + 選取/大量複製 + + + 接受 Broker 優先權 + + + Service Broker 識別碼 + + + Broker 已啟用 + + + 在檢查點截斷記錄 + + + 已啟用跨資料庫擁有權鏈結 + + + 可信任 + + + 已啟用日期相互關聯最佳化 prototype_db_prop_parameterization = 參數化 + + + 強制 + + + 簡易 + + + 資料列資料 + + + LOG + + + FILESTREAM 資料 + + + 不適用 + + + <預設路徑> + + + 開啟連接 + + + 為了變更資料庫屬性,SQL Server必須關閉所有其他與資料庫的連線。 +確定要變更屬性並關閉所有其他連線嗎? + + + 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 儲存格式已啟用 + + + SQL Server 2008 (100) + + + 加密已啟用 + + + OFF + + + ON + + + PRIMARY + + + 散發原則 HASH 的前置雜湊資料行是選擇性的,但應該介於 1 到 16 個資料行之間。 + + + SQL Server 2012 (110) + + + SQL Server 2014 (120) + + + SQL Server 2016 (130) + + + SQL Server vNext (140) + + + + + + Partial + + + FILESTREAM 檔案 + + + 沒有適用的檔案群組 + + + 無法存取資料庫 {0}。 + + + 沒有查詢結果可以回傳 + + + 資料列因結果集太長而無法載入 + + + 備份資料庫 + + + 進行中 + + + 已完成 + + + 參數化 + \ No newline at end of file diff --git a/src/Microsoft.SqlTools.ServiceLayer/TaskServices/SqlTask.cs b/src/Microsoft.SqlTools.ServiceLayer/TaskServices/SqlTask.cs index d84ab501..98697689 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TaskServices/SqlTask.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TaskServices/SqlTask.cs @@ -190,8 +190,11 @@ namespace Microsoft.SqlTools.ServiceLayer.TaskServices WaitHandle.WaitAny(waitHandles); try { - await this.TaskToCancel(this); - result.TaskStatus = SqlTaskStatus.Canceled; + if (token.IsCancellationRequested) + { + await this.TaskToCancel(this); + result.TaskStatus = SqlTaskStatus.Canceled; + } } catch (Exception ex) { diff --git a/src/Microsoft.SqlTools.ServiceLayer/Utility/GeneralRequestDetails.cs b/src/Microsoft.SqlTools.ServiceLayer/Utility/GeneralRequestDetails.cs new file mode 100644 index 00000000..af8a5bc4 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/Utility/GeneralRequestDetails.cs @@ -0,0 +1,69 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Globalization; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.SqlTools.ServiceLayer.Utility +{ + public class GeneralRequestDetails + { + public GeneralRequestDetails() + { + Options = new Dictionary(); + } + + protected T GetOptionValue(string name) + { + T result = default(T); + if (Options != null && Options.ContainsKey(name)) + { + object value = Options[name]; + try + { + if (value != null && (typeof(T) != value.GetType())) + { + if (typeof(T) == typeof(int) || typeof(T) == typeof(int?)) + { + value = Convert.ToInt32(value); + } + else if (typeof(T) == typeof(bool) || typeof(T) == typeof(bool?)) + { + value = Convert.ToBoolean(value); + } + } + result = value != null ? (T)value : default(T); + } + catch + { + result = default(T); + Logger.Write(LogLevel.Warning, string.Format(CultureInfo.InvariantCulture, + "Cannot convert option value {0}:{1} to {2}", name, value ?? "", typeof(T))); + } + } + return result; + } + + protected void SetOptionValue(string name, T value) + { + Options = Options ?? new Dictionary(); + if (Options.ContainsKey(name)) + { + Options[name] = value; + } + else + { + Options.Add(name, value); + } + } + + /// + /// Gets or Sets the options + /// + public Dictionary Options { get; set; } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/RestoreDatabaseServiceTests.cs b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/RestoreDatabaseServiceTests.cs index 4c44be41..21d90329 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/RestoreDatabaseServiceTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.IntegrationTests/DisasterRecovery/RestoreDatabaseServiceTests.cs @@ -3,13 +3,17 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // +using System.Collections.Generic; +using System.Data.SqlClient; using System.Globalization; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.SqlServer.Management.Smo; using Microsoft.SqlTools.Extensibility; using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.SqlTools.ServiceLayer.Admin; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.DisasterRecovery; using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts; @@ -29,6 +33,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery private ConnectionService _connectService = TestServiceProvider.Instance.ConnectionService; private Mock serviceHostMock; private DisasterRecoveryService service; + private string fullBackUpDatabase; public RestoreDatabaseServiceTests() { @@ -37,26 +42,81 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery service.InitializeService(serviceHostMock.Object); } + private async Task VerifyBackupFileCreated() + { + if(fullBackUpDatabase == null) + { + fullBackUpDatabase = await CreateBackupFile(); + } + } + [Fact] public async void RestorePlanShouldCreatedSuccessfullyForFullBackup() { - string backupFileName = "FullBackup.bak"; + await VerifyBackupFileCreated(); bool canRestore = true; - await VerifyRestore(backupFileName, canRestore); + await VerifyRestore(fullBackUpDatabase, canRestore); + } + + [Fact] + public async void RestoreShouldCreatedSuccessfullyGivenTwoBackupFiles() + { + + string[] backupFileNames = new string[] { "FullBackup.bak", "DiffBackup.bak" }; + bool canRestore = true; + var response = await VerifyRestore(backupFileNames, canRestore, false, "RestoredFromTwoBackupFile"); + Assert.True(response.BackupSetsToRestore.Count() == 2); + } + + [Fact] + public async void RestoreShouldFailGivenTwoBackupFilesButFilterFullBackup() + { + + string[] backupFileNames = new string[] { "FullBackup.bak", "DiffBackup.bak" }; + bool canRestore = true; + var response = await VerifyRestore(backupFileNames, canRestore, false, "RestoredFromTwoBackupFile"); + Assert.True(response.BackupSetsToRestore.Count() == 2); + var fileInfo = response.BackupSetsToRestore.FirstOrDefault(x => x.GetPropertyValueAsString(BackupSetInfo.BackupTypePropertyName) != RestoreConstants.TypeFull); + if(fileInfo != null) + { + var selectedBackupSets = new string[] { fileInfo.Id }; + await VerifyRestore(backupFileNames, false, false, "RestoredFromTwoBackupFile", selectedBackupSets); + } + } + + [Fact] + public async void RestoreShouldCompletedSuccessfullyGivenTowBackupFilesButFilterDifferentialBackup() + { + + string[] backupFileNames = new string[] { "FullBackup.bak", "DiffBackup.bak" }; + bool canRestore = true; + var response = await VerifyRestore(backupFileNames, canRestore, false, "RestoredFromTwoBackupFile"); + Assert.True(response.BackupSetsToRestore.Count() == 2); + var fileInfo = response.BackupSetsToRestore.FirstOrDefault(x => x.GetPropertyValueAsString(BackupSetInfo.BackupTypePropertyName) == RestoreConstants.TypeFull); + if (fileInfo != null) + { + var selectedBackupSets = new string[] { fileInfo.Id }; + await VerifyRestore(backupFileNames, true, false, "RestoredFromTwoBackupFile2", selectedBackupSets); + } } [Fact] public async void RestoreShouldExecuteSuccessfullyForFullBackup() { - string backupFileName = "FullBackup.bak"; + await VerifyBackupFileCreated(); + + string backupFileName = fullBackUpDatabase; bool canRestore = true; var restorePlan = await VerifyRestore(backupFileName, canRestore, true); + Assert.NotNull(restorePlan.BackupSetsToRestore); } [Fact] public async void RestoreToAnotherDatabaseShouldExecuteSuccessfullyForFullBackup() { - string backupFileName = "FullBackup.bak"; + await VerifyBackupFileCreated(); + + string backupFileName = fullBackUpDatabase; bool canRestore = true; var restorePlan = await VerifyRestore(backupFileName, canRestore, true, "NewRestoredDatabase"); } @@ -80,15 +140,17 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery [Fact] public async Task RestorePlanRequestShouldReturnResponseWithDbFiles() { + await VerifyBackupFileCreated(); + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) { TestConnectionResult connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath); - string filePath = GetBackupFilePath("FullBackup.bak"); + string filePath = GetBackupFilePath(fullBackUpDatabase); RestoreParams restoreParams = new RestoreParams { - BackupFilePath = filePath, + BackupFilePaths = filePath, OwnerUri = queryTempFile.FilePath }; @@ -97,7 +159,6 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery verify: ((result) => { Assert.True(result.DbFiles.Any()); - Assert.Equal(result.DatabaseName, "BackupTestDb"); })); } } @@ -113,7 +174,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery RestoreParams restoreParams = new RestoreParams { - BackupFilePath = filePath, + BackupFilePaths = filePath, OwnerUri = queryTempFile.FilePath }; @@ -140,7 +201,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery RestoreParams restoreParams = new RestoreParams { - BackupFilePath = filePath, + BackupFilePaths = filePath, OwnerUri = queryTempFile.FilePath }; @@ -164,7 +225,15 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery private async Task VerifyRestore(string backupFileName, bool canRestore, bool execute = false, string targetDatabase = null) { - string filePath = GetBackupFilePath(backupFileName); + return await VerifyRestore(new string[] { backupFileName }, canRestore, execute, targetDatabase); + } + + private async Task VerifyRestore(string[] backupFileNames, bool canRestore, bool execute = false, string targetDatabase = null, string[] selectedBackupSets = null) + { + var filePaths = backupFileNames.Select(x => GetBackupFilePath(x)); + string backUpFilePath = filePaths.Aggregate((current, next) => current + " ," + next); + + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) { TestConnectionResult connectionResult = await LiveConnectionHelper.InitLiveConnectionInfoAsync("master", queryTempFile.FilePath); @@ -172,15 +241,17 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery RestoreDatabaseHelper service = new RestoreDatabaseHelper(); var request = new RestoreParams { - BackupFilePath = filePath, - DatabaseName = targetDatabase, - OwnerUri = queryTempFile.FilePath + BackupFilePaths = backUpFilePath, + TargetDatabaseName = targetDatabase, + OwnerUri = queryTempFile.FilePath, + SelectedBackupSets = selectedBackupSets }; var restoreDataObject = service.CreateRestoreDatabaseTaskDataObject(request); var response = service.CreateRestorePlanResponse(restoreDataObject); Assert.NotNull(response); + Assert.False(string.IsNullOrWhiteSpace(response.RestoreSessionId)); Assert.Equal(response.CanRestore, canRestore); if (canRestore) { @@ -193,11 +264,18 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery if(execute) { + request.SessionId = response.RestoreSessionId; + restoreDataObject = service.CreateRestoreDatabaseTaskDataObject(request); + Assert.Equal(response.RestoreSessionId, restoreDataObject.SessionId); await DropDatabase(targetDatabase); Thread.Sleep(2000); request.RelocateDbFiles = response.RelocateFilesNeeded; service.ExecuteRestore(restoreDataObject); Assert.True(restoreDataObject.Server.Databases.Contains(targetDatabase)); + if(selectedBackupSets != null) + { + Assert.Equal(selectedBackupSets.Count(), restoreDataObject.RestorePlan.RestoreOperations.Count()); + } await DropDatabase(targetDatabase); } } @@ -230,8 +308,15 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery private string GetBackupFilePath(string fileName) { - FileInfo inputFile = GetBackupFile(fileName); - return inputFile.FullName; + if (!Path.IsPathRooted(fileName)) + { + FileInfo inputFile = GetBackupFile(fileName); + return inputFile.FullName; + } + else + { + return fileName; + } } protected DisasterRecoveryService CreateService() @@ -247,5 +332,56 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.DisasterRecovery return CreateProvider() .RegisterSingleService(new DisasterRecoveryService()); } + + public async Task CreateBackupFile() + { + using (SelfCleaningTempFile queryTempFile = new SelfCleaningTempFile()) + { + SqlTestDb testDb = await SqlTestDb.CreateNewAsync(TestServerType.OnPrem, false, null, null, "RestoreTest"); + var liveConnection = LiveConnectionHelper.InitLiveConnectionInfo(testDb.DatabaseName, queryTempFile.FilePath); + + // Initialize backup service + DatabaseTaskHelper helper = AdminService.CreateDatabaseTaskHelper(liveConnection.ConnectionInfo, databaseExists: true); + SqlConnection sqlConn = DisasterRecoveryService.GetSqlConnection(liveConnection.ConnectionInfo); + + // Get default backup path + BackupConfigInfo backupConfigInfo = DisasterRecoveryService.Instance.GetBackupConfigInfo(helper.DataContainer, sqlConn, sqlConn.Database); + string backupPath = Path.Combine(backupConfigInfo.DefaultBackupFolder, testDb.DatabaseName + ".bak"); + + BackupInfo backupInfo = CreateBackupInfo(testDb.DatabaseName, + BackupType.Full, + new List() { backupPath }, + new Dictionary() { { backupPath, (int)DeviceType.File } }); + + var backupParams = new BackupParams + { + OwnerUri = liveConnection.ConnectionInfo.OwnerUri, + BackupInfo = backupInfo + }; + + // Backup the database + BackupOperation backupOperation = DisasterRecoveryService.Instance.SetBackupInput(helper.DataContainer, sqlConn, backupParams.BackupInfo); + DisasterRecoveryService.Instance.PerformBackup(backupOperation); + + // Clean up the database + testDb.Cleanup(); + return backupPath; + } + } + + private BackupInfo CreateBackupInfo(string databaseName, BackupType backupType, List backupPathList, Dictionary backupPathDevices) + { + BackupInfo backupInfo = new BackupInfo(); + backupInfo.BackupComponent = (int)BackupComponent.Database; + backupInfo.BackupDeviceType = (int)BackupDeviceType.Disk; + backupInfo.BackupPathDevices = backupPathDevices; + backupInfo.BackupPathList = backupPathList; + backupInfo.BackupsetName = "default_backup"; + backupInfo.BackupType = (int)backupType; + backupInfo.DatabaseName = databaseName; + backupInfo.SelectedFileGroup = null; + backupInfo.SelectedFiles = ""; + return backupInfo; + } } } diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/DisasterRecovery/Backups/DiffBackup.bak b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/DisasterRecovery/Backups/DiffBackup.bak index d0b95795..9a31fe12 100644 Binary files a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/DisasterRecovery/Backups/DiffBackup.bak and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/DisasterRecovery/Backups/DiffBackup.bak differ diff --git a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/DisasterRecovery/Backups/FullBackup.bak b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/DisasterRecovery/Backups/FullBackup.bak index bcc7074f..0d769c96 100644 Binary files a/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/DisasterRecovery/Backups/FullBackup.bak and b/test/Microsoft.SqlTools.ServiceLayer.Test.Common/TestData/DisasterRecovery/Backups/FullBackup.bak differ diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/DatabaseFileInfoTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/DatabaseFileInfoTests.cs new file mode 100644 index 00000000..cbdf9ca6 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/DatabaseFileInfoTests.cs @@ -0,0 +1,53 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts; +using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery +{ + public class DatabaseFileInfoTests + { + [Fact] + public void DatabaseFileInfoConstructorShouldThrowExceptionGivenNull() + { + Assert.Throws(() => new DatabaseFileInfo(null)); + } + + [Fact] + public void DatabaseFileInfoShouldReturnNullGivenEmptyProperties() + { + LocalizedPropertyInfo[] properties = new LocalizedPropertyInfo[] { }; + var fileInfo = new DatabaseFileInfo(properties); + Assert.True(string.IsNullOrEmpty(fileInfo.Id)); + Assert.True(string.IsNullOrEmpty(fileInfo.GetPropertyValueAsString(BackupSetInfo.BackupComponentPropertyName))); + } + + [Fact] + public void DatabaseFileInfoShouldReturnValuesGivenValidProperties() + { + LocalizedPropertyInfo[] properties = new LocalizedPropertyInfo[] { + new LocalizedPropertyInfo + { + PropertyName = "name", + PropertyValue = 1 + }, + new LocalizedPropertyInfo + { + PropertyName = DatabaseFileInfo.IdPropertyName, + PropertyValue = "id" + } + + }; + var fileInfo = new DatabaseFileInfo(properties); + Assert.Equal(fileInfo.Id, "id"); + Assert.Equal(fileInfo.GetPropertyValueAsString("name"), "1"); + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/LocalizedPropertyInfoTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/LocalizedPropertyInfoTests.cs new file mode 100644 index 00000000..3f8f2143 --- /dev/null +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/DisasterRecovery/LocalizedPropertyInfoTests.cs @@ -0,0 +1,33 @@ +// +// 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.DisasterRecovery.Contracts; +using Xunit; + +namespace Microsoft.SqlTools.ServiceLayer.UnitTests.DisasterRecovery +{ + public class LocalizedPropertyInfoTests + { + [Fact] + public void PropertyDisplayNameShouldReturnNameWhenNotSet() + { + LocalizedPropertyInfo propertyInfo = new LocalizedPropertyInfo(); + propertyInfo.PropertyName = "name"; + + Assert.Equal(propertyInfo.PropertyDisplayName, propertyInfo.PropertyName); + } + + [Fact] + public void PropertyValudDisplayNameShouldReturnValudWhenNotSet() + { + LocalizedPropertyInfo propertyInfo = new LocalizedPropertyInfo(); + propertyInfo.PropertyName = "name"; + propertyInfo.PropertyValue = "value"; + + Assert.Equal(propertyInfo.PropertyValueDisplayName, propertyInfo.PropertyValue); + } + } +} diff --git a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/NodeTests.cs b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/NodeTests.cs index 8cf9cac3..3ae9ea25 100644 --- a/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/NodeTests.cs +++ b/test/Microsoft.SqlTools.ServiceLayer.UnitTests/ObjectExplorer/NodeTests.cs @@ -48,7 +48,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer defaultConnParams = new ConnectionCompleteParams() { ServerInfo = defaultServerInfo, - ConnectionSummary = defaultConnectionDetails, + ConnectionSummary = defaultConnectionDetails != null ? ((IConnectionSummary)defaultConnectionDetails).Clone(): null, OwnerUri = defaultOwnerUri }; @@ -119,6 +119,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.ObjectExplorer // But given a server node for a cloud DB that's not master defaultConnectionDetails.DatabaseName = "NotMaster"; + defaultConnParams.ConnectionSummary.DatabaseName = defaultConnectionDetails.DatabaseName; node = new ServerNode(defaultConnParams, ServiceProvider); // Then expect label to include db name