diff --git a/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/AzureSqlDbHelper.cs b/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/AzureSqlDbHelper.cs
index ceff06d8..49b1dd2b 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/AzureSqlDbHelper.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/AzureSqlDbHelper.cs
@@ -6,35 +6,94 @@
#nullable disable
using System;
-using System.Linq;
using System.Collections.Generic;
-using Microsoft.SqlServer.Management.Common;
+using System.Diagnostics;
+using System.Linq;
using Microsoft.SqlTools.ServiceLayer.Management;
-using SizeUnits = Microsoft.SqlTools.ServiceLayer.Management.DbSize.SizeUnits;
+using static Microsoft.SqlTools.ServiceLayer.Management.DbSize;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
public static class AzureSqlDbHelper
{
-
- ///
- /// Registry sub key for the AzureServiceObjectives overrides
- ///
- private const string AzureServiceObjectivesRegSubKey = @"AzureServiceObjectives";
-
///
/// Contains the various editions available for an Azure Database
+ /// The implementation is opaque to consumers
///
- /// ****IMPORTANT**** - If updating this enum make sure that the other logic in this class is updated as well
- public enum AzureEdition
+ [DebuggerDisplay("{Name,nq}")]
+ public class AzureEdition
{
- Web = 0,
- Business = 1,
- Basic = 2,
- Standard = 3,
- Premium = 4,
- DataWarehouse = 5,
- PremiumRS = 6
+ public static readonly AzureEdition Basic = new AzureEdition("Basic", "SR.BasicAzureEdition");
+ public static readonly AzureEdition Standard = new AzureEdition("Standard", "SR.StandardAzureEdition");
+ public static readonly AzureEdition Premium = new AzureEdition("Premium", "SR.PremiumAzureEdition");
+ public static readonly AzureEdition DataWarehouse = new AzureEdition("DataWarehouse", "SR.DataWarehouseAzureEdition");
+ public static readonly AzureEdition GeneralPurpose = new AzureEdition("GeneralPurpose", "SR.GeneralPurposeAzureEdition");
+ public static readonly AzureEdition BusinessCritical = new AzureEdition("BusinessCritical", "SR.BusinessCriticalAzureEdition");
+
+ public static readonly AzureEdition Hyperscale = new AzureEdition("Hyperscale", "SR.HyperscaleAzureEdition");
+ // Free does not offer DatabaseSize >=1GB, hence it's not "supported".
+ //public static readonly AzureEdition Free = new AzureEdition("Free", SR.FreeAzureEdition);
+ // Stretch and system do not seem to be applicable, so I'm commenting them out
+ //public static readonly AzureEdition Stretch = new AzureEdition("Stretch", SR.StretchAzureEdition);
+ //public static readonly AzureEdition System = new AzureEdition("System", SR.SystemAzureEdition);
+
+ internal string Name { get; private set; }
+ internal string DisplayName { get; private set; }
+
+ internal AzureEdition(string name, string displayName)
+ {
+ Name = name;
+ DisplayName = displayName;
+ }
+
+ public override int GetHashCode()
+ {
+ return Name.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is AzureEdition && ((AzureEdition)obj).Name.Equals(Name);
+ }
+
+ public static bool operator ==(AzureEdition left, AzureEdition right)
+ {
+ return ReferenceEquals(left, right) || ((object)left != null && left.Equals(right));
+ }
+
+ public static bool operator !=(AzureEdition left, AzureEdition right)
+ {
+ return !(left == right);
+ }
+
+ public override string ToString()
+ {
+ return Name;
+ }
+ }
+
+ ///
+ /// Given a string, returns the matching AzureEdition instance.
+ ///
+ ///
+ ///
+ public static AzureEdition AzureEditionFromString(string edition)
+ {
+ var azureEdition =
+ AzureServiceObjectiveInfo.Keys.FirstOrDefault(
+ key => key.Name.ToLowerInvariant().Equals(edition.ToLowerInvariant()));
+ if (azureEdition != null)
+ {
+ return azureEdition;
+ }
+ if (edition.Contains('\''))
+ {
+ throw new ArgumentException("ErrorInvalidEdition");
+ }
+ // we don't know what it is but Azure lets you send any value you want
+ // including an empty string
+ return new AzureEdition(edition.ToLowerInvariant(), edition);
+
}
///
@@ -45,47 +104,26 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
>
{
{
- 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
+ AzureEdition.Basic,
+ new KeyValuePair(
+ 4, //2GB
new[]
{
new DbSize(100, SizeUnits.MB),
+ new DbSize(250, SizeUnits.MB),
new DbSize(500, SizeUnits.MB),
new DbSize(1, SizeUnits.GB),
- new DbSize(2, SizeUnits.GB) //Default
+ new DbSize(2, SizeUnits.GB),
})
},
{
AzureEdition.Standard,
new KeyValuePair(
- 13, //250GB
+ 14, //250GB
new[]
{
new DbSize(100, SizeUnits.MB),
+ new DbSize(250, SizeUnits.MB),
new DbSize(500, SizeUnits.MB),
new DbSize(1, SizeUnits.GB),
new DbSize(2, SizeUnits.GB),
@@ -98,16 +136,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
new DbSize(100, SizeUnits.GB),
new DbSize(150, SizeUnits.GB),
new DbSize(200, SizeUnits.GB),
- new DbSize(250, SizeUnits.GB) //Default
+ new DbSize(250, SizeUnits.GB), //Default
+ new DbSize(300, SizeUnits.GB),
+ new DbSize(400, SizeUnits.GB),
+ new DbSize(500, SizeUnits.GB),
+ new DbSize(750, SizeUnits.GB),
+ new DbSize(1024, SizeUnits.GB),
})
},
{
AzureEdition.Premium,
new KeyValuePair(
- 16, //500GB
+ 17, //500GB
new[]
{
new DbSize(100, SizeUnits.MB),
+ new DbSize(250, SizeUnits.MB),
new DbSize(500, SizeUnits.MB),
new DbSize(1, SizeUnits.GB),
new DbSize(2, SizeUnits.GB),
@@ -124,6 +168,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
new DbSize(300, SizeUnits.GB),
new DbSize(400, SizeUnits.GB),
new DbSize(500, SizeUnits.GB), //Default
+ new DbSize(750, SizeUnits.GB),
new DbSize(1024, SizeUnits.GB) //Following portal to display this as GB instead of 1TB
})
},
@@ -143,23 +188,25 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
new DbSize(20480, SizeUnits.GB),
new DbSize(30720, SizeUnits.GB),
new DbSize(40960, SizeUnits.GB),
- new DbSize(51200, SizeUnits.GB)
+ new DbSize(51200, SizeUnits.GB),
+ new DbSize(61440, SizeUnits.GB),
+ new DbSize(71680, SizeUnits.GB),
+ new DbSize(81920, SizeUnits.GB),
+ new DbSize(92160, SizeUnits.GB),
+ new DbSize(102400, SizeUnits.GB),
+ new DbSize(153600, SizeUnits.GB),
+ new DbSize(204800, SizeUnits.GB),
+ new DbSize(245760, SizeUnits.GB),
+
})
},
{
- AzureEdition.PremiumRS,
+ AzureEdition.GeneralPurpose,
new KeyValuePair(
- 16, //500GB
+ 0, //32GB
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(32, SizeUnits.GB),
new DbSize(40, SizeUnits.GB),
new DbSize(50, SizeUnits.GB),
new DbSize(100, SizeUnits.GB),
@@ -168,34 +215,154 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
new DbSize(250, SizeUnits.GB),
new DbSize(300, SizeUnits.GB),
new DbSize(400, SizeUnits.GB),
- new DbSize(500, SizeUnits.GB), //Default
+ new DbSize(500, SizeUnits.GB),
+ new DbSize(750, SizeUnits.GB),
+ new DbSize(1024, SizeUnits.GB), //Following portal to display this as GB instead of 1TB
+ new DbSize(1536, SizeUnits.GB),
+ new DbSize(3072, SizeUnits.GB),
+ new DbSize(4096, SizeUnits.GB),
})
},
+ {
+ AzureEdition.BusinessCritical,
+ new KeyValuePair(
+ 0, //32GB
+ new[]
+ {
+ new DbSize(32, 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),
+ new DbSize(750, SizeUnits.GB),
+ new DbSize(1024, SizeUnits.GB), //Following portal to display this as GB instead of 1TB
+ new DbSize(1536, SizeUnits.GB),
+ new DbSize(2048, SizeUnits.GB),
+ new DbSize(4096, SizeUnits.GB)
+ })
+ },
+
+ {
+ AzureEdition.Hyperscale,
+ new KeyValuePair(0, new[] { new DbSize(0, SizeUnits.MB) })
+ },
};
///
/// 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).
+ /// can be overridden in the UI.
///
/// The key is the index of the default value for the list
///
+ /// Try to keep this data structure (particularly the default values for each SLO) in sync with
+ /// the heuristic in TryGetAzureServiceLevelObjective() in %SDXROOT%\sql\ssms\core\sqlmanagerui\src\azureservicelevelobjectiveprovider.cs
+ ///
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.Basic, new KeyValuePair(0, new string[] {"Basic"})},
+ {
+ AzureEdition.Standard,
+ new KeyValuePair(0, new[] {"S0", "S1", "S2", "S3", "S4", "S6", "S7", "S9", "S12"})
+ },
{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"})}
+ {
+ AzureEdition.DataWarehouse,
+ new KeyValuePair(3,
+ new[]
+ {
+ "DW100", "DW200", "DW300", "DW400", "DW500", "DW600", "DW1000", "DW1200", "DW1500", "DW2000",
+ "DW3000", "DW6000", "DW1000c","DW1500c","DW2000c",
+ "DW2500c","DW3000c","DW5000c","DW6000c","DW7500c",
+ "DW10000c","DW15000c","DW30000c"
+ })
+ },
+ {
+ // Added missing Vcore sku's
+ // Reference:https://docs.microsoft.com/en-us/azure/sql-database/sql-database-vcore-resource-limits-single-databases
+ AzureEdition.GeneralPurpose,
+ new KeyValuePair(6 /* Default = GP_Gen5_2 */,
+ new[]
+ {
+ "GP_Gen4_1", "GP_Gen4_2", "GP_Gen4_4", "GP_Gen4_8", "GP_Gen4_16","GP_Gen4_24",
+ "GP_Gen5_2","GP_Gen5_4","GP_Gen5_8","GP_Gen5_16","GP_Gen5_24","GP_Gen5_32","GP_Gen5_40","GP_Gen5_80"
+
+ })
+ },
+ {
+ // Added missing Vcore sku's
+ // Reference:https://docs.microsoft.com/en-us/azure/sql-database/sql-database-vcore-resource-limits-single-databases
+ AzureEdition.BusinessCritical,
+ new KeyValuePair(6 /* Default = BC_Gen5_2 */,
+ new[]
+ { "BC_Gen4_1", "BC_Gen4_2", "BC_Gen4_4", "BC_Gen4_8", "BC_Gen4_16","BC_Gen4_24",
+ "BC_Gen5_2","BC_Gen5_4","BC_Gen5_8","BC_Gen5_16","BC_Gen5_24", "BC_Gen5_32", "BC_Gen5_40","BC_Gen5_80"
+ })
+ },
+ {
+ // HS_Gen5_2 is the default since, as of 2/25/2020, customers, unless on an allowed list, are already prevented from choosing Gen4.
+ AzureEdition.Hyperscale,
+ new KeyValuePair(11, new[] {
+ "HS_Gen4_1", "HS_Gen4_2", "HS_Gen4_3", "HS_Gen4_4", "HS_Gen4_5", "HS_Gen4_6", "HS_Gen4_7", "HS_Gen4_8", "HS_Gen4_9", "HS_Gen4_10",
+ "HS_Gen4_24", "HS_Gen5_2", "HS_Gen5_4", "HS_Gen5_6", "HS_Gen5_8", "HS_Gen5_10", "HS_Gen5_14", "HS_Gen5_16", "HS_Gen5_18", "HS_Gen5_20",
+ "HS_Gen5_24", "HS_Gen5_32", "HS_Gen5_40", "HS_Gen5_80"
+ })
+ }
};
- ///
- /// 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()
+ //Supported BackupStorageRedundancy doc link:https://docs.microsoft.com/en-us/sql/t-sql/statements/create-database-transact-sql?view=azuresqldb-current&tabs=sqlpool
+ private static readonly Dictionary bsrAPIToUIValueMapping = new Dictionary()
{
+ { "GRS", "Geo" },
+ { "LRS", "Local" },
+ { "ZRS", "Zone" }
+ };
+
+ //KeyValuePair contains the BackupStorageRedundancy values for all azure editions.
+ private static readonly KeyValuePair keyValuePair = new KeyValuePair(0, bsrAPIToUIValueMapping.Values.ToArray());
+ private static readonly Dictionary> AzureBackupStorageRedundancy = new Dictionary
+ >
+ {
+ {
+ AzureEdition.Basic, keyValuePair
+ },
+ {
+ AzureEdition.Standard, keyValuePair
+ },
+ {
+ AzureEdition.Premium, keyValuePair
+ },
+ {
+ AzureEdition.DataWarehouse, keyValuePair
+ },
+ {
+ AzureEdition.GeneralPurpose, keyValuePair
+ },
+ {
+ AzureEdition.BusinessCritical, keyValuePair
+ },
+ {
+ AzureEdition.Hyperscale, keyValuePair
+ }
+ };
+
+ ///
+ /// Get the storageAccount Type string value from the dictionary backupStorageTypes.
+ ///
+ /// Current StorageAccountType
+ /// StorageAccountType string value for the current storageType
+ public static string GetStorageAccountTypeFromString(string storageAccountType)
+ {
+ if (bsrAPIToUIValueMapping.ContainsKey(storageAccountType))
+ {
+ return bsrAPIToUIValueMapping[storageAccountType];
+ }
+ return storageAccountType;
}
///
@@ -240,6 +407,25 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
return false;
}
+ ///
+ /// Get the backupStorageRedundancy value for the given azure edition.
+ ///
+ /// Azure Edition
+ /// Supported BackupStorageRedundancy value
+ /// backupStorageRedundancy value for the given azure edition
+ public static bool TryGetBackupStorageRedundancy(AzureEdition edition,
+ out KeyValuePair backupStorageRedundancy)
+ {
+ if (AzureBackupStorageRedundancy.TryGetValue(edition, out backupStorageRedundancy))
+ {
+ return true;
+ }
+
+ backupStorageRedundancy = new KeyValuePair(-1, new string[0]);
+
+ return false;
+ }
+
///
/// Gets the default database size for a specified Azure Edition
///
@@ -270,7 +456,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
KeyValuePair pair;
- if (AzureServiceObjectiveInfo.TryGetValue(edition, out pair))
+ if (TryGetServiceObjectiveInfo(edition, out pair))
{
//Bounds check since this value can be entered by users
if (pair.Key >= 0 && pair.Key < pair.Value.Length)
@@ -282,6 +468,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
return defaultServiceObjective;
}
+ public static string GetDefaultBackupStorageRedundancy(AzureEdition edition)
+ {
+ string defaultBackupStorageRedundancy = "";
+
+ KeyValuePair pair;
+
+ if (TryGetBackupStorageRedundancy(edition, out pair))
+ {
+ //Bounds check since this value can be entered by users
+ if (pair.Key >= 0 && pair.Key < pair.Value.Length)
+ {
+ defaultBackupStorageRedundancy = pair.Value[pair.Key];
+ }
+ }
+
+ return defaultBackupStorageRedundancy;
+ }
+
///
/// Gets the localized Azure Edition display name
///
@@ -289,82 +493,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
///
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;
+ return edition.DisplayName;
}
///
- /// Parses a display name back into its corresponding AzureEdition.
+ /// Parses a display name back into its corresponding AzureEdition.
+ /// If it doesn't match a known edition, returns one whose Name is a lowercase version of the
+ /// given displayName
///
///
///
/// 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;
+ edition = AzureServiceObjectiveInfo.Keys.FirstOrDefault(key => key.DisplayName.Equals(displayName)) ??
+ AzureEditionFromString(displayName);
+ return true;
}
///
@@ -374,23 +518,18 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// 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)
+ public static IEnumerable GetValidAzureEditionOptions(object unused)
{
- //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();
+ yield return AzureEdition.Basic;
+ yield return AzureEdition.Standard;
+ yield return AzureEdition.Premium;
+ yield return AzureEdition.DataWarehouse;
+ yield return AzureEdition.BusinessCritical;
+ yield return AzureEdition.GeneralPurpose;
+ //yield return AzureEdition.Free;
+ yield return AzureEdition.Hyperscale;
+ //yield return AzureEdition.Stretch;
+ //yield return AzureEdition.System;
}
}
}
diff --git a/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/CreateDatabaseObjects.cs b/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/CreateDatabaseObjects.cs
index 58508b07..d894a272 100644
--- a/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/CreateDatabaseObjects.cs
+++ b/src/Microsoft.SqlTools.ServiceLayer/Admin/Database/CreateDatabaseObjects.cs
@@ -6,16 +6,16 @@
#nullable disable
using System;
+using System.Collections.Generic;
using System.ComponentModel;
-using System.Resources;
using System.Data;
using System.IO;
+using System.Resources;
using Microsoft.SqlServer.Management.Common;
-using Microsoft.SqlServer.Management.Smo;
-using Smo = Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
-using System.Collections.Generic;
+using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Management;
+using Smo = Microsoft.SqlServer.Management.Smo;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
@@ -56,6 +56,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
public string name;
public bool isReadOnly;
public bool isDefault;
+ public bool isAutogrowAllFiles;
public FileGroupType fileGroupType = FileGroupType.RowsFileGroup;
///
@@ -66,17 +67,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
this.name = String.Empty;
this.isReadOnly = false;
this.isDefault = false;
+ this.isAutogrowAllFiles = false;
}
///
/// Creates an instance of FilegroupData
///
public FilegroupData(FileGroupType fileGroupType)
+ : this(name: String.Empty, isReadOnly: false, isDefault: false, fileGroupType: fileGroupType, isAutogrowAllFiles: false)
{
- this.name = String.Empty;
- this.isReadOnly = false;
- this.isDefault = false;
- this.fileGroupType = fileGroupType;
}
///
@@ -87,10 +86,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// Default filegroup or not
/// FileGroupType
public FilegroupData(string name, bool isReadOnly, bool isDefault, FileGroupType fileGroupType)
+ : this(name, isReadOnly, isDefault, fileGroupType, isAutogrowAllFiles: false)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the FilegroupData class.
+ ///
+ /// filegroup name
+ /// Readonly or not
+ /// Default filegroup or not
+ /// FileGroupType
+ /// Autogrow all files enabled or not
+ public FilegroupData(string name, bool isReadOnly, bool isDefault, FileGroupType fileGroupType, bool isAutogrowAllFiles)
{
this.name = name;
this.isReadOnly = isReadOnly;
this.isDefault = isDefault;
+ this.isAutogrowAllFiles = isAutogrowAllFiles;
this.fileGroupType = fileGroupType;
}
@@ -99,11 +112,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
///
///
public FilegroupData(FilegroupData other)
+ : this(other.name, other.isReadOnly, other.isDefault, other.fileGroupType, other.isAutogrowAllFiles)
{
- this.name = other.name;
- this.isReadOnly = other.isReadOnly;
- this.isDefault = other.isDefault;
- this.fileGroupType = other.fileGroupType;
}
///
@@ -135,6 +145,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
set
{
+ System.Diagnostics.Debug.Assert(!this.Exists, "can't rename existing filegroups");
if (!this.Exists)
{
string oldname = this.currentState.name;
@@ -178,6 +189,23 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
}
+ ///
+ /// Whether the filegroup has AUTOGROW_ALL_FILES enabled
+ ///
+ public bool IsAutogrowAllFiles
+ {
+ get { return this.currentState.isAutogrowAllFiles; }
+
+ set
+ {
+ if (this.currentState.isAutogrowAllFiles != value)
+ {
+ this.currentState.isAutogrowAllFiles = value;
+ this.parent.NotifyObservers();
+ }
+ }
+ }
+
///
/// Whether the filegroup is of filestream type
///
@@ -268,13 +296,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
///
///
public FilegroupPrototype(DatabasePrototype parent, FileGroupType filegroupType)
+ : this(parent: parent,
+ name: String.Empty,
+ isReadOnly: false,
+ isDefault: false,
+ filegroupType: filegroupType,
+ exists: false,
+ isAutogrowAllFiles: false)
{
- this.originalState = new FilegroupData(filegroupType);
- this.currentState = this.originalState.Clone();
- this.parent = parent;
-
- this.filegroupExists = false;
- this.removed = false;
}
///
@@ -288,8 +317,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// filegroup exists or not
public FilegroupPrototype(DatabasePrototype parent, string name, bool isReadOnly, bool isDefault,
FileGroupType filegroupType, bool exists)
+ : this(parent, name, isReadOnly, isDefault, filegroupType, exists, isAutogrowAllFiles: false)
{
- this.originalState = new FilegroupData(name, isReadOnly, isDefault, filegroupType);
+ }
+
+ ///
+ /// 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
+ /// is autogrow all files enabled or not
+ public FilegroupPrototype(DatabasePrototype parent, string name, bool isReadOnly, bool isDefault,
+ FileGroupType filegroupType, bool exists, bool isAutogrowAllFiles)
+ {
+ this.originalState = new FilegroupData(name, isReadOnly, isDefault, filegroupType, isAutogrowAllFiles);
this.currentState = this.originalState.Clone();
this.parent = parent;
@@ -321,7 +366,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
fg = db.FileGroups[this.Name];
}
else
- {
+ {
fg = new FileGroup(db, this.Name, this.FileGroupType);
db.FileGroups.Add(fg);
}
@@ -332,6 +377,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
filegroupChanged = true;
}
+ if (fg.IsSupportedProperty("AutogrowAllFiles") &&
+ (!this.Exists || (fg.AutogrowAllFiles != this.IsAutogrowAllFiles)))
+ {
+ fg.AutogrowAllFiles = this.IsAutogrowAllFiles;
+ filegroupChanged = true;
+ }
+
if (this.Exists && filegroupChanged)
{
fg.Alter();
@@ -352,7 +404,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
!this.Exists ||
this.Removed ||
(this.originalState.isDefault != this.currentState.isDefault) ||
- (this.originalState.isReadOnly != this.currentState.isReadOnly));
+ (this.originalState.isReadOnly != this.currentState.isReadOnly) ||
+ (this.originalState.isAutogrowAllFiles != this.currentState.isAutogrowAllFiles));
return result;
}
@@ -570,7 +623,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (FileGrowthType.Percent == file.GrowthType)
{
this.isGrowthInPercent = true;
- this.growthInPercent = (int) file.Growth;
+ this.growthInPercent = (int)file.Growth;
this.growthInKilobytes = 10240.0;
// paranoia - make sure percent amount is greater than 1
@@ -642,7 +695,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (FileGrowthType.Percent == fileGrowthType)
{
this.isGrowthInPercent = true;
- this.growthInPercent = (int) file.Growth;
+ this.growthInPercent = (int)file.Growth;
this.growthInKilobytes = 10240.0;
// paranoia - make sure percent amount is greater than 1
@@ -1020,9 +1073,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
set
{
+ System.Diagnostics.Debug.Assert(!this.Exists, "Can't change the filegroup of an existing file.");
+
if ((FileType.Data == this.currentState.fileType ||
FileType.FileStream == this.currentState.fileType) && !this.Exists && (value != null))
{
+ if (this.IsPrimaryFile && (value != null))
+ {
+ System.Diagnostics.Debug.Assert(value.Name == "PRIMARY", "Primary file must belong to primary filegroup");
+ }
+
if (this.currentState.filegroup != null)
{
this.currentState.filegroup.OnFileGroupDeletedHandler -=
@@ -1079,6 +1139,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
set
{
+ if (value == true)
+ {
+ System.Diagnostics.Debug.Assert(FileGroup.Name == "PRIMARY", "Primary file must belong to primary filegroup");
+ }
+
this.currentState.isPrimaryFile = value;
this.database.NotifyObservers();
}
@@ -1310,6 +1375,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// The database from which the file is to be removed
private void RemoveFile(Database db)
{
+ System.Diagnostics.Debug.Assert(this.Removed, "We're removing a file we arn't supposed to remove");
+
if (this.Exists)
{
if (FileType.Log == this.DatabaseFileType)
@@ -1404,7 +1471,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (this.Autogrowth.IsGrowthInPercent)
{
file.GrowthType = FileGrowthType.Percent;
- file.Growth = (double) this.Autogrowth.GrowthInPercent;
+ file.Growth = (double)this.Autogrowth.GrowthInPercent;
}
else
{
@@ -1436,7 +1503,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (this.currentState.autogrowth.IsGrowthInPercent)
{
newFileGrowthType = FileGrowthType.Percent;
- newGrowth = (double) this.currentState.autogrowth.GrowthInPercent;
+ newGrowth = (double)this.currentState.autogrowth.GrowthInPercent;
}
else
{
@@ -1455,7 +1522,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (this.originalState.autogrowth.IsGrowthInPercent)
{
originalFileGrowthType = FileGrowthType.Percent;
- originalGrowth = (double) this.originalState.autogrowth.GrowthInPercent;
+ originalGrowth = (double)this.originalState.autogrowth.GrowthInPercent;
}
else
{
@@ -1628,7 +1695,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (this.Autogrowth.IsGrowthInPercent)
{
file.GrowthType = FileGrowthType.Percent;
- file.Growth = (double) this.Autogrowth.GrowthInPercent;
+ file.Growth = (double)this.Autogrowth.GrowthInPercent;
}
else
{
@@ -1660,7 +1727,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (this.currentState.autogrowth.IsGrowthInPercent)
{
newFileGrowthType = FileGrowthType.Percent;
- newGrowth = (double) this.currentState.autogrowth.GrowthInPercent;
+ newGrowth = (double)this.currentState.autogrowth.GrowthInPercent;
}
else
{
@@ -1679,7 +1746,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (this.originalState.autogrowth.IsGrowthInPercent)
{
originalFileGrowthType = FileGrowthType.Percent;
- originalGrowth = (double) this.originalState.autogrowth.GrowthInPercent;
+ originalGrowth = (double)this.originalState.autogrowth.GrowthInPercent;
}
else
{
@@ -1764,12 +1831,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
else
{
+ System.Diagnostics.Debug.Assert(false,
+ "Client must set the ConnectionInfo property of the CDataContainer passed to the DatabasePrototype constructor");
+ // $CONSIDER throwing an exception here.
connectionInfo = context.ConnectionInfo;
}
// get default data file size
request.Urn = "Server/Database[@Name='model']/FileGroup[@Name='PRIMARY']/File";
- request.Fields = new String[1] {"Size"};
+ request.Fields = new String[1] { "Size" };
try
{
@@ -1781,8 +1851,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
defaultDataFileSize = DatabaseFilePrototype.RoundUpToNearestMegabyte(size);
}
- catch (Exception)
+ catch (Exception ex)
{
+ System.Diagnostics.Trace.TraceError(ex.Message);
// user doesn't have access to model so we set the default size
// to be 5 MB
defaultDataFileSize = 5120.0;
@@ -1790,7 +1861,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
// get default log file size
request.Urn = "Server/Database[@Name='model']/LogFile";
- request.Fields = new String[1] {"Size"};
+ request.Fields = new String[1] { "Size" };
try
{
@@ -1799,8 +1870,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
defaultLogFileSize = DatabaseFilePrototype.RoundUpToNearestMegabyte(size);
}
- catch (Exception)
+ catch (Exception ex)
{
+ System.Diagnostics.Trace.TraceError(ex.Message);
+
// user doesn't have access to model so we set the default size
// to be 1MB
defaultLogFileSize = 1024.0;
@@ -1808,7 +1881,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
// get default data and log folders
request.Urn = "Server/Setting";
- request.Fields = new String[] {"DefaultFile", "DefaultLog"};
+ request.Fields = new String[] { "DefaultFile", "DefaultLog" };
try
{
@@ -1819,7 +1892,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (defaultDataFolder.Length == 0 || defaultLogFolder.Length == 0)
{
request.Urn = "Server/Information";
- request.Fields = new string[] {"MasterDBPath", "MasterDBLogPath"};
+ request.Fields = new string[] { "MasterDBPath", "MasterDBLogPath" };
fileInfo = enumerator.Process(connectionInfo, request);
if (defaultDataFolder.Length == 0)
@@ -1858,8 +1931,9 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
rest);
}
}
- catch (Exception)
+ catch (Exception ex)
{
+ System.Diagnostics.Trace.TraceError(ex.Message);
}
}
@@ -1899,7 +1973,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (defaultDataAutogrowth.IsGrowthInPercent)
{
- defaultDataAutogrowth.GrowthInPercent = (int) datafile.Growth;
+ defaultDataAutogrowth.GrowthInPercent = (int)datafile.Growth;
defaultDataAutogrowth.GrowthInMegabytes = 10;
}
else
@@ -1945,7 +2019,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
if (defaultLogAutogrowth.IsGrowthInPercent)
{
- defaultLogAutogrowth.GrowthInPercent = (int) logfile.Growth;
+ defaultLogAutogrowth.GrowthInPercent = (int)logfile.Growth;
defaultLogAutogrowth.GrowthInMegabytes = 10;
}
else
@@ -2001,7 +2075,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
///
///
private void OnFilegroupDeleted(object sender, FilegroupDeletedEventArgs e)
- {
+ {
+ System.Diagnostics.Debug.Assert(this.FileGroup == sender, "received filegroup deleted notification from wrong filegroup");
e.DeletedFilegroup.OnFileGroupDeletedHandler -= new FileGroupDeletedEventHandler(OnFilegroupDeleted);
// SQL Server deletes all the files in a filegroup when the filegroup is removed
@@ -2021,7 +2096,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// The proposed file name to check
private void CheckFileName(string fileName)
{
- char[] badFileCharacters = new char[] {'\\', '/', ':', '*', '?', '\"', '<', '>', '|'};
+ char[] badFileCharacters = new char[] { '\\', '/', ':', '*', '?', '\"', '<', '>', '|' };
bool isAllWhitespace = (fileName.Trim(null).Length == 0);
@@ -2043,6 +2118,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
else
{
int i = fileName.IndexOfAny(badFileCharacters);
+ System.Diagnostics.Debug.Assert(-1 < i, "unexpected error type");
message = String.Format(System.Globalization.CultureInfo.CurrentCulture,
resourceManager.GetString("error_fileNameContainsIllegalCharacter"), fileName, fileName[i]);
@@ -2059,7 +2135,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// The equivalent number of megabytes
internal static int KilobytesToMegabytes(double kilobytes)
{
- return (int) Math.Ceiling(kilobytes/kilobytesPerMegabyte);
+ return (int)Math.Ceiling(kilobytes / kilobytesPerMegabyte);
}
///
@@ -2069,7 +2145,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// The equivalent number of kilobytes
internal static double MegabytesToKilobytes(int megabytes)
{
- return (((double) megabytes)*kilobytesPerMegabyte);
+ return (((double)megabytes) * kilobytesPerMegabyte);
}
///
@@ -2080,8 +2156,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// The number of kb in the next larger mb
internal static double RoundUpToNearestMegabyte(double kilobytes)
{
- double megabytes = Math.Ceiling(kilobytes/kilobytesPerMegabyte);
- return (megabytes*kilobytesPerMegabyte);
+ double megabytes = Math.Ceiling(kilobytes / kilobytesPerMegabyte);
+ return (megabytes * kilobytesPerMegabyte);
}
///
@@ -2112,6 +2188,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// If logical name is empty, or physical name is invalid.
private string MakeDiskFileName(string logicalName, string preferredPhysicalName, string suffix)
{
+ System.Diagnostics.Debug.Assert(logicalName != null, "unexpected param - logical name cannot be null");
+ System.Diagnostics.Debug.Assert(suffix != null, "unexpected param - suffix cannot be null. Pass String.Empty instead.");
ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
string filePath = String.Empty; // returned to the caller.
@@ -2132,6 +2210,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
string message = String.Empty;
message = resourceManager.GetString("error_emptyFileName");
+ System.Diagnostics.Debug.Assert(message != null, "unexpected error string missing.");
throw new InvalidOperationException(message);
}
@@ -2266,7 +2345,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
ResourceManager resourceManager =
new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
- typeof (DatabaseAlreadyExistsException).GetAssembly());
+ typeof(DatabaseAlreadyExistsException).Assembly);
format = resourceManager.GetString("error.databaseAlreadyExists");
}
@@ -2288,7 +2367,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
ResourceManager manager =
new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
- typeof (DatabasePrototype).GetAssembly());
+ typeof(DatabasePrototype).Assembly);
List standardValues = null;
TypeConverter.StandardValuesCollection result = null;
@@ -2331,7 +2410,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
ResourceManager manager =
new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
- typeof (DatabasePrototype90).GetAssembly());
+ typeof(DatabasePrototype90).Assembly);
List standardValues = new List();
TypeConverter.StandardValuesCollection result = null;
@@ -2373,7 +2452,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
ResourceManager manager =
new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
- typeof (DatabasePrototype80).GetAssembly());
+ typeof(DatabasePrototype80).Assembly);
List standardValues = new List();
TypeConverter.StandardValuesCollection result = null;
@@ -2417,7 +2496,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
ResourceManager manager =
new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
- typeof (DatabasePrototype80).GetAssembly());
+ typeof(DatabasePrototype80).Assembly);
List standardValues = new List();
TypeConverter.StandardValuesCollection result = null;
@@ -2501,7 +2580,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
ResourceManager manager =
new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
- typeof (DatabasePrototype).GetAssembly());
+ typeof(DatabasePrototype).Assembly);
List standardValues = new List();
TypeConverter.StandardValuesCollection result = null;
@@ -2539,176 +2618,4 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
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