Add upgrade functionality and support for schema-based operations

Introduced new features including database upgrade logic, schema comparison, and schema-based updates. Refactored main program structure for modularity. Added unit tests and updated configuration files to support upgrades and enhanced mapping functionality.
This commit is contained in:
Michal Buzik 2025-08-22 11:49:54 +02:00
parent 43f492745f
commit 7072399225
38 changed files with 195990 additions and 274 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,815 @@
{
"Tables": [
{
"TableName": "procedure",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"IsPrimaryKey": true,
"Nullable": "NO"
}
},
{
"OldColumn": "ItemNr",
"NewColumn": "ItemNr",
"Status": "matched",
"ColumnDef": {
"Name": "ItemNr",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Name",
"NewColumn": "Name",
"Status": "matched",
"ColumnDef": {
"Name": "Name",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Description",
"NewColumn": "Description",
"Status": "matched",
"ColumnDef": {
"Name": "Description",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "CreationUser",
"NewColumn": "CreationUser",
"Status": "matched",
"ColumnDef": {
"Name": "CreationUser",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "CreationTime",
"NewColumn": "CreationTime",
"Status": "matched",
"ColumnDef": {
"Name": "CreationTime",
"Type": "datetime",
"Nullable": "YES"
}
},
{
"OldColumn": "LastChgUser",
"NewColumn": "LastChgUser",
"Status": "matched",
"ColumnDef": {
"Name": "LastChgUser",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "LastChgTime",
"NewColumn": "LastChgTime",
"Status": "matched",
"ColumnDef": {
"Name": "LastChgTime",
"Type": "datetime",
"Nullable": "YES"
}
},
{
"OldColumn": "LongDescription",
"NewColumn": "LongDescription",
"Status": "matched",
"ColumnDef": {
"Name": "LongDescription",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ProcedureState",
"NewColumn": "ProcedureState",
"Status": "matched",
"ColumnDef": {
"Name": "ProcedureState",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Revision",
"NewColumn": "Revision",
"Status": "matched",
"ColumnDef": {
"Name": "Revision",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "PredecessorId",
"NewColumn": "PredecessorId",
"Status": "matched",
"ColumnDef": {
"Name": "PredecessorId",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "ObtainedByCopy",
"NewColumn": "ObtainedByCopy",
"Status": "matched",
"ColumnDef": {
"Name": "ObtainedByCopy",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "MetersKind",
"NewColumn": "MetersKind",
"Status": "matched",
"ColumnDef": {
"Name": "MetersKind",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Watermeters",
"NewColumn": "Watermeters",
"Status": "matched",
"ColumnDef": {
"Name": "Watermeters",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ProtocolTitle",
"Status": "new",
"Note": "New",
"ColumnDef": {
"Name": "ProtocolTitle",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Protected",
"NewColumn": "Protected",
"Status": "matched",
"ColumnDef": {
"Name": "Protected",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "MustBeComplete",
"NewColumn": "MustBeComplete",
"Status": "matched",
"ColumnDef": {
"Name": "MustBeComplete",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "ManualCtrlDisabled",
"NewColumn": "ManualCtrlDisabled",
"Status": "matched",
"ColumnDef": {
"Name": "ManualCtrlDisabled",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "DataEntry",
"NewColumn": "DataEntry",
"Status": "matched",
"ColumnDef": {
"Name": "DataEntry",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ResultsPrinter",
"NewColumn": "ResultsPrinter",
"Status": "matched",
"ColumnDef": {
"Name": "ResultsPrinter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ResultsWriter",
"NewColumn": "ResultsWriter",
"Status": "matched",
"ColumnDef": {
"Name": "ResultsWriter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionStart",
"NewColumn": "TransitionStart",
"Status": "matched",
"ColumnDef": {
"Name": "TransitionStart",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionEnd",
"NewColumn": "TransitionEnd",
"Status": "matched",
"ColumnDef": {
"Name": "TransitionEnd",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "AltProcName",
"NewColumn": "AltProcName",
"Status": "matched",
"ColumnDef": {
"Name": "AltProcName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "AltProcPeriod",
"NewColumn": "AltProcPeriod",
"Status": "matched",
"ColumnDef": {
"Name": "AltProcPeriod",
"Type": "int(11)",
"Nullable": "NO"
}
}
],
"IsNewTable": false
},
{
"TableName": "test",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"IsPrimaryKey": true,
"Nullable": "NO"
}
},
{
"OldColumn": "ItemNr",
"NewColumn": "ItemNr",
"Status": "matched",
"ColumnDef": {
"Name": "ItemNr",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Name",
"NewColumn": "Name",
"Status": "matched",
"ColumnDef": {
"Name": "Name",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Part",
"NewColumn": "Part",
"Status": "matched",
"ColumnDef": {
"Name": "Part",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Publish",
"NewColumn": "Publish",
"Status": "matched",
"ColumnDef": {
"Name": "Publish",
"Type": "tinyint(4)",
"Nullable": "YES"
}
},
{
"OldColumn": "Evaluate",
"NewColumn": "DoEvaluate",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "Evaluate",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "Qfrom",
"NewColumn": "Qfrom",
"Status": "Change",
"Note": "Could be part of JSON or renamed",
"ColumnDefList": [{
"Name": "Qfrom",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Qfrom",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Qto",
"NewColumn": "Qto",
"Status": "Change",
"Note": "",
"ColumnDefList": [
{
"Name": "Qto",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Qto",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Volume",
"Status": "Change",
"Note": "",
"ColumnDefList": [
{
"Name": "Volume",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Volume",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "TstTime",
"NewColumn": "TestTime",
"Status": "update",
"Note": "Could be part of JSON or renamed",
"ColumnDefList": [
{
"Name": "TstTime",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "TestTime",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Repeats",
"NewColumn": "Repeats",
"Status": "matched",
"ColumnDef": {
"Name": "Repeats",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Emptying",
"NewColumn": "DoDraining",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "Emptying",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "Zeroing",
"Status": "uncertain",
"Note": "Could be part of JSON or renamed",
"ColumnDef": {
"Name": "Zeroing",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "DoControlWaterTemp",
"Status": "uncertain",
"Note": "Could be part of JSON or renamed",
"ColumnDef": {
"Name": "DoControlWaterTemp",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "TempLimLo",
"NewColumn": "TempLimLo",
"Status": "matched",
"ColumnDef": {
"Name": "TempLimLo",
"Type": "float",
"Nullable": "NO"
}
},
{
"OldColumn": "TempLimHi",
"NewColumn": "TempLimHi",
"Status": "matched",
"ColumnDef": {
"Name": "TempLimHi",
"Type": "float",
"Nullable": "NO"
}
},
{
"OldColumn": "PumpPower",
"NewColumn": "PumpPower",
"Status": "matched",
"ColumnDef": {
"Name": "PumpPower",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "MassRepeats",
"NewColumn": "MassRepeats",
"Status": "matched",
"ColumnDef": {
"Name": "MassRepeats",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "MassSpread",
"NewColumn": "MassSpread",
"Status": "matched",
"ColumnDef": {
"Name": "MassSpread",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "MassMethod",
"NewColumn": "MassMethod",
"Status": "Changed",
"Note": "`MassMethod` tinyint(3) unsigned DEFAULT NULL,",
"ColumnDefList": [
{
"Name": "MassMethod",
"Type": "tinyint(1)",
"Nullable": "YES"
},
{
"Name": "MassMethod",
"Type": "tinyint(3)",
"Nullable": "YES"
}
]
},
{
"OldColumn": "TimeBeforeFlow",
"NewColumn": "TimeBeforeFlow",
"Status": "matched",
"ColumnDef": {
"Name": "TimeBeforeFlow",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeFlow2Mass",
"NewColumn": "TimeFlow2Mass",
"Status": "matched",
"ColumnDef": {
"Name": "TimeFlow2Mass",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeMass2Start",
"NewColumn": "TimePump2StartV",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "TimeMass2Start",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeStop2Mass",
"NewColumn": "TimeStop2Mass",
"Status": "matched",
"ColumnDef": {
"Name": "TimeStop2Mass",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Method",
"NewColumn": "Method",
"Status": "matched",
"ColumnDef": {
"Name": "Method",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ErrLimLo",
"NewColumn": "ErrLimLo",
"Status": "matched",
"ColumnDef": {
"Name": "ErrLimLo",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "ErrLimHi",
"NewColumn": "ErrLimHi",
"Status": "matched",
"ColumnDef": {
"Name": "ErrLimHi",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "Uncertainty",
"NewColumn": "Uncertainty",
"Status": "matched",
"ColumnDef": {
"Name": "Uncertainty",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "TolerRed",
"Status": "Deleted",
"ColumnDef": {
"Name": "TolerRed",
"Type": "double",
"Nullable": "YES"
}
},
{
"OldColumn": "RedType",
"Status": "Deleted",
"ColumnDef": {
"Name": "RedType",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "FeedingPath",
"NewColumn": "FeedingPath",
"Status": "matched",
"ColumnDef": {
"Name": "FeedingPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "BenchPath",
"NewColumn": "BenchPath",
"Status": "matched",
"ColumnDef": {
"Name": "BenchPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "OutputPath",
"NewColumn": "OutputPath",
"Status": "matched",
"ColumnDef": {
"Name": "OutputPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "MetersPath",
"NewColumn": "MetersPath",
"Status": "matched",
"ColumnDef": {
"Name": "MetersPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "HeatMetersPath",
"NewColumn": "HeatMetersPath",
"Status": "matched",
"ColumnDef": {
"Name": "HeatMetersPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransBefore",
"NewColumn": "TransBefore",
"Status": "Renamed",
"ColumnDef": {
"Name": "RelTransBefore",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransBetween",
"NewColumn": "TransBetween",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "RelTransBetween",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransAfter",
"NewColumn": "TransAfter",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "RelTransAfter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionAfter",
"Status": "Deleted",
"Note": "",
"ColumnDef": {
"Name": "TransitionAfter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Procedure_id",
"NewColumn": "Procedure_id",
"Status": "matched",
"ColumnDef": {
"Name": "Procedure_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
},
{
"TableName": "componentprocedure",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"IsPrimaryKey": true,
"Nullable": "NO"
}
},
{
"OldColumn": "CmpntName",
"NewColumn": "CmpntName",
"Status": "matched",
"ColumnDef": {
"Name": "CmpntName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Parameters",
"NewColumn": "Parameters",
"Status": "matched",
"ColumnDef": {
"Name": "Parameters",
"Type": "varchar(8000)",
"Nullable": "YES"
}
},
{
"OldColumn": "Procedure_id",
"NewColumn": "Procedure_id",
"Status": "matched",
"ColumnDef": {
"Name": "Procedure_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
},
{
"TableName": "componenttest",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"IsPrimaryKey": true,
"Nullable": "NO"
}
},
{
"OldColumn": "CmpntName",
"NewColumn": "CmpntName",
"Status": "matched",
"ColumnDef": {
"Name": "CmpntName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Parameters",
"NewColumn": "Parameters",
"Status": "matched",
"ColumnDef": {
"Name": "Parameters",
"Type": "varchar(8000)",
"Nullable": "YES"
}
},
{
"OldColumn": "Test_id",
"NewColumn": "Test_id",
"Status": "matched",
"ColumnDef": {
"Name": "Test_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
}
]
}

View File

@ -0,0 +1,52 @@
CREATE TABLE IF NOT EXISTS `test` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`ItemNr` int(11) DEFAULT NULL,
`Name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`Part` int(11) DEFAULT NULL,
`Publish` tinyint(4) DEFAULT NULL,
`Evaluate` tinyint(1) DEFAULT NULL,
`Qfrom` float DEFAULT NULL,
`Qto` float DEFAULT NULL,
`Volume` float DEFAULT NULL,
`TstTime` float DEFAULT NULL,
`Repeats` int(11) DEFAULT NULL,
`Emptying` tinyint(1) DEFAULT NULL,
`Zeroing` tinyint(1) DEFAULT NULL,
`DoControlWaterTemp` tinyint(1) NOT NULL DEFAULT '0',
`TempLimLo` float NOT NULL DEFAULT '15',
`TempLimHi` float NOT NULL DEFAULT '25',
`PumpPower` float DEFAULT NULL,
`MassRepeats` int(11) DEFAULT NULL,
`MassSpread` float DEFAULT NULL,
`MassMethod` tinyint(1) DEFAULT NULL,
`TimeBeforeFlow` int(11) DEFAULT NULL,
`TimeFlow2Mass` int(11) DEFAULT NULL,
`TimeMass2Start` int(11) DEFAULT NULL,
`TimeStop2Mass` int(11) DEFAULT NULL,
`Method` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`ErrLimLo` float DEFAULT NULL,
`ErrLimHi` float DEFAULT NULL,
`Uncertainty` float DEFAULT NULL,
`TolerRed` double DEFAULT NULL,
`RedType` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`FeedingPath` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`BenchPath` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`OutputPath` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`MetersPath` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`HeatMetersPath` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`RelTransBefore` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`RelTransBetween` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`RelTransAfter` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`TransitionAfter` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`Procedure_id` int(11) DEFAULT NULL,
PRIMARY KEY (`Id`),
KEY `Procedure_id` (`Procedure_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=4322 ;
--
-- Sťahujem dáta pre tabuľku `test`
--
INSERT INTO `test` (`Id`, `ItemNr`, `Name`, `Part`, `Publish`, `Evaluate`, `Qfrom`, `Qto`, `Volume`, `TstTime`, `Repeats`, `Emptying`, `Zeroing`, `DoControlWaterTemp`, `TempLimLo`, `TempLimHi`, `PumpPower`, `MassRepeats`, `MassSpread`, `MassMethod`, `TimeBeforeFlow`, `TimeFlow2Mass`, `TimeMass2Start`, `TimeStop2Mass`, `Method`, `ErrLimLo`, `ErrLimHi`, `Uncertainty`, `TolerRed`, `RedType`, `FeedingPath`, `BenchPath`, `OutputPath`, `MetersPath`, `HeatMetersPath`, `RelTransBefore`, `RelTransBetween`, `RelTransAfter`, `TransitionAfter`, `Procedure_id`) VALUES
(1, 0, 'Test1', 0, 1, 1, 2, 2.2, 58.3333, 100, 1, 0, 0, 0, 15, 25, 60, 0, 0, 0, 10, 5, 1, 5, 'FlyingStart.Single', -2, 2, 0, 0, 'Fix', 'CFeed1', 'PBench1', 'CPQ1B', 'PSens1', NULL, '', '', '', '', 4),
(2, 0, 'Test1', 0, 1, 1, 2, 2.2, 100, 171.429, 1, 0, 0, 0, 15, 25, 60, 0, 0, 0, 10, 5, 1, 5, 'FlyingStart.Single', -2, 2, 0, 0, 'Fix', 'CFeed1', 'PBench1', 'CPQ1B', 'PSens1', NULL, '', '', '', '', 5);

View File

@ -0,0 +1,111 @@
using System;
using System.IO;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using tbfDBBackup.compare_dumps.Parserer;
namespace tbfDBBackup.Tests.compare_dumps.Parserer;
[TestClass]
[TestSubject(typeof(SqlDumpFileParser))]
public class SqlDumpFileParserTest
{
string GetProjectRoot() {
string dir = AppContext.BaseDirectory;
while (dir != null && !Directory.GetFiles(dir, "*.csproj").Any()) {
dir = Directory.GetParent(dir)?.FullName;
}
return dir ?? throw new Exception("Project root not found.");
}
[TestMethod]
public void SqlDumpParserFile()
{
string basePath = GetProjectRoot();
string sql = Path.Combine(basePath,"Resources/old.sql");
ValidateSqlDumpParserResults(sql);
}
[TestMethod]
public void SqlDumpParserFile2()
{
string basePath = GetProjectRoot();
string sql = Path.Combine(basePath,"Resources/new.sql");
ValidateSqlDumpParserResults(sql);
}
[TestMethod]
public void SqlDumpParserFileR()
{
string basePath = GetProjectRoot();
string sql = Path.Combine(basePath,"Resources/old-r.sql");
ValidateSqlDumpParserResults(sql);
}
[TestMethod]
public void SqlDumpParserFileR2()
{
string basePath = GetProjectRoot();
string sql = Path.Combine(basePath,"Resources/new-r.sql");
ValidateSqlDumpParserResults(sql);
}
private static void ValidateSqlDumpParserResults(string sql)
{
SqlDumpFileParser parser = new();
parser.SqlDumpParserFile(sql);
Assert.IsTrue(parser.TableDefinitions.Count > 1);
foreach (var table in parser.TableDefinitions)
{
Console.WriteLine(table.Key);
Assert.IsTrue(table.Value.Substring(0, Math.Min(50, table.Value.Length)).Contains("CREATE"));
}
Assert.IsTrue(parser.TableInserts.Count > 1);
foreach (var table in parser.TableInserts)
{
Console.WriteLine(table.Key);
foreach (var row in table.Value)
{
Assert.IsTrue(row.Substring(0, Math.Min(20, row.Length-1)).Contains("INSERT INTO"));
string restString = row.Substring(20);
if (restString.Contains("INSERT INTO"))
{
Assert.Fail($"Insert contains insert more than once, see: {row}");
}
string lastCharacters = row.Length >= 5 ? row.Substring(row.Length - 5) : "";
Assert.IsTrue(lastCharacters.Contains(';'));
}
}
Assert.IsTrue(parser.TableForeignKeys.Count > 1);
foreach (var table in parser.TableForeignKeys)
{
Console.WriteLine(table.Key);
foreach (var row in table.Value)
{
//check if it contains alter table
Assert.IsTrue(row.Substring(0, Math.Min(20, row.Length-1)).Contains("ALTER TABLE"));
//check rest of string for alter table - non valid sql
string restString = row.Substring(20);
if (restString.Contains("ALTER TABLE"))
{
Assert.Fail($"Alter contains insert more than once, see: {row}");
}
//check if it ends with ;
string lastCharacters = row.Length >= 5 ? row.Substring(row.Length - 5) : "";
Assert.IsTrue(lastCharacters.Contains(';'));
}
}
}
}

View File

@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using tbfDBBackup.compare_dumps;
using tbfDBBackup.compare_dumps.Parserer;
namespace tbfDBBackup.Tests.compare_dumps;
[TestClass]
[TestSubject(typeof(SqlDumpParser))]
public class SqlDumpParserTest
{
[TestMethod]
public void ParseInsertBlock()
{
string sqlDump = "INSERT INTO `componentprocedure` (`Id`, `CmpntName`, `Parameters`, `Procedure_id`) " +
"VALUES\n(1, 'WM1', '<?xml version=\"1.0\" encoding=\"utf-16\"?>\\r\\n<ProcParams xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\\r\\n " +
"<ProductName />\\r\\n <Producer />\\r\\n <DN>0</DN>\\r\\n <L>0</L>\\r\\n <Mounting>NotSpecified</Mounting>\\r\\n <Qmax>4</Qmax>\\r\\n <Qn>2.5</Qn>\\r\\n <Qt>0.005</Qt>\\r\\n <Qmin>0.003125</Qmin>\\r\\n <MetrologicalClass>A</MetrologicalClass>\\r\\n <TemperatureClass>NotSpecified</TemperatureClass>\\r\\n <PressureLossClass>NotSpecified</PressureLossClass>\\r\\n <MaxAdmissiblePressure>NotSpecified</MaxAdmissiblePressure>\\r\\n <FlowProfileSensitivityClass>NotSpecified</FlowProfileSensitivityClass>\\r\\n <ApprovalInfo />\\r\\n <Certificate />\\r\\n <PulsesPerLtr>1</PulsesPerLtr>\\r\\n <Text1 />\\r\\n <Text2 />\\r\\n <Text3 />\\r\\n <Text4 />\\r\\n <Text5 />\\r\\n <WaterTemp>ColdWater</WaterTemp>\\r\\n</ProcParams>', 1),\n(2, 'WM2', '<?xml version=\"1.0\" encoding=\"utf-16\"?>\\r\\n<ProcParams xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\\r\\n <ProductName />\\r\\n <Producer />\\r\\n <DN>0</DN>\\r\\n <L>0</L>\\r\\n <Mounting>NotSpecified</Mounting>\\r\\n <Qmax>4</Qmax>\\r\\n <Qn>2.5</Qn>\\r\\n <Qt>0.005</Qt>\\r\\n <Qmin>0.003125</Qmin>\\r\\n <MetrologicalClass>A</MetrologicalClass>\\r\\n <TemperatureClass>NotSpecified</TemperatureClass>\\r\\n <PressureLossClass>NotSpecified</PressureLossClass>\\r\\n <MaxAdmissiblePressure>NotSpecified</MaxAdmissiblePressure>\\r\\n <FlowProfileSensitivityClass>NotSpecified</FlowProfileSensitivityClass>\\r\\n " +
"<ApprovalInfo />\\r\\n <Certificate />\\r\\n <PulsesPerLtr>1</PulsesPerLtr>\\r\\n <Text1 />\\r\\n <Text2 />\\r\\n <Text3 />\\r\\n <Text4 />\\r\\n <Text5 />\\r\\n " +
"<WaterTemp>ColdWater</WaterTemp>\\r\\n</ProcParams>', 1);";
Dictionary<int, Dictionary<string, string>> dictionary = SqlDumpParser.ParseInsertBlock(sqlDump);
Assert.AreEqual(2, dictionary.Count);
}
string GetProjectRoot() {
string dir = AppContext.BaseDirectory;
while (dir != null && !Directory.GetFiles(dir, "*.csproj").Any()) {
dir = Directory.GetParent(dir)?.FullName;
}
return dir ?? throw new Exception("Project root not found.");
}
[TestMethod]
public void ParseInsertBlock_File()
{
string projectRoot = GetProjectRoot();
string sql = File.ReadAllText( Path.Combine(projectRoot, "Resources","test_Block.sql"));
var parsed = SqlDumpParser.ParseInsertBlock(sql);
foreach (var kvp in parsed)
{
Console.WriteLine($"ID {kvp.Key}:");
//Get first 50 chars for all colums
foreach (var col in kvp.Value)
Console.WriteLine($" {col.Key} = {col.Value.Substring(0, Math.Min(80, col.Value.Length))}...");
}
}
[TestMethod]
public void ParseForeignKeys()
{
string alter = "ALTER TABLE `componentprocedure`\n ADD CONSTRAINT `FKF52C29EE1EC52E2B` FOREIGN KEY (`Procedure_id`) REFERENCES `procedure` (`Id`);";
Dictionary<string, List<ForeignKeyDef>> foreignKeys = SqlDumpParser.ParseForeignKeys(alter);
Assert.AreEqual(1, foreignKeys.Count);
Assert.AreEqual(1, foreignKeys.First().Value.Count);
Assert.AreEqual("componentprocedure", foreignKeys.First().Key);
Assert.AreEqual("FKF52C29EE1EC52E2B", foreignKeys.First().Value.First().Name);
Assert.AreEqual("Procedure_id", foreignKeys.First().Value.First().Column);
Assert.AreEqual("procedure", foreignKeys.First().Value.First().RefTable);
Assert.AreEqual("Id", foreignKeys.First().Value.First().RefColumn);
}
}

View File

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using JetBrains.Annotations;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using tbfDBBackup.compare_dumps.joinValues;
using tbfDBBackup.configuration;
namespace tbfDBBackup.Tests.compare_dumps.joinValues;
[TestClass]
[TestSubject(typeof(Joiner))]
public class JoinerTest
{
string GetProjectRoot() {
string dir = AppContext.BaseDirectory;
while (dir != null && !Directory.GetFiles(dir, "*.csproj").Any()) {
dir = Directory.GetParent(dir)?.FullName;
}
return dir ?? throw new Exception("Project root not found.");
}
[TestMethod]
public void SchemaJoiner()
{
// Arrange - project test
string projectRoot = GetProjectRoot();
//Configure test database
Configuration dbConfiguration = new Configuration();
dbConfiguration.DbConnectionStrings = new List<DbConnection>();
dbConfiguration.DbConnectionStrings.Add(new DbConnection()
{
Connection = "SERVER=localhost; DATABASE={DatabaseName}; UID=root; PASSWORD=; CHARSET=utf8;",
DatabaseName = "testdbupdate",
Enabled = true,
IsOneTimeOpaque = true,
Name = "test",
});
dbConfiguration.UpgradeDatabase = new List<Upgrade>();
dbConfiguration.UpgradeDatabase.Add(new Upgrade()
{
DatabaseName = "testdbupdate",
Enabled = true,
Name = "test upgrade",
JSONFileName = "",
Query = "",
IsOneTimeOpaque = true
});
Joiner joiner = new Joiner(
dbConfiguration,
projectRoot,
"Resources/old.sql",
"Resources/schema-mapping.json");
joiner.SchemaJoiner();
Assert.IsTrue(joiner.IsJoindedSuccesfully);
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2025.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.10.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.10.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\tbfDBBackup\tbfDBBackup.csproj" />
</ItemGroup>
</Project>

View File

@ -2,6 +2,8 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tbfDBBackup", "tbfDBBackup\tbfDBBackup.csproj", "{9F4F004F-8E31-42B3-BE6D-EA9453EADC7F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tbfDBBackup.Tests", "tbfDBBackup.Tests\tbfDBBackup.Tests.csproj", "{0D1C3FA3-7971-4710-9DDC-E498EC635989}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -12,5 +14,9 @@ Global
{9F4F004F-8E31-42B3-BE6D-EA9453EADC7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F4F004F-8E31-42B3-BE6D-EA9453EADC7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F4F004F-8E31-42B3-BE6D-EA9453EADC7F}.Release|Any CPU.Build.0 = Release|Any CPU
{0D1C3FA3-7971-4710-9DDC-E498EC635989}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D1C3FA3-7971-4710-9DDC-E498EC635989}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D1C3FA3-7971-4710-9DDC-E498EC635989}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D1C3FA3-7971-4710-9DDC-E498EC635989}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -24,6 +24,10 @@ public class Configuration
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<Backup>? BackupDB { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public List<Upgrade>? UpgradeDatabase { get; set; }
public static Configuration DeserializeFromJson(string jsonString)

View File

@ -1,281 +1,485 @@
// See https://aka.ms/new-console-template for more information
using System.Diagnostics;
using System.Text.Json;
using System.Text.RegularExpressions;
using MySqlConnector;
using tbfDBBackup;
using tbfDBBackup.compare_dumps;
using tbfDBBackup.compare_dumps.joinValues;
using tbfDBBackup.compare_dumps.mapping;
using tbfDBBackup.configuration;
namespace tbfDBBackup;
Console.WriteLine("---- TBF DB Backup process started -----");
//Read configuration
Configuration? configuration = GetConfiguration();
if (configuration == null)
public class Program
{
Console.WriteLine("**** Configuration no found!! ***");
return -1;
}
private static string ProgramName = Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]);
private static string defaultSchemaFimeName = "schema-mapping.json";
bool storeConfigPotentialChanges = configuration.HasPotentialModification();
public static void Main(string[] args)
{
// Entry point with args support
if (args.Length > 0)
{
string command = args[0].ToLowerInvariant();
switch (command)
{
case "compare":
RunSchemaComparison(args);
return;
case "test-schema-mapping":
RunTestSchemaMapping(args.Length > 1 ? args[1] : "");
return;
case "update-by-schema":
RunUpdateBySchemaMapping(args);
return;
case "help":
PrintHelp();
return;
default:
Console.WriteLine($"Unknown command: {command}");
PrintHelp();
return;
}
}
Console.WriteLine("---- TBF DB Backup process started -----");
//Read configuration
Configuration? configuration = GetConfiguration();
if (configuration == null)
{
Console.WriteLine("**** Configuration no found!! ***");
throw new Exception("Configuration no found!!");
}
bool storeConfigPotentialChanges = configuration.HasPotentialModification();
//update part
if (configuration.UpdateString != null)
{
try
{
UpdateDb(configuration);
}
catch (Exception e)
{
Console.WriteLine("------ MySql Data uprade FAILED!! *** -----");
Console.WriteLine(e);
}
}
if (configuration.UpdateString != null)
{
try
{
UpdateDb(configuration);
}
catch (Exception e)
{
Console.WriteLine("------ MySql Data uprade FAILED!! *** -----");
Console.WriteLine(e);
}
}
//database backup part
List<BackupCombination> backupCombinations = configuration.GetBackupCombinations();
foreach (BackupCombination combination in backupCombinations)
{
try
{
BackupDatabase(combination);
}
catch (Exception e)
{
Console.WriteLine($"------ MySql backup of database: {combination.DatabaseName} FAILED!! *** -----");
Console.WriteLine(e);
}
}
List<BackupCombination> backupCombinations = configuration.GetBackupCombinations();
foreach (BackupCombination combination in backupCombinations)
{
try
{
BackupDatabase(combination);
}
catch (Exception e)
{
Console.WriteLine($"------ MySql backup of database: {combination.DatabaseName} FAILED!! *** -----");
Console.WriteLine(e);
}
}
//Update one time config
//Upgrade one time config
if (configuration.UpgradeDatabase != null)
{
try
{
UpgradeDb(configuration);
}
catch (Exception e)
{
Console.WriteLine("------ MySql Data upgrade FAILED!! *** -----");
Console.WriteLine(e);
}
}
//store configuration
if (storeConfigPotentialChanges)
{
SaveConfiguration(configuration);
}
if (storeConfigPotentialChanges)
{
SaveConfiguration(configuration);
}
//final info
Console.WriteLine("Program finished correctly!!");
Console.WriteLine("Program finished correctly!!");
//wait to end
if (configuration != null && (configuration.WaitOnEndCmdOpen ?? false))
{
Console.ReadLine();
}
//program END
return 0;
//////////////////////////////////////////////////////////////////////////////
Configuration? GetConfiguration()
{
try
{
Console.WriteLine($"---- program started path: {Environment.CurrentDirectory}");
string fileNamePath = ConfigurationFileNamePath();
Console.WriteLine($"- full config file path: {fileNamePath}");
string jsonConfiguration = "";
using (StreamReader reader = new StreamReader(fileNamePath))
if (configuration != null && (configuration.WaitOnEndCmdOpen ?? false))
{
jsonConfiguration = reader.ReadToEnd();
Console.ReadLine();
}
}
//////////////////////////////////////////////////////////////////////////////
private static void UpgradeDb(Configuration configuration)
{
throw new NotImplementedException();
}
Configuration? configurationDeserialized = Configuration.DeserializeFromJson(jsonConfiguration);
if (configurationDeserialized != null && (configurationDeserialized.PrintConfigurationEnabled ?? false))
//////////////////////////////////////////////////////////////////////////////
static Configuration? GetConfiguration()
{
try
{
configurationDeserialized.PrintConfiguration();
}
Console.WriteLine($"---- program started path: {Environment.CurrentDirectory}");
string fileNamePath = ConfigurationFileNamePath();
Console.WriteLine($"- full config file path: {fileNamePath}");
return configurationDeserialized;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
void SaveConfiguration(Configuration configuration)
{
try
{
// Serialize the configuration back to JSON
string jsonString = configuration.SerializeToJson();
string fileNamePath = ConfigurationFileNamePath();
Console.WriteLine($"- full config file path: {fileNamePath}");
// Write the JSON string to the file
using (StreamWriter writer = new StreamWriter(fileNamePath))
{
writer.Write(jsonString);
}
Console.WriteLine("Configuration saved successfully.");
}
catch (Exception e)
{
Console.WriteLine($"Error saving configuration: {e}");
throw;
}
}
void BackupDatabase(BackupCombination backupCombination)
{
Console.WriteLine($"------ MySql backup of database: {backupCombination.DatabaseName} started -----");
DateTime currentTime = DateTime.Now; // Get current date and time
// Format the date and time as yyyyMMdd_HHmmss (e.g., 20241015_142530)
string time = currentTime.ToString("yyyyMMdd_HHmmss");
// Create the file name by appending the formatted time to the database name
string fileName = backupCombination.DatabaseName.Trim()
.Replace('\\', '_')
.Replace(' ', '_')
.ToLower() + "_backup_" + time + ".sql";
string filePathName = Path.Combine(backupCombination.BackupFilePath, fileName);
// Set up the mysqldump command
string dumpCommand =
$"mysqldump --user={backupCombination.UserName} --password={backupCombination.Password} --host={backupCombination.ServerName} {backupCombination.DatabaseName} --result-file=\"{filePathName}\" --routines --events";
// Check if the directory exists, and create it if not
if (!Directory.Exists(backupCombination.BackupFilePath))
{
Directory.CreateDirectory(backupCombination.BackupFilePath);
}
// Execute the mysqldump command
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
Process process = new Process
{
StartInfo = processInfo
};
process.Start();
using (var writer = process.StandardInput)
{
if (writer.BaseStream.CanWrite)
{
if (backupCombination.CommandPath.Length == 0)
string jsonConfiguration = "";
using (StreamReader reader = new StreamReader(fileNamePath))
{
writer.WriteLine(dumpCommand);
}
else
{
// Split the dumpCommand into the executable and the arguments
string[]
parts = dumpCommand.Split(' ', 2); // Split into two parts: the command and the rest (arguments)
// Combine the commandPath with the executable (first part of dumpCommand)
string fullCommand = Path.Combine(backupCombination.CommandPath, parts[0]) + " " + parts[1];
// Execute the command with the full path
writer.WriteLine(fullCommand);
}
}
}
process.WaitForExit();
string result = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(error))
{
Console.WriteLine($"Error: {error}");
}
else
{
Console.WriteLine($"Backup created successfully at {filePathName}");
}
process.Close();
//Deactivate if only one time possible run
if ((backupCombination.Path.IsOneTimeOpaque ?? false) && (backupCombination.Path.Enabled ?? true))
{
backupCombination.Path.Enabled = false;
}
}
void UpdateDb(Configuration dbConfiguration)
{
if (dbConfiguration.DbConnectionStrings != null)
foreach (DbConnection dbConnection in dbConfiguration.DbConnectionStrings)
{
if (!(dbConnection.Enabled ?? true))
{
continue;
jsonConfiguration = reader.ReadToEnd();
}
if (dbConfiguration.UpdateString != null)
foreach (Update update in dbConfiguration.UpdateString)
Configuration? configurationDeserialized = Configuration.DeserializeFromJson(jsonConfiguration);
if (configurationDeserialized != null && (configurationDeserialized.PrintConfigurationEnabled ?? false))
{
configurationDeserialized.PrintConfiguration();
}
return configurationDeserialized;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
static void SaveConfiguration(Configuration configuration)
{
try
{
// Serialize the configuration back to JSON
string jsonString = configuration.SerializeToJson();
string fileNamePath = ConfigurationFileNamePath();
Console.WriteLine($"- full config file path: {fileNamePath}");
// Write the JSON string to the file
using (StreamWriter writer = new StreamWriter(fileNamePath))
{
writer.Write(jsonString);
}
Console.WriteLine("Configuration saved successfully.");
}
catch (Exception e)
{
Console.WriteLine($"Error saving configuration: {e}");
throw;
}
}
static void BackupDatabase(BackupCombination backupCombination)
{
Console.WriteLine($"------ MySql backup of database: {backupCombination.DatabaseName} started -----");
DateTime currentTime = DateTime.Now; // Get current date and time
// Format the date and time as yyyyMMdd_HHmmss (e.g., 20241015_142530)
string time = currentTime.ToString("yyyyMMdd_HHmmss");
// Create the file name by appending the formatted time to the database name
string fileName = backupCombination.DatabaseName.Trim()
.Replace('\\', '_')
.Replace(' ', '_')
.ToLower() + "_backup_" + time + ".sql";
string filePathName = Path.Combine(backupCombination.BackupFilePath, fileName);
// Set up the mysqldump command
string dumpCommand =
$"mysqldump --user={backupCombination.UserName} --password={backupCombination.Password} --host={backupCombination.ServerName} {backupCombination.DatabaseName} --result-file=\"{filePathName}\" --routines --events";
// Check if the directory exists, and create it if not
if (!Directory.Exists(backupCombination.BackupFilePath))
{
Directory.CreateDirectory(backupCombination.BackupFilePath);
}
// Execute the mysqldump command
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
Process process = new Process
{
StartInfo = processInfo
};
process.Start();
using (var writer = process.StandardInput)
{
if (writer.BaseStream.CanWrite)
{
if (backupCombination.CommandPath.Length == 0)
{
if (!(update.Enabled ?? true) || dbConnection.DatabaseName != update.DatabaseName)
writer.WriteLine(dumpCommand);
}
else
{
// Split the dumpCommand into the executable and the arguments
string[]
parts = dumpCommand.Split(' ', 2); // Split into two parts: the command and the rest (arguments)
// Combine the commandPath with the executable (first part of dumpCommand)
string fullCommand = Path.Combine(backupCombination.CommandPath, parts[0]) + " " + parts[1];
// Execute the command with the full path
writer.WriteLine(fullCommand);
}
}
}
process.WaitForExit();
string result = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(error))
{
Console.WriteLine($"Error: {error}");
}
else
{
Console.WriteLine($"Backup created successfully at {filePathName}");
}
process.Close();
//Deactivate if only one time possible run
if ((backupCombination.Path.IsOneTimeOpaque ?? false) && (backupCombination.Path.Enabled ?? true))
{
backupCombination.Path.Enabled = false;
}
}
static void UpdateDb(Configuration dbConfiguration)
{
if (dbConfiguration.DbConnectionStrings != null)
foreach (DbConnection dbConnection in dbConfiguration.DbConnectionStrings)
{
if (!(dbConnection.Enabled ?? true))
{
continue;
}
if (dbConfiguration.UpdateString != null)
foreach (Update update in dbConfiguration.UpdateString)
{
continue;
}
try
{
Console.WriteLine($"------ MySql Data upgrade name: {update.Name} starting -----");
string connectionString =
dbConnection.Connection.Replace("{DatabaseName}", dbConnection.DatabaseName);
MySqlConnection connection = new MySqlConnection(connectionString);
connection.Open();
MySqlCommand command =
new MySqlCommand(update.Query.Replace("{DatabaseName}", update.DatabaseName), connection);
int affectedItems = command.ExecuteNonQuery();
Console.WriteLine($"Affected items: {affectedItems}");
connection.Close();
if (update.IsOneTimeOpaque ?? false)
if (!(update.Enabled ?? true) || dbConnection.DatabaseName != update.DatabaseName)
{
update.Enabled = false;
continue;
}
Console.WriteLine($"------ MySql Data upgrade name: {update.Name} finished! -----");
}
catch (Exception e)
{
Console.WriteLine($"------ MySql Data upgrade name: {update.Name} ERROR!");
Console.WriteLine(e);
}
}
}
}
try
{
Console.WriteLine($"------ MySql Data upgrade name: {update.Name} starting -----");
string connectionString =
dbConnection.Connection.Replace("{DatabaseName}", dbConnection.DatabaseName);
MySqlConnection connection = new MySqlConnection(connectionString);
connection.Open();
string ConfigurationFileNamePath()
MySqlCommand command =
new MySqlCommand(update.Query.Replace("{DatabaseName}", update.DatabaseName),
connection);
int affectedItems = command.ExecuteNonQuery();
Console.WriteLine($"Affected items: {affectedItems}");
connection.Close();
if (update.IsOneTimeOpaque ?? false)
{
update.Enabled = false;
}
Console.WriteLine($"------ MySql Data upgrade name: {update.Name} finished! -----");
}
catch (Exception e)
{
Console.WriteLine($"------ MySql Data upgrade name: {update.Name} ERROR!");
Console.WriteLine(e);
}
}
}
}
static string GetProjectPath()
{
string fileNamePath;
string currentDir;
#if DEBUG
Console.WriteLine("-- DEV version of THE PROJECT -- ");
string projectPath = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;
fileNamePath = Path.Combine(projectPath, Configuration.ConfigDir, Configuration.FileName);
currentDir = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;
#else
// For release mode, use an absolute path or the application base directory
Console.WriteLine("-- PROD version of THE PROJECT -- ");
fileNamePath = Path.Combine(Environment.CurrentDirectory, Configuration.ConfigDir, Configuration.FileName);
// For release mode, use an absolute path or the application base directory
Console.WriteLine("-- PROD version of THE PROJECT -- ");
currentDir = Environment.CurrentDirectory;
#endif
return fileNamePath;
return currentDir;
}
static string ConfigurationFileNamePath()
{
string projectPath = GetProjectPath();
return Path.Combine(projectPath, Configuration.ConfigDir, Configuration.FileName);
}
// ==================== SUPPORTING METHODS ====================
static void RunSchemaComparison(string[] args)
{
if (args.Length < 3)
{
Console.WriteLine($"Usage: {ProgramName} compare <old_dump.sql> <new_dump.sql>");
return;
}
string oldPath = args[1];
string newPath = args[2];
if (!File.Exists(oldPath) || !File.Exists(newPath))
{
Console.WriteLine($"Old file path not found: {Path.GetFullPath(oldPath)}");
Console.WriteLine($"New file path not found: {Path.GetFullPath(newPath)}");
Console.WriteLine("Error: One or both dump files not found.");
return;
}
Console.WriteLine($"Comparing: {Path.GetFileName(oldPath)} vs {Path.GetFileName(newPath)}");
var oldSchema = SqlDumpSchemaParser.Parse(oldPath);
var newSchema = SqlDumpSchemaParser.Parse(newPath);
SchemaMapping compareSchemas = SqlDumpSchemaParser.Compare(oldSchema, newSchema);
SchemaMapping compareSchemas2 = SqlDumpSchemaParser.CompareSchemas(oldSchema, newSchema);
var json = JsonSerializer.Serialize(compareSchemas2, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText("schema-mapping.json", json);
}
static void RunTestSchemaMapping(string schemaFimeName = "")
{
if (schemaFimeName.Length == 0)
{
schemaFimeName = defaultSchemaFimeName;
}
if (!File.Exists(schemaFimeName))
{
Console.WriteLine($"Schema file not found: {Path.GetFullPath(schemaFimeName)}");
return;
}
var editedMapping = JsonSerializer.Deserialize<SchemaMapping>(File.ReadAllText("schema-mapping.json"));
foreach (var table in editedMapping.Tables)
{
foreach (var mapping in table.ColumnMappings)
{
if (mapping.Status == "uncertain" && string.IsNullOrEmpty(mapping.NewColumn))
{
Console.WriteLine($"⚠️ Column {mapping.OldColumn} in table {table.TableName} is still not mapped.");
}
// You can also check: does NewColumn exist in the new schema?
}
}
}
private static void RunUpdateBySchemaMapping(string[] args)
{
if (args.Length < 3)
{
Console.WriteLine($"Usage: {ProgramName} update-by-schema <old_dump.sql> <schema-mapping.json>");
return;
}
string basePath = Path.Combine(GetProjectPath(), "joinConfig");
Configuration? configuration = GetConfiguration();
if (configuration == null)
{
throw new Exception($"Configuration no found on path: {basePath} !!");
}
Joiner joiner = new Joiner(
configuration,
basePath,
args[1],
args[2]);
joiner.TestInputsAndFiles();
joiner.SchemaJoiner();
Console.WriteLine(joiner.IsJoindedSuccesfully? "Upgrade successful!" : "Upgrade failed!");
}
static void PrintHelp()
{
Console.WriteLine("Usage:");
Console.WriteLine($" {ProgramName} \n --> Run default backup/update process using configuration.");
Console.WriteLine($" {ProgramName} compare <old.sql> <new.sql> \n --> Compare two SQL dump files.");
Console.WriteLine($" {ProgramName} test-schema-mapping <*?.json> \n --> Test undefined schema mapping file.");
Console.WriteLine($" {ProgramName} update-by-schema <old.sql> <*?.json> \n --> Update by schema mapping and dump files.");
Console.WriteLine($" {ProgramName} help \n --> Show help information.");
}
static string? TransformInsert(string line, SchemaMapping mapping)
{
// Match INSERT INTO `table` (`col1`, `col2`) VALUES ...
var regex = new Regex(@"INSERT INTO\s+`?(\w+)`?\s*\(([^)]+)\)\s*VALUES\s*(.+);", RegexOptions.IgnoreCase);
var match = regex.Match(line);
if (!match.Success)
return null;
string oldTableName = match.Groups[1].Value;
string[] oldColumns = match.Groups[2].Value.Split(',').Select(c => c.Trim(' ', '`')).ToArray();
string values = match.Groups[3].Value;
var table = mapping.Tables.FirstOrDefault(t => t.TableName.Equals(oldTableName, StringComparison.OrdinalIgnoreCase));
if (table == null)
{
Console.WriteLine($"[WARNING] Table not found in mapping: {oldTableName}");
return null;
}
var columnMap = new Dictionary<string, string>();
foreach (var col in oldColumns)
{
var map = table.ColumnMappings.FirstOrDefault(c => c.OldColumn == col && c.Status != "Deleted");
if (map != null && map.NewColumn != null)
columnMap[col] = map.NewColumn;
else
Console.WriteLine($"[INFO] Skipping column '{col}' (no mapping found or deleted)");
}
var newColumns = oldColumns.Where(c => columnMap.ContainsKey(c)).Select(c => $"`{columnMap[c]}`");
var insert = $"INSERT INTO `{table.TableName}` ({string.Join(", ", newColumns)}) VALUES {values};";
return insert;
}
}

55
tbfDBBackup/ReadMe.md Normal file
View File

@ -0,0 +1,55 @@
# Program tbfDBBackup
Program is designed to backup, upgrade, compare and restore database.
Only for advanced users!
* Program is written in C# and .NET 8.0.
* Program is using MySql.Data.MySqlClient.
* Program using mysqldump.exe in some cases.
* Program is designed for Windows.
* Program is designed to use with MySQL.
## Program features
* Backup database.
* Upgrade database.
* Compare database.
* Restore database.
### Backup database.
We can use this program to define a backup procedure. Can work like a cron job, or services to run backup procedure.
### Upgrade database.
We can use this program to define an upgrade procedure. Can work cyclic or one time per run.
# Description about program parameters
The program operates as a command-line driver, accepting parameters to control its behavior.
## Configuration
When using a configuration file, the program can function autonomously, execute a single-use procedure, or encapsulate the operation as an opaque process.
## Dirrect commnad-line
### List of cmd commands
## Cmd Help
### Connect to database via cmd
```aiignore
mysql -h 127.0.0.1 -P 3306 -u root
```
Under database, we can create our own schema or use standard SQL syntax. For example:
```aiignore
"CREATE DATABASE slm-end;"
```
### Reload dump to new schema
```aiignore
PS C:\xampp\mysql\bin> Get-Content "C:\Users\micha\git\sensus\tbfDBBackup\tbfDBBackup\bin\Debug\net8.0\old.sql" |
>> .\mysql.exe -h 127.0.0.1 -P 3306 -u root --one-database slm-end
```
```aiignore
PS C:\xampp\mysql\bin> Get-Content "C:\Users\micha\git\sensus\tbfDBBackup\tbfDBBackup\bin\Debug\net8.0\old-r.sql" |
>> .\mysql.exe -h 127.0.0.1 -P 3306 -u root --one-database slm-end-r
```

View File

@ -0,0 +1,12 @@
namespace tbfDBBackup.compare_dumps;
public class ColumnDef
{
public string Name { get; set; }
public string Type { get; set; }
public string Nullable { get; set; }
public bool IsPrimaryKey { get; set; }
public override string ToString() => $"{Name} {Type} {(Nullable == "NO" ? "NOT NULL" : "NULL")}";
}

View File

@ -0,0 +1,12 @@
namespace tbfDBBackup.compare_dumps.Parserer;
public class ForeignKeyDef
{
public string Name { get; set; } = "";
public string Column { get; set; } = "";
public string RefTable { get; set; } = "";
public string RefColumn { get; set; } = "";
public override string ToString() =>
$"{Name}: {Column} -> {RefTable}.{RefColumn}";
}

View File

@ -0,0 +1,122 @@
using System.Text;
using System.Text.RegularExpressions;
namespace tbfDBBackup.compare_dumps.Parserer;
public class SqlDumpFileParser
{
public Dictionary<string, string> TableDefinitions { get;set; }
public Dictionary<string, List<string>> TableInserts { get;set; }
public Dictionary<string, List<string>> TableForeignKeys { get; private set; } = new();
public void SqlDumpParserFile(string filePath)
{
TableDefinitions = new Dictionary<string, string>();
TableInserts = new Dictionary<string, List<string>>();
TableForeignKeys = new Dictionary<string, List<string>>();
SqlSection currentSection = SqlSection.None;
StringBuilder blockBuilder = new StringBuilder();
string currentTable = null;
foreach (var line in File.ReadLines(filePath))
{
// Normalize line
var trimmed = line.Trim();
if (trimmed.StartsWith("CREATE TABLE", StringComparison.OrdinalIgnoreCase))
{
currentSection = SqlSection.CreateTable;
blockBuilder.Clear();
blockBuilder.AppendLine(line);
// Extract table name
var match = Regex.Match(trimmed, @"CREATE TABLE(?: IF NOT EXISTS)? `(\w+)`", RegexOptions.IgnoreCase);
if (match.Success)
currentTable = match.Groups[1].Value;
continue;
}
if (trimmed.StartsWith("INSERT INTO", StringComparison.OrdinalIgnoreCase))
{
currentSection = SqlSection.InsertInto;
blockBuilder.Clear();
blockBuilder.AppendLine(line);
var match = Regex.Match(trimmed, @"INSERT INTO `(\w+)`", RegexOptions.IgnoreCase);
if (match.Success)
currentTable = match.Groups[1].Value;
continue;
}
// --- ALTER TABLE (foreign keys, constraints, etc.) ---
if (trimmed.StartsWith("ALTER TABLE", StringComparison.OrdinalIgnoreCase))
{
currentSection = SqlSection.AlterTable;
blockBuilder.Clear();
blockBuilder.AppendLine(line);
var match = Regex.Match(trimmed, @"ALTER TABLE `(\w+)`", RegexOptions.IgnoreCase);
if (match.Success)
currentTable = match.Groups[1].Value;
continue;
}
// ------------------------
// Accumulate CREATE TABLE
// ------------------------
if (currentSection == SqlSection.CreateTable)
{
blockBuilder.AppendLine(line);
if (trimmed.EndsWith(";"))
{
// Save table schema
if (currentTable != null)
TableDefinitions[currentTable] = blockBuilder.ToString();
currentSection = SqlSection.None;
}
}
// ------------------------
// Accumulate INSERT INTO
// ------------------------
else if (currentSection == SqlSection.InsertInto)
{
blockBuilder.AppendLine(line);
if (trimmed.EndsWith(";"))
{
// Save INSERT block
if (currentTable != null)
{
if (!TableInserts.ContainsKey(currentTable))
TableInserts[currentTable] = new List<string>();
TableInserts[currentTable].Add(blockBuilder.ToString());
}
currentSection = SqlSection.None;
}
}
// ------------------------
// Accumulate ALTER TABLE
// ------------------------
else if (currentSection == SqlSection.AlterTable)
{
blockBuilder.AppendLine(line);
if (trimmed.EndsWith(";"))
{
if (currentTable != null)
{
if (!TableForeignKeys.ContainsKey(currentTable))
TableForeignKeys[currentTable] = new List<string>();
TableForeignKeys[currentTable].Add(blockBuilder.ToString());
}
currentSection = SqlSection.None;
}
}
}
}
}

View File

@ -0,0 +1,150 @@

using System.Text;
using System.Text.RegularExpressions;
using tbfDBBackup.compare_dumps.Parserer;
namespace tbfDBBackup.compare_dumps;
public class SqlDumpParser
{
public static Dictionary<int, Dictionary<string, string>> ParseInsertBlock(string sql)
{
var result = new Dictionary<int, Dictionary<string, string>>();
var fullInsertRegex = new Regex(
@"INSERT INTO\s+`(?<table>\w+)`\s*\((?<columns>[^)]+)\)\s*VALUES\s*(?<values>.+);",
RegexOptions.Singleline | RegexOptions.IgnoreCase);
var match = fullInsertRegex.Match(sql);
if (!match.Success)
throw new Exception("INSERT block not matched.");
var columns = match.Groups["columns"].Value
.Split(',')
.Select(c => c.Trim().Trim('`', ' '))
.ToArray();
var valuesBlock = match.Groups["values"].Value;
// Match each value row: (1, 'WM1', '...', 1)
var rowRegex = new Regex(@"\(([^()]*(?:\([^)]*\)[^()]*)*)\)", RegexOptions.Singleline);
var rowMatches = rowRegex.Matches(valuesBlock);
foreach (Match rowMatch in rowMatches)
{
var rawRow = rowMatch.Groups[1].Value;
var values = ParseCsvRow(rawRow);
if (values.Count != columns.Length)
throw new Exception("Mismatch in column count.");
var rowDict = new Dictionary<string, string>();
for (int i = 0; i < columns.Length; i++)
rowDict[columns[i]] = values[i];
int rowId = int.Parse(rowDict["Id"]);
result[rowId] = rowDict;
}
return result;
}
private static List<string> ParseCsvRow(string row)
{
var values = new List<string>();
var current = new StringBuilder();
bool inQuotes = false;
char quoteChar = '\'';
for (int i = 0; i < row.Length; i++)
{
char c = row[i];
if (inQuotes)
{
if (c == quoteChar)
{
if (i + 1 < row.Length && row[i + 1] == quoteChar)
{
current.Append(c); // Escaped quote
i++;
}
else
{
inQuotes = false; // End quote
}
}
else
{
current.Append(c);
}
}
else
{
if (c == '\'' || c == '"')
{
inQuotes = true;
quoteChar = c;
}
else if (c == ',')
{
values.Add(current.ToString().Trim());
current.Clear();
}
else
{
current.Append(c);
}
}
}
if (current.Length > 0)
values.Add(current.ToString().Trim());
return values;
}
// Regex for ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY ...
private static readonly Regex alterTableForeignKeyRegex = new Regex(
@"ALTER\s+TABLE\s+`(?<table>\w+)`\s+ADD\s+CONSTRAINT\s+`(?<constraint>\w+)`\s+FOREIGN\s+KEY\s*\(`(?<column>\w+)`\)\s+REFERENCES\s+`(?<refTable>\w+)`\s*\(`(?<refColumn>\w+)`\)",
RegexOptions.IgnoreCase);
public static Dictionary<string, List<ForeignKeyDef>> ParseForeignKeys(string line)
{
var tableForeignKeys = new Dictionary<string, List<ForeignKeyDef>>();
var trimmed = line.Trim();
if (string.IsNullOrEmpty(trimmed) || trimmed.StartsWith("--"))
return tableForeignKeys;
var match = alterTableForeignKeyRegex.Match(trimmed);
if (match.Success)
{
string table = match.Groups["table"].Value;
string constraint = match.Groups["constraint"].Value;
string column = match.Groups["column"].Value;
string refTable = match.Groups["refTable"].Value;
string refColumn = match.Groups["refColumn"].Value;
var fk = new ForeignKeyDef
{
Name = constraint,
Column = column,
RefTable = refTable,
RefColumn = refColumn
};
if (!tableForeignKeys.ContainsKey(table))
tableForeignKeys[table] = new List<ForeignKeyDef>();
tableForeignKeys[table].Add(fk);
}
return tableForeignKeys;
}
}

View File

@ -0,0 +1,9 @@
namespace tbfDBBackup.compare_dumps;
public enum SqlSection
{
None,
CreateTable,
InsertInto,
AlterTable
}

View File

@ -0,0 +1,286 @@
using System.Text.RegularExpressions;
using System.Text.Json;
using tbfDBBackup.compare_dumps.mapping;
namespace tbfDBBackup.compare_dumps;
public class SqlDumpSchemaParser
{
public static Dictionary<string, TableDef> Parse(string filePath)
{
var schema = new Dictionary<string, TableDef>();
var lines = File.ReadAllLines(filePath);
TableDef? currentTable = null;
bool inCreateTable = false;
var createTableRegex = new Regex(@"CREATE TABLE\s+(IF NOT EXISTS\s+)?`?(\w+)`?", RegexOptions.IgnoreCase);
var columnDefRegex = new Regex(@"^\s*`(\w+)`\s+([a-zA-Z0-9\(\)]+)(.*)", RegexOptions.IgnoreCase);
foreach (var rawLine in lines)
{
var line = rawLine.Trim();
if (string.IsNullOrEmpty(line) || line.StartsWith("--") || line.StartsWith("/*") || line.StartsWith("/*!"))
continue;
// Start of CREATE TABLE
if (line.StartsWith("CREATE TABLE", StringComparison.OrdinalIgnoreCase))
{
var match = createTableRegex.Match(line);
if (match.Success)
{
string tableName = match.Groups[2].Value;
currentTable = new TableDef { Name = tableName };
schema[tableName] = currentTable;
inCreateTable = true;
}
continue;
}
// End of table
if (inCreateTable && line.StartsWith(")"))
{
currentTable?.PairPrivateKeys();
currentTable = null;
inCreateTable = false;
continue;
}
if (inCreateTable && currentTable != null)
{
if (line.StartsWith("PRIMARY KEY"))
{
currentTable.privateKeys.AddRange(GetPrimayKeysFromString(line));
}
// Skip keys and constraints
if (line.StartsWith("PRIMARY KEY") || line.StartsWith("UNIQUE") ||
line.StartsWith("KEY") || line.StartsWith("CONSTRAINT") || line.StartsWith("INDEX"))
continue;
// Match a column line
var match = columnDefRegex.Match(line);
if (match.Success)
{
string columnName = match.Groups[1].Value;
string dataType = match.Groups[2].Value;
string rest = match.Groups[3].Value.ToUpperInvariant();
string nullable = rest.Contains("NOT NULL") ? "NO" : "YES";
currentTable.Columns.Add(new ColumnDef
{
Name = columnName,
Type = dataType,
Nullable = nullable,
IsPrimaryKey = false
});
}
}
}
return schema;
}
private static List<string> GetPrimayKeysFromString(string input)
{
List<string> keys = new List<string>();
// Regex: captures everything between parentheses, allows whitespace
string pattern = @"PRIMARY\s+KEY\s*\(\s*`([^`]+)`(?:\s*,\s*`([^`]+)`)*\s*\)";
Match match = Regex.Match(input, pattern, RegexOptions.IgnoreCase);
if (match.Success)
{
// First group is always the first PK column
keys.Add(match.Groups[1].Value);
// If multiple PKs, theyll be in Captures of Group 2
foreach (Capture c in match.Groups[2].Captures)
{
keys.Add(c.Value);
}
}
return keys;
}
public static SchemaMapping Compare(Dictionary<string, TableDef> oldSchema, Dictionary<string, TableDef> newSchema)
{
var result = new SchemaMapping();
var allTables = oldSchema.Keys.Union(newSchema.Keys);
foreach (var table in allTables)
{
Console.WriteLine($"\n=== Table: {table} ===");
var tableMapping = new TableMapping { TableName = table };
if (!oldSchema.ContainsKey(table))
{
Console.WriteLine(" Table added in new schema.");
TableMissingInSchema(newSchema, table, tableMapping, result, true);
result.Tables.Add(tableMapping);
continue;
}
if (!newSchema.ContainsKey(table))
{
Console.WriteLine(" Table removed in new schema.");
TableMissingInSchema(oldSchema, table, tableMapping, result, false);
continue;
}
var oldCols = oldSchema[table].Columns.ToDictionary(c => c.Name);
var newCols = newSchema[table].Columns.ToDictionary(c => c.Name);
foreach (var col in oldCols.Keys.Except(newCols.Keys))
{
Console.WriteLine($" Column removed: {col}");
tableMapping.ColumnMappings.Add(new ColumnMapping
{
NewColumn = col,
Status = "missing",
Note = "Table not found in old schema"
});
}
foreach (var col in newCols.Keys.Except(oldCols.Keys))
{
Console.WriteLine($" Column added: {col}");
tableMapping.ColumnMappings.Add(new ColumnMapping
{
OldColumn = col,
Status = "missing",
Note = "Table not found in old schema",
ColumnDef = newCols[col]
});
}
foreach (var col in oldCols.Keys.Intersect(newCols.Keys))
{
var o = oldCols[col];
var n = newCols[col];
if (o.Type != n.Type || o.Nullable != n.Nullable)
{
Console.WriteLine($" Column changed: {col}");
Console.WriteLine($" Old: {o}");
Console.WriteLine($" New: {n}");
tableMapping.ColumnMappings.Add(new ColumnMapping
{
OldColumn = col,
Status = o.Type != n.Type ? "different" : "different_nullable",
Note = "Table not found in old schema",
ColumnDef = oldCols[col]
});
} else
{
Console.WriteLine($" Column mached: {col}");
tableMapping.ColumnMappings.Add(new ColumnMapping
{
OldColumn = col,
Status = "matched",
Note = "Table not found in old schema",
ColumnDef = oldCols[col]
});
}
}
}
return result;
}
private static void TableMissingInSchema(Dictionary<string, TableDef> tableSchema, string table, TableMapping tableMapping,
SchemaMapping result, bool isNewTable)
{
foreach (var column in tableSchema[table].Columns)
{
tableMapping.ColumnMappings.Add(new ColumnMapping
{
NewColumn = column.Name,
ColumnDef = column,
Status = "missing",
Note = "Table not found in old schema"
});
}
tableMapping.IsNewTable = isNewTable;
result.Tables.Add(tableMapping);
}
public static SchemaMapping CompareSchemas(
Dictionary<string, TableDef> oldSchema,
Dictionary<string, TableDef> newSchema)
{
var result = new SchemaMapping();
foreach (var (oldTableName, oldTableDef) in oldSchema)
{
var tableMapping = new TableMapping { TableName = oldTableName };
if (!newSchema.TryGetValue(oldTableName, out var newTableDef))
{
// Table removed or renamed
foreach (var oldCol in oldTableDef.Columns)
{
tableMapping.ColumnMappings.Add(new ColumnMapping
{
OldColumn = oldCol.Name,
ColumnDef = oldCol,
Status = "missing",
Note = "Table not found in new schema"
});
}
}
else
{
foreach (var oldCol in oldTableDef.Columns)
{
var match = newTableDef.Columns.FirstOrDefault(c =>
string.Equals(c.Name, oldCol.Name, StringComparison.OrdinalIgnoreCase) &&
string.Equals(c.Type, oldCol.Type, StringComparison.OrdinalIgnoreCase));
if (match != null)
{
tableMapping.ColumnMappings.Add(new ColumnMapping
{
OldColumn = oldCol.Name,
ColumnDef = oldCol,
NewColumn = match.Name,
Status = "matched"
});
}
else
{
// Try fuzzy match (e.g., JSON joins)
var possible = newTableDef.Columns
.Where(c => c.Type.Contains("json", StringComparison.OrdinalIgnoreCase))
.Select(c => c.Name)
.FirstOrDefault();
tableMapping.ColumnMappings.Add(new ColumnMapping
{
OldColumn = oldCol.Name,
ColumnDef = oldCol,
NewColumn = possible,
Status = "uncertain",
Note = "Could be part of JSON or renamed"
});
}
}
}
result.Tables.Add(tableMapping);
}
return result;
}
public SchemaMapping? LoadSchema(string combine)
{
var jsonString = File.ReadAllText(combine);
return System.Text.Json.JsonSerializer.Deserialize<SchemaMapping>(jsonString);
}
}

View File

@ -0,0 +1,27 @@
namespace tbfDBBackup.compare_dumps;
public class TableDef
{
public string Name;
public List<ColumnDef> Columns = new();
public List<string> privateKeys = new();
public void PairPrivateKeys()
{
foreach (string privateKey in privateKeys)
{
if (privateKey.Length <= 0)
{
continue;
}
foreach (ColumnDef column in Columns)
{
if (column.Name == privateKey)
{
column.IsPrimaryKey = true;
}
}
}
}
}

View File

@ -0,0 +1,496 @@
using System.Data;
using System.Text;
using MySqlConnector;
using tbfDBBackup.compare_dumps.mapping;
using tbfDBBackup.compare_dumps.Parserer;
using tbfDBBackup.configuration;
namespace tbfDBBackup.compare_dumps.joinValues;
public class Joiner
{
const int iMaxStepInsertRows = 20;
private Configuration dbConfiguration;
private string basePath;
private string oldDump;
private string schema;
public bool isJoindedSuccesfully = false;
public bool IsJoindedSuccesfully
{
get { return isJoindedSuccesfully; }
}
public Joiner(Configuration dbConfiguration, string basePath, string oldDump, string schema)
{
this.dbConfiguration = dbConfiguration;
this.basePath = basePath;
this.oldDump = oldDump;
this.schema = schema;
}
private MySqlConnection _connection;
private static string QuoteIdentifier(string identifier)
{
// Enforce a strict whitelist for identifiers (letters, digits, underscore).
// Adjust if you must allow more, but be cautious.
if (string.IsNullOrWhiteSpace(identifier) || !System.Text.RegularExpressions.Regex.IsMatch(identifier, @"^[A-Za-z0-9_]+$"))
throw new ArgumentException("Invalid identifier.", nameof(identifier));
// Escape backticks just in case you relax the whitelist in the future.
var escaped = identifier.Replace("`", "``");
return $"`{escaped}`";
}
private long GetMaxId(string tableName, string columnName)
{
if (columnName == null || columnName.Length == 0)
{
return 0;
}
OpenFirstDbConnection();
var qTable = QuoteIdentifier(tableName);
var qColumn = QuoteIdentifier(columnName);
try
{
using var cmd = new MySqlCommand($"SELECT COALESCE(MAX({qColumn}), 0) FROM {qTable};", _connection)
{
CommandTimeout = 30
};
var result = cmd.ExecuteScalar();
if (result is DBNull)
return 0;
try
{
// Consider checked/unchecked based on your tolerance for overflow.
return Convert.ToInt64(result, System.Globalization.CultureInfo.InvariantCulture);
}
catch (OverflowException)
{
// Decide on policy: throw with context or clamp/return 0.
throw new OverflowException($"MAX({columnName}) in {tableName} exceeds Int64 range.");
}
}
catch (Exception e)
{
// Decide on policy: throw with context or clamp/return 0.
throw new Exception($"MAX({columnName}) in {tableName} has problems: {e.Message}.");
}
}
public void SchemaJoiner()
{
try
{
string combinePath = Path.Combine(basePath, this.schema);
SqlDumpSchemaParser schemaParser = new SqlDumpSchemaParser();
SchemaMapping? schemaMapping = schemaParser.LoadSchema(combinePath);
if (schemaMapping == null)
{
Console.WriteLine($"SchemaMapping is null, check {combinePath}");
return;
}
if (schemaMapping.Tables.Count == 0)
{
Console.WriteLine($"Nothing to do! See schema: {combinePath}");
}
//we have schema mapping
SqlDumpFileParser oldDumpParser = new();
//SqlDumpFileParser newDumpParser = new();
oldDumpParser.SqlDumpParserFile(Path.Combine(basePath, oldDump));
//newDumpParser.SqlDumpParserFile(Path.Combine(basePath, newDump));
//we have opened files
// now list the schema to find out what to change
foreach (TableMapping table in schemaMapping?.Tables!)
{
Dictionary<int, Dictionary<string, string>> blockTable = new();
if (oldDumpParser.TableDefinitions.Keys.Contains(table.TableName))
{
bool tryGetInsertValue =
oldDumpParser.TableInserts.TryGetValue(table.TableName, out List<string>? oldRowsInserts);
StringBuilder builder = new StringBuilder();
if (tryGetInsertValue)
{
//get primary columns
List<string> primaryColumns = new List<string>();
table.ColumnMappings?.ForEach(col =>
{
if (col.IsPrimaryColumn) { primaryColumns.Add(col?.OldColumn); }
});
//get foreigner columns
bool tryGetForeignerColums =
oldDumpParser.TableForeignKeys.TryGetValue(table.TableName, out List<string>? oldForeignerTableNames);
List<ForeignKeyDef> foreignKeys = new List<ForeignKeyDef>();
if (tryGetForeignerColums)
{
oldForeignerTableNames.ForEach(ForeignKeyConstraintRow =>
{
Dictionary<string, List<ForeignKeyDef>> foreignerList =
SqlDumpParser.ParseForeignKeys(ForeignKeyConstraintRow);
if (foreignerList.Count == 1) // we expecting only one foreign key definition per table
{
var keyValuePair = foreignerList.First().Value;
foreach (var combination in keyValuePair)
{
foreignKeys.Add(combination);
}
}
}
);
}
//get max id from table - for insert
long iMaxId = GetMaxId(table.TableName, primaryColumns.First());
iMaxId ++;
table.PrivateKeyShift = iMaxId;
//store max id and increment it
//collect data by columns to insert command
oldRowsInserts.ForEach(colapsedInsertRow =>
{
Dictionary<int, Dictionary<string, string>> insertBlock = SqlDumpParser.ParseInsertBlock(colapsedInsertRow);
foreach (KeyValuePair<int, Dictionary<string, string>> keyValuePair in insertBlock)
{
//get columns from insert block - store to permittedColumns
Dictionary<string, string> permittedColumns = new();
foreach (KeyValuePair<string, string> column in keyValuePair.Value)
{
foreach (ColumnMapping columnMapping in table.ColumnMappings)
{
if (columnMapping.OldColumn == column.Key
&& columnMapping.NewColumn != null)
{
//if is column PRIMARY KEY we need add shift upgrade - if we have
if (columnMapping.IsPrimaryColumn && iMaxId > 0)
{
long _actualValue = ConvertValToLong(column.Value);
permittedColumns.Add(columnMapping.NewColumn, (_actualValue + iMaxId).ToString());
}
//if is Forine key we need add shift upgrade - of table max id
else if (foreignKeys.Count > 0 && foreignKeys.Any(fk => fk.Column == columnMapping.OldColumn))
{
//we have foreigner table name
foreach (ForeignKeyDef fk in foreignKeys)
{
if (fk.Column == columnMapping.OldColumn)
{
long shift = 0;
foreach (TableMapping tableMapping in schemaMapping.Tables)
{
TableMapping? tMap = schemaMapping.Tables.FirstOrDefault(t => t.TableName == fk.RefTable);
if (tMap != null)
{
shift = tMap.PrivateKeyShift;
break;
}
}
//TODO BUMI !! finish this - need react to converted data in different tables
long _actualValue = ConvertValToLong(column.Value);
permittedColumns.Add(columnMapping.NewColumn,
(_actualValue + shift).ToString());
}
}
}
else
{
permittedColumns.Add(columnMapping.NewColumn, column.Value);
}
break;
}
}
}
blockTable.Add(keyValuePair.Key, permittedColumns);
}
//TODO Insert data step by step into database ??
builder.Append($" Inserts: {blockTable.Count}, ");
});
Console.WriteLine(builder.ToString());
}
else
{
continue;
}
}
//TODO Insert data step by step into database
WriteBlockTableToDB(dbConfiguration, table.TableName, blockTable);
}
// finally, ok
isJoindedSuccesfully = true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
isJoindedSuccesfully = false;
}
finally
{
ReleaseConnectionToDB();
}
}
private long ConvertValToLong(object columnValue)
{
long result;
if (columnValue is long l)
{
result = l;
}
else if (columnValue is string s && long.TryParse(s, out long parsed))
{
result = parsed;
}
else
{
// fallback if null/invalid
result = 0;
}
return result;
}
private void WriteBlockTableToDB(Configuration dbConfiguration,string tableName,
Dictionary<int, Dictionary<string, string>> blockTable)
{
if (dbConfiguration == null)
{
throw new ArgumentNullException(nameof(dbConfiguration));
}
if (blockTable == null || blockTable.Count == 0)
{
return;
}
if (dbConfiguration.DbConnectionStrings != null)
foreach (DbConnection dbConnection in dbConfiguration.DbConnectionStrings)
{
if (!(dbConnection.Enabled ?? true))
{
continue;
}
if (dbConfiguration.UpgradeDatabase != null)
foreach (Upgrade upgrade in dbConfiguration.UpgradeDatabase)
{
string databaseName = upgrade.DatabaseName;
List<string> columns = blockTable.First().Value.Keys.ToList();
int iRowsStepCount = 0;
//join values
StringBuilder builderValues = new StringBuilder();
foreach (KeyValuePair<int, Dictionary<string, string>> table in blockTable)
{
builderValues.Append('(');
// Values
bool first = true;
foreach (string colName in columns)
{
var colValExist = table.Value.TryGetValue(colName, out string? col);
if (!first)
builderValues.Append(", ");
// Wrap string values in quotes
if (!colValExist)
builderValues.Append("NULL");
else
builderValues.Append($"'{col?.Replace("'", "''")}'");
first = false;
}
builderValues.Append("),");
//Send upgrade string to db
if (iRowsStepCount >= iMaxStepInsertRows)
{
SendInsertCommandToDb(dbConnection,databaseName, tableName, columns, builderValues);
builderValues.Clear();
iRowsStepCount = 0;
}
else
{
iRowsStepCount++;
}
}
if (builderValues.Length > 0)
{
SendInsertCommandToDb(dbConnection, databaseName, tableName, columns, builderValues);
builderValues.Clear();
iRowsStepCount = 0;
}
//we upgrade only one Upgrade connection
break;
}
}
}
private void SendInsertCommandToDb(DbConnection dbConnection,string databaseName, string tableName, List<string> columns, StringBuilder builderValues)
{
if (builderValues.Length > 0)
{
Console.WriteLine(builderValues.Length);
}
//Create upgrade string
StringBuilder builder = new StringBuilder();
builder.Append("INSERT INTO");
// Optional: prepend database name if provided
if (!string.IsNullOrEmpty(databaseName))
{
builder.Append($" `{databaseName}`.`{tableName}` ");
}
else
{
builder.Append($" `{tableName}` ");
}
// Columns
builder.Append('(');
builder.Append(string.Join(", ", columns));
builder.Append(") VALUES ");
builderValues.Remove(builderValues.Length - 1, 1);
builder.Append(builderValues).Append(';');
//Write to db
OpenConnectionToDB(dbConnection);
try
{
using (var tx = _connection.BeginTransaction())
using (var command = new MySqlCommand(builder.ToString(), _connection, tx))
{
int affectedItems = command.ExecuteNonQuery();
tx.Commit();
Console.WriteLine($"Affected items: {affectedItems}");
}
}
catch (Exception e)
{
Console.WriteLine("Command execution failed, see details: ",e);
File.AppendAllText("error.txt", "\nLOG Bug: \n");
File.AppendAllText("error.txt", e.Message);
//TODO BUMI remove this part as default
#if DEBUG
File.AppendAllText("error.txt", "\n\n ----------------------------------------------------------------------\n");
File.AppendAllText("error.txt", builder.ToString());
#else
throw;
#endif
}
}
private void OpenFirstDbConnection()
{
if (dbConfiguration.DbConnectionStrings != null)
foreach (DbConnection dbConnection in dbConfiguration.DbConnectionStrings)
{
if (!(dbConnection.Enabled ?? true))
{
continue;
}
if (dbConfiguration.UpgradeDatabase != null)
foreach (Upgrade upgrade in dbConfiguration.UpgradeDatabase)
{
OpenConnectionToDB(dbConnection, true);
return;
}
}
}
private void OpenConnectionToDB(DbConnection dbConnection, bool ForcedReloading = false)
{
if (ForcedReloading)
{
ReleaseConnectionToDB();
}
if (_connection == null || _connection.State == ConnectionState.Closed || _connection.State == ConnectionState.Broken)
{
ReleaseConnectionToDB();
string connectionString =
dbConnection.Connection.Replace("{DatabaseName}", dbConnection.DatabaseName);
_connection = new MySqlConnection(connectionString);
_connection.Open();
}
}
void ReleaseConnectionToDB()
{
if (_connection != null)
{
_connection.Dispose();
_connection.Close();
_connection = null;
}
}
public void TestInputsAndFiles()
{
if (dbConfiguration is null)
throw new ArgumentNullException(nameof(dbConfiguration));
if (dbConfiguration.DbConnectionStrings is null || dbConfiguration.DbConnectionStrings.Count == 0)
throw new ArgumentException("DbConnectionStrings must not be null or empty.", nameof(dbConfiguration));
if (string.IsNullOrWhiteSpace(basePath))
throw new ArgumentException("Base path must not be null or empty.", nameof(basePath));
if (string.IsNullOrWhiteSpace(oldDump))
throw new ArgumentException("Old dump file name must not be null or empty.", nameof(oldDump));
if (string.IsNullOrWhiteSpace(schema))
throw new ArgumentException("Schema mapping file name must not be null or empty.", nameof(schema));
var files = new[]
{
(Name: oldDump, Path: Path.Combine(basePath, oldDump)),
(Name: schema, Path: Path.Combine(basePath, schema)),
};
var missing = new List<string>();
foreach (var f in files)
{
if (!File.Exists(f.Path))
missing.Add(f.Name);
}
if (missing.Count > 0)
throw new FileNotFoundException($"Missing files: {string.Join(", ", missing)} on path {basePath} .");
}
}

View File

@ -0,0 +1,34 @@
using System.Text.Json.Serialization;
namespace tbfDBBackup.compare_dumps.mapping;
public class ColumnMapping
{
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? OldColumn { get; set; } // null if column only exists in new schema
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? NewColumn { get; set; } // null if column was removed or not yet mapped
public string Status { get; set; } // "matched", "uncertain", "missing", "added"
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Note { get; set; }
public ColumnDef ColumnDef { get; set; }
public List<ColumnDef> ColumnDefList { get; set; }
private bool? _isPrimaryColumn;
public bool IsPrimaryColumn { get { return GetPrimaryColumn(); } set { _isPrimaryColumn = value; } }
private bool GetPrimaryColumn()
{
if (_isPrimaryColumn != null)
{
return _isPrimaryColumn.Value;
}
return ColumnDef != null ? ColumnDef.IsPrimaryKey : false;
}
private JoinColumn? _joinColumn;
public JoinColumn? JoinColumn { get { return _joinColumn; } set { _joinColumn = value; } }
}

View File

@ -0,0 +1,7 @@
namespace tbfDBBackup.compare_dumps.mapping;
public class JoinColumn
{
public string ColumnName { get; set; }
public string TableName { get; set; }
}

View File

@ -0,0 +1,8 @@
using System.Xml.Serialization;
namespace tbfDBBackup.compare_dumps.mapping;
public class SchemaMapping
{
public List<TableMapping> Tables { get; set; } = new();
}

View File

@ -0,0 +1,11 @@
namespace tbfDBBackup.compare_dumps.mapping;
public class TableMapping
{
public string TableName { get; set; }
public List<ColumnMapping> ColumnMappings { get; set; } = new();
public bool IsNewTable { get; set; } = false;
public bool IsNeedRecalculate { get => PrivateKeyShift != 0; }
public long PrivateKeyShift { get; set; }
}

View File

@ -7,48 +7,41 @@
"Name": "Settings DB",
"Connection": "SERVER=localhost; DATABASE={DatabaseName}; UID=root; PASSWORD=; CHARSET=utf8;",
"DatabaseName": "wrcswindon298",
"Enabled": false
},
{
"Name": "Results DB",
"Connection": "SERVER=localhost; DATABASE={DatabaseName}; UID=root; PASSWORD=; CHARSET=utf8;",
"DatabaseName": "wrcswindon298-r",
"Enabled": true
}
],
"UpdateString": [
{
"Enabled": false,
"Name": "Alter table Water Meter",
"Query": "ALTER TABLE `{DatabaseName}`.`WaterMeter` ADD COLUMN `RadioAddress` BOOLEAN;",
"DatabaseName": "wrcswindon298-r"
}
],
"BackupDB": [
{
"DbConnectionStringsName": "Results DB",
"StoreDirPaths": [
{
"Path": "C:\\TBF\\",
"IsOneTimeOpaque": true
},
{
"Path": "C:\\TBF\\storeString"
}
],
"Enabled": true
"Query": "INSERT INTO \u0060group\u0060 (Name, AccessFlags) VALUES (\u0027MetrologicalAuthority\u0027, 0);\nINSERT INTO \u0060group\u0060 (Name, AccessFlags) VALUES (\u0027WaterMeterAuthority\u0027, 0);",
"DatabaseName": "wrcswindon298",
"Enabled": false,
"IsOneTimeOpaque": true
},
{
"DbConnectionStringsName": "Settings DB",
"StoreDirPaths": [
{
"Path": "C:\\TBF\\"
},
{
"Path": "C:\\TBF\\storeString"
}
],
"Enabled": false
"Name": "Alter table Water Meter",
"Query": "INSERT INTO usersgroups (Group_id, User_id) VALUES (8, 1);\nINSERT INTO usersgroups (Group_id, User_id) VALUES (9, 1);",
"DatabaseName": "wrcswindon298",
"Enabled": false,
"IsOneTimeOpaque": true
}
],
"UpgradeDatabase": [
{
"Enabled": true,
"Name": "Upgrade by JSON",
"Query": "",
"JSONFileName": "",
"DatabaseName": "wrcswindon298",
"IsOneTimeOpaque": true
},
{
"Enabled": true,
"Name": "Alter table Water Meter",
"Query": "INSERT INTO usersgroups (Group_id, User_id) VALUES (8, 1);\nINSERT INTO usersgroups (Group_id, User_id) VALUES (9, 1);",
"JSONFileName": null,
"DatabaseName": "wrcswindon298",
"IsOneTimeOpaque": true
}
]
}

View File

@ -0,0 +1,29 @@
{
"PathToDumpMysql": "C:\\xampp\\mysql\\bin",
"WaitOnEndCmdOpen": false,
"PrintConfigurationEnabled": false,
"DbConnectionStrings": [
{
"Name": "Settings DB",
"Connection": "SERVER=localhost; DATABASE={DatabaseName}; UID=root; PASSWORD=; CHARSET=utf8;",
"DatabaseName": "wrcswindon298",
"Enabled": true
}
],
"UpdateString": [
{
"Enabled": true,
"Name": "Alter table Water Meter",
"Query": "INSERT INTO `group` (Name, AccessFlags) VALUES ('MetrologicalAuthority', 0);\nINSERT INTO `group` (Name, AccessFlags) VALUES ('WaterMeterAuthority', 0);",
"DatabaseName": "wrcswindon298",
"IsOneTimeOpaque": true
},
{
"Enabled": true,
"Name": "Alter table Water Meter",
"Query": "INSERT INTO usersgroups (Group_id, User_id) VALUES (8, 1);\nINSERT INTO usersgroups (Group_id, User_id) VALUES (9, 1);",
"DatabaseName": "wrcswindon298",
"IsOneTimeOpaque": true
}
]
}

View File

@ -0,0 +1,810 @@
{
"Tables": [
{
"TableName": "componentprocedure",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"Nullable": "NO"
}
},
{
"OldColumn": "CmpntName",
"NewColumn": "CmpntName",
"Status": "matched",
"ColumnDef": {
"Name": "CmpntName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Parameters",
"NewColumn": "Parameters",
"Status": "matched",
"ColumnDef": {
"Name": "Parameters",
"Type": "varchar(8000)",
"Nullable": "YES"
}
},
{
"OldColumn": "Procedure_id",
"NewColumn": "Procedure_id",
"Status": "matched",
"ColumnDef": {
"Name": "Procedure_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
},
{
"TableName": "componenttest",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"Nullable": "NO"
}
},
{
"OldColumn": "CmpntName",
"NewColumn": "CmpntName",
"Status": "matched",
"ColumnDef": {
"Name": "CmpntName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Parameters",
"NewColumn": "Parameters",
"Status": "matched",
"ColumnDef": {
"Name": "Parameters",
"Type": "varchar(8000)",
"Nullable": "YES"
}
},
{
"OldColumn": "Test_id",
"NewColumn": "Test_id",
"Status": "matched",
"ColumnDef": {
"Name": "Test_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
},
{
"TableName": "procedure",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"Nullable": "NO"
}
},
{
"OldColumn": "ItemNr",
"NewColumn": "ItemNr",
"Status": "matched",
"ColumnDef": {
"Name": "ItemNr",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Name",
"NewColumn": "Name",
"Status": "matched",
"ColumnDef": {
"Name": "Name",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Description",
"NewColumn": "Description",
"Status": "matched",
"ColumnDef": {
"Name": "Description",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "CreationUser",
"NewColumn": "CreationUser",
"Status": "matched",
"ColumnDef": {
"Name": "CreationUser",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "CreationTime",
"NewColumn": "CreationTime",
"Status": "matched",
"ColumnDef": {
"Name": "CreationTime",
"Type": "datetime",
"Nullable": "YES"
}
},
{
"OldColumn": "LastChgUser",
"NewColumn": "LastChgUser",
"Status": "matched",
"ColumnDef": {
"Name": "LastChgUser",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "LastChgTime",
"NewColumn": "LastChgTime",
"Status": "matched",
"ColumnDef": {
"Name": "LastChgTime",
"Type": "datetime",
"Nullable": "YES"
}
},
{
"OldColumn": "LongDescription",
"NewColumn": "LongDescription",
"Status": "matched",
"ColumnDef": {
"Name": "LongDescription",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ProcedureState",
"NewColumn": "ProcedureState",
"Status": "matched",
"ColumnDef": {
"Name": "ProcedureState",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Revision",
"NewColumn": "Revision",
"Status": "matched",
"ColumnDef": {
"Name": "Revision",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "PredecessorId",
"NewColumn": "PredecessorId",
"Status": "matched",
"ColumnDef": {
"Name": "PredecessorId",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "ObtainedByCopy",
"NewColumn": "ObtainedByCopy",
"Status": "matched",
"ColumnDef": {
"Name": "ObtainedByCopy",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "MetersKind",
"NewColumn": "MetersKind",
"Status": "matched",
"ColumnDef": {
"Name": "MetersKind",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Watermeters",
"NewColumn": "Watermeters",
"Status": "matched",
"ColumnDef": {
"Name": "Watermeters",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ProtocolTitle",
"Status": "new",
"Note": "New",
"ColumnDef": {
"Name": "ProtocolTitle",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Protected",
"NewColumn": "Protected",
"Status": "matched",
"ColumnDef": {
"Name": "Protected",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "MustBeComplete",
"NewColumn": "MustBeComplete",
"Status": "matched",
"ColumnDef": {
"Name": "MustBeComplete",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "ManualCtrlDisabled",
"NewColumn": "ManualCtrlDisabled",
"Status": "matched",
"ColumnDef": {
"Name": "ManualCtrlDisabled",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "DataEntry",
"NewColumn": "DataEntry",
"Status": "matched",
"ColumnDef": {
"Name": "DataEntry",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ResultsPrinter",
"NewColumn": "ResultsPrinter",
"Status": "matched",
"ColumnDef": {
"Name": "ResultsPrinter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ResultsWriter",
"NewColumn": "ResultsWriter",
"Status": "matched",
"ColumnDef": {
"Name": "ResultsWriter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionStart",
"NewColumn": "TransitionStart",
"Status": "matched",
"ColumnDef": {
"Name": "TransitionStart",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionEnd",
"NewColumn": "TransitionEnd",
"Status": "matched",
"ColumnDef": {
"Name": "TransitionEnd",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "AltProcName",
"NewColumn": "AltProcName",
"Status": "matched",
"ColumnDef": {
"Name": "AltProcName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "AltProcPeriod",
"NewColumn": "AltProcPeriod",
"Status": "matched",
"ColumnDef": {
"Name": "AltProcPeriod",
"Type": "int(11)",
"Nullable": "NO"
}
}
],
"IsNewTable": false
},
{
"TableName": "test",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"Nullable": "NO"
}
},
{
"OldColumn": "ItemNr",
"NewColumn": "ItemNr",
"Status": "matched",
"ColumnDef": {
"Name": "ItemNr",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Name",
"NewColumn": "Name",
"Status": "matched",
"ColumnDef": {
"Name": "Name",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Part",
"NewColumn": "Part",
"Status": "matched",
"ColumnDef": {
"Name": "Part",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Publish",
"NewColumn": "Publish",
"Status": "matched",
"ColumnDef": {
"Name": "Publish",
"Type": "tinyint(4)",
"Nullable": "YES"
}
},
{
"OldColumn": "Evaluate",
"NewColumn": "DoEvaluate",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "Evaluate",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "Qfrom",
"NewColumn": "Qfrom",
"Status": "Change",
"Note": "Could be part of JSON or renamed",
"ColumnDefList": [{
"Name": "Qfrom",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Qfrom",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Qto",
"NewColumn": "Qto",
"Status": "Change",
"Note": "",
"ColumnDefList": [
{
"Name": "Qto",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Qto",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Volume",
"Status": "Change",
"Note": "",
"ColumnDefList": [
{
"Name": "Volume",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Volume",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "TstTime",
"NewColumn": "TestTime",
"Status": "update",
"Note": "Could be part of JSON or renamed",
"ColumnDefList": [
{
"Name": "TstTime",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "TestTime",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Repeats",
"NewColumn": "Repeats",
"Status": "matched",
"ColumnDef": {
"Name": "Repeats",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Emptying",
"NewColumn": "DoDraining",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "Emptying",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "Zeroing",
"Status": "uncertain",
"Note": "Could be part of JSON or renamed",
"ColumnDef": {
"Name": "Zeroing",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "DoControlWaterTemp",
"Status": "uncertain",
"Note": "Could be part of JSON or renamed",
"ColumnDef": {
"Name": "DoControlWaterTemp",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "TempLimLo",
"NewColumn": "TempLimLo",
"Status": "matched",
"ColumnDef": {
"Name": "TempLimLo",
"Type": "float",
"Nullable": "NO"
}
},
{
"OldColumn": "TempLimHi",
"NewColumn": "TempLimHi",
"Status": "matched",
"ColumnDef": {
"Name": "TempLimHi",
"Type": "float",
"Nullable": "NO"
}
},
{
"OldColumn": "PumpPower",
"NewColumn": "PumpPower",
"Status": "matched",
"ColumnDef": {
"Name": "PumpPower",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "MassRepeats",
"NewColumn": "MassRepeats",
"Status": "matched",
"ColumnDef": {
"Name": "MassRepeats",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "MassSpread",
"NewColumn": "MassSpread",
"Status": "matched",
"ColumnDef": {
"Name": "MassSpread",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "MassMethod",
"NewColumn": "MassMethod",
"Status": "Changed",
"Note": "`MassMethod` tinyint(3) unsigned DEFAULT NULL,",
"ColumnDefList": [
{
"Name": "MassMethod",
"Type": "tinyint(1)",
"Nullable": "YES"
},
{
"Name": "MassMethod",
"Type": "tinyint(3)",
"Nullable": "YES"
}
]
},
{
"OldColumn": "TimeBeforeFlow",
"NewColumn": "TimeBeforeFlow",
"Status": "matched",
"ColumnDef": {
"Name": "TimeBeforeFlow",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeFlow2Mass",
"NewColumn": "TimeFlow2Mass",
"Status": "matched",
"ColumnDef": {
"Name": "TimeFlow2Mass",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeMass2Start",
"NewColumn": "TimePump2StartV",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "TimeMass2Start",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeStop2Mass",
"NewColumn": "TimeStop2Mass",
"Status": "matched",
"ColumnDef": {
"Name": "TimeStop2Mass",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Method",
"NewColumn": "Method",
"Status": "matched",
"ColumnDef": {
"Name": "Method",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ErrLimLo",
"NewColumn": "ErrLimLo",
"Status": "matched",
"ColumnDef": {
"Name": "ErrLimLo",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "ErrLimHi",
"NewColumn": "ErrLimHi",
"Status": "matched",
"ColumnDef": {
"Name": "ErrLimHi",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "Uncertainty",
"NewColumn": "Uncertainty",
"Status": "matched",
"ColumnDef": {
"Name": "Uncertainty",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "TolerRed",
"Status": "Deleted",
"ColumnDef": {
"Name": "TolerRed",
"Type": "double",
"Nullable": "YES"
}
},
{
"OldColumn": "RedType",
"Status": "Deleted",
"ColumnDef": {
"Name": "RedType",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "FeedingPath",
"NewColumn": "FeedingPath",
"Status": "matched",
"ColumnDef": {
"Name": "FeedingPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "BenchPath",
"NewColumn": "BenchPath",
"Status": "matched",
"ColumnDef": {
"Name": "BenchPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "OutputPath",
"NewColumn": "OutputPath",
"Status": "matched",
"ColumnDef": {
"Name": "OutputPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "MetersPath",
"NewColumn": "MetersPath",
"Status": "matched",
"ColumnDef": {
"Name": "MetersPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "HeatMetersPath",
"NewColumn": "HeatMetersPath",
"Status": "matched",
"ColumnDef": {
"Name": "HeatMetersPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransBefore",
"NewColumn": "TransBefore",
"Status": "Renamed",
"ColumnDef": {
"Name": "RelTransBefore",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransBetween",
"NewColumn": "TransBetween",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "RelTransBetween",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransAfter",
"NewColumn": "TransAfter",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "RelTransAfter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionAfter",
"Status": "Deleted",
"Note": "",
"ColumnDef": {
"Name": "TransitionAfter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Procedure_id",
"NewColumn": "Procedure_id",
"Status": "matched",
"ColumnDef": {
"Name": "Procedure_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
}
]
}

View File

@ -0,0 +1,810 @@
{
"Tables": [
{
"TableName": "componentprocedure",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"Nullable": "NO"
}
},
{
"OldColumn": "CmpntName",
"NewColumn": "CmpntName",
"Status": "matched",
"ColumnDef": {
"Name": "CmpntName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Parameters",
"NewColumn": "Parameters",
"Status": "matched",
"ColumnDef": {
"Name": "Parameters",
"Type": "varchar(8000)",
"Nullable": "YES"
}
},
{
"OldColumn": "Procedure_id",
"NewColumn": "Procedure_id",
"Status": "matched",
"ColumnDef": {
"Name": "Procedure_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
},
{
"TableName": "componenttest",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"Nullable": "NO"
}
},
{
"OldColumn": "CmpntName",
"NewColumn": "CmpntName",
"Status": "matched",
"ColumnDef": {
"Name": "CmpntName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Parameters",
"NewColumn": "Parameters",
"Status": "matched",
"ColumnDef": {
"Name": "Parameters",
"Type": "varchar(8000)",
"Nullable": "YES"
}
},
{
"OldColumn": "Test_id",
"NewColumn": "Test_id",
"Status": "matched",
"ColumnDef": {
"Name": "Test_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
},
{
"TableName": "procedure",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"Nullable": "NO"
}
},
{
"OldColumn": "ItemNr",
"NewColumn": "ItemNr",
"Status": "matched",
"ColumnDef": {
"Name": "ItemNr",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Name",
"NewColumn": "Name",
"Status": "matched",
"ColumnDef": {
"Name": "Name",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Description",
"NewColumn": "Description",
"Status": "matched",
"ColumnDef": {
"Name": "Description",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "CreationUser",
"NewColumn": "CreationUser",
"Status": "matched",
"ColumnDef": {
"Name": "CreationUser",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "CreationTime",
"NewColumn": "CreationTime",
"Status": "matched",
"ColumnDef": {
"Name": "CreationTime",
"Type": "datetime",
"Nullable": "YES"
}
},
{
"OldColumn": "LastChgUser",
"NewColumn": "LastChgUser",
"Status": "matched",
"ColumnDef": {
"Name": "LastChgUser",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "LastChgTime",
"NewColumn": "LastChgTime",
"Status": "matched",
"ColumnDef": {
"Name": "LastChgTime",
"Type": "datetime",
"Nullable": "YES"
}
},
{
"OldColumn": "LongDescription",
"NewColumn": "LongDescription",
"Status": "matched",
"ColumnDef": {
"Name": "LongDescription",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ProcedureState",
"NewColumn": "ProcedureState",
"Status": "matched",
"ColumnDef": {
"Name": "ProcedureState",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Revision",
"NewColumn": "Revision",
"Status": "matched",
"ColumnDef": {
"Name": "Revision",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "PredecessorId",
"NewColumn": "PredecessorId",
"Status": "matched",
"ColumnDef": {
"Name": "PredecessorId",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "ObtainedByCopy",
"NewColumn": "ObtainedByCopy",
"Status": "matched",
"ColumnDef": {
"Name": "ObtainedByCopy",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "MetersKind",
"NewColumn": "MetersKind",
"Status": "matched",
"ColumnDef": {
"Name": "MetersKind",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Watermeters",
"NewColumn": "Watermeters",
"Status": "matched",
"ColumnDef": {
"Name": "Watermeters",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ProtocolTitle",
"Status": "new",
"Note": "New",
"ColumnDef": {
"Name": "ProtocolTitle",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Protected",
"NewColumn": "Protected",
"Status": "matched",
"ColumnDef": {
"Name": "Protected",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "MustBeComplete",
"NewColumn": "MustBeComplete",
"Status": "matched",
"ColumnDef": {
"Name": "MustBeComplete",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "ManualCtrlDisabled",
"NewColumn": "ManualCtrlDisabled",
"Status": "matched",
"ColumnDef": {
"Name": "ManualCtrlDisabled",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "DataEntry",
"NewColumn": "DataEntry",
"Status": "matched",
"ColumnDef": {
"Name": "DataEntry",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ResultsPrinter",
"NewColumn": "ResultsPrinter",
"Status": "matched",
"ColumnDef": {
"Name": "ResultsPrinter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ResultsWriter",
"NewColumn": "ResultsWriter",
"Status": "matched",
"ColumnDef": {
"Name": "ResultsWriter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionStart",
"NewColumn": "TransitionStart",
"Status": "matched",
"ColumnDef": {
"Name": "TransitionStart",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionEnd",
"NewColumn": "TransitionEnd",
"Status": "matched",
"ColumnDef": {
"Name": "TransitionEnd",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "AltProcName",
"NewColumn": "AltProcName",
"Status": "matched",
"ColumnDef": {
"Name": "AltProcName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "AltProcPeriod",
"NewColumn": "AltProcPeriod",
"Status": "matched",
"ColumnDef": {
"Name": "AltProcPeriod",
"Type": "int(11)",
"Nullable": "NO"
}
}
],
"IsNewTable": false
},
{
"TableName": "test",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"Nullable": "NO"
}
},
{
"OldColumn": "ItemNr",
"NewColumn": "ItemNr",
"Status": "matched",
"ColumnDef": {
"Name": "ItemNr",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Name",
"NewColumn": "Name",
"Status": "matched",
"ColumnDef": {
"Name": "Name",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Part",
"NewColumn": "Part",
"Status": "matched",
"ColumnDef": {
"Name": "Part",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Publish",
"NewColumn": "Publish",
"Status": "matched",
"ColumnDef": {
"Name": "Publish",
"Type": "tinyint(4)",
"Nullable": "YES"
}
},
{
"OldColumn": "Evaluate",
"NewColumn": "DoEvaluate",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "Evaluate",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "Qfrom",
"NewColumn": "Qfrom",
"Status": "Change",
"Note": "Could be part of JSON or renamed",
"ColumnDefList": [{
"Name": "Qfrom",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Qfrom",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Qto",
"NewColumn": "Qto",
"Status": "Change",
"Note": "",
"ColumnDefList": [
{
"Name": "Qto",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Qto",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Volume",
"Status": "Change",
"Note": "",
"ColumnDefList": [
{
"Name": "Volume",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Volume",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "TstTime",
"NewColumn": "TestTime",
"Status": "update",
"Note": "Could be part of JSON or renamed",
"ColumnDefList": [
{
"Name": "TstTime",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "TestTime",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Repeats",
"NewColumn": "Repeats",
"Status": "matched",
"ColumnDef": {
"Name": "Repeats",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Emptying",
"NewColumn": "DoDraining",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "Emptying",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "Zeroing",
"Status": "uncertain",
"Note": "Could be part of JSON or renamed",
"ColumnDef": {
"Name": "Zeroing",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "DoControlWaterTemp",
"Status": "uncertain",
"Note": "Could be part of JSON or renamed",
"ColumnDef": {
"Name": "DoControlWaterTemp",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "TempLimLo",
"NewColumn": "TempLimLo",
"Status": "matched",
"ColumnDef": {
"Name": "TempLimLo",
"Type": "float",
"Nullable": "NO"
}
},
{
"OldColumn": "TempLimHi",
"NewColumn": "TempLimHi",
"Status": "matched",
"ColumnDef": {
"Name": "TempLimHi",
"Type": "float",
"Nullable": "NO"
}
},
{
"OldColumn": "PumpPower",
"NewColumn": "PumpPower",
"Status": "matched",
"ColumnDef": {
"Name": "PumpPower",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "MassRepeats",
"NewColumn": "MassRepeats",
"Status": "matched",
"ColumnDef": {
"Name": "MassRepeats",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "MassSpread",
"NewColumn": "MassSpread",
"Status": "matched",
"ColumnDef": {
"Name": "MassSpread",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "MassMethod",
"NewColumn": "MassMethod",
"Status": "Changed",
"Note": "`MassMethod` tinyint(3) unsigned DEFAULT NULL,",
"ColumnDefList": [
{
"Name": "MassMethod",
"Type": "tinyint(1)",
"Nullable": "YES"
},
{
"Name": "MassMethod",
"Type": "tinyint(3)",
"Nullable": "YES"
}
]
},
{
"OldColumn": "TimeBeforeFlow",
"NewColumn": "TimeBeforeFlow",
"Status": "matched",
"ColumnDef": {
"Name": "TimeBeforeFlow",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeFlow2Mass",
"NewColumn": "TimeFlow2Mass",
"Status": "matched",
"ColumnDef": {
"Name": "TimeFlow2Mass",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeMass2Start",
"NewColumn": "TimePump2StartV",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "TimeMass2Start",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeStop2Mass",
"NewColumn": "TimeStop2Mass",
"Status": "matched",
"ColumnDef": {
"Name": "TimeStop2Mass",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Method",
"NewColumn": "Method",
"Status": "matched",
"ColumnDef": {
"Name": "Method",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ErrLimLo",
"NewColumn": "ErrLimLo",
"Status": "matched",
"ColumnDef": {
"Name": "ErrLimLo",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "ErrLimHi",
"NewColumn": "ErrLimHi",
"Status": "matched",
"ColumnDef": {
"Name": "ErrLimHi",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "Uncertainty",
"NewColumn": "Uncertainty",
"Status": "matched",
"ColumnDef": {
"Name": "Uncertainty",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "TolerRed",
"Status": "Deleted",
"ColumnDef": {
"Name": "TolerRed",
"Type": "double",
"Nullable": "YES"
}
},
{
"OldColumn": "RedType",
"Status": "Deleted",
"ColumnDef": {
"Name": "RedType",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "FeedingPath",
"NewColumn": "FeedingPath",
"Status": "matched",
"ColumnDef": {
"Name": "FeedingPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "BenchPath",
"NewColumn": "BenchPath",
"Status": "matched",
"ColumnDef": {
"Name": "BenchPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "OutputPath",
"NewColumn": "OutputPath",
"Status": "matched",
"ColumnDef": {
"Name": "OutputPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "MetersPath",
"NewColumn": "MetersPath",
"Status": "matched",
"ColumnDef": {
"Name": "MetersPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "HeatMetersPath",
"NewColumn": "HeatMetersPath",
"Status": "matched",
"ColumnDef": {
"Name": "HeatMetersPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransBefore",
"NewColumn": "TransBefore",
"Status": "Renamed",
"ColumnDef": {
"Name": "RelTransBefore",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransBetween",
"NewColumn": "TransBetween",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "RelTransBetween",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransAfter",
"NewColumn": "TransAfter",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "RelTransAfter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionAfter",
"Status": "Deleted",
"Note": "",
"ColumnDef": {
"Name": "TransitionAfter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Procedure_id",
"NewColumn": "Procedure_id",
"Status": "matched",
"ColumnDef": {
"Name": "Procedure_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
namespace tbfDBBackup.configuration;
public class Upgrade
{
public bool Enabled { get; set; }
public string Name { get; set; }
public string Query { get; set; }
public string JSONFileName { get; set; }
public string DatabaseName { get; set; }
public bool IsOneTimeOpaque { get; set; }
public override string ToString()
{
return $"Upgrade: {Name}";
}
}

View File

@ -0,0 +1,46 @@
{
"PathToDumpMysql": "C:\\xampp\\mysql\\bin",
"WaitOnEndCmdOpen": false,
"PrintConfigurationEnabled": false,
"DbConnectionStrings": [
{
"Name": "Settings DB",
"Connection": "SERVER=localhost; DATABASE={DatabaseName}; UID=root; PASSWORD=; CHARSET=utf8;",
"DatabaseName": "wrcswindon298",
"Enabled": true
}
],
"UpdateString": [
{
"Enabled": true,
"Name": "Alter table Water Meter",
"Query": "INSERT INTO `group` (Name, AccessFlags) VALUES ('MetrologicalAuthority', 0);\nINSERT INTO `group` (Name, AccessFlags) VALUES ('WaterMeterAuthority', 0);",
"DatabaseName": "wrcswindon298",
"IsOneTimeOpaque": true
},
{
"Enabled": true,
"Name": "Alter table Water Meter",
"Query": "INSERT INTO usersgroups (Group_id, User_id) VALUES (8, 1);\nINSERT INTO usersgroups (Group_id, User_id) VALUES (9, 1);",
"DatabaseName": "wrcswindon298",
"IsOneTimeOpaque": true
}
],
"UpgradeDatabase": [
{
"Enabled": true,
"Name": "Upgrade by JSON",
"Query": "",
"JSONFileName": "",
"DatabaseName": "wrcswindon298",
"IsOneTimeOpaque": true
},
{
"Enabled": true,
"Name": "Alter table Water Meter",
"Query": "INSERT INTO usersgroups (Group_id, User_id) VALUES (8, 1);\nINSERT INTO usersgroups (Group_id, User_id) VALUES (9, 1);",
"DatabaseName": "wrcswindon298",
"IsOneTimeOpaque": true
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

15879
tbfDBBackup/joinConfig/old.sql Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,815 @@
{
"Tables": [
{
"TableName": "procedure",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"IsPrimaryKey": true,
"Nullable": "NO"
}
},
{
"OldColumn": "ItemNr",
"NewColumn": "ItemNr",
"Status": "matched",
"ColumnDef": {
"Name": "ItemNr",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Name",
"NewColumn": "Name",
"Status": "matched",
"ColumnDef": {
"Name": "Name",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Description",
"NewColumn": "Description",
"Status": "matched",
"ColumnDef": {
"Name": "Description",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "CreationUser",
"NewColumn": "CreationUser",
"Status": "matched",
"ColumnDef": {
"Name": "CreationUser",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "CreationTime",
"NewColumn": "CreationTime",
"Status": "matched",
"ColumnDef": {
"Name": "CreationTime",
"Type": "datetime",
"Nullable": "YES"
}
},
{
"OldColumn": "LastChgUser",
"NewColumn": "LastChgUser",
"Status": "matched",
"ColumnDef": {
"Name": "LastChgUser",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "LastChgTime",
"NewColumn": "LastChgTime",
"Status": "matched",
"ColumnDef": {
"Name": "LastChgTime",
"Type": "datetime",
"Nullable": "YES"
}
},
{
"OldColumn": "LongDescription",
"NewColumn": "LongDescription",
"Status": "matched",
"ColumnDef": {
"Name": "LongDescription",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ProcedureState",
"NewColumn": "ProcedureState",
"Status": "matched",
"ColumnDef": {
"Name": "ProcedureState",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Revision",
"NewColumn": "Revision",
"Status": "matched",
"ColumnDef": {
"Name": "Revision",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "PredecessorId",
"NewColumn": "PredecessorId",
"Status": "matched",
"ColumnDef": {
"Name": "PredecessorId",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "ObtainedByCopy",
"NewColumn": "ObtainedByCopy",
"Status": "matched",
"ColumnDef": {
"Name": "ObtainedByCopy",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "MetersKind",
"NewColumn": "MetersKind",
"Status": "matched",
"ColumnDef": {
"Name": "MetersKind",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Watermeters",
"NewColumn": "Watermeters",
"Status": "matched",
"ColumnDef": {
"Name": "Watermeters",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ProtocolTitle",
"Status": "new",
"Note": "New",
"ColumnDef": {
"Name": "ProtocolTitle",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Protected",
"NewColumn": "Protected",
"Status": "matched",
"ColumnDef": {
"Name": "Protected",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "MustBeComplete",
"NewColumn": "MustBeComplete",
"Status": "matched",
"ColumnDef": {
"Name": "MustBeComplete",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "ManualCtrlDisabled",
"NewColumn": "ManualCtrlDisabled",
"Status": "matched",
"ColumnDef": {
"Name": "ManualCtrlDisabled",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "DataEntry",
"NewColumn": "DataEntry",
"Status": "matched",
"ColumnDef": {
"Name": "DataEntry",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ResultsPrinter",
"NewColumn": "ResultsPrinter",
"Status": "matched",
"ColumnDef": {
"Name": "ResultsPrinter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ResultsWriter",
"NewColumn": "ResultsWriter",
"Status": "matched",
"ColumnDef": {
"Name": "ResultsWriter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionStart",
"NewColumn": "TransitionStart",
"Status": "matched",
"ColumnDef": {
"Name": "TransitionStart",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionEnd",
"NewColumn": "TransitionEnd",
"Status": "matched",
"ColumnDef": {
"Name": "TransitionEnd",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "AltProcName",
"NewColumn": "AltProcName",
"Status": "matched",
"ColumnDef": {
"Name": "AltProcName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "AltProcPeriod",
"NewColumn": "AltProcPeriod",
"Status": "matched",
"ColumnDef": {
"Name": "AltProcPeriod",
"Type": "int(11)",
"Nullable": "NO"
}
}
],
"IsNewTable": false
},
{
"TableName": "test",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"IsPrimaryKey": true,
"Nullable": "NO"
}
},
{
"OldColumn": "ItemNr",
"NewColumn": "ItemNr",
"Status": "matched",
"ColumnDef": {
"Name": "ItemNr",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Name",
"NewColumn": "Name",
"Status": "matched",
"ColumnDef": {
"Name": "Name",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Part",
"NewColumn": "Part",
"Status": "matched",
"ColumnDef": {
"Name": "Part",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Publish",
"NewColumn": "Publish",
"Status": "matched",
"ColumnDef": {
"Name": "Publish",
"Type": "tinyint(4)",
"Nullable": "YES"
}
},
{
"OldColumn": "Evaluate",
"NewColumn": "DoEvaluate",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "Evaluate",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "Qfrom",
"NewColumn": "Qfrom",
"Status": "Change",
"Note": "Could be part of JSON or renamed",
"ColumnDefList": [{
"Name": "Qfrom",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Qfrom",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Qto",
"NewColumn": "Qto",
"Status": "Change",
"Note": "",
"ColumnDefList": [
{
"Name": "Qto",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Qto",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Volume",
"Status": "Change",
"Note": "",
"ColumnDefList": [
{
"Name": "Volume",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "Volume",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "TstTime",
"NewColumn": "TestTime",
"Status": "update",
"Note": "Could be part of JSON or renamed",
"ColumnDefList": [
{
"Name": "TstTime",
"Type": "float",
"Nullable": "YES"
},
{
"Name": "TestTime",
"Type": "double",
"Nullable": "YES"
}
]
},
{
"OldColumn": "Repeats",
"NewColumn": "Repeats",
"Status": "matched",
"ColumnDef": {
"Name": "Repeats",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Emptying",
"NewColumn": "DoDraining",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "Emptying",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "Zeroing",
"Status": "uncertain",
"Note": "Could be part of JSON or renamed",
"ColumnDef": {
"Name": "Zeroing",
"Type": "tinyint(1)",
"Nullable": "YES"
}
},
{
"OldColumn": "DoControlWaterTemp",
"Status": "uncertain",
"Note": "Could be part of JSON or renamed",
"ColumnDef": {
"Name": "DoControlWaterTemp",
"Type": "tinyint(1)",
"Nullable": "NO"
}
},
{
"OldColumn": "TempLimLo",
"NewColumn": "TempLimLo",
"Status": "matched",
"ColumnDef": {
"Name": "TempLimLo",
"Type": "float",
"Nullable": "NO"
}
},
{
"OldColumn": "TempLimHi",
"NewColumn": "TempLimHi",
"Status": "matched",
"ColumnDef": {
"Name": "TempLimHi",
"Type": "float",
"Nullable": "NO"
}
},
{
"OldColumn": "PumpPower",
"NewColumn": "PumpPower",
"Status": "matched",
"ColumnDef": {
"Name": "PumpPower",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "MassRepeats",
"NewColumn": "MassRepeats",
"Status": "matched",
"ColumnDef": {
"Name": "MassRepeats",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "MassSpread",
"NewColumn": "MassSpread",
"Status": "matched",
"ColumnDef": {
"Name": "MassSpread",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "MassMethod",
"NewColumn": "MassMethod",
"Status": "Changed",
"Note": "`MassMethod` tinyint(3) unsigned DEFAULT NULL,",
"ColumnDefList": [
{
"Name": "MassMethod",
"Type": "tinyint(1)",
"Nullable": "YES"
},
{
"Name": "MassMethod",
"Type": "tinyint(3)",
"Nullable": "YES"
}
]
},
{
"OldColumn": "TimeBeforeFlow",
"NewColumn": "TimeBeforeFlow",
"Status": "matched",
"ColumnDef": {
"Name": "TimeBeforeFlow",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeFlow2Mass",
"NewColumn": "TimeFlow2Mass",
"Status": "matched",
"ColumnDef": {
"Name": "TimeFlow2Mass",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeMass2Start",
"NewColumn": "TimePump2StartV",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "TimeMass2Start",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "TimeStop2Mass",
"NewColumn": "TimeStop2Mass",
"Status": "matched",
"ColumnDef": {
"Name": "TimeStop2Mass",
"Type": "int(11)",
"Nullable": "YES"
}
},
{
"OldColumn": "Method",
"NewColumn": "Method",
"Status": "matched",
"ColumnDef": {
"Name": "Method",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "ErrLimLo",
"NewColumn": "ErrLimLo",
"Status": "matched",
"ColumnDef": {
"Name": "ErrLimLo",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "ErrLimHi",
"NewColumn": "ErrLimHi",
"Status": "matched",
"ColumnDef": {
"Name": "ErrLimHi",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "Uncertainty",
"NewColumn": "Uncertainty",
"Status": "matched",
"ColumnDef": {
"Name": "Uncertainty",
"Type": "float",
"Nullable": "YES"
}
},
{
"OldColumn": "TolerRed",
"Status": "Deleted",
"ColumnDef": {
"Name": "TolerRed",
"Type": "double",
"Nullable": "YES"
}
},
{
"OldColumn": "RedType",
"Status": "Deleted",
"ColumnDef": {
"Name": "RedType",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "FeedingPath",
"NewColumn": "FeedingPath",
"Status": "matched",
"ColumnDef": {
"Name": "FeedingPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "BenchPath",
"NewColumn": "BenchPath",
"Status": "matched",
"ColumnDef": {
"Name": "BenchPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "OutputPath",
"NewColumn": "OutputPath",
"Status": "matched",
"ColumnDef": {
"Name": "OutputPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "MetersPath",
"NewColumn": "MetersPath",
"Status": "matched",
"ColumnDef": {
"Name": "MetersPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "HeatMetersPath",
"NewColumn": "HeatMetersPath",
"Status": "matched",
"ColumnDef": {
"Name": "HeatMetersPath",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransBefore",
"NewColumn": "TransBefore",
"Status": "Renamed",
"ColumnDef": {
"Name": "RelTransBefore",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransBetween",
"NewColumn": "TransBetween",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "RelTransBetween",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "RelTransAfter",
"NewColumn": "TransAfter",
"Status": "Renamed",
"Note": "",
"ColumnDef": {
"Name": "RelTransAfter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "TransitionAfter",
"Status": "Deleted",
"Note": "",
"ColumnDef": {
"Name": "TransitionAfter",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Procedure_id",
"NewColumn": "Procedure_id",
"Status": "matched",
"ColumnDef": {
"Name": "Procedure_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
},
{
"TableName": "componentprocedure",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"IsPrimaryKey": true,
"Nullable": "NO"
}
},
{
"OldColumn": "CmpntName",
"NewColumn": "CmpntName",
"Status": "matched",
"ColumnDef": {
"Name": "CmpntName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Parameters",
"NewColumn": "Parameters",
"Status": "matched",
"ColumnDef": {
"Name": "Parameters",
"Type": "varchar(8000)",
"Nullable": "YES"
}
},
{
"OldColumn": "Procedure_id",
"NewColumn": "Procedure_id",
"Status": "matched",
"ColumnDef": {
"Name": "Procedure_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
},
{
"TableName": "componenttest",
"ColumnMappings": [
{
"OldColumn": "Id",
"NewColumn": "Id",
"Status": "matched",
"ColumnDef": {
"Name": "Id",
"Type": "int(11)",
"IsPrimaryKey": true,
"Nullable": "NO"
}
},
{
"OldColumn": "CmpntName",
"NewColumn": "CmpntName",
"Status": "matched",
"ColumnDef": {
"Name": "CmpntName",
"Type": "varchar(255)",
"Nullable": "YES"
}
},
{
"OldColumn": "Parameters",
"NewColumn": "Parameters",
"Status": "matched",
"ColumnDef": {
"Name": "Parameters",
"Type": "varchar(8000)",
"Nullable": "YES"
}
},
{
"OldColumn": "Test_id",
"NewColumn": "Test_id",
"Status": "matched",
"ColumnDef": {
"Name": "Test_id",
"Type": "int(11)",
"Nullable": "YES"
}
}
],
"IsNewTable": false
}
]
}