Enable QueryStore tab to the database properties (#2200)

* initial commit

* adding prototypefile and server conditions

* Saving query store options completed, todo:tests

* adding LOC stings  according to the LOC version of the ms doc

* removing common constants

* merge conflict fix

* fixing null reference exception

* Adjusting the null reference exception property value in prototype.cs

* removing unused directive

* test fix that checks wrong value

* Purge query store data changes

* adding comment and uncommented the line
This commit is contained in:
Sai Avishkar Sreerama
2023-09-07 16:35:44 -05:00
committed by GitHub
parent 703691e897
commit a053457ba1
18 changed files with 782 additions and 4 deletions

View File

@@ -56,6 +56,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
public string currentServiceLevelObjective;
public DbSize maxSize;
public string backupStorageRedundancy;
public QueryStoreOptions queryStoreOptions;
public bool closeCursorOnCommit;
public bool isReadOnly;
@@ -172,6 +173,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
this.queryOptimizerHotfixes = DatabaseScopedConfigurationOnOff.Off;
this.queryOptimizerHotfixesForSecondary = DatabaseScopedConfigurationOnOff.Primary;
this.isLedger = false;
this.queryStoreOptions = null;
//The following properties are introduced for contained databases.
//In case of plain old databases, these values should reflect the server configuration values.
@@ -562,6 +564,22 @@ WHERE do.database_id = @DbID
this.databaseScopedConfigurations = db.DatabaseScopedConfigurations;
}
// Supported from Sql Server 2016 and higher
// QueryStore properties are not initialized at the time of database creation
if (db.IsSupportedObject<QueryStoreOptions>())
{
try
{
var queryStoreActualStateProperty = db.QueryStoreOptions.ActualState;
this.queryStoreOptions = db.QueryStoreOptions;
}
catch (NullReferenceException)
{
//db.QueryStoreOptions is not null, but its properties(actualState...etc) are Not initialized and when accessing them it throws the null reference exception.
this.queryStoreOptions = null;
}
}
//Only fill in the Azure properties when connected to an Azure server
if (context.Server.ServerType == DatabaseEngineType.SqlAzureDatabase)
{
@@ -696,6 +714,7 @@ WHERE do.database_id = @DbID
this.backupStorageRedundancy = other.backupStorageRedundancy;
this.isLedger = other.isLedger;
this.databaseScopedConfigurations = other.databaseScopedConfigurations;
this.queryStoreOptions = other.queryStoreOptions;
}
/// <summary>
@@ -781,7 +800,8 @@ WHERE do.database_id = @DbID
(this.maxSize == other.maxSize) &&
(this.backupStorageRedundancy == other.backupStorageRedundancy) &&
(this.isLedger == other.isLedger) &&
(this.databaseScopedConfigurations == other.databaseScopedConfigurations);
(this.databaseScopedConfigurations == other.databaseScopedConfigurations) &&
(this.queryStoreOptions == other.queryStoreOptions);
return result;
}

View File

@@ -48,6 +48,20 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
}
}
[Category("Category_QueryStoreOptions")]
public QueryStoreOptions QueryStoreOptions
{
get
{
return this.currentState.queryStoreOptions;
}
set
{
this.currentState.queryStoreOptions = value;
this.NotifyObservers();
}
}
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
@@ -66,6 +80,52 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
db.DatabaseScopedConfigurations[i].ValueForSecondary = this.currentState.databaseScopedConfigurations[i].ValueForSecondary;
}
}
if (db.IsSupportedObject<QueryStoreOptions>() && this.currentState.queryStoreOptions != null)
{
if (!this.Exists || (db.QueryStoreOptions.DesiredState != this.currentState.queryStoreOptions.DesiredState))
{
db.QueryStoreOptions.DesiredState = this.currentState.queryStoreOptions.DesiredState;
}
if (this.currentState.queryStoreOptions.DesiredState != QueryStoreOperationMode.Off)
{
if (!this.Exists || (db.QueryStoreOptions.DataFlushIntervalInSeconds != this.currentState.queryStoreOptions.DataFlushIntervalInSeconds))
{
db.QueryStoreOptions.DataFlushIntervalInSeconds = this.currentState.queryStoreOptions.DataFlushIntervalInSeconds;
}
if (!this.Exists || (db.QueryStoreOptions.StatisticsCollectionIntervalInMinutes != this.currentState.queryStoreOptions.StatisticsCollectionIntervalInMinutes))
{
db.QueryStoreOptions.StatisticsCollectionIntervalInMinutes = this.currentState.queryStoreOptions.StatisticsCollectionIntervalInMinutes;
}
if (!this.Exists || (db.QueryStoreOptions.MaxPlansPerQuery != this.currentState.queryStoreOptions.MaxPlansPerQuery))
{
db.QueryStoreOptions.MaxPlansPerQuery = this.currentState.queryStoreOptions.MaxPlansPerQuery;
}
if (!this.Exists || (db.QueryStoreOptions.MaxStorageSizeInMB != this.currentState.queryStoreOptions.MaxStorageSizeInMB))
{
db.QueryStoreOptions.MaxStorageSizeInMB = this.currentState.queryStoreOptions.MaxStorageSizeInMB;
}
if (!this.Exists || (db.QueryStoreOptions.QueryCaptureMode != this.currentState.queryStoreOptions.QueryCaptureMode))
{
db.QueryStoreOptions.QueryCaptureMode = this.currentState.queryStoreOptions.QueryCaptureMode;
}
if (!this.Exists || (db.QueryStoreOptions.SizeBasedCleanupMode != this.currentState.queryStoreOptions.SizeBasedCleanupMode))
{
db.QueryStoreOptions.SizeBasedCleanupMode = this.currentState.queryStoreOptions.SizeBasedCleanupMode;
}
if (!this.Exists || (db.QueryStoreOptions.StaleQueryThresholdInDays != this.currentState.queryStoreOptions.StaleQueryThresholdInDays))
{
db.QueryStoreOptions.StaleQueryThresholdInDays = this.currentState.queryStoreOptions.StaleQueryThresholdInDays;
}
}
}
}
}
}

View File

@@ -75,6 +75,17 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
if (db.IsSupportedObject<QueryStoreOptions>() && this.currentState.queryStoreOptions != null)
{
if (this.currentState.queryStoreOptions.DesiredState != QueryStoreOperationMode.Off)
{
if (!this.Exists || (db.QueryStoreOptions.WaitStatsCaptureMode != this.currentState.queryStoreOptions.WaitStatsCaptureMode))
{
db.QueryStoreOptions.WaitStatsCaptureMode = this.currentState.queryStoreOptions.WaitStatsCaptureMode;
}
}
}
}
}
}

View File

@@ -0,0 +1,55 @@
//
// 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;
namespace Microsoft.SqlTools.ServiceLayer.Admin
{
/// <summary>
/// Database properties for SqlServer 2019
/// </summary>
internal class DatabasePrototype150 : DatabasePrototype140
{
/// <summary>
/// Database properties for SqlServer 2019 class constructor
/// </summary>
public DatabasePrototype150(CDataContainer context)
: base(context)
{
}
protected override void SaveProperties(Database db)
{
base.SaveProperties(db);
if (db.IsSupportedObject<QueryStoreOptions>() && this.currentState.queryStoreOptions != null)
{
if (this.currentState.queryStoreOptions.QueryCaptureMode == QueryStoreCaptureMode.Custom && this.currentState.queryStoreOptions.DesiredState != QueryStoreOperationMode.Off)
{
if (!this.Exists || (db.QueryStoreOptions.CapturePolicyExecutionCount != this.currentState.queryStoreOptions.CapturePolicyExecutionCount))
{
db.QueryStoreOptions.CapturePolicyExecutionCount = this.currentState.queryStoreOptions.CapturePolicyExecutionCount;
}
if (!this.Exists || (db.QueryStoreOptions.CapturePolicyStaleThresholdInHrs != this.currentState.queryStoreOptions.CapturePolicyStaleThresholdInHrs))
{
db.QueryStoreOptions.CapturePolicyStaleThresholdInHrs = this.currentState.queryStoreOptions.CapturePolicyStaleThresholdInHrs;
}
if (!this.Exists || (db.QueryStoreOptions.CapturePolicyTotalCompileCpuTimeInMS != this.currentState.queryStoreOptions.CapturePolicyTotalCompileCpuTimeInMS))
{
db.QueryStoreOptions.CapturePolicyTotalCompileCpuTimeInMS = this.currentState.queryStoreOptions.CapturePolicyTotalCompileCpuTimeInMS;
}
if (!this.Exists || (db.QueryStoreOptions.CapturePolicyTotalExecutionCpuTimeInMS != this.currentState.queryStoreOptions.CapturePolicyTotalExecutionCpuTimeInMS))
{
db.QueryStoreOptions.CapturePolicyTotalExecutionCpuTimeInMS = this.currentState.queryStoreOptions.CapturePolicyTotalExecutionCpuTimeInMS;
}
}
}
}
}
}

View File

@@ -12,7 +12,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
/// <summary>
/// Database properties for SqlServer 2022
/// </summary>
internal class DatabasePrototype160 : DatabasePrototype140
internal class DatabasePrototype160 : DatabasePrototype150
{
/// <summary>
/// Database properties for SqlServer 2022 class constructor

View File

@@ -65,7 +65,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Admin
{
this.prototype = new DatabasePrototype160(context);
}
else if (majorVersionNumber >= 14)
else if (majorVersionNumber == 15)
{
this.prototype = new DatabasePrototype150(context);
}
else if (majorVersionNumber == 14)
{
this.prototype = new DatabasePrototype140(context);
}

View File

@@ -10709,6 +10709,166 @@ namespace Microsoft.SqlTools.ServiceLayer
}
}
public static string querystorecapturemode_all
{
get
{
return Keys.GetString(Keys.querystorecapturemode_all);
}
}
public static string querystorecapturemode_auto
{
get
{
return Keys.GetString(Keys.querystorecapturemode_auto);
}
}
public static string querystorecapturemode_none
{
get
{
return Keys.GetString(Keys.querystorecapturemode_none);
}
}
public static string querystorecapturemode_custom
{
get
{
return Keys.GetString(Keys.querystorecapturemode_custom);
}
}
public static string queryStoreSizeBasedCleanupMode_Off
{
get
{
return Keys.GetString(Keys.queryStoreSizeBasedCleanupMode_Off);
}
}
public static string queryStoreSizeBasedCleanupMode_Auto
{
get
{
return Keys.GetString(Keys.queryStoreSizeBasedCleanupMode_Auto);
}
}
public static string statisticsCollectionInterval_OneMinute
{
get
{
return Keys.GetString(Keys.statisticsCollectionInterval_OneMinute);
}
}
public static string statisticsCollectionInterval_FiveMinutes
{
get
{
return Keys.GetString(Keys.statisticsCollectionInterval_FiveMinutes);
}
}
public static string statisticsCollectionInterval_TenMinutes
{
get
{
return Keys.GetString(Keys.statisticsCollectionInterval_TenMinutes);
}
}
public static string statisticsCollectionInterval_FifteenMinutes
{
get
{
return Keys.GetString(Keys.statisticsCollectionInterval_FifteenMinutes);
}
}
public static string statisticsCollectionInterval_ThirtyMinutes
{
get
{
return Keys.GetString(Keys.statisticsCollectionInterval_ThirtyMinutes);
}
}
public static string statisticsCollectionInterval_OneHour
{
get
{
return Keys.GetString(Keys.statisticsCollectionInterval_OneHour);
}
}
public static string statisticsCollectionInterval_OneDay
{
get
{
return Keys.GetString(Keys.statisticsCollectionInterval_OneDay);
}
}
public static string queryStore_stale_threshold_OneHour
{
get
{
return Keys.GetString(Keys.queryStore_stale_threshold_OneHour);
}
}
public static string queryStore_stale_threshold_FourHours
{
get
{
return Keys.GetString(Keys.queryStore_stale_threshold_FourHours);
}
}
public static string queryStore_stale_threshold_EightHours
{
get
{
return Keys.GetString(Keys.queryStore_stale_threshold_EightHours);
}
}
public static string queryStore_stale_threshold_TwelveHours
{
get
{
return Keys.GetString(Keys.queryStore_stale_threshold_TwelveHours);
}
}
public static string queryStore_stale_threshold_OneDay
{
get
{
return Keys.GetString(Keys.queryStore_stale_threshold_OneDay);
}
}
public static string queryStore_stale_threshold_ThreeDays
{
get
{
return Keys.GetString(Keys.queryStore_stale_threshold_ThreeDays);
}
}
public static string queryStore_stale_threshold_SevenDays
{
get
{
return Keys.GetString(Keys.queryStore_stale_threshold_SevenDays);
}
}
public static string BasicAzureEdition
{
get
@@ -15511,6 +15671,66 @@ namespace Microsoft.SqlTools.ServiceLayer
public const string databaseBackupDate_None = "databaseBackupDate_None";
public const string querystorecapturemode_all = "querystorecapturemode_all";
public const string querystorecapturemode_auto = "querystorecapturemode_auto";
public const string querystorecapturemode_none = "querystorecapturemode_none";
public const string querystorecapturemode_custom = "querystorecapturemode_custom";
public const string queryStoreSizeBasedCleanupMode_Off = "queryStoreSizeBasedCleanupMode_Off";
public const string queryStoreSizeBasedCleanupMode_Auto = "queryStoreSizeBasedCleanupMode_Auto";
public const string statisticsCollectionInterval_OneMinute = "statisticsCollectionInterval_OneMinute";
public const string statisticsCollectionInterval_FiveMinutes = "statisticsCollectionInterval_FiveMinutes";
public const string statisticsCollectionInterval_TenMinutes = "statisticsCollectionInterval_TenMinutes";
public const string statisticsCollectionInterval_FifteenMinutes = "statisticsCollectionInterval_FifteenMinutes";
public const string statisticsCollectionInterval_ThirtyMinutes = "statisticsCollectionInterval_ThirtyMinutes";
public const string statisticsCollectionInterval_OneHour = "statisticsCollectionInterval_OneHour";
public const string statisticsCollectionInterval_OneDay = "statisticsCollectionInterval_OneDay";
public const string queryStore_stale_threshold_OneHour = "queryStore_stale_threshold_OneHour";
public const string queryStore_stale_threshold_FourHours = "queryStore_stale_threshold_FourHours";
public const string queryStore_stale_threshold_EightHours = "queryStore_stale_threshold_EightHours";
public const string queryStore_stale_threshold_TwelveHours = "queryStore_stale_threshold_TwelveHours";
public const string queryStore_stale_threshold_OneDay = "queryStore_stale_threshold_OneDay";
public const string queryStore_stale_threshold_ThreeDays = "queryStore_stale_threshold_ThreeDays";
public const string queryStore_stale_threshold_SevenDays = "queryStore_stale_threshold_SevenDays";
public const string BasicAzureEdition = "BasicAzureEdition";

View File

@@ -5911,6 +5911,86 @@ The Query Processor estimates that implementing the following index could improv
<value>None</value>
<comment></comment>
</data>
<data name="querystorecapturemode_all" xml:space="preserve">
<value>All</value>
<comment></comment>
</data>
<data name="querystorecapturemode_auto" xml:space="preserve">
<value>Auto</value>
<comment></comment>
</data>
<data name="querystorecapturemode_none" xml:space="preserve">
<value>None</value>
<comment></comment>
</data>
<data name="querystorecapturemode_custom" xml:space="preserve">
<value>Custom</value>
<comment></comment>
</data>
<data name="queryStoreSizeBasedCleanupMode_Off" xml:space="preserve">
<value>Off</value>
<comment></comment>
</data>
<data name="queryStoreSizeBasedCleanupMode_Auto" xml:space="preserve">
<value>Auto</value>
<comment></comment>
</data>
<data name="statisticsCollectionInterval_OneMinute" xml:space="preserve">
<value>1 Minute</value>
<comment></comment>
</data>
<data name="statisticsCollectionInterval_FiveMinutes" xml:space="preserve">
<value>5 Minutes</value>
<comment></comment>
</data>
<data name="statisticsCollectionInterval_TenMinutes" xml:space="preserve">
<value>10 Minutes</value>
<comment></comment>
</data>
<data name="statisticsCollectionInterval_FifteenMinutes" xml:space="preserve">
<value>15 Minutes</value>
<comment></comment>
</data>
<data name="statisticsCollectionInterval_ThirtyMinutes" xml:space="preserve">
<value>30 Minutes</value>
<comment></comment>
</data>
<data name="statisticsCollectionInterval_OneHour" xml:space="preserve">
<value>1 Hour</value>
<comment></comment>
</data>
<data name="statisticsCollectionInterval_OneDay" xml:space="preserve">
<value>1 Day</value>
<comment></comment>
</data>
<data name="queryStore_stale_threshold_OneHour" xml:space="preserve">
<value>1 Hour</value>
<comment></comment>
</data>
<data name="queryStore_stale_threshold_FourHours" xml:space="preserve">
<value>4 Hours</value>
<comment></comment>
</data>
<data name="queryStore_stale_threshold_EightHours" xml:space="preserve">
<value>8 Hours</value>
<comment></comment>
</data>
<data name="queryStore_stale_threshold_TwelveHours" xml:space="preserve">
<value>12 Hours</value>
<comment></comment>
</data>
<data name="queryStore_stale_threshold_OneDay" xml:space="preserve">
<value>1 Day</value>
<comment></comment>
</data>
<data name="queryStore_stale_threshold_ThreeDays" xml:space="preserve">
<value>3 Days</value>
<comment></comment>
</data>
<data name="queryStore_stale_threshold_SevenDays" xml:space="preserve">
<value>7 Days</value>
<comment></comment>
</data>
<data name="BasicAzureEdition" xml:space="preserve">
<value>Basic</value>
<comment></comment>

View File

@@ -2390,6 +2390,26 @@ general_containmentType_Partial = Partial
filegroups_filestreamFiles = FILESTREAM Files
prototype_file_noApplicableFileGroup = No Applicable Filegroup
databaseBackupDate_None = None
querystorecapturemode_all = All
querystorecapturemode_auto = Auto
querystorecapturemode_none = None
querystorecapturemode_custom = Custom
queryStoreSizeBasedCleanupMode_Off = Off
queryStoreSizeBasedCleanupMode_Auto = Auto
statisticsCollectionInterval_OneMinute = 1 Minute
statisticsCollectionInterval_FiveMinutes = 5 Minutes
statisticsCollectionInterval_TenMinutes = 10 Minutes
statisticsCollectionInterval_FifteenMinutes = 15 Minutes
statisticsCollectionInterval_ThirtyMinutes = 30 Minutes
statisticsCollectionInterval_OneHour = 1 Hour
statisticsCollectionInterval_OneDay = 1 Day
queryStore_stale_threshold_OneHour = 1 Hour
queryStore_stale_threshold_FourHours = 4 Hours
queryStore_stale_threshold_EightHours = 8 Hours
queryStore_stale_threshold_TwelveHours = 12 Hours
queryStore_stale_threshold_OneDay = 1 Day
queryStore_stale_threshold_ThreeDays = 3 Days
queryStore_stale_threshold_SevenDays = 7 Days
############################################################################
# Azure SQL DB

View File

@@ -7264,6 +7264,106 @@ The Query Processor estimates that implementing the following index could improv
<target state="new">Failed to find connection info about the server</target>
<note></note>
</trans-unit>
<trans-unit id="querystorecapturemode_all">
<source>All</source>
<target state="new">All</target>
<note></note>
</trans-unit>
<trans-unit id="querystorecapturemode_auto">
<source>Auto</source>
<target state="new">Auto</target>
<note></note>
</trans-unit>
<trans-unit id="querystorecapturemode_none">
<source>None</source>
<target state="new">None</target>
<note></note>
</trans-unit>
<trans-unit id="querystorecapturemode_custom">
<source>Custom</source>
<target state="new">Custom</target>
<note></note>
</trans-unit>
<trans-unit id="queryStoreSizeBasedCleanupMode_Off">
<source>Off</source>
<target state="new">Off</target>
<note></note>
</trans-unit>
<trans-unit id="queryStoreSizeBasedCleanupMode_Auto">
<source>Auto</source>
<target state="new">Auto</target>
<note></note>
</trans-unit>
<trans-unit id="statisticsCollectionInterval_OneMinute">
<source>1 Minute</source>
<target state="new">1 Minute</target>
<note></note>
</trans-unit>
<trans-unit id="statisticsCollectionInterval_FiveMinutes">
<source>5 Minutes</source>
<target state="new">5 Minutes</target>
<note></note>
</trans-unit>
<trans-unit id="statisticsCollectionInterval_TenMinutes">
<source>10 Minutes</source>
<target state="new">10 Minutes</target>
<note></note>
</trans-unit>
<trans-unit id="statisticsCollectionInterval_FifteenMinutes">
<source>15 Minutes</source>
<target state="new">15 Minutes</target>
<note></note>
</trans-unit>
<trans-unit id="statisticsCollectionInterval_ThirtyMinutes">
<source>30 Minutes</source>
<target state="new">30 Minutes</target>
<note></note>
</trans-unit>
<trans-unit id="statisticsCollectionInterval_OneHour">
<source>1 Hour</source>
<target state="new">1 Hour</target>
<note></note>
</trans-unit>
<trans-unit id="statisticsCollectionInterval_OneDay">
<source>1 Day</source>
<target state="new">1 Day</target>
<note></note>
</trans-unit>
<trans-unit id="queryStore_stale_threshold_OneHour">
<source>1 Hour</source>
<target state="new">1 Hour</target>
<note></note>
</trans-unit>
<trans-unit id="queryStore_stale_threshold_FourHours">
<source>4 Hours</source>
<target state="new">4 Hours</target>
<note></note>
</trans-unit>
<trans-unit id="queryStore_stale_threshold_EightHours">
<source>8 Hours</source>
<target state="new">8 Hours</target>
<note></note>
</trans-unit>
<trans-unit id="queryStore_stale_threshold_TwelveHours">
<source>12 Hours</source>
<target state="new">12 Hours</target>
<note></note>
</trans-unit>
<trans-unit id="queryStore_stale_threshold_OneDay">
<source>1 Day</source>
<target state="new">1 Day</target>
<note></note>
</trans-unit>
<trans-unit id="queryStore_stale_threshold_ThreeDays">
<source>3 Days</source>
<target state="new">3 Days</target>
<note></note>
</trans-unit>
<trans-unit id="queryStore_stale_threshold_SevenDays">
<source>7 Days</source>
<target state="new">7 Days</target>
<note></note>
</trans-unit>
</body>
</file>
</xliff>

View File

@@ -0,0 +1,34 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
#nullable disable
using Microsoft.SqlTools.Hosting.Protocol.Contracts;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement.Contracts
{
public class PurgeQueryStoreDataRequestParams : GeneralRequestDetails
{
/// <summary>
/// SFC (SMO) URN identifying the object
/// </summary>
public string ObjectUrn { get; set; }
/// <summary>
/// The target database name.
/// </summary>
public string Database { get; set; }
/// <summary>
/// URI of the underlying connection for this request
/// </summary>
public string ConnectionUri { get; set; }
}
public class PurgeQueryStoreDataRequestResponse { }
public class PurgeQueryStoreDataRequest
{
public static readonly RequestType<PurgeQueryStoreDataRequestParams, PurgeQueryStoreDataRequestResponse> Type = RequestType<PurgeQueryStoreDataRequestParams, PurgeQueryStoreDataRequestResponse>.Create("objectManagement/purgeQueryStoreData");
}
}

View File

@@ -72,6 +72,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
this.serviceHost.SetRequestHandler(DetachDatabaseRequest.Type, HandleDetachDatabaseRequest, true);
this.serviceHost.SetRequestHandler(AttachDatabaseRequest.Type, HandleAttachDatabaseRequest, true);
this.serviceHost.SetRequestHandler(DropDatabaseRequest.Type, HandleDropDatabaseRequest, true);
this.serviceHost.SetRequestHandler(PurgeQueryStoreDataRequest.Type, HandlePurgeQueryStoreDataRequest, true);
}
internal async Task HandleRenameRequest(RenameRequestParams requestParams, RequestContext<RenameRequestResponse> requestContext)
@@ -222,6 +223,13 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
await requestContext.SendResult(sqlScript);
}
internal async Task HandlePurgeQueryStoreDataRequest(PurgeQueryStoreDataRequestParams requestParams, RequestContext<PurgeQueryStoreDataRequestResponse> requestContext)
{
var handler = this.GetObjectTypeHandler(SqlObjectType.Database) as DatabaseHandler;
handler.PurgeQueryStoreData(requestParams);
await requestContext.SendResult(new PurgeQueryStoreDataRequestResponse());
}
private IObjectTypeHandler GetObjectTypeHandler(SqlObjectType objectType)
{
foreach (var handler in objectTypeHandlers)

View File

@@ -42,11 +42,20 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
private static readonly Dictionary<PageVerify, string> displayPageVerifyOptions = new Dictionary<PageVerify, string>();
private static readonly Dictionary<DatabaseUserAccess, string> displayRestrictAccessOptions = new Dictionary<DatabaseUserAccess, string>();
private static readonly ConcurrentDictionary<FileType, string> displayFileTypes = new ConcurrentDictionary<FileType, string>();
private static readonly ConcurrentDictionary<QueryStoreOperationMode, string> displayOperationModeOptions = new ConcurrentDictionary<QueryStoreOperationMode, string>();
private static readonly ConcurrentDictionary<QueryStoreCaptureMode, string> displayQueryStoreCaptureModeOptions = new ConcurrentDictionary<QueryStoreCaptureMode, string>();
private static readonly SortedDictionary<int, string> displayStatisticsCollectionIntervalInMinutes = new SortedDictionary<int, string>();
private static readonly SortedDictionary<int, string> displayQueryStoreStaleThresholdInHours = new SortedDictionary<int, string>();
private static readonly ConcurrentDictionary<QueryStoreSizeBasedCleanupMode, string> displaySizeBasedCleanupMode = new ConcurrentDictionary<QueryStoreSizeBasedCleanupMode, string>();
private static readonly Dictionary<string, CompatibilityLevel> compatLevelEnums = new Dictionary<string, CompatibilityLevel>();
private static readonly Dictionary<string, ContainmentType> containmentTypeEnums = new Dictionary<string, ContainmentType>();
private static readonly Dictionary<string, RecoveryModel> recoveryModelEnums = new Dictionary<string, RecoveryModel>();
private static readonly Dictionary<string, FileType> fileTypesEnums = new Dictionary<string, FileType>();
private static readonly Dictionary<string, QueryStoreOperationMode> operationModeEnums = new Dictionary<string, QueryStoreOperationMode>();
private static readonly Dictionary<string, QueryStoreCaptureMode> captureModeEnums = new Dictionary<string, QueryStoreCaptureMode>();
private static readonly Dictionary<string, int> statisticsCollectionIntervalValues = new Dictionary<string, int>();
private static readonly Dictionary<string, int> queryStoreStaleThresholdValues = new Dictionary<string, int>();
internal static readonly string[] AzureEditionNames;
internal static readonly string[] AzureBackupLevels;
@@ -89,6 +98,33 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
displayFileTypes.TryAdd(FileType.Log, SR.prototype_file_logFile);
displayFileTypes.TryAdd(FileType.FileStream, SR.prototype_file_filestreamFile);
displayOperationModeOptions.TryAdd(QueryStoreOperationMode.Off, CommonConstants.QueryStoreOperationMode_Off);
displayOperationModeOptions.TryAdd(QueryStoreOperationMode.ReadOnly, CommonConstants.QueryStoreOperationMode_ReadOnly);
displayOperationModeOptions.TryAdd(QueryStoreOperationMode.ReadWrite, CommonConstants.QueryStoreOperationMode_ReadWrite);
displayQueryStoreCaptureModeOptions.TryAdd(QueryStoreCaptureMode.All, SR.querystorecapturemode_all);
displayQueryStoreCaptureModeOptions.TryAdd(QueryStoreCaptureMode.Auto, SR.querystorecapturemode_auto);
displayQueryStoreCaptureModeOptions.TryAdd(QueryStoreCaptureMode.None, SR.querystorecapturemode_none);
displayStatisticsCollectionIntervalInMinutes.TryAdd(1, SR.statisticsCollectionInterval_OneMinute);
displayStatisticsCollectionIntervalInMinutes.TryAdd(5, SR.statisticsCollectionInterval_FiveMinutes);
displayStatisticsCollectionIntervalInMinutes.TryAdd(10, SR.statisticsCollectionInterval_TenMinutes);
displayStatisticsCollectionIntervalInMinutes.TryAdd(15, SR.statisticsCollectionInterval_FifteenMinutes);
displayStatisticsCollectionIntervalInMinutes.TryAdd(30, SR.statisticsCollectionInterval_ThirtyMinutes);
displayStatisticsCollectionIntervalInMinutes.TryAdd(60, SR.statisticsCollectionInterval_OneHour);
displayStatisticsCollectionIntervalInMinutes.TryAdd(1440, SR.statisticsCollectionInterval_OneDay);
displayQueryStoreStaleThresholdInHours.TryAdd(1, SR.queryStore_stale_threshold_OneHour);
displayQueryStoreStaleThresholdInHours.TryAdd(4, SR.queryStore_stale_threshold_FourHours);
displayQueryStoreStaleThresholdInHours.TryAdd(8, SR.queryStore_stale_threshold_EightHours);
displayQueryStoreStaleThresholdInHours.TryAdd(12, SR.queryStore_stale_threshold_TwelveHours);
displayQueryStoreStaleThresholdInHours.TryAdd(24, SR.queryStore_stale_threshold_OneDay);
displayQueryStoreStaleThresholdInHours.TryAdd(72, SR.queryStore_stale_threshold_ThreeDays);
displayQueryStoreStaleThresholdInHours.TryAdd(168, SR.queryStore_stale_threshold_SevenDays);
displaySizeBasedCleanupMode.TryAdd(QueryStoreSizeBasedCleanupMode.Off, SR.queryStoreSizeBasedCleanupMode_Off);
displaySizeBasedCleanupMode.TryAdd(QueryStoreSizeBasedCleanupMode.Auto, SR.queryStoreSizeBasedCleanupMode_Auto);
DscOnOffOptions = new[]{
CommonConstants.DatabaseScopedConfigurations_Value_On,
CommonConstants.DatabaseScopedConfigurations_Value_Off
@@ -123,6 +159,22 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
{
fileTypesEnums.Add(displayFileTypes[key], key);
}
foreach (QueryStoreOperationMode key in displayOperationModeOptions.Keys)
{
operationModeEnums.Add(displayOperationModeOptions[key], key);
}
foreach (QueryStoreCaptureMode key in displayQueryStoreCaptureModeOptions.Keys)
{
captureModeEnums.Add(displayQueryStoreCaptureModeOptions[key], key);
}
foreach (KeyValuePair<int, string> pair in displayStatisticsCollectionIntervalInMinutes)
{
statisticsCollectionIntervalValues.Add(pair.Value, pair.Key);
}
foreach (KeyValuePair<int, string> pair in displayQueryStoreStaleThresholdInHours)
{
queryStoreStaleThresholdValues.Add(pair.Value, pair.Key);
}
// Azure SLO info is invariant of server information, so set up static objects we can return later
var editions = AzureSqlDbHelper.GetValidAzureEditionOptions();
@@ -202,6 +254,38 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
((DatabaseInfo)databaseViewInfo.ObjectInfo).RecoveryModel = displayRecoveryModels[smoDatabase.RecoveryModel];
((DatabaseInfo)databaseViewInfo.ObjectInfo).LastDatabaseBackup = smoDatabase.LastBackupDate == DateTime.MinValue ? SR.databaseBackupDate_None : smoDatabase.LastBackupDate.ToString();
((DatabaseInfo)databaseViewInfo.ObjectInfo).LastDatabaseLogBackup = smoDatabase.LastLogBackupDate == DateTime.MinValue ? SR.databaseBackupDate_None : smoDatabase.LastLogBackupDate.ToString();
if (prototype is DatabasePrototype130)
{
((DatabaseInfo)databaseViewInfo.ObjectInfo).QueryStoreOptions = new QueryStoreOptions()
{
ActualMode = displayOperationModeOptions[smoDatabase.QueryStoreOptions.ActualState],
DataFlushIntervalInMinutes = smoDatabase.QueryStoreOptions.DataFlushIntervalInSeconds / 60,
StatisticsCollectionInterval = displayStatisticsCollectionIntervalInMinutes[(int)smoDatabase.QueryStoreOptions.StatisticsCollectionIntervalInMinutes],
MaxPlansPerQuery = smoDatabase.QueryStoreOptions.MaxPlansPerQuery,
MaxSizeInMB = smoDatabase.QueryStoreOptions.MaxStorageSizeInMB,
QueryStoreCaptureMode = smoDatabase.QueryStoreOptions.QueryCaptureMode.ToString(),
SizeBasedCleanupMode = smoDatabase.QueryStoreOptions.SizeBasedCleanupMode.ToString(),
StaleQueryThresholdInDays = smoDatabase.QueryStoreOptions.StaleQueryThresholdInDays,
CurrentStorageSizeInMB = smoDatabase.QueryStoreOptions.CurrentStorageSizeInMB
};
if (prototype is DatabasePrototype140)
{
((DatabaseInfo)databaseViewInfo.ObjectInfo).QueryStoreOptions!.WaitStatisticsCaptureMode = smoDatabase.QueryStoreOptions.WaitStatsCaptureMode == QueryStoreWaitStatsCaptureMode.On;
};
if (prototype is DatabasePrototype150)
{
((DatabaseInfo)databaseViewInfo.ObjectInfo).QueryStoreOptions!.CapturePolicyOptions = new QueryStoreCapturePolicyOptions()
{
ExecutionCount = smoDatabase.QueryStoreOptions.CapturePolicyExecutionCount,
StaleThreshold = displayQueryStoreStaleThresholdInHours[(int)smoDatabase.QueryStoreOptions.CapturePolicyStaleThresholdInHrs],
TotalCompileCPUTimeInMS = smoDatabase.QueryStoreOptions.CapturePolicyTotalCompileCpuTimeInMS,
TotalExecutionCPUTimeInMS = smoDatabase.QueryStoreOptions.CapturePolicyTotalExecutionCpuTimeInMS
};
// Sql Server 2019 and higher only support the custom query store capture mode
displayQueryStoreCaptureModeOptions.TryAdd(QueryStoreCaptureMode.Custom, SR.querystorecapturemode_custom);
}
}
}
if (!isManagedInstance)
{
@@ -229,6 +313,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
databaseViewInfo.DscOnOffOptions = DscOnOffOptions;
databaseViewInfo.DscElevateOptions = DscElevateOptions;
databaseViewInfo.DscEnableDisableOptions = DscEnableDisableOptions;
databaseViewInfo.OperationModeOptions = displayOperationModeOptions.Values.ToArray();
databaseViewInfo.QueryStoreCaptureModeOptions = displayQueryStoreCaptureModeOptions.Values.ToArray();
databaseViewInfo.StatisticsCollectionIntervalOptions = displayStatisticsCollectionIntervalInMinutes.Values.ToArray();
databaseViewInfo.StaleThresholdOptions = displayQueryStoreStaleThresholdInHours.Values.ToArray();
databaseViewInfo.SizeBasedCleanupModeOptions = displaySizeBasedCleanupMode.Values.ToArray();
}
// azure sql db doesn't have a sysadmin fixed role
@@ -541,6 +630,22 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
return sqlScript;
}
/// <summary>
/// Clears all query store data from the database
/// </summary>
/// <param name="purgeParams"></param>
public void PurgeQueryStoreData(PurgeQueryStoreDataRequestParams purgeParams)
{
using (var dataContainer = CreateDatabaseDataContainer(purgeParams.ConnectionUri, purgeParams.ObjectUrn, false, purgeParams.Database))
{
var smoDatabase = dataContainer.SqlDialogSubject as Database;
if (smoDatabase != null)
{
smoDatabase.QueryStoreOptions.PurgeQueryStoreData();
}
}
}
private CDataContainer CreateDatabaseDataContainer(string connectionUri, string? objectURN, bool isNewDatabase, string? databaseName)
{
ConnectionInfo connectionInfo = this.GetConnectionInfo(connectionUri);
@@ -684,6 +789,34 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
}
db130.DatabaseScopedConfiguration = databaseScopedConfigurationsCollection;
}
if (!viewParams.IsNewObject && database.QueryStoreOptions != null)
{
// Sql Server 2019 and higher supports custom query store capture mode
captureModeEnums.TryAdd(SR.querystorecapturemode_custom, QueryStoreCaptureMode.Custom);
db130.QueryStoreOptions.DesiredState = operationModeEnums[database.QueryStoreOptions.ActualMode];
db130.QueryStoreOptions.DataFlushIntervalInSeconds = database.QueryStoreOptions.DataFlushIntervalInMinutes * 60;
db130.QueryStoreOptions.StatisticsCollectionIntervalInMinutes = statisticsCollectionIntervalValues[database.QueryStoreOptions.StatisticsCollectionInterval];
db130.QueryStoreOptions.MaxPlansPerQuery = database.QueryStoreOptions.MaxPlansPerQuery;
db130.QueryStoreOptions.MaxStorageSizeInMB = database.QueryStoreOptions.MaxSizeInMB;
db130.QueryStoreOptions.QueryCaptureMode = captureModeEnums[database.QueryStoreOptions.QueryStoreCaptureMode];
db130.QueryStoreOptions.SizeBasedCleanupMode = database.QueryStoreOptions.SizeBasedCleanupMode == SR.queryStoreSizeBasedCleanupMode_Off ? QueryStoreSizeBasedCleanupMode.Off : QueryStoreSizeBasedCleanupMode.Auto;
db130.QueryStoreOptions.StaleQueryThresholdInDays = database.QueryStoreOptions.StaleQueryThresholdInDays;
if (prototype is DatabasePrototype140 db140 && database.QueryStoreOptions.WaitStatisticsCaptureMode != null)
{
db140.QueryStoreOptions.WaitStatsCaptureMode = (bool)database.QueryStoreOptions.WaitStatisticsCaptureMode ? QueryStoreWaitStatsCaptureMode.On : QueryStoreWaitStatsCaptureMode.Off;
}
if (prototype is DatabasePrototype150 db150 && database.QueryStoreOptions.QueryStoreCaptureMode == SR.querystorecapturemode_custom
&& database.QueryStoreOptions.CapturePolicyOptions != null)
{
db150.QueryStoreOptions.CapturePolicyExecutionCount = database.QueryStoreOptions.CapturePolicyOptions.ExecutionCount;
db150.QueryStoreOptions.CapturePolicyStaleThresholdInHrs = queryStoreStaleThresholdValues[database.QueryStoreOptions.CapturePolicyOptions.StaleThreshold];
db150.QueryStoreOptions.CapturePolicyTotalCompileCpuTimeInMS = database.QueryStoreOptions.CapturePolicyOptions.TotalCompileCPUTimeInMS;
db150.QueryStoreOptions.CapturePolicyTotalExecutionCpuTimeInMS = database.QueryStoreOptions.CapturePolicyOptions.TotalCompileCPUTimeInMS;
}
}
}
if (!viewParams.IsNewObject && database.Files != null)

View File

@@ -45,6 +45,7 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public bool? IsFilesTabSupported { get; set; }
public DatabaseFile[] Files { get; set; }
public FileGroupSummary[]? Filegroups { get; set; }
public QueryStoreOptions? QueryStoreOptions { get; set; }
}
public class DatabaseScopedConfigurationsInfo
@@ -80,4 +81,26 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public bool AutogrowAllFiles { get; set; }
}
public class QueryStoreOptions
{
public string ActualMode { get; set; }
public long DataFlushIntervalInMinutes { get; set; }
public string StatisticsCollectionInterval { get; set; }
public long MaxPlansPerQuery { get; set; }
public long MaxSizeInMB { get; set; }
public string QueryStoreCaptureMode { get; set; }
public string SizeBasedCleanupMode { get; set; }
public long StaleQueryThresholdInDays { get; set; }
public bool? WaitStatisticsCaptureMode { get; set; }
public QueryStoreCapturePolicyOptions? CapturePolicyOptions { get; set; }
public long CurrentStorageSizeInMB { get; set; }
}
public class QueryStoreCapturePolicyOptions
{
public int ExecutionCount { get; set; }
public string StaleThreshold { get; set; }
public long TotalCompileCPUTimeInMS { get; set; }
public long TotalExecutionCPUTimeInMS { get; set; }
}
}

View File

@@ -28,6 +28,11 @@ namespace Microsoft.SqlTools.ServiceLayer.ObjectManagement
public string[] DscElevateOptions { get; set; }
public string[] DscEnableDisableOptions { get; set; }
public string[] FileTypesOptions { get; set; }
public string[] OperationModeOptions { get; set; }
public string[] StatisticsCollectionIntervalOptions { get; set; }
public string[] QueryStoreCaptureModeOptions { get; set; }
public string[] SizeBasedCleanupModeOptions { get; set; }
public string[] StaleThresholdOptions { get; set; }
}
public class AzureEditionDetails

View File

@@ -25,5 +25,8 @@ namespace Microsoft.SqlTools.SqlCore.Utility
public const string DatabaseScopedConfigurations_Value_Fail_Unsupported = "FAIL_UNSUPPORTED";
public const string DatabaseScopedConfigurations_Value_Enabled = "ENABLED";
public const string DatabaseScopedConfigurations_Value_Disabled = "DISABLED";
public const string QueryStoreOperationMode_Off = "Off";
public const string QueryStoreOperationMode_ReadOnly = "Read Only";
public const string QueryStoreOperationMode_ReadWrite = "Read Write";
}
}

View File

@@ -311,6 +311,7 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files[0].Type, Is.EqualTo("ROWS Data"), $"Database files first file should be Row type database files");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).Files[1].Type, Is.EqualTo("LOG"), $"Database files first file should be Log type database files");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).Filegroups?.Length, Is.GreaterThan(0), $"Database file groups should exists");
Assert.That(((DatabaseInfo)databaseViewInfo.ObjectInfo).QueryStoreOptions, Is.Not.Null, $"Database Query store options are not null");
// cleanup
await ObjectManagementTestUtils.DropObject(connectionResult.ConnectionInfo.OwnerUri, objUrn, throwIfNotExist: true);

View File

@@ -83,7 +83,8 @@ namespace Microsoft.SqlTools.ServiceLayer.IntegrationTests.ObjectManagement
AutoShrink = false,
AutoUpdateStatistics = true,
AutoUpdateStatisticsAsynchronously = false,
DatabaseScopedConfigurations = null
DatabaseScopedConfigurations = null,
QueryStoreOptions = null
};
}