#nullable enable using MMoneyCoderSharp.Data; using MBN_STOCK_WEBVIEW.Infrastructure; using MySqlConnector; using Oracle.ManagedDataAccess.Client; namespace MBN_STOCK_WEBVIEW.DbWriteSmoke; /// /// Emits only a provider/type classification. Messages, SQL, credentials, /// identifiers, and values deliberately never cross this boundary. /// internal static class RedactedDatabaseFailureClassifier { internal static string Classify(Exception exception) { ArgumentNullException.ThrowIfNull(exception); foreach (var current in Flatten(exception)) { switch (current) { case OracleException oracle: return "Oracle-" + oracle.Number.ToString( System.Globalization.CultureInfo.InvariantCulture); case MySqlException mariaDb: return "MariaDb-" + ((int)mariaDb.ErrorCode).ToString( System.Globalization.CultureInfo.InvariantCulture); case DatabaseOperationException database: return database.DataSource + "-" + (database.ProviderErrorCode?.ToString( System.Globalization.CultureInfo.InvariantCulture) ?? "none"); case ManualFinancialMutationRejectedException rejected: return "ManualRejected-" + rejected.Reason; case OperatorCatalogConflictException conflict: return "CatalogConflict-" + conflict.Kind + "-" + conflict.CommandKind; } } return exception.GetType().Name; } private static IEnumerable Flatten(Exception exception) { var pending = new Stack(); var visited = new HashSet(ReferenceEqualityComparer.Instance); pending.Push(exception); while (pending.TryPop(out var current) && visited.Add(current)) { yield return current; if (current is AggregateException aggregate) { foreach (var inner in aggregate.InnerExceptions.Reverse()) { pending.Push(inner); } } else if (current.InnerException is not null) { pending.Push(current.InnerException); } } } }