The AX scripts written in 1.4 (own header style and a generator) now follow main's "SQL Scripts" structure: the review header, "-- Kilde:" blocks registered in SqlScriptSources and checked word for word against the code. - SqlScriptSources: the shared AX detection (DatabasesSql, LoginSql, BuildDetectionSql), companies, batch jobs, batch history (first read and from the watermark) and number sequences / RecId for Axapta 3.0, AX 4.0, AX 2009 and AX 2012; BlockingCollector split 2008 / 2005, as CONTEXT_INFO comes from sys.dm_exec_sessions from 2008 and from sysprocesses on 2005. - SQLI-AX-001..010 and _collectors/Ax*.sql in main's format; COM-AX-001..007 with the 1.4 queries, the AX detection and USE [AXDB]; BLK-001, BlockingCollector and DatabaseDiscovery updated (CONTEXT_INFO, sp_executesql). - Scripts_are_read_only stays strict (no INTO #temp anywhere) and now also checks the batch inside EXEC [db].sys.sp_executesql N'...'. - SQLINSIGHT_UPDATE_SQL_SCRIPTS=1 (from 1.4) rewrites out-of-date blocks from the code; the 1.4 generator test now checks that every AX script shows its sources for every AX version and says what is unverified. - README: SQLI-AX-001..010, the AX collector scripts, 108 rules. - AxDatabaseDetector: LoginSql and BuildDetectionSql as members, so the registry sees them. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
433 lines
39 KiB
C#
433 lines
39 KiB
C#
using System.Reflection;
|
||
using System.Text.RegularExpressions;
|
||
using SQLInsight.Collectors.Concurrency;
|
||
using SQLInsight.Collectors.Custom;
|
||
using SQLInsight.Collectors.Databases;
|
||
using SQLInsight.Collectors.Discovery;
|
||
using SQLInsight.Collectors.Instance;
|
||
using SQLInsight.Collectors.Performance;
|
||
using SQLInsight.Core.Instances;
|
||
|
||
namespace SQLInsight.Collectors.Tests.SqlScripts;
|
||
|
||
/// <summary>
|
||
/// Every SQL text the agent sends to a monitored instance, as the code builds it, keyed as the scripts in the folder
|
||
/// "SQL Scripts" name it on their <c>-- Kilde: <key></c> lines. Builders are called with the same arguments as the
|
||
/// scripts show (defaults from the agent's configuration, the database msdb). Values the agent computes at run time (a
|
||
/// trace file path, a point in time) are rendered as tokens ⟪name⟫: a script may put anything there, typically a variable
|
||
/// declared above it so the script runs in SSMS.
|
||
/// </summary>
|
||
internal static class SqlScriptSources
|
||
{
|
||
/// <summary>The database per-database queries are shown for: it exists on every instance, so the scripts run as they are.</summary>
|
||
public const string ExampleDatabase = "msdb";
|
||
|
||
/// <param name="Key">What the script's <c>-- Kilde:</c> line says.</param>
|
||
/// <param name="Collector">The collector (or InstanceProbe/connection) that sends it.</param>
|
||
/// <param name="Variant">The SQL Server versions or situation the text is sent for.</param>
|
||
/// <param name="File">The source file, relative to the repository root.</param>
|
||
/// <param name="Member">The constant or method holding the text.</param>
|
||
public sealed record Source(string Key, string Collector, string Variant, string File, string Member, Func<string> Render)
|
||
{
|
||
public string Sql => Normalize(Render());
|
||
}
|
||
|
||
private static readonly SqlServerVersion V2000 = SqlServerVersion.Parse("8.0.2039.0");
|
||
private static readonly SqlServerVersion V2005 = SqlServerVersion.Parse("9.0.5000.0");
|
||
private static readonly SqlServerVersion V2008 = SqlServerVersion.Parse("10.0.6000.29");
|
||
private static readonly SqlServerVersion V2008R2Sp1 = SqlServerVersion.Parse("10.50.2500.0");
|
||
private static readonly SqlServerVersion V2012 = SqlServerVersion.Parse("11.0.7001.0");
|
||
private static readonly SqlServerVersion V2014 = SqlServerVersion.Parse("12.0.6024.0");
|
||
private static readonly SqlServerVersion V2016Sp2 = SqlServerVersion.Parse("13.0.5026.0");
|
||
private static readonly SqlServerVersion V2022 = SqlServerVersion.Parse("16.0.4135.4");
|
||
|
||
private const string C = "src/SQLInsight.Collectors/";
|
||
|
||
public static IReadOnlyList<Source> All { get; } = Create();
|
||
|
||
public static IReadOnlyDictionary<string, Source> ByKey { get; } = All.ToDictionary(s => s.Key, StringComparer.Ordinal);
|
||
|
||
public static IEnumerable<Source> For(string collector) => All.Where(s => s.Collector == collector);
|
||
|
||
/// <summary>LF line endings: the sources and the scripts may be checked out with CRLF.</summary>
|
||
public static string Normalize(string sql) => sql.Replace("\r\n", "\n", StringComparison.Ordinal).Replace('\r', '\n');
|
||
|
||
/// <summary>A regex that finds <paramref name="sql"/> in a script, with any text where it has tokens.</summary>
|
||
public static Regex Pattern(string sql)
|
||
{
|
||
var parts = Regex.Split(Normalize(sql), "⟪[a-z]+⟫");
|
||
return new Regex(string.Join("(?:.+?)", parts.Select(Regex.Escape)), RegexOptions.Singleline | RegexOptions.CultureInvariant);
|
||
}
|
||
|
||
private static string Tokens(string sql, params string[] names)
|
||
{
|
||
foreach (var name in names)
|
||
{
|
||
sql = sql.Replace("N'§" + name + "§'", "⟪" + name + "⟫", StringComparison.Ordinal)
|
||
.Replace("'§" + name + "§'", "⟪" + name + "⟫", StringComparison.Ordinal)
|
||
.Replace("§" + name + "§", "⟪" + name + "⟫", StringComparison.Ordinal);
|
||
}
|
||
|
||
return sql;
|
||
}
|
||
|
||
private static string Internal(Type type, string field) =>
|
||
(string)(type.GetField(field, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)?.GetRawConstantValue()
|
||
?? throw new InvalidOperationException($"{type.Name}.{field} findes ikke."));
|
||
|
||
private static InstanceInfo Instance(SqlServerVersion version) => new()
|
||
{
|
||
ServerName = "eksempel",
|
||
Version = version,
|
||
Edition = "Enterprise Edition",
|
||
EngineEdition = EngineEdition.Enterprise,
|
||
IsHadrEnabled = version.Major >= 11,
|
||
};
|
||
|
||
private static string DatabaseSql2005(SqlServerVersion version)
|
||
{
|
||
var instance = Instance(version);
|
||
return DatabaseCollector.BuildSql2005(instance, InstanceCapabilities.From(instance));
|
||
}
|
||
|
||
private static List<Source> Create()
|
||
{
|
||
var probe = typeof(Connectivity.InstanceProbe);
|
||
var factory = typeof(Connectivity.SqlConnectionFactory);
|
||
var sources = new List<Source>
|
||
{
|
||
// Connection and registration.
|
||
new("SqlConnectionFactory.SessionSettings", "InstanceProbe", "Alle versioner: sættes på hver forbindelse, agenten åbner",
|
||
"src/SQLInsight.Connectivity/SqlConnectionFactory.cs", "SqlConnectionFactory.SessionSettings", () => Internal(factory, "SessionSettings")),
|
||
new("InstanceProbe.Query", "InstanceProbe", "Alle versioner (SQL Server 2000 og nyere)",
|
||
"src/SQLInsight.Connectivity/InstanceProbe.cs", "InstanceProbe.Query", () => Internal(probe, "Query")),
|
||
|
||
// Server.
|
||
new("ServerCollector.BuildSql(2012+)", "ServerCollector", "SQL Server 2012 og nyere",
|
||
C + "Instance/ServerCollector.cs", "ServerCollector.BuildSql(version)", () => ServerCollector.BuildSql(V2012)),
|
||
new("ServerCollector.BuildSql(2008 R2 SP1)", "ServerCollector", "SQL Server 2008 R2 SP1 og senere 2008 R2-builds",
|
||
C + "Instance/ServerCollector.cs", "ServerCollector.BuildSql(version)", () => ServerCollector.BuildSql(V2008R2Sp1)),
|
||
new("ServerCollector.BuildSql(2008)", "ServerCollector", "SQL Server 2008 og 2008 R2 før SP1",
|
||
C + "Instance/ServerCollector.cs", "ServerCollector.BuildSql(version)", () => ServerCollector.BuildSql(V2008)),
|
||
new("ServerCollector.BuildSql(2005)", "ServerCollector", "SQL Server 2005",
|
||
C + "Instance/ServerCollector.cs", "ServerCollector.BuildSql(version)", () => ServerCollector.BuildSql(V2005)),
|
||
StartTime("ServerCollector", V2000, "SQL Server 2000 (legacy ODBC-sti): starttidspunkt"),
|
||
new("ServerCollector.Sql2000", "ServerCollector", "SQL Server 2000 (legacy ODBC-sti): CPU og hukommelse",
|
||
C + "Instance/ServerCollector.cs", "ServerCollector.Sql2000", () => ServerCollector.Sql2000),
|
||
|
||
// Configuration and trace flags.
|
||
new("ConfigurationCollector.Sql2005", "ConfigurationCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/ConfigurationCollector.cs", "ConfigurationCollector.Sql2005", () => ConfigurationCollector.Sql2005),
|
||
new("ConfigurationCollector.Sql2000", "ConfigurationCollector", "SQL Server 2000 (legacy ODBC-sti)",
|
||
C + "Instance/ConfigurationCollector.cs", "ConfigurationCollector.Sql2000", () => ConfigurationCollector.Sql2000),
|
||
new("TraceFlagCollector.Sql", "TraceFlagCollector", "Alle versioner (SQL Server 2000 og nyere)",
|
||
C + "Instance/TraceFlagCollector.cs", "TraceFlagCollector.Sql", () => TraceFlagCollector.Sql),
|
||
|
||
// Instance configuration (the configuration page and its change log).
|
||
new("InstanceConfigurationCollector.PropertiesSql", "InstanceConfigurationCollector", "Alle versioner",
|
||
C + "Instance/InstanceConfigurationCollector.cs", "InstanceConfigurationCollector.PropertiesSql", () => InstanceConfigurationCollector.PropertiesSql),
|
||
new("InstanceConfigurationCollector.TempdbSql", "InstanceConfigurationCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/InstanceConfigurationCollector.cs", "InstanceConfigurationCollector.TempdbSql", () => InstanceConfigurationCollector.TempdbSql),
|
||
new("InstanceConfigurationCollector.ColumnsSql", "InstanceConfigurationCollector", "SQL Server 2008 R2 SP1 og nyere",
|
||
C + "Instance/InstanceConfigurationCollector.cs", "InstanceConfigurationCollector.ColumnsSql", () => InstanceConfigurationCollector.ColumnsSql),
|
||
new("InstanceConfigurationCollector.BuildServicesSql(med IFI)", "InstanceConfigurationCollector", "SQL Server 2008 R2 SP1 og nyere, builds med kolonnen instant_file_initialization_enabled (se ColumnsSql)",
|
||
C + "Instance/InstanceConfigurationCollector.cs", "InstanceConfigurationCollector.BuildServicesSql(true)", () => InstanceConfigurationCollector.BuildServicesSql(true)),
|
||
new("InstanceConfigurationCollector.BuildServicesSql(uden IFI)", "InstanceConfigurationCollector", "SQL Server 2008 R2 SP1 og nyere, builds uden kolonnen instant_file_initialization_enabled",
|
||
C + "Instance/InstanceConfigurationCollector.cs", "InstanceConfigurationCollector.BuildServicesSql(false)", () => InstanceConfigurationCollector.BuildServicesSql(false)),
|
||
new("InstanceConfigurationCollector.MemoryModelSql", "InstanceConfigurationCollector", "Builds med kolonnen sql_memory_model_desc (se ColumnsSql)",
|
||
C + "Instance/InstanceConfigurationCollector.cs", "InstanceConfigurationCollector.MemoryModelSql", () => InstanceConfigurationCollector.MemoryModelSql),
|
||
|
||
// Privileges.
|
||
new("PrivilegeCollector.MembersSql", "PrivilegeCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/PrivilegeCollector.cs", "PrivilegeCollector.MembersSql", () => PrivilegeCollector.MembersSql),
|
||
new("PrivilegeCollector.SqlLoginsSql", "PrivilegeCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/PrivilegeCollector.cs", "PrivilegeCollector.SqlLoginsSql", () => PrivilegeCollector.SqlLoginsSql),
|
||
new("PrivilegeCollector.DefaultTraceEnabledSql", "PrivilegeCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/PrivilegeCollector.cs", "PrivilegeCollector.DefaultTraceEnabledSql", () => PrivilegeCollector.DefaultTraceEnabledSql),
|
||
new("PrivilegeCollector.DefaultTracePathSql", "PrivilegeCollector", "SQL Server 2005 og nyere, kun når der er fundet ændringer (kræver ALTER TRACE)",
|
||
C + "Instance/PrivilegeCollector.cs", "PrivilegeCollector.DefaultTracePathSql", () => PrivilegeCollector.DefaultTracePathSql),
|
||
new("PrivilegeCollector.BuildTraceSql", "PrivilegeCollector", "SQL Server 2005 og nyere, kun når der er fundet ændringer (kræver ALTER TRACE)",
|
||
C + "Instance/PrivilegeCollector.cs", "PrivilegeCollector.BuildTraceSql(traceFileBase, sinceLocal)",
|
||
() => Tokens(PrivilegeCollector.BuildTraceSql("§fil§", "§siden§"), "fil", "siden")),
|
||
|
||
// Databases.
|
||
new("DatabaseCollector.BuildSql2005(2016 SP2+)", "DatabaseCollector", "SQL Server 2016 SP2 og nyere (med LastGoodCheckDbTime og availability groups)",
|
||
C + "Databases/DatabaseCollector.cs", "DatabaseCollector.BuildSql2005(instance, capabilities)", () => DatabaseSql2005(V2016Sp2)),
|
||
new("DatabaseCollector.BuildSql2005(2012)", "DatabaseCollector", "SQL Server 2012 – 2016 SP1",
|
||
C + "Databases/DatabaseCollector.cs", "DatabaseCollector.BuildSql2005(instance, capabilities)", () => DatabaseSql2005(V2012)),
|
||
new("DatabaseCollector.BuildSql2005(2005)", "DatabaseCollector", "SQL Server 2005 – 2008 R2",
|
||
C + "Databases/DatabaseCollector.cs", "DatabaseCollector.BuildSql2005(instance, capabilities)", () => DatabaseSql2005(V2008R2Sp1)),
|
||
new("DatabaseCollector.BuildSql2000", "DatabaseCollector", "SQL Server 2000 (legacy ODBC-sti)",
|
||
C + "Databases/DatabaseCollector.cs", "DatabaseCollector.BuildSql2000()", DatabaseCollector.BuildSql2000),
|
||
new("DatabaseCollector.Files2005", "DatabaseCollector", "SQL Server 2005 og nyere",
|
||
C + "Databases/DatabaseCollector.cs", "DatabaseCollector.Files2005", () => DatabaseCollector.Files2005),
|
||
new("DatabaseCollector.Files2000", "DatabaseCollector", "SQL Server 2000 (legacy ODBC-sti)",
|
||
C + "Databases/DatabaseCollector.cs", "DatabaseCollector.Files2000", () => DatabaseCollector.Files2000),
|
||
new("Db.UtcOffsetSql", "DatabaseCollector", "Alle versioner: serverens afstand til UTC (msdb-tider er lokal tid)",
|
||
C + "Db.cs", "Db.UtcOffsetSql", () => Db.UtcOffsetSql),
|
||
new("DatabaseCollector.VlfSql", "DatabaseCollector", "SQL Server 2016 SP2 og nyere (sys.dm_db_log_info)",
|
||
C + "Databases/DatabaseCollector.cs", "DatabaseCollector.VlfSql", () => DatabaseCollector.VlfSql),
|
||
new("DatabaseCollector.BuildQueryStoreSql", "DatabaseCollector", "SQL Server 2016 og nyere: én gang pr. online brugerdatabase (vist for " + ExampleDatabase + ")",
|
||
C + "Databases/DatabaseCollector.cs", "DatabaseCollector.BuildQueryStoreSql(database)", () => DatabaseCollector.BuildQueryStoreSql(ExampleDatabase)),
|
||
new("SuspectPageCollector.Sql", "SuspectPageCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/SuspectPageCollector.cs", "SuspectPageCollector.Sql", () => SuspectPageCollector.Sql),
|
||
|
||
// Plan cache, waits, I/O.
|
||
new("PlanCacheCollector.Sql", "PlanCacheCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/PlanCacheCollector.cs", "PlanCacheCollector.Sql", () => PlanCacheCollector.Sql),
|
||
StartTime("WaitStatsCollector", V2008, "SQL Server 2008 og nyere: starttidspunkt (nulstilling af kumulative tal)"),
|
||
StartTime("WaitStatsCollector", V2005, "SQL Server 2005: starttidspunkt"),
|
||
StartTime("WaitStatsCollector", V2000, "SQL Server 2000 (legacy ODBC-sti): starttidspunkt"),
|
||
new("WaitStatsCollector.Sql2005", "WaitStatsCollector", "SQL Server 2005 og nyere",
|
||
C + "Performance/WaitStatsCollector.cs", "WaitStatsCollector.Sql2005", () => WaitStatsCollector.Sql2005),
|
||
new("WaitStatsCollector.Sql2000", "WaitStatsCollector", "SQL Server 2000 (legacy ODBC-sti)",
|
||
C + "Performance/WaitStatsCollector.cs", "WaitStatsCollector.Sql2000", () => WaitStatsCollector.Sql2000),
|
||
StartTime("FileIoCollector", V2008, "SQL Server 2008 og nyere: starttidspunkt"),
|
||
StartTime("FileIoCollector", V2005, "SQL Server 2005: starttidspunkt"),
|
||
new("FileIoCollector.SqlWithVolumes", "FileIoCollector", "SQL Server 2008 R2 SP1 og nyere (med drev/mount point)",
|
||
C + "Performance/FileIoCollector.cs", "FileIoCollector.SqlWithVolumes", () => FileIoCollector.SqlWithVolumes),
|
||
new("FileIoCollector.Sql", "FileIoCollector", "SQL Server 2005 – 2008 R2 RTM",
|
||
C + "Performance/FileIoCollector.cs", "FileIoCollector.Sql", () => FileIoCollector.Sql),
|
||
|
||
// Top SQL and sampling.
|
||
StartTime("QueryStatsCollector", V2008, "SQL Server 2008 og nyere: starttidspunkt"),
|
||
StartTime("QueryStatsCollector", V2005, "SQL Server 2005: starttidspunkt"),
|
||
new("QueryStatsCollector.SqlFor(2008+)", "QueryStatsCollector", "SQL Server 2008 og nyere (første kørsel: de seneste 15 minutter)",
|
||
C + "Performance/QueryStatsCollector.cs", "QueryStatsCollector.Sql2008 via SqlFor(version, since: null)", () => QueryStatsCollector.SqlFor(V2008, null)),
|
||
new("QueryStatsCollector.SqlFor(2005)", "QueryStatsCollector", "SQL Server 2005 (første kørsel: de seneste 15 minutter)",
|
||
C + "Performance/QueryStatsCollector.cs", "QueryStatsCollector.Sql2005 via SqlFor(version, since: null)", () => QueryStatsCollector.SqlFor(V2005, null)),
|
||
new("QueryStatsCollector.ServerTimeSql", "QueryStatsCollector", "Alle versioner, kun når ingen sætning har kørt siden sidst",
|
||
C + "Performance/QueryStatsCollector.cs", "QueryStatsCollector.ServerTimeSql", () => QueryStatsCollector.ServerTimeSql),
|
||
new("WaitSamplingCollector.Sql2008", "WaitSamplingCollector", "SQL Server 2008 og nyere",
|
||
C + "Performance/WaitSamplingCollector.cs", "WaitSamplingCollector.Sql2008", () => WaitSamplingCollector.Sql2008),
|
||
new("WaitSamplingCollector.Sql2005", "WaitSamplingCollector", "SQL Server 2005",
|
||
C + "Performance/WaitSamplingCollector.cs", "WaitSamplingCollector.Sql2005", () => WaitSamplingCollector.Sql2005),
|
||
new("LongOperationCollector.Sql", "LongOperationCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/LongOperationCollector.cs", "LongOperationCollector.Sql", () => LongOperationCollector.Sql),
|
||
|
||
// Error log.
|
||
new("ErrorLogCollector.CanReadErrorLogSql", "ErrorLogCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/ErrorLogCollector.cs", "ErrorLogCollector.CanReadErrorLogSql", () => ErrorLogCollector.CanReadErrorLogSql),
|
||
new("ErrorLogCollector.BuildErrorLogSql", "ErrorLogCollector", "SQL Server 2005 og nyere, kilde 1: fejlloggen (når agenten er securityadmin)",
|
||
C + "Instance/ErrorLogCollector.cs", "ErrorLogCollector.BuildErrorLogSql(fromLocal, toLocal)",
|
||
() => Tokens(ErrorLogCollector.BuildErrorLogSql("§fra§", "§til§"), "fra", "til")),
|
||
new("ErrorLogCollector.DefaultTracePathSql", "ErrorLogCollector", "SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)",
|
||
C + "Instance/PrivilegeCollector.cs", "PrivilegeCollector.DefaultTracePathSql", () => PrivilegeCollector.DefaultTracePathSql),
|
||
new("ErrorLogCollector.BuildDefaultTraceSql", "ErrorLogCollector", "SQL Server 2005 og nyere, kilde 2: default trace (når agenten har ALTER TRACE)",
|
||
C + "Instance/ErrorLogCollector.cs", "ErrorLogCollector.BuildDefaultTraceSql(files, sinceLocal)",
|
||
() => Tokens(ErrorLogCollector.BuildDefaultTraceSql("§filer§", "§siden§"), "filer", "siden")),
|
||
new("ErrorLogCollector.RingBufferSql", "ErrorLogCollector", "SQL Server 2005 og nyere, kilde 3: exception ring buffer (kun VIEW SERVER STATE)",
|
||
C + "Instance/ErrorLogCollector.cs", "ErrorLogCollector.RingBufferSql", () => ErrorLogCollector.RingBufferSql),
|
||
new("ErrorLogCollector.ConnectivitySql", "ErrorLogCollector", "SQL Server 2008 og nyere, kilde 3: mislykkede logins fra connectivity ring buffer",
|
||
C + "Instance/ErrorLogCollector.cs", "ErrorLogCollector.ConnectivitySql", () => ErrorLogCollector.ConnectivitySql),
|
||
|
||
// tempdb.
|
||
new("TempdbCollector.SpaceSql", "TempdbCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/TempdbCollector.cs", "TempdbCollector.SpaceSql", () => TempdbCollector.SpaceSql),
|
||
new("TempdbCollector.SessionsSql", "TempdbCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/TempdbCollector.cs", "TempdbCollector.SessionsSql", () => TempdbCollector.SessionsSql),
|
||
new("TempdbCollector.OldestSnapshotSql", "TempdbCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/TempdbCollector.cs", "TempdbCollector.OldestSnapshotSql", () => TempdbCollector.OldestSnapshotSql),
|
||
new("TempdbCollector.GeneratorsSql", "TempdbCollector", "SQL Server 2005 og nyere, kun når version store er over halvdelen af grænsen, højst én gang i timen",
|
||
C + "Instance/TempdbCollector.cs", "TempdbCollector.GeneratorsSql", () => TempdbCollector.GeneratorsSql),
|
||
|
||
// Replication.
|
||
new("ReplicationCollector.DistributionDatabaseSql", "ReplicationCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/ReplicationCollector.cs", "ReplicationCollector.DistributionDatabaseSql", () => ReplicationCollector.DistributionDatabaseSql),
|
||
new("ReplicationCollector.CurrentDatabaseSql", "ReplicationCollector", "Kun på en distributør: husk databasen, der skal skiftes tilbage til",
|
||
C + "Db.cs", "Db.CurrentDatabaseSql", () => Db.CurrentDatabaseSql),
|
||
new("ReplicationCollector.AgentsSql", "ReplicationCollector", "Kun på en distributør, i distributionsdatabasen",
|
||
C + "Instance/ReplicationCollector.cs", "ReplicationCollector.AgentsSql", () => ReplicationCollector.AgentsSql),
|
||
new("ReplicationCollector.ErrorsSql", "ReplicationCollector", "Kun på en distributør, i distributionsdatabasen",
|
||
C + "Instance/ReplicationCollector.cs", "ReplicationCollector.ErrorsSql", () => ReplicationCollector.ErrorsSql),
|
||
|
||
// Counters and CPU.
|
||
StartTime("PerformanceCounterCollector", V2008, "SQL Server 2008 og nyere: starttidspunkt"),
|
||
StartTime("PerformanceCounterCollector", V2005, "SQL Server 2005: starttidspunkt"),
|
||
StartTime("PerformanceCounterCollector", V2000, "SQL Server 2000 (legacy ODBC-sti): starttidspunkt"),
|
||
new("PerformanceCounterCollector.BuildSql(dmv)", "PerformanceCounterCollector", "SQL Server 2005 og nyere",
|
||
C + "Performance/PerformanceCounterCollector.cs", "PerformanceCounterCollector.BuildSql(dmv: true)", () => PerformanceCounterCollector.BuildSql(true)),
|
||
new("PerformanceCounterCollector.BuildSql(sysperfinfo)", "PerformanceCounterCollector", "SQL Server 2000 (legacy ODBC-sti)",
|
||
C + "Performance/PerformanceCounterCollector.cs", "PerformanceCounterCollector.BuildSql(dmv: false)", () => PerformanceCounterCollector.BuildSql(false)),
|
||
new("CpuCollector.Sql", "CpuCollector", "SQL Server 2005 og nyere",
|
||
C + "Performance/CpuCollector.cs", "CpuCollector.Sql", () => CpuCollector.Sql),
|
||
new("CpuCollector.HostPlatformSql", "CpuCollector", "SQL Server 2017 og nyere (Windows eller Linux)",
|
||
C + "Performance/CpuCollector.cs", "CpuCollector.HostPlatformSql", () => CpuCollector.HostPlatformSql),
|
||
|
||
// Concurrency.
|
||
new("BlockingCollector.BuildSql2005(2012+)", "BlockingCollector", "SQL Server 2012 og nyere",
|
||
C + "Concurrency/BlockingCollector.cs", "BlockingCollector.BuildSql2005(version)", () => BlockingCollector.BuildSql2005(V2012)),
|
||
new("BlockingCollector.BuildSql2005(2008)", "BlockingCollector", "SQL Server 2008 – 2008 R2",
|
||
C + "Concurrency/BlockingCollector.cs", "BlockingCollector.BuildSql2005(version)", () => BlockingCollector.BuildSql2005(V2008R2Sp1)),
|
||
new("BlockingCollector.BuildSql2005(2005)", "BlockingCollector", "SQL Server 2005 (CONTEXT_INFO fra sys.sysprocesses)",
|
||
C + "Concurrency/BlockingCollector.cs", "BlockingCollector.BuildSql2005(version)", () => BlockingCollector.BuildSql2005(V2005)),
|
||
new("BlockingCollector.Sql2000", "BlockingCollector", "SQL Server 2000 (legacy ODBC-sti)",
|
||
C + "Concurrency/BlockingCollector.cs", "BlockingCollector.Sql2000", () => BlockingCollector.Sql2000),
|
||
new("ActivityCollector.BuildTransactionsSql", "ActivityCollector", "SQL Server 2005 og nyere (vist med standardgrænsen 1024 MB log)",
|
||
C + "Concurrency/ActivityCollector.cs", "ActivityCollector.BuildTransactionsSql(1024) = TransactionsSql udfyldt",
|
||
() => ActivityCollector.BuildTransactionsSql(1024)),
|
||
new("ActivityCollector.BuildLongRequestsSql", "ActivityCollector", "SQL Server 2005 og nyere (vist med standardgrænsen 15 minutter)",
|
||
C + "Concurrency/ActivityCollector.cs", "ActivityCollector.BuildLongRequestsSql(15) = LongRequestsSql udfyldt",
|
||
() => ActivityCollector.BuildLongRequestsSql(15)),
|
||
new("DeadlockCollector.BuildFileSql", "DeadlockCollector", "SQL Server 2012 og nyere (system_health-filer; første læsning)",
|
||
C + "Concurrency/DeadlockCollector.cs", "DeadlockCollector.BuildFileSql(lastFile: null, lastOffset: null)", () => DeadlockCollector.BuildFileSql(null, null)),
|
||
new("DeadlockCollector.RingBufferSql", "DeadlockCollector", "SQL Server 2008 – 2008 R2, og når event-filerne ikke kan læses",
|
||
C + "Concurrency/DeadlockCollector.cs", "DeadlockCollector.RingBufferSql", () => DeadlockCollector.RingBufferSql),
|
||
|
||
// Query Store and plans.
|
||
new("QueryStoreCollector.DatabasesSql", "QueryStoreCollector", "SQL Server 2016 og nyere",
|
||
C + "Performance/QueryStoreCollector.cs", "QueryStoreCollector.DatabasesSql", () => QueryStoreCollector.DatabasesSql),
|
||
new("QueryStoreCollector.BuildStatsSql", "QueryStoreCollector", "SQL Server 2016 og nyere: én gang pr. database med Query Store (vist for " + ExampleDatabase + ")",
|
||
C + "Performance/QueryStoreCollector.cs", "QueryStoreCollector.BuildStatsSql(database)", () => QueryStoreCollector.BuildStatsSql(ExampleDatabase)),
|
||
new("QueryStoreCollector.BuildFailedForcedSql", "QueryStoreCollector", "SQL Server 2016 og nyere: én gang pr. database med Query Store (vist for " + ExampleDatabase + ")",
|
||
C + "Performance/QueryStoreCollector.cs", "QueryStoreCollector.BuildFailedForcedSql(database)", () => QueryStoreCollector.BuildFailedForcedSql(ExampleDatabase)),
|
||
new("PlanAnalysisCollector.BuildSql(2016 SP2+)", "PlanAnalysisCollector", "SQL Server 2016 SP2 / 2017 CU3 og nyere (med spill- og memory grant-kolonner)",
|
||
C + "Performance/PlanAnalysisCollector.cs", "PlanAnalysisCollector.BuildSql(memoryColumns: true, queryHash: true)", () => PlanAnalysisCollector.BuildSql(true, true)),
|
||
new("PlanAnalysisCollector.BuildSql(2008)", "PlanAnalysisCollector", "SQL Server 2008 – 2016 SP1 og 2017 før CU3",
|
||
C + "Performance/PlanAnalysisCollector.cs", "PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: true)", () => PlanAnalysisCollector.BuildSql(false, true)),
|
||
new("PlanAnalysisCollector.BuildSql(2005)", "PlanAnalysisCollector", "SQL Server 2005 SP2 og nyere 2005-builds",
|
||
C + "Performance/PlanAnalysisCollector.cs", "PlanAnalysisCollector.BuildSql(memoryColumns: false, queryHash: false)", () => PlanAnalysisCollector.BuildSql(false, false)),
|
||
|
||
// Indexes and statistics.
|
||
StartTime("IndexCollector", V2008, "SQL Server 2008 og nyere: starttidspunkt"),
|
||
StartTime("IndexCollector", V2005, "SQL Server 2005: starttidspunkt"),
|
||
new("IndexCollector.DatabasesSql", "IndexCollector", "SQL Server 2005 og nyere",
|
||
C + "Databases/IndexCollector.cs", "IndexCollector.DatabasesSql", () => IndexCollector.DatabasesSql),
|
||
new("IndexCollector.MissingSql", "IndexCollector", "SQL Server 2005 og nyere",
|
||
C + "Databases/IndexCollector.cs", "IndexCollector.MissingSql", () => IndexCollector.MissingSql),
|
||
new("IndexCollector.BuildIndexSql(2008+)", "IndexCollector", "SQL Server 2008 og nyere: én gang pr. database (vist for " + ExampleDatabase + ")",
|
||
C + "Databases/IndexCollector.cs", "IndexCollector.BuildIndexSql(database, filteredIndexes: true)", () => IndexCollector.BuildIndexSql(ExampleDatabase, true)),
|
||
new("IndexCollector.BuildIndexSql(2005)", "IndexCollector", "SQL Server 2005: én gang pr. database (vist for " + ExampleDatabase + ")",
|
||
C + "Databases/IndexCollector.cs", "IndexCollector.BuildIndexSql(database, filteredIndexes: false)", () => IndexCollector.BuildIndexSql(ExampleDatabase, false)),
|
||
new("IndexCollector.BuildStatisticsSql", "IndexCollector", "SQL Server 2005 og nyere: én gang pr. database (vist for " + ExampleDatabase + ")",
|
||
C + "Databases/IndexCollector.cs", "IndexCollector.BuildStatisticsSql(database)", () => IndexCollector.BuildStatisticsSql(ExampleDatabase)),
|
||
|
||
// Availability and jobs.
|
||
new("AvailabilityGroupCollector.ReplicasSql", "AvailabilityGroupCollector", "SQL Server 2012 og nyere med Always On slået til",
|
||
C + "Instance/AvailabilityGroupCollector.cs", "AvailabilityGroupCollector.ReplicasSql", () => AvailabilityGroupCollector.ReplicasSql),
|
||
new("AvailabilityGroupCollector.DatabasesSql", "AvailabilityGroupCollector", "SQL Server 2012 og nyere med Always On slået til",
|
||
C + "Instance/AvailabilityGroupCollector.cs", "AvailabilityGroupCollector.DatabasesSql", () => AvailabilityGroupCollector.DatabasesSql),
|
||
new("AvailabilityGroupCollector.ClusterMembersSql", "AvailabilityGroupCollector", "SQL Server 2012 og nyere med Always On slået til (tom uden Windows-cluster)",
|
||
C + "Instance/AvailabilityGroupCollector.cs", "AvailabilityGroupCollector.ClusterMembersSql", () => AvailabilityGroupCollector.ClusterMembersSql),
|
||
new("AgentJobCollector.RunningSql", "AgentJobCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/AgentJobCollector.cs", "AgentJobCollector.RunningSql", () => AgentJobCollector.RunningSql),
|
||
new("AgentJobCollector.JobsSql", "AgentJobCollector", "SQL Server 2005 og nyere",
|
||
C + "Instance/AgentJobCollector.cs", "AgentJobCollector.JobsSql", () => AgentJobCollector.JobsSql),
|
||
|
||
// Community and local rules.
|
||
new("CustomQueryCollector.CurrentDatabaseSql", "CustomQueryCollector", "Husk databasen, der skal skiftes tilbage til",
|
||
C + "Db.cs", "Db.CurrentDatabaseSql", () => Db.CurrentDatabaseSql),
|
||
new("CustomQueryCollector.DatabasesSql", "CustomQueryCollector", "Databaserne, database-regler køres i",
|
||
C + "Custom/CustomQueryCollector.cs", "CustomQueryCollector.DatabasesSql", () => CustomQueryCollector.DatabasesSql),
|
||
new("CustomQueryCollector.BuildRuleSql", "CustomQueryCollector", "Én regel: skift database (master for server-regler, ellers hver brugerdatabase) og kør reglens forespørgsel",
|
||
C + "Custom/CustomQueryCollector.cs", "CustomQueryCollector.BuildRuleSql(database, query)",
|
||
() => Tokens(CustomQueryCollector.BuildRuleSql("§database§", "§forespoergsel§"), "database", "forespoergsel")),
|
||
|
||
// Servere og databaser (1.3): database discovery and the permission check, run by the agent when asked in
|
||
// SQLInsight Web (and the discovery hourly). The collectors above then skip databases not chosen (in C#; their SQL is unchanged).
|
||
new("DatabaseDiscovery.Databases2005Sql", "DatabaseDiscovery", "SQL Server 2005 og nyere",
|
||
C + "Discovery/DatabaseDiscovery.cs", "DatabaseDiscovery.Databases2005Sql", () => DatabaseDiscovery.Databases2005Sql),
|
||
new("DatabaseDiscovery.Databases2000Sql", "DatabaseDiscovery", "SQL Server 2000 (legacy ODBC-sti)",
|
||
C + "Discovery/DatabaseDiscovery.cs", "DatabaseDiscovery.Databases2000Sql", () => DatabaseDiscovery.Databases2000Sql),
|
||
new("DatabaseDiscovery.DynamicsAxSql(2005)", "DatabaseDiscovery", "SQL Server 2005 og nyere: én gang pr. online brugerdatabase, agenten kan åbne (vist for " + ExampleDatabase + ")",
|
||
C + "Discovery/DatabaseDiscovery.cs", "DatabaseDiscovery.DynamicsAxSql(database, version)", () => DatabaseDiscovery.DynamicsAxSql(ExampleDatabase, V2005)),
|
||
new("DatabaseDiscovery.DynamicsAxSql(2000)", "DatabaseDiscovery", "SQL Server 2000 (legacy ODBC-sti): én gang pr. online brugerdatabase (vist for " + ExampleDatabase + ")",
|
||
C + "Discovery/DatabaseDiscovery.cs", "DatabaseDiscovery.DynamicsAxSql(database, version)", () => DatabaseDiscovery.DynamicsAxSql(ExampleDatabase, V2000)),
|
||
new("PermissionCheck.WhoSql", "PermissionCheck", "Alle versioner (SQL Server 2000 og nyere)",
|
||
C + "Discovery/PermissionCheck.cs", "PermissionCheck.WhoSql", () => PermissionCheck.WhoSql),
|
||
new("PermissionCheck.BuildSql(2022+)", "PermissionCheck", "SQL Server 2022 og nyere",
|
||
C + "Discovery/PermissionCheck.cs", "PermissionCheck.BuildSql(checks)", () => PermissionCheck.BuildSql(PermissionCheck.ChecksFor(Instance(V2022)))),
|
||
new("PermissionCheck.BuildSql(2014)", "PermissionCheck", "SQL Server 2014 – 2019 og Azure SQL Managed Instance",
|
||
C + "Discovery/PermissionCheck.cs", "PermissionCheck.BuildSql(checks)", () => PermissionCheck.BuildSql(PermissionCheck.ChecksFor(Instance(V2014)))),
|
||
new("PermissionCheck.BuildSql(2005)", "PermissionCheck", "SQL Server 2005 – 2012",
|
||
C + "Discovery/PermissionCheck.cs", "PermissionCheck.BuildSql(checks)", () => PermissionCheck.BuildSql(PermissionCheck.ChecksFor(Instance(V2005)))),
|
||
new("PermissionCheck.DatabasesWithoutAccessSql", "PermissionCheck", "SQL Server 2005 – 2012 (før CONNECT ANY DATABASE)",
|
||
C + "Discovery/PermissionCheck.cs", "PermissionCheck.DatabasesWithoutAccessSql", () => PermissionCheck.DatabasesWithoutAccessSql),
|
||
};
|
||
|
||
sources.AddRange(DynamicsAx());
|
||
return sources;
|
||
}
|
||
|
||
/// <summary>The AX database the Dynamics AX scripts are shown for: there is no AX database on every instance, so the reader changes it.</summary>
|
||
public const string AxExampleDatabase = "AXDB";
|
||
|
||
/// <summary>A RecId the history watermark is rendered with, replaced by the token ⟪fra⟫ (the agent uses the highest RecId it has read).</summary>
|
||
private const long AxWatermark = 1_000_000_000;
|
||
|
||
private const string Ax = "src/SQLInsight.Core/DynamicsAx/";
|
||
|
||
private static string AxDirectory => Path.Combine(AppContext.BaseDirectory, "DynamicsAx");
|
||
|
||
/// <summary>
|
||
/// The AX versions SQLInsight has a schema for (docs/dynamics-ax/*.tsv): Axapta 3.0 from a real customer database,
|
||
/// AX 4.0 as 3.0 with bigint RecId in dbo, AX 2009 and 2012 R2/R3 from Microsoft's documentation.
|
||
/// </summary>
|
||
private static IReadOnlyList<(string Key, string Title, Core.DynamicsAx.AxDatabase Database)> AxVersions()
|
||
{
|
||
static Core.DynamicsAx.AxDatabase Load(string file) =>
|
||
Core.DynamicsAx.AxDetection.Recognise(AxExampleDatabase, Core.DynamicsAx.AxSchemaFile.Find(AxDirectory, file)!.DetectionRows(), [AxExampleDatabase, AxExampleDatabase + "_model"])!;
|
||
var ax40 = Core.DynamicsAx.AxDetection.Recognise(AxExampleDatabase, Core.DynamicsAx.AxSchemaFile.Find(AxDirectory, "schema-ax30")!.DetectionRows()
|
||
.Select(r => r with { Schema = "dbo", Precision = r.Column == "RECID" ? 19 : r.Precision, Type = r.Column == "RECID" ? "bigint" : r.Type }).ToList(), [AxExampleDatabase])!;
|
||
return
|
||
[
|
||
("3.0", "Axapta 3.0 (skema bmssa, verificeret mod kundedata)", Load("schema-ax30")),
|
||
("4.0", "AX 4.0 (skema dbo) - ikke verificeret mod kundedata", ax40),
|
||
("2009", "AX 2009 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata", Load("schema-ax2009")),
|
||
("2012", "AX 2012 RTM/R2/R3 - baseret på Microsofts dokumenterede skema, ikke verificeret mod kundedata", Load("schema-ax2012")),
|
||
];
|
||
}
|
||
|
||
private static string AxRead(Core.DynamicsAx.AxDatabase database, Core.DynamicsAx.AxQuery? query) =>
|
||
Core.DynamicsAx.AxSql.InDatabase(database.Database, query?.Sql ?? throw new InvalidOperationException(query?.NotMeasurable ?? "Ingen forespørgsel."), database.Isolation);
|
||
|
||
private static IEnumerable<Source> DynamicsAx()
|
||
{
|
||
// The shared detection: which monitored databases are AX (collector dynamics-ax, and before every AX check).
|
||
yield return new("AxDatabaseDetector.DatabasesSql", "AxDatabaseDetector", "Alle versioner fra SQL Server 2005: online brugerdatabaser og deres snapshot-indstillinger",
|
||
C + "DynamicsAx/AxDatabaseDetector.cs", "AxDatabaseDetector.DatabasesSql", () => Collectors.DynamicsAx.AxDatabaseDetector.DatabasesSql);
|
||
yield return new("AxDatabaseDetector.LoginSql", "AxDatabaseDetector", "Agentens login, til GRANT-teksten, når AX-læseadgangen mangler",
|
||
C + "DynamicsAx/AxDatabaseDetector.cs", "AxDatabaseDetector.LoginSql", () => Collectors.DynamicsAx.AxDatabaseDetector.LoginSql);
|
||
yield return new("AxDatabaseDetector.BuildDetectionSql", "AxDatabaseDetector",
|
||
"SQL Server 2005 og nyere: AX-genkendelsen i hver overvåget database (kun metadata; vist for " + AxExampleDatabase + ")",
|
||
C + "DynamicsAx/AxDatabaseDetector.cs", "AxDatabaseDetector.BuildDetectionSql(database) = AxSql.InDatabase(database, AxDetection.MetadataSql)",
|
||
() => Collectors.DynamicsAx.AxDatabaseDetector.BuildDetectionSql(AxExampleDatabase));
|
||
foreach (var (key, title, database) in AxVersions())
|
||
{
|
||
yield return new($"AxSchemaAdapter.Companies({key})", "AxDatabaseDetector", title + ": firmaerne (DATAAREA), kun med AX-læseadgang",
|
||
Ax + "AxSchemaAdapter.cs", "AxSchemaAdapter.Companies(database) via AxSql.InDatabase", () => AxRead(database, Core.DynamicsAx.AxSchemaAdapter.Companies(database)));
|
||
}
|
||
|
||
// Batch jobs (collector dynamics-ax-batch).
|
||
foreach (var (key, title, database) in AxVersions())
|
||
{
|
||
var adapter = Core.DynamicsAx.AxSchemaAdapter.For(database.Version)!;
|
||
yield return new($"AxSchemaAdapter.BatchJobs({key})", "AxBatchCollector", title + ": batchjob",
|
||
Ax + "AxSchemaAdapter.cs", "AxSchemaAdapter.BatchJobs(database) via AxSql.InDatabase", () => AxRead(database, adapter.BatchJobs(database)));
|
||
if (adapter.BatchHistory(database, null) is not null)
|
||
{
|
||
yield return new($"AxSchemaAdapter.BatchHistory({key}, første)", "AxBatchCollector", title + ": kørselshistorik, første læsning (de nyeste)",
|
||
Ax + "AxSchemaAdapter.cs", "AxSchemaAdapter.BatchHistory(database, afterRecId: null) via AxSql.InDatabase", () => AxRead(database, adapter.BatchHistory(database, null)));
|
||
yield return new($"AxSchemaAdapter.BatchHistory({key}, næste)", "AxBatchCollector",
|
||
title + $": kørselshistorik, de næste læsninger (fra den højeste RECID, SQLInsight har læst, minus {Core.DynamicsAx.AxSchemaAdapter.HistoryOverlap})",
|
||
Ax + "AxSchemaAdapter.cs", "AxSchemaAdapter.BatchHistory(database, afterRecId) via AxSql.InDatabase",
|
||
() => AxRead(database, adapter.BatchHistory(database, AxWatermark + Core.DynamicsAx.AxSchemaAdapter.HistoryOverlap))
|
||
.Replace("> " + AxWatermark.ToString(System.Globalization.CultureInfo.InvariantCulture), "> ⟪fra⟫", StringComparison.Ordinal));
|
||
}
|
||
}
|
||
|
||
// Number sequences and RecId (collector dynamics-ax-sequences).
|
||
foreach (var (key, title, database) in AxVersions())
|
||
{
|
||
var adapter = Core.DynamicsAx.AxSchemaAdapter.For(database.Version)!;
|
||
yield return new($"AxSchemaAdapter.NumberSequences({key})", "AxSequenceCollector", title + ": nummerserier",
|
||
Ax + "AxSchemaAdapter.cs", "AxSchemaAdapter.NumberSequences(database) via AxSql.InDatabase", () => AxRead(database, adapter.NumberSequences(database)));
|
||
yield return new($"AxSchemaAdapter.RecIds({key})", "AxSequenceCollector", title + ": RecId pr. tabel (SYSTEMSEQUENCES)",
|
||
Ax + "AxSchemaAdapter.cs", "AxSchemaAdapter.RecIds(database) via AxSql.InDatabase", () => AxRead(database, adapter.RecIds(database)));
|
||
}
|
||
}
|
||
|
||
private static Source StartTime(string collector, SqlServerVersion version, string variant) => new(
|
||
$"{collector}.StartTimeSql({(version.Major >= 10 ? "2008+" : version.Major == 9 ? "2005" : "2000")})",
|
||
collector, variant, C + "Db.cs", "Db.StartTimeSql(version)", () => Db.StartTimeSql(version));
|
||
}
|