diff --git a/ErrorLogImporter/ErrorLogImporter.cs b/ErrorLogImporter/ErrorLogImporter.cs new file mode 100644 index 0000000..69aafa2 --- /dev/null +++ b/ErrorLogImporter/ErrorLogImporter.cs @@ -0,0 +1,379 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using Microsoft.Data.SqlClient; +using NexusInterfaces; +using BulkLoadEx; + +namespace ErrorLogImporter +{ + public class ErrorLogImporter : INexusFileImporter + { + private const string TABLE_NAME = "tbl_ERRORLOG"; + private const string OPTION_DROP_EXISTING = "Drop existing tables (ERRORLOG)"; + private const string OPTION_ENABLED = "Enabled"; + + // Regex to match ERRORLOG lines: datetime, process, message + // Example: "2026-04-14 22:37:11.55 Server Microsoft SQL Server 2022..." + private static readonly Regex LogLineRegex = new Regex( + @"^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{2})\s+(\S+)\s+(.*)", + RegexOptions.Compiled); + + // Regex to extract Error number and State from messages like "Error: 18456, Severity: 14, State: 38." + private static readonly Regex ErrorStateRegex = new Regex( + @"Error:\s*(\d+),\s*Severity:\s*\d+,\s*State:\s*(\d+)", + RegexOptions.Compiled); + + private string fileMask = ""; + private string connStr = ""; + private ILogger logger; + + private ImportState state = ImportState.Idle; + private bool cancelled = false; + private long totalRowsInserted = 0; + private long totalLinesProcessed = 0; + private long fileSize = 0; + private long currentPosition = 0; + private bool hasDroppedTable = false; + private readonly ArrayList knownRowsets = new ArrayList(); + private readonly Dictionary options = new Dictionary(); + + + public ErrorLogImporter() + { + options.Add(OPTION_DROP_EXISTING, true); + options.Add(OPTION_ENABLED, true); + } + + private void LogMessage(string msg) + { + if (null == logger) + Trace.WriteLine(msg); + else + logger.LogMessage(msg); + } + + #region INexusImporter Members + + public Guid ID + { + get { return new Guid("D7E8F9A0-B1C2-4D3E-5F6A-7B8C9D0E1F2A"); } + } + + public void Initialize(string Filemask, string connString, string Server, bool UseWindowsAuth, string SQLLogin, string SQLPassword, string DatabaseName, ILogger Logger) + { + this.fileMask = Filemask; + this.connStr = connString; + this.logger = Logger; + this.state = ImportState.Idle; + this.cancelled = false; + this.totalRowsInserted = 0; + this.totalLinesProcessed = 0; + } + + public Dictionary Options + { + get { return options; } + } + + public Form OptionsDialog + { + get { return null; } + } + + public string[] SupportedMasks + { + get { return new string[] { "*_ERRORLOG*" }; } + } + + public string[] PreScripts + { + get { return new string[] { }; } + } + + public string[] PostScripts + { + get { return new string[] { }; } + } + + public ImportState State + { + get { return state; } + private set + { + state = value; + OnStatusChanged(EventArgs.Empty); + } + } + + public bool Cancelled + { + get { return cancelled; } + private set { cancelled = value; } + } + + public ArrayList KnownRowsets + { + get { return knownRowsets; } + } + + public long TotalRowsInserted + { + get { return totalRowsInserted; } + } + + public long TotalLinesProcessed + { + get { return totalLinesProcessed; } + } + + public string Name + { + get { return "ERRORLOG Importer"; } + } + + public bool DoImport() + { + try + { + string dir = Path.GetDirectoryName(fileMask); + string mask = Path.GetFileName(fileMask); + + if (string.IsNullOrEmpty(dir) || !Directory.Exists(dir)) + { + LogMessage("ErrorLogImporter: Directory not found: " + dir); + return false; + } + + string[] files = Directory.GetFiles(dir, mask); + if (files.Length == 0) + { + State = ImportState.NoFiles; + LogMessage("ErrorLogImporter: No ERRORLOG files found matching " + fileMask); + return true; + } + + State = ImportState.OpeningDatabaseConnection; + + if ((bool)options[OPTION_DROP_EXISTING] && !hasDroppedTable) + { + DropExistingTable(); + hasDroppedTable = true; + } + + CreateTable(); + + State = ImportState.Importing; + + foreach (string file in files) + { + if (Cancelled) + break; + + LogMessage("ErrorLogImporter: Importing file " + file); + ImportFile(file); + } + + State = ImportState.Idle; + LogMessage("ErrorLogImporter: Import complete. Total rows inserted: " + totalRowsInserted); + return true; + } + catch (Exception ex) + { + LogMessage("ErrorLogImporter: Error - " + ex); + State = ImportState.Idle; + return false; + } + } + + public void Cancel() + { + Cancelled = true; + State = ImportState.Canceling; + LogMessage("ErrorLogImporter: Received cancel request"); + } + + public event EventHandler StatusChanged; + + public void OnStatusChanged(EventArgs e) + { + StatusChanged?.Invoke(this, e); + } + + #endregion + + #region INexusProgressReporter Members + + public long CurrentPosition + { + get { return currentPosition; } + } + + public event EventHandler ProgressChanged; + + public void OnProgressChanged(EventArgs e) + { + ProgressChanged?.Invoke(this, e); + } + + #endregion + + #region INexusFileSizeReporter Members + + public long FileSize + { + get { return fileSize; } + } + + #endregion + + #region Private Methods + + private void DropExistingTable() + { + using (SqlConnection cn = new SqlConnection(connStr)) + { + cn.Open(); + using (SqlCommand cmd = new SqlCommand()) + { + cmd.Connection = cn; + cmd.CommandTimeout = 0; + cmd.CommandText = "IF OBJECT_ID ('" + TABLE_NAME + "', 'U') IS NOT NULL DROP TABLE [" + TABLE_NAME + "]"; + cmd.ExecuteNonQuery(); + } + } + } + + private void CreateTable() + { + using (SqlConnection cn = new SqlConnection(connStr)) + { + cn.Open(); + using (SqlCommand cmd = new SqlCommand()) + { + cmd.Connection = cn; + cmd.CommandTimeout = 0; + cmd.CommandText = @" + IF OBJECT_ID ('" + TABLE_NAME + @"', 'U') IS NULL + BEGIN + CREATE TABLE [" + TABLE_NAME + @"] ( + [RowNum] bigint IDENTITY(1,1) NOT NULL, + [LogDateTime] datetime NULL, + [Process] varchar(50) NULL, + [Message] varchar(max) NULL, + [ErrorNumber] int NULL, + [State] int NULL, + [FileName] varchar(256) NULL + ) + CREATE NONCLUSTERED INDEX [IX_" + TABLE_NAME + @"_LogDateTime_RowNum] ON [" + TABLE_NAME + @"] ([LogDateTime], [RowNum]) + END"; + cmd.ExecuteNonQuery(); + } + } + } + + private void ImportFile(string filePath) + { + FileInfo fi = new FileInfo(filePath); + fileSize = fi.Length; + currentPosition = 0; + string shortFileName = Path.GetFileName(filePath); + + BulkLoadRowset bulkLoad = new BulkLoadRowset(TABLE_NAME, connStr); + + try + { + DateTime? pendingDateTime = null; + string pendingProcess = null; + StringBuilder pendingMessageBuilder = null; + + using (StreamReader reader = new StreamReader(filePath)) + { + string line; + while ((line = reader.ReadLine()) != null) + { + if (Cancelled) + break; + + totalLinesProcessed++; + currentPosition += System.Text.Encoding.UTF8.GetByteCount(line) + 2; // +2 for \r\n + OnProgressChanged(EventArgs.Empty); + + Match match = LogLineRegex.Match(line); + if (match.Success) + { + // Flush the previous pending entry + if (pendingDateTime.HasValue) + { + InsertRow(bulkLoad, pendingDateTime.Value, pendingProcess, pendingMessageBuilder?.ToString(), shortFileName); + } + + + // Parse the new entry + string dateStr = match.Groups[1].Value; + pendingProcess = match.Groups[2].Value; + pendingMessageBuilder = new StringBuilder(match.Groups[3].Value); + + + pendingDateTime = DateTime.TryParseExact(dateStr, "yyyy-MM-dd HH:mm:ss.ff", + CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsedDate) + ? parsedDate + : (DateTime?)null; + + } + else + { + // Continuation line - append to current message + if (pendingMessageBuilder != null) + { + pendingMessageBuilder.Append(Environment.NewLine); + pendingMessageBuilder.Append(line); + } + } + } + + // Flush the last pending entry + if (pendingDateTime.HasValue) + { + InsertRow(bulkLoad, pendingDateTime.Value, pendingProcess, pendingMessageBuilder?.ToString(), shortFileName); + } + } + } + finally + { + bulkLoad.Close(); + } + } + + private void InsertRow(BulkLoadRowset bulkLoad, DateTime logDateTime, string process, string message, string fileName) + { + System.Data.DataRow row = bulkLoad.GetNewRow(); + row["LogDateTime"] = logDateTime; + row["Process"] = process != null && process.Length > 50 ? process.Substring(0, 50) : process; + row["Message"] = message ?? ""; + + // Extract Error number and State from message if present + if (message != null) + { + Match errorMatch = ErrorStateRegex.Match(message); + if (errorMatch.Success) + { + row["ErrorNumber"] = int.Parse(errorMatch.Groups[1].Value); + row["State"] = int.Parse(errorMatch.Groups[2].Value); + } + } + + row["FileName"] = fileName != null && fileName.Length > 256 ? fileName.Substring(0, 256) : fileName; + bulkLoad.InsertRow(row); + totalRowsInserted++; + } + + #endregion + } +} diff --git a/ErrorLogImporter/ErrorLogImporter.csproj b/ErrorLogImporter/ErrorLogImporter.csproj new file mode 100644 index 0000000..8dbba1e --- /dev/null +++ b/ErrorLogImporter/ErrorLogImporter.csproj @@ -0,0 +1,202 @@ + + + + + Debug + AnyCPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D} + Library + Properties + ErrorLogImporter + ErrorLogImporter + v4.8 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + true + + + SqlNexus.snk + + + + ..\packages\Azure.Core.1.44.1\lib\net472\Azure.Core.dll + + + ..\packages\Azure.Identity.1.12.1\lib\netstandard2.0\Azure.Identity.dll + + + ..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll + True + + + ..\packages\Microsoft.Bcl.TimeProvider.8.0.1\lib\net462\Microsoft.Bcl.TimeProvider.dll + + + ..\packages\Microsoft.Data.SqlClient.5.2.2\lib\net462\Microsoft.Data.SqlClient.dll + + + ..\packages\Microsoft.Identity.Client.4.65.0\lib\net472\Microsoft.Identity.Client.dll + + + ..\packages\Microsoft.Identity.Client.Extensions.Msal.4.65.0\lib\netstandard2.0\Microsoft.Identity.Client.Extensions.Msal.dll + + + ..\packages\Microsoft.IdentityModel.Abstractions.8.1.2\lib\net472\Microsoft.IdentityModel.Abstractions.dll + + + ..\packages\Microsoft.IdentityModel.JsonWebTokens.8.1.2\lib\net472\Microsoft.IdentityModel.JsonWebTokens.dll + + + ..\packages\Microsoft.IdentityModel.Logging.8.1.2\lib\net472\Microsoft.IdentityModel.Logging.dll + + + ..\packages\Microsoft.IdentityModel.Protocols.8.1.2\lib\net472\Microsoft.IdentityModel.Protocols.dll + + + ..\packages\Microsoft.IdentityModel.Protocols.OpenIdConnect.8.1.2\lib\net472\Microsoft.IdentityModel.Protocols.OpenIdConnect.dll + + + ..\packages\Microsoft.IdentityModel.Tokens.8.1.2\lib\net472\Microsoft.IdentityModel.Tokens.dll + + + + ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + + + ..\packages\System.ClientModel.1.2.1\lib\netstandard2.0\System.ClientModel.dll + + + ..\packages\System.Configuration.ConfigurationManager.8.0.1\lib\net462\System.Configuration.ConfigurationManager.dll + + + + ..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.IdentityModel.Tokens.Jwt.8.1.2\lib\net472\System.IdentityModel.Tokens.Jwt.dll + + + ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll + True + + + ..\packages\System.IO.FileSystem.AccessControl.5.0.0\lib\net461\System.IO.FileSystem.AccessControl.dll + + + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll + + + ..\packages\System.Memory.Data.8.0.1\lib\net462\System.Memory.Data.dll + + + ..\packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll + True + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll + True + + + ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + + + ..\packages\System.Security.AccessControl.6.0.1\lib\net461\System.Security.AccessControl.dll + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net463\System.Security.Cryptography.Algorithms.dll + True + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + True + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + True + + + ..\packages\System.Security.Cryptography.ProtectedData.8.0.0\lib\net462\System.Security.Cryptography.ProtectedData.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll + True + + + ..\packages\System.Security.Permissions.8.0.0\lib\net462\System.Security.Permissions.dll + + + ..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll + + + ..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll + True + + + ..\packages\System.Text.Json.8.0.5\lib\net462\System.Text.Json.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll + + + ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll + + + + + + + + + + {f9069c48-39a6-4fb9-b4b8-d8d0034709a3} + BulkLoadEx + + + {2217e9ca-442e-46c5-ab6c-7a46ae41a22c} + NexusInterfaces + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + diff --git a/ErrorLogImporter/Properties/AssemblyInfo.cs b/ErrorLogImporter/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9837498 --- /dev/null +++ b/ErrorLogImporter/Properties/AssemblyInfo.cs @@ -0,0 +1,15 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("ErrorLogImporter")] +[assembly: AssemblyDescription("SQL Server ERRORLOG Importer for SQL Nexus")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("ErrorLogImporter")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2026")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: Guid("A1B2C3D4-E5F6-4A5B-9C8D-7E6F5A4B3C2D")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ErrorLogImporter/SqlNexus.snk b/ErrorLogImporter/SqlNexus.snk new file mode 100644 index 0000000..4760abb Binary files /dev/null and b/ErrorLogImporter/SqlNexus.snk differ diff --git a/ErrorLogImporter/packages.config b/ErrorLogImporter/packages.config new file mode 100644 index 0000000..2583c8d --- /dev/null +++ b/ErrorLogImporter/packages.config @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RowsetImportEngine/TextRowsets.xml b/RowsetImportEngine/TextRowsets.xml index bb5e864..d5594af 100644 --- a/RowsetImportEngine/TextRowsets.xml +++ b/RowsetImportEngine/TextRowsets.xml @@ -724,16 +724,6 @@ - - - - - - - - - - diff --git a/sqlnexus.sln b/sqlnexus.sln index 504c512..45f9171 100644 --- a/sqlnexus.sln +++ b/sqlnexus.sln @@ -28,6 +28,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Setup-Related\SetupSQLNexusPrereq.ps1 = Setup-Related\SetupSQLNexusPrereq.ps1 EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ErrorLogImporter", "ErrorLogImporter\ErrorLogImporter.csproj", "{B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -395,6 +397,56 @@ Global {CCF72846-1645-4548-8E66-A2FFCE83692D}.Release|x64.Build.0 = Release|Any CPU {CCF72846-1645-4548-8E66-A2FFCE83692D}.Release|x86.ActiveCfg = Release|Any CPU {CCF72846-1645-4548-8E66-A2FFCE83692D}.Release|x86.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|Win32.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|Win32.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|x64.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|x64.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|x86.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug|x86.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|Any CPU.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|Any CPU.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|Mixed Platforms.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|Win32.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|Win32.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|x64.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|x64.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|x86.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Debug64|x86.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|Any CPU.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|Any CPU.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|Mixed Platforms.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|Win32.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|Win32.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|x64.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|x64.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|x86.ActiveCfg = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.DebugLocal|x86.Build.0 = Debug|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|Any CPU.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|Any CPU.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|Mixed Platforms.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|Mixed Platforms.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|Win32.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|Win32.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|x64.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|x64.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|x86.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Production|x86.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|Any CPU.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|Win32.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|Win32.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|x64.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|x64.Build.0 = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|x86.ActiveCfg = Release|Any CPU + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sqlnexus/AppConfig.xml b/sqlnexus/AppConfig.xml index 27eb501..036b649 100644 --- a/sqlnexus/AppConfig.xml +++ b/sqlnexus/AppConfig.xml @@ -21,6 +21,8 @@ + + diff --git a/sqlnexus/TextRowsets.xml b/sqlnexus/TextRowsets.xml index bb5e864..d5594af 100644 --- a/sqlnexus/TextRowsets.xml +++ b/sqlnexus/TextRowsets.xml @@ -724,16 +724,6 @@ - - - - - - - - - - diff --git a/sqlnexus/Utilities.cs b/sqlnexus/Utilities.cs index 497aa58..9e68606 100644 --- a/sqlnexus/Utilities.cs +++ b/sqlnexus/Utilities.cs @@ -35,6 +35,10 @@ public static bool IsEnabled(String option) { return m_options.ContainsKey(option) && m_options[option]; } + public static bool HasOption(String option) + { + return m_options.ContainsKey(option); + } public static void Set(String option, bool Enable ) { if (m_options.ContainsKey(option)) diff --git a/sqlnexus/fmImport.cs b/sqlnexus/fmImport.cs index cb1f47e..392c3c9 100644 --- a/sqlnexus/fmImport.cs +++ b/sqlnexus/fmImport.cs @@ -597,11 +597,11 @@ private void EnumImportersFromDirectory(string importerDirectory) subtsi.Tag = prod; subtsi.CheckOnClick = true; - bool UserSaved = ImportOptions.IsEnabled(String.Format("{0}.{1}", prod.Name, subtsi.Text)); + string savedKey = String.Format("{0}.{1}", prod.Name, subtsi.Text); MainForm.LogMessage("load: " + String.Format("{0}->{1}", prod.Name, option), MessageOptions.Silent); - if (ImportOptions.IsEnabled("SaveImportOptions")) - subtsi.Checked = UserSaved; + if (ImportOptions.IsEnabled("SaveImportOptions") && ImportOptions.HasOption(savedKey)) + subtsi.Checked = ImportOptions.IsEnabled(savedKey); else subtsi.Checked = (bool)prod.Options[option]; diff --git a/sqlnexus/sqlnexus.csproj b/sqlnexus/sqlnexus.csproj index 687ce72..72b4479 100644 --- a/sqlnexus/sqlnexus.csproj +++ b/sqlnexus/sqlnexus.csproj @@ -886,6 +886,10 @@ {8DB02D0C-68F3-4762-9BC9-AA3DF2B91F4B} RowsetImportEngine + + {B3A4C5D6-E7F8-4A9B-0C1D-2E3F4A5B6C7D} + ErrorLogImporter + @@ -1673,4 +1677,4 @@ - \ No newline at end of file +