Пример #1
0
        private void EnsureNoTriggerOnTable(DiscoveredTable tbl)
        {
            var triggerFactory = new TriggerImplementerFactory(tbl.Database.Server.DatabaseType);

            var triggerImplementer = triggerFactory.Create(tbl);

            if (triggerImplementer.GetTriggerStatus() != TriggerStatus.Missing)
            {
                throw new NotSupportedException("Table " + _tableInfo + " has a backup trigger on it, this will destroy performance and break when we add the ANOColumn, dropping the trigger is not an option because of the _Archive table still containing identifiable data (and other reasons)");
            }
        }
Пример #2
0
        /// <summary>
        /// Sets up a CHI/ECHI mapping table with fallback guid and populates each table with a single record.
        /// 0101010101 is a known CHI and 0202020202 is an known one (which was assigned a temporary guid mapping).
        /// Also prepares the main map table for DLE loading (<see cref="TriggerImplementer"/>)
        /// </summary>
        /// <param name="dbType"></param>
        /// <param name="map"></param>
        /// <param name="guidTable"></param>
        /// <param name="mapperOptions"></param>
        /// <param name="guids">true to create a <see cref="TableLookupWithGuidFallbackSwapper"/> otherwise creates a  <see cref="TableLookupSwapper"/></param>
        private void SetupMappers(DatabaseType dbType, out DiscoveredTable map, out DiscoveredTable guidTable, out IdentifierMapperOptions mapperOptions, bool guids = true)
        {
            var db = GetCleanedServer(dbType);

            using (var dt = new DataTable())
            {
                dt.Columns.Add("CHI");
                dt.Columns.Add("ECHI");

                dt.PrimaryKey = new [] { dt.Columns["CHI"] };

                dt.Rows.Add("0101010101", "0A0A0A0A0A");
                map = db.CreateTable("Map", dt);
            }

            mapperOptions = new IdentifierMapperOptions()
            {
                MappingTableName        = map.GetFullyQualifiedName(),
                MappingConnectionString = db.Server.Builder.ConnectionString,
                SwapColumnName          = "CHI",
                ReplacementColumnName   = "ECHI",
                MappingDatabaseType     = db.Server.DatabaseType,
                SwapperType             = (guids ? typeof(TableLookupWithGuidFallbackSwapper):typeof(TableLookupSwapper)).FullName
            };

            if (guids)
            {
                var swapper = new TableLookupWithGuidFallbackSwapper();
                swapper.Setup(mapperOptions);

                guidTable = swapper.GetGuidTableIfAny(mapperOptions);
                Assert.AreEqual(0, guidTable.GetRowCount(), "No temporary guids should exist yet");
                Assert.AreEqual(1, map.GetRowCount(), "We should have a mapping table with 1 entry");

                //lookup an as yet unknown value
                swapper.GetSubstitutionFor("0202020202", out _);

                Assert.AreEqual(1, map.GetRowCount(), "We should have a mapping table with 1 entry");
                Assert.AreEqual(1, guidTable.GetRowCount(), "We should have a temporary guid for 0202020202");
            }
            else
            {
                guidTable = null;
            }

            // make a fake data load into this table (create trigger and insert/update)
            var triggerImplementer = new TriggerImplementerFactory(dbType).Create(map);

            triggerImplementer.CreateTrigger(new ThrowImmediatelyCheckNotifier());
        }
Пример #3
0
        public void TestCheckUpdateTrigger()
        {
            // set SetUp a test database
            const string tableName = "TestTable";
            var          db        = GetCleanedServer(FAnsi.DatabaseType.MicrosoftSQLServer);

            var databaseName = db.GetRuntimeName();
            var table        = db.CreateTable(tableName, new[] { new DatabaseColumnRequest("Id", "int"), });

            var server = db.Server;

            using (var con = server.GetConnection())
            {
                con.Open();
                var cmd = server.GetCommand(
                    "CREATE TRIGGER dbo.[TestTable_OnUpdate] ON [dbo].[" + tableName +
                    "] AFTER DELETE AS RAISERROR('MESSAGE',16,10)", con);

                cmd.ExecuteNonQuery();
            }

            var dbInfo = DiscoveredServerICanCreateRandomDatabasesAndTablesOn.ExpectDatabase(databaseName);

            var factory = new TriggerImplementerFactory(dbInfo.Server.DatabaseType);

            var triggerImplementer = factory.Create(table);
            var isEnabled          = triggerImplementer.GetTriggerStatus();

            Assert.AreEqual(TriggerStatus.Enabled, isEnabled);


            // disable the trigger and test correct reporting
            using (var con = new SqlConnection(dbInfo.Server.Builder.ConnectionString))
            {
                con.Open();
                var cmd =
                    new SqlCommand(
                        "USE [" + databaseName + "]; DISABLE TRIGGER TestTable_OnUpdate ON [" + databaseName + "]..[" +
                        tableName + "]", con);
                cmd.ExecuteNonQuery();
            }

            isEnabled = triggerImplementer.GetTriggerStatus();
            Assert.AreEqual(TriggerStatus.Disabled, isEnabled);
        }
        public ExecuteCommandAlterTableAddArchiveTrigger(IBasicActivateItems activator, TableInfo tableInfo) : base(activator, tableInfo)
        {
            if (IsImpossible)
            {
                return;
            }

            if (!Table.DiscoverColumns().Any(c => c.IsPrimaryKey))
            {
                SetImpossible(GlobalStrings.TableHasNoPrimaryKey);
                return;
            }

            var factory = new TriggerImplementerFactory(TableInfo.DatabaseType);

            _triggerImplementer = factory.Create(Table);
            var currentStatus = _triggerImplementer.GetTriggerStatus();

            if (currentStatus != TriggerStatus.Missing)
            {
                SetImpossible(GlobalStrings.TriggerStatusIsCurrently, currentStatus.S());
            }
        }
Пример #5
0
        public ExecuteCommandAlterTableAddArchiveTrigger(IActivateItems activator, TableInfo tableInfo) : base(activator, tableInfo)
        {
            if (IsImpossible)
            {
                return;
            }

            if (!Table.DiscoverColumns().Any(c => c.IsPrimaryKey))
            {
                SetImpossible("Table has no Primary Key");
                return;
            }

            var factory = new TriggerImplementerFactory(TableInfo.DatabaseType);

            _triggerImplementer = factory.Create(Table);
            var currentStatus = _triggerImplementer.GetTriggerStatus();

            if (currentStatus != TriggerStatus.Missing)
            {
                SetImpossible("Trigger status is currently:" + currentStatus);
            }
        }
Пример #6
0
        public void TestCreateTableInSchemaAndImportAsTableInfo()
        {
            var db = GetCleanedServer(DatabaseType.MicrosoftSQLServer);

            using (var con = db.Server.GetConnection())
            {
                con.Open();

                db.Server.GetCommand("CREATE SCHEMA Omg", con).ExecuteNonQuery();

                var tbl = db.CreateTable("Fish", new [] { new DatabaseColumnRequest("MyCol", "int")
                                                          {
                                                              IsPrimaryKey = true
                                                          } }, schema: "Omg");

                Assert.AreEqual("Fish", tbl.GetRuntimeName());
                Assert.AreEqual("Omg", tbl.Schema);
                Assert.IsTrue(tbl.GetFullyQualifiedName().EndsWith("[Omg].[Fish]"));

                Assert.IsTrue(tbl.Exists());

                TableInfo    ti;
                ColumnInfo[] cols;
                Import(tbl, out ti, out cols);

                Assert.AreEqual("Omg", ti.Schema);
                var tbl2 = ti.Discover(DataAccessContext.InternalDataProcessing);
                Assert.AreEqual("Omg", tbl2.Schema);
                Assert.IsTrue(tbl2.Exists());

                Assert.IsTrue(ti.Name.EndsWith("[Omg].[Fish]"));

                Assert.IsTrue(ti.GetFullyQualifiedName().EndsWith("[Omg].[Fish]"));

                var c = cols.Single();

                Assert.AreEqual("MyCol", c.GetRuntimeName());
                StringAssert.Contains("[Omg].[Fish]", c.GetFullyQualifiedName());

                //should be primary key
                Assert.IsTrue(c.IsPrimaryKey);

                var triggerFactory = new TriggerImplementerFactory(DatabaseType.MicrosoftSQLServer);
                var impl           = triggerFactory.Create(tbl);

                Assert.AreEqual(TriggerStatus.Missing, impl.GetTriggerStatus());

                impl.CreateTrigger(new ThrowImmediatelyCheckNotifier());

                Assert.AreEqual(TriggerStatus.Enabled, impl.GetTriggerStatus());

                Assert.IsTrue(impl.CheckUpdateTriggerIsEnabledAndHasExpectedBody());

                //should be synced
                var sync = new TableInfoSynchronizer(ti);
                sync.Synchronize(new AcceptAllCheckNotifier());

                //Test importing the _Legacy table valued function that should be created in the Omg schema and test synching that too.
                var tvf = ti.Discover(DataAccessContext.InternalDataProcessing).Database.ExpectTableValuedFunction("Fish_Legacy", "Omg");
                Assert.IsTrue(tvf.Exists());

                var          importerTvf = new TableValuedFunctionImporter(CatalogueRepository, tvf);
                TableInfo    tvfTi;
                ColumnInfo[] tvfCols;
                importerTvf.DoImport(out tvfTi, out tvfCols);

                Assert.AreEqual("Omg", tvfTi.Schema);

                var syncTvf = new TableInfoSynchronizer(tvfTi);
                syncTvf.Synchronize(new ThrowImmediatelyCheckNotifier());

                StringAssert.EndsWith("[Omg].Fish_Legacy(@index) AS Fish_Legacy", tvfTi.Name);
            }
        }
Пример #7
0
        public void TestMerge(DatabaseType databaseType)
        {
            //microsoft one gets called for free in test setup (see base class)
            if (databaseType != DatabaseType.MicrosoftSQLServer)
            {
                SetupFromTo(databaseType);
            }

            var dt      = new DataTable();
            var colName = new DataColumn("Name", typeof(string));
            var colAge  = new DataColumn("Age", typeof(int));

            dt.Columns.Add(colName);
            dt.Columns.Add(colAge);
            dt.Columns.Add("Postcode", typeof(string));

            //Data in live awaiting toTbl be updated
            dt.Rows.Add(new object[] { "Dave", 18, "DD3 1AB" });
            dt.Rows.Add(new object[] { "Dave", 25, "DD1 1XS" });
            dt.Rows.Add(new object[] { "Mango", 32, DBNull.Value });
            dt.Rows.Add(new object[] { "Filli", 32, "DD3 78L" });
            dt.Rows.Add(new object[] { "Mandrake", 32, DBNull.Value });

            dt.PrimaryKey = new[] { colName, colAge };

            var toTbl = To.CreateTable("ToTable", dt);

            Assert.IsTrue(toTbl.DiscoverColumn("Name").IsPrimaryKey);
            Assert.IsTrue(toTbl.DiscoverColumn("Age").IsPrimaryKey);
            Assert.IsFalse(toTbl.DiscoverColumn("Postcode").IsPrimaryKey);

            dt.Rows.Clear();

            //new data being loaded
            dt.Rows.Add(new object[] { "Dave", 25, "DD1 1PS" });       //update toTbl change postcode toTbl "DD1 1PS"
            dt.Rows.Add(new object[] { "Chutney", 32, DBNull.Value }); //new insert Chutney
            dt.Rows.Add(new object[] { "Mango", 32, DBNull.Value });   //ignored because already present in dataset
            dt.Rows.Add(new object[] { "Filli", 32, DBNull.Value });   //update from "DD3 78L" null
            dt.Rows.Add(new object[] { "Mandrake", 32, "DD1 1PS" });   //update from null toTbl "DD1 1PS"
            dt.Rows.Add(new object[] { "Mandrake", 31, "DD1 1PS" });   // insert because Age is unique (and part of pk)

            var fromTbl = From.CreateTable(DatabaseName + "_ToTable_STAGING", dt);

            //import the toTbl table as a TableInfo
            TableInfo ti;

            ColumnInfo[] cis;
            var          cata = Import(toTbl, out ti, out cis);

            //put the backup trigger on the live table (this will also create the needed hic_ columns etc)
            var triggerImplementer = new TriggerImplementerFactory(databaseType).Create(toTbl);

            triggerImplementer.CreateTrigger(new ThrowImmediatelyCheckNotifier());

            var configuration = new MigrationConfiguration(From, LoadBubble.Staging, LoadBubble.Live,
                                                           new FixedStagingDatabaseNamer(toTbl.Database.GetRuntimeName(), fromTbl.Database.GetRuntimeName()));

            var lmd = new LoadMetadata(CatalogueRepository);

            cata.LoadMetadata_ID = lmd.ID;
            cata.SaveToDatabase();

            var migrationHost = new MigrationHost(From, To, configuration, new HICDatabaseConfiguration(lmd));

            //set SetUp a logging task
            var logServer  = new ServerDefaults(CatalogueRepository).GetDefaultFor(PermissableDefaults.LiveLoggingServer_ID);
            var logManager = new LogManager(logServer);

            logManager.CreateNewLoggingTaskIfNotExists("CrossDatabaseMergeCommandTest");
            var dli = logManager.CreateDataLoadInfo("CrossDatabaseMergeCommandTest", "tests", "running test", "", true);

            var job = new ThrowImmediatelyDataLoadJob();

            job.DataLoadInfo        = dli;
            job.RegularTablesToLoad = new List <ITableInfo>(new[] { ti });

            migrationHost.Migrate(job, new GracefulCancellationToken());

            var resultantDt = toTbl.GetDataTable();

            Assert.AreEqual(7, resultantDt.Rows.Count);

            AssertRowEquals(resultantDt, "Dave", 25, "DD1 1PS");
            AssertRowEquals(resultantDt, "Chutney", 32, DBNull.Value);
            AssertRowEquals(resultantDt, "Mango", 32, DBNull.Value);

            AssertRowEquals(resultantDt, "Filli", 32, DBNull.Value);
            AssertRowEquals(resultantDt, "Mandrake", 32, "DD1 1PS");
            AssertRowEquals(resultantDt, "Mandrake", 31, "DD1 1PS");

            AssertRowEquals(resultantDt, "Dave", 18, "DD3 1AB");


            var archival = logManager.GetArchivalDataLoadInfos("CrossDatabaseMergeCommandTest", new CancellationToken());
            var log      = archival.First();


            Assert.AreEqual(dli.ID, log.ID);
            Assert.AreEqual(2, log.TableLoadInfos.Single().Inserts);
            Assert.AreEqual(3, log.TableLoadInfos.Single().Updates);
        }
Пример #8
0
        public void MapperSource_IntegrationTest(DatabaseType dbType)
        {
            var db = GetCleanedServer(dbType);

            DataTable dt = new DataTable();

            dt.Columns.Add("PatientID", typeof(string));
            dt.Columns.Add("StudyDescription", typeof(string));
            dt.SetDoNotReType(true);

            // We have a live table with anonymised data.  There is one person with a known ECHI 0101010101=0A0A0A0A0A
            dt.Rows.Add("0A0A0A0A0A", "CT Head");

            //There are 2 people for whome we have added temporary identifiers
            dt.Rows.Add("bbb-bbb-bbb", "CT Tail");
            dt.Rows.Add("ccc-ccc-ccc", "CT Wings");

            var liveTable = db.CreateTable("MyLiveTable", dt);

            DiscoveredTable map;

            using (var dtMap = new DataTable())
            {
                dtMap.Columns.Add("CHI");
                dtMap.Columns.Add("ECHI");

                dtMap.PrimaryKey = new [] { dtMap.Columns["CHI"] };

                dtMap.Rows.Add("0101010101", "0A0A0A0A0A");
                map = db.CreateTable("Map", dtMap);
            }

            // Import into RDMP the live table so we have a TableInfo pointer to it floating around
            Import(liveTable);

            var mapperOptions = new IdentifierMapperOptions()
            {
                MappingTableName        = map.GetFullyQualifiedName(),
                MappingConnectionString = db.Server.Builder.ConnectionString,
                SwapColumnName          = "CHI",
                ReplacementColumnName   = "ECHI",
                MappingDatabaseType     = db.Server.DatabaseType,
                SwapperType             = typeof(TableLookupWithGuidFallbackSwapper).FullName
            };

            var swapper = new TableLookupWithGuidFallbackSwapper();

            swapper.Setup(mapperOptions);

            var guidTable = swapper.GetGuidTableIfAny(mapperOptions);

            Assert.AreEqual(0, guidTable.GetRowCount(), "No temporary guids should exist yet");
            Assert.AreEqual(1, map.GetRowCount(), "We should have a mapping table with 1 entry");

            guidTable.Insert(new Dictionary <string, object>()
            {
                { "CHI", "0202020202" },
                { TableLookupWithGuidFallbackSwapper.GuidColumnName, "bbb-bbb-bbb" }
            });
            guidTable.Insert(new Dictionary <string, object>()
            {
                { "CHI", "0303030303" },
                { TableLookupWithGuidFallbackSwapper.GuidColumnName, "ccc-ccc-ccc" }
            });

            Assert.AreEqual(1, map.GetRowCount(), "We should have a mapping table with 1 entry");
            Assert.AreEqual(2, guidTable.GetRowCount(), "We should have a temporary guid for 0202020202");

            // make a fake data load into this table (create trigger and insert/update)
            var triggerImplementer = new TriggerImplementerFactory(dbType).Create(map);

            triggerImplementer.CreateTrigger(new ThrowImmediatelyCheckNotifier());

            //create a brand new mapping
            map.Insert(new Dictionary <string, object>()
            {
                { "CHI", "0303030303" },
                { "ECHI", "0C0C0C0C0C" },
                { SpecialFieldNames.ValidFrom, DateTime.Now },
                { SpecialFieldNames.DataLoadRunID, 55 },
            });

            var globals = new GlobalOptionsFactory().Load();

            var cliOptions = new TriggerUpdatesFromMapperOptions()
            {
                DateOfLastUpdate      = new DateTime(2020, 01, 01),
                LiveDatabaseFieldName = "PatientID",
                Qualifier             = '\'',
            };

            globals.UseTestValues(
                RequiresRabbit.GetConnectionFactory(),
                RequiresMongoDb.GetMongoClientSettings(),
                RequiresRelationalDb.GetRelationalDatabaseConnectionStrings(),
                ((TableRepository)RepositoryLocator.CatalogueRepository).ConnectionStringBuilder,
                ((TableRepository)RepositoryLocator.DataExportRepository).ConnectionStringBuilder);


            //make sure the identifier mapper goes to the right table
            globals.IdentifierMapperOptions.MappingConnectionString = db.Server.Builder.ConnectionString;
            globals.IdentifierMapperOptions.MappingDatabaseType     = dbType;
            globals.IdentifierMapperOptions.MappingTableName        = map.GetFullyQualifiedName();
            globals.IdentifierMapperOptions.SwapperType             = typeof(TableLookupWithGuidFallbackSwapper).FullName;

            using (var tester = new MicroserviceTester(globals.RabbitOptions, globals.CohortExtractorOptions))
            {
                tester.CreateExchange(globals.TriggerUpdatesOptions.ExchangeName, globals.UpdateValuesOptions.QueueName);

                var sourceHost = new TriggerUpdatesHost(globals, new MapperSource(globals, cliOptions));
                var destHost   = new UpdateValuesHost(globals);

                sourceHost.Start();
                tester.StopOnDispose.Add(sourceHost);

                destHost.Start();
                tester.StopOnDispose.Add(destHost);


                //wait till updater is done updating the live table
                new TestTimelineAwaiter().Await(() => destHost.Consumer.AckCount == 1);
            }

            var liveDtAfter = liveTable.GetDataTable();

            Assert.AreEqual(1, liveDtAfter.Rows.Cast <DataRow>().Count(r => (string)r["PatientID"] == "0A0A0A0A0A"), "Expected original data to still be intact");
            Assert.AreEqual(1, liveDtAfter.Rows.Cast <DataRow>().Count(r => (string)r["PatientID"] == "bbb-bbb-bbb"), "Expected unknown CHI with guid bbb to still be unknown");
            Assert.AreEqual(1, liveDtAfter.Rows.Cast <DataRow>().Count(r => (string)r["PatientID"] == "0C0C0C0C0C"), "Expected the unknown CHI ccc to be now known as 0C0C0C0C0C");
        }
Пример #9
0
        public void TriggerImplementationTest(DatabaseType type)
        {
            var db  = GetCleanedServer(type);
            var tbl = db.CreateTable("MyTable", new[]
            {
                new DatabaseColumnRequest("name", new DatabaseTypeRequest(typeof(string), 30), false),
                new DatabaseColumnRequest("bubbles", new DatabaseTypeRequest(typeof(int)))
            });

            var factory     = new TriggerImplementerFactory(type);
            var implementer = factory.Create(tbl);

            Assert.AreEqual(TriggerStatus.Missing, implementer.GetTriggerStatus());

            Assert.AreEqual(2, tbl.DiscoverColumns().Length);

            implementer = factory.Create(tbl);

            //no primary keys
            Assert.Throws <TriggerException>(() => implementer.CreateTrigger(new ThrowImmediatelyCheckNotifier()));

            tbl.CreatePrimaryKey(tbl.DiscoverColumn("name"));

            implementer = factory.Create(tbl);

            implementer.CreateTrigger(new ThrowImmediatelyCheckNotifier());

            Assert.AreEqual(4, tbl.DiscoverColumns().Length);

            var archiveTable = tbl.Database.ExpectTable(tbl.GetRuntimeName() + "_Archive");

            Assert.IsTrue(archiveTable.Exists());

            Assert.AreEqual(7, archiveTable.DiscoverColumns().Count());

            Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("name")));
            Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("bubbles")));
            Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("hic_dataLoadrunID", StringComparison.CurrentCultureIgnoreCase)));
            Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("hic_validFrom", StringComparison.CurrentCultureIgnoreCase)));
            Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("hic_validTo", StringComparison.CurrentCultureIgnoreCase)));
            Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("hic_userID", StringComparison.CurrentCultureIgnoreCase)));
            Assert.AreEqual(1, archiveTable.DiscoverColumns().Count(c => c.GetRuntimeName().Equals("hic_status")));

            //is the trigger now existing
            Assert.AreEqual(TriggerStatus.Enabled, implementer.GetTriggerStatus());

            //does it function as expected
            using (var con = tbl.Database.Server.GetConnection())
            {
                con.Open();
                var cmd = tbl.Database.Server.GetCommand(string.Format("INSERT INTO {0}(name,bubbles) VALUES('bob',1)", tbl.GetRuntimeName()), con);
                cmd.ExecuteNonQuery();

                Assert.AreEqual(1, tbl.GetRowCount());
                Assert.AreEqual(0, archiveTable.GetRowCount());

                cmd = tbl.Database.Server.GetCommand(string.Format("UPDATE {0} set bubbles=2", tbl.GetRuntimeName()), con);
                cmd.ExecuteNonQuery();

                Assert.AreEqual(1, tbl.GetRowCount());
                Assert.AreEqual(1, archiveTable.GetRowCount());

                var archive = archiveTable.GetDataTable();
                var dr      = archive.Rows.Cast <DataRow>().Single();

                Assert.AreEqual(((DateTime)dr["hic_validTo"]).Date, DateTime.Now.Date);
            }

            //do the strict check too
            Assert.IsTrue(implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody());

            tbl.AddColumn("amagad", new DatabaseTypeRequest(typeof(float), null, new DecimalSize(2, 2)), true, 30);
            implementer = factory.Create(tbl);

            Assert.Throws <IrreconcilableColumnDifferencesInArchiveException>(() => implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody());

            archiveTable.AddColumn("amagad", new DatabaseTypeRequest(typeof(float), null, new DecimalSize(2, 2)), true, 30);

            var checks = new TriggerChecks(tbl);

            checks.Check(new AcceptAllCheckNotifier());

            Assert.IsTrue(implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody());


            //does it function as expected
            using (var con = tbl.Database.Server.GetConnection())
            {
                con.Open();

                Assert.AreEqual(1, tbl.GetRowCount());
                Assert.AreEqual(1, archiveTable.GetRowCount());

                var cmd = tbl.Database.Server.GetCommand(string.Format("UPDATE {0} set amagad=1.0", tbl.GetRuntimeName()), con);
                cmd.ExecuteNonQuery();

                cmd = tbl.Database.Server.GetCommand(string.Format("UPDATE {0} set amagad=.09", tbl.GetRuntimeName()), con);
                cmd.ExecuteNonQuery();

                Assert.AreEqual(1, tbl.GetRowCount());
                Assert.AreEqual(3, archiveTable.GetRowCount());

                var archive = archiveTable.GetDataTable();
                Assert.AreEqual(1, archive.Rows.Cast <DataRow>().Count(r => Equals(r["amagad"], (decimal)1.00)));
                Assert.AreEqual(2, archive.Rows.Cast <DataRow>().Count(r => r["amagad"] == DBNull.Value));
            }

            string problems;
            string worked;

            implementer.DropTrigger(out problems, out worked);

            Assert.IsTrue(string.IsNullOrEmpty(problems));

            Assert.AreEqual(TriggerStatus.Missing, implementer.GetTriggerStatus());
        }
        public void TestAddTag_WithArchive(DatabaseType type)
        {
            var db = GetCleanedServer(type);

            // Create a nice template with lots of columns
            var template = new ImageTableTemplate();

            template.TableName = "Fish";
            template.Columns   = new[]
            {
                new ImageColumnTemplate {
                    IsPrimaryKey = true, AllowNulls = true, ColumnName = "RelativeFileArchiveURI"
                },
                new ImageColumnTemplate {
                    IsPrimaryKey = false, AllowNulls = true, ColumnName = "SeriesInstanceUID"
                },
                new ImageColumnTemplate {
                    IsPrimaryKey = false, AllowNulls = true, ColumnName = "StudyDate"
                },
            };

            // use it to create a table
            var            tbl = db.ExpectTable(template.TableName);
            IAtomicCommand cmd = new ExecuteCommandCreateNewImagingDataset(RepositoryLocator, tbl, template);

            Assert.IsFalse(cmd.IsImpossible);
            cmd.Execute();

            Assert.IsTrue(tbl.Exists());

            // import RDMP reference to the table
            var importer = new TableInfoImporter(CatalogueRepository, tbl);

            importer.DoImport(out TableInfo ti, out ColumnInfo[] cols);

            var forward = new ForwardEngineerCatalogue(ti, cols);

            forward.ExecuteForwardEngineering(out Catalogue catalogue, out _, out _);

            // Create an archive table and backup trigger like we would have if this were the target of a data load
            var triggerImplementerFactory = new TriggerImplementerFactory(type);
            var implementer = triggerImplementerFactory.Create(tbl);

            implementer.CreateTrigger(new ThrowImmediatelyCheckNotifier());

            var archive = tbl.Database.ExpectTable(tbl.GetRuntimeName() + "_Archive");

            Assert.IsTrue(archive.Exists());

            var activator = new ConsoleInputManager(RepositoryLocator, new ThrowImmediatelyCheckNotifier())
            {
                DisallowInput = true
            };

            // Test the actual commands
            cmd = new ExecuteCommandAddTag(activator, catalogue, "ffffff", "int");
            Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible);
            cmd.Execute();

            cmd = new ExecuteCommandAddTag(activator, catalogue, "EchoTime", null);
            Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible);
            cmd.Execute();

            var ex = Assert.Throws <Exception>(() => new ExecuteCommandAddTag(activator, catalogue, "StudyDate", null).Execute());

            StringAssert.StartsWith("Failed check with message: There is already a column called 'StudyDate' in TableInfo ", ex.Message);

            cmd = new ExecuteCommandAddTag(activator, catalogue, "SeriesDate", null);
            Assert.IsFalse(cmd.IsImpossible, cmd.ReasonCommandImpossible);
            cmd.Execute();

            Assert.AreEqual("int", tbl.DiscoverColumn("ffffff").DataType.SQLType);
            Assert.AreEqual("decimal(38,19)", tbl.DiscoverColumn("EchoTime").DataType.SQLType);
            Assert.AreEqual(typeof(DateTime), tbl.DiscoverColumn("SeriesDate").DataType.GetCSharpDataType());

            Assert.AreEqual("int", archive.DiscoverColumn("ffffff").DataType.SQLType);
            Assert.AreEqual("decimal(38,19)", archive.DiscoverColumn("EchoTime").DataType.SQLType);
            Assert.AreEqual(typeof(DateTime), archive.DiscoverColumn("SeriesDate").DataType.GetCSharpDataType());
        }
Пример #11
0
        ///<inheritdoc/>
        public void Check(ICheckNotifier notifier)
        {
            if (_table.Exists() && _archiveTable.Exists())
            {
                string[] liveCols    = _table.DiscoverColumns().Select(c => c.GetRuntimeName()).ToArray();
                string[] archiveCols = _archiveTable.DiscoverColumns().Select(c => c.GetRuntimeName()).ToArray();

                var passed = CheckColumnOrderInTablesAndArchiveMatch(liveCols, archiveCols, notifier);

                if (!passed)
                {
                    return;
                }
            }

            var factory     = new TriggerImplementerFactory(_server.DatabaseType);
            var implementer = factory.Create(_table);

            bool present;

            var primaryKeys = _table.DiscoverColumns().Where(c => c.IsPrimaryKey).ToArray();

            //we don't know the primary keys
            if (!primaryKeys.Any())
            {
                try
                {
                    //see if it exists
                    present = implementer.GetTriggerStatus() == TriggerStatus.Enabled;
                }
                catch (TriggerMissingException)
                {
                    //clearly it doesnt exist
                    present = false;
                }
            }
            else
            {
                try
                {
                    //we do know the primary keys
                    present = implementer.CheckUpdateTriggerIsEnabledAndHasExpectedBody();
                }
                catch (IrreconcilableColumnDifferencesInArchiveException e)
                {
                    notifier.OnCheckPerformed(
                        new CheckEventArgs(
                            "Archive table for table " + _table +
                            " is corrupt, see inner Exception for specific errors", CheckResult.Fail, e));
                    return;
                }
                catch (Exception e)
                {
                    NotifyFail(e, notifier, implementer);
                    return;
                }
            }

            if (present)
            {
                notifier.OnCheckPerformed(new CheckEventArgs("Trigger presence/intactness for table " + _table + " matched expected presence", CheckResult.Success, null));
            }
            else
            {
                NotifyFail(null, notifier, implementer); //try creating it
            }
        }