Example #1
0
        public override void Perform(SchemaChanges changes, IOutput output)
        {
            foreach (var pending in PendingReorderTableType.AllFrom(changes.Current))
            {
                var originalTable = TableType.Identifier(pending.Name);
                var tempTable     = pending.ParentIdentifier;

                if (object.Equals(originalTable, tempTable))
                {
                    // If the database fails at precisely the wrong time, the rename can be succeed without dropping the PendingReorder,
                    // so the table thinks it's to be renamed to itself. In that case we need to drop the PendingReorder, NOT drop the table!
                    output.Verbose("Cleaning up after completed reorder of columns in " + originalTable);
                    changes.Remove(null, pending);
                }
                else if (changes.Current.ContainsRoot(originalTable))
                {
                    // If the original table still exists, we drop the temp table so we can start over (in case the data in the table has changed since the temp table
                    // was created, or the reordering has somehow become unnecessary).
                    output.Verbose("Clearing pending reorder of columns in " + originalTable);
                    changes.Remove(changes.SchemaDriver.GetDropTableSql(pending.ParentName), changes.Current.GetRoot(pending.ParentIdentifier));
                }
                else
                {
                    // The original table has been dropped so we need to recreate it by renaming the temp table.
                    output.Verbose("Completing pending reordering of columns in " + originalTable);
                    changes.Rename(changes.SchemaDriver.GetRenameTableSql(tempTable.Name, originalTable.Name), tempTable, originalTable);

                    // And forget about the pending rename.
                    changes.Remove(null, pending.WithParent(originalTable));
                }
            }
        }
Example #2
0
        private void renameTempTables(SchemaChanges changes, IOutput output)
        {
            // For any PendingReorderTables where the original table doesn't exist, rename the table to the target name and remove the pending rename.
            foreach (var pending in PendingReorderTableType.AllFrom(changes.Current))
            {
                var originalTable = TableType.Identifier(pending.Name);
                var tempTable     = pending.ParentIdentifier;

                if (changes.Current.ContainsRoot(originalTable))
                {
                    continue;
                }

                changes.Rename(changes.SchemaDriver.GetRenameTableSql(tempTable.Name, originalTable.Name), tempTable, originalTable);
                changes.Remove(null, pending.WithParent(originalTable));
            }
        }
Example #3
0
        private void dropOriginalTables(SchemaChanges changes, IOutput output)
        {
            // For any tables that are the target of existing PendingReorderTables, drop them (without prompting).
            foreach (var pending in PendingReorderTableType.AllFrom(changes.Current))
            {
                var originalTable = TableType.Identifier(pending.Name);
                var tempTable     = pending.ParentIdentifier;

                if (!changes.Current.ContainsRoot(originalTable))
                {
                    continue;
                }

                // FIXME: (Consider sanity checks before doing this - anything from "confirm all the right column names exist" to "confirm the right number of rows exist" to
                // "confirm all the data is identical in all the rows")
                changes.Remove(changes.SchemaDriver.GetDropTableSql(originalTable.Name), changes.Current.GetRoot(originalTable));
            }
        }
Example #4
0
        public override void Perform(SchemaChanges changes, IOutput output)
        {
            var pendingReorders = PendingReorderTableType.AllFrom(changes.Current);

            foreach (var desired in TableType.AllFrom(changes.Desired))
            {
                if (changes.Current.Contains(desired))
                {
                    continue;
                }

                var fields        = FieldType.ChildrenFrom(changes.Desired, desired.Identifier);
                var fieldCreation = from field in fields
                                    orderby field.State.OrdinalPosition
                                    select new FieldCreation(field.Name, field.State.DataType, field.State.IsNullable, field.State.IsSequencedPkey, field.State.SequenceName);

                changes.Put(changes.SchemaDriver.GetCreateTableSql(desired.Name, fieldCreation),
                            new ObjectState[] { desired }.Concat(fields));
            }
        }
Example #5
0
        private void createTempTables(SchemaChanges changes, IOutput output)
        {
            // For any tables with order-sensitivity and fields in different order between current and desired (ignoring fields that only exist in current),
            // Create a new table  "_nrdo_reorder" using "select (columns in correct order followed by columns to be dropped) from original table into newname"
            // Put the table, the fields (with nullability, datatype and identityness as current but in new order) and a PendingReorderTable into current
            // For any tables that need their fields reordered, create a copy of the table with the fields in the right order.
            foreach (var origTable in TableType.AllFrom(changes.Current))
            {
                // Tables that don't exist in desired state are to be dropped, they certainly don't need to be reordered!
                if (!changes.Desired.Contains(origTable))
                {
                    continue;
                }

                // Figure out whether a reorder is needed
                if (!FieldType.IsFieldReorderNeeded(changes, origTable.Identifier))
                {
                    continue;
                }

                // Put the fields in order.
                // At this point there may be extra fields that are to be dropped but haven't been yet. They need to stick around until
                // it's time to drop them, because before statements may rely on them. But we put those ones last (in the order they're currently in).
                var fieldsInOrder = from field in FieldType.ChildrenFrom(changes.Current, origTable.Identifier)
                                    let desired = changes.Desired.Get(field)
                                                  orderby
                                                  desired != null ? desired.State.OrdinalPosition : int.MaxValue,
                    field.State.OrdinalPosition
                select field;

                // Construct the state representation that will be used for the new table.
                // It inherits all before statements from the original table so that when it's renamed they'll still be there.
                // FIXME: This hardcodes the assumption that CreateTableAsSelect preserves field type, nullability and identity-ness, which may or may not be true on other DBs
                // FIXME: any other aspects of field state that we add support for (Default values, check constraints...) need to get dropped here.
                var tempTable       = TableType.Create(origTable.Name + "_nrdo_reorder");
                var pendingReorder  = PendingReorderTableType.Create(tempTable.Identifier, origTable.Name);
                var tempTableFields = from fi in fieldsInOrder.Select((field, index) => new { field, index })
                                      select fi.field
                                      .WithParent(tempTable.Identifier)
                                      .With(s => s.WithOrdinalPosition(fi.index));

                var tempTableBefores = from before in BeforeStatementType.ChildrenFrom(changes.Current, origTable.Identifier)
                                       select before.WithParent(tempTable.Identifier);

                // Gather all temporary objects into one list to put them into the database together
                var tempTableObjects =
                    new ObjectState[]
                {
                    tempTable,
                    pendingReorder
                }
                .Concat(tempTableFields)
                .Concat(tempTableBefores);

                var sql = changes.SchemaDriver.GetCreateTableAsSelectSql(tempTable.Name,
                                                                         string.Join(", ", from field in fieldsInOrder select changes.DbDriver.QuoteIdentifier(field.Name)),
                                                                         changes.DbDriver.QuoteSchemaIdentifier(origTable.Name));

                changes.Put(sql, tempTableObjects);
            }
        }