diff --git a/bin/nuget/Microsoft.SqlServer.Smo.140.17049.0.nupkg b/bin/nuget/Microsoft.SqlServer.Smo.140.17049.0.nupkg
deleted file mode 100644
index e79d8fc1..00000000
Binary files a/bin/nuget/Microsoft.SqlServer.Smo.140.17049.0.nupkg and /dev/null differ
diff --git a/bin/nuget/Microsoft.SqlServer.Smo.140.17050.0.nupkg b/bin/nuget/Microsoft.SqlServer.Smo.140.17050.0.nupkg
new file mode 100644
index 00000000..6b3fbe7d
Binary files /dev/null and b/bin/nuget/Microsoft.SqlServer.Smo.140.17050.0.nupkg differ
diff --git a/docs/samples/jsonrpc/netcore/executequery/project.json b/docs/samples/jsonrpc/netcore/executequery/project.json
index 6a081889..c6e8feaa 100644
--- a/docs/samples/jsonrpc/netcore/executequery/project.json
+++ b/docs/samples/jsonrpc/netcore/executequery/project.json
@@ -12,7 +12,7 @@
"Newtonsoft.Json": "9.0.1",
"System.Data.Common": "4.1.0",
"System.Data.SqlClient": "4.4.0-sqltools-24613-04",
- "Microsoft.SqlServer.Smo": "140.17049.0",
+ "Microsoft.SqlServer.Smo": "140.17050.0",
"System.Security.SecureString": "4.0.0",
"System.Collections.Specialized": "4.0.1",
"System.ComponentModel.TypeConverter": "4.1.0",
diff --git a/docs/samples/smo/netcore/ModifySetting/project.json b/docs/samples/smo/netcore/ModifySetting/project.json
index 912dedb8..fb27dece 100644
--- a/docs/samples/smo/netcore/ModifySetting/project.json
+++ b/docs/samples/smo/netcore/ModifySetting/project.json
@@ -5,7 +5,7 @@
"emitEntryPoint": true
},
"dependencies": {
- "Microsoft.SqlServer.Smo": "140.17049.0"
+ "Microsoft.SqlServer.Smo": "140.17050.0"
},
"frameworks": {
"netcoreapp1.0": {
diff --git a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/AdminServicesProviderOptions.cs b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/AdminServicesProviderOptions.cs
new file mode 100644
index 00000000..9d34f2d6
--- /dev/null
+++ b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/AdminServicesProviderOptions.cs
@@ -0,0 +1,20 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.SqlTools.Hosting.Contracts
+{
+ ///
+ /// Defines the admin services provider options that the DMP server implements.
+ ///
+ public class AdminServicesProviderOptions
+ {
+ public ServiceOption[] DatabaseInfoOptions { get; set; }
+
+ public ServiceOption[] DatabaseFileInfoOptions { get; set; }
+
+ public ServiceOption[] FileGroupInfoOptions { get; set; }
+ }
+}
+
diff --git a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ConnectionProviderOptions.cs b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ConnectionProviderOptions.cs
index 50089435..94dc400b 100644
--- a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ConnectionProviderOptions.cs
+++ b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ConnectionProviderOptions.cs
@@ -22,41 +22,14 @@ namespace Microsoft.SqlTools.Hosting.Contracts
public string Name { get; set; }
}
- public class ConnectionOption
+ public class ConnectionOption : ServiceOption
{
- public static readonly string ValueTypeString = "string";
- public static readonly string ValueTypeMultiString = "multistring";
- public static readonly string ValueTypePassword = "password";
- public static readonly string ValueTypeNumber = "number";
- public static readonly string ValueTypeCategory = "category";
- public static readonly string ValueTypeBoolean = "boolean";
-
public static readonly string SpecialValueServerName = "serverName";
public static readonly string SpecialValueDatabaseName = "databaseName";
public static readonly string SpecialValueAuthType = "authType";
public static readonly string SpecialValueUserName = "userName";
public static readonly string SpecialValuePasswordName = "password";
- public string Name { get; set; }
-
- public string DisplayName { get; set; }
-
- public string Description {get; set; }
-
- public string GroupName {get; set; }
-
- ///
- /// Type of the parameter. Can be either string, number, or category.
- ///
- public string ValueType { get; set; }
-
- public string DefaultValue { get; set; }
-
- ///
- /// Set of permitted values if ValueType is category.
- ///
- public CategoryValue[] CategoryValues { get; set; }
-
///
/// Determines if the parameter is one of the 'special' known values.
/// Can be either Server Name, Database Name, Authentication Type,
@@ -68,11 +41,6 @@ namespace Microsoft.SqlTools.Hosting.Contracts
/// Flag to indicate that this option is part of the connection identity
///
public bool IsIdentity { get; set; }
-
- ///
- /// Flag to indicate that this option is required
- ///
- public bool IsRequired { get; set; }
}
}
diff --git a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/DmpServerCapabilities.cs b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/DmpServerCapabilities.cs
index 9b204021..13ec99c3 100644
--- a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/DmpServerCapabilities.cs
+++ b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/DmpServerCapabilities.cs
@@ -17,5 +17,7 @@ namespace Microsoft.SqlTools.Hosting.Contracts
public string ProviderDisplayName { get; set; }
public ConnectionProviderOptions ConnectionProvider { get; set; }
+
+ public AdminServicesProviderOptions AdminServicesProvider { get; set; }
}
}
diff --git a/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ServiceOption.cs b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ServiceOption.cs
new file mode 100644
index 00000000..b394ebf8
--- /dev/null
+++ b/src/Microsoft.SqlTools.Hosting/Hosting/Contracts/ServiceOption.cs
@@ -0,0 +1,48 @@
+ //
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+namespace Microsoft.SqlTools.Hosting.Contracts
+{
+ public class ServiceOption
+ {
+ public static readonly string ValueTypeString = "string";
+ public static readonly string ValueTypeMultiString = "multistring";
+ public static readonly string ValueTypePassword = "password";
+ public static readonly string ValueTypeNumber = "number";
+ public static readonly string ValueTypeCategory = "category";
+ public static readonly string ValueTypeBoolean = "boolean";
+ public static readonly string ValueTypeObject = "object";
+
+ public string Name { get; set; }
+
+ public string DisplayName { get; set; }
+
+ public string Description {get; set; }
+
+ public string GroupName {get; set; }
+
+ ///
+ /// Type of the parameter. Can be either string, number, or category.
+ ///
+ public string ValueType { get; set; }
+
+ public string DefaultValue { get; set; }
+
+ public string ObjectType { get; set; }
+
+ ///
+ /// Set of permitted values if ValueType is category.
+ ///
+ public CategoryValue[] CategoryValues { get; set; }
+
+ ///
+ /// Flag to indicate that this option is required
+ ///
+ public bool IsRequired { get; set; }
+
+ public bool IsArray { get; set; }
+ }
+}
+
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Admin/AdminService.cs b/src/Microsoft.SqlTools.ServiceLayer/Admin/AdminService.cs
index 13152390..88d8edc8 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Admin/AdminService.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Admin/AdminService.cs
@@ -5,10 +5,12 @@
using Microsoft.SqlTools.Hosting.Protocol;
using Microsoft.SqlTools.ServiceLayer.Admin.Contracts;
+using Microsoft.SqlTools.ServiceLayer.Connection;
using Microsoft.SqlTools.ServiceLayer.Hosting;
using Microsoft.SqlTools.ServiceLayer.SqlContext;
using System;
using System.Threading.Tasks;
+using System.Xml;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
@@ -19,6 +21,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
private static readonly Lazy instance = new Lazy(() => new AdminService());
+ private static ConnectionService connectionService = null;
+
///
/// Default, parameterless constructor.
///
@@ -26,6 +30,26 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
}
+ ///
+ /// Internal for testing purposes only
+ ///
+ internal static ConnectionService ConnectionServiceInstance
+ {
+ get
+ {
+ if (AdminService.connectionService == null)
+ {
+ AdminService.connectionService = ConnectionService.Instance;
+ }
+ return AdminService.connectionService;
+ }
+
+ set
+ {
+ AdminService.connectionService = value;
+ }
+ }
+
///
/// Gets the singleton instance object
///
@@ -41,6 +65,62 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
serviceHost.SetRequestHandler(CreateDatabaseRequest.Type, HandleCreateDatabaseRequest);
serviceHost.SetRequestHandler(CreateLoginRequest.Type, HandleCreateLoginRequest);
+ serviceHost.SetRequestHandler(DefaultDatabaseInfoRequest.Type, HandleDefaultDatabaseInfoRequest);
+ }
+
+ public static async Task HandleDefaultDatabaseInfoRequest(
+ DefaultDatabaseInfoParams optionsParams,
+ RequestContext requestContext)
+ {
+ var response = new DefaultDatabaseInfoResponse();
+
+ ConnectionInfo connInfo;
+ AdminService.ConnectionServiceInstance.TryFindConnection(
+ optionsParams.OwnerUri,
+ out connInfo);
+
+ XmlDocument xmlDoc = CreateDataContainerDocument(connInfo);
+ char[] passwordArray = connInfo.ConnectionDetails.Password.ToCharArray();
+ unsafe
+ {
+ fixed (char* passwordPtr = passwordArray)
+ {
+ var dataContainer = new CDataContainer(
+ CDataContainer.ServerType.SQL,
+ connInfo.ConnectionDetails.ServerName,
+ false,
+ connInfo.ConnectionDetails.UserName,
+ new System.Security.SecureString(passwordPtr, passwordArray.Length),
+ xmlDoc.InnerXml);
+
+ var taskHelper = new DatabaseTaskHelper();
+ taskHelper.CreateDatabase(dataContainer);
+
+ response.DefaultDatabaseInfo = DatabaseTaskHelper.DatabasePrototypeToDatabaseInfo(taskHelper.Prototype);
+ }
+ }
+
+ await requestContext.SendResult(response);
+ }
+
+
+ private static XmlDocument CreateDataContainerDocument(ConnectionInfo connInfo)
+ {
+ string xml =
+ string.Format(@"
+
+ {0}
+ {0} (SQLServer, user = {1})
+ sql
+ Server[@Name='{0}']
+ Database
+ ",
+ connInfo.ConnectionDetails.ServerName.ToUpper(),
+ connInfo.ConnectionDetails.UserName);
+
+ var xmlDoc = new XmlDocument();
+ xmlDoc.LoadXml(xml);
+ return xmlDoc;
}
///
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Admin/AdminServicesProviderOptionsHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/Admin/AdminServicesProviderOptionsHelper.cs
new file mode 100644
index 00000000..2977cd71
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Admin/AdminServicesProviderOptionsHelper.cs
@@ -0,0 +1,114 @@
+//
+// 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.Hosting.Contracts;
+
+namespace Microsoft.SqlTools.ServiceLayer.Admin
+{
+ ///
+ /// Helper class for providing metadata about admin services
+ ///
+ public class AdminServicesProviderOptionsHelper
+ {
+ internal const string Name = "name";
+ internal const string Owner = "owner";
+ internal const string Collation = "collation";
+ internal const string FileGroups = "fileGroups";
+ internal const string DatabaseFiles = "databaseFiles";
+ internal const string PhysicalName = "physicalName";
+
+ internal static AdminServicesProviderOptions BuildAdminServicesProviderOptions()
+ {
+ return new AdminServicesProviderOptions
+ {
+ DatabaseInfoOptions = new ServiceOption[]
+ {
+ new ServiceOption
+ {
+ Name = AdminServicesProviderOptionsHelper.Name,
+ DisplayName = "Name",
+ Description = "Name of the database",
+ ValueType = ServiceOption.ValueTypeString,
+ IsRequired = true,
+ GroupName = "General"
+ },
+ new ServiceOption
+ {
+ Name = AdminServicesProviderOptionsHelper.Owner,
+ DisplayName = "Owner",
+ Description = "Database owner",
+ ValueType = ServiceOption.ValueTypeString,
+ IsRequired = true,
+ GroupName = "General"
+ },
+ new ServiceOption
+ {
+ Name = AdminServicesProviderOptionsHelper.Collation,
+ DisplayName = "Collation",
+ Description = "Database collation",
+ ValueType = ServiceOption.ValueTypeString,
+ IsRequired = true,
+ GroupName = "General"
+ },
+ new ServiceOption
+ {
+ Name = AdminServicesProviderOptionsHelper.FileGroups,
+ DisplayName = "File Groups",
+ Description = "File groups",
+ ObjectType = "FileGroupInfo",
+ ValueType = ServiceOption.ValueTypeObject,
+ IsRequired = true,
+ IsArray = true,
+ GroupName = "General"
+ },
+ new ServiceOption
+ {
+ Name = AdminServicesProviderOptionsHelper.DatabaseFiles,
+ DisplayName = "Database Files",
+ Description = "Database Files",
+ ObjectType = "DatabaseFileInfo",
+ ValueType = ServiceOption.ValueTypeObject,
+ IsRequired = true,
+ IsArray = true,
+ GroupName = "General"
+ }
+ },
+ FileGroupInfoOptions = new ServiceOption[]
+ {
+ new ServiceOption
+ {
+ Name = AdminServicesProviderOptionsHelper.Name,
+ DisplayName = "Name",
+ Description = "Name of the file group",
+ ValueType = ServiceOption.ValueTypeString,
+ IsRequired = true,
+ GroupName = "General"
+ }
+ },
+ DatabaseFileInfoOptions = new ServiceOption[]
+ {
+ new ServiceOption
+ {
+ Name = AdminServicesProviderOptionsHelper.Name,
+ DisplayName = "Name",
+ Description = "Name of the database file",
+ ValueType = ServiceOption.ValueTypeString,
+ IsRequired = true,
+ GroupName = "General"
+ },
+ new ServiceOption
+ {
+ Name = AdminServicesProviderOptionsHelper.PhysicalName,
+ DisplayName = "Physical Name",
+ Description = "Physical name of the database file",
+ ValueType = ServiceOption.ValueTypeString,
+ IsRequired = true,
+ GroupName = "General"
+ }
+ }
+ };
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Admin/Common/AzureSqlDbHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/Admin/Common/AzureSqlDbHelper.cs
new file mode 100644
index 00000000..66dc9447
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Admin/Common/AzureSqlDbHelper.cs
@@ -0,0 +1,466 @@
+//
+// 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.Linq;
+using System.Collections.Generic;
+using System.Globalization;
+using Microsoft.SqlServer.Diagnostics.STrace;
+using Microsoft.SqlServer.Management.Common;
+using Microsoft.Win32;
+using SizeUnits = Microsoft.SqlTools.ServiceLayer.Admin.DbSize.SizeUnits;
+
+namespace Microsoft.SqlTools.ServiceLayer.Admin
+{
+ public static class AzureSqlDbHelper
+ {
+
+ private static readonly TraceContext TraceContext = TraceContext.GetTraceContext("AzureSqlDbUtils", typeof(AzureSqlDbHelper).Name);
+
+ ///
+ /// Registry key for SSMS Azure overrides
+ ///
+ private static readonly string SSMSAzureRegKey =
+ @"HKEY_CURRENT_USER\Software\Microsoft\SQL Server Management Studio\14.0\Azure";
+
+ ///
+ /// Registry sub key for the AzureServiceObjectives overrides
+ ///
+ private const string AzureServiceObjectivesRegSubKey = @"AzureServiceObjectives";
+
+ ///
+ /// Contains the various editions available for an Azure Database
+ ///
+ /// ****IMPORTANT**** - If updating this enum make sure that the other logic in this class is updated as well
+ public enum AzureEdition
+ {
+ Web = 0,
+ Business = 1,
+ Basic = 2,
+ Standard = 3,
+ Premium = 4,
+ DataWarehouse = 5,
+ PremiumRS = 6
+ }
+
+ ///
+ /// Provides a mapping of Azure DB Editions to their respective size options
+ ///
+ /// Values below are taken from http://msdn.microsoft.com/en-us/library/dn268335.aspx
+ private static readonly Dictionary> AzureEditionDatabaseSizeMappings = new Dictionary
+ >
+ {
+ {
+ AzureEdition.Web, new KeyValuePair(
+ 1, //1GB
+ new[]
+ {
+ new DbSize(100, SizeUnits.MB),
+ new DbSize(1, SizeUnits.GB), //Default
+ new DbSize(5, SizeUnits.GB)
+ })
+ },
+ {
+ AzureEdition.Business, new KeyValuePair(
+ 0, //10GB
+ new[]
+ {
+ new DbSize(10, SizeUnits.GB), //Default
+ new DbSize(20, SizeUnits.GB),
+ new DbSize(30, SizeUnits.GB),
+ new DbSize(40, SizeUnits.GB),
+ new DbSize(50, SizeUnits.GB),
+ new DbSize(100, SizeUnits.GB),
+ new DbSize(150, SizeUnits.GB)
+ })
+ },
+ {
+ AzureEdition.Basic, new KeyValuePair(
+ 3, //2GB
+ new[]
+ {
+ new DbSize(100, SizeUnits.MB),
+ new DbSize(500, SizeUnits.MB),
+ new DbSize(1, SizeUnits.GB),
+ new DbSize(2, SizeUnits.GB) //Default
+ })
+ },
+ {
+ AzureEdition.Standard,
+ new KeyValuePair(
+ 13, //250GB
+ new[]
+ {
+ new DbSize(100, SizeUnits.MB),
+ new DbSize(500, SizeUnits.MB),
+ new DbSize(1, SizeUnits.GB),
+ new DbSize(2, SizeUnits.GB),
+ new DbSize(5, SizeUnits.GB),
+ new DbSize(10, SizeUnits.GB),
+ new DbSize(20, SizeUnits.GB),
+ new DbSize(30, SizeUnits.GB),
+ new DbSize(40, SizeUnits.GB),
+ new DbSize(50, SizeUnits.GB),
+ new DbSize(100, SizeUnits.GB),
+ new DbSize(150, SizeUnits.GB),
+ new DbSize(200, SizeUnits.GB),
+ new DbSize(250, SizeUnits.GB) //Default
+ })
+ },
+ {
+ AzureEdition.Premium,
+ new KeyValuePair(
+ 16, //500GB
+ new[]
+ {
+ new DbSize(100, SizeUnits.MB),
+ new DbSize(500, SizeUnits.MB),
+ new DbSize(1, SizeUnits.GB),
+ new DbSize(2, SizeUnits.GB),
+ new DbSize(5, SizeUnits.GB),
+ new DbSize(10, SizeUnits.GB),
+ new DbSize(20, SizeUnits.GB),
+ new DbSize(30, SizeUnits.GB),
+ new DbSize(40, SizeUnits.GB),
+ new DbSize(50, SizeUnits.GB),
+ new DbSize(100, SizeUnits.GB),
+ new DbSize(150, SizeUnits.GB),
+ new DbSize(200, SizeUnits.GB),
+ new DbSize(250, SizeUnits.GB),
+ new DbSize(300, SizeUnits.GB),
+ new DbSize(400, SizeUnits.GB),
+ new DbSize(500, SizeUnits.GB), //Default
+ new DbSize(1024, SizeUnits.GB) //Following portal to display this as GB instead of 1TB
+ })
+ },
+
+ {
+ AzureEdition.DataWarehouse,
+ new KeyValuePair(
+ 5, //10240GB
+ new[]
+ {
+ new DbSize(250, SizeUnits.GB),
+ new DbSize(500, SizeUnits.GB),
+ new DbSize(750, SizeUnits.GB),
+ new DbSize(1024, SizeUnits.GB),
+ new DbSize(5120, SizeUnits.GB),
+ new DbSize(10240, SizeUnits.GB),
+ new DbSize(20480, SizeUnits.GB),
+ new DbSize(30720, SizeUnits.GB),
+ new DbSize(40960, SizeUnits.GB),
+ new DbSize(51200, SizeUnits.GB)
+ })
+ },
+ {
+ AzureEdition.PremiumRS,
+ new KeyValuePair(
+ 16, //500GB
+ new[]
+ {
+ new DbSize(100, SizeUnits.MB),
+ new DbSize(500, SizeUnits.MB),
+ new DbSize(1, SizeUnits.GB),
+ new DbSize(2, SizeUnits.GB),
+ new DbSize(5, SizeUnits.GB),
+ new DbSize(10, SizeUnits.GB),
+ new DbSize(20, SizeUnits.GB),
+ new DbSize(30, SizeUnits.GB),
+ new DbSize(40, SizeUnits.GB),
+ new DbSize(50, SizeUnits.GB),
+ new DbSize(100, SizeUnits.GB),
+ new DbSize(150, SizeUnits.GB),
+ new DbSize(200, SizeUnits.GB),
+ new DbSize(250, SizeUnits.GB),
+ new DbSize(300, SizeUnits.GB),
+ new DbSize(400, SizeUnits.GB),
+ new DbSize(500, SizeUnits.GB), //Default
+ })
+ },
+ };
+
+ ///
+ /// Maps Azure DB Editions to their corresponding Service Objective (Performance Level) options. These values are the default but
+ /// can be overridden by use of the ImportExportWizard registry key (see static initializer above).
+ ///
+ /// The key is the index of the default value for the list
+ ///
+ private static readonly Dictionary> AzureServiceObjectiveInfo = new Dictionary
+ >
+ {
+ {AzureEdition.Basic, new KeyValuePair(0, new[] {"Basic"})},
+ {AzureEdition.Standard, new KeyValuePair(2, new[] {"S0", "S1", "S2", "S3"})},
+ {AzureEdition.Premium, new KeyValuePair(0, new[] {"P1", "P2", "P4", "P6", "P11", "P15"})},
+ {AzureEdition.PremiumRS, new KeyValuePair(0, new []{"PRS1", "PRS2", "PRS4", "PRS6"})},
+ {AzureEdition.DataWarehouse, new KeyValuePair(3, new[] {"DW100", "DW200", "DW300", "DW400", "DW500", "DW600", "DW1000", "DW1200", "DW1500", "DW2000", "DW3000", "DW6000"})}
+ };
+
+ ///
+ /// Static initializer to read in the registry key values for the Service Objective mappings, which allows the user to override the defaults set for
+ /// the service objective list. We allow them to do this as a temporary measure so that if we change the service objectives in the future we
+ /// can tell people to use the registry key to use the new values until an updated SSMS can be released.
+ ///
+ static AzureSqlDbHelper()
+ {
+ //foreach (AzureEdition edition in Enum.GetValues(typeof (AzureEdition)))
+ //{
+ // object value;
+
+ // try
+ // {
+ // value = Registry.GetValue(
+ // string.Format(CultureInfo.InvariantCulture, @"{0}\{1}", SSMSAzureRegKey,
+ // AzureServiceObjectivesRegSubKey), edition.ToString(), null);
+ // }
+ // catch (Exception e)
+ // {
+ // //We don't really care if we can't read in an override (just fall back to default) so log and move on
+ // TraceContext.TraceVerbose("Exception reading service objective overrides for {0} - {1}", edition, e.Message);
+ // continue;
+ // }
+
+ // if (value != null)
+ // {
+ // TraceContext.TraceVerbose("Found ServiceObjective override for {0}, value is {1}", edition, value);
+ // //Key is in format :
+ // //e.g. 2:S0,S1,S2
+ // //Only split into 2 parts since the service objectives could
+ // //be changed in the future to have :'s, so only treat the first
+ // //as special
+ // string[] values = value.ToString().Split(new[] {':'}, 2);
+ // if (values.Length != 2)
+ // {
+ // //Badly formatted value, ignore this one
+ // TraceContext.TraceVerbose("ServiceObjective override for {0} is badly formatted - skipping", edition);
+ // continue;
+ // }
+
+ // int defaultIndex;
+ // if (!int.TryParse(values[0], out defaultIndex))
+ // {
+ // //Invalid default index, ignore this one
+ // TraceContext.TraceVerbose("ServiceObjective override for {0} has non-parseable default index - skipping", edition);
+ // continue;
+ // }
+
+ // //Service objectives are in a comma-separated list
+ // string[] serviceObjectives = values[1].Split(',');
+ // if (defaultIndex < 0 || defaultIndex >= serviceObjectives.Length)
+ // {
+ // //Index out of bounds, ignore this one
+ // TraceContext.TraceVerbose("ServiceObjective override for {0} has out of bounds default index - skipping");
+ // continue;
+ // }
+ // if (AzureServiceObjectiveInfo.ContainsKey(edition))
+ // {
+ // //Overwrite our default values if the registry key for this edition exists
+ // AzureServiceObjectiveInfo[edition] = new KeyValuePair(defaultIndex,
+ // serviceObjectives);
+ // }
+ // else
+ // {
+ // AzureServiceObjectiveInfo.Add(edition,
+ // new KeyValuePair(defaultIndex, serviceObjectives));
+ // }
+ // }
+ //}
+ }
+
+ ///
+ /// Gets the list of databases sizes applicable for the specified Azure DB edition (if such
+ /// a mapping exists) as well as the index of the default size for that edition.
+ ///
+ /// Outputs an empty array with an index of -1 if no such mapping exists
+ ///
+ ///
+ ///
+ /// TRUE if a mapping exists, FALSE if it does not
+ public static bool TryGetDatabaseSizeInfo(AzureEdition edition, out KeyValuePair databaseSizeInfo)
+ {
+ if (AzureEditionDatabaseSizeMappings.TryGetValue(edition, out databaseSizeInfo))
+ {
+ return true;
+ }
+
+ databaseSizeInfo = new KeyValuePair(-1, new DbSize[0]);
+
+ return false;
+ }
+
+ ///
+ /// Gets a KeyValuePair containing a list of the ServiceObjective names mapped to a particular Azure DB Edition
+ /// (if such a mapping exists) as well as the index of the default Service Objective for that edition.
+ /// Outputs an empty array with a default index of -1 if no such mapping exists.
+ ///
+ ///
+ ///
+ /// TRUE if a mapping exists, FALSE if it did not
+ public static bool TryGetServiceObjectiveInfo(AzureEdition edition,
+ out KeyValuePair serviceObjectiveInfo)
+ {
+ if (AzureServiceObjectiveInfo.TryGetValue(edition, out serviceObjectiveInfo))
+ {
+ return true;
+ }
+
+ serviceObjectiveInfo = new KeyValuePair(-1, new string[0]);
+
+ return false;
+ }
+
+ ///
+ /// Gets the default database size for a specified Azure Edition
+ ///
+ ///
+ /// The default size, or NULL if no default exists
+ public static DbSize GetDatabaseDefaultSize(AzureEdition edition)
+ {
+ DbSize defaultSize = null;
+
+ KeyValuePair pair;
+
+ if (AzureEditionDatabaseSizeMappings.TryGetValue(edition, out pair))
+ {
+ defaultSize = pair.Value[pair.Key];
+ }
+
+ return defaultSize;
+ }
+
+ ///
+ /// Gets the default Service Objective name for a particular Azure DB edition
+ ///
+ ///
+ ///
+ public static string GetDefaultServiceObjective(AzureEdition edition)
+ {
+ string defaultServiceObjective = "";
+
+ KeyValuePair pair;
+
+ if (AzureServiceObjectiveInfo.TryGetValue(edition, out pair))
+ {
+ //Bounds check since this value can be entered by users
+ if (pair.Key >= 0 && pair.Key < pair.Value.Length)
+ {
+ defaultServiceObjective = pair.Value[pair.Key];
+ }
+ }
+
+ return defaultServiceObjective;
+ }
+
+ ///
+ /// Gets the localized Azure Edition display name
+ ///
+ ///
+ ///
+ public static string GetAzureEditionDisplayName(AzureEdition edition)
+ {
+ string result;
+ switch (edition)
+ {
+ //case AzureEdition.Business:
+ // result = SR.BusinessAzureEdition;
+ // break;
+ //case AzureEdition.Web:
+ // result = SR.WebAzureEdition;
+ // break;
+ //case AzureEdition.Basic:
+ // result = SR.BasicAzureEdition;
+ // break;
+ //case AzureEdition.Standard:
+ // result = SR.StandardAzureEdition;
+ // break;
+ //case AzureEdition.Premium:
+ // result = SR.PremiumAzureEdition;
+ // break;
+ //case AzureEdition.DataWarehouse:
+ // result = SR.DataWarehouseAzureEdition;
+ // break;
+ //case AzureEdition.PremiumRS:
+ // result = SR.PremiumRsAzureEdition;
+ // break;
+ default:
+ result = edition.ToString();
+ break;
+ }
+
+ return result;
+ }
+
+ ///
+ /// Parses a display name back into its corresponding AzureEdition.
+ ///
+ ///
+ ///
+ /// TRUE if the conversion succeeded, FALSE if it did not.
+ public static bool TryGetAzureEditionFromDisplayName(string displayName, out AzureEdition edition)
+ {
+ //if (string.Compare(displayName, SR.BusinessAzureEdition, CultureInfo.CurrentUICulture, CompareOptions.None) == 0)
+ //{
+ // edition = AzureEdition.Business;
+ //}
+ //else if (string.Compare(displayName, SR.WebAzureEdition, CultureInfo.CurrentUICulture, CompareOptions.None) == 0)
+ //{
+ // edition = AzureEdition.Web;
+ //}
+ //else if (string.Compare(displayName, SR.BasicAzureEdition, CultureInfo.CurrentUICulture, CompareOptions.None) == 0)
+ //{
+ // edition = AzureEdition.Basic;
+ //}
+ //else if (string.Compare(displayName, SR.StandardAzureEdition, CultureInfo.CurrentUICulture, CompareOptions.None) == 0)
+ //{
+ // edition = AzureEdition.Standard;
+ //}
+ //else if (string.Compare(displayName, SR.PremiumAzureEdition, CultureInfo.CurrentUICulture, CompareOptions.None) == 0)
+ //{
+ // edition = AzureEdition.Premium;
+ //}
+ //else if (string.Compare(displayName, SR.DataWarehouseAzureEdition, CultureInfo.CurrentUICulture, CompareOptions.None) == 0)
+ //{
+ // edition = AzureEdition.DataWarehouse;
+ //}
+ //else if (string.Compare(displayName, SR.PremiumRsAzureEdition, CultureInfo.CurrentUICulture, CompareOptions.None) == 0)
+ //{
+ // edition = AzureEdition.PremiumRS;
+ //}
+ //else
+ {
+ //"Default" edition is standard - but since we're returning false the user shouldn't look at this anyways
+ edition = AzureEdition.Standard;
+ return false;
+ }
+
+ // return true;
+ }
+
+ ///
+ /// Returns a list of AzureEditions that are valid values for the EDITION option
+ /// when creating a database.
+ ///
+ /// We do this so that the AzureEdition enum can have values such as NONE or DEFAULT added
+ /// without requiring clients to explicitly filter out those values themselves each time.
+ ///
+ public static IEnumerable GetValidAzureEditionOptions(ServerVersion version)
+ {
+ //Azure v12 and above doesn't have the Web and Business tiers
+ if (version.Major >= 12)
+ {
+ return new List()
+ {
+ AzureEdition.Basic,
+ AzureEdition.Standard,
+ AzureEdition.Premium,
+ AzureEdition.PremiumRS,
+ AzureEdition.DataWarehouse
+ };
+ }
+
+ //Default for now is to return all values since they're currently all valid
+ return Enum.GetValues(typeof(AzureEdition)).Cast();
+ }
+ }
+}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Admin/Common/CUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/Admin/Common/CUtils.cs
new file mode 100644
index 00000000..88dafa49
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Admin/Common/CUtils.cs
@@ -0,0 +1,717 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using Microsoft.SqlServer.Management.Sdk.Sfc;
+using System;
+using System.Text;
+using System.Xml;
+//using System.Drawing;
+//using System.Windows.Forms;
+using System.Threading;
+using System.IO;
+//using Microsoft.NetEnterpriseServers;
+//using Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer;
+using Microsoft.SqlServer.Management.Common;
+using SMO = Microsoft.SqlServer.Management.Smo;
+using Microsoft.SqlServer.Management.Diagnostics;
+//using Microsoft.SqlServer.Management.SqlMgmt;
+using System.Data.SqlClient;
+// using System.Management;
+using System.Collections;
+
+namespace Microsoft.SqlTools.ServiceLayer.Admin
+{
+ ///
+ /// Summary description for CUtils.
+ ///
+ internal class CUtils
+ {
+
+ private const int ObjectPermissionsDeniedErrorNumber = 229;
+ private const int ColumnPermissionsDeniedErrorNumber = 230;
+
+ public CUtils()
+ {
+ //
+ // TODO: Add constructor logic here
+ //
+ }
+
+
+ //public Bitmap LoadBitmap(string szBitmapName)
+ //{
+ // Bitmap bmp = null;
+ // Stream s = null;
+ // string strQualifiedName;
+
+ // strQualifiedName = typeof(CUtils).Namespace + ".Images." + szBitmapName;
+
+ // s = typeof(CUtils).Assembly.GetManifestResourceStream(strQualifiedName);
+
+ // if (s != null)
+ // {
+ // bmp = new Bitmap(s);
+ // return bmp;
+ // }
+
+ // return null;
+ //}
+
+ //public Icon LoadIcon(string strName)
+ //{
+
+ // Icon ico = null;
+ // Stream s = null;
+ // string strQualifiedName;
+
+ // strQualifiedName = typeof(CUtils).Namespace + ".Images." + strName;
+
+ // s = typeof(CUtils).Assembly.GetManifestResourceStream(strQualifiedName);
+
+ // if (s != null)
+ // {
+ // int iconSize = DpiUtil.GetScaledImageSize();
+ // ico = new Icon(s, iconSize, iconSize);
+ // return ico;
+ // }
+
+ // return null;
+ //}
+
+ //public void LoadAddIcon(ImageList imageList, string strName)
+ //{
+ // Icon ico = null;
+ // Stream s = null;
+ // string strQualifiedName;
+
+ // strQualifiedName = typeof(CUtils).Namespace + ".Images." + strName;
+
+ // s = typeof(CUtils).Module.Assembly.GetManifestResourceStream(strQualifiedName);
+
+ // if (s != null)
+ // {
+ // try
+ // {
+ // ico = new Icon(s, 16, 16);
+ // imageList.Images.Add(ico);
+ // }
+ // finally
+ // {
+ // if (ico != null)
+ // ico.Dispose();
+ // }
+ // }
+ //}
+
+ public static void UseMaster(SMO.Server server)
+ {
+ server.ConnectionContext.ExecuteNonQuery("use master");
+ }
+
+
+ /////
+ ///// returns height of my border (depending on its style)
+ /////
+ //public static int GetBorderHeight(BorderStyle style)
+ //{
+ // if (style == BorderStyle.FixedSingle)
+ // {
+ // return SystemInformation.BorderSize.Height;
+ // }
+ // else if (style == BorderStyle.Fixed3D)
+ // {
+ // return SystemInformation.Border3DSize.Height;
+ // }
+ // else
+ // {
+ // return 0;
+ // }
+ //}
+
+ //public static int GetBorderWidth(BorderStyle style)
+ //{
+ // if (style == BorderStyle.FixedSingle)
+ // {
+ // return SystemInformation.BorderSize.Width;
+ // }
+ // else if (style == BorderStyle.Fixed3D)
+ // {
+ // return SystemInformation.Border3DSize.Width;
+ // }
+ // else
+ // {
+ // return 0;
+ // }
+ //}
+
+ ///
+ /// Get a SMO Server object that is connected to the connection
+ ///
+ /// Conenction info
+ /// Smo Server object for the connection
+ public static Microsoft.SqlServer.Management.Smo.Server GetSmoServer(IManagedConnection mc)
+ {
+ SqlOlapConnectionInfoBase ci = mc.Connection;
+ if (ci == null)
+ {
+ throw new ArgumentNullException("ci");
+ }
+
+ SMO.Server server = null;
+
+ // see what type of connection we have been passed
+ SqlConnectionInfoWithConnection ciWithCon = ci as SqlConnectionInfoWithConnection;
+
+ if (ciWithCon != null)
+ {
+ server = new SMO.Server(ciWithCon.ServerConnection);
+ }
+ else
+ {
+ SqlConnectionInfo sqlCi = ci as SqlConnectionInfo;
+ if (sqlCi != null)
+ {
+ server = new SMO.Server(new ServerConnection(sqlCi));
+ }
+ }
+
+ if (server == null)
+ {
+ throw new InvalidOperationException();
+ }
+ return server;
+
+ }
+
+
+ public static int GetServerVersion(SMO.Server server)
+ {
+ return server.Information.Version.Major;
+ }
+
+ ///
+ /// validates current value of given numeric control. Shows message if the value is not valid
+ ///
+ ///
+ ///
+ /// true if control's value is valid, false otherwise
+ //public static bool ValidateNumeric(NumericUpDown numControl, string errMessageToShow, bool displayException)
+ //{
+ // try
+ // {
+ // int curValue = int.Parse(numControl.Text, System.Globalization.CultureInfo.CurrentCulture);
+ // if (curValue < numControl.Minimum || curValue > numControl.Maximum)
+ // {
+ // if (true == displayException)
+ // {
+ // ExceptionMessageBox box = new ExceptionMessageBox();
+
+ // box.Caption = SRError.SQLWorkbench;
+ // box.Message = new Exception(errMessageToShow);
+ // box.Symbol = ExceptionMessageBoxSymbol.Error;
+ // box.Buttons = ExceptionMessageBoxButtons.OK;
+ // box.Options = ExceptionMessageBoxOptions.RightAlign;
+ // box.Show(null);
+ // }
+
+ // try
+ // {
+ // numControl.Value = Convert.ToDecimal(numControl.Tag, System.Globalization.CultureInfo.CurrentCulture);
+ // numControl.Update();
+ // numControl.Text = Convert.ToString(numControl.Value, System.Globalization.CultureInfo.CurrentCulture);
+ // numControl.Refresh();
+
+ // }
+ // catch
+ // {
+
+ // }
+ // numControl.Focus();
+ // return false;
+ // }
+
+ // return true;
+ // }
+ // catch
+ // {
+ // if (true == displayException)
+ // {
+ // ExceptionMessageBox box = new ExceptionMessageBox();
+
+ // box.Caption = SRError.SQLWorkbench;
+ // box.Message = new Exception(errMessageToShow);
+ // box.Symbol = ExceptionMessageBoxSymbol.Error;
+ // box.Buttons = ExceptionMessageBoxButtons.OK;
+ // box.Options = ExceptionMessageBoxOptions.RightAlign;
+ // box.Show(null);
+ // }
+
+ // numControl.Focus();
+ // return false;
+ // }
+ //}
+
+ ///
+ /// Determines the oldest date based on the type of time units and the number of time units
+ ///
+ ///
+ ///
+ ///
+ public static DateTime GetOldestDate(int numUnits, TimeUnitType typeUnits)
+ {
+ DateTime result = DateTime.Now;
+
+ switch (typeUnits)
+ {
+ case TimeUnitType.Week:
+ {
+ result = (DateTime.Now).AddDays(-1 * 7 * numUnits);
+ break;
+ }
+ case TimeUnitType.Month:
+ {
+ result = (DateTime.Now).AddMonths(-1 * numUnits);
+ break;
+ }
+ case TimeUnitType.Year:
+ {
+ result = (DateTime.Now).AddYears(-1 * numUnits);
+ break;
+ }
+ default:
+ {
+ result = (DateTime.Now).AddDays(-1 * numUnits);
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ public static string TokenizeXml(string s)
+ {
+ if (null == s) return String.Empty;
+
+ System.Text.StringBuilder sb = new System.Text.StringBuilder();
+ foreach (char c in s)
+ {
+ switch (c)
+ {
+ case '<':
+ sb.Append("<");
+ break;
+ case '>':
+ sb.Append(">");
+ break;
+ case '&':
+ sb.Append("&");
+ break;
+ default:
+ sb.Append(c);
+ break;
+ }
+ }
+ return sb.ToString();
+ }
+
+ ///
+ /// Tries to get the SqlException out of an Enumerator exception
+ ///
+ ///
+ ///
+ public static SqlException GetSqlException(Exception e)
+ {
+ SqlException sqlEx = null;
+ Exception exception = e;
+ while (exception != null)
+ {
+ sqlEx = exception as SqlException;
+ if (null != sqlEx)
+ {
+ break;
+ }
+ exception = exception.InnerException;
+ }
+ return sqlEx;
+ }
+
+ ///
+ /// computes the name of the machine based on server's name (as returned by smoServer.Name)
+ ///
+ /// name of server ("",".","Server","Server\Instance",etc)
+ /// name of the machine hosting sql server instance
+ public static string GetMachineName(string sqlServerName)
+ {
+ System.Diagnostics.Debug.Assert(sqlServerName != null);
+
+ string machineName = sqlServerName;
+ if (sqlServerName.Trim().Length != 0)
+ {
+ // [0] = machine, [1] = instance (if any)
+ return sqlServerName.Split('\\')[0];
+ }
+ else
+ {
+ // we have default instance of default machine
+ return machineName;
+ }
+ }
+
+ ///
+ /// Determines if a SqlException is Permission denied exception
+ ///
+ ///
+ ///
+ public static bool IsPermissionDeniedException(SqlException sqlException)
+ {
+ bool isPermDenied = false;
+ if (null != sqlException.Errors)
+ {
+ foreach (SqlError sqlError in sqlException.Errors)
+ {
+ int errorNumber = GetSqlErrorNumber(sqlError);
+
+ if ((ObjectPermissionsDeniedErrorNumber == errorNumber) ||
+ (ColumnPermissionsDeniedErrorNumber == errorNumber))
+ {
+ isPermDenied = true;
+ break;
+ }
+ }
+ }
+ return isPermDenied;
+ }
+
+ ///
+ /// Returns the error number of a sql exeception
+ ///
+ ///
+ ///
+ public static int GetSqlErrorNumber(SqlError sqlerror)
+ {
+ return sqlerror.Number;
+ }
+
+ ///
+ /// Function doubles up specified character in a string
+ ///
+ ///
+ ///
+ ///
+ public static String EscapeString(string s, char cEsc)
+ {
+ StringBuilder sb = new StringBuilder(s.Length * 2);
+ foreach (char c in s)
+ {
+ sb.Append(c);
+ if (cEsc == c)
+ sb.Append(c);
+ }
+ return sb.ToString();
+ }
+
+ ///
+ /// Function doubles up ']' character in a string
+ ///
+ ///
+ ///
+ public static String EscapeStringCBracket(string s)
+ {
+ return CUtils.EscapeString(s, ']');
+ }
+
+ ///
+ /// Function doubles up '\'' character in a string
+ ///
+ ///
+ ///
+ public static String EscapeStringSQuote(string s)
+ {
+ return CUtils.EscapeString(s, '\'');
+ }
+
+ ///
+ /// Function removes doubled up specified character from a string
+ ///
+ ///
+ ///
+ ///
+ public static String UnEscapeString(string s, char cEsc)
+ {
+ StringBuilder sb = new StringBuilder(s.Length);
+ bool foundBefore = false;
+ foreach (char c in s)
+ {
+ if (cEsc == c) // character to unescape
+ {
+ if (foundBefore) // skip second occurrence
+ {
+ foundBefore = false;
+ }
+ else // set the flag to skip next time around
+ {
+ sb.Append(c);
+ foundBefore = true;
+ }
+ }
+ else
+ {
+ sb.Append(c);
+ foundBefore = false;
+ }
+ }
+ return sb.ToString();
+ }
+
+ ///
+ /// Function removes doubled up ']' character from a string
+ ///
+ ///
+ ///
+ public static String UnEscapeStringCBracket(string s)
+ {
+ return CUtils.UnEscapeString(s, ']');
+ }
+
+ ///
+ /// Function removes doubled up '\'' character from a string
+ ///
+ ///
+ ///
+ public static String UnEscapeStringSQuote(string s)
+ {
+ return CUtils.UnEscapeString(s, '\'');
+ }
+
+ ///
+ /// Helper method to convert DMTF format to DateTime from WMI property value
+ /// ManagementDateTimeConverter.ToDateTime() does not adjust time to UTC offset,
+ /// hence additional step to adjust datetime.
+ ///
+ ///
+ ///
+ //public static DateTime GetDateTimeFromDMTFTime(string dateTimeInDMTFFormat)
+ //{
+ // string[] dateTimeInfo = dateTimeInDMTFFormat.Split(new char[] { '+', '-' });
+ // DateTime dateTime = ManagementDateTimeConverter.ToDateTime(dateTimeInDMTFFormat);
+
+ // TimeSpan timeSpan = TimeSpan.FromMinutes(Convert.ToDouble(dateTimeInfo[1]));
+ // if (dateTimeInDMTFFormat.Contains("+"))
+ // {
+ // dateTime = dateTime - timeSpan;
+ // }
+ // else
+ // {
+ // dateTime = dateTime + timeSpan;
+ // }
+ // return dateTime;
+ //}
+
+ ///
+ /// Helper method to sort ManagementObjectCollection based ArchiveNumber property
+ ///
+ ///
+ ///
+ //public static ArrayList Sort(ManagementObjectCollection collection)
+ //{
+
+ // ArrayList array = new ArrayList();
+ // array.AddRange(collection);
+ // ArchiveNoComparer comparer = new ArchiveNoComparer();
+ // array.Sort(comparer);
+ // return array;
+ //}
+
+ ///
+ /// Helper function to execute WQL
+ ///
+ ///
+ ///
+ ///
+ //public static ManagementObjectCollection ExecuteWQL(WmiSqlMgmtConnectionInfo wmiCi, string wql)
+ //{
+ // ObjectQuery qry = new ObjectQuery(wql);
+ // ManagementScope scope = new ManagementScope(wmiCi.Namespace, wmiCi.ConnectionOptions);
+ // scope.Connect();
+ // ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, qry);
+ // return searcher.Get();
+ //}
+
+ ///
+ /// Get the windows login name with the domain portion in all-caps
+ ///
+ /// The windows login name
+ /// The windows login name with the domain portion in all-caps
+ public static string CanonicalizeWindowsLoginName(string windowsLoginName)
+ {
+ string result;
+ int lastBackslashIndex = windowsLoginName.LastIndexOf("\\", StringComparison.Ordinal);
+
+ if (-1 != lastBackslashIndex)
+ {
+ string domainName = windowsLoginName.Substring(0, lastBackslashIndex).ToUpperInvariant();
+ string afterDomain = windowsLoginName.Substring(lastBackslashIndex);
+
+ result = String.Concat(domainName, afterDomain);
+ }
+ else
+ {
+ result = windowsLoginName;
+ }
+
+ return result;
+
+ }
+
+ ///
+ /// Launches object picker and gets the user selected login
+ ///
+ ///
+ ///
+ ///
+ /// Returns null in case Object picker doesn't returns any loginName
+ //public static string GetWindowsLoginNameFromObjectPicker(object sender,
+ // Smo.Server server,
+ // string errorMsgToShowForTooManyLogins)
+ //{
+ // string loginName = null;
+
+ // ObjectPickerWrapper.TargetMachine = server.Information.NetName;
+ // ObjectPickerWrapper.SingleObjectSelection = true;
+
+ // ObjectPickerWrapper.GetUsersList(sender);
+
+ // int userCount = ObjectPickerWrapper.UsersList.Count;
+
+ // // if the user selected one NT login, set the edit control text to the selected login
+ // if (1 == userCount)
+ // {
+ // loginName = ObjectPickerWrapper.UsersList[0].ToString();
+
+ // if (loginName.Length != 0)
+ // {
+ // loginName = CanonicalizeWindowsLoginName(loginName);
+ // }
+ // }
+ // // if the user selected more than one login, display an error
+ // else if (1 < userCount)
+ // {
+ // SqlManagementUserControl sm = sender as SqlManagementUserControl;
+ // if (sm != null)
+ // {
+ // sm.DisplayExceptionMessage(new Exception(errorMsgToShowForTooManyLogins));
+ // }
+ // else
+ // {
+ // throw new InvalidOperationException(errorMsgToShowForTooManyLogins);
+ // }
+ // }
+
+ // return loginName;
+ //}
+
+ ///
+ /// Determines how a feature should behave (e.g. enabled or disabled) for a SQL instance's SKU/edition.
+ ///
+ /// A SMO Server object connected to a local or remote SQL instance
+ /// The setting to check (one of the feature constants used in settings.dat)
+ /// The value of the setting (e.g. SqlbootConst.SKU_YES, SqlbootConst.VALUE_UNLIMITED, etc)
+ //public static uint QueryRemoteSqlProductValue(ServerConnection serverConnection, uint setting)
+ //{
+ // if (serverConnection == null)
+ // {
+ // throw new ArgumentNullException("serverConnection");
+ // }
+
+ // // The instance could be remote, so we use GetSettingValueForSKUAbsolute because it allows us to
+ // // query the client-side SQLBOOT.DLL to ask what the setting's value would be for the server's SKU.
+ // // (Most other SQLBOOT APIs can only be used for locally-installed instances.)
+ // // First we must retrieve the server's edition ID (SKU ID).
+ // int editionId = (int)serverConnection.ExecuteScalar("SELECT SERVERPROPERTY('EditionId') AS EditionId");
+
+ // // Then ask SQLBOOT what the setting's value should be for that SKU.
+ // uint value = Sqlboot.GetSettingValueForSKUAbsolute(setting, unchecked((uint)editionId));
+ // return value;
+ //}
+ }
+
+ ///
+ /// Enum of time units types ( used in cleaning up history based on age )
+ ///
+ internal enum TimeUnitType
+ {
+ Day,
+ Week,
+ Month,
+ Year
+ }
+
+ ///
+ /// class to sort files based on archivenumber
+ ///
+ //internal class ArchiveNoComparer : IComparer
+ //{
+ // public int Compare(Object x, Object y)
+ // {
+ // ManagementObject lhs = x as ManagementObject;
+ // ManagementObject rhs = y as ManagementObject;
+
+ // if (null == lhs || null == rhs)
+ // {
+ // throw new ArgumentException("Object is not of type ManagementObject");
+ // }
+
+ // UInt32 l = Convert.ToUInt32(lhs.Properties["archivenumber"].Value);
+ // UInt32 r = Convert.ToUInt32(rhs.Properties["archivenumber"].Value);
+
+ // int retVal = l.CompareTo(r);
+
+ // return retVal;
+ // }
+ //}
+
+ ///
+ /// Object used to populate default language in
+ /// database and user dialogs.
+ ///
+ internal class LanguageDisplay
+ {
+ private SMO.Language language;
+
+ public string LanguageAlias
+ {
+ get
+ {
+ return language.Alias;
+ }
+ }
+
+ public SMO.Language Language
+ {
+ get
+ {
+ return language;
+ }
+ }
+
+ public LanguageDisplay(SMO.Language language)
+ {
+ this.language = language;
+ }
+
+ public override string ToString()
+ {
+ return language.Alias;
+ }
+ }
+}
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Admin/Common/CreateDatabaseData.cs b/src/Microsoft.SqlTools.ServiceLayer/Admin/Common/CreateDatabaseData.cs
new file mode 100644
index 00000000..384f6b30
--- /dev/null
+++ b/src/Microsoft.SqlTools.ServiceLayer/Admin/Common/CreateDatabaseData.cs
@@ -0,0 +1,2733 @@
+//
+// 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;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Resources;
+using System.Data;
+using System.IO;
+using System.Text;
+//using System.Windows.Forms;
+//using System.Drawing.Design;
+using Microsoft.SqlServer.Management.Common;
+// using Microsoft.SqlServer.Management.SqlMgmt;
+using Microsoft.SqlServer.Management.Smo;
+using Smo = Microsoft.SqlServer.Management.Smo;
+using Microsoft.SqlServer.Management.Sdk.Sfc;
+using Microsoft.SqlServer.Management.Diagnostics;
+//using Microsoft.NetEnterpriseServers;
+using System.Globalization;
+using System.Data.SqlClient;
+using System.Collections.Generic;
+
+// using DisplayNameAttribute = Microsoft.SqlServer.Management.SqlMgmt.DisplayNameAttribute;
+using AzureEdition = Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper.AzureEdition;
+using DataSet = Microsoft.Data.Tools.DataSets.DataSet;
+using DataTable = Microsoft.Data.Tools.DataSets.DataTable;
+
+namespace Microsoft.SqlTools.ServiceLayer.Admin
+{
+ public enum DefaultCursor
+ {
+ Local,
+ Global
+ }
+
+ public static class CDataContainerExtender
+ {
+ ///
+ /// Check if Query Store is supported.
+ ///
+ /// The data container.
+ /// The database.
+ /// True, if the Query Store feature is supported.
+ internal static bool IsQueryStoreSupported(this CDataContainer dataContainer, Smo.Database database)
+ {
+ // Query store is not supported on SQL DW.
+ // Query store is only supported on SQL 2016 and above and Azure V12 and above.
+ return (database.DatabaseEngineEdition != DatabaseEngineEdition.SqlDataWarehouse &&
+ ((dataContainer.SqlServerVersion >= 13) ||
+ (dataContainer.SqlServerVersion >= 12 &&
+ dataContainer.Server.ServerType == DatabaseEngineType.SqlAzureDatabase)));
+ }
+ }
+
+ ///
+ /// FileGroup Prototype
+ ///
+ public class FilegroupPrototype
+ {
+ #region data members
+
+ private class FilegroupData
+ {
+ public string name;
+ public bool isReadOnly;
+ public bool isDefault;
+ public FileGroupType fileGroupType = FileGroupType.RowsFileGroup;
+
+ ///
+ /// Creates an instance of FilegroupData
+ ///
+ public FilegroupData()
+ {
+ this.name = String.Empty;
+ this.isReadOnly = false;
+ this.isDefault = false;
+ }
+
+ ///
+ /// Creates an instance of FilegroupData
+ ///
+ public FilegroupData(FileGroupType fileGroupType)
+ {
+ this.name = String.Empty;
+ this.isReadOnly = false;
+ this.isDefault = false;
+ this.fileGroupType = fileGroupType;
+ }
+
+ ///
+ /// Initializes a new instance of the FilegroupData class.
+ ///
+ /// filegroup name
+ /// Readonly or not
+ /// Default filegroup or not
+ /// FileGroupType
+ public FilegroupData(string name, bool isReadOnly, bool isDefault, FileGroupType fileGroupType)
+ {
+ this.name = name;
+ this.isReadOnly = isReadOnly;
+ this.isDefault = isDefault;
+ this.fileGroupType = fileGroupType;
+ }
+
+ ///
+ /// Creates an instance of FilegroupData from another instance
+ ///
+ ///
+ public FilegroupData(FilegroupData other)
+ {
+ this.name = other.name;
+ this.isReadOnly = other.isReadOnly;
+ this.isDefault = other.isDefault;
+ this.fileGroupType = other.fileGroupType;
+ }
+
+ ///
+ /// Clones the instance oc FileGroupData
+ ///
+ ///
+ public FilegroupData Clone()
+ {
+ return new FilegroupData(this);
+ }
+ }
+
+ private FilegroupData originalState;
+ private FilegroupData currentState;
+ private bool filegroupExists;
+ private bool removed;
+ private DatabasePrototype parent;
+
+ #endregion
+
+ #region properties
+
+ ///
+ /// The name of the filegroup
+ ///
+ public string Name
+ {
+ get { return this.currentState.name; }
+
+ set
+ {
+ if (!this.Exists)
+ {
+ string oldname = this.currentState.name;
+ this.currentState.name = value;
+
+ this.NotifyFileGroupNameChanged(oldname, this.currentState.name);
+ this.parent.NotifyObservers();
+ }
+ }
+ }
+
+ ///
+ /// Whether the filegroup is read-only
+ ///
+ public bool IsReadOnly
+ {
+ get { return this.currentState.isReadOnly; }
+
+ set
+ {
+ this.currentState.isReadOnly = value;
+ this.parent.NotifyObservers();
+ }
+ }
+
+ ///
+ /// Whether the filegroup is the default filegroup
+ ///
+ public bool IsDefault
+ {
+ get { return this.currentState.isDefault; }
+
+ set
+ {
+ if (this.currentState.isDefault != value)
+ {
+ this.currentState.isDefault = value;
+ NotifyFileGroupDefaultChanged(!value, value);
+ this.parent.NotifyObservers();
+ }
+ }
+ }
+
+ ///
+ /// Whether the filegroup is of filestream type
+ ///
+ public bool IsFileStream
+ {
+ get { return (this.currentState.fileGroupType == Smo.FileGroupType.FileStreamDataFileGroup); }
+ }
+
+ ///
+ /// Whether the filegroup is of memory Optimized type
+ ///
+ public bool IsMemoryOptimized
+ {
+ get { return (this.currentState.fileGroupType == Smo.FileGroupType.MemoryOptimizedDataFileGroup); }
+ }
+
+ ///
+ /// FileGroupType
+ ///
+ public FileGroupType FileGroupType
+ {
+ get { return this.currentState.fileGroupType; }
+
+ set
+ {
+ this.currentState.fileGroupType = value;
+ this.parent.NotifyObservers();
+ }
+ }
+
+ ///
+ /// Whether the file group exists on the server
+ ///
+ public bool Exists
+ {
+ get { return this.filegroupExists; }
+
+ set { this.filegroupExists = value; }
+ }
+
+ ///
+ /// Whether the filegroup was removed
+ ///
+ public bool Removed
+ {
+ get { return this.removed; }
+
+ set
+ {
+ this.removed = value;
+ this.parent.NotifyObservers();
+ }
+ }
+
+ #endregion
+
+ ///
+ /// File group name changed event
+ ///
+ public event FileGroupNameChangedEventHandler OnFileGroupNameChangedHandler;
+
+ ///
+ /// File group default status changed event
+ ///
+ public event FileGroupDefaultChangedEventHandler OnFileGroupDefaultChangedHandler;
+
+ ///
+ /// File group deleted event
+ ///
+ public event FileGroupDeletedEventHandler OnFileGroupDeletedHandler;
+
+ ///
+ /// Constructor
+ ///
+ public FilegroupPrototype(DatabasePrototype parent)
+ {
+ this.originalState = new FilegroupData();
+ this.currentState = this.originalState.Clone();
+ this.parent = parent;
+
+ this.filegroupExists = false;
+ this.removed = false;
+ }
+
+ ///
+ /// Creates an instance of FilegroupPrototype
+ ///
+ ///
+ ///
+ public FilegroupPrototype(DatabasePrototype parent, FileGroupType filegroupType)
+ {
+ this.originalState = new FilegroupData(filegroupType);
+ this.currentState = this.originalState.Clone();
+ this.parent = parent;
+
+ this.filegroupExists = false;
+ this.removed = false;
+ }
+
+ ///
+ /// Initializes a new instance of the FilegroupPrototype class.
+ ///
+ /// instance of DatabasePrototype
+ /// file group name
+ /// whether it is readonly or not
+ /// is default or not
+ /// filegrouptype
+ /// filegroup exists or not
+ public FilegroupPrototype(DatabasePrototype parent, string name, bool isReadOnly, bool isDefault,
+ FileGroupType filegroupType, bool exists)
+ {
+ this.originalState = new FilegroupData(name, isReadOnly, isDefault, filegroupType);
+ this.currentState = this.originalState.Clone();
+ this.parent = parent;
+
+ this.filegroupExists = exists;
+ this.removed = false;
+ }
+
+ ///
+ /// Create, Alter, or Drop the filegroup on the server
+ ///
+ public void ApplyChanges(Database db)
+ {
+ if (this.ChangesExist())
+ {
+ if (this.Removed)
+ {
+ if (this.Exists)
+ {
+ db.FileGroups[this.Name].Drop();
+ }
+ }
+ else
+ {
+ FileGroup fg = null;
+ bool filegroupChanged = false;
+
+ if (this.Exists)
+ {
+ fg = db.FileGroups[this.Name];
+ }
+ else
+ {
+ fg = new FileGroup(db, this.Name, this.FileGroupType);
+ db.FileGroups.Add(fg);
+ }
+
+ if (!this.Exists || (fg.ReadOnly != this.IsReadOnly))
+ {
+ fg.ReadOnly = this.IsReadOnly;
+ filegroupChanged = true;
+ }
+
+ if (this.Exists && filegroupChanged)
+ {
+ fg.Alter();
+ }
+ }
+ }
+ }
+
+ ///
+ /// Would applying changes do anything?
+ ///
+ /// True if changes exist, false otherwise
+ public bool ChangesExist()
+ {
+ // name changes can only happen for non-existent filegroups, so no need to check for name changes
+
+ bool result = (
+ !this.Exists ||
+ this.Removed ||
+ (this.originalState.isDefault != this.currentState.isDefault) ||
+ (this.originalState.isReadOnly != this.currentState.isReadOnly));
+
+ return result;
+ }
+
+ ///
+ /// Notify listeners that this filegroup has been deleted
+ ///
+ ///
+ public void NotifyFileGroupDeleted(FilegroupPrototype defaultFilegroup)
+ {
+ this.Removed = true;
+
+ if (OnFileGroupDeletedHandler != null)
+ {
+ FilegroupDeletedEventArgs e = new FilegroupDeletedEventArgs(this, defaultFilegroup);
+ OnFileGroupDeletedHandler(this, e);
+ }
+ }
+
+ ///
+ /// Notify observers that the file group name has changed
+ ///
+ /// The file group name before the change
+ /// The file group name after the change
+ private void NotifyFileGroupNameChanged(string oldName, string newName)
+ {
+ if (OnFileGroupNameChangedHandler != null)
+ {
+ NameChangedEventArgs e = new NameChangedEventArgs(oldName, newName);
+ OnFileGroupNameChangedHandler(this, e);
+ }
+ }
+
+ ///
+ /// Notify observers that the file group's default status has changed
+ ///
+ /// The old default-ness
+ /// THe new default-ness
+ private void NotifyFileGroupDefaultChanged(bool oldValue, bool newValue)
+ {
+ if (OnFileGroupDefaultChangedHandler != null)
+ {
+ BooleanValueChangedEventArgs e = new BooleanValueChangedEventArgs(oldValue, newValue);
+ OnFileGroupDefaultChangedHandler(this, e);
+ }
+ }
+ }
+
+
+ ///
+ /// File type - Data or Log
+ ///
+ public enum FileType
+ {
+ Data,
+ Log,
+ FileStream
+ }
+
+ ///
+ /// File auto-growth data
+ ///
+ public class Autogrowth
+ {
+ #region data members
+
+ private int growthInPercent;
+ private double growthInKilobytes;
+ private double maximumFileSize;
+ private bool isEnabled;
+ private bool isGrowthInPercent;
+ private bool isGrowthRestricted;
+
+ private DatabasePrototype parent;
+
+ #endregion
+
+ #region properties
+
+ ///
+ /// Whether auto-growth is enabled
+ ///
+ public bool IsEnabled
+ {
+ get { return this.isEnabled; }
+
+ set { this.isEnabled = value; }
+ }
+
+ ///
+ /// Whether auto-growth is in percent
+ ///
+ ///
+ /// true means growth is in percent, false means growth is in megabytes
+ ///
+ public bool IsGrowthInPercent
+ {
+ get { return this.isGrowthInPercent; }
+
+ set { this.isGrowthInPercent = value; }
+ }
+
+ ///
+ /// How much the file grows when it grows, in percent
+ ///
+ public int GrowthInPercent
+ {
+ get { return this.growthInPercent; }
+
+ set { this.growthInPercent = value; }
+ }
+
+ ///
+ /// How much the file grows when it grows in kilobytes
+ ///
+ public double GrowthInKilobytes
+ {
+ get { return this.growthInKilobytes; }
+
+ set { this.growthInKilobytes = value; }
+ }
+
+ ///
+ /// How much the file grows when it grows in kilobytes
+ ///
+ public int GrowthInMegabytes
+ {
+ get { return DatabaseFilePrototype.KilobytesToMegabytes(this.growthInKilobytes); }
+
+ set { this.growthInKilobytes = DatabaseFilePrototype.MegabytesToKilobytes(value); }
+ }
+
+
+ ///
+ /// Whether file growth is restricted
+ ///
+ public bool IsGrowthRestricted
+ {
+ get { return this.isGrowthRestricted; }
+
+ set { this.isGrowthRestricted = value; }
+ }
+
+ ///
+ /// The maximum size of the file in megabytes
+ ///
+ public int MaximumFileSizeInMegabytes
+ {
+ get { return DatabaseFilePrototype.KilobytesToMegabytes(this.maximumFileSize); }
+
+ set { this.maximumFileSize = DatabaseFilePrototype.MegabytesToKilobytes(value); }
+ }
+
+ ///
+ /// The maximum size of the file in megabytes
+ ///
+ public double MaximumFileSizeInKilobytes
+ {
+ get { return this.maximumFileSize; }
+
+ set { this.maximumFileSize = value; }
+ }
+
+
+ #endregion
+
+ ///
+ /// Constructor
+ ///
+ public Autogrowth(DatabasePrototype parent)
+ {
+ Reset();
+ this.parent = parent;
+ }
+
+ ///
+ /// Copy constructor
+ ///
+ /// the instance to copy
+ public Autogrowth(Autogrowth other)
+ {
+ this.growthInKilobytes = other.growthInKilobytes;
+ this.growthInPercent = other.growthInPercent;
+ this.maximumFileSize = other.maximumFileSize;
+ this.isEnabled = other.isEnabled;
+ this.isGrowthInPercent = other.isGrowthInPercent;
+ this.isGrowthRestricted = other.isGrowthRestricted;
+ this.parent = other.parent;
+ }
+
+ ///
+ /// Constructor - extracts autogrowth information from a SMO DataFile object
+ ///
+ ///
+ /// The file whose autogrowth information is to be extracted
+ public Autogrowth(DatabasePrototype parent, DataFile file)
+ {
+ // this code looks stunningly similar to the code in Autogrowth(LogFile),
+ // but we can't use polymorphism to handle this because LogFile and DataFile
+ // have no common base class or shared interface.
+
+ if (FileGrowthType.None == file.GrowthType)
+ {
+ this.isEnabled = false;
+ this.isGrowthInPercent = true;
+ this.growthInPercent = 10;
+ this.growthInKilobytes = 10240.0;
+ this.isGrowthRestricted = false;
+ this.maximumFileSize = 102400.0;
+ }
+ else
+ {
+ this.isEnabled = true;
+
+ if (FileGrowthType.Percent == file.GrowthType)
+ {
+ this.isGrowthInPercent = true;
+ this.growthInPercent = (int) file.Growth;
+ this.growthInKilobytes = 10240.0;
+
+ // paranoia - make sure percent amount is greater than 1
+ if (this.growthInPercent < 1)
+ {
+ this.growthInPercent = 1;
+ }
+ }
+ else
+ {
+ this.isGrowthInPercent = false;
+ this.growthInKilobytes = file.Growth;
+ this.growthInPercent = 10;
+ }
+
+ // note: double-precision math comparisons - can't do != or ==
+ if (1e-16 < file.MaxSize)
+ {
+ // max file size is greater than zero
+ this.isGrowthRestricted = true;
+ this.maximumFileSize = file.MaxSize;
+ }
+ else
+ {
+ this.isGrowthRestricted = false;
+ this.maximumFileSize = 102400.0;
+ }
+ }
+
+ this.parent = parent;
+ }
+
+ ///
+ /// Constructor - extracts autogrowth information from a SMO LogFile object
+ ///
+ ///
+ /// The file whose autogrowth information is to be extracted
+ public Autogrowth(DatabasePrototype parent, LogFile file)
+ {
+ // this code looks stunningly similar to the code in Autogrowth(DataFile),
+ // but we can't use polymorphism to handle this because LogFile and DataFile
+ // have no common base class or shared interface.
+
+ FileGrowthType fileGrowthType = FileGrowthType.None;
+
+ try
+ {
+ fileGrowthType = file.GrowthType;
+
+ }
+ catch (Exception)
+ {
+ /// do nothing
+ }
+
+ if (FileGrowthType.None == fileGrowthType)
+ {
+ this.isEnabled = false;
+ this.isGrowthInPercent = true;
+ this.growthInPercent = 10;
+ this.growthInKilobytes = 10240.0;
+ this.isGrowthRestricted = false;
+ this.maximumFileSize = 102400.0;
+ }
+ else
+ {
+ this.isEnabled = true;
+
+ if (FileGrowthType.Percent == fileGrowthType)
+ {
+ this.isGrowthInPercent = true;
+ this.growthInPercent = (int) file.Growth;
+ this.growthInKilobytes = 10240.0;
+
+ // paranoia - make sure percent amount is greater than 1
+ if (this.growthInPercent < 1)
+ {
+ this.growthInPercent = 1;
+ }
+ }
+ else
+ {
+ this.isGrowthInPercent = false;
+ this.growthInKilobytes = file.Growth;
+ this.growthInPercent = 10;
+ }
+
+ // note: double-precision math comparisons - can't do != or ==
+ if (1e-16 < file.MaxSize)
+ {
+ // max file size is greater than zero
+ this.isGrowthRestricted = true;
+ this.maximumFileSize = file.MaxSize;
+ }
+ else
+ {
+ this.isGrowthRestricted = false;
+ this.maximumFileSize = 102400.0;
+ }
+ }
+
+ this.parent = parent;
+
+ }
+
+ ///
+ /// Reset the property values to their defaults
+ ///
+ public void Reset()
+ {
+ this.IsEnabled = true;
+ this.IsGrowthInPercent = true;
+ this.IsGrowthRestricted = false;
+
+ this.GrowthInPercent = 10;
+ this.GrowthInKilobytes = 10240.0;
+ this.MaximumFileSizeInKilobytes = 102400.0;
+ }
+
+
+ ///
+ /// Determine whether this Autogrowth has the same value as another Autogrowth
+ ///
+ /// The Autogrowth to compare with
+ /// True if values are the same, false otherwise
+ public bool HasSameValueAs(Autogrowth other)
+ {
+ bool result = true;
+
+ if (this.isEnabled != other.isEnabled)
+ {
+ result = false;
+ }
+ else if (this.isEnabled)
+ {
+ if ((this.isGrowthInPercent != other.isGrowthInPercent) ||
+ (this.isGrowthRestricted != other.isGrowthRestricted) ||
+ (this.isGrowthInPercent && (this.growthInPercent != other.growthInPercent)) ||
+ (!this.isGrowthInPercent && (this.growthInKilobytes != other.growthInKilobytes)) ||
+ (this.isGrowthRestricted && (this.maximumFileSize != other.maximumFileSize)))
+ {
+ result = false;
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Represent the auto-growth settings as a single string
+ ///
+ ///
+ /// The format is such that the result can be put into the Autogrowth column
+ /// of the grid on the CreateDatabaseGeneral form.
+ ///
+ /// The string representation
+ public override string ToString()
+ {
+ ResourceManager manager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ this.GetType().GetAssembly());
+ string result = "";
+
+ if (this.IsEnabled)
+ {
+ if (this.IsGrowthRestricted)
+ {
+ if (this.IsGrowthInPercent)
+ {
+ result = String.Format(System.Globalization.CultureInfo.CurrentCulture,
+ manager.GetString("prototype.autogrowth.restrictedGrowthByPercent"),
+ this.GrowthInPercent,
+ this.MaximumFileSizeInMegabytes);
+ }
+ else
+ {
+ result = String.Format(System.Globalization.CultureInfo.CurrentCulture,
+ manager.GetString("prototype.autogrowth.restrictedGrowthByMB"),
+ this.GrowthInMegabytes,
+ this.MaximumFileSizeInMegabytes);
+ }
+ }
+ else
+ {
+ if (this.IsGrowthInPercent)
+ {
+ result = String.Format(System.Globalization.CultureInfo.CurrentCulture,
+ manager.GetString("prototype.autogrowth.unrestrictedGrowthByPercent"),
+ this.GrowthInPercent);
+ }
+ else
+ {
+ result = String.Format(System.Globalization.CultureInfo.CurrentCulture,
+ manager.GetString("prototype.autogrowth.unrestrictedGrowthByMB"),
+ this.GrowthInMegabytes);
+ }
+
+
+ }
+
+
+ }
+ else
+ {
+ result = manager.GetString("prototype.autogrowth.disabled");
+ }
+
+ return result;
+ }
+ }
+
+
+ ///
+ /// Prototype database file
+ ///
+ public class DatabaseFilePrototype
+ {
+ #region data members
+
+ private class FileData
+ {
+ public string name;
+ public string physicalName;
+ public string folder;
+ public FileType fileType;
+ public FilegroupPrototype filegroup;
+ public double initialSize;
+ public Autogrowth autogrowth;
+ public bool isPrimaryFile;
+
+ ///
+ /// Creates instance of FileData
+ ///
+ ///
+ ///
+ public FileData(DatabasePrototype parent, FileType type)
+ {
+ this.name = String.Empty;
+ this.physicalName = String.Empty;
+ this.folder = String.Empty;
+ this.fileType = type;
+ this.filegroup = null;
+ this.initialSize = 1024.0d;
+ this.autogrowth = new Autogrowth(parent);
+ this.isPrimaryFile = false;
+ }
+
+ ///
+ /// Creates instaance of FileData
+ ///
+ ///
+ ///
+ ///
+ public FileData(DatabasePrototype parent, FilegroupPrototype filegroup, DataFile file)
+ {
+ this.autogrowth = new Autogrowth(parent, file);
+ this.name = file.Name;
+
+ if (file.FileName.EndsWith(":", StringComparison.Ordinal))
+ {
+ // the data file is on a raw device
+ ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
+ this.physicalName = manager.GetString("general_rawDevice");
+ this.folder = file.FileName;
+ }
+ else
+ {
+ this.physicalName = Path.GetFileName(file.FileName);
+ this.folder = PathWrapper.GetDirectoryName(file.FileName);
+ }
+
+ this.initialSize = file.Size;
+ this.filegroup = filegroup;
+ this.isPrimaryFile = file.IsPrimaryFile;
+
+ switch (filegroup.FileGroupType)
+ {
+ case FileGroupType.RowsFileGroup:
+ this.fileType = FileType.Data;
+ break;
+
+ case FileGroupType.FileStreamDataFileGroup:
+ case FileGroupType.MemoryOptimizedDataFileGroup:
+ this.fileType = FileType.FileStream;
+ break;
+
+ default:
+ throw new InvalidArgumentException("Unsupported filegroup type");
+
+ }
+ }
+
+ ///
+ /// Creates instance of FileData
+ ///
+ ///
+ ///
+ public FileData(DatabasePrototype parent, LogFile file)
+ {
+ this.autogrowth = new Autogrowth(parent, file);
+ this.name = file.Name;
+
+ try
+ {
+ if (file.FileName.EndsWith(":", StringComparison.Ordinal))
+ {
+ // the log file is on a raw device
+ ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
+ this.physicalName = manager.GetString("general_rawDevice");
+ this.folder = file.FileName;
+ }
+ else
+ {
+ this.physicalName = Path.GetFileName(file.FileName);
+ this.folder = PathWrapper.GetDirectoryName(file.FileName);
+ }
+
+ this.initialSize = file.Size;
+ }
+ catch (Exception)
+ {
+ ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
+ this.physicalName = manager.GetString("unavailable");
+ this.folder = manager.GetString("unavailable");
+ this.initialSize = 0;
+ }
+
+ this.fileType = FileType.Log;
+ this.filegroup = null;
+ this.isPrimaryFile = false;
+ }
+
+ ///
+ /// Creates a instance of FileData from another instance
+ ///
+ ///
+ public FileData(FileData other)
+ {
+ this.name = other.name;
+ this.physicalName = other.physicalName;
+ this.folder = other.folder;
+ this.fileType = other.fileType;
+ this.filegroup = other.filegroup;
+ this.initialSize = other.initialSize;
+ this.autogrowth = new Autogrowth(other.autogrowth);
+ this.isPrimaryFile = other.isPrimaryFile;
+ }
+
+ ///
+ /// Clone current instance of FileData
+ ///
+ ///
+ public FileData Clone()
+ {
+ return new FileData(this);
+ }
+ }
+
+ private FileData originalState;
+ private FileData currentState;
+
+ private string defaultDataFolder = String.Empty;
+ private string defaultLogFolder = String.Empty;
+ private double defaultDataFileSize;
+ private double defaultLogFileSize;
+ private Autogrowth defaultDataAutogrowth;
+ private Autogrowth defaultLogAutogrowth;
+ private bool usingDefaultFolder;
+
+ private bool fileExists;
+ private bool removed;
+ private DatabasePrototype database;
+
+ private const double kilobytesPerMegabyte = 1024.0d;
+
+ #endregion
+
+ #region properties
+
+ ///
+ /// The logical name of the file, without extension
+ ///
+ public string Name
+ {
+ get { return this.currentState.name; }
+
+ set
+ {
+ this.currentState.name = value;
+ this.database.NotifyObservers();
+ }
+ }
+
+ ///
+ /// The physical name of the file
+ ///
+ public string PhysicalName
+ {
+ get { return this.currentState.physicalName; }
+
+ set
+ {
+ this.currentState.physicalName = value;
+ this.database.NotifyObservers();
+ }
+ }
+
+ ///
+ /// The folder in which the file is to be created
+ ///
+ public string Folder
+ {
+ get { return this.currentState.folder; }
+
+ set
+ {
+ this.currentState.folder = value;
+ this.usingDefaultFolder = (0 == String.Compare(value, this.DefaultFolder, StringComparison.Ordinal));
+ this.database.NotifyObservers();
+ }
+ }
+
+ ///
+ /// The type of the file, either Log or Data
+ ///
+ public FileType DatabaseFileType
+ {
+ get { return this.currentState.fileType; }
+
+ set
+ {
+ this.currentState.fileType = value;
+
+ if (this.usingDefaultFolder)
+ {
+ this.currentState.folder = this.DefaultFolder;
+ }
+
+ this.database.NotifyObservers();
+ }
+ }
+
+ ///
+ /// The prototype of the filegroup that is to contain this file
+ ///
+ public FilegroupPrototype FileGroup
+ {
+ get { return this.currentState.filegroup; }
+
+ set
+ {
+ if ((FileType.Data == this.currentState.fileType ||
+ FileType.FileStream == this.currentState.fileType) && !this.Exists && (value != null))
+ {
+ if (this.currentState.filegroup != null)
+ {
+ this.currentState.filegroup.OnFileGroupDeletedHandler -=
+ new FileGroupDeletedEventHandler(OnFilegroupDeleted);
+ }
+
+ this.currentState.filegroup = value;
+ this.currentState.filegroup.OnFileGroupDeletedHandler +=
+ new FileGroupDeletedEventHandler(OnFilegroupDeleted);
+ this.database.NotifyObservers();
+ }
+ }
+ }
+
+ ///
+ /// The initial size of the file in Megabytes
+ ///
+ public int InitialSize
+ {
+ get
+ {
+ // size kept in kilobytes internally
+ return DatabaseFilePrototype.KilobytesToMegabytes(this.currentState.initialSize);
+ }
+
+ set
+ {
+ // size kept in kilobytes internally
+ this.currentState.initialSize = DatabaseFilePrototype.MegabytesToKilobytes(value);
+ this.database.NotifyObservers();
+ }
+ }
+
+ ///
+ /// Auto-growth data for the file
+ ///
+ public Autogrowth Autogrowth
+ {
+ get { return this.currentState.autogrowth; }
+
+ set
+ {
+ this.currentState.autogrowth = new Autogrowth(value);
+ this.database.NotifyObservers();
+ }
+ }
+
+ ///
+ /// Whether this is the primary data file (the file with the .mdf extension)
+ ///
+ public bool IsPrimaryFile
+ {
+ get { return this.currentState.isPrimaryFile; }
+
+ set
+ {
+ this.currentState.isPrimaryFile = value;
+ this.database.NotifyObservers();
+ }
+ }
+
+ ///
+ /// The default folder for this file type
+ ///
+ public string DefaultFolder
+ {
+ get
+ {
+ if (this.currentState.fileType == FileType.Log)
+ {
+ return this.defaultLogFolder;
+ }
+ else
+ {
+ return this.defaultDataFolder;
+ }
+ }
+ }
+
+ ///
+ /// The default size for this file type
+ ///
+ public int DefaultSize
+ {
+ get
+ {
+ if (this.currentState.fileType == FileType.Log)
+ {
+ return DatabaseFilePrototype.KilobytesToMegabytes(this.defaultLogFileSize);
+ }
+ else
+ {
+ return DatabaseFilePrototype.KilobytesToMegabytes(this.defaultDataFileSize);
+ }
+ }
+ set
+ {
+ if (this.currentState.fileType == FileType.Log)
+ {
+ this.defaultLogFileSize = DatabaseFilePrototype.MegabytesToKilobytes(value);
+ }
+ else
+ {
+ this.defaultDataFileSize = DatabaseFilePrototype.MegabytesToKilobytes(value);
+ }
+ }
+ }
+
+ ///
+ /// The default size for this file type
+ ///
+ public Autogrowth DefaultAutogrowth
+ {
+ get
+ {
+ if (this.currentState.fileType == FileType.Log)
+ {
+ return this.defaultLogAutogrowth;
+ }
+ else
+ {
+ return this.defaultDataAutogrowth;
+ }
+ }
+ set
+ {
+ if (this.currentState.fileType == FileType.Log)
+ {
+ this.defaultLogAutogrowth = value;
+ }
+ else
+ {
+ this.defaultDataAutogrowth = value;
+ }
+ }
+ }
+
+ ///
+ /// Whether the file exists on the server
+ ///
+ public bool Exists
+ {
+ get { return this.fileExists; }
+
+ set { this.fileExists = value; }
+ }
+
+ ///
+ /// Whether the file was removed
+ ///
+ public bool Removed
+ {
+ get { return this.removed; }
+
+ set
+ {
+ this.removed = value;
+ this.database.NotifyObservers();
+ }
+ }
+
+ #endregion
+
+ ///
+ /// Constructor for new files
+ ///
+ /// server information
+ /// The parent database prototype
+ /// The type of the file
+ public DatabaseFilePrototype(CDataContainer context,
+ DatabasePrototype database,
+ FileType type)
+ {
+ Initialize(context, database, type);
+ }
+
+ ///
+ /// Constructor for new files whose name is known
+ ///
+ /// server information
+ /// The parent database prototype
+ /// The type of the file
+ /// The name of the file, without extension
+ public DatabaseFilePrototype(CDataContainer context,
+ DatabasePrototype database,
+ FileType type,
+ string name)
+ {
+ Initialize(context, database, type);
+
+ this.currentState.name = name;
+ }
+
+ ///
+ /// Constructor for existing data files
+ ///
+ /// Prototype database containing the prototype file
+ /// Prototype file group containing the prototype file
+ /// The SMO DataFile object whose definition is to be extracted
+ public DatabaseFilePrototype(DatabasePrototype database,
+ FilegroupPrototype filegroup,
+ DataFile file)
+ {
+ this.originalState = new FileData(database, filegroup, file);
+ this.currentState = this.originalState.Clone();
+
+ this.fileExists = true;
+ this.removed = false;
+ this.database = database;
+ }
+
+ ///
+ /// Constructor for existing log files
+ ///
+ /// Prototype database containing the prototype file
+ /// The SMO LogFile object whose definition is to be extracted
+ public DatabaseFilePrototype(DatabasePrototype database, LogFile file)
+ {
+ this.originalState = new FileData(database, file);
+ this.currentState = this.originalState.Clone();
+
+ this.fileExists = true;
+ this.removed = false;
+ this.database = database;
+ }
+
+ ///
+ /// Apply the changes to the database
+ ///
+ /// The database whose definition is being modified
+ public void ApplyChanges(Database db)
+ {
+ if (this.ChangesExist())
+ {
+ if (this.Removed)
+ {
+ this.RemoveFile(db);
+ }
+ else
+ {
+ switch (this.DatabaseFileType)
+ {
+ case FileType.Data:
+ this.CreateOrAlterDataFile(db);
+ break;
+
+ case FileType.Log:
+ this.CreateOrAlterLogFile(db);
+ break;
+
+ case FileType.FileStream:
+ this.CreateOrAlterFileStreamFile(db);
+ break;
+
+ default:
+ throw new InvalidOperationException("Invalid DatabaseFileType");
+ }
+ }
+ }
+ }
+
+ ///
+ /// Would calling ApplyChanges change anything?
+ ///
+ /// True if changes exist, false otherwise
+ public bool ChangesExist()
+ {
+ bool result = (
+ !this.Exists ||
+ this.Removed ||
+ (this.currentState.fileType != this.originalState.fileType) ||
+ (this.currentState.filegroup != this.originalState.filegroup) ||
+ (this.currentState.isPrimaryFile != this.originalState.isPrimaryFile) ||
+ (this.currentState.initialSize != this.originalState.initialSize) ||
+ !this.currentState.autogrowth.HasSameValueAs(this.originalState.autogrowth) ||
+ (0 != String.Compare(this.currentState.name, this.originalState.name, StringComparison.Ordinal)) ||
+ (0 != String.Compare(this.currentState.folder, this.originalState.folder, StringComparison.Ordinal)));
+
+ return result;
+ }
+
+ ///
+ /// Remove an existing file from the database
+ ///
+ /// The database from which the file is to be removed
+ private void RemoveFile(Database db)
+ {
+ if (this.Exists)
+ {
+ if (FileType.Log == this.DatabaseFileType)
+ {
+ LogFile lf = db.LogFiles[this.originalState.name];
+ if (lf != null)
+ {
+ lf.Drop();
+ }
+ }
+ else
+ {
+ if (!this.currentState.filegroup.Removed)
+ {
+ DataFile df = db.FileGroups[this.FileGroup.Name].Files[this.originalState.name];
+ if (df != null)
+ {
+ df.Drop();
+ }
+ }
+ }
+ }
+
+ }
+
+ ///
+ /// Create a data file
+ ///
+ /// The database object that is to contain the new file
+ private void CreateOrAlterDataFile(Database db)
+ {
+ // note: This method looks strikingly similar to CreateLogFile(), below.
+ // The initialization code can't be shared because LogFile and DataFile have
+ // no common base class, so we can't use polymorphism to our advantage.
+
+ // form the file path, create the data file
+ string fileSuffix = this.IsPrimaryFile ? ".mdf" : ".ndf";
+ DataFile file = null;
+ FileGroup fg = db.FileGroups[this.FileGroup.Name];
+
+ if (this.Exists)
+ {
+ file = db.FileGroups[this.FileGroup.Name].Files[this.originalState.name];
+
+ if (!file.Name.Equals(this.Name))
+ {
+ file.Rename(this.Name);
+ }
+ }
+ else
+ {
+ file = new DataFile(fg, this.Name);
+ fg.Files.Add(file);
+ }
+
+ if (this.IsPrimaryFile && !this.Exists)
+ {
+ file.IsPrimaryFile = true;
+ }
+
+ // set the file name (you can't change the file name after the file has been created)
+ if (!this.Exists)
+ {
+ file.FileName = MakeDiskFileName(this.Name, this.PhysicalName, fileSuffix);
+ }
+
+ // set its initial size
+ double originalSize = this.originalState.initialSize;
+ double newSize = this.currentState.initialSize;
+
+ // if the file does not exist or if the existing file size was changed in the UI and is
+ // significantly larger than the value on the server, set the file size
+ if (!this.Exists || ((1e-6 < Math.Abs(newSize - originalSize)) && (1e-6 < (newSize - file.Size))))
+ {
+ file.Size = newSize;
+ }
+ else if ((newSize < originalSize) && (newSize < file.Size))
+ {
+ file.Shrink(KilobytesToMegabytes(newSize), ShrinkMethod.Default);
+ }
+
+ if (!this.Exists)
+ {
+ // if auto-growth is enabled, set auto-growth data
+ if (this.Autogrowth.IsEnabled)
+ {
+ if (this.Autogrowth.IsGrowthRestricted)
+ {
+ file.MaxSize = this.Autogrowth.MaximumFileSizeInKilobytes;
+ }
+
+ if (this.Autogrowth.IsGrowthInPercent)
+ {
+ file.GrowthType = FileGrowthType.Percent;
+ file.Growth = (double) this.Autogrowth.GrowthInPercent;
+ }
+ else
+ {
+ file.GrowthType = FileGrowthType.KB;
+ file.Growth = this.Autogrowth.GrowthInKilobytes;
+ }
+ }
+ else
+ {
+ file.GrowthType = FileGrowthType.None;
+ }
+ }
+ else
+ {
+ FileGrowthType newFileGrowthType = FileGrowthType.None;
+ FileGrowthType originalFileGrowthType = FileGrowthType.None;
+ double newGrowth = 0.0;
+ double originalGrowth = 0.0;
+ double newMaxSize = 0.0;
+ double originalMaxSize = 0.0;
+
+ if (this.currentState.autogrowth.IsEnabled)
+ {
+ if (this.currentState.autogrowth.IsGrowthRestricted)
+ {
+ newMaxSize = this.currentState.autogrowth.MaximumFileSizeInKilobytes;
+ }
+
+ if (this.currentState.autogrowth.IsGrowthInPercent)
+ {
+ newFileGrowthType = FileGrowthType.Percent;
+ newGrowth = (double) this.currentState.autogrowth.GrowthInPercent;
+ }
+ else
+ {
+ newFileGrowthType = FileGrowthType.KB;
+ newGrowth = this.currentState.autogrowth.GrowthInKilobytes;
+ }
+ }
+
+ if (this.originalState.autogrowth.IsEnabled)
+ {
+ if (this.originalState.autogrowth.IsGrowthRestricted)
+ {
+ originalMaxSize = this.originalState.autogrowth.MaximumFileSizeInKilobytes;
+ }
+
+ if (this.originalState.autogrowth.IsGrowthInPercent)
+ {
+ originalFileGrowthType = FileGrowthType.Percent;
+ originalGrowth = (double) this.originalState.autogrowth.GrowthInPercent;
+ }
+ else
+ {
+ originalFileGrowthType = FileGrowthType.KB;
+ originalGrowth = this.originalState.autogrowth.GrowthInKilobytes;
+ }
+ }
+
+ // if file growth type has changed in the UI and is different from the value on the server
+ if ((newFileGrowthType != originalFileGrowthType) && (file.GrowthType != newFileGrowthType))
+ {
+ // change the file growth type
+ file.GrowthType = newFileGrowthType;
+ }
+
+ // if the growth amount has changed in the UI and is different from the value on the server
+ if ((1e-6 < (Math.Abs(newGrowth - originalGrowth))) && (1e-6 < Math.Abs(newGrowth - file.Growth)))
+ {
+ // change the growth amount
+ file.Growth = newGrowth;
+ }
+
+ // when file size is unlimited, MaxSize is non-positive. For the
+ // purposes of our code, convert non-positive to zero, then compare
+ // vs. the prototype file size.
+ double fileMaxSize = (0.0 <= file.MaxSize) ? file.MaxSize : 0.0;
+
+ // if the max size has changed in the UI and is different from the value on the server
+ if ((1e-6 < Math.Abs(originalMaxSize - newMaxSize)) && (1e-6 < Math.Abs(fileMaxSize - newMaxSize)))
+ {
+ // set the file max size
+ file.MaxSize = newMaxSize;
+ }
+ }
+ }
+
+ ///
+ /// Create a filestream file
+ ///
+ /// The database object that is to contain the new file
+ private void CreateOrAlterFileStreamFile(Database db)
+ {
+ // form the file path, create the data file
+ DataFile file = null;
+ FileGroup fg = db.FileGroups[this.FileGroup.Name];
+
+ if (this.Exists)
+ {
+ file = db.FileGroups[this.FileGroup.Name].Files[this.originalState.name];
+
+ if (!file.Name.Equals(this.Name))
+ {
+ file.Rename(this.Name);
+ }
+ }
+ else
+ {
+ file = new DataFile(fg, this.Name);
+ fg.Files.Add(file);
+ }
+
+ // set the file name (you can't change the file name after the file has been created)
+ if (!this.Exists)
+ {
+ // filestream files ignore the filename but if provided it just puts it
+ // into the transact-sql query. If in future that query starts using the
+ // filename in some manner we get that functionality automatically by
+ // passing in the same name to the server. -anchals
+ file.FileName = MakeDiskFileName(this.Name, this.PhysicalName, String.Empty);
+ }
+
+ if (this.database.ServerVersion.Major >= 11)
+ {
+ double newMaxSize = 0.0;
+ double originalMaxSize = 0.0;
+ if (!this.Exists)
+ {
+ if (this.Autogrowth.IsGrowthRestricted)
+ {
+ file.MaxSize = this.Autogrowth.MaximumFileSizeInKilobytes;
+ }
+ }
+ else
+ {
+ if (this.currentState.autogrowth.IsGrowthRestricted)
+ {
+ newMaxSize = this.currentState.autogrowth.MaximumFileSizeInKilobytes;
+ }
+ if (this.originalState.autogrowth.IsGrowthRestricted)
+ {
+ originalMaxSize = this.originalState.autogrowth.MaximumFileSizeInKilobytes;
+ }
+
+ // when file size is unlimited, MaxSize is non-positive. For the
+ // purposes of our code, convert non-positive to zero, then compare
+ // vs. the prototype file size.
+ double fileMaxSize = (0.0 <= file.MaxSize) ? file.MaxSize : 0.0;
+
+ // if the max size has changed in the UI and is different from the value on the server
+ if ((1e-6 < Math.Abs(originalMaxSize - newMaxSize)) && (1e-6 < Math.Abs(fileMaxSize - newMaxSize)))
+ {
+ // set the file max size
+ file.MaxSize = newMaxSize;
+ }
+ }
+
+ }
+ }
+
+ ///
+ /// Create a log file
+ ///
+ /// The database object that is to contain the new file
+ private void CreateOrAlterLogFile(Database db)
+ {
+ // note: This method looks strikingly similar to CreateDataFile(), above.
+ // The initialization code can't be shared because LogFile and DataFile have
+ // no common base class, so we can't use polymorphism to our advantage.
+
+ LogFile file = null;
+
+ if (this.Exists)
+ {
+ file = db.LogFiles[this.originalState.name];
+
+ if (!file.Name.Equals(this.Name))
+ {
+ file.Rename(this.Name);
+ }
+ }
+ else
+ {
+ file = new LogFile(db, this.Name);
+ db.LogFiles.Add(file);
+ }
+
+ // set its path and initial size
+ if (!this.Exists)
+ {
+ file.FileName = MakeDiskFileName(this.Name, this.PhysicalName, ".ldf");
+ }
+
+ // set its initial size
+ double originalSize = this.originalState.initialSize;
+ double newSize = this.currentState.initialSize;
+
+ // if the file does not exist or if the existing file size was changed in the UI and is
+ // significantly larger than the value on the server, set the file size
+ if (!this.Exists || ((1e-6 < Math.Abs(newSize - originalSize)) && (1e-6 < (newSize - file.Size))))
+ {
+ file.Size = newSize;
+ }
+ else if ((newSize < originalSize) && (newSize < file.Size))
+ {
+ file.Shrink(KilobytesToMegabytes(newSize), ShrinkMethod.Default);
+ }
+
+
+ // if auto-growth is enabled, set auto-growth data
+ if (!this.Exists)
+ {
+ // if auto-growth is enabled, set auto-growth data
+ if (this.Autogrowth.IsEnabled)
+ {
+ if (this.Autogrowth.IsGrowthRestricted)
+ {
+ file.MaxSize = this.Autogrowth.MaximumFileSizeInKilobytes;
+ }
+
+ if (this.Autogrowth.IsGrowthInPercent)
+ {
+ file.GrowthType = FileGrowthType.Percent;
+ file.Growth = (double) this.Autogrowth.GrowthInPercent;
+ }
+ else
+ {
+ file.GrowthType = FileGrowthType.KB;
+ file.Growth = this.Autogrowth.GrowthInKilobytes;
+ }
+ }
+ else
+ {
+ file.GrowthType = FileGrowthType.None;
+ }
+ }
+ else
+ {
+ FileGrowthType newFileGrowthType = FileGrowthType.None;
+ FileGrowthType originalFileGrowthType = FileGrowthType.None;
+ double newGrowth = 0.0;
+ double originalGrowth = 0.0;
+ double newMaxSize = 0.0;
+ double originalMaxSize = 0.0;
+
+ if (this.currentState.autogrowth.IsEnabled)
+ {
+ if (this.currentState.autogrowth.IsGrowthRestricted)
+ {
+ newMaxSize = this.currentState.autogrowth.MaximumFileSizeInKilobytes;
+ }
+
+ if (this.currentState.autogrowth.IsGrowthInPercent)
+ {
+ newFileGrowthType = FileGrowthType.Percent;
+ newGrowth = (double) this.currentState.autogrowth.GrowthInPercent;
+ }
+ else
+ {
+ newFileGrowthType = FileGrowthType.KB;
+ newGrowth = this.currentState.autogrowth.GrowthInKilobytes;
+ }
+ }
+
+ if (this.originalState.autogrowth.IsEnabled)
+ {
+ if (this.originalState.autogrowth.IsGrowthRestricted)
+ {
+ originalMaxSize = this.originalState.autogrowth.MaximumFileSizeInKilobytes;
+ }
+
+ if (this.originalState.autogrowth.IsGrowthInPercent)
+ {
+ originalFileGrowthType = FileGrowthType.Percent;
+ originalGrowth = (double) this.originalState.autogrowth.GrowthInPercent;
+ }
+ else
+ {
+ originalFileGrowthType = FileGrowthType.KB;
+ originalGrowth = this.originalState.autogrowth.GrowthInKilobytes;
+ }
+ }
+
+ // if file growth type has changed in the UI and is different from the value on the server
+ if ((newFileGrowthType != originalFileGrowthType) && (file.GrowthType != newFileGrowthType))
+ {
+ // change the file growth type
+ file.GrowthType = newFileGrowthType;
+ }
+
+ // if the growth amount has changed in the UI and is different from the value on the server
+ if ((1e-6 < (Math.Abs(newGrowth - originalGrowth))) && (1e-6 < Math.Abs(newGrowth - file.Growth)))
+ {
+ // change the growth amount
+ file.Growth = newGrowth;
+ }
+
+ // when file size is unlimited, MaxSize is non-positive. For the
+ // purposes of our code, convert non-positive to zero, then compare
+ // vs. the prototype file size.
+ double fileMaxSize = (0.0 <= file.MaxSize) ? file.MaxSize : 0.0;
+
+ // if the max size has changed in the UI and is different from the value on the server
+ if ((1e-6 < Math.Abs(originalMaxSize - newMaxSize)) && (1e-6 < Math.Abs(fileMaxSize - newMaxSize)))
+ {
+ // set the file max size
+ file.MaxSize = newMaxSize;
+ }
+ }
+ }
+
+ ///
+ /// Shared construction code for new files
+ ///
+ ///
+ /// The parent database prototype
+ /// The type of the file
+ private void Initialize(CDataContainer context, DatabasePrototype database, FileType type)
+ {
+ this.originalState = new FileData(database, type);
+
+
+ this.fileExists = false;
+ this.removed = false;
+ this.database = database;
+
+ GetDefaultValues(context);
+ GetDefaultAutoGrowthValues(context);
+
+ if (FileType.Data == type)
+ {
+ InitializeDataFile(context);
+ }
+ else if (FileType.Log == type)
+ {
+ InitializeLogFile(context);
+ }
+
+ this.currentState = this.originalState.Clone();
+ }
+
+ ///
+ /// Get the default folder for log and data files
+ ///
+ private void GetDefaultValues(CDataContainer context)
+ {
+ Enumerator enumerator = new Enumerator();
+ Request request = new Request();
+ //object connectionInfo = context.ConnectionInfo;
+ object connectionInfo = null;
+ DataTable fileInfo = null;
+ double size;
+
+ if (null != context.Server)
+ {
+ connectionInfo = context.Server.ConnectionContext;
+ }
+ else
+ {
+ connectionInfo = context.ConnectionInfo;
+ }
+
+ // get default data file size
+ request.Urn = "Server/Database[@Name='model']/FileGroup[@Name='PRIMARY']/File";
+ request.Fields = new String[1] {"Size"};
+
+ try
+ {
+ fileInfo = enumerator.Process(connectionInfo, request);
+ size = Convert.ToDouble(fileInfo.Rows[0][0], System.Globalization.CultureInfo.InvariantCulture);
+
+ // file size returned by the enumerator is in kilobytes but the dialog displays
+ // file size in megabytes
+
+ defaultDataFileSize = DatabaseFilePrototype.RoundUpToNearestMegabyte(size);
+ }
+ catch (Exception ex)
+ {
+ // user doesn't have access to model so we set the default size
+ // to be 5 MB
+ defaultDataFileSize = 5120.0;
+ }
+
+ // get default log file size
+ request.Urn = "Server/Database[@Name='model']/LogFile";
+ request.Fields = new String[1] {"Size"};
+
+ try
+ {
+ fileInfo = enumerator.Process(connectionInfo, request);
+ size = Convert.ToDouble(fileInfo.Rows[0][0], System.Globalization.CultureInfo.InvariantCulture);
+
+ defaultLogFileSize = DatabaseFilePrototype.RoundUpToNearestMegabyte(size);
+ }
+ catch (Exception ex)
+ {
+ // user doesn't have access to model so we set the default size
+ // to be 1MB
+ defaultLogFileSize = 1024.0;
+ }
+
+ // get default data and log folders
+ request.Urn = "Server/Setting";
+ request.Fields = new String[] {"DefaultFile", "DefaultLog"};
+
+ try
+ {
+ fileInfo = enumerator.Process(connectionInfo, request);
+ defaultDataFolder = fileInfo.Rows[0]["DefaultFile"].ToString();
+ defaultLogFolder = fileInfo.Rows[0]["DefaultLog"].ToString();
+
+ if (defaultDataFolder.Length == 0 || defaultLogFolder.Length == 0)
+ {
+ request.Urn = "Server/Information";
+ request.Fields = new string[] {"MasterDBPath", "MasterDBLogPath"};
+ fileInfo = enumerator.Process(connectionInfo, request);
+
+ if (defaultDataFolder.Length == 0)
+ {
+ defaultDataFolder = fileInfo.Rows[0]["MasterDBPath"].ToString();
+ }
+
+ if (defaultLogFolder.Length == 0)
+ {
+ defaultLogFolder = fileInfo.Rows[0]["MasterDBLogPath"].ToString();
+ }
+ }
+
+ if ((3 <= defaultDataFolder.Length) && (defaultDataFolder[1] == ':') && (defaultDataFolder[2] != '\\'))
+ {
+ string drivePart = defaultDataFolder.Substring(0, 2);
+ string rest = defaultDataFolder.Substring(2);
+
+ defaultDataFolder = String.Format(
+ System.Globalization.CultureInfo.InvariantCulture,
+ "{0}\\{1}",
+ drivePart,
+ rest);
+ }
+
+
+ if ((3 <= defaultLogFolder.Length) && (defaultLogFolder[1] == ':') && (defaultLogFolder[2] != '\\'))
+ {
+ string drivePart = defaultLogFolder.Substring(0, 2);
+ string rest = defaultLogFolder.Substring(2);
+
+ defaultLogFolder = String.Format(
+ System.Globalization.CultureInfo.InvariantCulture,
+ "{0}\\{1}",
+ drivePart,
+ rest);
+ }
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+
+ ///
+ /// Get the default Autogrowth values for log or data files
+ ///
+ ///
+ private void GetDefaultAutoGrowthValues(CDataContainer context)
+ {
+ // get autogrowth information
+ defaultDataAutogrowth = new Autogrowth(this.database);
+
+ // try to get defaults from model database
+ try
+ {
+ // copy default data size and autogrowth from the model database
+ Database model = context.Server.Databases["model"];
+ FileGroup filegroup = model.FileGroups["PRIMARY"];
+ DataFile datafile = filegroup.Files[0];
+
+ defaultDataAutogrowth.IsEnabled = (datafile.GrowthType != FileGrowthType.None);
+
+ if (defaultDataAutogrowth.IsEnabled)
+ {
+ defaultDataAutogrowth.MaximumFileSizeInKilobytes = datafile.MaxSize;
+ defaultDataAutogrowth.IsGrowthRestricted = (0.0 < defaultDataAutogrowth.MaximumFileSizeInKilobytes);
+ defaultDataAutogrowth.IsGrowthInPercent = datafile.GrowthType == FileGrowthType.Percent;
+
+ if (!defaultDataAutogrowth.IsGrowthRestricted)
+ {
+ // we need to set a default maximum size for the file in the
+ // event the user changes to restricted growth. 0.0 is not
+ // a valid maximum file size.
+
+ defaultDataAutogrowth.MaximumFileSizeInKilobytes = 102400.0;
+ }
+
+ if (defaultDataAutogrowth.IsGrowthInPercent)
+ {
+ defaultDataAutogrowth.GrowthInPercent = (int) datafile.Growth;
+ defaultDataAutogrowth.GrowthInMegabytes = 10;
+ }
+ else
+ {
+ defaultDataAutogrowth.GrowthInKilobytes =
+ DatabaseFilePrototype.RoundUpToNearestMegabyte(datafile.Growth);
+ defaultDataAutogrowth.GrowthInPercent = 10;
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // there was an error getting information about the model database,
+ // so just set the default sizes to default values
+ defaultDataAutogrowth.Reset();
+ }
+ // get default autogrowth information
+ defaultLogAutogrowth = new Autogrowth(this.database);
+
+ // try to get defaults from model database
+ try
+ {
+ // copy default data size and autogrowth from the model database
+ Database model = context.Server.Databases["model"];
+ LogFile logfile = model.LogFiles[0];
+
+ defaultLogAutogrowth.IsEnabled = (logfile.GrowthType != FileGrowthType.None);
+
+ if (defaultLogAutogrowth.IsEnabled)
+ {
+ defaultLogAutogrowth.MaximumFileSizeInKilobytes = logfile.MaxSize;
+ defaultLogAutogrowth.IsGrowthRestricted = (0.0 < defaultLogAutogrowth.MaximumFileSizeInKilobytes);
+ defaultLogAutogrowth.IsGrowthInPercent = logfile.GrowthType == FileGrowthType.Percent;
+
+ if (!defaultLogAutogrowth.IsGrowthRestricted)
+ {
+ // we need to set a default maximum size for the file in the
+ // event the user changes to restricted growth. 0.0 is not
+ // a valid maximum file size.
+
+ defaultLogAutogrowth.MaximumFileSizeInKilobytes = 102400.0;
+ }
+
+ if (defaultLogAutogrowth.IsGrowthInPercent)
+ {
+ defaultLogAutogrowth.GrowthInPercent = (int) logfile.Growth;
+ defaultLogAutogrowth.GrowthInMegabytes = 10;
+ }
+ else
+ {
+ defaultLogAutogrowth.GrowthInKilobytes =
+ DatabaseFilePrototype.RoundUpToNearestMegabyte(logfile.Growth);
+ defaultLogAutogrowth.GrowthInPercent = 10;
+ }
+ }
+ }
+ catch (Exception)
+ {
+ // there was an error getting information about the model database,
+ // so just set the default sizes to default values
+ defaultLogAutogrowth.Reset();
+ }
+ }
+
+ ///
+ /// Initialize a data file, called during construction
+ ///
+ ///
+ private void InitializeDataFile(CDataContainer context)
+ {
+ // set our state
+ this.originalState.folder = this.defaultDataFolder;
+ this.usingDefaultFolder = true;
+ this.originalState.autogrowth = defaultDataAutogrowth;
+ this.originalState.initialSize = this.defaultDataFileSize;
+ this.originalState.filegroup = this.database.DefaultFilegroup;
+
+ this.database.DefaultFilegroup.OnFileGroupDeletedHandler +=
+ new FileGroupDeletedEventHandler(OnFilegroupDeleted);
+ }
+
+ ///
+ /// Initialize a new log file prototype, called during construction
+ ///
+ ///
+ private void InitializeLogFile(CDataContainer context)
+ {
+ // set our state
+ this.originalState.folder = this.defaultLogFolder;
+ this.usingDefaultFolder = true;
+ this.originalState.filegroup = null;
+ this.originalState.autogrowth = defaultLogAutogrowth;
+ this.originalState.initialSize = this.defaultLogFileSize;
+ }
+
+ ///
+ /// Handle deleted events from the filegroup that contains the file
+ ///
+ ///
+ ///
+ private void OnFilegroupDeleted(object sender, FilegroupDeletedEventArgs e)
+ {
+ e.DeletedFilegroup.OnFileGroupDeletedHandler -= new FileGroupDeletedEventHandler(OnFilegroupDeleted);
+
+ // SQL Server deletes all the files in a filegroup when the filegroup is removed
+ if (this.Exists)
+ {
+ this.database.Remove(this);
+ }
+ else
+ {
+ this.FileGroup = e.DefaultFilegroup;
+ }
+ }
+
+ ///
+ /// Check whether a proposed file name is valid. An exception is thrown if the check fails.
+ ///
+ /// The proposed file name to check
+ private void CheckFileName(string fileName)
+ {
+ char[] badFileCharacters = new char[] {'\\', '/', ':', '*', '?', '\"', '<', '>', '|'};
+
+ bool isAllWhitespace = (fileName.Trim(null).Length == 0);
+
+ if (isAllWhitespace || (0 == fileName.Length) || (-1 != fileName.IndexOfAny(badFileCharacters)))
+ {
+ ResourceManager resourceManager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ this.GetType().GetAssembly());
+
+ string message = String.Empty;
+
+ if (0 == fileName.Length)
+ {
+ message = resourceManager.GetString("error.emptyFileName");
+ }
+ else if (isAllWhitespace)
+ {
+ message = resourceManager.GetString("error.whitespaceDatabaseName");
+ }
+ else
+ {
+ int i = fileName.IndexOfAny(badFileCharacters);
+
+ message = String.Format(System.Globalization.CultureInfo.CurrentCulture,
+ resourceManager.GetString("error.fileNameContainsIllegalCharacter"), fileName, fileName[i]);
+ }
+
+ throw new InvalidOperationException(message);
+ }
+ }
+
+ ///
+ /// Get the number of megabytes equivalent to an input number of kilobytes, rounding up.
+ ///
+ /// The number of kilobytes to convert
+ /// The equivalent number of megabytes
+ internal static int KilobytesToMegabytes(double kilobytes)
+ {
+ return (int) Math.Ceiling(kilobytes/kilobytesPerMegabyte);
+ }
+
+ ///
+ /// Get the number of kilobytes equivalent to an input number of megabytes.
+ ///
+ /// The number of megabytes to convert
+ /// The equivalent number of kilobytes
+ internal static double MegabytesToKilobytes(int megabytes)
+ {
+ return (((double) megabytes)*kilobytesPerMegabyte);
+ }
+
+ ///
+ /// Get the number of kilobytes that is a round number of megabytes
+ /// larger than the input number of kilobytes. e.g. 1600 kb -> 2048 kb
+ ///
+ /// The number of kilobytes to round up
+ /// The number of kb in the next larger mb
+ internal static double RoundUpToNearestMegabyte(double kilobytes)
+ {
+ double megabytes = Math.Ceiling(kilobytes/kilobytesPerMegabyte);
+ return (megabytes*kilobytesPerMegabyte);
+ }
+
+ ///
+ /// Create the Physical file name for the data file to be created on disk
+ /// from user preferred logical and physical Name. This also verifies the
+ /// logical file name provided to the data file.
+ /// If a valid physical name is provided then that is returned with proper extension.
+ /// Else logical name is used.
+ ///
+ /// MakeDiskFileName returns the actual physical filename that could be used for the T-SQL query
+ /// It makes sure:
+ /// 1. provide a way to provide different physical and logical file names to a database file.
+ /// 2. Its optional if preferred physical name is blank then logical name is used to generate the physical file name. (logical name and
+ /// physical filename are then same. (except that the physical filename has a proper extension)
+ /// 3. since logical file name check is not that stringent in t-sql; this check is relaxed only when a physical name is explicitly provided.
+ /// 4. we don't enable the physical file name input control for filestream files since the filename passed to t-sql in this case is simply ignored. Internally
+ /// we evaluate the final file name in case of filestreams also in the same manner for consistency (and if in future t-sql starts using the physical filename
+ /// apart from the path.)
+ /// 5. Also if the preferred physical filename is without a file extension then default extension is appended.
+ /// Otherwise the user defined extension is used.
+ ///
+ /// Logical name of the data file. Cannot be blank. Its verified.
+ /// User Preferred Physical name of the file. Can be blank.
+ /// Preferred suffix of the file. can be String.Empty. If provided physical name doesn't
+ /// have an extension or is empty then this is used.
+ /// full filename for the disk. The filename
+ /// is prefixed with this.Folder path to generate the full name.
+ /// If logical name is empty, or physical name is invalid.
+ private string MakeDiskFileName(string logicalName, string preferredPhysicalName, string suffix)
+ {
+ ResourceManager resourceManager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ this.GetType().GetAssembly());
+
+ string filePath = String.Empty; // returned to the caller.
+ if (String.IsNullOrEmpty(preferredPhysicalName))
+ {
+ // make the file name using the logical name and suffix provided.
+ this.CheckFileName(logicalName);
+ filePath = PathWrapper.Combine(this.Folder, logicalName) + suffix;
+ }
+ else
+ {
+ // do sanity check on name since logical name must exist always.
+ // The check for logical name is not as stringent as that for physical file name. This is because
+ // transact sql allows special characters to be present in logical filename but don't allow them
+ // as physical filename. e.g. '?' can be a valid logical name but not a valid physical name. [anchals]
+ if (logicalName.Length == 0)
+ {
+ string message = String.Empty;
+
+ message = resourceManager.GetString("error.emptyFileName");
+ throw new InvalidOperationException(message);
+ }
+
+ // validate provided physical name and if it does not have an extension
+ // append the suffix to it.
+ this.CheckFileName(preferredPhysicalName);
+ filePath = PathWrapper.Combine(this.Folder, preferredPhysicalName);
+ }
+ return filePath;
+ }
+ }
+
+ ///
+ /// Information regarding a name-change event
+ ///
+ public class NameChangedEventArgs : EventArgs
+ {
+ private string oldName;
+ private string newName;
+
+ ///
+ /// The name before the change
+ ///
+ public string OldName
+ {
+ get { return oldName; }
+ }
+
+ ///
+ /// The name after the change
+ ///
+ public string NewName
+ {
+ get { return newName; }
+ }
+
+ ///
+ /// Constructor
+ ///
+ /// The name before the change
+ /// The name after the change
+ public NameChangedEventArgs(string oldName, string newName)
+ {
+ this.oldName = oldName;
+ this.newName = newName;
+ }
+ }
+
+ ///
+ /// Information regarding a changes to boolean property values
+ ///
+ public class BooleanValueChangedEventArgs : EventArgs
+ {
+ private bool oldValue;
+ private bool newValue;
+
+ ///
+ /// The value before the change
+ ///
+ public bool OldValue
+ {
+ get { return oldValue; }
+ }
+
+ ///
+ /// The value after the change
+ ///
+ public bool NewValue
+ {
+ get { return newValue; }
+ }
+
+ ///
+ /// Constructor
+ ///
+ /// The value before the change
+ /// The value after the change
+ public BooleanValueChangedEventArgs(bool oldValue, bool newValue)
+ {
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ }
+ }
+
+ ///
+ /// Information regarding the deletion of a filegroup
+ ///
+ public class FilegroupDeletedEventArgs : EventArgs
+ {
+ private FilegroupPrototype defaultFilegroup;
+ private FilegroupPrototype deletedFilegroup;
+
+ ///
+ /// The default filegroup for the database
+ ///
+ public FilegroupPrototype DefaultFilegroup
+ {
+ get { return defaultFilegroup; }
+ }
+
+ ///
+ /// The filegroup that was deleted
+ ///
+ public FilegroupPrototype DeletedFilegroup
+ {
+ get { return deletedFilegroup; }
+ }
+
+ ///
+ /// Constructor
+ ///
+ /// The filegroup that was deleted
+ /// The default filegroup for the database
+ public FilegroupDeletedEventArgs(FilegroupPrototype deletedFilegroup, FilegroupPrototype defaultFilegroup)
+ {
+ this.deletedFilegroup = deletedFilegroup;
+ this.defaultFilegroup = defaultFilegroup;
+ }
+ }
+
+ public delegate void FileGroupNameChangedEventHandler(object sender, NameChangedEventArgs e);
+
+ public delegate void FileGroupDeletedEventHandler(object sender, FilegroupDeletedEventArgs e);
+
+ public delegate void FileGroupDefaultChangedEventHandler(object sender, BooleanValueChangedEventArgs e);
+
+ internal class DatabaseAlreadyExistsException : Exception
+ {
+ private static string format;
+
+ static DatabaseAlreadyExistsException()
+ {
+ ResourceManager resourceManager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ typeof (DatabaseAlreadyExistsException).GetAssembly());
+ format = resourceManager.GetString("error.databaseAlreadyExists");
+ }
+
+ public DatabaseAlreadyExistsException(string databaseName)
+ : base(String.Format(System.Globalization.CultureInfo.CurrentCulture, format, databaseName))
+ {
+ }
+ }
+
+ internal class DefaultCursorTypes : StringConverter
+ {
+ ///
+ /// This method returns a list of default cursor Types
+ /// which will be populated as a drop down list.
+ ///
+ ///
+ /// List of DefaultCursor Types
+ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ {
+ ResourceManager manager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ typeof (DatabasePrototype).GetAssembly());
+ List standardValues = null;
+ TypeConverter.StandardValuesCollection result = null;
+
+ if (
+ string.Compare(context.PropertyDescriptor.Name, "DefaultCursorDisplay",
+ StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ standardValues = new List();
+ standardValues.Add(manager.GetString("prototype.db.prop.defaultCursor.value.local"));
+ standardValues.Add(manager.GetString("prototype.db.prop.defaultCursor.value.global"));
+ }
+ if (standardValues != null)
+ {
+ result = new TypeConverter.StandardValuesCollection(standardValues);
+ }
+
+ return result;
+ }
+
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+ }
+
+ internal class ParameterizationTypes : StringConverter
+ {
+ ///
+ /// This method returns a list of parameterization Types
+ /// which will be populated as a drop down list.
+ ///
+ ///
+ /// List of Parameterization Types
+ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ {
+ ResourceManager manager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ typeof (DatabasePrototype90).GetAssembly());
+ List standardValues = new List();
+ TypeConverter.StandardValuesCollection result = null;
+
+ if (
+ string.Compare(context.PropertyDescriptor.Name, "Parameterization", StringComparison.OrdinalIgnoreCase) ==
+ 0)
+ {
+ standardValues.Add(manager.GetString("prototype.db.prop.parameterization.value.forced"));
+ standardValues.Add(manager.GetString("prototype.db.prop.parameterization.value.simple"));
+ }
+ if (standardValues.Count > 0)
+ {
+ result = new TypeConverter.StandardValuesCollection(standardValues);
+ }
+
+ return result;
+ }
+
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+ }
+
+ internal class PageVerifyTypes80 : StringConverter
+ {
+ ///
+ /// This method returns a list of pageverify Types
+ /// which will be populated as a drop down list.
+ ///
+ ///
+ /// List of Page Verify Types
+ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ {
+ ResourceManager manager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ typeof (DatabasePrototype80).GetAssembly());
+ List standardValues = new List();
+ TypeConverter.StandardValuesCollection result = null;
+
+ if (
+ string.Compare(context.PropertyDescriptor.Name, "PageVerifyDisplay", StringComparison.OrdinalIgnoreCase) ==
+ 0)
+ {
+ standardValues.Add(manager.GetString("prototype.db.prop.pageVerify.value.tornPageDetection"));
+ standardValues.Add(manager.GetString("prototype.db.prop.pageVerify.value.none"));
+ }
+
+ if (standardValues.Count > 0)
+ {
+ result = new TypeConverter.StandardValuesCollection(standardValues);
+ }
+
+ return result;
+ }
+
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+ }
+
+
+ internal class PageVerifyTypes90 : StringConverter
+ {
+ ///
+ /// This method returns a list of pageverify Types
+ /// which will be populated as a drop down list.
+ ///
+ ///
+ /// List of Page Verify Types
+ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ {
+ ResourceManager manager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ typeof (DatabasePrototype80).GetAssembly());
+ List standardValues = new List();
+ TypeConverter.StandardValuesCollection result = null;
+
+ if (
+ string.Compare(context.PropertyDescriptor.Name, "PageVerifyDisplay", StringComparison.OrdinalIgnoreCase) ==
+ 0)
+ {
+ standardValues.Add(manager.GetString("prototype.db.prop.pageVerify.value.checksum"));
+ standardValues.Add(manager.GetString("prototype.db.prop.pageVerify.value.tornPageDetection"));
+ standardValues.Add(manager.GetString("prototype.db.prop.pageVerify.value.none"));
+ }
+
+ if (standardValues.Count > 0)
+ {
+ result = new TypeConverter.StandardValuesCollection(standardValues);
+ }
+
+ return result;
+ }
+
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+ }
+
+ internal class RestrictAccessTypes : StringConverter
+ {
+ ///
+ /// This method returns a list of Access Types
+ /// which will be populated as a drop down list.
+ ///
+ ///
+ /// List of Restrict Access Types
+ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ {
+ ResourceManager manager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ typeof (DatabasePrototype).GetAssembly());
+ List standardValues = new List();
+ TypeConverter.StandardValuesCollection result = null;
+
+ if (string.Compare(context.PropertyDescriptor.Name, "RestrictAccess", StringComparison.OrdinalIgnoreCase) ==
+ 0)
+ {
+ standardValues.Add(manager.GetString("prototype.db.prop.restrictAccess.value.multiple"));
+ standardValues.Add(manager.GetString("prototype.db.prop.restrictAccess.value.single"));
+ standardValues.Add(manager.GetString("prototype.db.prop.restrictAccess.value.restricted"));
+ }
+ if (standardValues.Count > 0)
+ {
+ result = new TypeConverter.StandardValuesCollection(standardValues);
+ }
+
+ return result;
+ }
+
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+ }
+
+ internal class DatabaseStatusTypes : StringConverter
+ {
+ ///
+ /// This method returns a list of database status Types
+ /// which will be populated as a drop down list.
+ ///
+ ///
+ /// List of Database Status Types
+ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ {
+ ResourceManager manager =
+ new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
+ typeof (DatabasePrototype).GetAssembly());
+ List standardValues = new List();
+ TypeConverter.StandardValuesCollection result = null;
+
+ if (
+ string.Compare(context.PropertyDescriptor.Name, "DatabaseStatusDisplay",
+ StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.normal"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.restoring"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.recoveryPending"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.recovering"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.suspect"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.offline"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.inaccessible"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.standby"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.shutdown"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.emergency"));
+ standardValues.Add(manager.GetString("prototype.db.prop.databaseState.value.autoClosed"));
+ }
+ if (standardValues.Count > 0)
+ {
+ result = new TypeConverter.StandardValuesCollection(standardValues);
+ }
+
+ return result;
+ }
+
+ public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+
+ public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
+ {
+ return true;
+ }
+ }
+
+ /////
+ ///// Helper class to provide standard values for populating drop down boxes on
+ ///// properties displayed in the Properties Grid
+ /////
+ //internal class DynamicValuesConverter : StringConverter
+ //{
+ // ///
+ // /// This method returns a list of dynamic values
+ // /// for various Properties in this class.
+ // ///
+ // ///
+ // /// List of Database Status Types
+ // public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
+ // {
+ // var standardValues = new List