From 6337da48453144be0bd615a3b0e7acfb3f910e71 Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Thu, 11 Jun 2026 03:44:21 +0100 Subject: [PATCH] Fix high-impact SQL collector defects from Fable code review (chunk 5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 09 Query Store: plan_type and plan_forcing_type were stored in each other's columns. The dynamic SELECT emits plan_forcing_type (2017+ block) before plan_type (2022+ block), but the INSERT...EXEC column list had plan_type first; INSERT...EXEC binds by ordinal, so every Query Store row had the two swapped. Reordered the INSERT list to match the SELECT. - 23/25/28 (blocked-process / deadlock / system-health wrappers): when an explicit @procedure_database was passed, the proc stored QUOTENAME(name) (e.g. "[master]") in the *_database variable and then QUOTENAME'd it again at the EXECUTE site, producing "[[master]]]" — so the explicit-database path was always broken. The default (NULL) path stores the raw name. Now the explicit path also stores the raw name (quote-escaped via REPLACE) so the single call-site QUOTENAME brackets it once, consistent with the default path. - 06 ensure_collection_table self-heal created collect.server_properties without lock_pages_in_memory / instant_file_initialization_enabled / memory_dump_count (present in 02 and inserted by 53's collector), so a self-healed table failed every collection with "invalid column name". Added the three columns. Validation: all five scripts CREATE OR ALTER cleanly on SQL2016 (2.12.0.0), exit 0. 2017-2025 still need your version testing (those instances were down). Remaining collector findings flagged for follow-up: 29/31 dedup window shorter than the sweep (duplicate rows); 05 gauge metrics run through counter-delta math; 23 marks unparsed blocked-process rows processed past the cap; 38 trace-flag removal detection; 10 procedure_stats tempdb/function-branch filters; 08 first-run self-defeat; 11 raw @procedure_database literal; 27 memory_pressure self-heal unreachable. Co-Authored-By: Claude Opus 4.8 (1M context) --- install/06_ensure_collection_table.sql | 3 +++ install/09_collect_query_store.sql | 6 +++++- install/23_process_blocked_process_xml.sql | 2 +- install/25_process_deadlock_xml.sql | 2 +- install/28_collect_system_health_wrapper.sql | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/install/06_ensure_collection_table.sql b/install/06_ensure_collection_table.sql index dc1414e6..e78e5bb9 100644 --- a/install/06_ensure_collection_table.sql +++ b/install/06_ensure_collection_table.sql @@ -1157,6 +1157,9 @@ BEGIN is_clustered bit NULL, enterprise_features nvarchar(max) NULL, service_objective sysname NULL, + lock_pages_in_memory bit NULL, + instant_file_initialization_enabled bit NULL, + memory_dump_count integer NULL, row_hash binary(32) NULL, CONSTRAINT PK_server_properties diff --git a/install/09_collect_query_store.sql b/install/09_collect_query_store.sql index db18720e..7e812a91 100644 --- a/install/09_collect_query_store.sql +++ b/install/09_collect_query_store.sql @@ -662,8 +662,12 @@ BEGIN avg_tempdb_space_used, min_tempdb_space_used, max_tempdb_space_used, - plan_type, + /* Order must match the dynamic SELECT, which is bound by ordinal by + INSERT...EXEC: the 2017+ block emits plan_forcing_type before the 2022+ + block emits plan_type. Swapping these silently stores each in the other's + column. */ plan_forcing_type, + plan_type, is_forced_plan, force_failure_count, last_force_failure_reason_desc, diff --git a/install/23_process_blocked_process_xml.sql b/install/23_process_blocked_process_xml.sql index df664c44..4fbd8084 100644 --- a/install/23_process_blocked_process_xml.sql +++ b/install/23_process_blocked_process_xml.sql @@ -75,7 +75,7 @@ BEGIN SET @sql = N' IF OBJECT_ID(N''' + QUOTENAME(@procedure_database) + N'.dbo.sp_HumanEventsBlockViewer'', N''P'') IS NOT NULL BEGIN - SELECT @blockviewer_database = N''' + QUOTENAME(@procedure_database) + N'''; + SELECT @blockviewer_database = N''' + REPLACE(@procedure_database, '''', '''''') + N'''; END;'; EXECUTE sys.sp_executesql diff --git a/install/25_process_deadlock_xml.sql b/install/25_process_deadlock_xml.sql index 02f48383..263b6b6c 100644 --- a/install/25_process_deadlock_xml.sql +++ b/install/25_process_deadlock_xml.sql @@ -73,7 +73,7 @@ BEGIN SET @sql = N' IF OBJECT_ID(N''' + QUOTENAME(@procedure_database) + N'.dbo.sp_BlitzLock'', N''P'') IS NOT NULL BEGIN - SELECT @blitzlock_database = N''' + QUOTENAME(@procedure_database) + N'''; + SELECT @blitzlock_database = N''' + REPLACE(@procedure_database, '''', '''''') + N'''; END;'; EXECUTE sys.sp_executesql diff --git a/install/28_collect_system_health_wrapper.sql b/install/28_collect_system_health_wrapper.sql index 70f74b8a..4f3bd3ed 100644 --- a/install/28_collect_system_health_wrapper.sql +++ b/install/28_collect_system_health_wrapper.sql @@ -69,7 +69,7 @@ BEGIN SET @sql = N' IF OBJECT_ID(N''' + QUOTENAME(@procedure_database) + N'.dbo.sp_HealthParser'', N''P'') IS NOT NULL BEGIN - SELECT @healthparser_database = N''' + QUOTENAME(@procedure_database) + N'''; + SELECT @healthparser_database = N''' + REPLACE(@procedure_database, '''', '''''') + N'''; END;'; EXECUTE sys.sp_executesql