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)); } } }
public override void Perform(SchemaChanges changes, IOutput output) { if (changes.Options.FieldDropBehavior == DropBehavior.SkipDrop) { return; } var errorResponse = changes.Options.FieldDropBehavior == DropBehavior.TryDrop ? ErrorResponse.Ignore : ErrorResponse.Fail; foreach (var current in FieldType.AllFrom(changes.Current)) { if (changes.Desired.Contains(current)) { continue; } // If we're going to drop the whole table then don't bother dropping the field if (!changes.Desired.ContainsRoot(current.ParentIdentifier)) { continue; } if (!changes.AllowDropWithPossibleDataLoss(current, changes.Options.FieldDropBehavior)) { continue; } changes.Remove(changes.SchemaDriver.GetDropFieldSql(current.ParentName, current.Name), current); } }
public override void Perform(SchemaChanges changes, IOutput output) { // This isn't really anything to do with pre-upgrade-hooks but there's no other good place to give this warning! foreach (var query in QueryType.AllFrom(changes.Current)) { if (query.State != null && query.State.Body.StartsWith("<FAIL>")) { output.Warning(query.State.Body.Substring(6)); } } foreach (var hook in PreUpgradeHookType.AllFrom(changes.Current)) { var proc = QueryType.GetFrom(changes.Current, hook.ParentIdentifier); if (proc.State == null || proc.State is QueryType.FunctionState || proc.State.Parameters.Any()) { output.Warning("Cannot execute pre-upgrade hook " + proc.Name + ": stored procedure does not exist or has parameters."); } changes.Put(changes.SchemaDriver.GetExecuteProcSql(hook.ParentName)); if (changes.Desired.Get(hook) == null) { changes.Remove(null, hook); } } }
public override void Perform(SchemaChanges changes, IOutput output) { foreach (var current in TriggerType.AllFrom(changes.Current)) { if (!TriggerType.TriggerHasChanged(changes, current)) { continue; } changes.Remove(changes.SchemaDriver.GetDropTriggerSql(current.ParentName, current.Name), current); } }
public override void Perform(SchemaChanges changes, IOutput output) { foreach (var current in SequenceType.AllFrom(changes.Current)) { if (changes.Desired.Contains(current)) { continue; } changes.Remove(changes.SchemaDriver.GetDropSequenceSql(current.Name), current); } }
public override void Perform(SchemaChanges changes, IOutput output) { foreach (var current in ViewType.AllFrom(changes.Current)) { var desired = changes.Desired.Get(current); if (desired != null && ViewType.IsEqual(current.State, desired.State, changes.DbDriver)) { continue; } changes.Remove(changes.SchemaDriver.GetDropViewSql(current.Name), current); } }
public override void Perform(SchemaChanges changes, IOutput output) { // This step covers both unique keys (including primary keys) and non-unique indexes foreach (var current in UniqueIndexType.AllFrom(changes.Current)) { if (!UniqueIndexType.IndexHasChanged(changes, current)) { continue; } changes.Remove(changes.SchemaDriver.GetDropUniqueConstraintSql(current.ParentName, current.Name), current); } foreach (var current in NonUniqueIndexType.AllFrom(changes.Current)) { if (!NonUniqueIndexType.IndexHasChanged(changes, current)) { continue; } changes.Remove(changes.SchemaDriver.GetDropIndexSql(current.ParentName, current.Name), current); } }
public override void Perform(SchemaChanges changes, IOutput output) { foreach (var current in QueryType.AllFrom(changes.Current)) { // Queries that are neither stored proc or stored function in the current schema don't need to be dropped! if (current.State == null) { continue; } var desired = changes.Desired.Get(current); if (desired != null) { if (changes.SchemaDriver.IsCreateOrReplaceProcSupported) { // If CREATE OR REPLACE PROCEDURE is supported in the current database, there's no need to drop it unless // it's changed from function to procedure or vice versa. if (QueryType.IsTypeEqual(current.State, desired.State)) { continue; } } else { // Even if CREATE OR REPLACE PROCEDURE is not supported, we don't need to drop it if it's // not changed at all. if (QueryType.IsEqual(current.State, desired.State, changes.DbDriver)) { continue; } } } var dropSql = current.State is QueryType.FunctionState ? changes.SchemaDriver.GetDropFunctionSql(current.Name) : changes.SchemaDriver.GetDropProcSql(current.Name); if (desired != null) { // The query isn't going away entirely so we don't want to lose its associated before statements changes.Put(dropSql, QueryType.CreateUnstored(current.Name)); } else { changes.Remove(dropSql, current); } } }
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)); } }
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)); } }
public override void Perform(SchemaChanges changes, IOutput output) { foreach (var current in FieldType.AllFrom(changes.Current)) { var desired = FieldType.GetDesired(changes, current); // At this point we are only dropping changed fields, not fields that are being // removed entirely, which we keep around til later to allow them to be used by // before statements for migration. So we only want to drop fields that conflict // with fields in the eventual state of the table (including the conflict // that would occur if two identity fields existed in the same table). if (desired == null && !isSequencedPkeyToBeDropped(changes, current)) { continue; } // If the type and sequenced-ness are unchanged then we don't need to do anything here. if (desired != null && FieldType.IsTypeEqual(current.State, desired.State, changes.SchemaDriver.IsSequencedPartOfFieldDeclaration)) { continue; } // Fields being dropped here need to be replaced later, so failing to drop them has to be fatal regardless of FieldDropBehavior if (!changes.AllowDropWithPossibleDataLoss(current, DropBehavior.Drop)) { continue; } // If we are about to drop the last field from a table, add a temporary field so that the drop will be allowed if (FieldType.ChildrenFrom(changes.Current, current.ParentIdentifier).Count() == 1) { var placeholder = FieldType.Create(current.ParentIdentifier, "nrdo_placeholder_field", 2, "int", true); changes.Put(changes.SchemaDriver.GetAddFieldSql(placeholder.ParentName, placeholder.Name, placeholder.State.DataType, false, null), placeholder); if (changes.HasFailed) { continue; } } // Drop the field changes.Remove(changes.SchemaDriver.GetDropFieldSql(current.ParentName, current.Name), current); } }
public override void Perform(SchemaChanges changes, IOutput output) { if (changes.Options.TableDropBehavior == DropBehavior.SkipDrop) { return; } var errorResponse = changes.Options.TableDropBehavior == DropBehavior.TryDrop ? ErrorResponse.Ignore : ErrorResponse.Fail; foreach (var current in TableType.AllFrom(changes.Current)) { if (changes.Desired.Contains(current)) { continue; } if (!changes.AllowDropWithPossibleDataLoss(current, changes.Options.TableDropBehavior)) { continue; } // Drop the table changes.Remove(changes.SchemaDriver.GetDropTableSql(current.Name), errorResponse, current); } }