示例#1
0
        /// <summary> Create a new <code>PatchTable</code>.
        /// 
        /// </summary>
        /// <param name="migrationContext">the migration configuration and connection source
        /// </param>
        /// <param name="connection">the database connection to use; this will NOT be closed
        /// </param>
        //UPGRADE_NOTE: There are other database providers or managers under System.Data namespace which can be used optionally to better fit the application requirements. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1208'"
        public PatchTable(IAdoMigrationContext migrationContext)
        {
            this.context = migrationContext;

            if (context.DatabaseType == null)
            {
                throw new System.ArgumentException("The ADO.NET database type is required");
            }
        }
 public TestAdoMigrationLauncher(IAdoMigrationContext context)
     : base(context)
 {
     // does nothing
 }
示例#3
0
        /// <summary>
        /// Parses the SQL (DML/DDL) to execute and returns a list of individual statements. For database
        /// types that support multiple statements in a single <code>Statement.execute</code> call,
        /// this method will return a one-element <code>List</code> containing the entire SQL
        /// file.
        /// </summary>
        /// <param name="context">
        /// the <code>IMigrationContext</code>, to figure out db type and if it can handle multiple
        /// statements at once
        /// </param>
        /// <returns>
        /// a list of SQL (DML/DDL) statements to execute
        /// </returns>
        public virtual IList<String> GetSqlStatements(IAdoMigrationContext context)
        {
            IList<String> statements = new List<String>();

            if (context.DatabaseType.MultipleStatementsSupported)
            {
                statements.Add(sql);
                return statements;
            }

            StringBuilder currentStatement = new StringBuilder();
            bool inQuotedString = false;
            bool inComment = false;
            char[] sqlChars = sql.ToCharArray();

            for (int i = 0; i < sqlChars.Length; i++)
            {
                if (sqlChars[i] == '\n')
                {
                    inComment = false;
                }

                if (!inComment)
                {
                    switch (sqlChars[i])
                    {

                        case '-':
                        case '/':
                            if (!inQuotedString && i + 1 < sqlChars.Length && sqlChars[i + 1] == sqlChars[i])
                            {
                                inComment = true;
                            }
                            else
                            {
                                currentStatement.Append(sqlChars[i]);
                            }
                            break;

                        case '\'':
                            inQuotedString = !inQuotedString;
                            currentStatement.Append(sqlChars[i]);
                            break;

                        case ';':
                            if (!inQuotedString)
                            {
                                // If we're in a stored procedure, just keep rolling
                                if (context.DatabaseType.getDatabaseType().Equals("oracle")
                                    && (currentStatement.ToString().Trim().ToLower().StartsWith("begin")
                                        || currentStatement.ToString().Trim().ToLower().StartsWith("create or replace method")
                                        || currentStatement.ToString().Trim().ToLower().StartsWith("create or replace function")
                                        || currentStatement.ToString().Trim().ToLower().StartsWith("create or replace procedure")
                                        || currentStatement.ToString().Trim().ToLower().StartsWith("create or replace package")))
                                {
                                    currentStatement.Append(sqlChars[i]);
                                }
                                else
                                {
                                    statements.Add(currentStatement.ToString().Trim());
                                    currentStatement = new StringBuilder();
                                }
                            }
                            else
                            {
                                currentStatement.Append(sqlChars[i]);
                            }
                            break;

                        default:
                            currentStatement.Append(sqlChars[i]);
                            break;

                    }
                }
            }

            if (currentStatement.ToString().Trim().Length > 0)
            {
                statements.Add(currentStatement.ToString().Trim());
            }

            return statements;
        }
 /// <seealso cref="AdoMigrationLauncher.AdoMigrationLauncher(IAdoMigrationContext)"/>
 public DistributedAdoMigrationLauncher(IAdoMigrationContext context)
     : base(context)
 {
 }
示例#5
0
        /// <summary>
        /// Lock the patch store. This is done safely, such that we safely handle the case where
        /// other migration launchers are patching at the same time.
        /// </summary>
        /// <param name="context">
        /// the context to lock the store in
        /// </param>
        /// <exception cref="MigrationException">
        /// if the reading or setting lock state fails
        /// </exception>
        private void LockPatchStore(IAdoMigrationContext context)
        {
            // Patch locks ensure that only one system sharing a patch store will patch
            // it at the same time.
            bool lockObtained = false;

            while (!lockObtained)
            {
                WaitForFreeLock(context);

                IPatchInfoStore piStore = contexts[context];
                int patchLevel = piStore.PatchLevel;

                try
                {
                    piStore.LockPatchStore();
                    lockObtained = true;
                }
                catch (Exception)
                {
                    // this happens when someone woke up at the same time,
                    // raced us to the lock and won. We re-sleep and try again.
                }
            }
        }
示例#6
0
        /// <summary>
        /// Pauses until the patch lock become available.
        /// </summary>
        /// <param name="context">
        /// the context related to the store
        /// </param>
        /// <exception cref="MigrationException">
        /// if an unrecoverable error occurs
        /// </exception>
        private void WaitForFreeLock(IAdoMigrationContext context)
        {
            IPatchInfoStore piStore = contexts[context];

            while (piStore.PatchStoreLocked)
            {
                log.Info("Waiting for migration lock for system \"" + context.SystemName + "\"");

                try
                {
                    Thread.Sleep(new TimeSpan(TimeSpan.TicksPerMillisecond * LockPollMillis));
                }
                catch (ThreadInterruptedException e)
                {
                    log.Error("Received ThreadInterruptedException while waiting for patch lock", e);
                }
            }
        }
示例#7
0
        /// <summary>
        /// Performs the application migration process in one go.
        /// </summary>
        /// <param name="context">
        /// the context to run the patches in
        /// </param>
        /// <returns>
        /// the number of patches applied
        /// </returns>
        /// <exception cref="DbException">
        /// if an unrecoverable database error occurs while working with the patches table
        /// </exception>
        /// <exception cref="MigrationException">
        /// if an unrecoverable error occurs during the migration
        /// </exception>
        protected virtual int DoMigrations(IAdoMigrationContext context)
        {
            IPatchInfoStore patchTable = CreatePatchStore(context);

            LockPatchStore(context);

            // Now apply the patches
            int executedPatchCount = 0;
            try
            {
                int patchLevel = patchTable.PatchLevel;

                executedPatchCount = migrationProcess.DoMigrations(patchLevel, context);
            }
            catch (MigrationException me)
            {
                // If there was any kind of error, we don't want to eat it, but we do
                // want to unlock the patch store. So do that, then re-throw.
                patchTable.UnlockPatchStore();
                throw me;
            }

            // Do any post-patch tasks
            try
            {
                migrationProcess.DoPostPatchMigrations(context);
                return executedPatchCount;
            }
            finally
            {
                try
                {
                    patchTable.UnlockPatchStore();
                }
                catch (MigrationException e)
                {
                    log.Error("Error unlocking patch table: ", e);
                }
            }
        }
示例#8
0
        /// <summary>
        /// Create a patch table object for use in migrations.
        /// </summary>
        /// <param name="context">
        /// the context to create the store in
        /// </param>
        /// <returns>
        /// a <code>PatchInfoStore</code> object for use in accessing patch state information
        /// </returns>
        /// <exception cref="MigrationException">
        /// if unable to create the store
        /// </exception>
        protected virtual IPatchInfoStore CreatePatchStore(IAdoMigrationContext context)
        {
            //IPatchInfoStore piStore = new PatchTable(context);

            // Make sure the table is created before claiming it exists by returning
            IPatchInfoStore piStore = contexts[context];
            int patchLevel = piStore.PatchLevel;

            return piStore;
        }
示例#9
0
 /// <summary>
 /// Get the patch level from the database.
 /// </summary>
 /// <param name="ctx">
 /// the migration context to get the patch level for
 /// </param>
 /// <returns>
 /// the current database patch level
 /// </returns>
 /// <exception cref="MigrationException">
 /// if there is a database connection error, or the patch level can't be determined
 /// </exception>
 public virtual int GetDatabasePatchLevel(IAdoMigrationContext ctx)
 {
     return contexts[ctx].PatchLevel;
 }
示例#10
0
 /// <summary>
 /// Adds an <code>IAdoMigrationContext</code> used for the migrations.
 /// </summary>
 /// <param name="context">
 /// the <code>IAdoMigrationContext</code> used for the migrations
 /// </param>
 public virtual void AddContext(IAdoMigrationContext context)
 {
     IPatchInfoStore patchTable = new PatchTable(context);
     log.Debug("Adding context " + context + " with patch table " + patchTable + " in launcher " + this);
     contexts.Add(context, patchTable);
 }
示例#11
0
 /// <summary>
 /// Create a new <code>AdoMigrationLauncher</code>.
 /// </summary>
 /// <param name="context">
 /// the <code>IAdoMigrationContext</code> to use
 /// </param>
 public AdoMigrationLauncher(IAdoMigrationContext context)
     : this()
 {
     AddContext(context);
 }