using System.Data.Common; using SQLInsight.Core.Instances; namespace SQLInsight.Connectivity; /// /// Reads version, edition and key settings from an instance. Works on every version from SQL Server 2000: /// only SERVERPROPERTY is used, and properties an older version does not know return NULL. /// public static class InstanceProbe { internal const string Query = """ SELECT CAST(SERVERPROPERTY('ServerName') AS nvarchar(256)), CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)), CAST(SERVERPROPERTY('ProductLevel') AS nvarchar(128)), CAST(SERVERPROPERTY('ProductUpdateLevel') AS nvarchar(128)), CAST(SERVERPROPERTY('Edition') AS nvarchar(128)), CAST(SERVERPROPERTY('EngineEdition') AS int), CAST(SERVERPROPERTY('IsClustered') AS int), CAST(SERVERPROPERTY('IsHadrEnabled') AS int) """; public static async Task DetectAsync(DbConnection connection, CancellationToken cancellationToken = default) { ArgumentNullException.ThrowIfNull(connection); await using var command = connection.CreateCommand(); command.CommandText = Query; command.CommandTimeout = 30; await using var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false); if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false)) { throw new InvalidOperationException("SERVERPROPERTY returned no rows."); } var productVersion = GetString(reader, 1); if (!SqlServerVersion.TryParse(productVersion, out var version)) { throw new InvalidOperationException($"Could not parse ProductVersion '{productVersion}'."); } return new InstanceInfo { ServerName = GetString(reader, 0) ?? string.Empty, Version = version, ProductLevel = GetString(reader, 2), ProductUpdateLevel = GetString(reader, 3), Edition = GetString(reader, 4) ?? string.Empty, EngineEdition = reader.IsDBNull(5) ? EngineEdition.Unknown : (EngineEdition)reader.GetInt32(5), IsClustered = GetBool(reader, 6), IsHadrEnabled = GetBool(reader, 7), }; } private static string? GetString(DbDataReader reader, int ordinal) => reader.IsDBNull(ordinal) ? null : reader.GetString(ordinal); private static bool? GetBool(DbDataReader reader, int ordinal) => reader.IsDBNull(ordinal) ? null : reader.GetInt32(ordinal) == 1; }