From 08d004b4880c8498c41b41fef79aaddd0d14f727 Mon Sep 17 00:00:00 2001 From: Drew Skwiers-Koballa Date: Thu, 16 Jan 2025 16:39:56 -0800 Subject: [PATCH 1/5] wait_stats_capture_mode querystore option parse and gen --- SqlScriptDom/Parser/TSql/Ast.xml | 4 +++ .../Parser/TSql/CodeGenerationSupporter.cs | 3 ++- .../Parser/TSql/QueryStoreOptionKind.cs | 3 ++- .../Parser/TSql/QueryStoreOptionsHelper.cs | 1 + SqlScriptDom/Parser/TSql/TSql140.g | 27 +++++++++++++++++++ SqlScriptDom/Parser/TSql/TSql150.g | 27 +++++++++++++++++++ SqlScriptDom/Parser/TSql/TSql160.g | 27 +++++++++++++++++++ SqlScriptDom/Parser/TSql/TSql170.g | 27 +++++++++++++++++++ 8 files changed, 117 insertions(+), 2 deletions(-) diff --git a/SqlScriptDom/Parser/TSql/Ast.xml b/SqlScriptDom/Parser/TSql/Ast.xml index 24ef837..5c73908 100644 --- a/SqlScriptDom/Parser/TSql/Ast.xml +++ b/SqlScriptDom/Parser/TSql/Ast.xml @@ -2529,6 +2529,10 @@ + + + + diff --git a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs index 918e01c..4d4a999 100644 --- a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs +++ b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs @@ -1076,6 +1076,7 @@ internal static class CodeGenerationSupporter internal const string VirtualDevice = "VIRTUAL_DEVICE"; internal const string VStart = "VSTART"; internal const string WaitAtLowPriority = "WAIT_AT_LOW_PRIORITY"; + internal const string WaitStatsCaptureMode = "WAIT_STATS_CAPTURE_MODE"; internal const string WebMethod = "WEBMETHOD"; internal const string WellFormedXml = "WELL_FORMED_XML"; internal const string WideChar = "WIDECHAR"; @@ -1263,7 +1264,7 @@ internal static class CodeGenerationSupporter internal const string Russian = "RUSSIAN"; internal const string Romanian = "ROMANIAN"; internal const string Brazilian = "BRAZILIAN"; - internal const string NorwegianBokmal = "NORWEGIAN (BOKMÅL)"; + internal const string NorwegianBokmal = "NORWEGIAN (BOKM�L)"; internal const string Dutch = "DUTCH"; internal const string Korean = "KOREAN"; internal const string Japanese = "JAPANESE"; diff --git a/SqlScriptDom/Parser/TSql/QueryStoreOptionKind.cs b/SqlScriptDom/Parser/TSql/QueryStoreOptionKind.cs index 39d2ed3..6271914 100644 --- a/SqlScriptDom/Parser/TSql/QueryStoreOptionKind.cs +++ b/SqlScriptDom/Parser/TSql/QueryStoreOptionKind.cs @@ -21,7 +21,8 @@ public enum QueryStoreOptionKind Interval_Length_Minutes, Current_Storage_Size_MB, Max_Plans_Per_Query, - Stale_Query_Threshold_Days + Stale_Query_Threshold_Days, + Wait_Stats_Capture_Mode } diff --git a/SqlScriptDom/Parser/TSql/QueryStoreOptionsHelper.cs b/SqlScriptDom/Parser/TSql/QueryStoreOptionsHelper.cs index 2aca14e..17b194e 100644 --- a/SqlScriptDom/Parser/TSql/QueryStoreOptionsHelper.cs +++ b/SqlScriptDom/Parser/TSql/QueryStoreOptionsHelper.cs @@ -26,6 +26,7 @@ private QueryStoreOptionsHelper() AddOptionMapping(QueryStoreOptionKind.Current_Storage_Size_MB, CodeGenerationSupporter.MaxQdsSize); AddOptionMapping(QueryStoreOptionKind.Max_Plans_Per_Query, CodeGenerationSupporter.MaxPlansPerQuery); AddOptionMapping(QueryStoreOptionKind.Stale_Query_Threshold_Days, CodeGenerationSupporter.CleanupPolicy); + AddOptionMapping(QueryStoreOptionKind.Wait_Stats_Capture_Mode, CodeGenerationSupporter.WaitStatsCaptureMode, SqlVersionFlags.TSql140AndAbove); } internal static readonly QueryStoreOptionsHelper Instance = new QueryStoreOptionsHelper(); diff --git a/SqlScriptDom/Parser/TSql/TSql140.g b/SqlScriptDom/Parser/TSql/TSql140.g index 08042c5..1311d88 100644 --- a/SqlScriptDom/Parser/TSql/TSql140.g +++ b/SqlScriptDom/Parser/TSql/TSql140.g @@ -3144,6 +3144,9 @@ queryStoreOneOption returns [QueryStoreOption vResult = null] | {NextTokenMatches(CodeGenerationSupporter.CleanupPolicy)}? vResult = queryStoreTimeCleanupPolicy + | + {NextTokenMatches(CodeGenerationSupporter.WaitStatsCaptureMode)}? + vResult = queryStoreWaitStatsCaptureOption ; queryStoreDesiredStateOption returns [QueryStoreDesiredStateOption vResult = FragmentFactory.CreateFragment()] @@ -3326,6 +3329,30 @@ queryStoreTimeCleanupPolicy returns [QueryStoreTimeCleanupPolicyOption vResult = } ; +queryStoreWaitStatsCaptureOption returns [QueryStoreWaitStatsCaptureOption vResult = FragmentFactory.CreateFragment()] + : tWaitStatsCaptureMode:Identifier + { + Match(tWaitStatsCaptureMode, CodeGenerationSupporter.WaitStatsCaptureMode); + vResult.OptionKind = QueryStoreOptionKind.Wait_Stats_Capture_Mode; + UpdateTokenInfo(vResult, tWaitStatsCaptureMode); + } + ( + (EqualsSign tOff:Off + { + vResult.OptionState = OptionState.Off; + UpdateTokenInfo(vResult, tOff); + } + ) + | + (EqualsSign tOn:On + { + vResult.OptionState = OptionState.On; + UpdateTokenInfo(vResult, tOn); + } + ) + ) + ; + automaticTuningDbOption returns [AutomaticTuningDatabaseOption vResult = FragmentFactory.CreateFragment()] : tAutomaticTuning:Identifier { diff --git a/SqlScriptDom/Parser/TSql/TSql150.g b/SqlScriptDom/Parser/TSql/TSql150.g index d04b752..555902c 100644 --- a/SqlScriptDom/Parser/TSql/TSql150.g +++ b/SqlScriptDom/Parser/TSql/TSql150.g @@ -3667,6 +3667,9 @@ queryStoreOneOption returns [QueryStoreOption vResult = null] | {NextTokenMatches(CodeGenerationSupporter.CleanupPolicy)}? vResult = queryStoreTimeCleanupPolicy + | + {NextTokenMatches(CodeGenerationSupporter.WaitStatsCaptureMode)}? + vResult = queryStoreWaitStatsCaptureOption ; queryStoreDesiredStateOption returns [QueryStoreDesiredStateOption vResult = FragmentFactory.CreateFragment()] @@ -3894,6 +3897,30 @@ automaticTuningDbOption returns [AutomaticTuningDatabaseOption vResult = Fragmen ) ; +queryStoreWaitStatsCaptureOption returns [QueryStoreWaitStatsCaptureOption vResult = FragmentFactory.CreateFragment()] + : tWaitStatsCaptureMode:Identifier + { + Match(tWaitStatsCaptureMode, CodeGenerationSupporter.WaitStatsCaptureMode); + vResult.OptionKind = QueryStoreOptionKind.Wait_Stats_Capture_Mode; + UpdateTokenInfo(vResult, tWaitStatsCaptureMode); + } + ( + (EqualsSign tOff:Off + { + vResult.OptionState = OptionState.Off; + UpdateTokenInfo(vResult, tOff); + } + ) + | + (EqualsSign tOn:On + { + vResult.OptionState = OptionState.On; + UpdateTokenInfo(vResult, tOn); + } + ) + ) + ; + automaticTuningOptions [AutomaticTuningDatabaseOption vParent] { AutomaticTuningOption vAutomaticTuningOption; diff --git a/SqlScriptDom/Parser/TSql/TSql160.g b/SqlScriptDom/Parser/TSql/TSql160.g index ea2694c..913e2a0 100644 --- a/SqlScriptDom/Parser/TSql/TSql160.g +++ b/SqlScriptDom/Parser/TSql/TSql160.g @@ -3687,6 +3687,9 @@ queryStoreOneOption returns [QueryStoreOption vResult = null] | {NextTokenMatches(CodeGenerationSupporter.CleanupPolicy)}? vResult = queryStoreTimeCleanupPolicy + | + {NextTokenMatches(CodeGenerationSupporter.WaitStatsCaptureMode)}? + vResult = queryStoreWaitStatsCaptureOption ; queryStoreDesiredStateOption returns [QueryStoreDesiredStateOption vResult = FragmentFactory.CreateFragment()] @@ -3869,6 +3872,30 @@ queryStoreTimeCleanupPolicy returns [QueryStoreTimeCleanupPolicyOption vResult = } ; +queryStoreWaitStatsCaptureOption returns [QueryStoreWaitStatsCaptureOption vResult = FragmentFactory.CreateFragment()] + : tWaitStatsCaptureMode:Identifier + { + Match(tWaitStatsCaptureMode, CodeGenerationSupporter.WaitStatsCaptureMode); + vResult.OptionKind = QueryStoreOptionKind.Wait_Stats_Capture_Mode; + UpdateTokenInfo(vResult, tWaitStatsCaptureMode); + } + ( + (EqualsSign tOff:Off + { + vResult.OptionState = OptionState.Off; + UpdateTokenInfo(vResult, tOff); + } + ) + | + (EqualsSign tOn:On + { + vResult.OptionState = OptionState.On; + UpdateTokenInfo(vResult, tOn); + } + ) + ) + ; + automaticTuningDbOption returns [AutomaticTuningDatabaseOption vResult = FragmentFactory.CreateFragment()] : tAutomaticTuning:Identifier { diff --git a/SqlScriptDom/Parser/TSql/TSql170.g b/SqlScriptDom/Parser/TSql/TSql170.g index b6ba097..46794be 100644 --- a/SqlScriptDom/Parser/TSql/TSql170.g +++ b/SqlScriptDom/Parser/TSql/TSql170.g @@ -3687,6 +3687,9 @@ queryStoreOneOption returns [QueryStoreOption vResult = null] | {NextTokenMatches(CodeGenerationSupporter.CleanupPolicy)}? vResult = queryStoreTimeCleanupPolicy + | + {NextTokenMatches(CodeGenerationSupporter.WaitStatsCaptureMode)}? + vResult = queryStoreWaitStatsCaptureOption ; queryStoreDesiredStateOption returns [QueryStoreDesiredStateOption vResult = FragmentFactory.CreateFragment()] @@ -3869,6 +3872,30 @@ queryStoreTimeCleanupPolicy returns [QueryStoreTimeCleanupPolicyOption vResult = } ; +queryStoreWaitStatsCaptureOption returns [QueryStoreWaitStatsCaptureOption vResult = FragmentFactory.CreateFragment()] + : tWaitStatsCaptureMode:Identifier + { + Match(tWaitStatsCaptureMode, CodeGenerationSupporter.WaitStatsCaptureMode); + vResult.OptionKind = QueryStoreOptionKind.Wait_Stats_Capture_Mode; + UpdateTokenInfo(vResult, tWaitStatsCaptureMode); + } + ( + (EqualsSign tOff:Off + { + vResult.OptionState = OptionState.Off; + UpdateTokenInfo(vResult, tOff); + } + ) + | + (EqualsSign tOn:On + { + vResult.OptionState = OptionState.On; + UpdateTokenInfo(vResult, tOn); + } + ) + ) + ; + automaticTuningDbOption returns [AutomaticTuningDatabaseOption vResult = FragmentFactory.CreateFragment()] : tAutomaticTuning:Identifier { From 5f7970057f7650cb0a25d6e381b4ccc54040dbe1 Mon Sep 17 00:00:00 2001 From: Drew Skwiers-Koballa Date: Thu, 16 Jan 2025 16:40:24 -0800 Subject: [PATCH 2/5] tests on 140+ --- Test/SqlDom/Baselines140/AlterDatabaseOptionsTests140.sql | 7 +++++++ Test/SqlDom/Only140SyntaxTests.cs | 2 +- Test/SqlDom/TestScripts/AlterDatabaseOptionsTests140.sql | 4 ++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Test/SqlDom/Baselines140/AlterDatabaseOptionsTests140.sql b/Test/SqlDom/Baselines140/AlterDatabaseOptionsTests140.sql index 85185be..841f2e8 100644 --- a/Test/SqlDom/Baselines140/AlterDatabaseOptionsTests140.sql +++ b/Test/SqlDom/Baselines140/AlterDatabaseOptionsTests140.sql @@ -51,3 +51,10 @@ ALTER DATABASE db ALTER DATABASE db SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = OFF); + + +ALTER DATABASE db + SET QUERY_STORE (DESIRED_STATE = READ_ONLY, QUERY_CAPTURE_MODE = ALL, SIZE_BASED_CLEANUP_MODE = OFF, INTERVAL_LENGTH_MINUTES = 100, MAX_STORAGE_SIZE_MB = 1000, MAX_PLANS_PER_QUERY = 200, CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 367), WAIT_STATS_CAPTURE_MODE = ON); + +ALTER DATABASE db + SET QUERY_STORE = ON(DESIRED_STATE = READ_ONLY, QUERY_CAPTURE_MODE = ALL, SIZE_BASED_CLEANUP_MODE = OFF, INTERVAL_LENGTH_MINUTES = 100, MAX_STORAGE_SIZE_MB = 1000, MAX_PLANS_PER_QUERY = 200, CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 367), WAIT_STATS_CAPTURE_MODE = OFF); \ No newline at end of file diff --git a/Test/SqlDom/Only140SyntaxTests.cs b/Test/SqlDom/Only140SyntaxTests.cs index 80a8e89..934222e 100644 --- a/Test/SqlDom/Only140SyntaxTests.cs +++ b/Test/SqlDom/Only140SyntaxTests.cs @@ -16,7 +16,7 @@ public partial class SqlDomTests private static readonly ParserTest[] Only140TestInfos = { new ParserTest140("AlterIndexStatementTests140.sql", 2, 20, 20, 20, 20, 20), - new ParserTest140("AlterDatabaseOptionsTests140.sql", 18, 18, 18, 18, 18, 18), + new ParserTest140("AlterDatabaseOptionsTests140.sql", 20, 20, 20, 20, 20, 20), new ParserTest140("CreateIndexStatementTests140.sql", 18, 14, 14, 14, 14, 14), new ParserTest140("CreateTableTests140.sql", 17, 15, 15, 15, 15, 11), new ParserTest140("OptimizerHintsTests140.sql", 6, 6, 6, 6, 6, 0), diff --git a/Test/SqlDom/TestScripts/AlterDatabaseOptionsTests140.sql b/Test/SqlDom/TestScripts/AlterDatabaseOptionsTests140.sql index 21b9151..053a71a 100644 --- a/Test/SqlDom/TestScripts/AlterDatabaseOptionsTests140.sql +++ b/Test/SqlDom/TestScripts/AlterDatabaseOptionsTests140.sql @@ -17,3 +17,7 @@ ALTER DATABASE db SET AUTOMATIC_TUNING (MAINTAIN_INDEX = DEFAULT); ALTER DATABASE db SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = ON, CREATE_INDEX = DEFAULT, MAINTAIN_INDEX = ON, DROP_INDEX = ON); alter database db set automatic_tuning = auto; ALtER DataBAsE db SET AUTomaTIC_TUNING (ForCE_LasT_GooD_PLAN = ofF); + +-- query_store options for 2017+ +alter database db set query_store (desired_state = read_only, query_capture_mode = all, size_based_cleanup_mode = off, interval_length_minutes = 100, max_storage_size_mb = 1000, max_plans_per_query = 200, cleanup_policy = (stale_query_threshold_days = 367), WAIT_STATS_CAPTURE_MODE = ON); +alter database db set query_store = on(desired_state = read_only, query_capture_mode = all, size_based_cleanup_mode = off, interval_length_minutes = 100, max_storage_size_mb = 1000, max_plans_per_query = 200, cleanup_policy = (stale_query_threshold_days = 367), WAIT_STATS_CAPTURE_MODE = OFF); From 89c6696b21922a95a5e14349a51163b00364fcf8 Mon Sep 17 00:00:00 2001 From: Drew Skwiers-Koballa Date: Thu, 16 Jan 2025 16:45:44 -0800 Subject: [PATCH 3/5] git is hard - missed a file --- ...neratorVisitor.QueryStoreDatabaseOption.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.QueryStoreDatabaseOption.cs b/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.QueryStoreDatabaseOption.cs index 5737310..362cd40 100644 --- a/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.QueryStoreDatabaseOption.cs +++ b/SqlScriptDom/ScriptDom/SqlServer/ScriptGenerator/SqlScriptGeneratorVisitor.QueryStoreDatabaseOption.cs @@ -74,5 +74,24 @@ public override void ExplicitVisit(QueryStoreTimeCleanupPolicyOption node) GenerateNameEqualsValue(CodeGenerationSupporter.StaleQueryThresholdDays, node.StaleQueryThreshold); GenerateSymbol(TSqlTokenType.RightParenthesis); } + + public override void ExplicitVisit(QueryStoreWaitStatsCaptureOption node) + { + System.Diagnostics.Debug.Assert(node.OptionKind == QueryStoreOptionKind.Wait_Stats_Capture_Mode); + GenerateIdentifier(CodeGenerationSupporter.WaitStatsCaptureMode); + GenerateSpace(); + + switch (node.OptionState) + { + case OptionState.Off: + GenerateSymbolAndSpace(TSqlTokenType.EqualsSign); + GenerateKeyword(TSqlTokenType.Off); + break; + case OptionState.On: + GenerateSymbolAndSpace(TSqlTokenType.EqualsSign); + GenerateKeyword(TSqlTokenType.On); + break; + } + } } } \ No newline at end of file From bf70151485fce734f8b46ccd50dc6bd0a93453a9 Mon Sep 17 00:00:00 2001 From: Drew Skwiers-Koballa Date: Fri, 17 Jan 2025 10:07:02 -0800 Subject: [PATCH 4/5] reverting character malformation --- SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs index 4d4a999..adcb40f 100644 --- a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs +++ b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs @@ -1264,7 +1264,7 @@ internal static class CodeGenerationSupporter internal const string Russian = "RUSSIAN"; internal const string Romanian = "ROMANIAN"; internal const string Brazilian = "BRAZILIAN"; - internal const string NorwegianBokmal = "NORWEGIAN (BOKM�L)"; + internal const string NorwegianBokmal = "NORWEGIAN (BOKMÃ…L)"; internal const string Dutch = "DUTCH"; internal const string Korean = "KOREAN"; internal const string Japanese = "JAPANESE"; From 567cf6cb4b7c718b239f2c6fc1dfaa3392d501f7 Mon Sep 17 00:00:00 2001 From: Drew Skwiers-Koballa Date: Thu, 23 Jan 2025 09:48:39 -0800 Subject: [PATCH 5/5] convert from utf8 to utf8bom --- SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs index adcb40f..dbca4a1 100644 --- a/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs +++ b/SqlScriptDom/Parser/TSql/CodeGenerationSupporter.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. //