mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-22 17:24:07 -05:00
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
|
||||
this.currentState.pageVerify = PageVerify.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
this.currentState.pageVerify = PageVerify.TornPageDetection;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user