Exemplo n.º 1
0
 public IEnumerable<string> GenerateUpdateSql(DatabaseInventory inventory, int currentVersion)
 {
     if (inventory == null) {
         throw new ArgumentNullException("inventory");
     }
     SetQualification(inventory.SchemaName);
     inventory.SetQualification(inventory.SchemaName);
     try {
         DependencyResolver resolver = new DependencyResolver();
         List<IInstallStatement> alterUsingUpdateScript = new List<IInstallStatement>();
         Dictionary<string, IScriptableStatement> dropStatements = new Dictionary<string, IScriptableStatement>(StringComparer.OrdinalIgnoreCase);
         HashSet<string> newObjectNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
         HashSet<string> refreshObjectNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
         refreshObjectNames.UnionWith(inventory.Objects.OfType<CreateViewStatement>().Where(v => !(v.ViewOption is OptionSchemabindingToken)).Select(v => v.ObjectName));
         // refreshObjectNames.UnionWith(inventory.Objects.OfType<CreateFunctionStatement>().Where(f => !(f.Option is OptionSchemabindingToken)).Select(f => f.ObjectName));
         foreach (KeyValuePair<IAlterableCreateStatement, InventoryObjectDifference> pair in Compare(inventory, this, inventory.TargetEngine)) {
             switch (pair.Value) {
             case InventoryObjectDifference.None:
                 resolver.AddExistingObject(pair.Key.ObjectName);
                 break;
             case InventoryObjectDifference.Different:
                 if (pair.Key.AlterUsingUpdateScript) {
                     alterUsingUpdateScript.Add(pair.Key);
                 } else {
                     AlterTableAddConstraintFragment alterConstraint = pair.Key as AlterTableAddConstraintFragment;
                     if (alterConstraint != null) {
                         dropStatements.Add(pair.Key.ObjectName, pair.Key.CreateDropStatement());
                         resolver.Add(pair.Key);
                     } else {
                         if (pair.Key.DisableUsagesForUpdate) {
                             Debug.Assert(!(pair.Key is CreateTableFragment)); // we must not wrap those - but they shouldn't return true for this flag
                             resolver.Add(new DependencyDisablingAlterStatement(pair.Key.CreateAlterStatement()));
                         } else {
                             resolver.Add(pair.Key.CreateAlterStatement());
                         }
                     }
                     refreshObjectNames.Remove(pair.Key.ObjectName);
                 }
                 break;
             case InventoryObjectDifference.SourceOnly:
                 dropStatements.Add(pair.Key.ObjectName, pair.Key.CreateDropStatement());
                 refreshObjectNames.Remove(pair.Key.ObjectName);
                 break;
             case InventoryObjectDifference.TargetOnly:
                 resolver.Add(pair.Key);
                 if (pair.Key.IsPartOfSchemaDefinition) {
                     newObjectNames.Add(pair.Key.ObjectName);
                 }
                 break;
             }
         }
         StringBuilder builder = new StringBuilder(4096);
         // first drop table constraints and indices (if any)
         foreach (AlterTableDropConstraintStatement dropStatement in dropStatements.Values.OfType<AlterTableDropConstraintStatement>()) {
             yield return WriteStatement(dropStatement, builder, inventory.TargetEngine);
         }
         foreach (DropIndexStatement dropStatement in dropStatements.Values.OfType<DropIndexStatement>()) {
             yield return WriteStatement(dropStatement, builder, inventory.TargetEngine);
         }
         // now perform all possible actions which do not rely on tables which are altered
         HashSet<string> createdTables = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
         foreach (IInstallStatement statement in resolver.GetInOrder(false)) {
             CreateTableFragment createTable = statement as CreateTableFragment;
             if (createTable != null) {
                 yield return WriteStatement(createTable.Owner.CreateStatementFragments(CreateFragmentMode.CreateOnExistingSchema).OfType<CreateTableFragment>().Single(), builder, inventory.TargetEngine);
                 createdTables.Add(createTable.ObjectName);
             } else if (!statement.IsTableUniqueConstraintOfTables(createdTables)) {
                 foreach (IInstallStatement innerStatement in HandleDependendObjects(statement, inventory, dropStatements.Keys)) {
                     yield return WriteStatement(innerStatement, builder, inventory.TargetEngine);
                 }
             }
         }
         // then perform updates (if any)
         HashSet<string> droppedTables = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
         foreach (KeyValuePair<int, IScriptableStatement[]> update in updateStatements.Where(u => u.Key > currentVersion)) {
             foreach (IScriptableStatement statement in update.Value) {
                 DropTableStatement dropTable = statement as DropTableStatement;
                 if (dropTable != null) {
                     droppedTables.Add(dropTable.ObjectName);
                 }
                 yield return WriteStatement(statement, builder, inventory.TargetEngine);
             }
         }
         // now that the update scripts have updated the tables, mark the tables in the dependency resolver
         foreach (IInstallStatement createTableStatement in alterUsingUpdateScript) {
             resolver.AddExistingObject(createTableStatement.ObjectName);
         }
         // refresh the views and functions
         foreach (string objectName in refreshObjectNames) {
             yield return string.Format("EXEC [sp_refreshsqlmodule] '[{0}].[{1}]'", inventory.SchemaName, objectName);
         }
         // try to perform the remaining actions
         foreach (IInstallStatement statement in resolver.GetInOrder(true).Where(statement => !(statement.IsTableUniqueConstraintOfTables(createdTables) || statement.DependsOnTables(droppedTables)))) {
             foreach (IInstallStatement innerStatement in HandleDependendObjects(statement, inventory, dropStatements.Keys)) {
                 yield return WriteStatement(innerStatement, builder, inventory.TargetEngine);
             }
         }
         // execute insert statements for table setup data
         if (AdditionalSetupStatements.Any()) {
             bool disabledChecks = false;
             foreach (IScriptableStatement statement in AdditionalSetupStatements) {
                 Qualified<SchemaName, TableName> name = null;
                 InsertStatement insertStatement = statement as InsertStatement;
                 if (insertStatement != null) {
                     DestinationRowset<Qualified<SchemaName, TableName>> targetTable = insertStatement.DestinationRowset as DestinationRowset<Qualified<SchemaName, TableName>>;
                     if (targetTable != null) {
                         name = targetTable.Name;
                     }
                 } else {
                     SetIdentityInsertStatement setIdentityInsertStatement = statement as SetIdentityInsertStatement;
                     if (setIdentityInsertStatement != null) {
                         name = setIdentityInsertStatement.TableName;
                     }
                 }
                 if ((name != null) && name.IsQualified && string.Equals(name.Qualification.Value, inventory.SchemaName, StringComparison.OrdinalIgnoreCase) && newObjectNames.Contains(name.Name.Value)) {
                     if (!disabledChecks) {
                         foreach (CreateTableStatement table in Objects.OfType<CreateTableStatement>()) {
                             yield return WriteStatement(new AlterTableNocheckConstraintStatement(table.TableName, new TableCheckToken()), builder, inventory.TargetEngine);
                         }
                         disabledChecks = true;
                     }
                     yield return WriteStatement(statement, builder, inventory.TargetEngine);
                 }
             }
             if (disabledChecks) {
                 foreach (CreateTableStatement table in Objects.OfType<CreateTableStatement>()) {
                     yield return WriteStatement(new AlterTableCheckConstraintStatement(table.TableName, new TableWithCheckToken()), builder, inventory.TargetEngine);
                 }
             }
         }
         // finally drop objects which are no longer used
         foreach (IScriptableStatement dropStatement in dropStatements.Values.Where(s => !(s is AlterTableDropConstraintStatement || s is DropTableStatement || s is DropIndexStatement || s.DependsOnTables(droppedTables)))) {
             yield return WriteStatement(dropStatement, builder, inventory.TargetEngine);
         }
         // refresh the SPs
         foreach (string objectName in Objects.OfType<CreateProcedureStatement>().Where(sp => !(sp.Option is OptionSchemabindingToken)).Select(sp => sp.ObjectName)) {
             yield return string.Format("EXEC [sp_refreshsqlmodule] '[{0}].[{1}]'", inventory.SchemaName, objectName);
         }
     } finally {
         UnsetQualification();
         inventory.UnsetQualification();
     }
 }
 public IEnumerable<string> GenerateInstallSql(DatabaseEngine targetEngine, string schemaName, string ownerName)
 {
     if (string.IsNullOrEmpty(schemaName)) {
         throw new ArgumentNullException("schemaName");
     }
     bool newSchema = !schemaName.Equals("dbo", StringComparison.OrdinalIgnoreCase);
     StringBuilder builder = new StringBuilder(4096);
     DependencyResolver resolver = new DependencyResolver();
     IEnumerable<IAlterableCreateStatement> createStatements = Objects.SelectMany(o => o.CreateStatementFragments(newSchema ? CreateFragmentMode.CreateOnNewSchema : CreateFragmentMode.CreateOnExistingSchema)).Where(s => s.DoesApplyToEngine(targetEngine));
     if (newSchema) {
         SetQualification(null);
         try {
             using (StringWriter writer = new StringWriter(builder)) {
                 SqlWriter sqlWriter = new SqlWriter(writer, targetEngine);
                 sqlWriter.WriteKeyword("CREATE SCHEMA");
                 using (sqlWriter.Indent()) {
                     sqlWriter.WriteScript(new SchemaName(schemaName), WhitespacePadding.SpaceBefore);
                     if (!string.IsNullOrEmpty(ownerName)) {
                         sqlWriter.Write(" AUTHORIZATION");
                         sqlWriter.WriteScript(new ObjectName(ownerName), WhitespacePadding.SpaceBefore);
                     }
                     DependencyResolver schemaResolver = new DependencyResolver();
                     foreach (IAlterableCreateStatement statement in createStatements) {
                         if (statement.IsPartOfSchemaDefinition) {
                             if (statement is CreateTableFragment) {
                                 sqlWriter.WriteLine();
                                 statement.WriteTo(sqlWriter);
                                 resolver.AddExistingObject(statement.ObjectName);
                                 schemaResolver.AddExistingObject(statement.ObjectName);
                             } else {
                                 schemaResolver.Add(statement);
                             }
                         } else {
                             resolver.Add(statement);
                         }
                     }
                     try {
                         foreach (IInstallStatement statement in schemaResolver.GetInOrder(true)) {
                             sqlWriter.WriteLine();
                             statement.WriteTo(sqlWriter);
                             resolver.AddExistingObject(statement.ObjectName);
                         }
                     } catch (InvalidOperationException ex) {
                         schemaResolver.TransferPendingObjects(resolver);
                         log.DebugFormat("SCHEMA CREATE trimmed because of {0} - processing continues", ex, ex.Message);
                     }
                 }
                 yield return writer.ToString();
             }
         } finally {
             UnsetQualification();
         }
     } else {
         foreach (IAlterableCreateStatement statement in createStatements) {
             resolver.Add(statement);
         }
     }
     SetQualification(schemaName);
     try {
         foreach (IInstallStatement statement in resolver.GetInOrder(true)) {
             yield return WriteStatement(statement, builder, targetEngine);
         }
         if (AdditionalSetupStatements.Any()) {
             foreach (CreateTableStatement table in Objects.OfType<CreateTableStatement>()) {
                 yield return WriteStatement(new AlterTableNocheckConstraintStatement(table.TableName, new TableCheckToken()), builder, targetEngine);
             }
             foreach (IScriptableStatement additionalSetupStatement in AdditionalSetupStatements) {
                 yield return WriteStatement(additionalSetupStatement, builder, targetEngine);
             }
             foreach (CreateTableStatement table in Objects.OfType<CreateTableStatement>()) {
                 yield return WriteStatement(new AlterTableCheckConstraintStatement(table.TableName, new TableWithCheckToken()), builder, targetEngine);
             }
         }
     } finally {
         UnsetQualification();
     }
 }