--- source_files: - DataPRO/Modules/Database/DatabaseMigrator/MigrateDatabase.cs - DataPRO/Modules/Database/DatabaseMigrator/MigrationForm.Designer.cs - DataPRO/Modules/Database/DatabaseMigrator/MigrationForm.cs generated_at: "2026-04-16T04:35:00.160493+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "ea93d67370ed0c49" --- # DatabaseMigrator Module Documentation ## 1. Purpose This module provides a Windows Forms-based utility for upgrading a local DataPRO database to a specified target version. It serves as a standalone migration tool that interacts with SQL Server Express LocalDB instances, validates the current database version, creates backups before migration, executes version-specific upgrade scripts via the `DbOperations.Connection.UpgradeVersionsIfNeeded` method, and handles error reporting and user interaction. It is intended for use during application upgrades where the embedded database schema has changed, ensuring safe and traceable schema evolution. ## 2. Public Interface The module exposes only one public class: `MigrationForm`. All other types (`MigrateDatabase`, `DbOperations`, `MigrationResult`, etc.) are referenced but not defined in the provided source. ### `MigrationForm(string targetDir)` **Namespace:** `DatabaseMigrator` **Inherits:** `System.Windows.Forms.Form` **Behavior:** Constructor that initializes the form UI and stores the `_targetDir` path (used to locate database files and configuration). It does not perform any migration logic itself. ### `MigrationForm.buttonOK_Click(object sender, EventArgs e)` **Access:** `private` (event handler) **Behavior:** Handles the OK button click. Performs the following sequence: 1. Queries the current database version via `GetDatabaseVersion(true)`. 2. Compares current version to `_desiredDatabaseVersion`. 3. If versions match or current > desired, shows a warning message. 4. If migration is needed: - Calls `CopyLocalDB()` to create a backup. - Invokes `DbOperations.Connection.UpgradeVersionsIfNeeded(...)` with hardcoded arguments (`"DataPRO"`, `"previousdir"`, `"targetdir"`, `"DataPRO.exe"`, `"applicationSettings"`). - Displays success or failure via `MessageBox`. 5. Closes the form. ### `MigrationForm.buttonCancel_Click(object sender, EventArgs e)` **Access:** `private` (event handler) **Behavior:** Closes the form without performing any migration. ### `MigrationForm.GetDatabaseVersion(bool usingLocalDatabase)` **Access:** `private` **Behavior:** Determines the current database version by: - Attempting to run the stored procedure `sp_DbVersionGet` (via `DbOperations.GetSQLCommand(true)`). - Parsing the returned version numbers and returning the maximum. - Falls back to returning `0` on failure (commented-out SQLite fallback logic is present but inactive). - If `localSQLLocalDbDataExists` is true, calls `InstallDatabase()` first to set up the LocalDB instance. ### `MigrationForm.CopyLocalDB()` **Access:** `private` **Behavior:** Creates a timestamped backup of the `DataPRO.mdf` and `DataPRO_log.ldf` files in the `_targetDir`. It: - Calls `ProcessSqlLocalDbCommand(...StopDataProInstance...)` to stop the LocalDB instance. - Copies the `.mdf` and `.ldf` files to new filenames with suffix `_YYYY_MM_DD HH_MM`. - Returns `true` if `.mdf` copy succeeds (`.ldf` copy is not checked for success). ### `MigrationForm.InstallDatabase()` **Access:** `private` **Behavior:** Sets up a fresh LocalDB instance named `(localdb)\DataPROInstance` by: - Setting `DbOperations._usingMSSQL = true`, `_usingCentralizedDB = false`, `_usingNTLMAuthentication = true`. - Executing a sequence of `sqllocaldb.exe` commands via `ProcessSqlLocalDbCommand(...)`: - Stop instance - Delete instance - Create instance - Start instance - Attaching two databases (`DataPRO` and `ISO`) using `AttachDatabase(...)`, which internally calls `sqlcmd.exe` via a batch file. ### `MigrationForm.SetMigrationStatus(string migrationStatus)` **Access:** `private` **Behavior:** Updates the `MigrationStatusLabel` UI element with the given status string and forces a UI refresh. ### `MigrationForm.SetStatus(string status, bool output = false)` **Access:** `private` **Behavior:** Updates the `statusTextLabel` UI element with the given status string and forces a UI refresh. The `output` parameter is unused. ### `MigrationForm.numericUpDownDesiredVersion_ValueChanged(object sender, EventArgs e)` **Access:** `private` (event handler) **Behavior:** Updates `_desiredDatabaseVersion` to the current value of `numericUpDownDesiredVersion`. ### `MigrationForm.LocalDataExists()` **Access:** `private` **Behavior:** Checks for existence of database files in `_targetDir\LocalDb\`: - First checks for `DataPRO.mdf` → sets `localSQLLocalDbDataExists = true`. - Else checks for `DataPRO.db` (SQLite) → sets `localSQLiteDataExists = true`. - Returns `true` if either exists. ### `MigrationForm.MigrationForm_Load(object sender, EventArgs e)` **Access:** `private` (event handler) **Behavior:** On form load: - Sets `numericUpDownDesiredVersion` range to `[61, DbOperations.CURRENT_DB_VERSION]`. - Sets initial value to `DbOperations.CURRENT_DB_VERSION`. - Calls `LocalDataExists()` to detect existing database type. - Populates `TbDatabasePath.Text` with the full path to `DataPRO.mdf` if LocalDB data exists. ### `MigrationForm.ConvertMigrationResultToSetting(MigrationResult result)` **Access:** `private` **Behavior:** Maps `MigrationResult` enum values to user-facing strings using `Settings.Default.*` resources. Currently only handles `WarningAllowStreamingModesWasNotMigrated`. ### `MigrationForm.ConvertResultAndDisplay(MigrationResult result)` **Access:** `private` **Behavior:** Calls `ConvertMigrationResultToSetting(...)` and displays the result in a `MessageBox`. ### `MigrationForm.ProcessSqlLocalDbCommand(string command)` *(static)* **Access:** `private static` **Behavior:** Executes a command string via `sqllocaldb.exe`: - Locates the highest installed LocalDB version via registry (`HKLM\...\LocalDB\InstalledVersions`). - Constructs full path to `SqlLocalDB.exe`. - Invokes `SqlCommandProcessor(...)` to run the command and capture output. ### `MigrationForm.AttachDatabase(string targetDir, string dbName, string sqlDbFileName, string sqlLogFileName)` *(static)* **Access:** `private static` **Behavior:** Attaches a database using a batch file (`Settings.Default.AttachDBsbat`) via `BatchCommandProcessor(...)`. Uses `sqlcmd.exe` from ODBC tools path. ### `MigrationForm.GetSqlServerLocalDBPath()` *(static)* **Access:** `private static` **Behavior:** Reads the Windows registry to find the highest installed SQL Server LocalDB version and returns the path to its tools directory. ### `MigrationForm.OutputHandler(...)` *(static)* **Access:** `private static` **Behavior:** Appends asynchronous output from a `Process` to a static `StringBuilder` (`sb`). ### `MigrationForm.SqlCommandProcessor(...)` *(static)* **Access:** `public static` **Behavior:** Executes a command-line process (e.g., `sqllocaldb.exe` or batch file), captures output via `OutputHandler`, and returns accumulated output as a string. ### `MigrationForm.BatchCommandProcessor(...)` *(static)* **Access:** `public static` **Behavior:** Executes a batch file with arguments (e.g., database attach script), captures output, and returns accumulated output. > **Note:** The following types are used but *not defined* in the provided source: > - `DbOperations` (class with static `Connection`, `_usingCentralizedDB`, `_usingMSSQL`, `CURRENT_DB_VERSION`, `GetSQLCommand(...)`, `DbVersions`, `DbVersionFields`) > - `DbOperationsEnum.StoredProcedure` > - `MigrationResult` (enum with at least `OK`, `ExceptionThrown`, `WarningAllowStreamingModesWasNotMigrated`) > - `Settings.Default` (properties: `LocalDbDataPROInstance`, `StopDataProInstance`, `DeleteDataProInstance`, `CreateDataProInstance`, `StartDataProInstance`, `LocalDbFolder`, `Mdf`, `LogLdf`, `DataPRO`, `ISO`, `AttachDBsbat`, `RegistrySoftwareMicrosoftMicrosoftSQLServerLocalDBInstalledVersions`, `InstanceAPIPath`, `SqlUserInstanceDll`, `LocalDB`, `Tools`, `SqlLocalDBExe`, `SqlServerLocalDbNotInstalled`, `SameVersionDatabase`, `CurrentVersionGreater`, `DatabaseMigrationSucceeded`, `DatabaseMigrationFailed`, `ActionRequired`, `Warning`, `WarningAllowStreamingModesWasNotMigrated`, `Db`) > - `DTS.Common.Storage`, `DTS.Common.Enums`, `DTS.Common.Utils.Database` namespaces ## 3. Invariants - `_desiredDatabaseVersion` is always set to the current value of `numericUpDownDesiredVersion` via the `ValueChanged` event handler. - `numericUpDownDesiredVersion` is constrained to `[61, DbOperations.CURRENT_DB_VERSION]` at form load. - Database backup is *always* attempted before migration (even if `CopyDatabaseFile` does not validate `.ldf` copy success). - `GetDatabaseVersion` returns `0` if no version can be determined (e.g., stored procedure fails or no versions found). - LocalDB instance setup (`InstallDatabase`) is only triggered if `localSQLLocalDbDataExists` is true *and* `GetDatabaseVersion` is called. - `DbOperations.Connection.Server` is hardcoded to `Settings.Default.LocalDbDataPROInstance` in `InstallDatabase`. - `DbOperations.Connection.DBName` is hardcoded to `"DataPRO"` in `GetDatabaseVersion`. - `DbOperations.Connection.UpgradeVersionsIfNeeded(...)` is called with fixed string arguments: `"DataPRO"`, `"previousdir"`, `"targetdir"`, `"DataPRO.exe"`, `"applicationSettings"` — no dynamic configuration is used. ## 4. Dependencies ### External Dependencies (Inferred from Imports/Usings): - `System.Windows.Forms` (UI framework) - `System.Data.SqlClient` (SQL Server client) - `System.Diagnostics` (process execution) - `System.IO` (file operations) - `Microsoft.Win32` (registry access) - `DTS.Common.Storage` (likely contains `DbOperations` and related types) - `DTS.Common.Enums` (likely contains `DbOperationsEnum.StoredProcedure`, `MigrationResult`, `STARTUP_ERRORS`) - `DTS.Common.Utils.Database` (contains `GetODBCToolsPath(...)`) ### Internal Dependencies (Inferred from Usage): - `DatabaseMigrator.Properties.Settings.Default` — provides configuration strings (e.g., instance names, file extensions, registry keys, messages). - `DbOperations.Connection` — central database access object (must expose `Server`, `DBName`, `DbVersion`, `UpgradeVersionsIfNeeded(...)`, `GetSQLCommand(...)`, and static fields like `_usingMSSQL`, `_usingCentralizedDB`, `_usingNTLMAuthentication`). - `DbOperationsEnum.StoredProcedure` — must include `sp_DbVersionGet`. - `DbOperations.DbVersions` — must contain `DbVersionFields.Version`. - `DTS.Common.Utils.Database.GetODBCToolsPath(...)` — returns path to `sqlcmd.exe`. ### What Depends on This Module: - The main entry point (`MigrateDatabase.Main`) is invoked as a standalone executable (likely triggered by the main DataPRO installer or updater). - No other modules in this codebase reference `MigrationForm` — it is self-contained. ## 5. Gotchas - **Hardcoded Migration Arguments**: `DbOperations.Connection.UpgradeVersionsIfNeeded(...)` is called with fixed string parameters (`"previousdir"`, `"targetdir"`, etc.) that do not appear to be derived from user input or configuration. This may cause migration to fail if those strings are not meaningful to the underlying upgrade logic. - **Silent `.ldf` Copy Failure**: `CopyDatabaseFile` copies the `.mdf` file first and returns `true` if that succeeds, but does *not* check success of the `.ldf` copy — potentially leaving the backup incomplete. - **`GetDatabaseVersion` Ignores `usingLocalDatabase` Parameter**: The parameter is always `true` in practice (hardcoded in `buttonOK_Click` and `MigrationForm_Load`), and the `else` branch for centralized DB is commented out. - **SQLite Support Inactive**: `localSQLiteDataExists` is set but never used — the SQLite fallback path in `GetDatabaseVersion` is commented out. - **Registry Assumptions**: `GetSqlServerLocalDBPath` assumes LocalDB is installed in a specific registry path and uses hardcoded suffixes (`Settings.Default.LocalDB`, `SqlUserInstanceDll`, `InstanceAPIPath`, `Tools`). Failure to match these will cause `ProcessSqlLocalDbCommand` to fail. - **No Validation of Desired Version**: User can select any version in the `NumericUpDown`, but `DbOperations.Connection.UpgradeVersionsIfNeeded(...)` may not support downgrades or arbitrary version jumps — behavior is unknown without its source. - **UI Blocking**: All migration logic runs on the UI thread (synchronous `Process.WaitForExit()` calls), which may cause the form to freeze during long operations. - **Hardcoded Database Names**: `"DataPRO"` and `"ISO"` are hardcoded in multiple places (`InstallDatabase`, `CopyLocalDB`, `LocalDataExists`). No support for custom database names. - **`SetStatus` Parameter Unused**: The `output` parameter in `SetStatus(string status, bool output = false)` is never used. - **`_testIDTimestamp` Format Ambiguity**: Backup filename timestamp uses space (`" {0:00}_{1:00}"`) which may cause issues on some filesystems (e.g., network shares with strict naming rules).