User management support classes (#1856)

* WIP

* Fix nullable warnings in UserData class

* WIP2

* WIP

* Refresh database prototype classes

* Fix some typos & merge issues

* WIP

* WIP

* WIP

* Additional updates

* Remove unneded using
This commit is contained in:
Karl Burtram
2023-02-08 18:02:08 -08:00
committed by GitHub
parent ee086e2067
commit 2ef5f0918a
24 changed files with 3584 additions and 1336 deletions

View File

@@ -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
{
/// <summary>
/// Registry sub key for the AzureServiceObjectives overrides
/// </summary>
private const string AzureServiceObjectivesRegSubKey = @"AzureServiceObjectives";
/// <summary>
/// Contains the various editions available for an Azure Database
/// The implementation is opaque to consumers
/// </summary>
/// ****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;
}
}
/// <summary>
/// Given a string, returns the matching AzureEdition instance.
/// </summary>
/// <param name="edition"></param>
/// <returns></returns>
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);
}
/// <summary>
@@ -45,47 +104,26 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
<AzureEdition, KeyValuePair<int, DbSize[]>>
{
{
AzureEdition.Web, new KeyValuePair<int, DbSize[]>(
1, //1GB
new[]
{
new DbSize(100, SizeUnits.MB),
new DbSize(1, SizeUnits.GB), //Default
new DbSize(5, SizeUnits.GB)
})
},
{
AzureEdition.Business, new KeyValuePair<int, DbSize[]>(
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<int, DbSize[]>(
3, //2GB
AzureEdition.Basic,
new KeyValuePair<int, DbSize[]>(
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<int, DbSize[]>(
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<int, DbSize[]>(
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<int, DbSize[]>(
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<int, DbSize[]>(
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<int, DbSize[]>(0, new[] { new DbSize(0, SizeUnits.MB) })
},
};
/// <summary>
/// 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
/// </summary>
/// <remarks>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
/// </remarks>
private static readonly Dictionary<AzureEdition, KeyValuePair<int, string[]>> AzureServiceObjectiveInfo = new Dictionary
<AzureEdition, KeyValuePair<int, string[]>>
{
{AzureEdition.Basic, new KeyValuePair<int, string[]>(0, new[] {"Basic"})},
{AzureEdition.Standard, new KeyValuePair<int, string[]>(2, new[] {"S0", "S1", "S2", "S3"})},
{AzureEdition.Basic, new KeyValuePair<int, string[]>(0, new string[] {"Basic"})},
{
AzureEdition.Standard,
new KeyValuePair<int, string[]>(0, new[] {"S0", "S1", "S2", "S3", "S4", "S6", "S7", "S9", "S12"})
},
{AzureEdition.Premium, new KeyValuePair<int, string[]>(0, new[] {"P1", "P2", "P4", "P6", "P11", "P15"})},
{AzureEdition.PremiumRS, new KeyValuePair<int, string[]>(0, new []{"PRS1", "PRS2", "PRS4", "PRS6"})},
{AzureEdition.DataWarehouse, new KeyValuePair<int, string[]>(3, new[] {"DW100", "DW200", "DW300", "DW400", "DW500", "DW600", "DW1000", "DW1200", "DW1500", "DW2000", "DW3000", "DW6000"})}
{
AzureEdition.DataWarehouse,
new KeyValuePair<int, string[]>(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<int, string[]>(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<int, string[]>(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<int, string[]>(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"
})
}
};
/// <summary>
/// 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.
/// </summary>
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<string, string> bsrAPIToUIValueMapping = new Dictionary<string, string>()
{
{ "GRS", "Geo" },
{ "LRS", "Local" },
{ "ZRS", "Zone" }
};
//KeyValuePair contains the BackupStorageRedundancy values for all azure editions.
private static readonly KeyValuePair<int, string[]> keyValuePair = new KeyValuePair<int, string[]>(0, bsrAPIToUIValueMapping.Values.ToArray());
private static readonly Dictionary<AzureEdition, KeyValuePair<int, string[]>> AzureBackupStorageRedundancy = new Dictionary
<AzureEdition, KeyValuePair<int, string[]>>
{
{
AzureEdition.Basic, keyValuePair
},
{
AzureEdition.Standard, keyValuePair
},
{
AzureEdition.Premium, keyValuePair
},
{
AzureEdition.DataWarehouse, keyValuePair
},
{
AzureEdition.GeneralPurpose, keyValuePair
},
{
AzureEdition.BusinessCritical, keyValuePair
},
{
AzureEdition.Hyperscale, keyValuePair
}
};
/// <summary>
/// Get the storageAccount Type string value from the dictionary backupStorageTypes.
/// </summary>
/// <param name="storageAccountType">Current StorageAccountType</param>
/// <returns>StorageAccountType string value for the current storageType</returns>
public static string GetStorageAccountTypeFromString(string storageAccountType)
{
if (bsrAPIToUIValueMapping.ContainsKey(storageAccountType))
{
return bsrAPIToUIValueMapping[storageAccountType];
}
return storageAccountType;
}
/// <summary>
@@ -240,6 +407,25 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
return false;
}
/// <summary>
/// Get the backupStorageRedundancy value for the given azure edition.
/// </summary>
/// <param name="edition">Azure Edition</param>
/// <param name="backupStorageRedundancy">Supported BackupStorageRedundancy value</param>
/// <returns>backupStorageRedundancy value for the given azure edition</returns>
public static bool TryGetBackupStorageRedundancy(AzureEdition edition,
out KeyValuePair<int, string[]> backupStorageRedundancy)
{
if (AzureBackupStorageRedundancy.TryGetValue(edition, out backupStorageRedundancy))
{
return true;
}
backupStorageRedundancy = new KeyValuePair<int, string[]>(-1, new string[0]);
return false;
}
/// <summary>
/// Gets the default database size for a specified Azure Edition
/// </summary>
@@ -270,7 +456,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
KeyValuePair<int, string[]> 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<int, string[]> 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;
}
/// <summary>
/// Gets the localized Azure Edition display name
/// </summary>
@@ -289,82 +493,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <returns></returns>
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;
}
/// <summary>
/// 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
/// </summary>
/// <param name="displayName"></param>
/// <param name="edition"></param>
/// <returns>TRUE if the conversion succeeded, FALSE if it did not. </returns>
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;
}
/// <summary>
@@ -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.
/// <returns></returns>
public static IEnumerable<AzureEdition> GetValidAzureEditionOptions(ServerVersion version)
public static IEnumerable<AzureEdition> GetValidAzureEditionOptions(object unused)
{
//Azure v12 and above doesn't have the Web and Business tiers
if (version.Major >= 12)
{
return new List<AzureEdition>()
{
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<AzureEdition>();
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;
}
}
}

View File

@@ -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;
/// <summary>
@@ -66,17 +67,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
this.name = String.Empty;
this.isReadOnly = false;
this.isDefault = false;
this.isAutogrowAllFiles = false;
}
/// <summary>
/// Creates an instance of FilegroupData
/// </summary>
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;
}
/// <summary>
@@ -87,10 +86,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <param name="isDefault">Default filegroup or not</param>
/// <param name="fileGroupType">FileGroupType</param>
public FilegroupData(string name, bool isReadOnly, bool isDefault, FileGroupType fileGroupType)
: this(name, isReadOnly, isDefault, fileGroupType, isAutogrowAllFiles: false)
{
}
/// <summary>
/// Initializes a new instance of the FilegroupData class.
/// </summary>
/// <param name="name">filegroup name</param>
/// <param name="isReadOnly">Readonly or not</param>
/// <param name="isDefault">Default filegroup or not</param>
/// <param name="fileGroupType">FileGroupType</param>
/// <param name="isAutogrowAllFiles">Autogrow all files enabled or not</param>
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
/// </summary>
/// <param name="other"></param>
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;
}
/// <summary>
@@ -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
}
}
/// <summary>
/// Whether the filegroup has AUTOGROW_ALL_FILES enabled
/// </summary>
public bool IsAutogrowAllFiles
{
get { return this.currentState.isAutogrowAllFiles; }
set
{
if (this.currentState.isAutogrowAllFiles != value)
{
this.currentState.isAutogrowAllFiles = value;
this.parent.NotifyObservers();
}
}
}
/// <summary>
/// Whether the filegroup is of filestream type
/// </summary>
@@ -268,13 +296,14 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <param name="parent"></param>
/// <param name="filegroupType"></param>
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;
}
/// <summary>
@@ -288,8 +317,24 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <param name="exists">filegroup exists or not</param>
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);
}
/// <summary>
/// Initializes a new instance of the FilegroupPrototype class.
/// </summary>
/// <param name="parent">instance of DatabasePrototype</param>
/// <param name="name">file group name</param>
/// <param name="isReadOnly">whether it is readonly or not</param>
/// <param name="isDefault">is default or not</param>
/// <param name="filegroupType">filegrouptype</param>
/// <param name="exists">filegroup exists or not</param>
/// <param name="isAutogrowAllFiles">is autogrow all files enabled or not</param>
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
/// <param name="db">The database from which the file is to be removed</param>
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
/// <param name="sender"></param>
/// <param name="e"></param>
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
/// <param name="fileName">The proposed file name to check</param>
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
/// <returns>The equivalent number of megabytes</returns>
internal static int KilobytesToMegabytes(double kilobytes)
{
return (int) Math.Ceiling(kilobytes/kilobytesPerMegabyte);
return (int)Math.Ceiling(kilobytes / kilobytesPerMegabyte);
}
/// <summary>
@@ -2069,7 +2145,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <returns>The equivalent number of kilobytes</returns>
internal static double MegabytesToKilobytes(int megabytes)
{
return (((double) megabytes)*kilobytesPerMegabyte);
return (((double)megabytes) * kilobytesPerMegabyte);
}
/// <summary>
@@ -2080,8 +2156,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <returns>The number of kb in the next larger mb</returns>
internal static double RoundUpToNearestMegabyte(double kilobytes)
{
double megabytes = Math.Ceiling(kilobytes/kilobytesPerMegabyte);
return (megabytes*kilobytesPerMegabyte);
double megabytes = Math.Ceiling(kilobytes / kilobytesPerMegabyte);
return (megabytes * kilobytesPerMegabyte);
}
/// <summary>
@@ -2112,6 +2188,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <exception cref="InvalidOperationException">If logical name is empty, or physical name is invalid.</exception>
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<string> 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<string> standardValues = new List<string>();
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<string> standardValues = new List<string>();
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<string> standardValues = new List<string>();
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<string> standardValues = new List<string>();
TypeConverter.StandardValuesCollection result = null;
@@ -2539,176 +2618,4 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
return true;
}
}
///// <summary>
///// Helper class to provide standard values for populating drop down boxes on
///// properties displayed in the Properties Grid
///// </summary>
//internal class DynamicValuesConverter : StringConverter
//{
// /// <summary>
// /// This method returns a list of dynamic values
// /// for various Properties in this class.
// /// </summary>
// /// <param name="context"></param>
// /// <returns>List of Database Status Types </returns>
// public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
// {
// var standardValues = new List<object>();
// StandardValuesCollection result = null;
// //Handle ServiceLevelObjective values
// if (context.PropertyDescriptor != null &&
// string.Compare(context.PropertyDescriptor.Name, "CurrentServiceLevelObjective",
// StringComparison.OrdinalIgnoreCase) == 0)
// {
// var designableObject = context.Instance as DesignableObject;
// if (designableObject != null)
// {
// var prototype = designableObject.ObjectDesigned as DatabasePrototypeAzure;
// if (prototype != null)
// {
// KeyValuePair<int, string[]> pair;
// if (AzureSqlDbHelper.TryGetServiceObjectiveInfo(prototype.AzureEdition, out pair))
// {
// standardValues.AddRange(pair.Value);
// }
// }
// }
// }
// //Handle AzureEditionDisplay values
// else if (context.PropertyDescriptor != null &&
// string.Compare(context.PropertyDescriptor.Name, "AzureEditionDisplay",
// StringComparison.OrdinalIgnoreCase) == 0)
// {
// var designableObject = context.Instance as DesignableObject;
// if (designableObject != null)
// {
// var prototype = designableObject.ObjectDesigned as DatabasePrototype;
// if (prototype != null)
// {
// foreach (
// AzureEdition edition in
// AzureSqlDbHelper.GetValidAzureEditionOptions(prototype.ServerVersion))
// {
// // We don't yet support creating DW with the UI
// if (prototype.Exists || edition != AzureEdition.DataWarehouse)
// {
// standardValues.Add(AzureSqlDbHelper.GetAzureEditionDisplayName(edition));
// }
// }
// }
// else
// {
// STrace.Assert(false,
// "DesignableObject ObjectDesigned isn't a DatabasePrototype for AzureEditionDisplay StandardValues");
// }
// }
// else
// {
// STrace.Assert(designableObject != null,
// "Context instance isn't a DesignableObject for AzureEditionDisplay StandardValues");
// }
// }
// //Handle MaxSize values
// else if (context.PropertyDescriptor != null &&
// string.Compare(context.PropertyDescriptor.Name, "MaxSize", StringComparison.OrdinalIgnoreCase) == 0)
// {
// var designableObject = context.Instance as DesignableObject;
// if (designableObject != null)
// {
// var prototype = designableObject.ObjectDesigned as DatabasePrototypeAzure;
// if (prototype != null)
// {
// KeyValuePair<int, DbSize[]> pair;
// if (AzureSqlDbHelper.TryGetDatabaseSizeInfo(prototype.AzureEdition, out pair))
// {
// standardValues.AddRange(pair.Value);
// }
// }
// }
// }
// if (standardValues.Count > 0)
// {
// result = new StandardValuesCollection(standardValues);
// }
// return result;
// }
// public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
// {
// //Tells the grid that we'll support the values to display in a drop down
// return true;
// }
// public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
// {
// //The values are exclusive (populated in a drop-down list instead of combo box)
// return true;
// }
//}
///// <summary>
///// Helper class to provide standard values for populating drop down boxes on
///// database scoped configuration properties displayed in the Properties Grid
///// </summary>
//internal class DatabaseScopedConfigurationOnOffTypes : StringConverter
//{
// /// <summary>
// /// This method returns a list of database scoped configuration on off values
// /// which will be populated as a drop down list.
// /// </summary>
// /// <param name="context"></param>
// /// <returns>Database scoped configurations which will populate the drop down list.</returns>
// public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
// {
// ResourceManager manager =
// new ResourceManager("Microsoft.SqlServer.Management.SqlManagerUI.CreateDatabaseStrings",
// typeof (DatabasePrototype).GetAssembly());
// List<string> standardValues = new List<string>();
// TypeConverter.StandardValuesCollection result = null;
// if (
// string.Compare(context.PropertyDescriptor.Name, "LegacyCardinalityEstimationDisplay",
// StringComparison.OrdinalIgnoreCase) == 0 ||
// string.Compare(context.PropertyDescriptor.Name, "ParameterSniffingDisplay",
// StringComparison.OrdinalIgnoreCase) == 0 ||
// string.Compare(context.PropertyDescriptor.Name, "QueryOptimizerHotfixesDisplay",
// StringComparison.OrdinalIgnoreCase) == 0)
// {
// standardValues.Add(manager.GetString("prototype.db.prop.databasescopedconfig.value.off"));
// standardValues.Add(manager.GetString("prototype.db.prop.databasescopedconfig.value.on"));
// }
// else
// {
// standardValues.Add(manager.GetString("prototype.db.prop.databasescopedconfig.value.off"));
// standardValues.Add(manager.GetString("prototype.db.prop.databasescopedconfig.value.on"));
// standardValues.Add(manager.GetString("prototype.db.prop.databasescopedconfig.value.primary"));
// }
// if (standardValues.Count > 0)
// {
// result = new TypeConverter.StandardValuesCollection(standardValues);
// }
// return result;
// }
// public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
// {
// //Tells the grid that we'll support the values to display in a drop down
// return true;
// }
// public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
// {
// //The values are exclusive (populated in a drop-down list instead of combo box)
// return true;
// }
//}
}

View File

@@ -273,6 +273,8 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
break;
}
System.Diagnostics.Debug.Assert(result != null && result.Length != 0, "no string found for database scoped configuration value");
return result;
}
@@ -291,11 +293,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
return DatabaseScopedConfigurationOnOff.Off;
}
else if (displayText == manager.GetString("prototype_db_prop_databasescopedconfig_value_on") || !forSecondary)
{
{
return DatabaseScopedConfigurationOnOff.On;
}
else
{
{
return DatabaseScopedConfigurationOnOff.Primary;
}
}

View File

@@ -9,6 +9,8 @@ using System.ComponentModel;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlTools.ServiceLayer.Management;
using Microsoft.SqlTools.ServiceLayer.Utility;
using Microsoft.SqlServer.Management.Common;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
@@ -50,6 +52,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
}
public LanguageChoice DefaultLanguage
{
get
{
return LanguageUtils.GetLanguageChoiceAlias(this.context.Server,
this.currentState.defaultLanguageLcid);
}
set
{
this.currentState.defaultLanguageLcid = value.lcid;
this.NotifyObservers();
}
}
[Category("Category_ContainedDatabases"),
DisplayNameAttribute("Property_NestedTriggersEnabled")]
public bool NestedTriggersEnabled
@@ -152,6 +168,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
db.DefaultFullTextLanguage.Lcid = this.DefaultFullTextLanguageLcid;
}
if (!this.Exists || (db.DefaultLanguage.Lcid != this.DefaultLanguage.lcid))
{
db.DefaultLanguage.Lcid = this.DefaultLanguage.lcid;
}
if (!this.Exists || (db.NestedTriggersEnabled != this.NestedTriggersEnabled))
{
db.NestedTriggersEnabled = this.NestedTriggersEnabled;
@@ -185,5 +206,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
}
}
int Lcid
{
get { return this.DefaultLanguage.lcid; }
}
ServerConnection Connection
{
get { return this.context.ServerConnection; }
}
}
}

View File

@@ -0,0 +1,77 @@
//
// 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.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Management;
using System;
using System.ComponentModel;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database properties for SqlServer 2017
/// </summary>
internal class DatabasePrototype140 : DatabasePrototype110
{
/// <summary>
/// Database properties for SqlServer 2017 class constructor
/// </summary>
public DatabasePrototype140(CDataContainer context)
: base(context)
{
}
/// <summary>
/// Whether or not the UI should show File Groups
/// </summary>
public override bool HideFileSettings
{
get
{
return (this.context != null && this.context.Server != null && (this.context.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlManagedInstance || this.context.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlOnDemand));
}
}
/// <summary>
/// The recovery model for the database
/// </summary>
[Browsable(false)]
public override RecoveryModel RecoveryModel
{
get
{
if (this.context != null &&
this.context.Server != null &&
this.context.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlManagedInstance)
{
return RecoveryModel.Full;
}
else
{
return this.currentState.recoveryModel;
}
}
set
{
if (this.context != null &&
this.context.Server != null &&
this.context.Server.DatabaseEngineEdition == DatabaseEngineEdition.SqlManagedInstance &&
value != RecoveryModel.Full)
{
System.Diagnostics.Debug.Assert(false, "Managed Instance supports only FULL recovery model!");
throw new ArgumentException("Managed Instance supports only FULL recovery model!");
}
else
{
base.RecoveryModel = value;
}
}
}
}
}

View File

@@ -0,0 +1,53 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Management;
using System.ComponentModel;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database properties for SqlServer 2022
/// </summary>
internal class DatabasePrototype160 : DatabasePrototype140
{
/// <summary>
/// Database properties for SqlServer 2022 class constructor
/// </summary>
public DatabasePrototype160(CDataContainer context)
: base(context)
{
}
[Category("Category_Ledger"),
DisplayNameAttribute("Property_IsLedgerDatabase")]
public bool IsLedger
{
get {
return this.currentState.isLedger;
}
set
{
this.currentState.isLedger = value;
this.NotifyObservers();
}
}
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
if (db.IsSupportedProperty("IsLedger"))
{
// Ledger can only be set on a new database, it is read-only after creation
if (!this.Exists)
{
db.IsLedger = this.IsLedger;
}
}
}
}
}

View File

@@ -84,7 +84,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
this.currentState.pageVerify = PageVerify.None;
}
else
{
{
this.currentState.pageVerify = PageVerify.TornPageDetection;
}

View File

@@ -11,28 +11,29 @@ using Microsoft.Data.SqlClient;
using System.Globalization;
using System.Linq;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlTools.ServiceLayer.Management;
using AzureEdition = Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper.AzureEdition;
using System;
using System.Data;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database properties for SQL Azure DB.
/// Business/Web editions are up to compat level 100 now
/// </summary>
[TypeConverter(typeof(DynamicValueTypeConverter))]
internal class DatabasePrototypeAzure : DatabasePrototype100
internal class DatabasePrototypeAzure : DatabasePrototype160
{
#region Constants
public const string Category_Azure = "Category_Azure";
public const string Category_Azure_BRS = "Category_Azure_BRS";
public const string Property_AzureMaxSize = "Property_AzureMaxSize";
public const string Property_AzureCurrentServiceLevelObjective = "Property_AzureCurrentServiceLevelObjective";
public const string Property_AzureConfiguredServiceLevelObjective = "Property_AzureConfiguredServiceLevelObjective";
public const string Property_AzureEdition = "Property_AzureEdition";
public const string Property_AzureBackupStorageRedundancy = "Property_AzureBackupStorageRedundancy";
#endregion Constants
public DatabasePrototypeAzure(CDataContainer context, DatabaseEngineEdition editionToCreate = DatabaseEngineEdition.SqlDatabase)
@@ -42,9 +43,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
#region Properties
[Category(Category_Azure),
DisplayNameAttribute(Property_AzureMaxSize)]
public string MaxSize
{
get
@@ -53,13 +52,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
set
{
this.currentState.maxSize = DbSize.ParseDbSize(value);
this.currentState.maxSize = string.IsNullOrEmpty(value) ? null : DbSize.ParseDbSize(value);
this.NotifyObservers();
}
}
[Category(Category_Azure),
DisplayNameAttribute(Property_AzureCurrentServiceLevelObjective)]
public string CurrentServiceLevelObjective
{
get
@@ -68,23 +65,15 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
set
{
if (value != null && value.Contains('\''))
{
throw new ArgumentException("Error_InvalidServiceLevelObjective");
}
this.currentState.currentServiceLevelObjective = value;
this.NotifyObservers();
}
}
[Category(Category_Azure),
DisplayNameAttribute(Property_AzureConfiguredServiceLevelObjective)]
public string ConfiguredServiceLevelObjective
{
//This value is read only because it's changed by changing the current SLO,
//we just expose this to show if the DB is currently transitioning
get
{
return this.currentState.configuredServiceLevelObjective;
}
}
[Browsable(false)]
public AzureEdition AzureEdition
{
@@ -94,35 +83,79 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
}
[Category(Category_Azure),
DisplayNameAttribute(Property_AzureEdition)]
//We have a separate property here so that the AzureEdition enum value is still exposed
//(This property is for the name displayed in the drop down menu, which needs to be a string for casting purposes)
public string AzureEditionDisplay
{
get
{
return this.currentState.azureEditionDisplayValue;
return AzureSqlDbHelper.GetAzureEditionDisplayName(this.currentState.azureEdition);
}
set
{
// TODO set from here should probably allow for the fact that System is a valid edition for
// actual system DBs. Not handling for now
AzureEdition edition;
if (AzureSqlDbHelper.TryGetAzureEditionFromDisplayName(value, out edition))
{
if (edition == this.currentState.azureEdition)
{ //No changes, return early since we don't need to do any of the changes below
return;
}
// set
// {
// AzureEdition edition;
// if (AzureSqlDbHelper.TryGetAzureEditionFromDisplayName(value, out edition))
// {
// //Try to get the ServiceLevelObjective from the api,if not the default hardcoded service level objectives will be retrieved.
// string serverLevelObjective = AzureServiceLevelObjectiveProvider.TryGetAzureServiceLevelObjective(value, AzureServiceLocation);
this.currentState.azureEdition = edition;
this.currentState.azureEditionDisplayValue = value;
this.CurrentServiceLevelObjective = AzureSqlDbHelper.GetDefaultServiceObjective(edition);
this.MaxSize = AzureSqlDbHelper.GetDatabaseDefaultSize(edition).ToString();
this.NotifyObservers();
}
}
// if (!string.IsNullOrEmpty(serverLevelObjective))
// {
// this.currentState.azureEdition = edition;
// this.currentState.currentServiceLevelObjective = serverLevelObjective;
// // Instead of creating db instance with default Edition, update EditionToCreate while selecting Edition from the UI.
// this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
// string storageAccountType = AzureServiceLevelObjectiveProvider.TryGetAzureStorageType(value, AzureServiceLocation);
// if (!string.IsNullOrEmpty(storageAccountType))
// {
// this.currentState.backupStorageRedundancy = storageAccountType;
// }
// // Try to get the azure maxsize from the api,if not the default hardcoded maxsize will be retrieved.
// DbSize dbSize = AzureServiceLevelObjectiveProvider.TryGetAzureMaxSize(value, serverLevelObjective, AzureServiceLocation);
// if (!string.IsNullOrEmpty(dbSize.ToString()))
// {
// this.currentState.maxSize = new DbSize(dbSize.Size, dbSize.SizeUnit);
// }
// }
// else
// {
// if (edition == this.currentState.azureEdition)
// { //No changes, return early since we don't need to do any of the changes below
// return;
// }
// this.currentState.azureEdition = edition;
// this.EditionToCreate = MapAzureEditionToDbEngineEdition(edition);
// this.CurrentServiceLevelObjective = AzureSqlDbHelper.GetDefaultServiceObjective(edition);
// this.BackupStorageRedundancy = AzureSqlDbHelper.GetDefaultBackupStorageRedundancy(edition);
// var defaultSize = AzureSqlDbHelper.GetDatabaseDefaultSize(edition);
// this.MaxSize = defaultSize == null ? String.Empty : defaultSize.ToString();
// }
// this.NotifyObservers();
// }
// else
// {
// //Can't really do much if we fail to parse the display name so just leave it as is and log a message
// System.Diagnostics.Debug.Assert(false,
// string.Format(CultureInfo.InvariantCulture,
// "Failed to parse edition display name '{0}' back into AzureEdition", value));
// }
// }
}
/// <summary>
/// Mapping funtion to get the Database engine edition based on the selected AzureEdition value
/// </summary>
/// <param name="edition">Selected dropdown Azure Edition value</param>
/// <returns>Corresponding DatabaseEngineEdition value</returns>
private static DatabaseEngineEdition MapAzureEditionToDbEngineEdition(AzureEdition edition)
{
// As of now we only know for sure that AzureEdition.DataWarehouse maps to
// DatabaseEngineEdition.SqlDataWarehouse, for all others we keep the default value
// as before which was 'SqlDatabase'
return edition == AzureEdition.DataWarehouse ? DatabaseEngineEdition.SqlDataWarehouse : DatabaseEngineEdition.SqlDatabase;
}
public override IList<FilegroupPrototype> Filegroups
@@ -148,6 +181,22 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
get { return this.ServerVersion.Major > 11 && this.AzureEdition != AzureEdition.DataWarehouse; }
}
// [Browsable(false)]
// public SubscriptionLocationKey AzureServiceLocation { get; set; }
public string BackupStorageRedundancy
{
get
{
return this.currentState.backupStorageRedundancy;
}
set
{
this.currentState.backupStorageRedundancy = value;
this.NotifyObservers();
}
}
#endregion Properties
#region DatabasePrototype overrides
@@ -159,69 +208,71 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <returns>The SMO database object that was created or modified</returns>
public override Database ApplyChanges()
{
// For v12 Non-DW DBs lets use SMO
if (this.ServerVersion.Major >= 12 && this.AzureEdition != AzureEdition.DataWarehouse)
{
return base.ApplyChanges();
}
//Note : We purposely don't call base.ApplyChanges() here since SMO doesn't fully support Azure yet and so will throw
//an error if we try to modify the Database object directly
string alterDbPropertiesStatement = DatabasePrototypeAzure.CreateModifyAzureDbOptionsStatement(this.Name, this.AzureEdition, this.MaxSize, this.CurrentServiceLevelObjective);
if (this.AzureEdition == AzureEdition.DataWarehouse)
{
alterDbPropertiesStatement = DatabasePrototypeAzure.CreateModifySqlDwDbOptionsStatement(this.Name, this.MaxSize, this.CurrentServiceLevelObjective);
}
string alterAzureDbRecursiveTriggersEnabledStatement = DatabasePrototypeAzure.CreateAzureDbSetRecursiveTriggersStatement(this.Name, this.RecursiveTriggers);
string alterAzureDbIsReadOnlyStatement = DatabasePrototypeAzure.CreateAzureDbSetIsReadOnlyStatement(this.Name, this.IsReadOnly);
Database db = this.GetDatabase();
//Altering the DB needs to be done on the master DB
using (var conn = new SqlConnection(this.context.ServerConnection.GetDatabaseConnection("master").ConnectionString))
{
using (var cmd = new SqlCommand())
Database database = base.ApplyChanges();
if (this.AzureEdition != AzureEdition.DataWarehouse)
{
// We don't need to alter BSR value if the user is just scripting or if the DB is not creating.
if (database != null && this.context.Server.ConnectionContext.SqlExecutionModes != SqlExecutionModes.CaptureSql)
{
cmd.Connection = conn;
conn.Open();
//Only run the alter statements for modifications made. This is mostly to allow the non-Azure specific
//properties to be updated when a SLO change is in progress, but it also is beneficial to save trips to the
//server whenever we can (especially when Azure is concerned)
if (currentState.azureEdition != originalState.azureEdition ||
currentState.currentServiceLevelObjective != originalState.currentServiceLevelObjective ||
currentState.maxSize != originalState.maxSize)
string alterAzureDbBackupStorageRedundancy = DatabasePrototypeAzure.CreateModifySqlDBBackupStorageRedundancyStatement(this.Name, this.currentState.backupStorageRedundancy);
using (var conn = this.context.ServerConnection.GetDatabaseConnection(this.Name).SqlConnectionObject)
{
cmd.CommandText = alterDbPropertiesStatement;
cmd.ExecuteNonQuery();
}
if (currentState.recursiveTriggers != originalState.recursiveTriggers)
{
cmd.CommandText = alterAzureDbRecursiveTriggersEnabledStatement;
cmd.ExecuteNonQuery();
}
if (currentState.isReadOnly != originalState.isReadOnly)
{
cmd.CommandText = alterAzureDbIsReadOnlyStatement;
cmd.ExecuteNonQuery();
//While scripting the database, there is already an open connection. So, we are checking the state of the connection here.
if (conn != null && conn.State == ConnectionState.Closed)
{
conn.Open();
using (var cmd = new SqlCommand { Connection = conn })
{
cmd.CommandText = alterAzureDbBackupStorageRedundancy;
cmd.ExecuteNonQuery();
}
}
}
}
}
//Because we didn't use SMO to do the alter we should refresh the DB object so it picks up the correct properties
db.Refresh();
return database;
}
// For properties that are supported in Database.Alter(), call SaveProperties, and then alter the DB.
//
if (this.AzureEdition != AzureEdition.DataWarehouse)
{
this.SaveProperties(db);
db.Alter(TerminationClause.FailOnOpenTransactions);
}
return db;
string alterDbPropertiesStatement = DatabasePrototypeAzure.CreateModifySqlDwDbOptionsStatement(this.Name, this.MaxSize, this.CurrentServiceLevelObjective);
string alterAzureDbRecursiveTriggersEnabledStatement = DatabasePrototypeAzure.CreateAzureDbSetRecursiveTriggersStatement(this.Name, this.RecursiveTriggers);
string alterAzureDbIsReadOnlyStatement = DatabasePrototypeAzure.CreateAzureDbSetIsReadOnlyStatement(this.Name, this.IsReadOnly);
Database db = this.GetDatabase();
//Altering the DB needs to be done on the master DB
using (var conn = this.context.ServerConnection.GetDatabaseConnection("master").SqlConnectionObject)
{
var cmd = new SqlCommand { Connection = conn };
conn.Open();
//Only run the alter statements for modifications made. This is mostly to allow the non-Azure specific
//properties to be updated when a SLO change is in progress, but it also is beneficial to save trips to the
//server whenever we can (especially when Azure is concerned)
if ((currentState.azureEdition != null && currentState.azureEdition != originalState.azureEdition) ||
(!string.IsNullOrEmpty(currentState.currentServiceLevelObjective) && currentState.currentServiceLevelObjective != originalState.currentServiceLevelObjective) ||
(currentState.maxSize != null && currentState.maxSize != originalState.maxSize))
{
cmd.CommandText = alterDbPropertiesStatement;
cmd.ExecuteNonQuery();
}
if (currentState.recursiveTriggers != originalState.recursiveTriggers)
{
cmd.CommandText = alterAzureDbRecursiveTriggersEnabledStatement;
cmd.ExecuteNonQuery();
}
if (currentState.isReadOnly != originalState.isReadOnly)
{
cmd.CommandText = alterAzureDbIsReadOnlyStatement;
cmd.ExecuteNonQuery();
}
}
//Because we didn't use SMO to do the alter we should refresh the DB object so it picks up the correct properties
db.Refresh();
return db;
}
#endregion DatabasePrototype overrides
@@ -229,30 +280,28 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
if (this.ServerVersion.Major >= 12 && this.AzureEdition != AzureEdition.DataWarehouse)
// treat null as defaults/unchanged
// SMO will only script changed values so if the user changes edition and size and SLO are empty the alter
// will change the db to the default size and slo for the new edition
// if the new combination of edition/size/slo is invalid the alter will fail
if (this.currentState.maxSize != null && (!this.Exists || (this.originalState.maxSize != this.currentState.maxSize)))
{
if (!this.Exists || (this.originalState.maxSize != this.currentState.maxSize))
{
db.MaxSizeInBytes = this.currentState.maxSize.SizeInBytes;
}
if (!this.Exists || (this.originalState.azureEdition != this.currentState.azureEdition))
{
db.AzureEdition = this.currentState.azureEdition.ToString();
}
if (!this.Exists || (this.originalState.currentServiceLevelObjective != this.currentState.currentServiceLevelObjective))
{
db.AzureServiceObjective = this.currentState.currentServiceLevelObjective;
}
db.MaxSizeInBytes = this.currentState.maxSize.SizeInBytes;
}
if (this.currentState.azureEdition != null && (!this.Exists || (this.originalState.azureEdition != this.currentState.azureEdition)))
{
db.AzureEdition = this.currentState.azureEdition.ToString();
}
if (!string.IsNullOrEmpty(this.currentState.currentServiceLevelObjective) && (!this.Exists || (this.originalState.currentServiceLevelObjective != this.currentState.currentServiceLevelObjective)))
{
db.AzureServiceObjective = this.currentState.currentServiceLevelObjective;
}
}
private const string AlterDbStatementFormat =
@"ALTER DATABASE [{0}] {1}";
private const string ModifyAzureDbStatementFormat = @"MODIFY (EDITION = '{0}', MAXSIZE={1} {2})";
private const string AlterDbStatementFormat = @"ALTER DATABASE [{0}] {1}";
private const string ModifySqlDwDbStatementFormat = @"MODIFY (MAXSIZE={0} {1})";
private const string AzureServiceLevelObjectiveOptionFormat = @"SERVICE_OBJECTIVE = '{0}'";
private const string SetReadOnlyOption = @"SET READ_ONLY";
@@ -260,6 +309,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
private const string SetRecursiveTriggersOptionFormat = @"SET RECURSIVE_TRIGGERS {0}";
private const string On = @"ON";
private const string Off = @"OFF";
private const string ModifySqlDbBackupStorageRedundancy = @"MODIFY BACKUP_STORAGE_REDUNDANCY = '{0}'";
/// <summary>
/// Creates an ALTER DATABASE statement to modify the Read-Only status of the target DB
@@ -288,29 +338,6 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
recursiveTriggersEnabled ? DatabasePrototypeAzure.On : DatabasePrototypeAzure.Off));
}
/// <summary>
/// Creates an ALTER DATABASE statement to modify the Azure Database properties (Edition, MaxSize and Service Level Objective)
/// for the target database
/// </summary>
/// <param name="dbName"></param>
/// <param name="edition"></param>
/// <param name="maxSize"></param>
/// <param name="serviceLevelObjective"></param>
/// <returns></returns>
protected static string CreateModifyAzureDbOptionsStatement(string dbName, AzureEdition edition, string maxSize, string serviceLevelObjective)
{
//We might not have a SLO since some editions don't support it
string sloOption = string.IsNullOrEmpty(serviceLevelObjective) ?
string.Empty : ", " + string.Format(CultureInfo.InvariantCulture, AzureServiceLevelObjectiveOptionFormat, serviceLevelObjective);
return CreateAzureAlterDbStatement(dbName,
string.Format(CultureInfo.InvariantCulture,
ModifyAzureDbStatementFormat,
edition,
maxSize,
sloOption));
}
/// <summary>
/// Creates an ALTER DATABASE statement to modify the Azure DataWarehouse properties (MaxSize and Service Level Objective)
/// for the target database
@@ -332,6 +359,21 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
sloOption));
}
/// <summary>
/// Creates the ATLER DATABASE statement from the given backup storage redundancy option.
/// </summary>
/// <param name="dbName"></param>
/// <param name="option"></param>
/// <returns></returns>
protected static string CreateModifySqlDBBackupStorageRedundancyStatement(string dbName, string option)
{
//Note: We allow user to select any one of the value from the UI for backupStorageRedundancy. So, we are inlining the value.
return CreateAzureAlterDbStatement(dbName,
string.Format(CultureInfo.InvariantCulture,
ModifySqlDbBackupStorageRedundancy,
option));
}
/// <summary>
/// Creates the ALTER DATABASE statement from the given op
/// </summary>