499 lines
23 KiB
C#
499 lines
23 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Data.SqlClient;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using DatabaseMigrator.Properties;
|
|
using DTS.Common.Storage;
|
|
using Microsoft.Win32;
|
|
using DTS.Common.Enums;
|
|
|
|
namespace DatabaseMigrator
|
|
{
|
|
public partial class MigrationForm : Form
|
|
{
|
|
public MigrationForm(string targetDir)
|
|
{
|
|
InitializeComponent();
|
|
_targetDir = targetDir;
|
|
}
|
|
|
|
private readonly string _targetDir;
|
|
private int _desiredDatabaseVersion;
|
|
|
|
private bool localDataExists = false;
|
|
private bool localSQLiteDataExists = false;
|
|
private bool localSQLLocalDbDataExists = false;
|
|
|
|
private void buttonOK_Click(object sender, EventArgs e)
|
|
{
|
|
SetMigrationStatus("Querying database version...");
|
|
var currentDatabaseVersion = GetDatabaseVersion(true); //fix this rbLocal.Checked);
|
|
if (currentDatabaseVersion == _desiredDatabaseVersion)
|
|
{
|
|
MessageBox.Show(string.Format(Settings.Default.SameVersionDatabase, currentDatabaseVersion), Settings.Default.ActionRequired, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
|
|
}
|
|
else if (currentDatabaseVersion > _desiredDatabaseVersion)
|
|
{
|
|
MessageBox.Show(string.Format(Settings.Default.CurrentVersionGreater, currentDatabaseVersion), Settings.Default.ActionRequired, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
|
|
}
|
|
else
|
|
{
|
|
SetMigrationStatus("Creating a backup database prior to migration...");
|
|
//Make a backup copy
|
|
CopyLocalDB();
|
|
|
|
DbOperations.Connection.DbVersion = currentDatabaseVersion;
|
|
|
|
//Migrate the database
|
|
SetMigrationStatus("Migrating database from verion " + currentDatabaseVersion + " to " + _desiredDatabaseVersion + "...");
|
|
try
|
|
{
|
|
MigrationResult result = DbOperations.Connection.UpgradeVersionsIfNeeded(_desiredDatabaseVersion, SetStatus, "DataPRO", "previousdir", "targetdir", "DataPRO.exe", "applicationSettings" /*fix this*/); //handle exceptions and display error
|
|
if (result != MigrationResult.OK)
|
|
{
|
|
ConvertResultAndDisplay(result);
|
|
}
|
|
MessageBox.Show(string.Format(Settings.Default.DatabaseMigrationSucceeded, currentDatabaseVersion, _desiredDatabaseVersion), Settings.Default.ActionRequired, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
MessageBox.Show(string.Format(Settings.Default.DatabaseMigrationFailed, Environment.NewLine + Environment.NewLine), Settings.Default.ActionRequired, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
|
|
}
|
|
}
|
|
Close();
|
|
}
|
|
private void ConvertResultAndDisplay(MigrationResult result)
|
|
{
|
|
string stringResult = ConvertMigrationResultToSetting(result);
|
|
MessageBox.Show(stringResult, Settings.Default.ActionRequired, MessageBoxButtons.OK,
|
|
MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly);
|
|
}
|
|
private string ConvertMigrationResultToSetting(MigrationResult result)
|
|
{
|
|
var stringResult = string.Empty;
|
|
|
|
switch (result)
|
|
{
|
|
case MigrationResult.OK:
|
|
break;
|
|
case MigrationResult.ExceptionThrown:
|
|
break;
|
|
case MigrationResult.WarningAllowStreamingModesWasNotMigrated:
|
|
stringResult = string.Format(Settings.Default.WarningAllowStreamingModesWasNotMigrated, Environment.NewLine, Environment.NewLine);
|
|
break;
|
|
}
|
|
return stringResult;
|
|
}
|
|
|
|
private void buttonCancel_Click(object sender, EventArgs e)
|
|
{
|
|
Close();
|
|
}
|
|
|
|
private string InstallDatabase()
|
|
{
|
|
DbOperations._usingCentralizedDB = false;
|
|
DbOperations._usingMSSQL = true;
|
|
DbOperations.Connection.Server = Settings.Default.LocalDbDataPROInstance;
|
|
DbOperations._usingNTLMAuthentication = true;
|
|
|
|
var resultString = ProcessSqlLocalDbCommand(Settings.Default.StopDataProInstance);
|
|
if (resultString.Length != 0)
|
|
{
|
|
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
|
|
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
|
|
}
|
|
|
|
resultString = ProcessSqlLocalDbCommand(Settings.Default.DeleteDataProInstance);
|
|
if (resultString.Length != 0)
|
|
{
|
|
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
|
|
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
|
|
}
|
|
|
|
resultString = ProcessSqlLocalDbCommand(Settings.Default.CreateDataProInstance);
|
|
if (resultString.Length != 0)
|
|
{
|
|
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
|
|
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
|
|
}
|
|
|
|
resultString = ProcessSqlLocalDbCommand(Settings.Default.StartDataProInstance);
|
|
if (resultString.Length != 0)
|
|
{
|
|
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
|
|
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
|
|
}
|
|
|
|
//Attach the DataPRO database
|
|
var dbFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, DbOperations.Connection.DBName) + ".mdf";
|
|
var logFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, DbOperations.Connection.DBName) + "_log.ldf";
|
|
resultString = AttachDatabase(_targetDir, Settings.Default.DataPRO, dbFileName, logFileName);
|
|
if (resultString.Length != 0)
|
|
{
|
|
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
|
|
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
|
|
}
|
|
|
|
//Attach the ISO database
|
|
dbFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, Settings.Default.ISO) + ".mdf";
|
|
logFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, Settings.Default.ISO) + "_log.ldf";
|
|
resultString = AttachDatabase(_targetDir, Settings.Default.ISO, dbFileName, logFileName);
|
|
if (resultString.Length != 0)
|
|
{
|
|
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
|
|
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
|
|
}
|
|
return resultString;
|
|
}
|
|
private void SetMigrationStatus(string migrationStatus)
|
|
{
|
|
//Remove the previous status
|
|
SetStatus(string.Empty);
|
|
|
|
MigrationStatusLabel.Text = migrationStatus;
|
|
MigrationStatusLabel.Refresh();
|
|
}
|
|
|
|
private void SetStatus(string status, bool output = false)
|
|
{
|
|
statusTextLabel.Text = status;
|
|
statusTextLabel.Refresh();
|
|
}
|
|
/// <summary>
|
|
/// Builds the path to the database and database log files and calls CopyDatabaseFile for each.
|
|
/// </summary>
|
|
private bool CopyLocalDB()
|
|
{
|
|
var dbFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text.Trim()*/ + Settings.Default.Mdf);
|
|
var dbFileLogName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text.Trim()*/ + Settings.Default.LogLdf);
|
|
|
|
//Copy .mdf file
|
|
if (CopyDatabaseFile(Settings.Default.Mdf, dbFileName))
|
|
{
|
|
//Copy .ldf file
|
|
CopyDatabaseFile(Settings.Default.LogLdf, dbFileLogName);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool CopyDatabaseFile(string extension, string destFileName)
|
|
{
|
|
//The database file that is to be copied was attached to (localdb)\DataPROInstance, so detach it so it can be copied
|
|
var resultString = ProcessSqlLocalDbCommand(Settings.Default.StopDataProInstance);
|
|
if (resultString.Length != 0)
|
|
{
|
|
MessageBox.Show(resultString, Settings.Default.Warning, MessageBoxButtons.OK);
|
|
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
|
|
}
|
|
|
|
//var sourceFileName = string.Empty;
|
|
//sourceFileName = //cbCopyDataFromPrevious.Checked ?
|
|
// Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text.Trim()*/ + extension); //:
|
|
//Path.Combine(_targetDir, Settings.Default.LocalDbFolder, Settings.Default.DataPRO + extension);
|
|
//if (File.Exists(destFileName))
|
|
//{
|
|
//Back it up
|
|
var _testIDTimestamp = string.Format("{0:0000}_{1:00}_{2:00} {3:00}_{4:00}", DateTime.Now.Year,
|
|
DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute);
|
|
|
|
var temp = destFileName.Replace(extension, "_" + _testIDTimestamp + extension);
|
|
File.Copy(destFileName, temp, true); //Don't worry about overwriting a db with this timestamp
|
|
//}
|
|
//try
|
|
//{
|
|
// File.Copy(sourceFileName, destFileName, true);
|
|
// //log.WriteEntry(sourceFileName + " was copied as " + destFileName);
|
|
//}
|
|
//catch (Exception ex)
|
|
//{
|
|
// MessageBox.Show("Previous database was not copied: " + ex.Message);
|
|
// return false;
|
|
//}
|
|
return true;
|
|
}
|
|
private int GetDatabaseVersion(bool usingLocalDatabase)
|
|
{
|
|
var oldVersion = 0;
|
|
|
|
try
|
|
{
|
|
DbOperations.Connection.DBName = "DataPRO"; //fix this tbDBName.Text;
|
|
if (true) //fix this usingLocalDatabase)
|
|
{
|
|
//log.WriteEntry("Using local database");
|
|
|
|
if (localSQLLocalDbDataExists)
|
|
{
|
|
//log.WriteEntry("Local SQLLocalDb database exists in previous install");
|
|
var resultString = InstallDatabase();
|
|
if (resultString.Length != 0)
|
|
{
|
|
MessageBox.Show(resultString, Settings.Default.Warning,
|
|
MessageBoxButtons.OK);
|
|
//Environment.Exit((int)STARTUP_ERRORS.ISO_DB_NOT_ATTACHED);
|
|
}
|
|
}
|
|
//else if (localSQLiteDataExists)
|
|
//{
|
|
// log.WriteEntry("Local SQLite database exists in previous install");
|
|
|
|
// DbOperations._usingMSSQL = false;
|
|
// oldVersion = UsePreviousDatabaseStructure(true);
|
|
// return oldVersion;
|
|
//}
|
|
else
|
|
{
|
|
//log.WriteEntry("No local database exists in previous install");
|
|
}
|
|
}
|
|
//else
|
|
//{
|
|
// log.WriteEntry("Using centralized database");
|
|
|
|
// DbOperations._usingMSSQL = true;
|
|
// DbOperations.Connection.Server = tbDBHostname.Text;
|
|
// DbOperations._usingNTLMAuthentication = cbUseNTLMAuthentication.Checked;
|
|
// DbOperations.Connection.Username = tbDBUser.Text;
|
|
// DbOperations.Connection.Password = tbDBPassword.Text;
|
|
// }
|
|
//First try the most recent database structure
|
|
using (var cmd = DbOperations.GetSQLCommand(true))
|
|
{
|
|
try
|
|
{
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_DbVersionGet.ToString();
|
|
cmd.Parameters.Add(new SqlParameter("@Version", SqlDbType.Int) { Value = null });
|
|
var reader = cmd.ExecuteReader();
|
|
var dbVersionsList = new List<int>();
|
|
while (reader.Read())
|
|
{
|
|
var version = Convert.ToInt32(reader[DbOperations.DbVersions.DbVersionFields.Version.ToString()]);
|
|
dbVersionsList.Add(version);
|
|
}
|
|
reader.Close();
|
|
|
|
oldVersion = dbVersionsList.Max();
|
|
|
|
//log.WriteEntry("Result of using stored procedure sp_DbVersionGet is " + oldVersion);
|
|
if (oldVersion > 0)
|
|
{
|
|
return oldVersion;
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
cmd.Connection.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
catch (Exception)
|
|
{
|
|
//log.WriteEntry("Exception while getting previous database version: " + ex.Message);
|
|
}
|
|
|
|
return 0; //fix thisUsePreviousDatabaseStructure(usingLocalDatabase);
|
|
}
|
|
/// <summary>
|
|
/// Get the path to the latest version of SQL Server Express LocalDB
|
|
/// installed, and run the command passed in.
|
|
/// </summary>
|
|
/// <param name="command"></param>
|
|
/// <returns></returns>
|
|
private static string ProcessSqlLocalDbCommand(string command)
|
|
{
|
|
//SQL Server Express LocalDB 2014 is a Prerequisite of the DataPRO Installer,
|
|
//so it should be there unless it has been subsequently uninstalled.
|
|
var localDbPath = GetSqlServerLocalDBPath();
|
|
if (localDbPath == string.Empty)
|
|
{
|
|
//SQL Server LocalDb is not installed so display error and go away
|
|
return Settings.Default.SqlServerLocalDbNotInstalled;
|
|
}
|
|
var sqlLocalDbExeFileName = localDbPath + Settings.Default.SqlLocalDBExe;
|
|
return SqlCommandProcessor(sqlLocalDbExeFileName, command);
|
|
}
|
|
private static string AttachDatabase(string targetDir, string dbName, string sqlDbFileName, string sqlLogFileName)
|
|
{
|
|
const string SqlCmdExe = "sqlcmd.exe";
|
|
|
|
var oDBCToolsPath = DTS.Common.Utils.Database.GetODBCToolsPath(null);
|
|
var fullSqlcmdPath = Path.Combine(oDBCToolsPath, SqlCmdExe); //e.g. $"\"C:\\Program Files\\Microsoft SQL Server\\Client SDK\\ODBC\\110\\Tools\\Binn\\sqlcmd.exe\""
|
|
//var batchFileName = Path.Combine(targetDir, Settings.Default.ScriptsFolder, Settings.Default.AttachDBsbat);
|
|
var batchFileName = Settings.Default.AttachDBsbat;
|
|
return BatchCommandProcessor(batchFileName, dbName, sqlDbFileName, sqlLogFileName, fullSqlcmdPath);
|
|
}
|
|
private static string GetSqlServerLocalDBPath()
|
|
{
|
|
var highestVersionInstalledPath = string.Empty;
|
|
|
|
var rk = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
|
|
var sk1 = rk.OpenSubKey(Settings.Default.RegistrySoftwareMicrosoftMicrosoftSQLServerLocalDBInstalledVersions);
|
|
if (sk1 == null) return string.Empty;
|
|
var maxProductVersion = 0.0;
|
|
foreach (var productSubKeyName in sk1.GetSubKeyNames())
|
|
{
|
|
var thisVersion = -1D;
|
|
if (!double.TryParse(productSubKeyName, out thisVersion)) continue;
|
|
if (thisVersion < maxProductVersion) continue;
|
|
maxProductVersion = thisVersion;
|
|
var newKey = sk1.OpenSubKey(productSubKeyName);
|
|
if (newKey == null) continue;
|
|
var val = newKey.GetValue(Settings.Default.InstanceAPIPath, -1, RegistryValueOptions.None).ToString();
|
|
if ((val == "-1") || (!val.EndsWith(Settings.Default.SqlUserInstanceDll))) continue;
|
|
highestVersionInstalledPath = val.Substring(0, val.Length - Settings.Default.SqlUserInstanceDll.Length);
|
|
}
|
|
|
|
return highestVersionInstalledPath.Replace(Settings.Default.LocalDB, Settings.Default.Tools);
|
|
}
|
|
private static readonly StringBuilder sb = new StringBuilder();
|
|
static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
|
|
{
|
|
if (outLine.Data != null)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(outLine.Data))
|
|
{
|
|
sb.Append("\r\n");
|
|
}
|
|
sb.Append(outLine.Data);
|
|
}
|
|
}
|
|
public static string SqlCommandProcessor(string sqlLocalDbExeFileName, string command)
|
|
{
|
|
var resultString = string.Empty;
|
|
|
|
sb.Clear();
|
|
var process = new Process
|
|
{
|
|
StartInfo =
|
|
{
|
|
FileName = sqlLocalDbExeFileName,
|
|
Arguments = command,
|
|
LoadUserProfile = true,
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
CreateNoWindow = true
|
|
}
|
|
};
|
|
//* Set ONLY ONE handler here.
|
|
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
|
|
//* Start process
|
|
process.Start();
|
|
//* Read one element asynchronously
|
|
process.BeginErrorReadLine();
|
|
//* Read the other one synchronously
|
|
var output = process.StandardOutput.ReadToEnd();
|
|
Console.WriteLine(output);
|
|
//APILogger.Log("Result of " + command + " command is: " + output);
|
|
process.WaitForExit();
|
|
if (sb.Length > 0)
|
|
{
|
|
resultString = sb.ToString();
|
|
}
|
|
return resultString;
|
|
}
|
|
public static string BatchCommandProcessor(string batchFileName, string dbName, string sqlDbFileName, string sqlLogFileName,
|
|
string fullSqlcmdPath)
|
|
{
|
|
var resultString = string.Empty;
|
|
|
|
sb.Clear();
|
|
var process = new Process
|
|
{
|
|
StartInfo =
|
|
{
|
|
FileName = batchFileName,
|
|
Arguments = dbName + " " + "\"" + sqlDbFileName + "\"" + " " + "\"" + sqlLogFileName + "\"" + " " + "\"" + fullSqlcmdPath + "\"",
|
|
LoadUserProfile = true,
|
|
UseShellExecute = false,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
CreateNoWindow = true
|
|
}
|
|
};
|
|
//* Set ONLY ONE handler here.
|
|
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
|
|
//* Start process
|
|
process.Start();
|
|
//* Read one element asynchronously
|
|
process.BeginErrorReadLine();
|
|
//* Read the other one synchronously
|
|
var output = process.StandardOutput.ReadToEnd();
|
|
Console.WriteLine(output);
|
|
//APILogger.Log("Result of attach " + dbName + " using " + sqlDbFileName + " and " + sqlLogFileName + " is:");
|
|
//APILogger.Log(output);
|
|
process.WaitForExit();
|
|
if (sb.Length > 0)
|
|
{
|
|
resultString = sb.ToString();
|
|
}
|
|
return resultString;
|
|
}
|
|
|
|
private bool LocalDataExists()
|
|
{
|
|
//if (!PreviousVersionInstalled())
|
|
//{
|
|
// return false;
|
|
//}
|
|
|
|
//Check for "DataPRO.mdf" (SqlLocalDb in 1.5 or later) in previously-installed folder
|
|
var sourceFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text*/ + Settings.Default.Mdf);
|
|
if (File.Exists(sourceFileName))
|
|
{
|
|
localSQLLocalDbDataExists = true;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
localSQLLocalDbDataExists = false;
|
|
|
|
//Check for "datapro.db" (SQLite file in 1.4 or earlier) in previously-installed folder
|
|
sourceFileName = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text*/ + Settings.Default.Db);
|
|
if (File.Exists(sourceFileName))
|
|
{
|
|
localSQLiteDataExists = true;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
localSQLiteDataExists = false;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void MigrationForm_Load(object sender, EventArgs e)
|
|
{
|
|
numericUpDownDesiredVersion.Minimum = 61;
|
|
numericUpDownDesiredVersion.Maximum = DbOperations.CURRENT_DB_VERSION;
|
|
numericUpDownDesiredVersion.Value = DbOperations.CURRENT_DB_VERSION;
|
|
|
|
localDataExists = LocalDataExists();
|
|
if (localSQLLocalDbDataExists)
|
|
{
|
|
TbDatabasePath.Text = Path.Combine(_targetDir, Settings.Default.LocalDbFolder, "DataPRO" /*tbDBName.Text*/ + Settings.Default.Mdf);
|
|
}
|
|
}
|
|
|
|
private void numericUpDownDesiredVersion_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
_desiredDatabaseVersion = Convert.ToInt32(numericUpDownDesiredVersion.Value);
|
|
}
|
|
}
|
|
}
|