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

@@ -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