Exemple #1
0
        private PatchingUI(SqlConnectionStringBuilder builder, ITableRepository repository, Version databaseVersion, IPatcher patcher, Patch[] patchesInDatabase, SortedDictionary<string, Patch> allPatchesInAssembly)
        {
            _builder = builder;
            _repository = repository;
            _databaseVersion = databaseVersion;
            _patcher = patcher;
            
            InitializeComponent();

            if (_patcher == null)
                return;

            _hostAssemblyVersion = new Version(FileVersionInfo.GetVersionInfo(_patcher.GetDbAssembly().Location).FileVersion);
            _patchesInDatabase = patchesInDatabase;
            _allPatchesInAssembly = allPatchesInAssembly;
            
            lblPatchingAssembly.Text = patcher.GetDbAssembly().FullName;

            if (builder == null || string.IsNullOrWhiteSpace(builder.InitialCatalog))
            {
                lblDatabaseVersion.Text = "Form loaded without a specific database to target!";
                lblDatabaseVersion.ForeColor = Color.Red;
            }
            else
            {
                lblDatabaseVersion.Text = string.Format("{0}, Version:{1}", builder.InitialCatalog,repository.GetVersion());
            }

            

        }
Exemple #2
0
        private PatchingUI(DiscoveredDatabase database, ITableRepository repository, Version databaseVersion, IPatcher patcher, Patch[] patchesInDatabase, SortedDictionary <string, Patch> allPatchesInAssembly)
        {
            _database        = database;
            _repository      = repository;
            _databaseVersion = databaseVersion;
            _patcher         = patcher;

            InitializeComponent();

            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            {
                return;
            }

            _hostAssemblyVersion  = new Version(FileVersionInfo.GetVersionInfo(_patcher.GetDbAssembly().Location).FileVersion);
            _patchesInDatabase    = patchesInDatabase;
            _allPatchesInAssembly = allPatchesInAssembly;

            string name = patcher.Name + " v" + patcher.GetDbAssembly().GetName().Version.ToString(3);

            int numberOfPatchesToApply = _allPatchesInAssembly.Values.Except(_patchesInDatabase).Count();

            tbPatch.Text = $"{name} ({numberOfPatchesToApply} Patch{(numberOfPatchesToApply > 1 ? "es":"")})";

            if (_database == null)
            {
                tbDatabase.Text      = "Form loaded without a specific database to target!";
                tbDatabase.ForeColor = Color.Red;
            }
            else
            {
                tbDatabase.Text = string.Format("{0}, Version:{1}", _database.GetRuntimeName(), repository.GetVersion());
            }
        }
Exemple #3
0
        private PatchingUI(DiscoveredDatabase database, ITableRepository repository, IPatcher patcher)
        {
            _database   = database;
            _repository = repository;
            _patcher    = patcher;

            InitializeComponent();

            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            {
                return;
            }

            string name = patcher.Name + " v" + patcher.GetDbAssembly().GetName().Version.ToString(3);

            tbPatch.Text = $"{name}";

            if (_database == null)
            {
                tbDatabase.Text      = "Form loaded without a specific database to target!";
                tbDatabase.ForeColor = Color.Red;
            }
            else
            {
                tbDatabase.Text = string.Format("{0}, Version:{1}", _database.GetRuntimeName(), repository.GetVersion());
            }
        }
Exemple #4
0
        public static string GetInitialCreateScriptContents(IPatcher patcher)
        {
            var   assembly     = patcher.GetDbAssembly();
            var   subdirectory = patcher.ResourceSubdirectory;
            Regex initialCreationRegex;

            if (string.IsNullOrWhiteSpace(subdirectory))
            {
                initialCreationRegex = new Regex(@".*\.runAfterCreateDatabase\..*\.sql");
            }
            else
            {
                initialCreationRegex = new Regex(@".*\." + Regex.Escape(subdirectory) + @"\.runAfterCreateDatabase\..*\.sql");
            }

            var candidates = assembly.GetManifestResourceNames().Where(r => initialCreationRegex.IsMatch(r)).ToArray();

            if (candidates.Length == 1)
            {
                var sr = new StreamReader(assembly.GetManifestResourceStream(candidates[0]));
                return(sr.ReadToEnd());
            }

            if (candidates.Length == 0)
            {
                throw new FileNotFoundException("Could not find an initial create database script in dll " + assembly.FullName + ".  Make sure it is marked as an Embedded Resource and that it is in a folder called 'runAfterCreateDatabase' (and matches regex " + initialCreationRegex + "). And make sure that it is marked as 'Embedded Resource' in the .csproj build action");
            }

            throw new Exception("There are too many create scripts in the assembly " + assembly.FullName + " only 1 create database script is allowed, all other scripts must go into the up folder");
        }
Exemple #5
0
        public static SortedDictionary <string, Patch> GetAllPatchesInAssembly(IPatcher patcher)
        {
            var   assembly     = patcher.GetDbAssembly();
            var   subdirectory = patcher.ResourceSubdirectory;
            Regex upgradePatchesRegexPattern;

            if (string.IsNullOrWhiteSpace(subdirectory))
            {
                upgradePatchesRegexPattern = new Regex(@".*\.up\.(.*\.sql)");
            }
            else
            {
                upgradePatchesRegexPattern = new Regex(@".*\." + Regex.Escape(subdirectory) + @"\.up\.(.*\.sql)");
            }

            var files = new SortedDictionary <string, Patch>();

            //get all resources out of
            foreach (string manifestResourceName in assembly.GetManifestResourceNames())
            {
                var match = upgradePatchesRegexPattern.Match(manifestResourceName);
                if (match.Success)
                {
                    string fileContents = new StreamReader(assembly.GetManifestResourceStream(manifestResourceName)).ReadToEnd();
                    files.Add(match.Groups[1].Value, new Patch(match.Groups[1].Value, fileContents));
                }
            }

            return(files);
        }
        public override Image GetImage(IIconProvider iconProvider)
        {
            if (_patcher != null)
            {
                var basicIcon = _databaseIconProvider.GetIconForAssembly(_patcher.GetDbAssembly());
                return(_overlayProvider.GetOverlay(basicIcon, OverlayKind.Add));
            }

            return(iconProvider.GetImage(RDMPConcept.ExternalDatabaseServer, OverlayKind.Add));
        }
Exemple #7
0
        public static PatchingState IsPatchingRequired(DiscoveredDatabase database, IPatcher patcher, out Version databaseVersion, out Patch[] patchesInDatabase, out SortedDictionary <string, Patch> allPatchesInAssembly)
        {
            databaseVersion = DatabaseVersionProvider.GetVersionFromDatabase(database);

            MasterDatabaseScriptExecutor scriptExecutor = new MasterDatabaseScriptExecutor(database);

            patchesInDatabase = scriptExecutor.GetPatchesRun();

            allPatchesInAssembly = patcher.GetAllPatchesInAssembly(database);

            AssemblyName databaseAssemblyName = patcher.GetDbAssembly().GetName();

            if (databaseAssemblyName.Version < databaseVersion)
            {
                return(PatchingState.SoftwareBehindDatabase);
            }

            //if there are patches that have not been applied
            return
                (allPatchesInAssembly.Values
                 .Except(patchesInDatabase)
                 .Any() ? PatchingState.Required:PatchingState.NotRequired);
        }
Exemple #8
0
        public static PatchingState IsPatchingRequired(SqlConnectionStringBuilder builder, IPatcher patcher, out Version databaseVersion, out Patch[] patchesInDatabase, out SortedDictionary <string, Patch> allPatchesInAssembly)
        {
            databaseVersion = DatabaseVersionProvider.GetVersionFromDatabase(builder);

            MasterDatabaseScriptExecutor scriptExecutor = new MasterDatabaseScriptExecutor(builder.DataSource, builder.InitialCatalog, builder.UserID, builder.Password);

            patchesInDatabase = scriptExecutor.GetPatchesRun();

            allPatchesInAssembly = GetAllPatchesInAssembly(patcher);

            AssemblyName databaseAssemblyName = patcher.GetDbAssembly().GetName();

            if (databaseAssemblyName.Version < databaseVersion)
            {
                return(PatchingState.SoftwareBehindDatabase);
            }

            //if there are patches that have not been applied
            return
                (allPatchesInAssembly.Values
                 .Except(patchesInDatabase)
                 .Any() ? PatchingState.Required:PatchingState.NotRequired);
        }
Exemple #9
0
        private void btnAttemptPatching_Click(object sender, EventArgs e)
        {
            bool stop = false;

            //start with the assumption that we will apply all patches
            SortedDictionary <string, Patch> toApply = new SortedDictionary <string, Patch>();

            foreach (Patch potentialInstallable in _allPatchesInAssembly.Values.Except(_patchesInDatabase))
            {
                toApply.Add(potentialInstallable.locationInAssembly, potentialInstallable);
            }

            var listener = new ToMemoryCheckNotifier(checksUI1);

            checksUI1.BeginUpdate();
            try
            {
                //make sure the existing patches in the live database are not freaky phantom patches
                foreach (Patch patch in _patchesInDatabase)
                {
                    //if patch is not in database assembly
                    if (!_allPatchesInAssembly.Any(a => a.Value.Equals(patch)))
                    {
                        listener.OnCheckPerformed(new CheckEventArgs(
                                                      "The database contains an unexplained patch called " + patch.locationInAssembly +
                                                      " (it is not in " + _patcher.GetDbAssembly().FullName + " ) so how did it get there?", CheckResult.Warning,
                                                      null));
                    }
                    else if (!_allPatchesInAssembly[patch.locationInAssembly].GetScriptBody().Equals(patch.GetScriptBody()))
                    {
                        listener.OnCheckPerformed(new CheckEventArgs(
                                                      "The contents of patch " + patch.locationInAssembly +
                                                      " are different between live database and the database patching assembly", CheckResult.Warning,
                                                      null));

                        //do not apply this patch
                        toApply.Remove(patch.locationInAssembly);
                    }
                    else
                    {
                        //we found it and it was intact
                        listener.OnCheckPerformed(new CheckEventArgs("Patch " + patch.locationInAssembly + " was previously installed successfully so no need to touch it", CheckResult.Success, null));

                        //do not apply this patch
                        toApply.Remove(patch.locationInAssembly);
                    }
                }
            }
            catch (Exception exception)
            {
                listener.OnCheckPerformed(new CheckEventArgs("Patch evaluation failed", CheckResult.Fail, exception));
                stop = true;
            }
            finally
            {
                checksUI1.EndUpdate();
            }


            //if any of the patches we are trying to apply are earlier than the latest in the database
            IEnumerable <Patch> missedOppertunities = toApply.Values.Where(p => p.DatabaseVersionNumber < _patchesInDatabase.Max(p2 => p2.DatabaseVersionNumber));

            foreach (Patch missedOppertunity in missedOppertunities)
            {
                stop = true;
                listener.OnCheckPerformed(new CheckEventArgs(
                                              "Patch " + missedOppertunity.locationInAssembly +
                                              " cannot be applied because it's version number is " + missedOppertunity.DatabaseVersionNumber +
                                              " but the current database is at version " + _databaseVersion
                                              + Environment.NewLine
                                              + " Contents of patch was:" + Environment.NewLine + missedOppertunity.EntireScript
                                              , CheckResult.Fail, null));
            }

            //if the patches to be applied would bring the version number above that of the host Library
            foreach (Patch futurePatch in toApply.Values.Where(patch => patch.DatabaseVersionNumber > _hostAssemblyVersion))
            {
                listener.OnCheckPerformed(new CheckEventArgs(
                                              "Cannot apply patch " + futurePatch.locationInAssembly + " because it's database version number is " + futurePatch.DatabaseVersionNumber + " which is higher than the currently loaded host assembly (" + _patcher.GetDbAssembly().FullName + "). ", CheckResult.Fail, null));
                stop = true;
            }


            if (stop)
            {
                listener.OnCheckPerformed(new CheckEventArgs("Abandonning patching process (no patches have been applied) because of one or more previous errors", CheckResult.Fail, null));
                return;
            }
            try
            {
                MasterDatabaseScriptExecutor executor = new MasterDatabaseScriptExecutor(_database);

                //todo: Only ms has a backup implementation in FAnsi currently
                bool backupDatabase = _database.Server.DatabaseType == DatabaseType.MicrosoftSQLServer &&
                                      MessageBox.Show("Backup Database First", "Backup", MessageBoxButtons.YesNo) ==
                                      DialogResult.Yes;

                executor.PatchDatabase(toApply, listener, PreviewPatch, backupDatabase);

                //if it crashed during patching
                if (listener.GetWorst() == CheckResult.Fail)
                {
                    btnAttemptPatching.Enabled = true;
                    return;
                }

                listener.OnCheckPerformed(new CheckEventArgs("Patching completed without exception, disabling the patching button", CheckResult.Success, null));
                //patching worked so prevent them doing it again!
                btnAttemptPatching.Enabled = false;

                if (_repository != null)
                {
                    _repository.ClearUpdateCommandCache();
                    checksUI1.OnCheckPerformed(new CheckEventArgs("Cleared UPDATE commands cache", CheckResult.Success, null));
                }

                checksUI1.OnCheckPerformed(new CheckEventArgs("Patching Succesful", CheckResult.Success, null));

                if (MessageBox.Show("Application will now restart", "Close?", MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    Application.Restart();
                }
            }
            catch (Exception exception)
            {
                checksUI1.OnCheckPerformed(new CheckEventArgs("Patching failed", CheckResult.Fail, exception));
            }
        }