Fix create db resource strings (#348)

* Hook up SMO call into create db handler

* Clean-up resource strings

* Few additional code clean-ups
This commit is contained in:
Karl Burtram
2017-05-12 07:53:45 -07:00
committed by GitHub
parent 848cfadf9a
commit ed978fe5b7
15 changed files with 128 additions and 180 deletions

View File

@@ -0,0 +1,398 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.SqlServer.Diagnostics.STrace;
using Microsoft.SqlServer.Management.Common;
using Microsoft.Win32;
using SizeUnits = Microsoft.SqlTools.ServiceLayer.Admin.DbSize.SizeUnits;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
public static class AzureSqlDbHelper
{
private static readonly TraceContext TraceContext = TraceContext.GetTraceContext("AzureSqlDbUtils", typeof(AzureSqlDbHelper).Name);
/// <summary>
/// Registry sub key for the AzureServiceObjectives overrides
/// </summary>
private const string AzureServiceObjectivesRegSubKey = @"AzureServiceObjectives";
/// <summary>
/// Contains the various editions available for an Azure Database
/// </summary>
/// ****IMPORTANT**** - If updating this enum make sure that the other logic in this class is updated as well
public enum AzureEdition
{
Web = 0,
Business = 1,
Basic = 2,
Standard = 3,
Premium = 4,
DataWarehouse = 5,
PremiumRS = 6
}
/// <summary>
/// Provides a mapping of Azure DB Editions to their respective size options
/// </summary>
/// Values below are taken from http://msdn.microsoft.com/en-us/library/dn268335.aspx
private static readonly Dictionary<AzureEdition, KeyValuePair<int, DbSize[]>> AzureEditionDatabaseSizeMappings = new Dictionary
<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
new[]
{
new DbSize(100, SizeUnits.MB),
new DbSize(500, SizeUnits.MB),
new DbSize(1, SizeUnits.GB),
new DbSize(2, SizeUnits.GB) //Default
})
},
{
AzureEdition.Standard,
new KeyValuePair<int, DbSize[]>(
13, //250GB
new[]
{
new DbSize(100, SizeUnits.MB),
new DbSize(500, SizeUnits.MB),
new DbSize(1, SizeUnits.GB),
new DbSize(2, SizeUnits.GB),
new DbSize(5, SizeUnits.GB),
new DbSize(10, SizeUnits.GB),
new DbSize(20, SizeUnits.GB),
new DbSize(30, SizeUnits.GB),
new DbSize(40, SizeUnits.GB),
new DbSize(50, SizeUnits.GB),
new DbSize(100, SizeUnits.GB),
new DbSize(150, SizeUnits.GB),
new DbSize(200, SizeUnits.GB),
new DbSize(250, SizeUnits.GB) //Default
})
},
{
AzureEdition.Premium,
new KeyValuePair<int, DbSize[]>(
16, //500GB
new[]
{
new DbSize(100, SizeUnits.MB),
new DbSize(500, SizeUnits.MB),
new DbSize(1, SizeUnits.GB),
new DbSize(2, SizeUnits.GB),
new DbSize(5, SizeUnits.GB),
new DbSize(10, SizeUnits.GB),
new DbSize(20, SizeUnits.GB),
new DbSize(30, SizeUnits.GB),
new DbSize(40, SizeUnits.GB),
new DbSize(50, SizeUnits.GB),
new DbSize(100, SizeUnits.GB),
new DbSize(150, SizeUnits.GB),
new DbSize(200, SizeUnits.GB),
new DbSize(250, SizeUnits.GB),
new DbSize(300, SizeUnits.GB),
new DbSize(400, SizeUnits.GB),
new DbSize(500, SizeUnits.GB), //Default
new DbSize(1024, SizeUnits.GB) //Following portal to display this as GB instead of 1TB
})
},
{
AzureEdition.DataWarehouse,
new KeyValuePair<int, DbSize[]>(
5, //10240GB
new[]
{
new DbSize(250, SizeUnits.GB),
new DbSize(500, SizeUnits.GB),
new DbSize(750, SizeUnits.GB),
new DbSize(1024, SizeUnits.GB),
new DbSize(5120, SizeUnits.GB),
new DbSize(10240, SizeUnits.GB),
new DbSize(20480, SizeUnits.GB),
new DbSize(30720, SizeUnits.GB),
new DbSize(40960, SizeUnits.GB),
new DbSize(51200, SizeUnits.GB)
})
},
{
AzureEdition.PremiumRS,
new KeyValuePair<int, DbSize[]>(
16, //500GB
new[]
{
new DbSize(100, SizeUnits.MB),
new DbSize(500, SizeUnits.MB),
new DbSize(1, SizeUnits.GB),
new DbSize(2, SizeUnits.GB),
new DbSize(5, SizeUnits.GB),
new DbSize(10, SizeUnits.GB),
new DbSize(20, SizeUnits.GB),
new DbSize(30, SizeUnits.GB),
new DbSize(40, SizeUnits.GB),
new DbSize(50, SizeUnits.GB),
new DbSize(100, SizeUnits.GB),
new DbSize(150, SizeUnits.GB),
new DbSize(200, SizeUnits.GB),
new DbSize(250, SizeUnits.GB),
new DbSize(300, SizeUnits.GB),
new DbSize(400, SizeUnits.GB),
new DbSize(500, SizeUnits.GB), //Default
})
},
};
/// <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).
///
/// The key is the index of the default value for the list
/// </summary>
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.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"})}
};
/// <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()
{
}
/// <summary>
/// Gets the list of databases sizes applicable for the specified Azure DB edition (if such
/// a mapping exists) as well as the index of the default size for that edition.
///
/// Outputs an empty array with an index of -1 if no such mapping exists
/// </summary>
/// <param name="edition"></param>
/// <param name="databaseSizeInfo"></param>
/// <returns>TRUE if a mapping exists, FALSE if it does not</returns>
public static bool TryGetDatabaseSizeInfo(AzureEdition edition, out KeyValuePair<int, DbSize[]> databaseSizeInfo)
{
if (AzureEditionDatabaseSizeMappings.TryGetValue(edition, out databaseSizeInfo))
{
return true;
}
databaseSizeInfo = new KeyValuePair<int, DbSize[]>(-1, new DbSize[0]);
return false;
}
/// <summary>
/// Gets a KeyValuePair containing a list of the ServiceObjective names mapped to a particular Azure DB Edition
/// (if such a mapping exists) as well as the index of the default Service Objective for that edition.
/// Outputs an empty array with a default index of -1 if no such mapping exists.
/// </summary>
/// <param name="edition"></param>
/// <param name="serviceObjectiveInfo"></param>
/// <returns>TRUE if a mapping exists, FALSE if it did not</returns>
public static bool TryGetServiceObjectiveInfo(AzureEdition edition,
out KeyValuePair<int, string[]> serviceObjectiveInfo)
{
if (AzureServiceObjectiveInfo.TryGetValue(edition, out serviceObjectiveInfo))
{
return true;
}
serviceObjectiveInfo = new KeyValuePair<int, string[]>(-1, new string[0]);
return false;
}
/// <summary>
/// Gets the default database size for a specified Azure Edition
/// </summary>
/// <param name="edition"></param>
/// <returns>The default size, or NULL if no default exists</returns>
public static DbSize GetDatabaseDefaultSize(AzureEdition edition)
{
DbSize defaultSize = null;
KeyValuePair<int, DbSize[]> pair;
if (AzureEditionDatabaseSizeMappings.TryGetValue(edition, out pair))
{
defaultSize = pair.Value[pair.Key];
}
return defaultSize;
}
/// <summary>
/// Gets the default Service Objective name for a particular Azure DB edition
/// </summary>
/// <param name="edition"></param>
/// <returns></returns>
public static string GetDefaultServiceObjective(AzureEdition edition)
{
string defaultServiceObjective = "";
KeyValuePair<int, string[]> pair;
if (AzureServiceObjectiveInfo.TryGetValue(edition, out pair))
{
//Bounds check since this value can be entered by users
if (pair.Key >= 0 && pair.Key < pair.Value.Length)
{
defaultServiceObjective = pair.Value[pair.Key];
}
}
return defaultServiceObjective;
}
/// <summary>
/// Gets the localized Azure Edition display name
/// </summary>
/// <param name="edition"></param>
/// <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;
}
/// <summary>
/// Parses a display name back into its corresponding AzureEdition.
/// </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;
}
/// <summary>
/// Returns a list of AzureEditions that are valid values for the EDITION option
/// when creating a database.
/// </summary>
/// 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)
{
//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>();
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,303 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System;
using System.ComponentModel;
using System.Resources;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Diagnostics;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database properties for SqlServer 2008
/// </summary>
[TypeConverter(typeof(DynamicValueTypeConverter))]
internal class DatabasePrototype100 : DatabasePrototype90
{
/// <summary>
/// Whether vardecimal compression is enabled on the server
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_VarDecimalEnabled")]
public bool VarDecimalEnabled
{
get
{
return this.currentState.varDecimalEnabled;
}
//there is no set for user database in katmai. By default it's true.
}
/// <summary>
/// Whether database is encrypted or not
/// </summary>
[Category("Category_State"),
DisplayNameAttribute("Property_EncryptionEnabled")]
public bool EncryptionEnabled
{
get
{
return this.currentState.encryptionEnabled;
}
set
{
this.currentState.encryptionEnabled = value;
this.NotifyObservers();
}
}
/// <summary>
/// Honor Broker Priority
/// </summary>
[Category("Category_ServiceBroker"),
DisplayNameAttribute("Property_HonorBrokerPriority")]
public bool HonorBrokerPriority
{
get
{
return this.currentState.honorBrokerPriority;
}
}
[Category("Category_DatabaseScopedConfigurations")]
[DisplayNameAttribute("Property_MaxDop")]
public int MaxDop
{
get
{
return this.currentState.maxDop;
}
set
{
this.currentState.maxDop = value;
this.NotifyObservers();
}
}
[Category("Category_DatabaseScopedConfigurations")]
[DisplayNameAttribute("Property_MaxDopForSecondary")]
public int? MaxDopForSecondary
{
get
{
return this.currentState.maxDopForSecondary;
}
set
{
this.currentState.maxDopForSecondary = value;
this.NotifyObservers();
}
}
[Category("Category_DatabaseScopedConfigurations"),
DisplayNameAttribute("Property_LegacyCardinalityEstimation")]
public string LegacyCardinalityEstimationDisplay
{
get
{
return GetDatabaseScopedConfigDisplayText(this.currentState.legacyCardinalityEstimation);
}
set
{
this.currentState.legacyCardinalityEstimation = SetDatabaseScopedConfigHelper(value, forSecondary: false);
this.NotifyObservers();
}
}
[Category("Category_DatabaseScopedConfigurations"),
DisplayNameAttribute("Property_LegacyCardinalityEstimationForSecondary")]
public String LegacyCardinalityEstimationForSecondaryDisplay
{
get
{
return GetDatabaseScopedConfigDisplayText(this.currentState.legacyCardinalityEstimationForSecondary);
}
set
{
this.currentState.legacyCardinalityEstimationForSecondary = SetDatabaseScopedConfigHelper(value, forSecondary: true);
this.NotifyObservers();
}
}
[Category("Category_DatabaseScopedConfigurations"),
DisplayNameAttribute("Property_ParameterSniffing")]
public string ParameterSniffingDisplay
{
get
{
return GetDatabaseScopedConfigDisplayText(this.currentState.parameterSniffing);
}
set
{
this.currentState.parameterSniffing = SetDatabaseScopedConfigHelper(value, forSecondary: false);
this.NotifyObservers();
}
}
[Category("Category_DatabaseScopedConfigurations"),
DisplayNameAttribute("Property_ParameterSniffingForSecondary")]
public String ParameterSniffingForSecondaryDisplay
{
get
{
return GetDatabaseScopedConfigDisplayText(this.currentState.parameterSniffingForSecondary);
}
set
{
this.currentState.parameterSniffingForSecondary = SetDatabaseScopedConfigHelper(value, forSecondary: true);
this.NotifyObservers();
}
}
[Category("Category_DatabaseScopedConfigurations"),
DisplayNameAttribute("Property_QueryOptimizerHotfixes")]
public String QueryOptimizerHotfixesDisplay
{
get
{
return GetDatabaseScopedConfigDisplayText(this.currentState.queryOptimizerHotfixes);
}
set
{
this.currentState.queryOptimizerHotfixes = SetDatabaseScopedConfigHelper(value, forSecondary: false);
this.NotifyObservers();
}
}
[Category("Category_DatabaseScopedConfigurations"),
DisplayNameAttribute("Property_QueryOptimizerHotfixesForSecondary")]
public String QueryOptimizerHotfixesForSecondaryDisplay
{
get
{
return GetDatabaseScopedConfigDisplayText(this.currentState.queryOptimizerHotfixesForSecondary);
}
set
{
this.currentState.queryOptimizerHotfixesForSecondary = SetDatabaseScopedConfigHelper(value, forSecondary: true);
this.NotifyObservers();
}
}
public DatabasePrototype100(CDataContainer context) : base(context) { }
/// <summary>
/// Commit changes to the database
/// </summary>
/// <param name="db">The database whose properties we are changing</param>
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
if (!this.Exists || this.originalState.encryptionEnabled != this.currentState.encryptionEnabled)
{
db.EncryptionEnabled = this.currentState.encryptionEnabled;
}
// Check if we support database scoped configurations in this database. Since these were all added at the same time,
// only check if MaxDop is supported rather than each individual property.
if (db.IsSupportedProperty("MaxDop"))
{
if (!this.Exists || (db.MaxDop != this.MaxDop))
{
db.MaxDop = this.MaxDop;
}
if (!this.Exists || (db.MaxDopForSecondary != this.MaxDopForSecondary))
{
db.MaxDopForSecondary = this.MaxDopForSecondary;
}
if (!this.Exists || (db.LegacyCardinalityEstimation != this.currentState.legacyCardinalityEstimation))
{
db.LegacyCardinalityEstimation = this.currentState.legacyCardinalityEstimation;
}
if (!this.Exists || (db.LegacyCardinalityEstimationForSecondary != this.currentState.legacyCardinalityEstimationForSecondary))
{
db.LegacyCardinalityEstimationForSecondary = this.currentState.legacyCardinalityEstimationForSecondary;
}
if (!this.Exists || (db.ParameterSniffing != this.currentState.parameterSniffing))
{
db.ParameterSniffing = this.currentState.parameterSniffing;
}
if (!this.Exists || (db.ParameterSniffingForSecondary != this.currentState.parameterSniffingForSecondary))
{
db.ParameterSniffingForSecondary = this.currentState.parameterSniffingForSecondary;
}
if (!this.Exists || (db.QueryOptimizerHotfixes != this.currentState.queryOptimizerHotfixes))
{
db.QueryOptimizerHotfixes = this.currentState.queryOptimizerHotfixes;
}
if (!this.Exists || (db.QueryOptimizerHotfixesForSecondary != this.currentState.queryOptimizerHotfixesForSecondary))
{
db.QueryOptimizerHotfixesForSecondary = this.currentState.queryOptimizerHotfixesForSecondary;
}
}
}
#region Helper Methods
/// <summary>
/// Gets the display text for a database scoped configuration setting.
/// </summary>
/// <param name="onOffValue">The database scoped configuration setting value.</param>
/// <returns>A string from the resource manager representing the value.</returns>
private string GetDatabaseScopedConfigDisplayText(DatabaseScopedConfigurationOnOff onOffValue)
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
string result = null;
switch (onOffValue)
{
case DatabaseScopedConfigurationOnOff.Off:
result = manager.GetString("prototype_db_prop_databasescopedconfig_value_off");
break;
case DatabaseScopedConfigurationOnOff.On:
result = manager.GetString("prototype_db_prop_databasescopedconfig_value_on");
break;
case DatabaseScopedConfigurationOnOff.Primary:
result = manager.GetString("prototype_db_prop_databasescopedconfig_value_primary");
break;
}
return result;
}
/// <summary>
/// Translates a string to a database scoped configuration enum value for the set method.
/// </summary>
/// <param name="displayText">The display text.</param>
/// <param name="forSecondary">Whether this is for a secondary in which case "PRIMARY" is allowable.</param>
/// <returns>The database scoped configuration enum value that matches the display text.</returns>
private DatabaseScopedConfigurationOnOff SetDatabaseScopedConfigHelper(string displayText, bool forSecondary)
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
if (displayText == manager.GetString("prototype_db_prop_databasescopedconfig_value_off"))
{
return DatabaseScopedConfigurationOnOff.Off;
}
else if (displayText == manager.GetString("prototype_db_prop_databasescopedconfig_value_on") || !forSecondary)
{
return DatabaseScopedConfigurationOnOff.On;
}
else
{
return DatabaseScopedConfigurationOnOff.Primary;
}
}
#endregion
}
}

View File

@@ -0,0 +1,187 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.ComponentModel;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database properties for SqlServer 2011
/// </summary>
[TypeConverter(typeof(DynamicValueTypeConverter))]
internal class DatabasePrototype110 : DatabasePrototype100
{
/// <summary>
/// Database compatibility level
/// </summary>
[Browsable(false)]
public ContainmentType DatabaseContainmentType
{
get
{
return this.currentState.databaseContainmentType;
}
set
{
this.currentState.databaseContainmentType = value;
this.NotifyObservers();
}
}
[Category("Category_ContainedDatabases"),
DisplayNameAttribute("Property_DefaultFullTextLanguageLcid")]
public int DefaultFullTextLanguageLcid
{
get
{
return this.currentState.defaultFulltextLanguageLcid;
}
set
{
this.currentState.defaultFulltextLanguageLcid = value;
this.NotifyObservers();
}
}
[Category("Category_ContainedDatabases"),
DisplayNameAttribute("Property_NestedTriggersEnabled")]
public bool NestedTriggersEnabled
{
get
{
return this.currentState.nestedTriggersEnabled;
}
set
{
this.currentState.nestedTriggersEnabled = value;
this.NotifyObservers();
}
}
[Category("Category_ContainedDatabases"),
DisplayNameAttribute("Property_TransformNoiseWords")]
public bool TransformNoiseWords
{
get
{
return this.currentState.transformNoiseWords;
}
set
{
this.currentState.transformNoiseWords = value;
this.NotifyObservers();
}
}
[Category("Category_ContainedDatabases"),
DisplayNameAttribute("Property_TwoDigitYearCutoff")]
public int TwoDigitYearCutoff
{
get
{
return this.currentState.twoDigitYearCutoff;
}
set
{
this.currentState.twoDigitYearCutoff = value;
this.NotifyObservers();
}
}
[Category("Category_Recovery"),
DisplayNameAttribute("Property_TargetRecoveryTime")]
public int TargetRecoveryTime
{
get
{
return this.currentState.targetRecoveryTime;
}
set
{
this.currentState.targetRecoveryTime = value;
this.NotifyObservers();
}
}
[Category("Category_Misc"),
DisplayNameAttribute("Property_DelayedDurability")]
public DelayedDurability DelayedDurability
{
get
{
return this.currentState.delayedDurability;
}
set
{
this.currentState.delayedDurability = value;
this.NotifyObservers();
}
}
public DatabasePrototype110(CDataContainer context)
: base(context)
{
}
/// <summary>
/// Commit changes to the database
/// </summary>
/// <param name="db">The database whose properties we are changing</param>
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
if (db.IsSupportedProperty("ContainmentType"))
{
if (!this.Exists || (db.ContainmentType != this.DatabaseContainmentType))
{
db.ContainmentType = this.DatabaseContainmentType;
}
if (this.DatabaseContainmentType != ContainmentType.None)
{
if (!this.Exists || (db.DefaultFullTextLanguage.Lcid != this.DefaultFullTextLanguageLcid))
{
db.DefaultFullTextLanguage.Lcid = this.DefaultFullTextLanguageLcid;
}
if (!this.Exists || (db.NestedTriggersEnabled != this.NestedTriggersEnabled))
{
db.NestedTriggersEnabled = this.NestedTriggersEnabled;
}
if (!this.Exists || (db.TransformNoiseWords != this.TransformNoiseWords))
{
db.TransformNoiseWords = this.TransformNoiseWords;
}
if (!this.Exists || (db.TwoDigitYearCutoff != this.TwoDigitYearCutoff))
{
db.TwoDigitYearCutoff = this.TwoDigitYearCutoff;
}
}
}
if (db.IsSupportedProperty("TargetRecoveryTime"))
{
if (!this.Exists || (db.TargetRecoveryTime != this.TargetRecoveryTime))
{
db.TargetRecoveryTime = this.TargetRecoveryTime;
}
}
if (db.IsSupportedProperty("DelayedDurability"))
{
if (!this.Exists || (db.DelayedDurability != this.DelayedDurability))
{
db.DelayedDurability = this.DelayedDurability;
}
}
}
}
}

View File

@@ -0,0 +1,280 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.ComponentModel;
using System.Resources;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Diagnostics;
using System.Collections.Generic;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database Prototype for SqlServer 2000 and later servers
/// </summary>
internal class DatabasePrototype80 : DatabasePrototype, IDynamicValues
{
/// <summary>
/// Whether the database is read-only
/// </summary>
[
Category("Category_State"),
DisplayNameAttribute("Property_ReadOnly")
]
public bool IsReadOnly
{
get
{
return this.currentState.isReadOnly;
}
set
{
this.currentState.isReadOnly = value;
this.NotifyObservers();
}
}
/// <summary>
/// Whether torn page detection is enabled
/// </summary>
[Category("Category_Recovery"),
DisplayNameAttribute("Property_PageVerify"),
TypeConverter(typeof(PageVerifyTypes80))]
public virtual string PageVerifyDisplay
{
get
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
string result = null;
switch (this.currentState.pageVerify)
{
case PageVerify.Checksum:
result = manager.GetString("prototype_db_prop_pageVerify_value_checksum");
break;
case PageVerify.None:
result = manager.GetString("prototype_db_prop_pageVerify_value_none");
break;
case PageVerify.TornPageDetection:
result = manager.GetString("prototype.db.prop.pageVerify.value.tornPageDetection");
break;
}
return result;
}
set
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
if (value == manager.GetString("prototype_db_prop_pageVerify_value_checksum"))
{
this.currentState.pageVerify = PageVerify.Checksum;
}
else if (value == manager.GetString("prototype_db_prop_pageVerify_value_none"))
{
this.currentState.pageVerify = PageVerify.None;
}
else
{
this.currentState.pageVerify = PageVerify.TornPageDetection;
}
this.NotifyObservers();
}
}
/// <summary>
/// ANSI Padding enabled
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_ANSIPadding")]
public bool AnsiPadding
{
get
{
return this.currentState.ansiPadding;
}
set
{
this.currentState.ansiPadding = value;
this.NotifyObservers();
}
}
/// <summary>
/// Use ANSI warnings
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_ANSIWarnings")]
public bool AnsiWarnings
{
get
{
return this.currentState.ansiWarnings;
}
set
{
this.currentState.ansiWarnings = value;
this.NotifyObservers();
}
}
/// <summary>
/// Arithabort
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_ArithAbort")]
public bool Arithabort
{
get
{
return this.currentState.arithabort;
}
set
{
this.currentState.arithabort = value;
this.NotifyObservers();
}
}
/// <summary>
/// Whether contatenating a null string yields a null result
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_ConcatNullYieldsNull")]
public bool ConcatNullYieldsNull
{
get
{
return this.currentState.concatNullYieldsNull;
}
set
{
this.currentState.concatNullYieldsNull = value;
this.NotifyObservers();
}
}
/// <summary>
/// Numeric Roundabout
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_NumericRoundAbort")]
public bool NumericRoundAbort
{
get
{
return this.currentState.numericRoundAbort;
}
set
{
this.currentState.numericRoundAbort = value;
this.NotifyObservers();
}
}
public DatabasePrototype80(CDataContainer context) : base(context) { }
/// <summary>
/// Commit property changes to the database
/// </summary>
/// <param name="db">The database whose properties we are changing</param>
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
// never set the real database collation to "<server default>" - there is no
// real collation with that name. "<server default>" is only valid for new
// databases and just means "don't set the collation".
if ((!this.Exists || (this.Exists && (db.Collation != this.Collation))) &&
(this.originalState.defaultCollation != this.Collation))
{
db.Collation = this.Collation;
}
if (!this.Exists || (db.DatabaseOptions.AnsiPaddingEnabled != this.AnsiPadding))
{
db.DatabaseOptions.AnsiPaddingEnabled = this.AnsiPadding;
}
if (!this.Exists || (db.DatabaseOptions.AnsiWarningsEnabled != this.AnsiWarnings))
{
db.DatabaseOptions.AnsiWarningsEnabled = this.AnsiWarnings;
}
if (!this.Exists || (db.DatabaseOptions.ArithmeticAbortEnabled != this.Arithabort))
{
db.DatabaseOptions.ArithmeticAbortEnabled = this.Arithabort;
}
if (!this.Exists || (db.DatabaseOptions.ConcatenateNullYieldsNull != this.ConcatNullYieldsNull))
{
db.DatabaseOptions.ConcatenateNullYieldsNull = this.ConcatNullYieldsNull;
}
if (db.IsSupportedProperty("PageVerify"))
{
if (!this.Exists || (db.DatabaseOptions.PageVerify != this.currentState.pageVerify))
{
db.DatabaseOptions.PageVerify = this.currentState.pageVerify;
}
}
if (!this.Exists || (db.DatabaseOptions.NumericRoundAbortEnabled != this.NumericRoundAbort))
{
db.DatabaseOptions.NumericRoundAbortEnabled = this.NumericRoundAbort;
}
if (!this.Exists || (db.DatabaseOptions.ReadOnly != this.IsReadOnly))
{
db.DatabaseOptions.ReadOnly = this.IsReadOnly;
}
}
#region IDynamicValues Members
public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
TypeConverter.StandardValuesCollection result = null;
if (context.PropertyDescriptor.Name == "PageVerifyDisplay")
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
List<string> standardValues = new List<string>();
if (this.IsYukonOrLater)
{
standardValues.Add(manager.GetString("prototype_db_prop_pageVerify_value_checksum"));
}
standardValues.Add(manager.GetString("prototype_db_prop_pageVerify_value_tornPageDetection"));
standardValues.Add(manager.GetString("prototype_db_prop_pageVerify_value_none"));
result = new TypeConverter.StandardValuesCollection(standardValues);
}
else
{
result = base.GetStandardValues(context);
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,33 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.ComponentModel;
using Microsoft.SqlServer.Management.Sdk.Sfc;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database Prototype for SqlServer 2000 SP3 and later servers
/// </summary>
[TypeConverter(typeof(DynamicValueTypeConverter))]
internal class DatabasePrototype80SP3 : DatabasePrototype80
{
/// <summary>
/// ANSI Padding enabled
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_DBChaining")]
public bool DbChaining
{
get
{
return this.currentState.dbChaining;
}
}
public DatabasePrototype80SP3(CDataContainer context) : base(context) { }
}
}

View File

@@ -0,0 +1,284 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.ComponentModel;
using System.Resources;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Common;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Diagnostics;
using System.Collections.Generic;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database Prototype for SqlServer 2005 and later servers
/// </summary>
internal class DatabasePrototype90 : DatabasePrototype80SP3, IDynamicValues
{
/// <summary>
/// Whether torn page detection is enabled
/// </summary>
[Category("Category_Automatic"),
DisplayNameAttribute("Property_AutoUpdateStateAsync")]
public bool AutoUpdateStatisticsAsync
{
get
{
return this.currentState.autoUpdateStatisticsAsync;
}
set
{
this.currentState.autoUpdateStatisticsAsync = value;
this.NotifyObservers();
}
}
/// <summary>
/// Whether torn page detection is enabled
/// </summary>
[Category("Category_Recovery"),
DisplayNameAttribute("Property_PageVerify"),
TypeConverter(typeof(PageVerifyTypes90))]
public override string PageVerifyDisplay
{
get
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
string result = null;
switch (this.currentState.pageVerify)
{
case PageVerify.Checksum:
result = manager.GetString("prototype_db_prop_pageVerify_value_checksum");
break;
case PageVerify.None:
result = manager.GetString("prototype_db_prop_pageVerify_value_none");
break;
case PageVerify.TornPageDetection:
result = manager.GetString("prototype_db_prop_pageVerify_value_tornPageDetection");
break;
}
return result;
}
set
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
if (value == manager.GetString("prototype_db_prop_pageVerify_value_checksum"))
{
this.currentState.pageVerify = PageVerify.Checksum;
}
else if (value == manager.GetString("prototype_db_prop_pageVerify_value_none"))
{
this.currentState.pageVerify = PageVerify.None;
}
else
{
this.currentState.pageVerify = PageVerify.TornPageDetection;
}
this.NotifyObservers();
}
}
/// <summary>
/// Use ANSI warnings
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_Trustworthy")]
public bool Trustworthy
{
get
{
return this.currentState.trustworthy;
}
}
/// <summary>
/// Arithabort
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_DateCorrelationOptimization")]
public bool DateCorrelationOptimization
{
get
{
return this.currentState.dateCorrelationOptimization;
}
set
{
this.currentState.dateCorrelationOptimization = value;
this.NotifyObservers();
}
}
/// <summary>
/// AllowSnapshotIsolation
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_AllowSnapshotIsolation")]
public bool AllowSnapshotIsolation
{
get
{
return this.currentState.allowSnapshotIsolation;
}
set
{
this.currentState.allowSnapshotIsolation = value;
this.NotifyObservers();
}
}
/// <summary>
/// IsReadCommittedSnapshotOn
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_IsReadCommittedSnapshotOn")]
public bool IsReadCommittedSnapshotOn
{
get
{
return this.currentState.isReadCommittedSnapshotOn;
}
set
{
this.currentState.isReadCommittedSnapshotOn = value;
this.NotifyObservers();
}
}
/// <summary>
/// BrokerEnabled
/// </summary>
[Category("Category_ServiceBroker"),
DisplayNameAttribute("Property_BrokerEnabled")]
public bool BrokerEnabled
{
get
{
return this.currentState.brokerEnabled;
}
set
{
this.currentState.brokerEnabled = value;
this.NotifyObservers();
}
}
/// <summary>
/// Whether contatenating a null string yields a null result
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_Parameterization")]
[TypeConverter(typeof(ParameterizationTypes))]
public string Parameterization
{
get
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
string result = this.currentState.parameterization ?
manager.GetString("prototype_db_prop_parameterization_value_forced") :
manager.GetString("prototype_db_prop_parameterization_value_simple");
return result;
}
set
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
this.currentState.parameterization = (value == manager.GetString("prototype_db_prop_parameterization_value_forced"));
this.NotifyObservers();
}
}
/// <summary>
/// Service Broker Guid
/// </summary>
[Category("Category_ServiceBroker"),
DisplayNameAttribute("Property_ServiceBrokerGUID")]
public System.Guid ServiceBrokerGuid
{
get
{
return this.currentState.serviceBrokerGuid;
}
}
public DatabasePrototype90(CDataContainer context) : base(context) { }
/// <summary>
/// Commit property changes to the database
/// </summary>
/// <param name="db">The database whose properties we are changing</param>
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
if (!this.Exists || (db.DatabaseOptions.AutoUpdateStatisticsAsync != this.AutoUpdateStatisticsAsync))
{
db.DatabaseOptions.AutoUpdateStatisticsAsync = this.AutoUpdateStatisticsAsync;
}
if (!this.Exists || (db.DatabaseOptions.DateCorrelationOptimization != this.DateCorrelationOptimization))
{
db.DatabaseOptions.DateCorrelationOptimization = this.DateCorrelationOptimization;
}
if (!this.Exists || (db.DatabaseOptions.IsParameterizationForced != this.currentState.parameterization))
{
db.DatabaseOptions.IsParameterizationForced = this.currentState.parameterization;
}
if (db.IsSupportedProperty("BrokerEnabled"))
{
if (!this.Exists || (db.DatabaseOptions.BrokerEnabled != this.currentState.brokerEnabled))
{
db.DatabaseOptions.BrokerEnabled = this.currentState.brokerEnabled;
}
}
if (!this.Exists || (db.IsReadCommittedSnapshotOn != this.IsReadCommittedSnapshotOn))
{
db.IsReadCommittedSnapshotOn = this.IsReadCommittedSnapshotOn;
}
}
#region IDynamicValues Members
public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
TypeConverter.StandardValuesCollection result = null;
if (context.PropertyDescriptor.Name == "Parameterization")
{
ResourceManager manager = new ResourceManager("Microsoft.SqlTools.ServiceLayer.Localization.SR", typeof(DatabasePrototype).GetAssembly());
List<string> standardValues = new List<string>();
standardValues.Add(manager.GetString("prototype_db_prop_parameterization_value_forced"));
standardValues.Add(manager.GetString("prototype_db_prop_parameterization_value_simple"));
result = new TypeConverter.StandardValuesCollection(standardValues);
}
else
{
result = base.GetStandardValues(context);
}
return result;
}
#endregion
}
}

View File

@@ -0,0 +1,58 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.ComponentModel;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database Prototype for SqlServer 2005 Enterprise SP2 and later servers
/// </summary>
[TypeConverter(typeof(DynamicValueTypeConverter))]
internal class DatabasePrototype90EnterpriseSP2 : DatabasePrototype90
{
/// <summary>
/// Whether vardecimal compression is enabled on the server
/// </summary>
[Category("Category_Misc"),
DisplayNameAttribute("Property_VarDecimalEnabled")]
public bool VarDecimalEnabled
{
get
{
return this.currentState.varDecimalEnabled;
}
set
{
this.currentState.varDecimalEnabled = value;
this.NotifyObservers();
}
}
public DatabasePrototype90EnterpriseSP2(CDataContainer context) : base(context) { }
/// <summary>
/// Commit property changes to the database
/// </summary>
/// <param name="db">The database whose properties we are changing</param>
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
// changing decimal compression status is very expensive, so
// only set a value for vardecimal compression if its value has changed
if (this.originalState.varDecimalEnabled != this.currentState.varDecimalEnabled)
{
db.IsVarDecimalStorageFormatEnabled = this.currentState.varDecimalEnabled;
}
}
}
}

View File

@@ -0,0 +1,343 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
using System.ComponentModel;
using System.Text;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.Sdk.Sfc;
using Microsoft.SqlServer.Management.Diagnostics;
using System.Globalization;
using System.Data.SqlClient;
using AzureEdition = Microsoft.SqlTools.ServiceLayer.Admin.AzureSqlDbHelper.AzureEdition;
using Microsoft.SqlServer.Management.Common;
using System;
using System.Collections.Generic;
using System.Linq;
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
{
#region Constants
public const string Category_Azure = "Category_Azure";
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";
#endregion Constants
public DatabasePrototypeAzure(CDataContainer context, DatabaseEngineEdition editionToCreate = DatabaseEngineEdition.SqlDatabase)
: base(context)
{
EditionToCreate = editionToCreate;
}
#region Properties
[Category(Category_Azure),
DisplayNameAttribute(Property_AzureMaxSize)]
public string MaxSize
{
get
{
return this.currentState.maxSize == null ? null : this.currentState.maxSize.ToString();
}
set
{
this.currentState.maxSize = DbSize.ParseDbSize(value);
this.NotifyObservers();
}
}
[Category(Category_Azure),
DisplayNameAttribute(Property_AzureCurrentServiceLevelObjective)]
public string CurrentServiceLevelObjective
{
get
{
return this.currentState.currentServiceLevelObjective;
}
set
{
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
{
get
{
return this.currentState.azureEdition;
}
}
[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 AzureSqlDbHelper.GetAzureEditionDisplayName(this.currentState.azureEdition);
}
set
{
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;
}
this.currentState.azureEdition = edition;
this.CurrentServiceLevelObjective = AzureSqlDbHelper.GetDefaultServiceObjective(edition);
this.MaxSize = AzureSqlDbHelper.GetDatabaseDefaultSize(edition).ToString();
this.NotifyObservers();
}
}
}
public override IList<FilegroupPrototype> Filegroups
{
get { return Enumerable.Empty<FilegroupPrototype>().ToList(); }
}
public override IList<DatabaseFilePrototype> Files
{
get { return Enumerable.Empty<DatabaseFilePrototype>().ToList(); }
}
[Browsable(false)]
public override bool HideFileSettings
{
get { return true; }
}
[Browsable(false)]
public override bool AllowScripting
{
get { return this.ServerVersion.Major > 11 && this.AzureEdition != AzureEdition.DataWarehouse; }
}
#endregion Properties
#region DatabasePrototype overrides
/// <summary>
/// Commit changes to the database
/// </summary>
/// <param name="marshallingControl">The control through which UI interactions are to be marshalled</param>
/// <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))
{
var cmd = new SqlCommand();
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)
{
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();
// 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;
}
#endregion DatabasePrototype overrides
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
if (this.ServerVersion.Major >= 12 && this.AzureEdition != AzureEdition.DataWarehouse)
{
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;
}
}
}
private const string AlterDbStatementFormat =
@"ALTER DATABASE [{0}] {1}";
private const string ModifyAzureDbStatementFormat = @"MODIFY (EDITION = '{0}', MAXSIZE={1} {2})";
private const string ModifySqlDwDbStatementFormat = @"MODIFY (MAXSIZE={0} {1})";
private const string AzureServiceLevelObjectiveOptionFormat = @"SERVICE_OBJECTIVE = '{0}'";
private const string SetReadOnlyOption = @"SET READ_ONLY";
private const string SetReadWriteOption = @"SET READ_WRITE";
private const string SetRecursiveTriggersOptionFormat = @"SET RECURSIVE_TRIGGERS {0}";
private const string On = @"ON";
private const string Off = @"OFF";
/// <summary>
/// Creates an ALTER DATABASE statement to modify the Read-Only status of the target DB
/// </summary>
/// <param name="dbName"></param>
/// <param name="isReadOnly"></param>
/// <returns></returns>
protected static string CreateAzureDbSetIsReadOnlyStatement(string dbName, bool isReadOnly)
{
return CreateAzureAlterDbStatement(dbName,
string.Format(CultureInfo.InvariantCulture,
isReadOnly ? SetReadOnlyOption : SetReadWriteOption));
}
/// <summary>
/// Creates an ALTER DATABASE statement to modify the RECURSIVE_TRIGGERS option of the target DB
/// </summary>
/// <param name="dbName"></param>
/// <param name="recursiveTriggersEnabled"></param>
/// <returns></returns>
protected static string CreateAzureDbSetRecursiveTriggersStatement(string dbName, bool recursiveTriggersEnabled)
{
return CreateAzureAlterDbStatement(dbName,
string.Format(CultureInfo.InvariantCulture,
DatabasePrototypeAzure.SetRecursiveTriggersOptionFormat,
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
/// </summary>
/// <param name="dbName">Name of the database</param>
/// <param name="maxSize">MaxSize of the database</param>
/// <param name="serviceLevelObjective">New SLO of the database</param>
/// <returns>Sql Statement to Alter the database.</returns>
protected static string CreateModifySqlDwDbOptionsStatement(string dbName, 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,
ModifySqlDwDbStatementFormat,
maxSize,
sloOption));
}
/// <summary>
/// Creates the ALTER DATABASE statement from the given op
/// </summary>
/// <returns></returns>
private static string CreateAzureAlterDbStatement(string dbName, string options)
{
return string.Format(CultureInfo.InvariantCulture, AlterDbStatementFormat,
CUtils.EscapeString(CUtils.EscapeString(dbName, ']'), '\''),
options);
}
}
}

View File

@@ -0,0 +1,178 @@
//
// 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.Admin.Contracts;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
public class DatabaseTaskHelper
{
private DatabasePrototype prototype;
private XmlDocument document;
public CDataContainer DataContainer { get; set; }
/// <summary>
/// Expose database prototype to internal classes
/// </summary>
public DatabasePrototype Prototype
{
get
{
return this.prototype;
}
set
{
this.prototype = value;
}
}
public DatabaseTaskHelper(CDataContainer context)
{
Initialize(context);
}
internal void Initialize(CDataContainer context)
{
if (context != null)
{
this.DataContainer = context;
this.document = context.Document;
int majorVersionNumber = context.Server.Information.Version.Major;
Version sql2000sp3 = new Version(8, 0, 760);
Version sql2005sp2 = new Version(9, 0, 3000);
if (context.Server.DatabaseEngineType == DatabaseEngineType.SqlAzureDatabase)
{
this.prototype = new DatabasePrototypeAzure(context);
}
else if (Utils.IsSql11OrLater(context.Server.Version.Major))
{
this.prototype = new DatabasePrototype110(context);
}
else if (majorVersionNumber == 10)
{
this.prototype = new DatabasePrototype100(context);
}
else if ((sql2005sp2 <= context.Server.Information.Version) &&
(context.Server.Information.EngineEdition == Edition.EnterpriseOrDeveloper))
{
this.prototype = new DatabasePrototype90EnterpriseSP2(context);
}
else if (8 < majorVersionNumber)
{
this.prototype = new DatabasePrototype90(context);
}
else if (sql2000sp3 <= context.Server.Information.Version)
{
this.prototype = new DatabasePrototype80SP3(context);
}
else if (7 < majorVersionNumber)
{
this.prototype = new DatabasePrototype80(context);
}
else
{
this.prototype = new DatabasePrototype(context);
}
this.prototype.Initialize();
}
else
{
this.DataContainer = null;
this.document = null;
this.prototype = null;
}
}
internal static DatabaseInfo DatabasePrototypeToDatabaseInfo(DatabasePrototype prototype)
{
var databaseInfo = new DatabaseInfo();
databaseInfo.Options.Add(AdminServicesProviderOptionsHelper.Name, prototype.Name);
databaseInfo.Options.Add(AdminServicesProviderOptionsHelper.Owner, prototype.Owner);
databaseInfo.Options.Add(AdminServicesProviderOptionsHelper.Collation, prototype.Collation);
databaseInfo.Options.Add(AdminServicesProviderOptionsHelper.DatabaseState, prototype.DatabaseState.ToString());
databaseInfo.Options.Add(AdminServicesProviderOptionsHelper.IsSystemDB, prototype.IsSystemDB.ToString());
databaseInfo.Options.Add(AdminServicesProviderOptionsHelper.AnsiNulls, prototype.AnsiNulls.ToString());
databaseInfo.Options.Add(
AdminServicesProviderOptionsHelper.FileGroups + "Count",
prototype.Filegroups.Count);
for (int i = 0; i < prototype.Filegroups.Count; ++i)
{
var fileGroup = prototype.Filegroups[i];
string itemPrefix = AdminServicesProviderOptionsHelper.FileGroups + "." + i + ".";
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.Name, fileGroup.Name);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.IsMemoryOptimized, fileGroup.IsMemoryOptimized);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.IsReadOnly, fileGroup.IsReadOnly);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.IsFileStream, fileGroup.IsFileStream);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.IsDefault, fileGroup.IsDefault);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.FileGroupType, fileGroup.FileGroupType.ToString());
}
databaseInfo.Options.Add(
AdminServicesProviderOptionsHelper.DatabaseFiles + "Count",
prototype.Files.Count);
for (int i = 0; i < prototype.Files.Count; ++i)
{
var file = prototype.Files[i];
string itemPrefix = AdminServicesProviderOptionsHelper.DatabaseFiles + "." + i + ".";
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.Name, file.Name);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.PhysicalName, file.PhysicalName);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.Autogrowth, file.DefaultAutogrowth.ToString());
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.DatabaseFileType, file.DatabaseFileType.ToString());
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.Folder, file.DefaultFolder);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.Size, file.DefaultSize);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.FileGroup, file.FileGroup != null ? file.FileGroup.Name : string.Empty);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.InitialSize, file.InitialSize);
databaseInfo.Options.Add(itemPrefix + AdminServicesProviderOptionsHelper.IsPrimaryFile, file.IsPrimaryFile);
}
return databaseInfo;
}
private static T GetValueOrDefault<T>(string key, Dictionary<string, object> map, T defaultValue)
{
if (map != null && map.ContainsKey(key))
{
return map[key] != null ? (T)map[key] : default(T);
}
return defaultValue;
}
private static int logicalNameCount = 0;
public static DatabasePrototype ApplyToPrototype(DatabaseInfo databaseInfo, DatabasePrototype prototype)
{
if (databaseInfo != null && prototype != null)
{
prototype.Name = GetValueOrDefault(AdminServicesProviderOptionsHelper.Name, databaseInfo.Options, prototype.Name);
foreach (var file in prototype.Files)
{
if (string.IsNullOrWhiteSpace(file.Name))
{
file.Name = prototype.Name + "_" + logicalNameCount;
}
}
}
return prototype;
}
}
}