From a524ea2fbc30463b024bbbc764623040d31265c0 Mon Sep 17 00:00:00 2001 From: Max Obrist Date: Wed, 13 Jun 2018 19:43:17 +0200 Subject: [PATCH 1/9] Added functions to ScriptAll --- DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs index 20fa763..24e4b43 100644 --- a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs +++ b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs @@ -74,12 +74,19 @@ public ScripterResult ScriptAll() ScriptAllUserDefinedTypes(context); }); + var functionsScriptTask = Task.Run(() => + { + var context = GetDatabaseContext(true); + this.ScriptAllFunctions(context); + }); + Task.WaitAll( tablesScriptTask, viewsScriptTask, storedProceduresScriptTask, synonymsScriptTask, - udtScriptTask + udtScriptTask, + functionsScriptTask ); } catch (Exception ex) From e31e6f8d0f6e7353c16ad0c2ebe1ab1697d8a0fd Mon Sep 17 00:00:00 2001 From: Max Obrist Date: Wed, 13 Jun 2018 19:45:27 +0200 Subject: [PATCH 2/9] Adding ScriptBatchTerminator option --- DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs | 7 +++++++ DbUp.Support.SqlServer.Scripting/Options.cs | 1 + 2 files changed, 8 insertions(+) diff --git a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs index 24e4b43..015dac2 100644 --- a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs +++ b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs @@ -489,6 +489,13 @@ private void SaveScript(ScriptObject scriptObject, StringCollection script, stri { sb.Append(str); sb.Append(Environment.NewLine); + + if (this.m_options.ScriptBatchTerminator) + { + sb.Append("GO"); + sb.Append(Environment.NewLine); + sb.Append(Environment.NewLine); + } } m_log.WriteInformation(string.Format("Saving object definition: {0}", Path.Combine(outputDirectory, scriptObject.FileName))); diff --git a/DbUp.Support.SqlServer.Scripting/Options.cs b/DbUp.Support.SqlServer.Scripting/Options.cs index 3f69df2..d917801 100644 --- a/DbUp.Support.SqlServer.Scripting/Options.cs +++ b/DbUp.Support.SqlServer.Scripting/Options.cs @@ -46,6 +46,7 @@ public Options() public string FolderNameProcedures { get; set; } public string FolderNameFunctions { get; set; } public string FolderNameSynonyms { get; set; } + public bool ScriptBatchTerminator { get; set; } public ObjectTypeEnum ObjectsToInclude { get; set; } } } From d27464e17c1f3b03acc4a4f5b8a96e831067f9b1 Mon Sep 17 00:00:00 2001 From: Max Obrist Date: Wed, 13 Jun 2018 19:58:20 +0200 Subject: [PATCH 3/9] Scripting applied scripts when upgrade has not been successful --- .../ScriptingUpgrader.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs b/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs index e8330da..a431b31 100644 --- a/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs +++ b/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs @@ -120,14 +120,22 @@ public DatabaseUpgradeResult Run(string[] args) } else { + var executedScriptsBeforeUpgrade = this.m_engine.GetExecutedScripts(); result = m_engine.PerformUpgrade(); - - if (result.Successful - && args.Any(a => "--fromconsole".Equals(a.Trim(), StringComparison.InvariantCultureIgnoreCase))) + if (args.Any(a => "--fromconsole".Equals(a.Trim(), StringComparison.InvariantCultureIgnoreCase))) { - this.Log.WriteInformation("Scripting changed database objects..."); - var scripter = new DbObjectScripter(this.ConnectionString, m_options, this.Log); - var scriptorResult = scripter.ScriptMigrationTargets(scriptsToExecute); + var scripter = new DbObjectScripter(this.ConnectionString, this.m_options, this.Log); + if (result.Successful) + { + this.Log.WriteInformation("Scripting changed database objects..."); + var scriptorResult = scripter.ScriptMigrationTargets(scriptsToExecute); + } else + { + this.Log.WriteInformation("Scripting successfully changed database objects..."); + var executedScriptsAfterUpgrade = this.m_engine.GetExecutedScripts(); + var appliedScripts = scriptsToExecute.Where(s => executedScriptsAfterUpgrade.Except(executedScriptsBeforeUpgrade).Contains(s.Name)) + var scriptorResult = scripter.ScriptMigrationTargets(appliedScripts); + } } } } From ce467636770136b4aa2ca44d8f6205593814e1d7 Mon Sep 17 00:00:00 2001 From: Max Obrist Date: Wed, 13 Jun 2018 20:00:28 +0200 Subject: [PATCH 4/9] Scripting applied scripts when upgrade has not been successful --- DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs b/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs index a431b31..c815e04 100644 --- a/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs +++ b/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs @@ -133,7 +133,8 @@ public DatabaseUpgradeResult Run(string[] args) { this.Log.WriteInformation("Scripting successfully changed database objects..."); var executedScriptsAfterUpgrade = this.m_engine.GetExecutedScripts(); - var appliedScripts = scriptsToExecute.Where(s => executedScriptsAfterUpgrade.Except(executedScriptsBeforeUpgrade).Contains(s.Name)) + var appliedScripts = scriptsToExecute.Where(s => executedScriptsAfterUpgrade.Except(executedScriptsBeforeUpgrade) + .Contains(s.Name)); var scriptorResult = scripter.ScriptMigrationTargets(appliedScripts); } } From ade9bc55c2b183e0a09ebab7605aab5b851abab0 Mon Sep 17 00:00:00 2001 From: Max Obrist Date: Wed, 13 Jun 2018 20:50:14 +0200 Subject: [PATCH 5/9] cleanup duplicate in scripted objects to avoid multiple scripting of objects and to avoid errors, when an object has later been dropped --- .../DbObjectScripter.cs | 80 ++++++++++++------- .../ScriptingUpgrader.cs | 3 +- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs index 015dac2..6843bfd 100644 --- a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs +++ b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs @@ -10,6 +10,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.Remoting.Messaging; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -18,7 +19,9 @@ namespace DbUp.Support.SqlServer.Scripting { public class DbObjectScripter { - private readonly string m_scrptingObjectRegEx = @"(CREATE|ALTER|DROP)\s*(TABLE|VIEW|PROCEDURE|PROC|FUNCTION|SYNONYM|TYPE) ([\w\[\]\-]+)?\.?([\w\[\]\-]*)"; + private const string m_scrptingObjectRegExString = @"(CREATE|ALTER|DROP)\s*(TABLE|VIEW|PROCEDURE|PROC|FUNCTION|SYNONYM|TYPE) ([\w\[\]\-]+)?\.?([\w\[\]\-]*)"; + private readonly Regex m_targetDbObjectRegex = new Regex(m_scrptingObjectRegExString, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); + private Options m_options; private string m_definitionDirectory; private SqlConnectionStringBuilder m_connectionBuilder; @@ -100,45 +103,64 @@ public ScripterResult ScriptAll() public ScripterResult ScriptMigrationTargets(IEnumerable migrationScripts) { - Regex targetDbObjectRegex = new Regex(m_scrptingObjectRegEx, - RegexOptions.IgnoreCase | RegexOptions.Multiline); + List scriptObjects = new List(migrationScripts.SelectMany(this.GetObjectsFromMigrationScripts)); + scriptObjects = CleanupScriptObjects(scriptObjects); - List scriptObjects = new List(); - foreach (SqlScript script in migrationScripts) + return ScriptObjects(scriptObjects); + } + + private IEnumerable GetObjectsFromMigrationScripts(SqlScript script) + { + //extract db object target(s) from scripts + MatchCollection matches = this.m_targetDbObjectRegex.Matches(script.Contents); + foreach (Match m in matches) { - //extract db object target(s) from scripts - MatchCollection matches = targetDbObjectRegex.Matches(script.Contents); - foreach (Match m in matches) + string objectType = m.Groups[2].Value; + + if (Enum.TryParse(objectType, true, out var type)) { - string objectType = m.Groups[2].Value; + ObjectActionEnum action = (ObjectActionEnum)Enum.Parse(typeof(ObjectActionEnum), m.Groups[1].Value, true); + var scriptObject = new ScriptObject(type, action); - ObjectTypeEnum type; - if (Enum.TryParse(objectType, true, out type)) + if (string.IsNullOrEmpty(m.Groups[4].Value) && !string.IsNullOrEmpty(m.Groups[3].Value)) { - ObjectActionEnum action = (ObjectActionEnum)Enum.Parse(typeof(ObjectActionEnum), m.Groups[1].Value, true); - var scriptObject = new ScriptObject(type, action); + //no schema specified + scriptObject.ObjectName = m.Groups[3].Value; + } + else + { + scriptObject.ObjectSchema = m.Groups[3].Value; + scriptObject.ObjectName = m.Groups[4].Value; + } - if (string.IsNullOrEmpty(m.Groups[4].Value) && !string.IsNullOrEmpty(m.Groups[3].Value)) - { - //no schema specified - scriptObject.ObjectName = m.Groups[3].Value; - } - else - { - scriptObject.ObjectSchema = m.Groups[3].Value; - scriptObject.ObjectName = m.Groups[4].Value; - } + char[] removeCharacters = { '[', ']' }; + scriptObject.ObjectSchema = removeCharacters.Aggregate(scriptObject.ObjectSchema, (c1, c2) => c1.Replace(c2.ToString(), "")); + scriptObject.ObjectName = removeCharacters.Aggregate(scriptObject.ObjectName, (c1, c2) => c1.Replace(c2.ToString(), "")); - char[] removeCharacters = new char[] { '[', ']' }; - scriptObject.ObjectSchema = removeCharacters.Aggregate(scriptObject.ObjectSchema, (c1, c2) => c1.Replace(c2.ToString(), "")); - scriptObject.ObjectName = removeCharacters.Aggregate(scriptObject.ObjectName, (c1, c2) => c1.Replace(c2.ToString(), "")); + yield return scriptObject; + } + } + } + /// + /// Remove duplicates from a list of ScriptObjects to avoid double sripting of files and not run into errors with later droped objects + /// + /// + /// + private static List CleanupScriptObjects(List scriptObjects) + { + var preCleanUpScripts = new List(scriptObjects); + preCleanUpScripts.Reverse(); - scriptObjects.Add(scriptObject); - } + var cleanedUpScripts = new List(); + foreach (var script in preCleanUpScripts) + { + if (!cleanedUpScripts.Any(s => s.FullName.Equals(script.FullName, StringComparison.OrdinalIgnoreCase))) + { + cleanedUpScripts.Add(script); } } - return ScriptObjects(scriptObjects); + return cleanedUpScripts; } public ScripterResult ScriptObjects(IEnumerable objects) diff --git a/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs b/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs index c815e04..d300580 100644 --- a/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs +++ b/DbUp.Support.SqlServer.Scripting/ScriptingUpgrader.cs @@ -129,7 +129,8 @@ public DatabaseUpgradeResult Run(string[] args) { this.Log.WriteInformation("Scripting changed database objects..."); var scriptorResult = scripter.ScriptMigrationTargets(scriptsToExecute); - } else + } + else { this.Log.WriteInformation("Scripting successfully changed database objects..."); var executedScriptsAfterUpgrade = this.m_engine.GetExecutedScripts(); From 62228e08d41164415a022c187efebe709d067dd7 Mon Sep 17 00:00:00 2001 From: Max Obrist Date: Wed, 13 Jun 2018 22:07:46 +0200 Subject: [PATCH 6/9] support for CREATE OR ALTER and DROP IF EXISTS statements --- .../DbObjectScripter.cs | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs index 6843bfd..63b9571 100644 --- a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs +++ b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs @@ -19,8 +19,12 @@ namespace DbUp.Support.SqlServer.Scripting { public class DbObjectScripter { - private const string m_scrptingObjectRegExString = @"(CREATE|ALTER|DROP)\s*(TABLE|VIEW|PROCEDURE|PROC|FUNCTION|SYNONYM|TYPE) ([\w\[\]\-]+)?\.?([\w\[\]\-]*)"; - private readonly Regex m_targetDbObjectRegex = new Regex(m_scrptingObjectRegExString, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); + private const string SCRIPTING_OBJECT_REGEX = @"(CREATE|ALTER|DROP|CREATE\s*OR\s*ALTER)\s*(TABLE|VIEW|PROCEDURE|PROC|FUNCTION|SYNONYM|TYPE)\s*I?F?\s*E?X?I?S?T?S?\s*([\w\[\]\-]+)?\.?([\w\[\]\-]*)"; + private const int REGEX_INDEX_ACTION_TYPE = 1; + private const int REGEX_INDEX_OBJECT_TYPE = 2; + private const int REGEX_INDEX_SCHEMA_NAME = 3; + private const int REGEX_INDEX_OBJECT_NAME = 4; + private readonly Regex m_targetDbObjectRegex = new Regex(SCRIPTING_OBJECT_REGEX, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); private Options m_options; private string m_definitionDirectory; @@ -115,22 +119,25 @@ private IEnumerable GetObjectsFromMigrationScripts(SqlScript scrip MatchCollection matches = this.m_targetDbObjectRegex.Matches(script.Contents); foreach (Match m in matches) { - string objectType = m.Groups[2].Value; - - if (Enum.TryParse(objectType, true, out var type)) + if (Enum.TryParse(m.Groups[REGEX_INDEX_OBJECT_TYPE].Value, true, out var type)) { - ObjectActionEnum action = (ObjectActionEnum)Enum.Parse(typeof(ObjectActionEnum), m.Groups[1].Value, true); + // replace CREATE OR ALTER by CREATE + var actionString = m.Groups[REGEX_INDEX_ACTION_TYPE].Value.StartsWith(ObjectActionEnum.Create.ToString(), StringComparison.OrdinalIgnoreCase) + ? ObjectActionEnum.Create.ToString() + : m.Groups[REGEX_INDEX_ACTION_TYPE].Value; + + ObjectActionEnum action = (ObjectActionEnum)Enum.Parse(typeof(ObjectActionEnum), actionString, true); var scriptObject = new ScriptObject(type, action); - if (string.IsNullOrEmpty(m.Groups[4].Value) && !string.IsNullOrEmpty(m.Groups[3].Value)) + if (string.IsNullOrEmpty(m.Groups[REGEX_INDEX_OBJECT_NAME].Value) && !string.IsNullOrEmpty(m.Groups[REGEX_INDEX_SCHEMA_NAME].Value)) { - //no schema specified - scriptObject.ObjectName = m.Groups[3].Value; + //no schema specified. in that case, object name is in the schema group + scriptObject.ObjectName = m.Groups[REGEX_INDEX_SCHEMA_NAME].Value; } else { - scriptObject.ObjectSchema = m.Groups[3].Value; - scriptObject.ObjectName = m.Groups[4].Value; + scriptObject.ObjectSchema = m.Groups[REGEX_INDEX_SCHEMA_NAME].Value; + scriptObject.ObjectName = m.Groups[REGEX_INDEX_OBJECT_NAME].Value; } char[] removeCharacters = { '[', ']' }; From 54ade8acdcbfee6eba1797580175402e6bd7edf6 Mon Sep 17 00:00:00 2001 From: Max Obrist Date: Wed, 13 Jun 2018 23:49:29 +0200 Subject: [PATCH 7/9] Added support for sp_rename --- .../DbObjectScripter.cs | 127 +++++++++++++++--- .../ObjectTypeEnum.cs | 1 + 2 files changed, 107 insertions(+), 21 deletions(-) diff --git a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs index 63b9571..89791ca 100644 --- a/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs +++ b/DbUp.Support.SqlServer.Scripting/DbObjectScripter.cs @@ -19,11 +19,14 @@ namespace DbUp.Support.SqlServer.Scripting { public class DbObjectScripter { - private const string SCRIPTING_OBJECT_REGEX = @"(CREATE|ALTER|DROP|CREATE\s*OR\s*ALTER)\s*(TABLE|VIEW|PROCEDURE|PROC|FUNCTION|SYNONYM|TYPE)\s*I?F?\s*E?X?I?S?T?S?\s*([\w\[\]\-]+)?\.?([\w\[\]\-]*)"; - private const int REGEX_INDEX_ACTION_TYPE = 1; - private const int REGEX_INDEX_OBJECT_TYPE = 2; - private const int REGEX_INDEX_SCHEMA_NAME = 3; - private const int REGEX_INDEX_OBJECT_NAME = 4; + private const string SCRIPTING_OBJECT_REGEX = @"((CREATE|ALTER|DROP|CREATE\s*OR\s*ALTER)\s*(TABLE|VIEW|PROCEDURE|PROC|FUNCTION|SYNONYM|TYPE)\s*I?F?\s*E?X?I?S?T?S?\s*([\w\[\]\-]+)?\.?([\w\[\]\-]*))|(sp_rename{1,1}\s*'([\w\[\]\-]+)?\.?([\w\[\]\-]*)'\s*,\s*'([\w\[\]\-]*)')"; + private const int REGEX_INDEX_ACTION_TYPE = 2; + private const int REGEX_INDEX_OBJECT_TYPE = 3; + private const int REGEX_INDEX_SCHEMA_NAME = 4; + private const int REGEX_INDEX_OBJECT_NAME = 5; + private const int REGEX_INDEX_OBJECT_RENAME_SCHEMA = 7; + private const int REGEX_INDEX_OBJECT_RENAME_OLD_NAME = 8; + private const int REGEX_INDEX_OBJECT_RENAME_NEW_NAME = 9; private readonly Regex m_targetDbObjectRegex = new Regex(SCRIPTING_OBJECT_REGEX, RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); private Options m_options; @@ -119,35 +122,107 @@ private IEnumerable GetObjectsFromMigrationScripts(SqlScript scrip MatchCollection matches = this.m_targetDbObjectRegex.Matches(script.Contents); foreach (Match m in matches) { - if (Enum.TryParse(m.Groups[REGEX_INDEX_OBJECT_TYPE].Value, true, out var type)) + //if this group is empty, it means the second part of the regex matched (sp_rename) + if (!string.IsNullOrEmpty(m.Groups[REGEX_INDEX_ACTION_TYPE].Value)) { - // replace CREATE OR ALTER by CREATE - var actionString = m.Groups[REGEX_INDEX_ACTION_TYPE].Value.StartsWith(ObjectActionEnum.Create.ToString(), StringComparison.OrdinalIgnoreCase) - ? ObjectActionEnum.Create.ToString() - : m.Groups[REGEX_INDEX_ACTION_TYPE].Value; + + if (Enum.TryParse(m.Groups[REGEX_INDEX_OBJECT_TYPE].Value, true, out var type)) + { + //replace CREATE OR ALTER by CREATE + var actionString = m.Groups[REGEX_INDEX_ACTION_TYPE].Value.StartsWith(ObjectActionEnum.Create.ToString(), StringComparison.OrdinalIgnoreCase) + ? ObjectActionEnum.Create.ToString() + : m.Groups[REGEX_INDEX_ACTION_TYPE].Value; + + ObjectActionEnum action = (ObjectActionEnum)Enum.Parse(typeof(ObjectActionEnum), actionString, true); + var scriptObject = new ScriptObject(type, action); - ObjectActionEnum action = (ObjectActionEnum)Enum.Parse(typeof(ObjectActionEnum), actionString, true); - var scriptObject = new ScriptObject(type, action); + if (string.IsNullOrEmpty(m.Groups[REGEX_INDEX_OBJECT_NAME].Value) && !string.IsNullOrEmpty(m.Groups[REGEX_INDEX_SCHEMA_NAME].Value)) + { + //no schema specified. in that case, object name is in the schema group + scriptObject.ObjectName = RemoveBrackets(m.Groups[REGEX_INDEX_SCHEMA_NAME].Value); + } + else + { + scriptObject.ObjectSchema = RemoveBrackets(m.Groups[REGEX_INDEX_SCHEMA_NAME].Value); + scriptObject.ObjectName = RemoveBrackets(m.Groups[REGEX_INDEX_OBJECT_NAME].Value); + } - if (string.IsNullOrEmpty(m.Groups[REGEX_INDEX_OBJECT_NAME].Value) && !string.IsNullOrEmpty(m.Groups[REGEX_INDEX_SCHEMA_NAME].Value)) + yield return scriptObject; + } + } + else + { + string schemaName; + string oldObjectName; + string newObjectName; + if (string.IsNullOrEmpty(m.Groups[REGEX_INDEX_OBJECT_RENAME_OLD_NAME].Value) && !string.IsNullOrEmpty(m.Groups[REGEX_INDEX_OBJECT_RENAME_SCHEMA].Value)) { //no schema specified. in that case, object name is in the schema group - scriptObject.ObjectName = m.Groups[REGEX_INDEX_SCHEMA_NAME].Value; + schemaName = "dbo"; + oldObjectName = RemoveBrackets(m.Groups[REGEX_INDEX_OBJECT_RENAME_SCHEMA].Value); + newObjectName = RemoveBrackets(m.Groups[REGEX_INDEX_OBJECT_RENAME_OLD_NAME].Value); } else { - scriptObject.ObjectSchema = m.Groups[REGEX_INDEX_SCHEMA_NAME].Value; - scriptObject.ObjectName = m.Groups[REGEX_INDEX_OBJECT_NAME].Value; + schemaName = m.Groups[REGEX_INDEX_OBJECT_RENAME_SCHEMA].Value; + oldObjectName = RemoveBrackets(m.Groups[REGEX_INDEX_OBJECT_RENAME_OLD_NAME].Value); + newObjectName = RemoveBrackets(m.Groups[REGEX_INDEX_OBJECT_RENAME_NEW_NAME].Value); } + + var type = GetObjectTypeFromDb(schemaName, newObjectName); + + var scriptObjectDrop = new ScriptObject(type, ObjectActionEnum.Drop); + scriptObjectDrop.ObjectSchema = schemaName; + scriptObjectDrop.ObjectName = oldObjectName; - char[] removeCharacters = { '[', ']' }; - scriptObject.ObjectSchema = removeCharacters.Aggregate(scriptObject.ObjectSchema, (c1, c2) => c1.Replace(c2.ToString(), "")); - scriptObject.ObjectName = removeCharacters.Aggregate(scriptObject.ObjectName, (c1, c2) => c1.Replace(c2.ToString(), "")); + yield return scriptObjectDrop; - yield return scriptObject; + var scriptObjectCreate = new ScriptObject(type, ObjectActionEnum.Create); + scriptObjectCreate.ObjectSchema = schemaName; + scriptObjectCreate.ObjectName = newObjectName; + + yield return scriptObjectCreate; } } } + + private static string RemoveBrackets(string @string) + { + char[] removeCharacters = { '[', ']' }; + return removeCharacters.Aggregate(@string, (c1, c2) => c1.Replace(c2.ToString(), "")); + } + + private ObjectTypeEnum GetObjectTypeFromDb(string schemaName, string objectName) + { + var context = this.GetDatabaseContext(false); + if (context.Database.Tables[objectName, schemaName] != null) + { + return ObjectTypeEnum.Table; + } + if (context.Database.Views[objectName, schemaName] != null) + { + return ObjectTypeEnum.View; + } + if (context.Database.Synonyms[objectName, schemaName] != null) + { + return ObjectTypeEnum.Synonym; + } + if (context.Database.StoredProcedures[objectName, schemaName] != null || context.Database.ExtendedStoredProcedures[objectName, schemaName] != null) + { + return ObjectTypeEnum.Procedure; + } + if (context.Database.UserDefinedFunctions[objectName, schemaName] != null) + { + return ObjectTypeEnum.Function; + } + if (context.Database.UserDefinedDataTypes[objectName, schemaName] != null || context.Database.UserDefinedTableTypes[objectName, schemaName] != null|| context.Database.UserDefinedTypes[objectName, schemaName] != null) + { + return ObjectTypeEnum.Type; + } + + return ObjectTypeEnum.Undefined; + } + /// /// Remove duplicates from a list of ScriptObjects to avoid double sripting of files and not run into errors with later droped objects /// @@ -184,6 +259,8 @@ public ScripterResult ScriptObjects(IEnumerable objects) ScriptFunctions(context, objects.Where(o => o.ObjectType == ObjectTypeEnum.Function)); ScriptSynonyms(context, objects.Where(o => o.ObjectType == ObjectTypeEnum.Synonym)); ScriptUserDefinedTypes(context, objects.Where(o => o.ObjectType == ObjectTypeEnum.Type)); + + WarnUndefinedObjects(objects.Where(o => o.ObjectType == ObjectTypeEnum.Undefined)); } catch (Exception ex) { @@ -503,7 +580,15 @@ private void ScriptDefinition(ScriptObject dbObject, string outputDirectory, Fun } catch (Exception ex) { - m_log.WriteError(string.Format("Error when scripting definition for {0}: {1}", dbObject.ObjectName, ex.Message)); + m_log.WriteError(string.Format("Error when scripting definition for {0}.{1}: {2}", dbObject.ObjectSchema, dbObject.ObjectName, ex.Message)); + } + } + + private void WarnUndefinedObjects(IEnumerable dbObjects) + { + foreach (var dbObject in dbObjects) + { + m_log.WriteWarning(string.Format("The object {0}.{1} could not be scripted, since the object type was not identifyable. Normally this means, that the object has been dropped in the meantime. If necessary delete the file manually.", dbObject.ObjectSchema, dbObject.ObjectName)); } } diff --git a/DbUp.Support.SqlServer.Scripting/ObjectTypeEnum.cs b/DbUp.Support.SqlServer.Scripting/ObjectTypeEnum.cs index 57db66e..66d4ae0 100644 --- a/DbUp.Support.SqlServer.Scripting/ObjectTypeEnum.cs +++ b/DbUp.Support.SqlServer.Scripting/ObjectTypeEnum.cs @@ -9,6 +9,7 @@ namespace DbUp.Support.SqlServer.Scripting [Flags] public enum ObjectTypeEnum : int { + Undefined = 0, Table = 1, View = 2, Procedure = 4, From 2f653010fc19626ad5094dd6eba7183f7df336ab Mon Sep 17 00:00:00 2001 From: Max Obrist Date: Thu, 14 Jun 2018 16:11:11 +0200 Subject: [PATCH 8/9] Added user defined types to the list of supported object types --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ba5067e..e8ee4ba 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ The following SQL Server object types are currently supported: * Stored Procedures * User Defined Functions * Synonyms +* User Defined Types ## Script All Definitions You can run `Start-DatabaseScript` from the Package Manager Console to script all objects in the database. If working with an existing database, it is recommended to run this command initially so that all your definition files are saved. From f69bdd18379365d34116e464a765ebcdcde84aa8 Mon Sep 17 00:00:00 2001 From: Max Obrist Date: Thu, 14 Jun 2018 17:03:43 +0200 Subject: [PATCH 9/9] extending README.md with list of supported types and known issues regarding sp_rename --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index e8ee4ba..54a586e 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,21 @@ The following SQL Server object types are currently supported: * Synonyms * User Defined Types +## Statement Types +The following list shows which statement types are currently supported: + +* CREATE +* CREATE OR ALTER +* ALTER +* CREATE +* CREATE IF EXISTS +* Renaming with sp_rename + +## Known Issues +* Renaming with sp_rename +** Only the renaming of objects itself (like table, view, procedures, etc.) is supported, but not the renaming of columns, indexes, keys +** When dropping or again renaming an object after it has been renamed with sp_rename, those objects can not be properly scripted + ## Script All Definitions You can run `Start-DatabaseScript` from the Package Manager Console to script all objects in the database. If working with an existing database, it is recommended to run this command initially so that all your definition files are saved.