Initial commit

This commit is contained in:
2021-08-26 20:59:17 +02:00
commit 3afa4c82ef
524 changed files with 52428 additions and 0 deletions

View File

@@ -0,0 +1,126 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Assembly : Code
{
public Assembly(ISchemaBase parent)
: base(parent, ObjectType.Assembly, ScriptAction.AddAssembly, ScriptAction.DropAssembly)
{
Files = new SchemaList<AssemblyFile, Assembly>(this);
}
public override ISchemaBase Clone(ISchemaBase parent)
{
Assembly item = new Assembly(parent)
{
Id = this.Id,
Name = this.Name,
Owner = this.Owner,
Visible = this.Visible,
Text = this.Text,
PermissionSet = this.PermissionSet,
CLRName = this.CLRName,
Guid = this.Guid,
Files = this.Files
};
this.DependenciesOut.ForEach(dep => item.DependenciesOut.Add(dep));
this.ExtendedProperties.ForEach(ep => item.ExtendedProperties.Add(ep));
return item;
}
public SchemaList<AssemblyFile, Assembly> Files { get; set; }
public override string FullName
{
get { return "[" + Name + "]"; }
}
public string CLRName { get; set; }
public bool Visible { get; set; }
public string PermissionSet { get; set; }
public override string ToSql()
{
string access = PermissionSet;
if (PermissionSet.Equals("UNSAFE_ACCESS")) access = "UNSAFE";
if (PermissionSet.Equals("SAFE_ACCESS")) access = "SAFE";
string toSql = "CREATE ASSEMBLY ";
toSql += FullName + "\r\n";
toSql += "AUTHORIZATION " + Owner + "\r\n";
toSql += "FROM " + Text + "\r\n";
toSql += "WITH PERMISSION_SET = " + access + "\r\n";
toSql += "GO\r\n";
toSql += Files.ToSql();
toSql += this.ExtendedProperties.ToSql();
return toSql;
}
public override string ToSqlDrop()
{
return "DROP ASSEMBLY " + FullName + "\r\nGO\r\n";
}
public override string ToSqlAdd()
{
return ToSql();
}
private string ToSQLAlter()
{
string access = PermissionSet;
if (PermissionSet.Equals("UNSAFE_ACCESS")) access = "UNSAFE";
if (PermissionSet.Equals("SAFE_ACCESS")) access = "SAFE";
return "ALTER ASSEMBLY " + FullName + " WITH PERMISSION_SET = " + access + "\r\nGO\r\n";
}
private string ToSQLAlterOwner()
{
return "ALTER AUTHORIZATION ON ASSEMBLY::" + FullName + " TO " + Owner + "\r\nGO\r\n";
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
list.AddRange(RebuildDependencies());
list.Add(Drop());
}
if (this.Status == ObjectStatus.Create)
list.Add(Create());
if (this.HasState(ObjectStatus.Rebuild))
list.AddRange(Rebuild());
if (this.HasState(ObjectStatus.ChangeOwner))
list.Add(ToSQLAlterOwner(), 0, ScriptAction.AlterAssembly);
if (this.HasState(ObjectStatus.PermissionSet))
list.Add(ToSQLAlter(), 0, ScriptAction.AlterAssembly);
if (this.HasState(ObjectStatus.Alter))
list.AddRange(Files.ToSqlDiff());
list.AddRange(this.ExtendedProperties.ToSqlDiff());
return list;
}
public bool Compare(Assembly obj)
{
if (obj == null) throw new ArgumentNullException("obj");
if (!this.CLRName.Equals(obj.CLRName)) return false;
if (!this.PermissionSet.Equals(obj.PermissionSet)) return false;
if (!this.Owner.Equals(obj.Owner)) return false;
if (!this.Text.Equals(obj.Text)) return false;
if (this.Files.Count != obj.Files.Count) return false;
for (int j = 0; j < this.Files.Count; j++)
if (!this.Files[j].Content.Equals(obj.Files[j].Content)) return false;
return true;
}
public override Boolean IsCodeType
{
get { return true; }
}
}
}

View File

@@ -0,0 +1,67 @@
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class AssemblyFile : SQLServerSchemaBase
{
public AssemblyFile(ISchemaBase parent, AssemblyFile assemblyFile, ObjectStatus status)
: base(parent, ObjectType.AssemblyFile)
{
this.Name = assemblyFile.Name;
this.Content = assemblyFile.Content;
this.Status = status;
}
public AssemblyFile(ISchemaBase parent, string name, string content)
: base(parent, ObjectType.AssemblyFile)
{
this.Name = name;
this.Content = content;
}
public override string FullName
{
get { return "[" + Name + "]"; }
}
public string Content { get; set; }
public override string ToSqlAdd()
{
string sql = "ALTER ASSEMBLY ";
sql += this.Parent.FullName + "\r\n";
sql += "ADD FILE FROM " + this.Content + "\r\n";
sql += "AS N'" + this.Name + "'\r\n";
return sql + "GO\r\n";
}
public override string ToSql()
{
return ToSqlAdd();
}
public override string ToSqlDrop()
{
string sql = "ALTER ASSEMBLY ";
sql += this.Parent.FullName + "\r\n";
sql += "DROP FILE N'" + this.Name + "'\r\n";
return sql + "GO\r\n";
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropAssemblyFile);
if (this.Status == ObjectStatus.Create)
listDiff.Add(ToSqlAdd(), 0, ScriptAction.AddAssemblyFile);
if (this.HasState(ObjectStatus.Alter))
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropAssemblyFile);
listDiff.Add(ToSqlAdd(), 0, ScriptAction.AddAssemblyFile);
}
return listDiff;
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public abstract class CLRCode : Code
{
public CLRCode(ISchemaBase parent, ObjectType type, ScriptAction addAction, ScriptAction dropAction)
: base(parent, type, addAction, dropAction)
{
}
public string AssemblyMethod { get; set; }
public string AssemblyExecuteAs { get; set; }
public string AssemblyName { get; set; }
public Boolean IsAssembly { get; set; }
public string AssemblyClass { get; set; }
public int AssemblyId { get; set; }
public override Boolean IsCodeType
{
get { return true; }
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class CLRFunction : CLRCode
{
public CLRFunction(ISchemaBase parent)
: base(parent, ObjectType.CLRFunction, ScriptAction.AddFunction, ScriptAction.DropFunction)
{
Parameters = new List<Parameter>();
ReturnType = new Parameter();
}
public List<Parameter> Parameters { get; set; }
public Parameter ReturnType { get; private set; }
public override string ToSql()
{
string sql = "CREATE FUNCTION " + FullName + "";
string param = "";
Parameters.ForEach(item => param += item.ToSql() + ",");
if (!String.IsNullOrEmpty(param))
{
param = param.Substring(0, param.Length - 1);
sql += " (" + param + ")\r\n";
}
else
sql += "()\r\n";
sql += "RETURNS " + ReturnType.ToSql() + " ";
sql += "WITH EXECUTE AS " + AssemblyExecuteAs + "\r\n";
sql += "AS\r\n";
sql += "EXTERNAL NAME [" + AssemblyName + "].[" + AssemblyClass + "].[" + AssemblyMethod + "]\r\n";
sql += "GO\r\n";
return sql;
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.HasState(ObjectStatus.Drop))
list.Add(Drop());
if (this.HasState(ObjectStatus.Create))
list.Add(Create());
if (this.Status == ObjectStatus.Alter)
{
list.AddRange(Rebuild());
}
list.AddRange(this.ExtendedProperties.ToSqlDiff());
return list;
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class CLRStoredProcedure : CLRCode
{
public CLRStoredProcedure(ISchemaBase parent)
: base(parent, ObjectType.CLRStoredProcedure, ScriptAction.AddStoredProcedure, ScriptAction.DropStoredProcedure)
{
Parameters = new List<Parameter>();
}
public List<Parameter> Parameters { get; set; }
public override string ToSql()
{
string sql = "CREATE PROCEDURE " + FullName + "\r\n";
string param = "";
Parameters.ForEach(item => param += "\t" + item.ToSql() + ",\r\n");
if (!String.IsNullOrEmpty(param)) param = param.Substring(0, param.Length - 3) + "\r\n";
sql += param;
sql += "WITH EXECUTE AS " + AssemblyExecuteAs + "\r\n";
sql += "AS\r\n";
sql += "EXTERNAL NAME [" + AssemblyName + "].[" + AssemblyClass + "].[" + AssemblyMethod + "]\r\n";
sql += "GO\r\n";
return sql;
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.HasState(ObjectStatus.Drop))
list.Add(Drop());
if (this.HasState(ObjectStatus.Create))
list.Add(Create());
if (this.Status == ObjectStatus.Alter)
{
list.AddRange(Rebuild());
}
list.AddRange(this.ExtendedProperties.ToSqlDiff());
return list;
}
}
}

View File

@@ -0,0 +1,48 @@
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class CLRTrigger : CLRCode
{
public CLRTrigger(ISchemaBase parent)
: base(parent, ObjectType.CLRTrigger, ScriptAction.AddTrigger, ScriptAction.DropTrigger)
{
}
public override string ToSql()
{
string sql = "CREATE TRIGGER " + FullName + " ON " + Parent.FullName;
sql += " AFTER ";
if (IsInsert) sql += "INSERT,";
if (IsUpdate) sql += "UPDATE,";
if (IsDelete) sql += "DELETE,";
sql = sql.Substring(0, sql.Length - 1) + " ";
sql += "AS\r\n";
sql += "EXTERNAL NAME [" + AssemblyName + "].[" + AssemblyClass + "].[" + AssemblyMethod + "]\r\n";
sql += "GO\r\n";
return sql;
}
public bool IsUpdate { get; set; }
public bool IsInsert { get; set; }
public bool IsDelete { get; set; }
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.HasState(ObjectStatus.Drop))
list.Add(Drop());
if (this.HasState(ObjectStatus.Create))
list.Add(Create());
if (this.Status == ObjectStatus.Alter)
{
list.AddRange(Rebuild());
}
list.AddRange(this.ExtendedProperties.ToSqlDiff());
return list;
}
}
}

View File

@@ -0,0 +1,256 @@
using OpenDBDiff.Schema.Model;
using OpenDBDiff.Schema.SQLServer.Generates.Model.Util;
using OpenDBDiff.Schema.SQLServer.Generates.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public abstract class Code : SQLServerSchemaBase, ICode
{
protected string sql = null;
protected string typeName = "";
private int deepMax = 0;
private int deepMin = 0;
private ScriptAction addAction;
private ScriptAction dropAction;
public Code(ISchemaBase parent, ObjectType type, ScriptAction addAction, ScriptAction dropAction)
: base(parent, type)
{
DependenciesIn = new List<String>();
DependenciesOut = new List<String>();
typeName = GetObjectTypeName(ObjectType);
/*Por el momento, solo los Assemblys manejan deep de dependencias*/
if (this.ObjectType == ObjectType.Assembly)
{
deepMax = 501;
deepMin = 500;
}
this.addAction = addAction;
this.dropAction = dropAction;
}
public override SQLScript Create()
{
int iCount = DependenciesCount;
if (iCount > 0) iCount = iCount * -1;
if (!GetWasInsertInDiffList(addAction))
{
SetWasInsertInDiffList(addAction);
return new SQLScript(this.ToSqlAdd(), iCount, addAction);
}
else
return null;
}
public override SQLScript Drop()
{
int iCount = DependenciesCount;
if (!GetWasInsertInDiffList(dropAction))
{
SetWasInsertInDiffList(dropAction);
return new SQLScript(this.ToSqlDrop(), iCount, dropAction);
}
else
return null;
}
private static string GetObjectTypeName(ObjectType type)
{
if (type == ObjectType.Rule) return "RULE";
if (type == ObjectType.Trigger) return "TRIGGER";
if (type == ObjectType.View) return "VIEW";
if (type == ObjectType.Function) return "FUNCTION";
if (type == ObjectType.StoredProcedure) return "PROCEDURE";
if (type == ObjectType.CLRStoredProcedure) return "PROCEDURE";
if (type == ObjectType.CLRTrigger) return "TRIGGER";
if (type == ObjectType.CLRFunction) return "FUNCTION";
if (type == ObjectType.Assembly) return "ASSEMBLY";
return "";
}
/// <summary>
/// Names collection of dependant objects of the object
/// </summary>
public List<String> DependenciesOut { get; set; }
/// <summary>
/// Names collection of objects which the object depends on
/// </summary>
public List<String> DependenciesIn { get; set; }
public Boolean IsSchemaBinding { get; set; }
public string Text { get; set; }
public override int DependenciesCount
{
get
{
int iCount = 0;
if (this.DependenciesOut.Any())
{
Dictionary<string, bool> depencyTracker = new Dictionary<string, bool>();
iCount = DependenciesCountFilter(this.FullName, depencyTracker);
}
return iCount;
}
}
private int DependenciesCountFilter(string FullName, Dictionary<string, bool> depencyTracker)
{
int count = 0;
ICode item;
try
{
item = (ICode)((Database)Parent).Find(FullName);
if (item != null)
{
for (int j = 0; j < item.DependenciesOut.Count; j++)
{
if (!depencyTracker.ContainsKey(FullName.ToUpper()))
{
depencyTracker.Add(FullName.ToUpper(), true);
}
count += 1 + DependenciesCountFilter(item.DependenciesOut[j], depencyTracker);
}
}
return count;
}
catch (Exception)
{
return 0;
}
}
/// <summary>
/// Indicates if there are dependant tables on the object which must be rebuild
/// </summary>
/// <returns></returns>
public Boolean HasToRebuild
{
get
{
for (int j = 0; j < DependenciesIn.Count; j++)
{
ISchemaBase item = ((Database)Parent).Find(DependenciesIn[j]);
if (item != null)
{
if ((item.Status == ObjectStatus.Rebuild) || (item.Status == ObjectStatus.RebuildDependencies))
return true;
}
};
return IsSchemaBinding;
}
}
private SQLScriptList RebuildDependencies(List<string> depends, int deepMin, int deepMax)
{
int newDeepMax = (deepMax != 0) ? deepMax + 1 : 0;
int newDeepMin = (deepMin != 0) ? deepMin - 1 : 0;
SQLScriptList list = new SQLScriptList();
for (int j = 0; j < depends.Count; j++)
{
ISchemaBase item = ((Database)Parent).Find(depends[j]);
if (item != null)
{
if ((item.Status != ObjectStatus.Create) && (item.Status != ObjectStatus.Drop))
{
if ((item.ObjectType != ObjectType.CLRStoredProcedure) && (item.ObjectType != ObjectType.Assembly) && (item.ObjectType != ObjectType.UserDataType) && (item.ObjectType != ObjectType.View) && (item.ObjectType != ObjectType.Function))
{
newDeepMin = 0;
newDeepMax = 0;
}
if (item.Status != ObjectStatus.Drop)
{
if (!((item.Parent.HasState(ObjectStatus.Rebuild)) && (item.ObjectType == ObjectType.Trigger)))
list.Add(item.Drop(), newDeepMin);
}
if ((this.Status != ObjectStatus.Drop) && (item.Status != ObjectStatus.Create))
list.Add(item.Create(), newDeepMax);
if (item.IsCodeType)
list.AddRange(RebuildDependencies(((ICode)item).DependenciesOut, newDeepMin, newDeepMax));
}
}
};
return list;
}
/// <summary>
/// Rebuilds the object and all its dependant objects.
/// </summary>
/// <returns></returns>
public SQLScriptList Rebuild()
{
SQLScriptList list = new SQLScriptList();
list.AddRange(RebuildDependencies());
if (this.Status != ObjectStatus.Create) list.Add(Drop(), deepMin);
if (this.Status != ObjectStatus.Drop) list.Add(Create(), deepMax);
return list;
}
/// <summary>
/// Rebuilds the dependant objects.
/// </summary>
/// <returns></returns>
public SQLScriptList RebuildDependencies()
{
return RebuildDependencies(this.DependenciesOut, deepMin, deepMax);
}
public override string ToSql()
{
if (String.IsNullOrEmpty(sql))
sql = FormatCode.FormatCreate(typeName, Text, this);
return sql;
}
public override string ToSqlAdd()
{
string sql = ToSql();
sql += this.ExtendedProperties.ToSql();
return sql;
}
public override string ToSqlDrop()
{
return String.Format("DROP {0} {1}\r\nGO\r\n", typeName, FullName);
}
public virtual bool CompareExceptWhitespace(ICode obj)
{
if (obj == null) throw new ArgumentNullException("obj");
string sql1 = this.ToSql();
string sql2 = obj.ToSql();
Regex whitespace = new Regex(@"\s");
sql1 = whitespace.Replace(this.ToSql(), "");
sql2 = whitespace.Replace(obj.ToSql(), "");
if (((Database)RootParent).Options.Comparison.CaseSensityInCode == Options.SqlOptionComparison.CaseSensityOptions.CaseInsensity)
return (sql1.Equals(sql2, StringComparison.InvariantCultureIgnoreCase));
return (sql1.Equals(sql2, StringComparison.InvariantCulture));
}
public virtual bool Compare(ICode obj)
{
if (obj == null) throw new ArgumentNullException("obj");
string sql1 = this.ToSql();
string sql2 = obj.ToSql();
if (((Database)RootParent).Options.Comparison.IgnoreWhiteSpacesInCode)
{
Regex whitespace = new Regex(@"\s");
sql1 = whitespace.Replace(this.ToSql(), "");
sql2 = whitespace.Replace(obj.ToSql(), "");
}
if (((Database)RootParent).Options.Comparison.CaseSensityInCode == SqlOptionComparison.CaseSensityOptions.CaseInsensity)
return (sql1.Equals(sql2, StringComparison.InvariantCultureIgnoreCase));
return (sql1.Equals(sql2, StringComparison.InvariantCulture));
}
}
}

View File

@@ -0,0 +1,641 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml.Serialization;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Column : SQLServerSchemaBase, IComparable<Column>
{
public Column(ISchemaBase parent)
: base(parent, ObjectType.Column)
{
ComputedFormula = "";
Collation = "";
this.Default = new Default(this);
this.Rule = new Rule(this);
this.DefaultConstraint = null;
}
/// <summary>
/// Clona el objeto Column en una nueva instancia.
/// </summary>
public new Column Clone(ISchemaBase parent)
{
Column col;
if (parent == null)
col = new Column(this.Parent);
else
col = new Column(parent);
col.ComputedFormula = this.ComputedFormula;
col.DataUserTypeId = this.DataUserTypeId;
col.Id = this.Id;
col.Guid = this.Guid;
col.Owner = this.Owner;
col.IdentityIncrement = this.IdentityIncrement;
col.IdentitySeed = this.IdentitySeed;
col.IsIdentity = this.IsIdentity;
col.IsIdentityForReplication = this.IsIdentityForReplication;
col.IsComputed = this.IsComputed;
col.IsRowGuid = this.IsRowGuid;
col.IsPersisted = this.IsPersisted;
col.IsFileStream = this.IsFileStream;
col.IsSparse = this.IsSparse;
col.IsXmlDocument = this.IsXmlDocument;
col.IsUserDefinedType = this.IsUserDefinedType;
col.HasComputedDependencies = this.HasComputedDependencies;
col.HasIndexDependencies = this.HasIndexDependencies;
col.Name = this.Name;
col.IsNullable = this.IsNullable;
col.Position = this.Position;
col.Precision = this.Precision;
col.Scale = this.Scale;
col.Collation = this.Collation;
col.Size = this.Size;
col.Status = this.Status;
col.Type = this.Type;
col.XmlSchema = this.XmlSchema;
col.Default = this.Default.Clone(this);
col.Rule = this.Rule.Clone(this);
if (this.DefaultConstraint != null)
col.DefaultConstraint = this.DefaultConstraint.Clone(this);
return col;
}
public ColumnConstraint DefaultConstraint { get; set; }
public Rule Rule { get; set; }
public Default Default { get; set; }
public Boolean IsFileStream { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is XML document.
/// </summary>
/// <value>
/// <c>true</c> if this instance is XML document; otherwise, <c>false</c>.
/// </value>
public Boolean IsXmlDocument { get; set; }
/// <summary>
/// Gets or sets the XML schema.
/// </summary>
/// <value>The XML schema.</value>
public string XmlSchema { get; set; }
public Boolean IsSparse { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is user defined type.
/// </summary>
/// <value>
/// <c>true</c> if this instance is user defined type; otherwise, <c>false</c>.
/// </value>
public Boolean IsUserDefinedType { get; set; }
public int DataUserTypeId { get; set; }
/// <summary>
/// Gets or sets the column position.
/// </summary>
/// <value>The position.</value>
public int Position { get; set; }
/// <summary>
/// Gets or sets the scale (only in numeric or decimal datatypes).
/// </summary>
/// <value>The scale.</value>
public int Scale { get; set; }
/// <summary>
/// Gets or sets the precision (only in numeric or decimal datatypes).
/// </summary>
/// <value>The precision.</value>
public int Precision { get; set; }
/// <summary>
/// Gets or sets the collation (only in text datatypes).
/// </summary>
/// <value>The collation.</value>
public string Collation { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Column"/> is nullable.
/// </summary>
/// <value><c>true</c> if nullable; otherwise, <c>false</c>.</value>
public Boolean IsNullable { get; set; }
/// <summary>
/// Gets or sets the size.
/// </summary>
/// <value>The size.</value>
public int Size { get; set; }
/// <summary>
/// Gets or sets the type.
/// </summary>
/// <value>The type.</value>
public string Type { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is persisted (only in Computed columns).
/// </summary>
/// <value>
/// <c>true</c> if this instance is persisted; otherwise, <c>false</c>.
/// </value>
public Boolean IsPersisted { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has index dependencies.
/// </summary>
/// <value>
/// <c>true</c> if this instance has index dependencies; otherwise, <c>false</c>.
/// </value>
public Boolean HasIndexDependencies { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has computed dependencies.
/// </summary>
/// <value>
/// <c>true</c> if this instance has computed dependencies; otherwise, <c>false</c>.
/// </value>
public Boolean HasComputedDependencies { get; set; }
/// <summary>
/// Gets a value indicating whether this instance has to rebuild only constraint.
/// </summary>
/// <value>
/// <c>true</c> if this instance has to rebuild only constraint; otherwise, <c>false</c>.
/// </value>
public Boolean HasToRebuildOnlyConstraint
{
get
{
return (HasIndexDependencies && !HasComputedDependencies && !IsComputed);
}
}
/// <summary>
/// Gets a value indicating whether this instance has to rebuild.
/// </summary>
/// <value>
/// <c>true</c> if this instance has to rebuild; otherwise, <c>false</c>.
/// </value>
public Boolean HasToRebuild(int newPosition, string newType, bool isFileStream)
{
if (newType.Equals("text") && (!this.IsText)) return true;
if (newType.Equals("ntext") && (!this.IsText)) return true;
if (newType.Equals("image") && (!this.IsBinary)) return true;
if (isFileStream != this.IsFileStream) return true;
return ((Position != newPosition) || HasComputedDependencies || HasIndexDependencies || IsComputed || Type.ToLower().Equals("timestamp"));
}
/// <summary>
/// Gets or sets the computed formula (only in Computed columns).
/// </summary>
/// <value>The computed formula.</value>
public string ComputedFormula { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is computed.
/// </summary>
/// <value>
/// <c>true</c> if this instance is computed; otherwise, <c>false</c>.
/// </value>
public Boolean IsComputed { get; set; }
/// <summary>
/// Gets a value indicating whether this column is BLOB.
/// </summary>
/// <value><c>true</c> if this column is BLOB; otherwise, <c>false</c>.</value>
public Boolean IsBLOB
{
get
{
return Type.Equals("varchar(MAX)") || Type.Equals("nvarchar(MAX)") || Type.Equals("varbinary(MAX)") || Type.Equals("text") || Type.Equals("image") || Type.Equals("ntext") || Type.Equals("xml");
}
}
public Boolean IsText
{
get
{
return Type.Equals("varchar(MAX)") || Type.Equals("nvarchar(MAX)") || Type.Equals("ntext") || Type.Equals("text") || Type.Equals("nvarchar") || Type.Equals("varchar") || Type.Equals("xml") || Type.Equals("char") || Type.Equals("nchar");
}
}
public Boolean IsBinary
{
get
{
return Type.Equals("varbinary") || Type.Equals("varbinary(MAX)") || Type.Equals("image") || Type.Equals("binary");
}
}
/// <summary>
/// Gets or sets a value indicating whether this field is identity for replication.
/// </summary>
/// <value>
/// <c>true</c> if this field is identity for replication; otherwise, <c>false</c>.
/// </value>
public Boolean IsIdentityForReplication { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this field is identity.
/// </summary>
/// <value>
/// <c>true</c> if this field is identity; otherwise, <c>false</c>.
/// </value>
public Boolean IsIdentity { get; set; }
/// <summary>
/// Gets or sets the identity increment (only if the field is Identity).
/// </summary>
/// <value>The identity increment.</value>
public int IdentityIncrement { get; set; }
/// <summary>
/// Gets or sets the identity seed (only if the field is Identity).
/// </summary>
/// <value>The identity seed.</value>
public long IdentitySeed { get; set; }
/// <summary>
/// Indica si el campo es Row Guid
/// </summary>
public Boolean IsRowGuid { get; set; }
/// <summary>
/// Nombre completo del objeto, incluyendo el owner.
/// </summary>
public override string FullName
{
get
{
return Parent.FullName + ".[" + Name + "]";
}
}
/// <summary>
/// Convierte el schema de la tabla en XML.
/// </summary>
public string ToXML()
{
/*string xml = "";
xml += "<COLUMN name=\"" + Name + "\" HasIndexDependencies=\"" + (hasIndexDependencies ? "1" : "0") + "\" HasComputedDependencies=\"" + (hasComputedDependencies ? "1" : "0") + "\" IsRowGuid=\"" + (isRowGuid ? "1" : "0") + "\" IsComputed=\"" + (isComputed ? "1" : "0") + "\" computedFormula=\"" + computedFormula + "\">\n";
xml += "<TYPE>" + type + "</TYPE>";
xml += "<ORIGINALTYPE>" + OriginalType + "</ORIGINALTYPE>";
xml += "<SIZE>" + size.ToString() + "</SIZE>";
xml += "<NULLABLE>" + (nullable ? "1":"0") + "</NULLABLE>";
xml += "<PREC>" + precision.ToString() + "</PREC>";
xml += "<SCALE>" + scale.ToString() + "</SCALE>";
if (this.identity)
xml += "<IDENTITY seed=\"" + identitySeed.ToString() + "\",increment=\"" + identityIncrement.ToString() + "\"/>";
if (this.identityForReplication)
xml += "<IDENTITYNOTFORREPLICATION seed=\"" + identitySeed.ToString() + "\",increment=\"" + identityIncrement.ToString() + "\"/>";
xml += constraints.ToXML();
xml += "</COLUMN>\n";
return xml;*/
XmlSerializer serial = new XmlSerializer(this.GetType());
return serial.ToString();
}
public Boolean HasToForceValue
{
get
{
return (this.HasState(ObjectStatus.Update)) || ((!this.IsNullable) && (this.Status == ObjectStatus.Create));
}
}
/// <summary>
/// Gets the default force value.
/// </summary>
/// <value>The default force value.</value>
public string DefaultForceValue
{
get
{
string tl = this.Type;
if (this.IsUserDefinedType)
tl = ((Database)this.Parent.Parent).UserTypes[Type].Type.ToLower();
if ((((Database)Parent.Parent).Options.Defaults.UseDefaultValueIfExists) && (this.DefaultConstraint != null))
{
return this.DefaultConstraint.Definition;
}
else
{
if (tl.Equals("time")) return ((Database)Parent.Parent).Options.Defaults.DefaultTime;
if (tl.Equals("int") || tl.Equals("bit") || tl.Equals("smallint") || tl.Equals("bigint") || tl.Equals("tinyint")) return ((Database)Parent.Parent).Options.Defaults.DefaultIntegerValue;
if (tl.Equals("text") || tl.Equals("char") || tl.Equals("varchar") || tl.Equals("varchar(max)")) return ((Database)Parent.Parent).Options.Defaults.DefaultTextValue;
if (tl.Equals("ntext") || tl.Equals("nchar") || tl.Equals("nvarchar") || tl.Equals("nvarchar(max)")) return ((Database)Parent.Parent).Options.Defaults.DefaultNTextValue;
if (tl.Equals("date") || tl.Equals("datetimeoffset") || tl.Equals("datetime2") || tl.Equals("datetime") || tl.Equals("smalldatetime")) return ((Database)Parent.Parent).Options.Defaults.DefaultDateValue;
if (tl.Equals("numeric") || tl.Equals("decimal") || tl.Equals("float") || tl.Equals("money") || tl.Equals("smallmoney") || tl.Equals("real")) return ((Database)Parent.Parent).Options.Defaults.DefaultRealValue;
if (tl.Equals("sql_variant")) return ((Database)Parent.Parent).Options.Defaults.DefaultVariantValue;
if (tl.Equals("uniqueidentifier")) return ((Database)Parent.Parent).Options.Defaults.DefaultUniqueValue;
if (tl.Equals("image") || tl.Equals("binary") || tl.Equals("varbinary")) return ((Database)Parent.Parent).Options.Defaults.DefaultBlobValue;
}
return "";
}
}
/// <summary>
/// Toes the SQL drop.
/// </summary>
/// <returns></returns>
public override string ToSqlDrop()
{
string sql = "ALTER TABLE " + Parent.FullName + " DROP COLUMN [" + Name + "]\r\nGO\r\n";
return sql;
}
/// <summary>
/// Toes the SQL add.
/// </summary>
/// <returns></returns>
public override string ToSqlAdd()
{
return "ALTER TABLE " + Parent.FullName + " ADD " + ToSql(false) + "\r\nGO\r\n";
}
public override string ToSql()
{
return ToSql(true);
}
public string ToSQLRedefine(string type, int size, string xmlSchema)
{
string originalType = "";
int originalSize = 0;
string originalXMLSchema = "";
string sql;
if (type != null)
{
originalType = this.Type;
this.Type = type;
}
if (size != 0)
{
originalSize = this.Size;
this.Size = size;
}
if (xmlSchema != null)
{
originalXMLSchema = this.XmlSchema;
this.XmlSchema = xmlSchema;
}
sql = this.ToSql(false);
if (type != null)
this.Type = originalType;
if (size != 0)
this.Size = originalSize;
if (xmlSchema != null)
this.XmlSchema = originalXMLSchema;
return sql;
}
/// <summary>
/// Devuelve el schema de la columna en formato SQL.
/// </summary>
public string ToSql(Boolean sqlConstraint)
{
string sql = "";
sql += "[" + Name + "] ";
if (!IsComputed)
{
if (this.IsUserDefinedType)
sql += Type;
else
sql += "[" + Type + "]";
if (Type.Equals("binary") || Type.Equals("varbinary") || Type.Equals("varchar") || Type.Equals("char") || Type.Equals("nchar") || Type.Equals("nvarchar"))
{
if (Size == -1)
sql += " (max)";
else
{
if (Type.Equals("nchar") || Type.Equals("nvarchar"))
sql += " (" + (Size / 2).ToString(CultureInfo.InvariantCulture) + ")";
else
sql += " (" + Size.ToString(CultureInfo.InvariantCulture) + ")";
}
}
if (Type.Equals("xml"))
{
if (!String.IsNullOrEmpty(XmlSchema))
{
if (IsXmlDocument)
sql += "(DOCUMENT " + XmlSchema + ")";
else
sql += "(CONTENT " + XmlSchema + ")";
}
}
if (Type.Equals("numeric") || Type.Equals("decimal")) sql += " (" + Precision.ToString(CultureInfo.InvariantCulture) + "," + Scale.ToString(CultureInfo.InvariantCulture) + ")";
if (((Database)Parent.Parent).Info.Version >= DatabaseInfo.SQLServerVersion.SQLServer2008)
{
if (Type.Equals("datetime2") || Type.Equals("datetimeoffset") || Type.Equals("time")) sql += "(" + Scale.ToString(CultureInfo.InvariantCulture) + ")";
}
if ((!String.IsNullOrEmpty(Collation)) && (!IsUserDefinedType)) sql += " COLLATE " + Collation;
if (IsIdentity) sql += " IDENTITY (" + IdentitySeed.ToString(CultureInfo.InvariantCulture) + "," + IdentityIncrement.ToString(CultureInfo.InvariantCulture) + ")";
if (IsIdentityForReplication) sql += " NOT FOR REPLICATION";
if (IsSparse) sql += " SPARSE";
if (IsFileStream) sql += " FILESTREAM";
if (IsNullable)
sql += " NULL";
else
sql += " NOT NULL";
if (IsRowGuid) sql += " ROWGUIDCOL";
}
else
{
sql += "AS " + ComputedFormula;
if (IsPersisted) sql += " PERSISTED";
}
if ((sqlConstraint) && (DefaultConstraint != null))
{
if (DefaultConstraint.Status != ObjectStatus.Drop)
sql += " " + DefaultConstraint.ToSql().Replace("\t", "").Trim();
}
return sql;
}
public SQLScriptList RebuildDependencies()
{
SQLScriptList list = new SQLScriptList();
list.AddRange(RebuildConstraint());
list.AddRange(RebuildIndex());
list.AddRange(RebuildFullTextIndex());
return list;
}
private SQLScriptList RebuildFullTextIndex()
{
return RebuildFullTextIndex(null);
}
private SQLScriptList RebuildFullTextIndex(string index)
{
bool it;
SQLScriptList list = new SQLScriptList();
((Table)Parent).FullTextIndex.ForEach(item =>
{
if (index == null)
it = item.Columns.Exists(col => { return col.ColumnName.Equals(this.Name); });
else
it = item.Index.Equals(index);
if (it)
{
if (item.Status != ObjectStatus.Create) list.Add(item.Drop());
if (item.Status != ObjectStatus.Drop) list.Add(item.Create());
}
}
);
return list;
}
private SQLScriptList RebuildConstraint()
{
SQLScriptList list = new SQLScriptList();
((Table)Parent).Constraints.ForEach(item =>
{
ConstraintColumn ic = item.Columns.Find(this.Id);
if (ic != null)
{
if (item.Status != ObjectStatus.Create) list.Add(item.Drop());
if (item.Status != ObjectStatus.Drop) list.Add(item.Create());
list.AddRange(RebuildFullTextIndex(item.Name));
}
});
return list;
}
private SQLScriptList RebuildIndex()
{
SQLScriptList list = new SQLScriptList();
if (HasIndexDependencies)
{
((Table)Parent).Indexes.ForEach(item =>
{
IndexColumn ic = item.Columns.Find(this.Id);
if (ic != null)
{
if (item.Status != ObjectStatus.Create) list.Add(item.Drop());
if (item.Status != ObjectStatus.Drop) list.Add(item.Create());
list.AddRange(RebuildFullTextIndex(item.Name));
}
});
}
return list;
}
public SQLScriptList RebuildConstraint(Boolean Check)
{
SQLScriptList list = new SQLScriptList();
if (DefaultConstraint != null)
{
if ((!Check) || (DefaultConstraint.CanCreate)) list.Add(DefaultConstraint.Create());
list.Add(DefaultConstraint.Drop());
}
return list;
}
public SQLScriptList RebuildSchemaBindingDependencies()
{
SQLScriptList list = new SQLScriptList();
List<ISchemaBase> items = ((Database)this.Parent.Parent).Dependencies.Find(this.Parent.Id, this.Id, 0);
items.ForEach(item =>
{
if ((item.ObjectType == ObjectType.Function) || (item.ObjectType == ObjectType.View))
{
if (item.Status != ObjectStatus.Create)
list.Add(item.Drop());
if (item.Status != ObjectStatus.Drop)
list.Add(item.Create());
}
});
return list;
}
public SQLScriptList Alter(ScriptAction typeStatus)
{
SQLScriptList list = new SQLScriptList();
string sql = "ALTER TABLE " + Parent.FullName + " ALTER COLUMN " + this.ToSql(false) + "\r\nGO\r\n";
list.Add(sql, 0, typeStatus);
return list;
}
/// <summary>
/// Compara solo las propiedades de dos campos relacionadas con los Identity. Si existen
/// diferencias, devuelve falso, caso contrario, true.
/// </summary>
public static Boolean CompareIdentity(Column origin, Column destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.IsIdentity != destination.IsIdentity) return false;
if (origin.IsIdentityForReplication != destination.IsIdentityForReplication) return false;
if (origin.IdentityIncrement != destination.IdentityIncrement) return false;
if (origin.IdentitySeed != destination.IdentitySeed) return false;
return true;
}
public static Boolean CompareRule(Column origin, Column destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if ((origin.Rule.Name != null) && (destination.Rule.Name == null)) return false;
if ((origin.Rule.Name == null) && (destination.Rule.Name != null)) return false;
if (origin.Rule.Name != null)
if (!origin.Rule.Name.Equals(destination.Rule.Name)) return false;
return true;
}
/// <summary>
/// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean Compare(Column origin, Column destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (!origin.ComputedFormula.Equals(destination.ComputedFormula)) return false;
if (origin.IsComputed != destination.IsComputed) return false;
//if (origin.Position != destination.Position) return false;
if (!origin.IsComputed)
{
if (origin.IsXmlDocument != destination.IsXmlDocument) return false;
if ((origin.XmlSchema == null) && (destination.XmlSchema != null)) return false;
if (origin.XmlSchema != null)
if (!origin.XmlSchema.Equals(destination.XmlSchema)) return false;
if (origin.IsNullable != destination.IsNullable) return false;
if (origin.IsFileStream != destination.IsFileStream) return false;
if (origin.IsSparse != destination.IsSparse) return false;
if (!origin.Collation.Equals(destination.Collation)) return false;
if (!origin.Type.Equals(destination.Type, StringComparison.CurrentCultureIgnoreCase)) return false;
//Si el tipo de campo es custom, no compara size del campo.
if (!origin.IsUserDefinedType)
{
if (origin.Precision != destination.Precision) return false;
if (origin.Scale != destination.Scale) return false;
//Si el tamaño de un campo Text cambia, entonces por la opcion TextInRowLimit.
if ((origin.Size != destination.Size) && (origin.Type.Equals(destination.Type, StringComparison.CurrentCultureIgnoreCase)) && (!origin.Type.Equals("text", StringComparison.CurrentCultureIgnoreCase))) return false;
}
}
else
{
if (origin.IsPersisted != destination.IsPersisted) return false;
}
if (!CompareIdentity(origin, destination)) return false;
return CompareRule(origin, destination);
}
public int CompareTo(Column other)
{
return this.Id.CompareTo(other.Id);
}
}
}

View File

@@ -0,0 +1,171 @@
using System;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
/// <summary>
/// Clase de constraints de Columnas (Default Constraint y Check Constraint)
/// </summary>
public class ColumnConstraint : SQLServerSchemaBase
{
public ColumnConstraint(Column parent)
: base(parent, ObjectType.Constraint)
{
}
/// <summary>
/// Clona el objeto ColumnConstraint en una nueva instancia.
/// </summary>
public ColumnConstraint Clone(Column parent)
{
ColumnConstraint ccons = new ColumnConstraint(parent);
ccons.Name = this.Name;
ccons.Type = this.Type;
ccons.Definition = this.Definition;
ccons.Status = this.Status;
ccons.Disabled = this.Disabled;
ccons.Owner = this.Owner;
return ccons;
}
/// <summary>
/// Indica si la constraint esta deshabilitada.
/// </summary>
public Boolean Disabled { get; set; }
/// <summary>
/// Indica si la constraint va a ser usada en replicacion.
/// </summary>
public Boolean NotForReplication { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [with no check].
/// </summary>
/// <value><c>true</c> if [with no check]; otherwise, <c>false</c>.</value>
public Boolean WithNoCheck { get; set; }
/// <summary>
/// Valor de la constraint.
/// </summary>
public string Definition { get; set; }
/// <summary>
/// Indica el tipo de constraint (Default o Check constraint).
/// </summary>
public Constraint.ConstraintType Type { get; set; }
/// <summary>
/// Convierte el schema de la constraint en XML.
/// </summary>
public string ToXML()
{
string xml = "";
if (this.Type == Constraint.ConstraintType.Default)
{
xml += "<COLUMNCONSTRAINT name=\"" + Name + "\" type=\"DF\" value=\"" + Definition + "\"/>\n";
}
if (this.Type == Constraint.ConstraintType.Check)
{
xml += "<COLUMNCONSTRAINT name=\"" + Name + "\" type=\"C\" value=\"" + Definition + "\" notForReplication=\"" + (NotForReplication ? "1" : "0") + "\"/>\n";
}
return xml;
}
/// <summary>
/// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean Compare(ColumnConstraint origin, ColumnConstraint destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.NotForReplication != destination.NotForReplication) return false;
if (origin.Disabled != destination.Disabled) return false;
if ((!origin.Definition.Equals(destination.Definition)) && (!origin.Definition.Equals("(" + destination.Definition + ")"))) return false;
return true;
}
public override SQLScript Create()
{
ScriptAction action = ScriptAction.AddConstraint;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(this.ToSqlAdd(), 0, action);
}
else
return null;
}
public override SQLScript Drop()
{
ScriptAction action = ScriptAction.DropConstraint;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(this.ToSqlDrop(), 0, action);
}
else
return null;
}
public Boolean CanCreate
{
get
{
ObjectStatus tableStatus = this.Parent.Parent.Status;
ObjectStatus columnStatus = this.Parent.Status;
return ((columnStatus != ObjectStatus.Drop) && (((tableStatus == ObjectStatus.Alter) || (tableStatus == ObjectStatus.Original) || (tableStatus == ObjectStatus.RebuildDependencies)) && (this.Status == ObjectStatus.Original)));
}
}
/// <summary>
/// Devuelve el schema de la constraint en formato SQL.
/// </summary>
public override string ToSql()
{
string sql = "";
if (this.Type == Constraint.ConstraintType.Default)
sql = " CONSTRAINT [" + Name + "] DEFAULT " + Definition;
return sql;
}
/// <summary>
/// Toes the SQL add.
/// </summary>
/// <returns></returns>
public override string ToSqlAdd()
{
if (this.Type == Constraint.ConstraintType.Default)
return "ALTER TABLE " + ((Table)Parent.Parent).FullName + " ADD" + ToSql() + " FOR [" + Parent.Name + "]\r\nGO\r\n";
if (this.Type == Constraint.ConstraintType.Check)
return "ALTER TABLE " + ((Table)Parent.Parent).FullName + " ADD" + ToSql() + "\r\nGO\r\n";
return "";
}
/// <summary>
/// Toes the SQL drop.
/// </summary>
/// <returns></returns>
public override string ToSqlDrop()
{
return "ALTER TABLE " + ((Table)Parent.Parent).FullName + " DROP CONSTRAINT [" + Name + "]\r\nGO\r\n";
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<OpenDBDiff.Schema.Model.ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.HasState(ObjectStatus.Drop))
list.Add(Drop());
if (this.HasState(ObjectStatus.Create))
list.Add(Create());
if (this.Status == ObjectStatus.Alter)
{
list.Add(Drop());
list.Add(Create());
}
return list;
}
}
}

View File

@@ -0,0 +1,114 @@
using OpenDBDiff.Schema.Model;
using System;
using System.Linq;
using System.Text;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Columns<T> : SchemaList<Column, T> where T : ISchemaBase
{
public Columns(T parent) : base(parent)
{
}
/// <summary>
/// Clona el objeto Columns en una nueva instancia.
/// </summary>
public new Columns<T> Clone(T parentObject)
{
Columns<T> columns = new Columns<T>(parentObject);
for (int index = 0; index < this.Count; index++)
{
columns.Add(this[index].Clone(parentObject));
}
return columns;
}
public override string ToSql()
{
return string.Join
(
",\r\n",
this
.Where(c => !c.HasState(ObjectStatus.Drop))
.Select(c => "\t" + c.ToSql(true))
);
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
string sqlDrop = "";
string sqlAdd = "";
string sqlCons = "";
string sqlBinds = "";
SQLScriptList list = new SQLScriptList();
if (Parent.Status != ObjectStatus.Rebuild)
{
this.ForEach(item =>
{
bool isIncluded = schemas.Count == 0;
if (!isIncluded)
{
foreach (var selectedSchema in schemas)
{
if (selectedSchema.Id == item.Id)
{
isIncluded = true;
break;
}
}
}
if (isIncluded)
{
if (item.HasState(ObjectStatus.Drop))
{
if (item.DefaultConstraint != null)
list.Add(item.DefaultConstraint.Drop());
/*Si la columna formula debe ser eliminada y ya fue efectuada la operacion en otro momento, no
* se borra nuevamente*/
if (!item.GetWasInsertInDiffList(ScriptAction.AlterColumnFormula))
sqlDrop += "[" + item.Name + "],";
}
if (item.HasState(ObjectStatus.Create))
sqlAdd += "\r\n" + item.ToSql(true) + ",";
if ((item.HasState(ObjectStatus.Alter) || (item.HasState(ObjectStatus.RebuildDependencies))))
{
if ((!item.Parent.HasState(ObjectStatus.RebuildDependencies) || (!item.Parent.HasState(ObjectStatus.Rebuild))))
list.AddRange(item.RebuildSchemaBindingDependencies());
list.AddRange(item.RebuildConstraint(false));
list.AddRange(item.RebuildDependencies());
list.AddRange(item.Alter(ScriptAction.AlterTable));
}
if (item.HasState(ObjectStatus.Update))
list.Add("UPDATE " + Parent.FullName + " SET [" + item.Name + "] = " + item.DefaultForceValue + " WHERE [" + item.Name + "] IS NULL\r\nGO\r\n", 0, ScriptAction.UpdateTable);
if (item.HasState(ObjectStatus.Bind))
{
if (item.Rule.Id != 0)
sqlBinds += item.Rule.ToSQLAddBind();
if (item.Rule.Id == 0)
sqlBinds += item.Rule.ToSQLAddUnBind();
}
if (item.DefaultConstraint != null)
list.AddRange(item.DefaultConstraint.ToSqlDiff(schemas));
}
});
if (!String.IsNullOrEmpty(sqlDrop))
sqlDrop = "ALTER TABLE " + Parent.FullName + " DROP COLUMN " + sqlDrop.Substring(0, sqlDrop.Length - 1) + "\r\nGO\r\n";
if (!String.IsNullOrEmpty(sqlAdd))
sqlAdd = "ALTER TABLE " + Parent.FullName + " ADD " + sqlAdd.Substring(0, sqlAdd.Length - 1) + "\r\nGO\r\n";
if (!String.IsNullOrEmpty(sqlDrop + sqlAdd + sqlCons + sqlBinds))
list.Add(sqlDrop + sqlAdd + sqlBinds, 0, ScriptAction.AlterTable);
}
else
{
this.ForEach(item =>
{
if (item.Status != ObjectStatus.Original)
item.RootParent.ActionMessage[item.Parent.FullName].Add(item);
});
}
return list;
}
}
}

View File

@@ -0,0 +1,359 @@
using System;
using System.Globalization;
using System.Text;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Constraint : SQLServerSchemaBase
{
public enum ConstraintType
{
None = 0,
PrimaryKey = 1,
ForeignKey = 2,
Default = 3,
Unique = 4,
Check = 5
}
public Constraint(ISchemaBase parent)
: base(parent, ObjectType.Constraint)
{
this.Columns = new ConstraintColumns(this);
this.Index = new Index(parent);
}
/// <summary>
/// Clona el objeto Column en una nueva instancia.
/// </summary>
public override ISchemaBase Clone(ISchemaBase parent)
{
Constraint col = new Constraint(parent);
col.Id = this.Id;
col.Name = this.Name;
col.NotForReplication = this.NotForReplication;
col.RelationalTableFullName = this.RelationalTableFullName;
col.Status = this.Status;
col.Type = this.Type;
col.WithNoCheck = this.WithNoCheck;
col.OnDeleteCascade = this.OnDeleteCascade;
col.OnUpdateCascade = this.OnUpdateCascade;
col.Owner = this.Owner;
col.Columns = this.Columns.Clone();
col.Index = (Index)this.Index.Clone(parent);
col.IsDisabled = this.IsDisabled;
col.Definition = this.Definition;
col.Guid = this.Guid;
return col;
}
/// <summary>
/// Informacion sobre le indice asociado al Constraint.
/// </summary>
public Index Index { get; set; }
/// <summary>
/// Coleccion de columnas de la constraint.
/// </summary>
public ConstraintColumns Columns { get; set; }
/// <summary>
/// Indica si la constraint tiene asociada un indice Clustered.
/// </summary>
public Boolean HasClusteredIndex
{
get
{
if (Index != null)
return (Index.Type == Index.IndexTypeEnum.Clustered);
return false;
}
}
/// <summary>
/// Gets or sets a value indicating whether this constraint is disabled.
/// </summary>
/// <value>
/// <c>true</c> if this constraint is disabled; otherwise, <c>false</c>.
/// </value>
public Boolean IsDisabled { get; set; }
/// <summary>
/// Gets or sets the on delete cascade (only for FK).
/// </summary>
/// <value>The on delete cascade.</value>
public int OnDeleteCascade { get; set; }
/// <summary>
/// Gets or sets the on update cascade (only for FK).
/// </summary>
/// <value>The on update cascade.</value>
public int OnUpdateCascade { get; set; }
/// <summary>
/// Valor de la constraint (se usa para los Check Constraint).
/// </summary>
public string Definition { get; set; }
/// <summary>
/// Indica si la constraint va a ser usada en replicacion.
/// </summary>
public Boolean NotForReplication { get; set; }
/// <summary>
/// Gets or sets a value indicating whether [with no check].
/// </summary>
/// <value><c>true</c> if [with no check]; otherwise, <c>false</c>.</value>
public Boolean WithNoCheck { get; set; }
/// <summary>
/// Indica el tipo de constraint (PrimaryKey, ForeignKey, Unique o Default).
/// </summary>
public ConstraintType Type { get; set; }
/// <summary>
/// ID de la tabla relacionada a la que hace referencia (solo aplica a FK)
/// </summary>
public int RelationalTableId { get; set; }
/// <summary>
/// Nombre de la tabla relacionada a la que hace referencia (solo aplica a FK)
/// </summary>
public string RelationalTableFullName { get; set; }
/// <summary>
/// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean Compare(Constraint origin, Constraint destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.NotForReplication != destination.NotForReplication) return false;
if ((origin.RelationalTableFullName == null) && (destination.RelationalTableFullName != null)) return false;
if (origin.RelationalTableFullName != null)
if (!origin.RelationalTableFullName.Equals(destination.RelationalTableFullName, StringComparison.CurrentCultureIgnoreCase)) return false;
if ((origin.Definition == null) && (destination.Definition != null)) return false;
if (origin.Definition != null)
if ((!origin.Definition.Equals(destination.Definition)) && (!origin.Definition.Equals("(" + destination.Definition + ")"))) return false;
/*Solo si la constraint esta habilitada, se chequea el is_trusted*/
if (!destination.IsDisabled)
if (origin.WithNoCheck != destination.WithNoCheck) return false;
if (origin.OnUpdateCascade != destination.OnUpdateCascade) return false;
if (origin.OnDeleteCascade != destination.OnDeleteCascade) return false;
if (!ConstraintColumns.Compare(origin.Columns, destination.Columns)) return false;
if ((origin.Index != null) && (destination.Index != null))
return Index.Compare(origin.Index, destination.Index);
return true;
}
private string ToSQLGeneric(ConstraintType consType)
{
Database database = null;
ISchemaBase current = this;
while (database == null && current.Parent != null)
{
database = current.Parent as Database;
current = current.Parent;
}
var isAzure10 = database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10;
string typeConstraint = "";
StringBuilder sql = new StringBuilder();
if (Index.Type == Index.IndexTypeEnum.Clustered) typeConstraint = "CLUSTERED";
if (Index.Type == Index.IndexTypeEnum.Nonclustered) typeConstraint = "NONCLUSTERED";
if (Index.Type == Index.IndexTypeEnum.XML) typeConstraint = "XML";
if (Index.Type == Index.IndexTypeEnum.Heap) typeConstraint = "HEAP";
if (Parent.ObjectType != ObjectType.TableType)
sql.Append("CONSTRAINT [" + Name + "] ");
else
sql.Append("\t");
if (consType == ConstraintType.PrimaryKey)
sql.Append("PRIMARY KEY " + typeConstraint + "\r\n\t(\r\n");
else
sql.Append("UNIQUE " + typeConstraint + "\r\n\t(\r\n");
this.Columns.Sort();
for (int j = 0; j < this.Columns.Count; j++)
{
sql.Append("\t\t[" + this.Columns[j].Name + "]");
if (this.Columns[j].Order) sql.Append(" DESC"); else sql.Append(" ASC");
if (j != this.Columns.Count - 1) sql.Append(",");
sql.Append("\r\n");
}
sql.Append("\t)");
sql.Append(" WITH (");
if (Parent.ObjectType == ObjectType.TableType)
if (Index.IgnoreDupKey) sql.Append("IGNORE_DUP_KEY = ON"); else sql.Append("IGNORE_DUP_KEY = OFF");
else
{
if (!isAzure10)
{
if (Index.IsPadded) sql.Append("PAD_INDEX = ON, "); else sql.Append("PAD_INDEX = OFF, ");
}
if (Index.IsAutoStatistics) sql.Append("STATISTICS_NORECOMPUTE = ON"); else sql.Append("STATISTICS_NORECOMPUTE = OFF");
if (Index.IgnoreDupKey) sql.Append(", IGNORE_DUP_KEY = ON"); else sql.Append(", IGNORE_DUP_KEY = OFF");
if (!isAzure10)
{
if (Index.AllowRowLocks) sql.Append(", ALLOW_ROW_LOCKS = ON"); else sql.Append(", ALLOW_ROW_LOCKS = OFF");
if (Index.AllowPageLocks) sql.Append(", ALLOW_PAGE_LOCKS = ON"); else sql.Append(", ALLOW_PAGE_LOCKS = OFF");
if (Index.FillFactor != 0) sql.Append(", FILLFACTOR = " + Index.FillFactor.ToString(CultureInfo.InvariantCulture));
}
}
sql.Append(")");
if (!isAzure10)
{
if (!String.IsNullOrEmpty(Index.FileGroup)) sql.Append(" ON [" + Index.FileGroup + "]");
}
return sql.ToString();
}
/// <summary>
/// Devuelve el schema de la tabla en formato SQL.
/// </summary>
public override string ToSql()
{
if (this.Type == ConstraintType.PrimaryKey)
{
return ToSQLGeneric(ConstraintType.PrimaryKey);
}
if (this.Type == ConstraintType.ForeignKey)
{
StringBuilder sql = new StringBuilder();
StringBuilder sqlReference = new StringBuilder();
int indexc = 0;
this.Columns.Sort();
sql.Append("CONSTRAINT [" + Name + "] FOREIGN KEY\r\n\t(\r\n");
foreach (ConstraintColumn column in this.Columns)
{
sql.Append("\t\t[" + column.Name + "]");
sqlReference.Append("\t\t[" + column.ColumnRelationalName + "]");
if (indexc != this.Columns.Count - 1)
{
sql.Append(",");
sqlReference.Append(",");
}
sql.Append("\r\n");
sqlReference.Append("\r\n");
indexc++;
}
sql.Append("\t)\r\n");
sql.Append("\tREFERENCES " + this.RelationalTableFullName + "\r\n\t(\r\n");
sql.Append(sqlReference + "\t)");
if (OnUpdateCascade == 1) sql.Append(" ON UPDATE CASCADE");
if (OnDeleteCascade == 1) sql.Append(" ON DELETE CASCADE");
if (OnUpdateCascade == 2) sql.Append(" ON UPDATE SET NULL");
if (OnDeleteCascade == 2) sql.Append(" ON DELETE SET NULL");
if (OnUpdateCascade == 3) sql.Append(" ON UPDATE SET DEFAULT");
if (OnDeleteCascade == 3) sql.Append(" ON DELETE SET DEFAULT");
sql.Append((NotForReplication ? " NOT FOR REPLICATION" : ""));
return sql.ToString();
}
if (this.Type == ConstraintType.Unique)
{
return ToSQLGeneric(ConstraintType.Unique);
}
if (this.Type == ConstraintType.Check)
{
string sqlcheck = "";
if (Parent.ObjectType != ObjectType.TableType)
sqlcheck = "CONSTRAINT [" + Name + "] ";
return sqlcheck + "CHECK " + (NotForReplication ? "NOT FOR REPLICATION" : "") + " (" + Definition + ")";
}
return "";
}
public override string ToSqlAdd()
{
return "ALTER TABLE " + Parent.FullName + (WithNoCheck ? " WITH NOCHECK" : "") + " ADD " + ToSql() + "\r\nGO\r\n";
}
public override string ToSqlDrop()
{
return ToSqlDrop(null);
}
public override SQLScript Create()
{
ScriptAction action = ScriptAction.AddConstraint;
if (this.Type == ConstraintType.ForeignKey)
action = ScriptAction.AddConstraintFK;
if (this.Type == ConstraintType.PrimaryKey)
action = ScriptAction.AddConstraintPK;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(this.ToSqlAdd(), ((Table)Parent).DependenciesCount, action);
}
else
return null;
}
public override SQLScript Drop()
{
ScriptAction action = ScriptAction.DropConstraint;
if (this.Type == ConstraintType.ForeignKey)
action = ScriptAction.DropConstraintFK;
if (this.Type == ConstraintType.PrimaryKey)
action = ScriptAction.DropConstraintPK;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(this.ToSqlDrop(), ((Table)Parent).DependenciesCount, action);
}
else
return null;
}
public string ToSqlDrop(string FileGroupName)
{
string sql = "ALTER TABLE " + ((Table)Parent).FullName + " DROP CONSTRAINT [" + Name + "]";
if (!String.IsNullOrEmpty(FileGroupName)) sql += " WITH (MOVE TO [" + FileGroupName + "])";
sql += "\r\nGO\r\n";
return sql;
}
public string ToSQLEnabledDisabled()
{
StringBuilder sql = new StringBuilder();
if (this.IsDisabled)
return "ALTER TABLE " + Parent.FullName + " NOCHECK CONSTRAINT [" + Name + "]\r\nGO\r\n";
else
{
return "ALTER TABLE " + Parent.FullName + " CHECK CONSTRAINT [" + Name + "]\r\nGO\r\n";
}
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.Status != ObjectStatus.Original)
RootParent.ActionMessage[Parent.FullName].Add(this);
if (this.HasState(ObjectStatus.Drop))
{
if (this.Parent.Status != ObjectStatus.Rebuild)
list.Add(Drop());
}
if (this.HasState(ObjectStatus.Create))
list.Add(Create());
if (this.HasState(ObjectStatus.Alter))
{
list.Add(Drop());
list.Add(Create());
}
if (this.HasState(ObjectStatus.Disabled))
{
list.Add(this.ToSQLEnabledDisabled(), ((Table)Parent).DependenciesCount, ScriptAction.AlterConstraint);
}
/*if (this.Status == StatusEnum.ObjectStatusType.ChangeFileGroup)
{
list.Add(this.ToSQLDrop(this.Index.FileGroup), ((Table)Parent).DependenciesCount, actionDrop);
list.Add(this.ToSQLAdd(), ((Table)Parent).DependenciesCount, actionAdd);
}*/
return list;
}
}
}

View File

@@ -0,0 +1,89 @@
using System;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class ConstraintColumn : SQLServerSchemaBase, IComparable<ConstraintColumn>
{
public ConstraintColumn(Constraint parentObject)
: base(parentObject, ObjectType.ConstraintColumn)
{
}
public ConstraintColumn Clone()
{
ConstraintColumn ccol = new ConstraintColumn((Constraint)this.Parent);
ccol.ColumnRelationalName = this.ColumnRelationalName;
ccol.ColumnRelationalId = this.ColumnRelationalId;
ccol.Name = this.Name;
ccol.IsIncluded = this.IsIncluded;
ccol.Order = this.Order;
ccol.KeyOrder = this.KeyOrder;
ccol.Id = this.Id;
ccol.DataTypeId = this.DataTypeId;
ccol.ColumnRelationalDataTypeId = this.ColumnRelationalDataTypeId;
return ccol;
}
public int DataTypeId { get; set; }
public int ColumnRelationalDataTypeId { get; set; }
public int ColumnRelationalId { get; set; }
/// <summary>
/// Gets or sets the column key order in the index.
/// </summary>
/// <value>The key order.</value>
public int KeyOrder { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this column is included in the index leaf page.
/// </summary>
/// <value>
/// <c>true</c> if this column is included; otherwise, <c>false</c>.
/// </value>
public Boolean IsIncluded { get; set; }
/// <summary>
/// Orden de la columna (Ascendente o Descendente). Se usa solo en Primary Keys.
/// </summary>
public Boolean Order { get; set; }
public string ColumnRelationalName { get; set; }
public override string ToSqlDrop()
{
return "";
}
public override string ToSqlAdd()
{
return "";
}
public override string ToSql()
{
return "";
}
public static Boolean Compare(ConstraintColumn origin, ConstraintColumn destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if ((origin.ColumnRelationalName == null) && (destination.ColumnRelationalName != null)) return false;
if (origin.ColumnRelationalName != null)
{
if (!origin.ColumnRelationalName.Equals(destination.ColumnRelationalName, StringComparison.CurrentCultureIgnoreCase)) return false;
}
if (origin.IsIncluded != destination.IsIncluded) return false;
if (origin.Order != destination.Order) return false;
if (origin.KeyOrder != destination.KeyOrder) return false;
return true;
}
public int CompareTo(ConstraintColumn other)
{
return this.ColumnRelationalId.CompareTo(other.ColumnRelationalId);
}
}
}

View File

@@ -0,0 +1,53 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class ConstraintColumns : SchemaList<ConstraintColumn, Constraint>
{
public ConstraintColumns(Constraint parent)
: base(parent)
{
}
/// <summary>
/// Clona el objeto ColumnConstraints en una nueva instancia.
/// </summary>
public ConstraintColumns Clone()
{
ConstraintColumns columns = new ConstraintColumns(this.Parent);
for (int index = 0; index < this.Count; index++)
{
columns.Add(this[index].Clone());
}
return columns;
}
/// <summary>
/// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean Compare(ConstraintColumns origin, ConstraintColumns destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.Count != destination.Count) return false;
for (int j = 0; j < origin.Count; j++)
{
ConstraintColumn item = destination[origin[j].FullName];
if (item == null)
return false;
else
if (!ConstraintColumn.Compare(origin[j], item)) return false;
}
for (int j = 0; j < destination.Count; j++)
{
ConstraintColumn item = origin[destination[j].FullName];
if (item == null)
return false;
else
if (!ConstraintColumn.Compare(destination[j], item)) return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,446 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using OpenDBDiff.Schema.Attributes;
using OpenDBDiff.Schema.Model;
using OpenDBDiff.Schema.SQLServer.Generates.Options;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Database : SQLServerSchemaBase, IDatabase
{
private readonly List<DatabaseChangeStatus> _changesOptions;
public Database() : base(null, ObjectType.Database)
{
AllObjects = new SearchSchemaBase();
_changesOptions = new List<DatabaseChangeStatus>();
Dependencies = new Dependencies();
TablesTypes = new SchemaList<TableType, Database>(this, AllObjects);
UserTypes = new SchemaList<UserDataType, Database>(this, AllObjects);
XmlSchemas = new SchemaList<XMLSchema, Database>(this, AllObjects);
Schemas = new SchemaList<Schema, Database>(this, AllObjects);
Procedures = new SchemaList<StoredProcedure, Database>(this, AllObjects);
CLRProcedures = new SchemaList<CLRStoredProcedure, Database>(this, AllObjects);
CLRFunctions = new SchemaList<CLRFunction, Database>(this, AllObjects);
FileGroups = new SchemaList<FileGroup, Database>(this);
Rules = new SchemaList<Rule, Database>(this, AllObjects);
DDLTriggers = new SchemaList<Trigger, Database>(this, AllObjects);
Synonyms = new SchemaList<Synonym, Database>(this, AllObjects);
Assemblies = new SchemaList<Assembly, Database>(this, AllObjects);
Views = new SchemaList<View, Database>(this, AllObjects);
Users = new SchemaList<User, Database>(this, AllObjects);
FullText = new SchemaList<FullText, Database>(this, AllObjects);
Functions = new SchemaList<Function, Database>(this, AllObjects);
PartitionFunctions = new SchemaList<PartitionFunction, Database>(this, AllObjects);
PartitionSchemes = new SchemaList<PartitionScheme, Database>(this, AllObjects);
Roles = new SchemaList<Role, Database>(this);
Tables = new SchemaList<Table, Database>(this, AllObjects);
Defaults = new SchemaList<Default, Database>(this, AllObjects);
ActionMessage = new SqlAction(this);
}
internal SearchSchemaBase AllObjects { get; private set; }
[SchemaNode("Full Text Catalog", "FullText")]
public SchemaList<FullText, Database> FullText { get; private set; }
[SchemaNode("Table Type", "Table")]
public SchemaList<TableType, Database> TablesTypes { get; private set; }
[SchemaNode("Partition Scheme", "PartitionScheme")]
public SchemaList<PartitionScheme, Database> PartitionSchemes { get; private set; }
[SchemaNode("Partition Functions", "PartitionFunction")]
public SchemaList<PartitionFunction, Database> PartitionFunctions { get; private set; }
[SchemaNode("Defaults")]
public SchemaList<Default, Database> Defaults { get; private set; }
[SchemaNode("Roles", "Rol")]
public SchemaList<Role, Database> Roles { get; private set; }
[SchemaNode("Functions", "Function", true)]
public SchemaList<Function, Database> Functions { get; private set; }
[SchemaNode("Users", "User")]
public SchemaList<User, Database> Users { get; private set; }
[SchemaNode("Views", "View", true)]
public SchemaList<View, Database> Views { get; private set; }
[SchemaNode("Assemblies", "Assembly")]
public SchemaList<Assembly, Database> Assemblies { get; private set; }
[SchemaNode("Synonyms", "Assembly")] // We don't have an icon for synonyms at the moment.
public SchemaList<Synonym, Database> Synonyms { get; private set; }
[SchemaNode("DLL Triggers")]
public SchemaList<Trigger, Database> DDLTriggers { get; private set; }
[SchemaNode("File Groups")]
public SchemaList<FileGroup, Database> FileGroups { get; private set; }
[SchemaNode("Rules")]
public SchemaList<Rule, Database> Rules { get; private set; }
[SchemaNode("Stored Procedures", "Procedure", true)]
public SchemaList<StoredProcedure, Database> Procedures { get; private set; }
[SchemaNode("CLR Stored Procedures", "CLRProcedure", true)]
public SchemaList<CLRStoredProcedure, Database> CLRProcedures { get; private set; }
[SchemaNode("CLR Functions", "CLRFunction", true)]
public SchemaList<CLRFunction, Database> CLRFunctions { get; private set; }
[SchemaNode("Schemas", "Schema")]
public SchemaList<Schema, Database> Schemas { get; private set; }
[SchemaNode("XML Schemas", "XMLSchema")]
public SchemaList<XMLSchema, Database> XmlSchemas { get; private set; }
[SchemaNode("Tables", "Table", true)]
public SchemaList<Table, Database> Tables { get; private set; }
[SchemaNode("User Types", "UDT")]
public SchemaList<UserDataType, Database> UserTypes { get; private set; }
public SqlOption Options { get; set; }
IOption IDatabase.Options { get { return Options; } }
public DatabaseInfo Info { get; set; }
public DatabaseInfo SourceInfo
{
get;
set;
}
/// <summary>
/// Coleccion de dependencias de constraints.
/// </summary>
internal Dependencies Dependencies { get; set; }
private List<DatabaseChangeStatus> ChangesOptions
{
get { return _changesOptions; }
}
#region IDatabase Members
public override ISchemaBase Clone(ISchemaBase parent)
{
//Get a list of all of the objects that are SchemaLists, so that we can clone them all.
var item = new Database() { AllObjects = this.AllObjects };
var explicitProperties = (from properties in this.GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)
where properties.PropertyType.GetInterface(typeof(ISchemaList<Code, Database>).Name) != null
select properties).ToList();
foreach (var property in explicitProperties)
{
object value = property.GetValue(this, null);
//Clone the value
value = value.GetType().GetMethod("Clone").Invoke(value, new object[] { this });
//Set the value to the cloned object
property.SetValue(item, value, null);
}
return item;
}
public SqlAction ActionMessage { get; private set; }
public Boolean IsCaseSensitive
{
get
{
bool isCS = false;
if (!String.IsNullOrEmpty(Info.Collation))
isCS = Info.Collation.IndexOf("_CS_") != -1;
if (Options.Comparison.CaseSensityType == SqlOptionComparison.CaseSensityOptions.Automatic)
return isCS;
if (Options.Comparison.CaseSensityType == SqlOptionComparison.CaseSensityOptions.CaseSensity)
return true;
if (Options.Comparison.CaseSensityType == SqlOptionComparison.CaseSensityOptions.CaseInsensity)
return false;
return false;
}
}
public override string ToSql()
{
string sql = "";
sql += FileGroups.ToSql();
sql += Schemas.ToSql();
sql += XmlSchemas.ToSql();
sql += Rules.ToSql();
sql += UserTypes.ToSql();
sql += Assemblies.ToSql();
sql += Tables.ToSql();
sql += Functions.ToSql();
sql += Procedures.ToSql();
sql += CLRProcedures.ToSql();
sql += CLRFunctions.ToSql();
sql += DDLTriggers.ToSql();
sql += Synonyms.ToSql();
sql += Views.ToSql();
sql += Users.ToSql();
sql += PartitionFunctions.ToSql();
sql += FullText.ToSql();
return sql;
}
public override SQLScriptList ToSqlDiff(ICollection<ISchemaBase> schemas)
{
var isAzure10 = this.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10;
var listDiff = new SQLScriptList();
var header = $@"/*
OpenDBDiff {System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()}
https://github.com/OpenDBDiff/OpenDBDiff
Script created by {Environment.UserDomainName}\{Environment.UserName} on {DateTime.Now.ToShortDateString()} at {DateTime.Now.ToLongTimeString()}.
Created on: {Environment.MachineName}
Source: {SourceInfo?.Database ?? "Unknown"} on {SourceInfo?.Server ?? "Unknown"}
Destination: {Info?.Database ?? "Unknown"} on {Info?.Server ?? "Unknown"}
### This script performs actions to change the Destination schema to the Source schema. ###
*/
";
listDiff.Add(new SQLScript(header, 0, ScriptAction.None));
if (!isAzure10)
{
listDiff.Add("USE [" + Name + "]\r\nGO\r\n\r\n", 0, ScriptAction.UseDatabase);
listDiff.AddRange(Assemblies.ToSqlDiff(schemas));
listDiff.AddRange(UserTypes.ToSqlDiff(schemas));
}
listDiff.AddRange(TablesTypes.ToSqlDiff(schemas));
listDiff.AddRange(Tables.ToSqlDiff(schemas));
listDiff.AddRange(Rules.ToSqlDiff(schemas));
listDiff.AddRange(Schemas.ToSqlDiff(schemas));
listDiff.AddRange(XmlSchemas.ToSqlDiff(schemas));
listDiff.AddRange(Procedures.ToSqlDiff(schemas));
if (!isAzure10)
{
listDiff.AddRange(CLRProcedures.ToSqlDiff(schemas));
listDiff.AddRange(CLRFunctions.ToSqlDiff(schemas));
listDiff.AddRange(FileGroups.ToSqlDiff(schemas));
}
listDiff.AddRange(DDLTriggers.ToSqlDiff(schemas));
listDiff.AddRange(Synonyms.ToSqlDiff(schemas));
listDiff.AddRange(Views.ToSqlDiff(schemas));
listDiff.AddRange(Users.ToSqlDiff(schemas));
listDiff.AddRange(Functions.ToSqlDiff(schemas));
listDiff.AddRange(Roles.ToSqlDiff(schemas));
listDiff.AddRange(PartitionFunctions.ToSqlDiff(schemas));
listDiff.AddRange(PartitionSchemes.ToSqlDiff(schemas));
if (!isAzure10)
{
listDiff.AddRange(FullText.ToSqlDiff(schemas));
}
return listDiff;
}
public override string ToSqlDrop()
{
return "";
}
public override string ToSqlAdd()
{
return "";
}
#endregion
public ISchemaBase Find(int id)
{
try
{
string full = AllObjects.GetFullName(id);
return Find(full);
}
catch
{
return null;
}
}
public ISchemaBase Find(String _FullName)
{
try
{
var typeVal = AllObjects.GetType(_FullName);
if (!typeVal.HasValue)
{
return null;
}
ObjectType type = typeVal.Value;
string parentName = "";
switch (type)
{
case ObjectType.Table:
return Tables[_FullName];
case ObjectType.StoredProcedure:
return Procedures[_FullName];
case ObjectType.Function:
return Functions[_FullName];
case ObjectType.View:
return Views[_FullName];
case ObjectType.Assembly:
return Assemblies[_FullName];
case ObjectType.UserDataType:
return UserTypes[_FullName];
case ObjectType.TableType:
return TablesTypes[_FullName];
case ObjectType.XMLSchema:
return XmlSchemas[_FullName];
case ObjectType.CLRStoredProcedure:
return CLRProcedures[_FullName];
case ObjectType.CLRFunction:
return CLRFunctions[_FullName];
case ObjectType.Synonym:
return Synonyms[_FullName];
case ObjectType.FullText:
return FullText[_FullName];
case ObjectType.Rule:
return Rules[_FullName];
case ObjectType.PartitionFunction:
return PartitionFunctions[_FullName];
case ObjectType.PartitionScheme:
return PartitionSchemes[_FullName];
case ObjectType.Role:
return Roles[_FullName];
case ObjectType.Schema:
return Schemas[_FullName];
case ObjectType.Constraint:
parentName = AllObjects.GetParentName(_FullName);
return Tables[parentName].Constraints[_FullName];
case ObjectType.Index:
parentName = AllObjects.GetParentName(_FullName);
var typeName = AllObjects.GetType(parentName);
if (!typeName.HasValue)
{
return null;
}
type = typeName.Value;
if (type == ObjectType.Table)
return Tables[parentName].Indexes[_FullName];
return Views[parentName].Indexes[_FullName];
case ObjectType.Trigger:
parentName = AllObjects.GetParentName(_FullName);
var typeNameB = AllObjects.GetType(parentName);
if (!typeNameB.HasValue)
{
return null;
}
type = typeNameB.Value;
if (type == ObjectType.Table)
return Tables[parentName].Triggers[_FullName];
return Views[parentName].Triggers[_FullName];
case ObjectType.CLRTrigger:
parentName = AllObjects.GetParentName(_FullName);
var typeNameC = AllObjects.GetType(parentName);
if (!typeNameC.HasValue)
{
return null;
}
type = typeNameC.Value;
if (type == ObjectType.Table)
return Tables[parentName].CLRTriggers[_FullName];
return Views[parentName].CLRTriggers[_FullName];
}
return null;
}
catch
{
return null;
}
}
/*private SQLScriptList CleanScripts(SQLScriptList listDiff)
{
SQLScriptList alters = listDiff.FindAlter();
for (int j = 0; j < alters.Count; j++)
{
//alters[j].
}
return null;
}*/
public void BuildDependency()
{
ISchemaBase schema;
var indexes = new List<Index>();
var constraints = new List<Constraint>();
Tables.ForEach(item => indexes.AddRange(item.Indexes));
Views.ForEach(item => indexes.AddRange(item.Indexes));
Tables.ForEach(item => constraints.AddRange(item.Constraints));
foreach (Index index in indexes)
{
schema = index.Parent;
foreach (IndexColumn icolumn in index.Columns)
{
Dependencies.Add(this, schema.Id, icolumn.Id, schema.Id, icolumn.DataTypeId, index);
}
}
foreach (Constraint con in constraints)
{
schema = con.Parent;
if (con.Type != Constraint.ConstraintType.Check)
{
foreach (ConstraintColumn ccolumn in con.Columns)
{
Dependencies.Add(this, schema.Id, ccolumn.Id, schema.Id, ccolumn.DataTypeId, con);
if (con.Type == Constraint.ConstraintType.ForeignKey)
{
Dependencies.Add(this, con.RelationalTableId, ccolumn.ColumnRelationalId, schema.Id,
ccolumn.ColumnRelationalDataTypeId, con);
}
else
{
if (
((Table)schema).FullTextIndex.Exists(
item => { return item.Index.Equals(con.Name); }))
{
Dependencies.Add(this, schema.Id, 0, schema.Id, 0, con);
}
}
}
}
else
Dependencies.Add(this, schema.Id, 0, schema.Id, 0, con);
}
}
#region Nested type: DatabaseChangeStatus
private enum DatabaseChangeStatus
{
AlterChangeTracking = 1,
AlterCollation = 2
}
#endregion
}
}

View File

@@ -0,0 +1,94 @@
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class DatabaseInfo
{
public enum SQLServerVersion
{
SQLServer2000,
SQLServer2005,
SQLServer2008,
SQLServer2008R2,
// Azure will be reporting v11 instead of v10.25 soon...
// http://social.msdn.microsoft.com/Forums/en-US/ssdsgetstarted/thread/ad7aae98-26ac-4979-848d-517a86c3fa5c/
SQLServerAzure10, /*Azure*/
SQLServer2012,
SQLServer2014,
SQLServer2016,
SQLServer2017,
}
public enum SQLServerEdition
{
Personal = 1,
Standard = 2,
Enterprise = 3,
Express = 4,
Azure = 5
}
private float versionNumber;
public DatabaseInfo()
{
Version = SQLServerVersion.SQLServer2005;
}
public string Server { get; set; }
public string Database { get; set; }
public SQLServerVersion Version { get; private set; }
public SQLServerEdition Edition { get; private set; }
public string Collation { get; set; }
public bool HasFullTextEnabled { get; set; }
public string ChangeTrackingPeriodUnitsDesc { get; set; }
public int ChangeTrackingPeriodUnits { get; set; }
public int ChangeTrackingRetentionPeriod { get; set; }
public bool IsChangeTrackingAutoCleanup { get; set; }
public bool HasChangeTracking { get; set; }
public float VersionNumber
{
get { return versionNumber; }
set
{
versionNumber = value;
SQLServerVersion version = this.Version;
// https://buildnumbers.wordpress.com/sqlserver/
if (versionNumber >= 8) version = SQLServerVersion.SQLServer2000;
if (versionNumber >= 9) version = SQLServerVersion.SQLServer2005;
if (versionNumber >= 10) version = SQLServerVersion.SQLServer2008;
if (versionNumber >= 10.25) version = SQLServerVersion.SQLServerAzure10;
if (versionNumber >= 10.5) version = SQLServerVersion.SQLServer2008R2;
if (versionNumber >= 11.0) version = SQLServerVersion.SQLServer2012;
if (versionNumber >= 12.0) version = SQLServerVersion.SQLServer2014;
if (versionNumber >= 13.0) version = SQLServerVersion.SQLServer2016;
if (versionNumber >= 14.0) version = SQLServerVersion.SQLServer2017;
this.Version = version;
}
}
public void SetEdition(SQLServerEdition edition)
{
this.Edition = edition;
if (edition == SQLServerEdition.Azure)
{
this.Version = SQLServerVersion.SQLServerAzure10;
}
}
}
}

View File

@@ -0,0 +1,76 @@
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Default : SQLServerSchemaBase
{
public Default(ISchemaBase parent)
: base(parent, ObjectType.Default)
{
}
public new Default Clone(ISchemaBase parent)
{
Default item = new Default(parent);
item.Id = this.Id;
item.Name = this.Name;
item.Owner = this.Owner;
item.Value = this.Value;
return item;
}
public string Value { get; set; }
public string ToSQLAddBind()
{
string sql = "";
sql += "EXEC sp_bindefault N'" + Name + "', N'" + this.Parent.Name + "'\r\nGO\r\n";
return sql;
}
public string ToSQLAddUnBind()
{
string sql = "";
sql += "EXEC sp_unbindefault @objname=N'" + this.Parent.Name + "'\r\nGO\r\n";
return sql;
}
public override string ToSqlAdd()
{
return ToSql();
}
public override string ToSqlDrop()
{
return "DROP DEFAULT " + FullName + "\r\nGO\r\n";
}
public override string ToSql()
{
return "";
}
/// <summary>
/// Devuelve el schema de diferencias del Schema en formato SQL.
/// </summary>
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropRule);
}
if (this.Status == ObjectStatus.Create)
{
listDiff.Add(ToSql(), 0, ScriptAction.AddRule);
}
if (this.Status == ObjectStatus.Alter)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropRule);
listDiff.Add(ToSql(), 0, ScriptAction.AddRule);
}
return listDiff;
}
}
}

View File

@@ -0,0 +1,151 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
internal class Dependencies : List<Dependency>
{
public Database Database { get; private set; }
public void Add(Database database, int tableId, int columnId, int ownerTableId, int typeId, ISchemaBase constraint)
{
Dependency dependency = new Dependency();
dependency.SubObjectId = columnId;
dependency.ObjectId = tableId;
dependency.OwnerTableId = ownerTableId;
dependency.FullName = constraint.FullName;
dependency.Type = constraint.ObjectType;
dependency.DataTypeId = typeId;
this.Database = database;
base.Add(dependency);
}
public void Add(Database database, int objectId, ISchemaBase objectSchema)
{
Dependency dependency = new Dependency();
dependency.ObjectId = objectId;
dependency.FullName = objectSchema.FullName;
dependency.Type = objectSchema.ObjectType;
this.Database = database;
base.Add(dependency);
}
/// <summary>
/// Devuelve todos las constraints dependientes de una tabla.
/// </summary>
public List<ISchemaBase> FindNotOwner(int tableId, ObjectType type)
{
try
{
List<ISchemaBase> cons = new List<ISchemaBase>();
this.ForEach(dependency =>
{
if (dependency.Type == type)
{
ISchemaBase item = (ISchemaBase)Database.Find(dependency.FullName);
if (dependency.Type == ObjectType.Constraint)
{
if ((dependency.ObjectId == tableId) && (((Constraint)item).Type == Constraint.ConstraintType.ForeignKey))
cons.Add(item);
}
else
if (dependency.ObjectId == tableId)
cons.Add(item);
}
});
return cons;
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// Devuelve todos las constraints dependientes de una tabla.
/// </summary>
/*public void Set(int tableId, Constraint constraint)
{
this.ForEach(item =>
{
if (item.Type == ObjectType.Constraint)
if ((item.ObjectId == tableId) && (item.ObjectSchema.Name.Equals(constraint.Name)))
item.ObjectSchema = constraint;
});
}*/
/// <summary>
/// Devuelve todos las constraints dependientes de una tabla.
/// </summary>
public List<ISchemaBase> Find(int tableId)
{
return Find(tableId, 0, 0);
}
public int DependenciesCount(int objectId, ObjectType type)
{
Dictionary<int, bool> depencyTracker = new Dictionary<int, bool>();
return DependenciesCount(objectId, type, depencyTracker);
}
private int DependenciesCount(int tableId, ObjectType type, Dictionary<int, bool> depencyTracker)
{
int count = 0;
bool putItem = false;
int relationalTableId;
List<ISchemaBase> constraints = this.FindNotOwner(tableId, type);
for (int index = 0; index < constraints.Count; index++)
{
ISchemaBase cons = constraints[index];
if (cons.ObjectType == type)
{
if (type == ObjectType.Constraint)
{
relationalTableId = ((Constraint)cons).RelationalTableId;
putItem = (relationalTableId == tableId);
}
}
if (putItem)
{
if (!depencyTracker.ContainsKey(tableId))
{
depencyTracker.Add(tableId, true);
count += 1 + DependenciesCount(cons.Parent.Id, type, depencyTracker);
}
}
}
return count;
}
/// <summary>
/// Devuelve todos las constraints dependientes de una tabla y una columna.
/// </summary>
public List<ISchemaBase> Find(int tableId, int columnId, int dataTypeId)
{
List<string> cons = new List<string>();
List<ISchemaBase> real = new List<ISchemaBase>();
cons = (from depends in this
where (depends.Type == ObjectType.Constraint || depends.Type == ObjectType.Index) &&
((depends.DataTypeId == dataTypeId || dataTypeId == 0) && (depends.SubObjectId == columnId || columnId == 0) && (depends.ObjectId == tableId))
select depends.FullName)
.Concat(from depends in this
where (depends.Type == ObjectType.View || depends.Type == ObjectType.Function) &&
(depends.ObjectId == tableId)
select depends.FullName).ToList();
cons.ForEach(item =>
{
ISchemaBase schema = Database.Find(item);
if (schema != null) real.Add(schema);
}
);
return real;
}
}
}

View File

@@ -0,0 +1,23 @@
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
internal class Dependency
{
public string FullName { get; set; }
public int DataTypeId { get; set; }
public ObjectType Type { get; set; }
public int SubObjectId { get; set; }
/// <summary>
/// ID de la tabla a la que hace referencia la constraint.
/// </summary>
public int ObjectId { get; set; }
/// <summary>
/// ID de la tabla a la que pertenece la constraint.
/// </summary>
public int OwnerTableId { get; set; }
}
}

View File

@@ -0,0 +1,97 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class ExtendedProperty : SQLServerSchemaBase, ISchemaBase
{
public ExtendedProperty(ISchemaBase parent)
: base(parent, ObjectType.ExtendedProperty)
{
}
public override string FullName
{
get
{
string normal = "[" + Level0name + "]" + (String.IsNullOrEmpty(Level1name) ? "" : ".[" + Level1name + "]") + (String.IsNullOrEmpty(Level2name) ? "" : ".[" + Level2name + "]");
if ((String.IsNullOrEmpty(Level1type)) || (String.IsNullOrEmpty(Level2type)))
return normal;
if (!Level2type.Equals("TRIGGER"))
return normal;
else
return "[" + Level0name + "].[" + Level2name + "]";
}
}
public string Level2name { get; set; }
public string Level2type { get; set; }
public string Level1name { get; set; }
public string Level1type { get; set; }
public string Level0name { get; set; }
public string Level0type { get; set; }
public string Value { get; set; }
public override SQLScript Create()
{
ScriptAction action = ScriptAction.AddExtendedProperty;
return new SQLScript(this.ToSqlAdd(), 0, action);
}
public override SQLScript Drop()
{
ScriptAction action = ScriptAction.DropExtendedProperty;
return new SQLScript(this.ToSqlDrop(), 0, action);
}
public override ObjectStatus Status { get; set; }
public override string ToSqlAdd()
{
string sql = "EXEC sys.sp_addextendedproperty @name=N'" + Name + "', @value=N'" + Value + "' ,";
sql += "@level0type=N'" + Level0type + "',@level0name=N'" + Level0name + "'";
if (!String.IsNullOrEmpty(Level1name))
sql += ", @level1type=N'" + Level1type + "',@level1name=N'" + Level1name + "'";
if (!String.IsNullOrEmpty(Level2name))
sql += ", @level2type=N'" + Level2type + "',@level2name=N'" + Level2name + "'";
return sql + "\r\nGO\r\n";
}
public override string ToSqlDrop()
{
string sql = "EXEC sys.sp_dropextendedproperty @name=N'" + Name + "', @value=N'" + Value + "' ,";
sql += "@level0type=N'" + Level0type + "',@level0name=N'" + Level0name + "'";
if (!String.IsNullOrEmpty(Level1name))
sql += ", @level1type=N'" + Level1type + "',@level1name=N'" + Level1name + "'";
if (!String.IsNullOrEmpty(Level2name))
sql += ", @level2type=N'" + Level2type + "',@level2name=N'" + Level2name + "'";
return sql + "\r\nGO\r\n";
}
public override string ToSql()
{
return ToSqlAdd();
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.Parent.Status != ObjectStatus.Create)
{
if (this.Status == ObjectStatus.Create)
list.Add(this.Create());
if (this.Status == ObjectStatus.Drop)
list.Add(this.Drop());
}
return list;
}
}
}

View File

@@ -0,0 +1,106 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class FileGroup : SQLServerSchemaBase
{
public FileGroup(ISchemaBase parent)
: base(parent, ObjectType.FileGroup)
{
Files = new FileGroupFiles(this);
}
public override ISchemaBase Clone(ISchemaBase parent)
{
FileGroup file = new FileGroup(parent);
file.IsDefaultFileGroup = this.IsDefaultFileGroup;
file.IsReadOnly = this.IsReadOnly;
file.Name = this.Name;
file.Id = this.Id;
file.Files = this.Files.Clone(file);
file.Guid = this.Guid;
file.IsFileStream = this.IsFileStream;
return file;
}
public FileGroupFiles Files { get; set; }
public Boolean IsFileStream { get; set; }
public Boolean IsDefaultFileGroup { get; set; }
public Boolean IsReadOnly { get; set; }
public static Boolean Compare(FileGroup origin, FileGroup destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.IsReadOnly != destination.IsReadOnly) return false;
if (origin.IsDefaultFileGroup != destination.IsDefaultFileGroup) return false;
if (origin.IsFileStream != destination.IsFileStream) return false;
return true;
}
private string ToSQL(string action)
{
string sql = "ALTER DATABASE [" + Parent.Name + "] " + action + " ";
sql += "FILEGROUP [" + Name + "]";
if (action.Equals("MODIFY"))
{
if (IsDefaultFileGroup) sql += " DEFAULT";
}
else
if (IsFileStream) sql += " CONTAINS FILESTREAM";
if (IsReadOnly) sql += " READONLY";
sql += "\r\nGO\r\n";
return sql;
}
public override string ToSql()
{
string sql = ToSQL("ADD");
foreach (FileGroupFile file in this.Files)
sql += file.ToSql();
if (IsDefaultFileGroup)
sql += ToSQL("MODIFY");
return sql;
}
public override string ToSqlAdd()
{
string sql = ToSQL("ADD");
foreach (FileGroupFile file in this.Files)
sql += file.ToSqlAdd();
if (IsDefaultFileGroup)
sql += ToSQL("MODIFY");
return sql;
}
public string ToSQLAlter()
{
return ToSQL("MODIFY");
}
public override string ToSqlDrop()
{
string sql = "";
sql = Files.ToSQLDrop();
return sql + "ALTER DATABASE [" + Parent.Name + "] REMOVE FILEGROUP [" + Name + "]\r\nGO\r\n\r\n";
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
listDiff.Add(this.ToSqlDrop(), 1, ScriptAction.DropFileGroup);
if (this.Status == ObjectStatus.Create)
listDiff.Add(this.ToSqlAdd(), 1, ScriptAction.AddFileGroup);
if (this.Status == ObjectStatus.Alter)
listDiff.Add(this.ToSQLAlter(), 1, ScriptAction.AlterFileGroup);
return listDiff;
}
}
}

View File

@@ -0,0 +1,111 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class FileGroupFile : SQLServerSchemaBase
{
public FileGroupFile(ISchemaBase parent)
: base(parent, ObjectType.File)
{
}
public override ISchemaBase Clone(ISchemaBase parent)
{
FileGroupFile file = new FileGroupFile(parent);
file.Growth = this.Growth;
file.Id = this.Id;
file.IsPercentGrowth = this.IsPercentGrowth;
file.IsSparse = this.IsSparse;
file.MaxSize = this.MaxSize;
file.Name = this.Name;
file.PhysicalName = this.PhysicalName;
file.Size = this.Size;
file.Type = this.Type;
return file;
}
public int Size { get; set; }
public Boolean IsSparse { get; set; }
public Boolean IsPercentGrowth { get; set; }
private string TypeGrowth
{
get
{
if (Growth == 0)
return "";
else
if (IsPercentGrowth)
return "%";
else
return "KB";
}
}
public int Growth { get; set; }
public int MaxSize { get; set; }
public string PhysicalName { get; set; }
public int Type { get; set; }
private string GetNameNewFileGroup(string path)
{
string result = "";
string[] flies = path.Split('\\');
for (int index = 0; index < flies.Length - 1; index++)
if (!String.IsNullOrEmpty(flies[index]))
result += flies[index] + "\\";
result += Parent.Parent.Name + "_" + Name + "_DB.ndf";
return result;
}
/// <summary>
/// Compara dos triggers y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean Compare(FileGroupFile origin, FileGroupFile destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.Growth != destination.Growth) return false;
if (origin.IsPercentGrowth != destination.IsPercentGrowth) return false;
if (origin.IsSparse != destination.IsSparse) return false;
if (origin.MaxSize != destination.MaxSize) return false;
if (!origin.PhysicalName.Equals(destination.PhysicalName)) return false;
return true;
}
public override string ToSql()
{
if (Type != 2)
return "ALTER DATABASE " + Parent.Parent.FullName + "\r\nADD" + ((Type != 1) ? "" : " LOG") + " FILE ( NAME = N'" + Name + "', FILENAME = N'" + PhysicalName + "' , SIZE = " + Size * 1000 + "KB , FILEGROWTH = " + Growth * 1000 + TypeGrowth + ") TO FILEGROUP " + Parent.FullName + "\r\nGO\r\n";
else
return "ALTER DATABASE " + Parent.Parent.FullName + "\r\nADD" + ((Type != 1) ? "" : " LOG") + " FILE ( NAME = N'" + Name + "', FILENAME = N'" + PhysicalName + "') TO FILEGROUP " + Parent.FullName + "\r\nGO\r\n";
}
public override string ToSqlAdd()
{
if (Type != 2)
return "ALTER DATABASE " + Parent.Parent.FullName + "\r\nADD" + ((Type != 1) ? "" : " LOG") + " FILE ( NAME = N'" + Name + "', FILENAME = N'" + GetNameNewFileGroup(PhysicalName) + "' , SIZE = " + Size * 1000 + "KB , FILEGROWTH = " + Growth * 1000 + TypeGrowth + ") TO FILEGROUP " + Parent.FullName + "\r\nGO\r\n";
else
return "ALTER DATABASE " + Parent.Parent.FullName + "\r\nADD" + ((Type != 1) ? "" : " LOG") + " FILE ( NAME = N'" + Name + "', FILENAME = N'" + GetNameNewFileGroup(PhysicalName) + "') TO FILEGROUP " + Parent.FullName + "\r\nGO\r\n";
}
public string ToSQLAlter()
{
if (Type != 2)
return "ALTER DATABASE " + Parent.Parent.FullName + " MODIFY FILE ( NAME = N'" + Name + "', FILENAME = N'" + PhysicalName + "' , SIZE = " + Size * 1000 + "KB , FILEGROWTH = " + Growth * 1000 + TypeGrowth + ")";
else
return "ALTER DATABASE " + Parent.Parent.FullName + " MODIFY FILE ( NAME = N'" + Name + "', FILENAME = N'" + PhysicalName + "')";
}
public override string ToSqlDrop()
{
return "ALTER DATABASE " + Parent.Parent.FullName + " REMOVE FILE " + this.FullName + "\r\nGO\r\n";
}
}
}

View File

@@ -0,0 +1,104 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class FileGroupFiles : List<FileGroupFile>
{
private Hashtable hash = new Hashtable();
/// <summary>
/// Constructor de la clase.
/// </summary>
/// <param name="parent">
/// Objeto Database padre.
/// </param>
public FileGroupFiles(FileGroup parent)
{
this.Parent = parent;
}
/// <summary>
/// Clona el objeto FileGroups en una nueva instancia.
/// </summary>
public FileGroupFiles Clone(FileGroup parentObject)
{
FileGroupFiles columns = new FileGroupFiles(parentObject);
for (int index = 0; index < this.Count; index++)
{
columns.Add((FileGroupFile)this[index].Clone(parentObject));
}
return columns;
}
/// <summary>
/// Indica si el nombre del FileGroup existe en la coleccion de tablas del objeto.
/// </summary>
/// <param name="table">
/// Nombre de la tabla a buscar.
/// </param>
/// <returns></returns>
public Boolean Find(string table)
{
return hash.ContainsKey(table);
}
/// <summary>
/// Agrega un objeto columna a la coleccion de columnas.
/// </summary>
public new void Add(FileGroupFile file)
{
if (file != null)
{
hash.Add(file.FullName, file);
base.Add(file);
}
else
throw new ArgumentNullException("file");
}
public FileGroupFile this[string name]
{
get { return (FileGroupFile)hash[name]; }
set
{
hash[name] = value;
for (int index = 0; index < base.Count; index++)
{
if (((FileGroupFile)base[index]).Name.Equals(name))
{
base[index] = value;
break;
}
}
}
}
/// <summary>
/// Devuelve la tabla perteneciente a la coleccion de campos.
/// </summary>
public FileGroup Parent { get; private set; }
public string ToSQL()
{
StringBuilder sql = new StringBuilder();
for (int index = 0; index < this.Count; index++)
{
sql.Append(this[index].ToSql());
}
return sql.ToString();
}
public string ToSQLDrop()
{
StringBuilder sql = new StringBuilder();
for (int index = 0; index < this.Count; index++)
{
sql.Append(this[index].ToSqlDrop());
}
return sql.ToString();
}
}
}

View File

@@ -0,0 +1,131 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class FullText : SQLServerSchemaBase
{
public FullText(ISchemaBase parent)
: base(parent, ObjectType.FullText)
{
}
public override string FullName
{
get { return "[" + Name + "]"; }
}
public string Path { get; set; }
public Boolean IsDefault { get; set; }
public Boolean IsAccentSensity { get; set; }
public string FileGroupName { get; set; }
public override string ToSql()
{
Database database = (Database)this.Parent;
string sql = "CREATE FULLTEXT CATALOG " + FullName + " ";
if (!IsAccentSensity)
sql += "WITH ACCENT_SENSITIVITY = OFF\r\n";
else
sql += "WITH ACCENT_SENSITIVITY = ON\r\n";
if (!String.IsNullOrEmpty(this.Path))
{
if (!database.Options.Ignore.FilterFullTextPath)
sql += "--";
sql += "IN PATH N'" + Path + "'\r\n";
}
if (IsDefault)
sql += "AS DEFAULT\r\n";
sql += "AUTHORIZATION [" + Owner + "]\r\n";
return sql + "GO\r\n";
}
private string ToSqlAlterDefault()
{
if (IsDefault)
{
string sql = "ALTER FULLTEXT CATALOG " + FullName + "\r\n";
sql += "AS DEFAULT";
sql += "\r\nGO\r\n";
return sql;
}
else return "";
}
private string ToSqlAlterOwner()
{
string sql = "ALTER AUTHORIZATION ON FULLTEXT CATALOG::" + FullName + "\r\n";
sql += "TO [" + Owner + "]\r\nGO\r\n";
return sql;
}
private string ToSqlAlter()
{
string sql = "ALTER FULLTEXT CATALOG " + FullName + "\r\n";
sql += "REBUILD WITH ACCENT_SENSITIVITY = ";
if (IsAccentSensity) sql += "ON"; else sql += "OFF";
sql += "\r\nGO\r\n";
return sql;
}
public override string ToSqlDrop()
{
return "DROP FULLTEXT CATALOG " + FullName + "\r\nGO\r\n";
}
public override string ToSqlAdd()
{
return ToSql();
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropFullText);
}
if (this.Status == ObjectStatus.Create)
{
listDiff.Add(ToSql(), 0, ScriptAction.AddFullText);
}
if (this.HasState(ObjectStatus.Alter))
{
listDiff.Add(ToSqlAlter(), 0, ScriptAction.AddFullText);
}
if (this.HasState(ObjectStatus.Disabled))
{
listDiff.Add(ToSqlAlterDefault(), 0, ScriptAction.AddFullText);
}
if (this.HasState(ObjectStatus.ChangeOwner))
{
listDiff.Add(ToSqlAlterOwner(), 0, ScriptAction.AddFullText);
}
return listDiff;
}
/// <summary>
/// Compara dos Synonyms y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public Boolean Compare(FullText destination)
{
Database database = (Database)this.Parent;
if (destination == null) throw new ArgumentNullException("destination");
if (!this.IsAccentSensity.Equals(destination.IsAccentSensity)) return false;
if (!this.IsDefault.Equals(destination.IsDefault)) return false;
if ((!String.IsNullOrEmpty(this.FileGroupName)) && (!String.IsNullOrEmpty(destination.FileGroupName)))
if (!this.FileGroupName.Equals(destination.FileGroupName)) return false;
if (database.Options.Ignore.FilterFullTextPath)
if ((!String.IsNullOrEmpty(this.Path)) && (!String.IsNullOrEmpty(destination.Path)))
return this.Path.Equals(destination.Path, StringComparison.CurrentCultureIgnoreCase);
return true;
}
}
}

View File

@@ -0,0 +1,159 @@
using System;
using System.Collections.Generic;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class FullTextIndex : SQLServerSchemaBase
{
public FullTextIndex(ISchemaBase parent)
: base(parent, ObjectType.FullTextIndex)
{
Columns = new List<FullTextIndexColumn>();
}
public override ISchemaBase Clone(ISchemaBase parent)
{
FullTextIndex index = new FullTextIndex(parent);
index.ChangeTrackingState = this.ChangeTrackingState;
index.FullText = this.FullText;
index.Name = this.Name;
index.FileGroup = this.FileGroup;
index.Id = this.Id;
index.Index = this.Index;
index.IsDisabled = this.IsDisabled;
index.Status = this.Status;
index.Owner = this.Owner;
index.Columns = this.Columns;
this.ExtendedProperties.ForEach(item => index.ExtendedProperties.Add(item));
return index;
}
public string FileGroup { get; set; }
public Boolean IsDisabled { get; set; }
public string Index { get; set; }
public string FullText { get; set; }
public string ChangeTrackingState { get; set; }
public override string FullName
{
get
{
return this.Name;
}
}
public List<FullTextIndexColumn> Columns { get; set; }
public override SQLScript Create()
{
ScriptAction action = ScriptAction.AddFullTextIndex;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(this.ToSqlAdd(), Parent.DependenciesCount, action);
}
else
return null;
}
public override SQLScript Drop()
{
ScriptAction action = ScriptAction.DropFullTextIndex;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(this.ToSqlDrop(), Parent.DependenciesCount, action);
}
else
return null;
}
public override string ToSqlAdd()
{
string sql = "CREATE FULLTEXT INDEX ON " + Parent.FullName + "( ";
Columns.ForEach(item => { sql += "[" + item.ColumnName + "] LANGUAGE [" + item.Language + "],"; });
sql = sql.Substring(0, sql.Length - 1);
sql += ")\r\n";
if (((Database)this.RootParent).Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008)
{
sql += "KEY INDEX " + Index + " ON ([" + FullText + "]";
sql += ", FILEGROUP [" + FileGroup + "]";
sql += ") WITH (CHANGE_TRACKING " + ChangeTrackingState + ")";
}
else
{
sql += "KEY INDEX " + Index + " ON [" + FullText + "]";
sql += " WITH CHANGE_TRACKING " + ChangeTrackingState;
}
sql += "\r\nGO\r\n";
if (!this.IsDisabled)
sql += "ALTER FULLTEXT INDEX ON " + Parent.FullName + " ENABLE\r\nGO\r\n";
return sql;
}
public string ToSqlEnabled()
{
if (this.IsDisabled)
return "ALTER FULLTEXT INDEX ON " + Parent.FullName + " DISABLE\r\nGO\r\n";
else
return "ALTER FULLTEXT INDEX ON " + Parent.FullName + " ENABLE\r\nGO\r\n";
}
public override string ToSqlDrop()
{
return "DROP FULLTEXT INDEX ON " + Parent.FullName + "\r\nGO\r\n";
}
public override string ToSql()
{
return ToSqlAdd();
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.Status != ObjectStatus.Original)
RootParent.ActionMessage[Parent.FullName].Add(this);
if (this.HasState(ObjectStatus.Drop))
list.Add(Drop());
if (this.HasState(ObjectStatus.Create))
list.Add(Create());
if (this.HasState(ObjectStatus.Alter))
{
list.Add(Drop());
list.Add(Create());
}
if (this.Status == ObjectStatus.Disabled)
{
list.Add(this.ToSqlEnabled(), Parent.DependenciesCount, ScriptAction.AlterFullTextIndex);
}
/*if (this.Status == StatusEnum.ObjectStatusType.ChangeFileGroup)
{
listDiff.Add(this.ToSQLDrop(this.FileGroup), ((Table)Parent).DependenciesCount, StatusEnum.ScripActionType.DropIndex);
listDiff.Add(this.ToSQLAdd(), ((Table)Parent).DependenciesCount, StatusEnum.ScripActionType.AddIndex);
}*/
list.AddRange(this.ExtendedProperties.ToSqlDiff());
return list;
}
public Boolean Compare(FullTextIndex destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (!this.ChangeTrackingState.Equals(destination.ChangeTrackingState)) return false;
if (!this.FullText.Equals(destination.FullText)) return false;
if (!this.Index.Equals(destination.Index)) return false;
if (this.IsDisabled != destination.IsDisabled) return false;
if (this.Columns.Count != destination.Columns.Count) return false;
if (this.Columns.Exists(item => { return !destination.Columns.Exists(item2 => item2.ColumnName.Equals(item.ColumnName)); })) return false;
if (destination.Columns.Exists(item => { return !this.Columns.Exists(item2 => item2.ColumnName.Equals(item.ColumnName)); })) return false;
return true;
}
}
}

View File

@@ -0,0 +1,9 @@
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class FullTextIndexColumn
{
public string Language { get; set; }
public string ColumnName { get; set; }
}
}

View File

@@ -0,0 +1,80 @@
using System;
using OpenDBDiff.Schema.Model;
using OpenDBDiff.Schema.SQLServer.Generates.Model.Util;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Function : Code
{
public Function(ISchemaBase parent)
: base(parent, ObjectType.Function, ScriptAction.AddFunction, ScriptAction.DropFunction)
{
}
/// <summary>
/// Clona el objeto en una nueva instancia.
/// </summary>
public override ISchemaBase Clone(ISchemaBase parent)
{
Function item = new Function(parent);
item.Text = this.Text;
item.Status = this.Status;
item.Name = this.Name;
item.Id = this.Id;
item.Owner = this.Owner;
item.Guid = this.Guid;
item.IsSchemaBinding = this.IsSchemaBinding;
this.DependenciesIn.ForEach(dep => item.DependenciesIn.Add(dep));
this.DependenciesOut.ForEach(dep => item.DependenciesOut.Add(dep));
return item;
}
public override Boolean IsCodeType
{
get { return true; }
}
public string ToSQLAlter()
{
return ToSQLAlter(false);
}
public string ToSQLAlter(Boolean quitSchemaBinding)
{
return FormatCode.FormatAlter("FUNCTION", ToSql(), this, quitSchemaBinding);
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.Status != ObjectStatus.Original)
RootParent.ActionMessage.Add(this);
if (this.HasState(ObjectStatus.Drop))
list.Add(Drop());
if (this.HasState(ObjectStatus.Create))
list.Add(Create());
if (this.HasState(ObjectStatus.Alter))
{
if (this.HasState(ObjectStatus.RebuildDependencies))
list.AddRange(RebuildDependencies());
if (!this.GetWasInsertInDiffList(ScriptAction.DropFunction))
{
if (this.HasState(ObjectStatus.Rebuild))
{
list.Add(Drop());
list.Add(Create());
}
if (this.HasState(ObjectStatus.AlterBody))
{
int iCount = DependenciesCount;
list.Add(ToSQLAlter(), iCount, ScriptAction.AlterFunction);
}
}
}
return list;
}
}
}

View File

@@ -0,0 +1,13 @@
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public interface ITable<T> where T : ISchemaBase
{
Columns<T> Columns { get; }
SchemaList<Constraint, T> Constraints { get; }
SchemaList<Index, T> Indexes { get; }
ISchemaBase Parent { get; set; }
string Owner { get; set; }
}
}

View File

@@ -0,0 +1,300 @@
using System;
using System.Text;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Index : SQLServerSchemaBase
{
public enum IndexTypeEnum
{
Heap = 0,
Clustered = 1,
Nonclustered = 2,
XML = 3,
GEO = 4
}
public Index(ISchemaBase parent)
: base(parent, ObjectType.Index)
{
FilterDefintion = "";
Columns = new IndexColumns(parent);
}
public override ISchemaBase Clone(ISchemaBase parent)
{
Index index = new Index(parent)
{
AllowPageLocks = this.AllowPageLocks,
AllowRowLocks = this.AllowRowLocks,
Columns = this.Columns.Clone(),
FillFactor = this.FillFactor,
FileGroup = this.FileGroup,
Id = this.Id,
IgnoreDupKey = this.IgnoreDupKey,
IsAutoStatistics = this.IsAutoStatistics,
IsDisabled = this.IsDisabled,
IsPadded = this.IsPadded,
IsPrimaryKey = this.IsPrimaryKey,
IsUniqueKey = this.IsUniqueKey,
Name = this.Name,
SortInTempDb = this.SortInTempDb,
Status = this.Status,
Type = this.Type,
Owner = this.Owner,
FilterDefintion = this.FilterDefintion
};
ExtendedProperties.ForEach(item => index.ExtendedProperties.Add(item));
return index;
}
public string FileGroup { get; set; }
public Boolean SortInTempDb { get; set; }
public string FilterDefintion { get; set; }
public IndexColumns Columns { get; set; }
public Boolean IsAutoStatistics { get; set; }
public Boolean IsUniqueKey { get; set; }
public Boolean IsPrimaryKey { get; set; }
public IndexTypeEnum Type { get; set; }
public short FillFactor { get; set; }
public Boolean IsDisabled { get; set; }
public Boolean IsPadded { get; set; }
public Boolean IgnoreDupKey { get; set; }
public Boolean AllowPageLocks { get; set; }
public Boolean AllowRowLocks { get; set; }
public override string FullName
{
get
{
return Parent.FullName + ".[" + Name + "]";
}
}
/// <summary>
/// Compara dos indices y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean Compare(Index origin, Index destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.AllowPageLocks != destination.AllowPageLocks) return false;
if (origin.AllowRowLocks != destination.AllowRowLocks) return false;
if (origin.FillFactor != destination.FillFactor) return false;
if (origin.IgnoreDupKey != destination.IgnoreDupKey) return false;
if (origin.IsAutoStatistics != destination.IsAutoStatistics) return false;
if (origin.IsDisabled != destination.IsDisabled) return false;
if (origin.IsPadded != destination.IsPadded) return false;
if (origin.IsPrimaryKey != destination.IsPrimaryKey) return false;
if (origin.IsUniqueKey != destination.IsUniqueKey) return false;
if (origin.Type != destination.Type) return false;
if (origin.SortInTempDb != destination.SortInTempDb) return false;
if (!origin.FilterDefintion.Equals(destination.FilterDefintion)) return false;
if (!IndexColumns.Compare(origin.Columns, destination.Columns)) return false;
return CompareFileGroup(origin, destination);
}
public static Boolean CompareExceptIsDisabled(Index origin, Index destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.AllowPageLocks != destination.AllowPageLocks) return false;
if (origin.AllowRowLocks != destination.AllowRowLocks) return false;
if (origin.FillFactor != destination.FillFactor) return false;
if (origin.IgnoreDupKey != destination.IgnoreDupKey) return false;
if (origin.IsAutoStatistics != destination.IsAutoStatistics) return false;
if (origin.IsPadded != destination.IsPadded) return false;
if (origin.IsPrimaryKey != destination.IsPrimaryKey) return false;
if (origin.IsUniqueKey != destination.IsUniqueKey) return false;
if (origin.Type != destination.Type) return false;
if (origin.SortInTempDb != destination.SortInTempDb) return false;
if (!origin.FilterDefintion.Equals(destination.FilterDefintion)) return false;
if (!IndexColumns.Compare(origin.Columns, destination.Columns)) return false;
//return true;
return CompareFileGroup(origin, destination);
}
private static Boolean CompareFileGroup(Index origin, Index destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.FileGroup != null)
{
if (!origin.FileGroup.Equals(destination.FileGroup)) return false;
}
return true;
}
public override string ToSql()
{
Database database = null;
ISchemaBase current = this;
while (database == null && current.Parent != null)
{
database = current.Parent as Database;
current = current.Parent;
}
var isAzure10 = database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10;
StringBuilder sql = new StringBuilder();
string includes = "";
if ((Type == IndexTypeEnum.Clustered) && (IsUniqueKey)) sql.Append("CREATE UNIQUE CLUSTERED ");
if ((Type == IndexTypeEnum.Clustered) && (!IsUniqueKey)) sql.Append("CREATE CLUSTERED ");
if ((Type == IndexTypeEnum.Nonclustered) && (IsUniqueKey)) sql.Append("CREATE UNIQUE NONCLUSTERED ");
if ((Type == IndexTypeEnum.Nonclustered) && (!IsUniqueKey)) sql.Append("CREATE NONCLUSTERED ");
if (Type == IndexTypeEnum.XML) sql.Append("CREATE PRIMARY XML ");
sql.Append("INDEX [" + Name + "] ON " + Parent.FullName + "\r\n(\r\n");
/*Ordena la coleccion de campos del Indice en funcion de la propieda IsIncluded*/
Columns.Sort();
for (int j = 0; j < Columns.Count; j++)
{
if (!Columns[j].IsIncluded)
{
sql.Append("\t[" + Columns[j].Name + "]");
if (Type != IndexTypeEnum.XML)
{
if (Columns[j].Order) sql.Append(" DESC"); else sql.Append(" ASC");
}
if (j < Columns.Count - 1) sql.Append(",");
sql.Append("\r\n");
}
else
{
if (String.IsNullOrEmpty(includes)) includes = ") INCLUDE (";
includes += "[" + Columns[j].Name + "],";
}
}
if (!String.IsNullOrEmpty(includes)) includes = includes.Substring(0, includes.Length - 1);
sql.Append(includes);
sql.Append(")");
if (!String.IsNullOrEmpty(FilterDefintion)) sql.Append("\r\n WHERE " + FilterDefintion + "\r\n");
sql.Append(" WITH (");
if (Parent.ObjectType == ObjectType.TableType)
{
if ((IgnoreDupKey) && (IsUniqueKey)) sql.Append("IGNORE_DUP_KEY = ON "); else sql.Append("IGNORE_DUP_KEY = OFF ");
}
else
{
if (!isAzure10)
{
if (IsPadded) sql.Append("PAD_INDEX = ON, "); else sql.Append("PAD_INDEX = OFF, ");
}
if (IsAutoStatistics) sql.Append("STATISTICS_NORECOMPUTE = ON"); else sql.Append("STATISTICS_NORECOMPUTE = OFF");
if (Type != IndexTypeEnum.XML)
if ((IgnoreDupKey) && (IsUniqueKey)) sql.Append("IGNORE_DUP_KEY = ON, "); else sql.Append(", IGNORE_DUP_KEY = OFF");
if (!isAzure10)
{
if (AllowRowLocks) sql.Append(", ALLOW_ROW_LOCKS = ON"); else sql.Append(", ALLOW_ROW_LOCKS = OFF");
if (AllowPageLocks) sql.Append(", ALLOW_PAGE_LOCKS = ON"); else sql.Append(", ALLOW_PAGE_LOCKS = OFF");
if (FillFactor != 0) sql.Append(", FILLFACTOR = " + FillFactor.ToString());
}
}
sql.Append(")");
if (!isAzure10)
{
if (!String.IsNullOrEmpty(FileGroup)) sql.Append(" ON [" + FileGroup + "]");
}
sql.Append("\r\nGO\r\n");
if (IsDisabled)
sql.Append("ALTER INDEX [" + Name + "] ON " + ((Table)Parent).FullName + " DISABLE\r\nGO\r\n");
sql.Append(ExtendedProperties.ToSql());
return sql.ToString();
}
public override string ToSqlAdd()
{
return ToSql();
}
public override string ToSqlDrop()
{
return ToSqlDrop(null);
}
private string ToSqlDrop(string FileGroupName)
{
string sql = "DROP INDEX [" + Name + "] ON " + Parent.FullName;
if (!String.IsNullOrEmpty(FileGroupName)) sql += " WITH (MOVE TO [" + FileGroupName + "])";
sql += "\r\nGO\r\n";
return sql;
}
public override SQLScript Create()
{
ScriptAction action = ScriptAction.AddIndex;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(ToSqlAdd(), Parent.DependenciesCount, action);
}
return null;
}
public override SQLScript Drop()
{
ScriptAction action = ScriptAction.DropIndex;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(ToSqlDrop(), Parent.DependenciesCount, action);
}
return null;
}
private string ToSqlEnabled()
{
if (IsDisabled)
return "ALTER INDEX [" + Name + "] ON " + Parent.FullName + " DISABLE\r\nGO\r\n";
return "ALTER INDEX [" + Name + "] ON " + Parent.FullName + " REBUILD\r\nGO\r\n";
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (Status != ObjectStatus.Original)
{
var actionMessage = RootParent.ActionMessage[Parent.FullName];
if (actionMessage != null)
actionMessage.Add(this);
}
if (HasState(ObjectStatus.Drop))
list.Add(Drop());
if (HasState(ObjectStatus.Create))
list.Add(Create());
if (HasState(ObjectStatus.Alter))
{
list.Add(Drop());
list.Add(Create());
}
if (Status == ObjectStatus.Disabled)
{
list.Add(ToSqlEnabled(), Parent.DependenciesCount, ScriptAction.AlterIndex);
}
/*if (this.Status == StatusEnum.ObjectStatusType.ChangeFileGroup)
{
listDiff.Add(this.ToSQLDrop(this.FileGroup), ((Table)Parent).DependenciesCount, StatusEnum.ScripActionType.DropIndex);
listDiff.Add(this.ToSQLAdd(), ((Table)Parent).DependenciesCount, StatusEnum.ScripActionType.AddIndex);
}*/
list.AddRange(ExtendedProperties.ToSqlDiff());
return list;
}
}
}

View File

@@ -0,0 +1,72 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class IndexColumn : SQLServerSchemaBase, IComparable<IndexColumn>
{
public IndexColumn(ISchemaBase parentObject)
: base(parentObject, ObjectType.IndexColumn)
{
}
public new IndexColumn Clone(ISchemaBase parent)
{
IndexColumn column = new IndexColumn(parent);
column.Id = this.Id;
column.IsIncluded = this.IsIncluded;
column.Name = this.Name;
column.Order = this.Order;
column.Status = this.Status;
column.KeyOrder = this.KeyOrder;
column.DataTypeId = this.DataTypeId;
return column;
}
public int DataTypeId { get; set; }
public int KeyOrder { get; set; }
public Boolean IsIncluded { get; set; }
public Boolean Order { get; set; }
public static Boolean Compare(IndexColumn origin, IndexColumn destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.IsIncluded != destination.IsIncluded) return false;
if (origin.Order != destination.Order) return false;
if (origin.KeyOrder != destination.KeyOrder) return false;
return true;
}
public override string ToSqlDrop()
{
return "";
}
public override string ToSqlAdd()
{
return "";
}
public override string ToSql()
{
return "";
}
public int CompareTo(IndexColumn other)
{
/*if (other.Name.Equals(this.Name))
{*/
if (other.IsIncluded == this.IsIncluded)
return this.KeyOrder.CompareTo(other.KeyOrder);
else
return other.IsIncluded.CompareTo(this.IsIncluded);
/*}
else
return this.Name.CompareTo(other.Name);*/
}
}
}

View File

@@ -0,0 +1,53 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class IndexColumns : SchemaList<IndexColumn, ISchemaBase>
{
public IndexColumns(ISchemaBase parent)
: base(parent)
{
}
/// <summary>
/// Clona el objeto ColumnConstraints en una nueva instancia.
/// </summary>
public IndexColumns Clone()
{
IndexColumns columns = new IndexColumns(Parent);
for (int index = 0; index < this.Count; index++)
{
columns.Add(this[index].Clone(Parent));
}
return columns;
}
/// <summary>
/// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean Compare(IndexColumns origin, IndexColumns destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.Count != destination.Count) return false;
for (int j = 0; j < origin.Count; j++)
{
IndexColumn item = destination[origin[j].FullName];
if (item == null)
return false;
else
if (!IndexColumn.Compare(origin[j], item)) return false;
}
for (int j = 0; j < destination.Count; j++)
{
IndexColumn item = origin[destination[j].FullName];
if (item == null)
return false;
else
if (!IndexColumn.Compare(destination[j], item)) return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,14 @@
using System.Collections.Generic;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public interface ICode : ISchemaBase
{
SQLScriptList Rebuild();
List<string> DependenciesIn { get; set; }
List<string> DependenciesOut { get; set; }
bool IsSchemaBinding { get; set; }
string Text { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public interface ISQLServerSchemaBase
{
SchemaList<ExtendedProperty, ISchemaBase> ExtendedProperties { get; }
}
}

View File

@@ -0,0 +1,30 @@
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class ObjectDependency
{
public ObjectDependency(string name, string Column, ObjectType type)
{
this.Name = name;
this.ColumnName = Column;
this.Type = type;
}
public ObjectDependency(string name, string Column)
{
this.Name = name;
this.ColumnName = Column;
}
public string Name { get; set; }
public string ColumnName { get; set; }
public ObjectType Type { get; set; }
public bool IsCodeType
{
get { return ((Type == ObjectType.StoredProcedure) || (Type == ObjectType.Trigger) || (Type == ObjectType.View) || (Type == ObjectType.Function)); }
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Globalization;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Parameter
{
public bool Output { get; set; }
public byte Scale { get; set; }
public byte Precision { get; set; }
public string Name { get; set; }
public int Size { get; set; }
public string Type { get; set; }
public string ToSql()
{
string sql = Name + " [" + Type + "]";
if (Type.Equals("binary") || Type.Equals("varbinary") || Type.Equals("varchar") || Type.Equals("char") || Type.Equals("nchar") || Type.Equals("nvarchar"))
{
if (Size == -1)
sql += "(max)";
else
{
sql += "(" + Size.ToString(CultureInfo.InvariantCulture) + ")";
}
}
if (Type.Equals("numeric") || Type.Equals("decimal")) sql += "(" + Precision.ToString(CultureInfo.InvariantCulture) + "," + Scale.ToString(CultureInfo.InvariantCulture) + ")";
if (Output) sql += " OUTPUT";
return sql;
}
}
}

View File

@@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class PartitionFunction : SQLServerSchemaBase
{
private const int IS_STRING = 0;
private const int IS_UNIQUE = 1;
private const int IS_DATE = 2;
private const int IS_NUMERIC = 3;
public PartitionFunction(ISchemaBase parent)
: base(parent, ObjectType.PartitionFunction)
{
Values = new List<string>();
}
public new PartitionFunction Clone(ISchemaBase parent)
{
PartitionFunction item = new PartitionFunction(parent);
item.Id = this.Id;
item.IsBoundaryRight = this.IsBoundaryRight;
item.Name = this.Name;
item.Precision = this.Precision;
item.Scale = this.Scale;
item.Size = this.Size;
item.Type = this.Type;
this.Values.ForEach(value => { item.Values.Add(value); });
return item;
}
public List<string> Values { get; set; }
public PartitionFunction Old { get; set; }
public int Precision { get; set; }
public int Scale { get; set; }
public int Size { get; set; }
public bool IsBoundaryRight { get; set; }
public string Type { get; set; }
private int ValueItem(string typeName)
{
if ((typeName.Equals("nchar") || typeName.Equals("nvarchar") || typeName.Equals("varchar") || typeName.Equals("char")))
return IS_STRING;
if (typeName.Equals("uniqueidentifier"))
return IS_UNIQUE;
if (typeName.Equals("datetime") || typeName.Equals("smalldatetime") || typeName.Equals("datetime2") || typeName.Equals("time") || typeName.Equals("datetimeoffset"))
return IS_DATE;
if (typeName.Equals("numeric") || typeName.Equals("decimal") || typeName.Equals("float") || typeName.Equals("real") || typeName.Equals("money") || typeName.Equals("smallmoney"))
return IS_NUMERIC;
return IS_NUMERIC;
}
public override string ToSql()
{
string sqltype = Type;
if (Type.Equals("binary") || Type.Equals("varbinary") || Type.Equals("varchar") || Type.Equals("char") || Type.Equals("nchar") || Type.Equals("nvarchar"))
{
if (Type.Equals("nchar") || Type.Equals("nvarchar"))
sqltype += " (" + (Size / 2).ToString(CultureInfo.InvariantCulture) + ")";
else
sqltype += " (" + Size.ToString(CultureInfo.InvariantCulture) + ")";
}
if (Type.Equals("numeric") || Type.Equals("decimal")) sqltype += " (" + Precision.ToString(CultureInfo.InvariantCulture) + "," + Scale.ToString(CultureInfo.InvariantCulture) + ")";
if (((Database)Parent).Info.Version >= DatabaseInfo.SQLServerVersion.SQLServer2008)
{
if (Type.Equals("datetime2") || Type.Equals("datetimeoffset") || Type.Equals("time")) sqltype += "(" + Scale.ToString(CultureInfo.InvariantCulture) + ")";
}
string sql = "CREATE PARTITION FUNCTION [" + Name + "](" + sqltype + ") AS RANGE\r\n ";
if (IsBoundaryRight)
sql += "RIGHT";
else
sql += "LEFT";
sql += " FOR VALUES (";
string sqlvalues = "";
int valueType = ValueItem(Type);
if (valueType == IS_STRING)
Values.ForEach(item => { sqlvalues += "N'" + item + "',"; });
else
if (valueType == IS_DATE)
Values.ForEach(item => { sqlvalues += "'" + DateTime.Parse(item).ToString("yyyyMMdd HH:mm:ss.fff") + "',"; });
else
if (valueType == IS_UNIQUE)
Values.ForEach(item => { sqlvalues += "'{" + item + "}',"; });
else
if (valueType == IS_NUMERIC)
Values.ForEach(item => { sqlvalues += item.Replace(",", ".") + ","; });
else
Values.ForEach(item => { sqlvalues += item + ","; });
sql += sqlvalues.Substring(0, sqlvalues.Length - 1) + ")";
return sql + "\r\nGO\r\n";
}
public override string ToSqlDrop()
{
return "DROP PARTITION FUNCTION [" + Name + "]\r\nGO\r\n";
}
public override string ToSqlAdd()
{
return ToSql();
}
public string ToSqlAlter()
{
StringBuilder sqlFinal = new StringBuilder();
string sql = "ALTER PARTITION FUNCTION [" + Name + "]()\r\n";
string sqlmergue = "";
string sqsplit = "";
IEnumerable<string> items = Old.Values.Except<string>(this.Values);
int valueType = ValueItem(Type);
foreach (var item in items)
{
sqlmergue = "MERGE RANGE (";
if (valueType == IS_STRING)
sqlmergue += "N'" + item + "'";
else
if (valueType == IS_DATE)
sqlmergue += "'" + DateTime.Parse(item).ToString("yyyyMMdd HH:mm:ss.fff") + "'";
else
if (valueType == IS_UNIQUE)
sqlmergue += "'{" + item + "}'";
else
if (valueType == IS_NUMERIC)
sqlmergue += item.Replace(",", ".");
else
sqlmergue += item;
sqlFinal.Append(sql + sqlmergue + ")\r\nGO\r\n");
}
IEnumerable<string> items2 = this.Values.Except<string>(this.Old.Values);
foreach (var item in items2)
{
sqsplit = "SPLIT RANGE (";
if (valueType == IS_STRING)
sqsplit += "N'" + item + "'";
else
if (valueType == IS_DATE)
sqsplit += "'" + DateTime.Parse(item).ToString("yyyyMMdd HH:mm:ss.fff") + "'";
else
if (valueType == IS_UNIQUE)
sqsplit += "'{" + item + "}'";
else
if (valueType == IS_NUMERIC)
sqsplit += item.Replace(",", ".");
else
sqsplit += item;
sqlFinal.Append(sql + sqsplit + ")\r\nGO\r\n");
}
return sqlFinal.ToString();
}
/// <summary>
/// Devuelve el schema de diferencias del Schema en formato SQL.
/// </summary>
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropPartitionFunction);
}
if (this.Status == ObjectStatus.Rebuild)
{
listDiff.Add(ToSqlDrop() + ToSqlAdd(), 0, ScriptAction.AlterPartitionFunction);
}
if (this.Status == ObjectStatus.Alter)
listDiff.Add(ToSqlAlter(), 0, ScriptAction.AlterPartitionFunction);
if (this.Status == ObjectStatus.Create)
{
listDiff.Add(ToSqlAdd(), 0, ScriptAction.AddPartitionFunction);
}
return listDiff;
}
public static Boolean Compare(PartitionFunction origin, PartitionFunction destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (!origin.Type.Equals(destination.Type)) return false;
if (origin.Size != destination.Size) return false;
if (origin.Precision != destination.Precision) return false;
if (origin.Scale != destination.Scale) return false;
if (origin.IsBoundaryRight != destination.IsBoundaryRight) return false;
return true;
}
public static Boolean CompareValues(PartitionFunction origin, PartitionFunction destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (origin.Values.Count != destination.Values.Count) return false;
if (origin.Values.Except(destination.Values).ToList().Count != 0) return false;
return true;
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class PartitionScheme : SQLServerSchemaBase
{
public PartitionScheme(ISchemaBase parent)
: base(parent, ObjectType.PartitionFunction)
{
FileGroups = new List<string>();
}
public List<string> FileGroups { get; set; }
public string PartitionFunction { get; set; }
public override string ToSqlAdd()
{
string sql = "CREATE PARTITION SCHEME " + FullName + "\r\n";
sql += " AS PARTITION " + PartitionFunction + "\r\n";
sql += "TO (";
FileGroups.ForEach(item => sql += "[" + item + "],");
sql = sql.Substring(0, sql.Length - 1);
sql += ")\r\nGO\r\n";
return sql;
}
public override string ToSqlDrop()
{
return "DROP PARTITION SCHEME " + FullName + "\r\nGO\r\n";
}
public override string ToSql()
{
return ToSqlAdd();
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropPartitionScheme);
}
if (this.Status == ObjectStatus.Rebuild)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropPartitionScheme);
listDiff.Add(ToSqlAdd(), 0, ScriptAction.AddPartitionScheme);
}
if (this.Status == ObjectStatus.Create)
{
listDiff.Add(ToSqlAdd(), 0, ScriptAction.AddPartitionScheme);
}
return listDiff;
}
public static Boolean Compare(PartitionScheme origin, PartitionScheme destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (!origin.PartitionFunction.Equals(destination.PartitionFunction)) return false;
if (origin.FileGroups.Count != destination.FileGroups.Count) return false;
for (int j = 0; j < origin.FileGroups.Count; j++)
{
if (origin.CompareFullNameTo(origin.FileGroups[j], destination.FileGroups[j]) != 0)
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,79 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Role : SQLServerSchemaBase
{
public enum RoleTypeEnum
{
ApplicationRole = 1,
DatabaseRole = 2
}
public Role(ISchemaBase parent)
: base(parent, ObjectType.Role)
{
}
public override string FullName
{
get { return "[" + Name + "]"; }
}
public RoleTypeEnum Type { get; set; }
public string Password { get; set; }
public override string ToSql()
{
string sql = "";
sql += "CREATE " + ((Type == RoleTypeEnum.ApplicationRole) ? "APPLICATION" : "") + " ROLE ";
sql += FullName + " ";
sql += "WITH PASSWORD = N'" + Password + "'";
if (!String.IsNullOrEmpty(Owner))
sql += " ,DEFAULT_SCHEMA=[" + Owner + "]";
return sql.Trim() + "\r\nGO\r\n";
}
public override string ToSqlDrop()
{
return "DROP " + ((Type == RoleTypeEnum.ApplicationRole) ? "APPLICATION" : "") + " ROLE " + FullName + "\r\nGO\r\n";
}
public override string ToSqlAdd()
{
return ToSql();
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropRole);
}
if (this.Status == ObjectStatus.Create)
{
listDiff.Add(ToSql(), 0, ScriptAction.AddRole);
}
if ((this.Status & ObjectStatus.Alter) == ObjectStatus.Alter)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropRole);
listDiff.Add(ToSql(), 0, ScriptAction.AddRole);
}
return listDiff;
}
public Boolean Compare(Role obj)
{
if (obj == null) throw new ArgumentNullException("destination");
if (this.Type != obj.Type) return false;
if (!this.Password.Equals(obj.Password)) return false;
if (!this.Owner.Equals(obj.Owner)) return false;
return true;
}
}
}

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections;
using System.Collections.Generic;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Rule : Code
{
public Rule(ISchemaBase parent)
: base(parent, ObjectType.Rule, ScriptAction.AddRule, ScriptAction.DropRule)
{
}
public new Rule Clone(ISchemaBase parent)
{
Rule item = new Rule(parent);
item.Id = this.Id;
item.Name = this.Name;
item.Owner = this.Owner;
item.Text = this.Text;
item.Guid = this.Guid;
return item;
}
public string ToSQLAddBind()
{
string sql;
if (this.Parent.ObjectType == ObjectType.Column)
sql = String.Format("EXEC sp_bindrule N'{0}', N'[{1}].[{2}]','futureonly'\r\nGO\r\n", Name, this.Parent.Parent.Name, this.Parent.Name);
else
sql = String.Format("EXEC sp_bindrule N'{0}', N'{1}','futureonly'\r\nGO\r\n", Name, this.Parent.Name);
return sql;
}
public string ToSQLAddUnBind()
{
string sql;
if (this.Parent.ObjectType == ObjectType.Column)
sql = String.Format("EXEC sp_unbindrule @objname=N'[{0}].[{1}]'\r\nGO\r\n", this.Parent.Parent.Name, this.Parent.Name);
else
sql = String.Format("EXEC sp_unbindrule @objname=N'{0}'\r\nGO\r\n", this.Parent.Name);
return sql;
}
private SQLScriptList ToSQLUnBindAll()
{
SQLScriptList listDiff = new SQLScriptList();
Hashtable items = new Hashtable();
List<UserDataType> useDataTypes = ((Database)this.Parent).UserTypes.FindAll(item => { return item.Rule.FullName.Equals(this.FullName); });
foreach (UserDataType item in useDataTypes)
{
foreach (ObjectDependency dependency in item.Dependencies)
{
Column column = ((Database)this.Parent).Tables[dependency.Name].Columns[dependency.ColumnName];
if ((!column.IsComputed) && (column.Status != ObjectStatus.Create))
{
if (!items.ContainsKey(column.FullName))
{
listDiff.Add("EXEC sp_unbindrule '" + column.FullName + "'\r\nGO\r\n", 0, ScriptAction.UnbindRuleColumn);
items.Add(column.FullName, column.FullName);
}
}
}
if (item.Rule.Status != ObjectStatus.Create)
listDiff.Add("EXEC sp_unbindrule '" + item.FullName + "'\r\nGO\r\n", 0, ScriptAction.UnbindRuleType);
}
return listDiff;
}
/// <summary>
/// Devuelve el schema de diferencias del Schema en formato SQL.
/// </summary>
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
listDiff.AddRange(ToSQLUnBindAll());
listDiff.Add(Drop());
}
if (this.Status == ObjectStatus.Create)
listDiff.Add(Create());
if (this.Status == ObjectStatus.Alter)
{
listDiff.AddRange(ToSQLUnBindAll());
listDiff.AddRange(Rebuild());
}
return listDiff;
}
}
}

View File

@@ -0,0 +1,15 @@
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public abstract class SQLServerSchemaBase : SchemaBase, ISQLServerSchemaBase
{
protected SQLServerSchemaBase(ISchemaBase parent, ObjectType objectType) : base("[", "]", objectType)
{
this.Parent = parent;
ExtendedProperties = new SchemaList<ExtendedProperty, ISchemaBase>(parent);
}
public SchemaList<ExtendedProperty, ISchemaBase> ExtendedProperties { get; private set; }
}
}

View File

@@ -0,0 +1,49 @@
using System.Text;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Schema : SQLServerSchemaBase
{
public Schema(Database parent)
: base(parent, ObjectType.Schema)
{
}
public override string ToSql()
{
StringBuilder sql = new StringBuilder();
sql.Append("CREATE SCHEMA ");
sql.Append("[" + this.Name + "] AUTHORIZATION [" + Owner + "]");
sql.Append("\r\nGO\r\n");
return sql.ToString();
}
public override string ToSqlAdd()
{
return ToSql();
}
public override string ToSqlDrop()
{
return "DROP SCHEMA [" + Name + "]\r\nGO\r\n";
}
/// <summary>
/// Devuelve el schema de diferencias del Schema en formato SQL.
/// </summary>
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<OpenDBDiff.Schema.Model.ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropSchema);
}
if (this.Status == ObjectStatus.Create)
{
listDiff.Add(ToSql(), 0, ScriptAction.AddSchema);
}
return listDiff;
}
}
}

View File

@@ -0,0 +1,67 @@
using System;
using OpenDBDiff.Schema.Model;
using OpenDBDiff.Schema.SQLServer.Generates.Model.Util;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class StoredProcedure : Code
{
public StoredProcedure(ISchemaBase parent)
: base(parent, ObjectType.StoredProcedure, ScriptAction.AddStoredProcedure, ScriptAction.DropStoredProcedure)
{
}
/// <summary>
/// Clona el objeto en una nueva instancia.
/// </summary>
public override ISchemaBase Clone(ISchemaBase parent)
{
StoredProcedure item = new StoredProcedure(parent);
item.Text = this.Text;
item.Status = this.Status;
item.Name = this.Name;
item.Id = this.Id;
item.Owner = this.Owner;
item.Guid = this.Guid;
return item;
}
public override Boolean IsCodeType
{
get { return true; }
}
public override string ToSql()
{
//if (String.IsNullOrEmpty(sql))
sql = FormatCode.FormatCreate("PROC(EDURE)?", Text, this);
return sql;
}
public string ToSQLAlter()
{
return FormatCode.FormatAlter("PROC(EDURE)?", ToSql(), this, false);
}
/// <summary>
/// Devuelve el schema de diferencias del Schema en formato SQL.
/// </summary>
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.Status != ObjectStatus.Original)
RootParent.ActionMessage.Add(this);
if (this.HasState(ObjectStatus.Drop))
list.Add(Drop());
if (this.HasState(ObjectStatus.Create))
list.Add(Create());
if (this.HasState(ObjectStatus.Alter))
list.Add(ToSQLAlter(), 0, ScriptAction.AlterProcedure);
if (this.HasState(ObjectStatus.AlterWhitespace))
list.Add(ToSQLAlter(), 0, ScriptAction.AlterProcedure);
return list;
}
}
}

View File

@@ -0,0 +1,76 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Synonym : SQLServerSchemaBase
{
public Synonym(ISchemaBase parent)
: base(parent, ObjectType.Synonym)
{
}
public override ISchemaBase Clone(ISchemaBase parent)
{
Synonym item = new Synonym(parent);
item.Id = this.Id;
item.Name = this.Name;
item.Owner = this.Owner;
item.Value = this.Value;
item.Guid = this.Guid;
return item;
}
public string Value { get; set; }
public override string ToSql()
{
string sql = "CREATE SYNONYM " + FullName + " FOR " + Value + "\r\nGO\r\n";
return sql;
}
public override string ToSqlDrop()
{
return "DROP SYNONYM " + FullName + "\r\nGO\r\n";
}
public override string ToSqlAdd()
{
return ToSql();
}
/// <summary>
/// Devuelve el schema de diferencias del Schema en formato SQL.
/// </summary>
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropSynonyms);
}
if (this.Status == ObjectStatus.Create)
{
listDiff.Add(ToSql(), 0, ScriptAction.AddSynonyms);
}
if (this.Status == ObjectStatus.Alter)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropSynonyms);
listDiff.Add(ToSql(), 0, ScriptAction.AddSynonyms);
}
return listDiff;
}
/// <summary>
/// Compara dos Synonyms y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean Compare(Synonym origin, Synonym destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (!origin.Value.Equals(destination.Value)) return false;
return true;
}
}
}

View File

@@ -0,0 +1,732 @@
using OpenDBDiff.Schema.Attributes;
using OpenDBDiff.Schema.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Table : SQLServerSchemaBase, IComparable<Table>, ITable<Table>
{
private int dependenciesCount;
private List<ISchemaBase> dependencies;
private Boolean? hasFileStream;
public Table(ISchemaBase parent)
: base(parent, ObjectType.Table)
{
dependenciesCount = -1;
Columns = new Columns<Table>(this);
Constraints = new SchemaList<Constraint, Table>(this, ((Database)parent).AllObjects);
Options = new SchemaList<TableOption, Table>(this);
Triggers = new SchemaList<Trigger, Table>(this, ((Database)parent).AllObjects);
CLRTriggers = new SchemaList<CLRTrigger, Table>(this, ((Database)parent).AllObjects);
Indexes = new SchemaList<Index, Table>(this, ((Database)parent).AllObjects);
Partitions = new SchemaList<TablePartition, Table>(this, ((Database)parent).AllObjects);
FullTextIndex = new SchemaList<FullTextIndex, Table>(this);
}
public string CompressType { get; set; }
public string FileGroupText { get; set; }
public Boolean HasChangeDataCapture { get; set; }
public Boolean HasChangeTrackingTrackColumn { get; set; }
public Boolean HasChangeTracking { get; set; }
public string FileGroupStream { get; set; }
public Boolean HasClusteredIndex { get; set; }
public string FileGroup { get; set; }
public Table OriginalTable { get; set; }
[SchemaNode("Constraints")]
public SchemaList<Constraint, Table> Constraints { get; private set; }
[SchemaNode("Indexes", "Index")]
public SchemaList<Index, Table> Indexes { get; private set; }
[SchemaNode("CLR Triggers")]
public SchemaList<CLRTrigger, Table> CLRTriggers { get; private set; }
[SchemaNode("Triggers")]
public SchemaList<Trigger, Table> Triggers { get; private set; }
public SchemaList<FullTextIndex, Table> FullTextIndex { get; private set; }
public SchemaList<TablePartition, Table> Partitions { get; set; }
public SchemaList<TableOption, Table> Options { get; set; }
/// <summary>
/// Indica si la tabla tiene alguna columna que sea Identity.
/// </summary>
public Boolean HasIdentityColumn
{
get
{
foreach (Column col in Columns)
{
if (col.IsIdentity) return true;
}
return false;
}
}
public Boolean HasFileStream
{
get
{
if (hasFileStream == null)
{
hasFileStream = false;
foreach (Column col in Columns)
{
if (col.IsFileStream) hasFileStream = true;
}
}
return hasFileStream.Value;
}
}
public Boolean HasBlobColumn
{
get
{
foreach (Column col in Columns)
{
if (col.IsBLOB) return true;
}
return false;
}
}
/// <summary>
/// Indica la cantidad de Constraints dependientes de otra tabla (FK) que tiene
/// la tabla.
/// </summary>
public override int DependenciesCount
{
get
{
if (dependenciesCount == -1)
dependenciesCount = ((Database)Parent).Dependencies.DependenciesCount(Id,
ObjectType.Constraint);
return dependenciesCount;
}
}
#region IComparable<Table> Members
/// <summary>
/// Compara en primer orden por la operacion
/// (Primero van los Drops, luego los Create y finalesmente los Alter).
/// Si la operacion es la misma, ordena por cantidad de tablas dependientes.
/// </summary>
public int CompareTo(Table other)
{
if (other == null) throw new ArgumentNullException("other");
if (Status == other.Status)
return DependenciesCount.CompareTo(other.DependenciesCount);
return other.Status.CompareTo(Status);
}
#endregion IComparable<Table> Members
#region ITable<Table> Members
/// <summary>
/// Coleccion de campos de la tabla.
/// </summary>
[SchemaNode("Columns", "Column")]
public Columns<Table> Columns { get; set; }
#endregion ITable<Table> Members
/// <summary>
/// Clona el objeto Table en una nueva instancia.
/// </summary>
public override ISchemaBase Clone(ISchemaBase objectParent)
{
var table = new Table(objectParent)
{
Owner = Owner,
Name = Name,
Id = Id,
Guid = Guid,
Status = Status,
FileGroup = FileGroup,
FileGroupText = FileGroupText,
FileGroupStream = FileGroupStream,
HasClusteredIndex = HasClusteredIndex,
HasChangeTracking = HasChangeTracking,
HasChangeTrackingTrackColumn = HasChangeTrackingTrackColumn,
HasChangeDataCapture = HasChangeDataCapture,
dependenciesCount = DependenciesCount
};
table.Columns = Columns.Clone(table);
table.Options = Options.Clone(table);
table.CompressType = CompressType;
table.Triggers = Triggers.Clone(table);
table.Indexes = Indexes.Clone(table);
table.Partitions = Partitions.Clone(table);
table.Constraints = Constraints.Clone(table);
return table;
}
public override string ToSql()
{
return ToSql(true);
}
/// <summary>
/// Devuelve el schema de la tabla en formato SQL.
/// </summary>
public string ToSql(Boolean showFK)
{
Database database = null;
ISchemaBase current = this;
while (database == null && current.Parent != null)
{
database = current.Parent as Database;
current = current.Parent;
}
if (database == null)
return string.Empty;
var isAzure10 = database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10;
string sql = "";
string sqlPK = "";
string sqlUC = "";
string sqlFK = "";
if (Columns.Any())
{
sql += "CREATE TABLE " + FullName + "\r\n(\r\n";
sql += Columns.ToSql();
if (Constraints.Any())
{
sql += ",\r\n";
Constraints.AsQueryable()
// Add the constraint if it's not in DropStatus
.Where(c => !c.HasState(ObjectStatus.Drop))
.ToList()
.ForEach(item =>
{
if (item.Type == Constraint.ConstraintType.PrimaryKey)
sqlPK += "\t" + item.ToSql() + ",\r\n";
if (item.Type == Constraint.ConstraintType.Unique)
sqlUC += "\t" + item.ToSql() + ",\r\n";
if (showFK && item.Type == Constraint.ConstraintType.ForeignKey)
sqlFK += "\t" + item.ToSql() + ",\r\n";
});
sql += sqlPK + sqlUC + sqlFK;
sql = sql.Substring(0, sql.Length - 3) + "\r\n";
}
else
{
sql += "\r\n";
if (!String.IsNullOrEmpty(CompressType))
sql += "WITH (DATA_COMPRESSION = " + CompressType + ")\r\n";
}
sql += ")";
if (!isAzure10)
{
if (!String.IsNullOrEmpty(FileGroup)) sql += " ON [" + FileGroup + "]";
if (!String.IsNullOrEmpty(FileGroupText))
{
if (HasBlobColumn)
sql += " TEXTIMAGE_ON [" + FileGroupText + "]";
}
if ((!String.IsNullOrEmpty(FileGroupStream)) && (HasFileStream))
sql += " FILESTREAM_ON [" + FileGroupStream + "]";
}
sql += "\r\n";
sql += "GO\r\n";
Constraints.ForEach(item =>
{
if (item.Type == Constraint.ConstraintType.Check)
sql += item.ToSqlAdd() + "\r\n";
});
if (HasChangeTracking)
sql += ToSqlChangeTracking();
sql += Indexes.ToSql();
sql += FullTextIndex.ToSql();
sql += Options.ToSql();
sql += Triggers.ToSql();
}
return sql;
}
private string ToSqlChangeTracking()
{
string sql;
if (HasChangeTracking)
{
sql = "ALTER TABLE " + FullName + " ENABLE CHANGE_TRACKING";
if (HasChangeTrackingTrackColumn)
sql += " WITH(TRACK_COLUMNS_UPDATED = ON)";
}
else
sql = "ALTER TABLE " + FullName + " DISABLE CHANGE_TRACKING";
return sql + "\r\nGO\r\n";
}
public override string ToSqlAdd()
{
return ToSql();
}
public override string ToSqlDrop()
{
return "DROP TABLE " + FullName + "\r\nGO\r\n";
}
/*
private SQLScriptList BuildSQLFileGroup()
{
var listDiff = new SQLScriptList();
Boolean found = false;
Index clustered = Indexes.Find(item => item.Type == Index.IndexTypeEnum.Clustered);
if (clustered == null)
{
foreach (Constraint cons in Constraints)
{
if (cons.Index.Type == Index.IndexTypeEnum.Clustered)
{
listDiff.Add(cons.ToSqlDrop(FileGroup), dependenciesCount, ScripActionType.DropConstraint);
listDiff.Add(cons.ToSqlAdd(), dependenciesCount, ScripActionType.AddConstraint);
found = true;
}
}
if (!found)
{
Status = ObjectStatusType.RebuildStatus;
listDiff = ToSqlDiff();
}
}
else
{
listDiff.Add(clustered.ToSqlDrop(FileGroup), dependenciesCount, ScripActionType.DropIndex);
listDiff.Add(clustered.ToSqlAdd(), dependenciesCount, ScripActionType.AddIndex);
}
return listDiff;
}
*/
/// <summary>
/// Devuelve el schema de diferencias de la tabla en formato SQL.
/// </summary>
public override SQLScriptList ToSqlDiff(ICollection<ISchemaBase> schemas)
{
var listDiff = new SQLScriptList();
if (Status != ObjectStatus.Original)
{
if (((Database)Parent).Options.Ignore.FilterTable)
RootParent.ActionMessage.Add(this);
}
if (Status == ObjectStatus.Drop)
{
if (((Database)Parent).Options.Ignore.FilterTable)
{
listDiff.Add(ToSqlDrop(), dependenciesCount, ScriptAction.DropTable);
listDiff.AddRange(ToSQLDropFKBelow());
}
}
if (Status == ObjectStatus.Create)
{
string sql = "";
Constraints.ForEach(item =>
{
if (item.Type == Constraint.ConstraintType.ForeignKey)
sql += item.ToSqlAdd() + "\r\n";
});
listDiff.Add(ToSql(false), dependenciesCount, ScriptAction.AddTable);
listDiff.Add(sql, dependenciesCount, ScriptAction.AddConstraintFK);
}
if (HasState(ObjectStatus.RebuildDependencies))
{
GenerateDependencies();
listDiff.AddRange(ToSQLDropDependencies());
listDiff.AddRange(Columns.ToSqlDiff(schemas));
listDiff.AddRange(ToSQLCreateDependencies());
listDiff.AddRange(Constraints.ToSqlDiff());
listDiff.AddRange(Indexes.ToSqlDiff());
listDiff.AddRange(Options.ToSqlDiff());
listDiff.AddRange(Triggers.ToSqlDiff());
listDiff.AddRange(CLRTriggers.ToSqlDiff());
listDiff.AddRange(FullTextIndex.ToSqlDiff());
}
if (HasState(ObjectStatus.Alter))
{
listDiff.AddRange(Columns.ToSqlDiff(schemas));
listDiff.AddRange(Constraints.ToSqlDiff());
listDiff.AddRange(Indexes.ToSqlDiff());
listDiff.AddRange(Options.ToSqlDiff());
listDiff.AddRange(Triggers.ToSqlDiff());
listDiff.AddRange(CLRTriggers.ToSqlDiff());
listDiff.AddRange(FullTextIndex.ToSqlDiff());
}
if (HasState(ObjectStatus.Rebuild))
{
GenerateDependencies();
listDiff.AddRange(ToSQLRebuild());
listDiff.AddRange(Columns.ToSqlDiff());
listDiff.AddRange(Constraints.ToSqlDiff());
listDiff.AddRange(Indexes.ToSqlDiff());
listDiff.AddRange(Options.ToSqlDiff());
//Como recrea la tabla, solo pone los nuevos triggers, por eso va ToSQL y no ToSQLDiff
listDiff.Add(Triggers.ToSql(), dependenciesCount, ScriptAction.AddTrigger);
listDiff.Add(CLRTriggers.ToSql(), dependenciesCount, ScriptAction.AddTrigger);
listDiff.AddRange(FullTextIndex.ToSqlDiff());
}
if (HasState(ObjectStatus.Disabled))
{
listDiff.Add(ToSqlChangeTracking(), 0, ScriptAction.AlterTableChangeTracking);
}
return listDiff;
}
private string ToSQLTableRebuild()
{
string sql = "";
string tempTable = "Temp" + Name;
Boolean IsIdentityNew = false;
var columnNamesStringBuilder = new StringBuilder();
var valuesStringBuilder = new StringBuilder();
foreach (Column column in Columns)
{
if (column.Status != ObjectStatus.Drop &&
!(column.Status == ObjectStatus.Create && column.IsNullable) &&
!column.IsComputed && !column.Type.ToLower().Equals("timestamp"))
{
/*Si la nueva columna a agregar es XML, no se inserta ese campo y debe ir a la coleccion de Warnings*/
/*Si la nueva columna a agregar es Identity, tampoco se debe insertar explicitamente*/
if (
!(column.Status == ObjectStatus.Create &&
(column.Type.ToLower().Equals("xml") || column.IsIdentity)))
{
columnNamesStringBuilder.Append("[");
columnNamesStringBuilder.Append(column.Name);
columnNamesStringBuilder.Append("],");
if (column.HasToForceValue)
{
if (column.HasState(ObjectStatus.Update))
{
valuesStringBuilder.Append("ISNULL([");
valuesStringBuilder.Append(column.Name);
valuesStringBuilder.Append("],");
valuesStringBuilder.Append(column.DefaultForceValue);
valuesStringBuilder.Append("),");
}
else
{
valuesStringBuilder.Append(column.DefaultForceValue);
valuesStringBuilder.Append(",");
}
}
else
{
valuesStringBuilder.Append("[");
valuesStringBuilder.Append(column.Name);
valuesStringBuilder.Append("],");
}
}
else
{
if (column.IsIdentity) IsIdentityNew = true;
}
}
}
if (columnNamesStringBuilder.Length > 0)
{
var listColumns = columnNamesStringBuilder.ToString(0, columnNamesStringBuilder.Length - 1);
var listValues = valuesStringBuilder.ToString(0, valuesStringBuilder.Length - 1);
sql += ToSQLTemp(tempTable) + "\r\n";
if ((HasIdentityColumn) && (!IsIdentityNew))
sql += "SET IDENTITY_INSERT [" + Owner + "].[" + tempTable + "] ON\r\n";
sql += "INSERT INTO [" + Owner + "].[" + tempTable + "] (" + listColumns + ")" + " SELECT " +
listValues + " FROM " + FullName + "\r\n";
if ((HasIdentityColumn) && (!IsIdentityNew))
sql += "SET IDENTITY_INSERT [" + Owner + "].[" + tempTable + "] OFF\r\nGO\r\n\r\n";
sql += "DROP TABLE " + FullName + "\r\nGO\r\n";
if (HasFileStream)
{
Constraints.ForEach(item =>
{
if (item.Type == Constraint.ConstraintType.Unique &&
item.Status != ObjectStatus.Drop)
{
sql += "EXEC sp_rename N'[" + Owner + "].[Temp_XX_" + item.Name +
"]',N'" + item.Name + "', 'OBJECT'\r\nGO\r\n";
}
});
}
sql += "EXEC sp_rename N'[" + Owner + "].[" + tempTable + "]',N'" + Name +
"', 'OBJECT'\r\nGO\r\n\r\n";
sql += OriginalTable.Options.ToSql();
}
else
sql = "";
return sql;
}
private SQLScriptList ToSQLRebuild()
{
var listDiff = new SQLScriptList();
listDiff.AddRange(ToSQLDropDependencies());
listDiff.Add(ToSQLTableRebuild(), dependenciesCount, ScriptAction.RebuildTable);
listDiff.AddRange(ToSQLCreateDependencies());
return listDiff;
}
private string ToSQLTemp(String TableName)
{
string sql = "";
// Drop constraints first, to avoid duplicate constraints created in temp table
foreach (var column in Columns.Where(c => !string.IsNullOrWhiteSpace(c.DefaultConstraint?.Name)))
{
sql += $"ALTER TABLE {this.FullName} DROP CONSTRAINT [{column.DefaultConstraint.Name}]\r\n";
}
if (!string.IsNullOrWhiteSpace(sql))
sql += "\r\n";
sql += "CREATE TABLE [" + Owner + "].[" + TableName + "]\r\n(\r\n";
Columns.Sort();
for (int index = 0; index < Columns.Count; index++)
{
if (Columns[index].Status != ObjectStatus.Drop)
{
sql += "\t" + Columns[index].ToSql(true);
if (index != Columns.Count - 1)
sql += ",";
sql += "\r\n";
}
}
if (HasFileStream)
{
sql = sql.Substring(0, sql.Length - 2);
sql += ",\r\n";
Constraints.ForEach(item =>
{
if (item.Type == Constraint.ConstraintType.Unique &&
item.Status != ObjectStatus.Drop)
{
item.Name = "Temp_XX_" + item.Name;
sql += "\t" + item.ToSql() + ",\r\n";
item.SetWasInsertInDiffList(ScriptAction.AddConstraint);
item.Name = item.Name.Substring(8, item.Name.Length - 8);
}
});
sql = sql.Substring(0, sql.Length - 3) + "\r\n";
}
else
{
sql += "\r\n";
if (!String.IsNullOrEmpty(CompressType))
sql += "WITH (DATA_COMPRESSION = " + CompressType + ")\r\n";
}
sql += ")";
if (!String.IsNullOrEmpty(FileGroup)) sql += " ON [" + FileGroup + "]";
if (!String.IsNullOrEmpty(FileGroupText) && HasBlobColumn)
sql += " TEXTIMAGE_ON [" + FileGroupText + "]";
if (!String.IsNullOrEmpty(FileGroupStream) && HasFileStream)
sql += " FILESTREAM_ON [" + FileGroupStream + "]";
sql += "\r\n";
sql += "GO\r\n";
return sql;
}
private void GenerateDependencies()
{
List<ISchemaBase> myDependencies;
/*Si el estado es AlterRebuildDependeciesStatus, busca las dependencias solamente en las columnas que fueron modificadas*/
if (Status == ObjectStatus.RebuildDependencies)
{
myDependencies = new List<ISchemaBase>();
for (int ic = 0; ic < Columns.Count; ic++)
{
if ((Columns[ic].Status == ObjectStatus.RebuildDependencies) ||
(Columns[ic].Status == ObjectStatus.Alter))
myDependencies.AddRange(((Database)Parent).Dependencies.Find(Id, 0, Columns[ic].DataUserTypeId));
}
/*Si no encuentra ninguna, toma todas las de la tabla*/
if (myDependencies.Count == 0)
myDependencies.AddRange(((Database)Parent).Dependencies.Find(Id));
}
else
myDependencies = ((Database)Parent).Dependencies.Find(Id);
dependencies = new List<ISchemaBase>();
for (int j = 0; j < myDependencies.Count; j++)
{
ISchemaBase item = null;
if (myDependencies[j].ObjectType == ObjectType.Index)
item = Indexes[myDependencies[j].FullName];
if (myDependencies[j].ObjectType == ObjectType.Constraint)
item =
((Database)Parent).Tables[myDependencies[j].Parent.FullName].Constraints[
myDependencies[j].FullName];
if (myDependencies[j].ObjectType == ObjectType.Default)
item = Columns[myDependencies[j].FullName].DefaultConstraint;
if (myDependencies[j].ObjectType == ObjectType.View)
item = ((Database)Parent).Views[myDependencies[j].FullName];
if (myDependencies[j].ObjectType == ObjectType.Function)
item = ((Database)Parent).Functions[myDependencies[j].FullName];
if (item != null)
dependencies.Add(item);
}
}
/// <summary>
/// Genera una lista de FK que deben ser eliminadas previamente a la eliminacion de la tablas.
/// Esto pasa porque para poder eliminar una tabla, hay que eliminar antes todas las constraints asociadas.
/// </summary>
private SQLScriptList ToSQLDropFKBelow()
{
var listDiff = new SQLScriptList();
Constraints.ForEach(constraint =>
{
if ((constraint.Type == Constraint.ConstraintType.ForeignKey) &&
(((Table)constraint.Parent).DependenciesCount <= DependenciesCount))
{
/*Si la FK pertenece a la misma tabla, no se debe explicitar el DROP CONSTRAINT antes de hacer el DROP TABLE*/
if (constraint.Parent.Id != constraint.RelationalTableId)
{
listDiff.Add(constraint.Drop());
}
}
});
return listDiff;
}
/// <summary>
/// Genera una lista de script de DROPS de todas los constraints dependientes de la tabla.
/// Se usa cuando se quiere reconstruir una tabla y todos sus objectos dependientes.
/// </summary>
private SQLScriptList ToSQLDropDependencies()
{
bool addDependency = true;
var listDiff = new SQLScriptList();
//Se buscan todas las table constraints.
for (int index = 0; index < dependencies.Count; index++)
{
if ((dependencies[index].Status == ObjectStatus.Original) ||
(dependencies[index].Status == ObjectStatus.Drop))
{
addDependency = true;
if (dependencies[index].ObjectType == ObjectType.Constraint)
{
if ((((Constraint)dependencies[index]).Type == Constraint.ConstraintType.Unique) &&
((HasFileStream) || (OriginalTable.HasFileStream)))
addDependency = false;
if ((((Constraint)dependencies[index]).Type != Constraint.ConstraintType.ForeignKey) &&
(dependencies[index].Status == ObjectStatus.Drop))
addDependency = false;
}
if (addDependency)
listDiff.Add(dependencies[index].Drop());
}
}
//Se buscan todas las columns constraints.
Columns.ForEach(column =>
{
if (column.DefaultConstraint != null)
{
if (((column.DefaultConstraint.Status == ObjectStatus.Original) ||
(column.DefaultConstraint.Status == ObjectStatus.Drop) ||
(column.DefaultConstraint.Status == ObjectStatus.Alter)) &&
(column.Status != ObjectStatus.Create))
listDiff.Add(column.DefaultConstraint.Drop());
}
});
return listDiff;
}
private SQLScriptList ToSQLCreateDependencies()
{
bool addDependency = true;
var listDiff = new SQLScriptList();
//Las constraints de deben recorrer en el orden inverso.
for (int index = dependencies.Count - 1; index >= 0; index--)
{
if ((dependencies[index].Status == ObjectStatus.Original) &&
(dependencies[index].Parent.Status != ObjectStatus.Drop))
{
addDependency = true;
if (dependencies[index].ObjectType == ObjectType.Constraint)
{
if ((((Constraint)dependencies[index]).Type == Constraint.ConstraintType.Unique) &&
(HasFileStream))
addDependency = false;
}
if (addDependency)
listDiff.Add(dependencies[index].Create());
}
}
//Se buscan todas las columns constraints.
for (int index = Columns.Count - 1; index >= 0; index--)
{
if (Columns[index].DefaultConstraint != null)
{
if ((Columns[index].DefaultConstraint.CanCreate) &&
(Columns.Parent.Status != ObjectStatus.Rebuild))
listDiff.Add(Columns[index].DefaultConstraint.Create());
}
}
return listDiff;
}
/// <summary>
/// Compara dos tablas y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean CompareFileGroup(Table origin, Table destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if ((!String.IsNullOrEmpty(destination.FileGroup) && (!String.IsNullOrEmpty(origin.FileGroup))))
if (!destination.FileGroup.Equals(origin.FileGroup))
return false;
return true;
}
/// <summary>
/// Compara dos tablas y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean CompareFileGroupText(Table origin, Table destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if ((!String.IsNullOrEmpty(destination.FileGroupText) && (!String.IsNullOrEmpty(origin.FileGroupText))))
if (!destination.FileGroupText.Equals(origin.FileGroupText))
return false;
return true;
}
}
}

View File

@@ -0,0 +1,95 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class TableOption : SQLServerSchemaBase
{
public TableOption(string Name, string value, ISchemaBase parent)
: base(parent, ObjectType.TableOption)
{
this.Name = Name;
this.Value = value;
}
public TableOption(ISchemaBase parent)
: base(parent, ObjectType.TableOption)
{
}
/// <summary>
/// Clona el objeto en una nueva instancia.
/// </summary>
public override ISchemaBase Clone(ISchemaBase parent)
{
TableOption option = new TableOption(parent);
option.Name = this.Name;
option.Status = this.Status;
option.Value = this.Value;
return option;
}
public string Value { get; set; }
/// <summary>
/// Compara dos indices y devuelve true si son iguales, caso contrario, devuelve false.
/// </summary>
public static Boolean Compare(TableOption origin, TableOption destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if (!destination.Value.Equals(origin.Value)) return false;
return true;
}
public override string ToSqlDrop()
{
if (this.Name.Equals("TextInRow"))
return "EXEC sp_tableoption " + Parent.Name + ", 'text in row','off'\r\nGO\r\n";
if (this.Name.Equals("LargeValues"))
return "EXEC sp_tableoption " + Parent.Name + ", 'large value types out of row','0'\r\nGO\r\n";
if (this.Name.Equals("VarDecimal"))
return "EXEC sp_tableoption " + Parent.Name + ", 'vardecimal storage format','0'\r\nGO\r\n";
if (this.Name.Equals("LockEscalation"))
return "";
return "";
}
public override string ToSql()
{
if (this.Name.Equals("TextInRow"))
return "EXEC sp_tableoption " + Parent.Name + ", 'text in row'," + Value + "\r\nGO\r\n";
if (this.Name.Equals("LargeValues"))
return "EXEC sp_tableoption " + Parent.Name + ", 'large value types out of row'," + Value + "\r\nGO\r\n";
if (this.Name.Equals("VarDecimal"))
return "EXEC sp_tableoption " + Parent.Name + ", 'vardecimal storage format','1'\r\nGO\r\n";
if (this.Name.Equals("LockEscalation"))
{
if ((!this.Value.Equals("TABLE")) || (this.Status != ObjectStatus.Original))
return "ALTER TABLE " + Parent.Name + " SET (LOCK_ESCALATION = " + Value + ")\r\nGO\r\n";
}
return "";
}
public override string ToSqlAdd()
{
return ToSql();
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
listDiff.Add(ToSqlDrop(), 0, ScriptAction.AddOptions);
if (this.Status == ObjectStatus.Create)
listDiff.Add(ToSql(), 0, ScriptAction.DropOptions);
if (this.Status == ObjectStatus.Alter)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropOptions);
listDiff.Add(ToSql(), 0, ScriptAction.AddOptions);
}
return listDiff;
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class TablePartition : SQLServerSchemaBase
{
public TablePartition(Table parent)
: base(parent, ObjectType.Partition)
{
}
public string CompressType { get; set; }
public override string ToSql()
{
throw new NotImplementedException();
}
public override string ToSqlDrop()
{
throw new NotImplementedException();
}
public override string ToSqlAdd()
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,116 @@
using OpenDBDiff.Schema.Model;
using System.Linq;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class TableType : SQLServerSchemaBase, ITable<TableType>
{
public TableType(ISchemaBase parent)
: base(parent, ObjectType.TableType)
{
Columns = new Columns<TableType>(this);
Constraints = new SchemaList<Constraint, TableType>(this, ((Database)parent).AllObjects);
Indexes = new SchemaList<Index, TableType>(this, ((Database)parent).AllObjects);
}
public override ISchemaBase Clone(ISchemaBase parent)
{
var tableType = new TableType(parent)
{
Owner = this.Owner,
Name = this.Name,
Id = this.Id,
Guid = this.Guid,
Status = this.Status,
Columns = null,
Constraints = null,
Indexes = null
};
tableType.Columns = this.Columns.Clone(tableType);
tableType.Constraints = this.Constraints.Clone(tableType);
tableType.Indexes = this.Indexes.Clone(tableType);
return tableType;
}
public Columns<TableType> Columns { get; private set; }
public SchemaList<Constraint, TableType> Constraints { get; private set; }
public SchemaList<Index, TableType> Indexes { get; private set; }
public override string ToSql()
{
string sql = "";
if (Columns.Any())
{
sql += "CREATE TYPE " + FullName + " AS TABLE\r\n(\r\n";
sql += Columns.ToSql() + "\r\n";
sql += Constraints.ToSql();
sql += ")";
sql += "\r\nGO\r\n";
}
return sql;
}
public override string ToSqlDrop()
{
return "DROP TYPE " + FullName + "\r\nGO\r\n";
}
public override string ToSqlAdd()
{
return ToSql();
}
public override SQLScript Create()
{
ScriptAction action = ScriptAction.AddTableType;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(this.ToSqlAdd(), 0, action);
}
else
return null;
}
public override SQLScript Drop()
{
ScriptAction action = ScriptAction.DropTableType;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(this.ToSqlDrop(), 0, action);
}
else
return null;
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
try
{
SQLScriptList list = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
list.Add(Drop());
}
if (this.HasState(ObjectStatus.Create))
{
list.Add(Create());
}
if (this.Status == ObjectStatus.Alter)
{
list.Add(ToSqlDrop() + ToSql(), 0, ScriptAction.AddTableType);
}
return list;
}
catch
{
return null;
}
}
}
}

View File

@@ -0,0 +1,96 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class Trigger : Code
{
public Trigger(ISchemaBase parent)
: base(parent, ObjectType.Trigger, ScriptAction.AddTrigger, ScriptAction.DropTrigger)
{
this.Parent = parent;
}
/// <summary>
/// Clona el objeto en una nueva instancia.
/// </summary>
public override ISchemaBase Clone(ISchemaBase parent)
{
Trigger trigger = new Trigger(parent);
trigger.Text = this.Text;
trigger.Status = this.Status;
trigger.Name = this.Name;
trigger.IsDisabled = this.IsDisabled;
trigger.InsteadOf = this.InsteadOf;
trigger.NotForReplication = this.NotForReplication;
trigger.Owner = this.Owner;
trigger.Id = this.Id;
trigger.IsDDLTrigger = this.IsDDLTrigger;
trigger.Guid = this.Guid;
return trigger;
}
public Boolean IsDDLTrigger { get; set; }
public Boolean InsteadOf { get; set; }
public Boolean IsDisabled { get; set; }
public Boolean NotForReplication { get; set; }
public override Boolean IsCodeType
{
get { return true; }
}
public override string ToSqlDrop()
{
if (!IsDDLTrigger)
return "DROP TRIGGER " + FullName + "\r\nGO\r\n";
else
return "DROP TRIGGER " + FullName + " ON DATABASE\r\nGO\r\n";
}
public string ToSQLEnabledDisabled()
{
if (!IsDDLTrigger)
{
if (IsDisabled)
return "DISABLE TRIGGER [" + Name + "] ON " + Parent.FullName + "\r\nGO\r\n";
else
return "ENABLE TRIGGER [" + Name + "] ON " + Parent.FullName + "\r\nGO\r\n";
}
else
{
if (IsDisabled)
return "DISABLE TRIGGER [" + Name + "]\r\nGO\r\n";
else
return "ENABLE TRIGGER [" + Name + "]\r\nGO\r\n";
}
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
list.Add(Drop());
if (this.Status == ObjectStatus.Create)
list.Add(Create());
if (this.HasState(ObjectStatus.Alter))
list.AddRange(Rebuild());
if (this.HasState(ObjectStatus.Disabled))
list.Add(this.ToSQLEnabledDisabled(), 0, ScriptAction.EnabledTrigger);
return list;
}
public override bool Compare(ICode obj)
{
if (obj == null) throw new ArgumentNullException("obj");
if (!this.ToSql().Equals(obj.ToSql())) return false;
if (this.InsteadOf != ((Trigger)obj).InsteadOf) return false;
if (this.IsDisabled != ((Trigger)obj).IsDisabled) return false;
if (this.NotForReplication != ((Trigger)obj).NotForReplication) return false;
return true;
}
}
}

View File

@@ -0,0 +1,72 @@
using System;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class User : SQLServerSchemaBase
{
public User(ISchemaBase parent)
: base(parent, ObjectType.User)
{
}
public override string FullName
{
get { return "[" + Name + "]"; }
}
public string Login { get; set; }
public override string ToSql()
{
string sql = "";
sql += "CREATE USER ";
sql += FullName + " ";
if (!String.IsNullOrEmpty(Login))
sql += "FOR LOGIN [" + Login + "] ";
else
sql += "WITHOUT LOGIN ";
if (!String.IsNullOrEmpty(Owner))
sql += "WITH DEFAULT_SCHEMA=[" + Owner + "]";
return sql.Trim() + "\r\nGO\r\n";
}
public override string ToSqlDrop()
{
return "DROP USER " + FullName + "\r\nGO\r\n";
}
public override string ToSqlAdd()
{
return ToSql();
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList listDiff = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropUser);
}
if (this.Status == ObjectStatus.Create)
{
listDiff.Add(ToSql(), 0, ScriptAction.AddUser);
}
if ((this.Status & ObjectStatus.Alter) == ObjectStatus.Alter)
{
listDiff.Add(ToSqlDrop(), 0, ScriptAction.DropUser);
listDiff.Add(ToSql(), 0, ScriptAction.AddUser);
}
return listDiff;
}
public bool Compare(User obj)
{
if (obj == null) throw new ArgumentNullException("destination");
if (!this.Login.Equals(obj.Login)) return false;
if (!this.Owner.Equals(obj.Owner)) return false;
return true;
}
}
}

View File

@@ -0,0 +1,356 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class UserDataType : SQLServerSchemaBase
{
public UserDataType(ISchemaBase parent)
: base(parent, ObjectType.UserDataType)
{
Default = new Default(this);
Rule = new Rule(this);
Dependencies = new List<ObjectDependency>();
}
public List<ObjectDependency> Dependencies { get; private set; }
public Rule Rule { get; private set; }
public Default Default { get; private set; }
public string AssemblyName { get; set; }
public Boolean IsAssembly { get; set; }
public string AssemblyClass { get; set; }
public int AssemblyId { get; set; }
/// <summary>
/// Cantidad de digitos que permite el campo (solo para campos Numeric).
/// </summary>
public int Scale { get; set; }
/// <summary>
/// Cantidad de decimales que permite el campo (solo para campos Numeric).
/// </summary>
public int Precision { get; set; }
public Boolean AllowNull { get; set; }
public int Size { get; set; }
public string Type { get; set; }
public String AssemblyFullName
{
get
{
if (IsAssembly)
return AssemblyName + "." + AssemblyClass;
return "";
}
}
/// <summary>
/// Clona el objeto Column en una nueva instancia.
/// </summary>
public override ISchemaBase Clone(ISchemaBase parent)
{
var item = new UserDataType(parent)
{
Name = Name,
Id = Id,
Owner = Owner,
Guid = Guid,
AllowNull = AllowNull,
Precision = Precision,
Scale = Scale,
Size = Size,
Type = Type,
Default = Default.Clone(this),
Rule = Rule.Clone(this),
Dependencies = Dependencies,
IsAssembly = IsAssembly,
AssemblyClass = AssemblyClass,
AssemblyId = AssemblyId,
AssemblyName = AssemblyName
};
return item;
}
public static Boolean CompareRule(UserDataType origin, UserDataType destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if ((origin.Rule.Name != null) && (destination.Rule.Name == null)) return false;
if ((origin.Rule.Name == null) && (destination.Rule.Name != null)) return false;
if (origin.Rule.Name != null)
if (!origin.Rule.Name.Equals(destination.Rule.Name)) return false;
return true;
}
public static Boolean CompareDefault(UserDataType origin, UserDataType destination)
{
if (destination == null) throw new ArgumentNullException("destination");
if (origin == null) throw new ArgumentNullException("origin");
if ((origin.Default.Name != null) && (destination.Default.Name == null)) return false;
if ((origin.Default.Name == null) && (destination.Default.Name != null)) return false;
if (origin.Default.Name != null)
if (!origin.Default.Name.Equals(destination.Default.Name)) return false;
return true;
}
public override string ToSql()
{
string sql = "CREATE TYPE " + FullName;
if (!IsAssembly)
{
sql += " FROM [" + Type + "]";
if (Type.Equals("binary") || Type.Equals("varbinary") || Type.Equals("varchar") || Type.Equals("char") ||
Type.Equals("nchar") || Type.Equals("nvarchar"))
sql += "(" + Size.ToString(CultureInfo.InvariantCulture) + ")";
if (Type.Equals("numeric") || Type.Equals("decimal"))
sql += " (" + Precision.ToString(CultureInfo.InvariantCulture) + "," +
Scale.ToString(CultureInfo.InvariantCulture) + ")";
if (AllowNull)
sql += " NULL";
else
sql += " NOT NULL";
}
else
{
sql += " EXTERNAL NAME [" + AssemblyName + "].[" + AssemblyClass + "]";
}
sql += "\r\nGO\r\n";
return sql + ToSQLAddBinds();
}
public override string ToSqlDrop()
{
return "DROP TYPE " + FullName + "\r\nGO\r\n";
}
public override string ToSqlAdd()
{
return ToSql();
}
private string ToSQLAddBinds()
{
string sql = "";
if (!String.IsNullOrEmpty(Default.Name))
sql += Default.ToSQLAddBind();
if (!String.IsNullOrEmpty(Rule.Name))
sql += Rule.ToSQLAddBind();
return sql;
}
private SQLScriptList RebuildDependencies(Table table)
{
var list = new SQLScriptList();
List<ISchemaBase> items = ((Database)table.Parent).Dependencies.Find(table.Id);
items.ForEach(item =>
{
ISchemaBase realItem = ((Database)table.Parent).Find(item.FullName);
if (realItem.IsCodeType)
list.AddRange(((ICode)realItem).Rebuild());
});
return list;
}
private SQLScriptList ToSQLChangeColumns()
{
var fields = new Hashtable();
var list = new SQLScriptList();
var listDependencies = new SQLScriptList();
if ((Status == ObjectStatus.Alter) || (Status == ObjectStatus.Rebuild))
{
foreach (ObjectDependency dependency in Dependencies)
{
ISchemaBase itemDepens = ((Database)Parent).Find(dependency.Name);
/*Si la dependencia es una funcion o una vista, reconstruye el objecto*/
if (dependency.IsCodeType)
{
if (itemDepens != null)
list.AddRange(((ICode)itemDepens).Rebuild());
}
/*Si la dependencia es una tabla, reconstruye los indices, constraint y columnas asociadas*/
if (dependency.Type == ObjectType.Table)
{
Column column = ((Table)itemDepens).Columns[dependency.ColumnName];
if ((column.Parent.Status != ObjectStatus.Drop) &&
(column.Parent.Status != ObjectStatus.Create) &&
((column.Status != ObjectStatus.Create) || (column.IsComputed)))
{
if (!fields.ContainsKey(column.FullName))
{
listDependencies.AddRange(RebuildDependencies((Table)itemDepens));
if (column.HasToRebuildOnlyConstraint)
//column.Parent.Status = ObjectStatusType.AlterRebuildDependenciesStatus;
list.AddRange(column.RebuildDependencies());
if (!column.IsComputed)
{
list.AddRange(column.RebuildConstraint(true));
list.Add(
"ALTER TABLE " + column.Parent.FullName + " ALTER COLUMN " +
column.ToSQLRedefine(Type, Size, null) + "\r\nGO\r\n", 0,
ScriptAction.AlterColumn);
/*Si la columna va a ser eliminada o la tabla va a ser reconstruida, no restaura la columna*/
if ((column.Status != ObjectStatus.Drop) &&
(column.Parent.Status != ObjectStatus.Rebuild))
list.AddRange(column.Alter(ScriptAction.AlterColumnRestore));
}
else
{
if (column.Status != ObjectStatus.Create)
{
if (!column.GetWasInsertInDiffList(ScriptAction.AlterColumnFormula))
{
column.SetWasInsertInDiffList(ScriptAction.AlterColumnFormula);
list.Add(column.ToSqlDrop(), 0, ScriptAction.AlterColumnFormula);
List<ISchemaBase> drops =
((Database)column.Parent.Parent).Dependencies.Find(column.Parent.Id,
column.Id, 0);
drops.ForEach(item =>
{
if (item.Status != ObjectStatus.Create)
list.Add(item.Drop());
if (item.Status != ObjectStatus.Drop)
list.Add(item.Create());
});
/*Si la columna va a ser eliminada o la tabla va a ser reconstruida, no restaura la columna*/
if ((column.Status != ObjectStatus.Drop) &&
(column.Parent.Status != ObjectStatus.Rebuild))
list.Add(column.ToSqlAdd(), 0,
ScriptAction.AlterColumnFormulaRestore);
}
}
}
fields.Add(column.FullName, column.FullName);
}
}
}
}
}
list.AddRange(listDependencies);
return list;
}
private Boolean HasAnotherUDTClass()
{
if (IsAssembly)
{
/*If another UDT exists in the same assembly to bre created. It must be deleted BEFORE creating the new one.*/
UserDataType other =
((Database)Parent).UserTypes.Find(
item =>
(item.Status == ObjectStatus.Drop) &&
(item.AssemblyName + "." + item.AssemblyClass).Equals((AssemblyName + "." + AssemblyClass)));
if (other != null)
return true;
}
return false;
}
private string SQLDropOlder()
{
UserDataType other =
((Database)Parent).UserTypes.Find(
item =>
(item.Status == ObjectStatus.Drop) &&
(item.AssemblyName + "." + item.AssemblyClass).Equals((AssemblyName + "." + AssemblyClass)));
return other.ToSqlDrop();
}
public override SQLScript Create()
{
ScriptAction action = ScriptAction.AddUserDataType;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(ToSqlAdd(), 0, action);
}
else
return null;
}
public override SQLScript Drop()
{
const ScriptAction action = ScriptAction.DropUserDataType;
if (!GetWasInsertInDiffList(action))
{
SetWasInsertInDiffList(action);
return new SQLScript(ToSqlDrop(), 0, action);
}
return null;
}
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
try
{
var list = new SQLScriptList();
if (Status == ObjectStatus.Drop)
{
if (!HasAnotherUDTClass())
list.Add(Drop());
}
if (HasState(ObjectStatus.Create))
{
list.Add(Create());
}
if (Status == ObjectStatus.Alter)
{
if (Default.Status == ObjectStatus.Create)
list.Add(Default.ToSQLAddBind(), 0, ScriptAction.AddUserDataType);
if (Default.Status == ObjectStatus.Drop)
list.Add(Default.ToSQLAddUnBind(), 0, ScriptAction.UnbindRuleType);
if (Rule.Status == ObjectStatus.Create)
list.Add(Rule.ToSQLAddBind(), 0, ScriptAction.AddUserDataType);
if (Rule.Status == ObjectStatus.Drop)
list.Add(Rule.ToSQLAddUnBind(), 0, ScriptAction.UnbindRuleType);
}
if (Status == ObjectStatus.Rebuild)
{
list.AddRange(ToSQLChangeColumns());
if (!GetWasInsertInDiffList(ScriptAction.DropUserDataType))
{
list.Add(ToSqlDrop() + ToSql(), 0, ScriptAction.AddUserDataType);
}
else
list.Add(Create());
}
if (HasState(ObjectStatus.DropOlder))
{
list.Add(SQLDropOlder(), 0, ScriptAction.AddUserDataType);
}
return list;
}
catch
{
return null;
}
}
public bool Compare(UserDataType obj)
{
if (obj == null) throw new ArgumentNullException("obj");
if (Scale != obj.Scale) return false;
if (Precision != obj.Precision) return false;
if (AllowNull != obj.AllowNull) return false;
if (Size != obj.Size) return false;
if (!Type.Equals(obj.Type)) return false;
if (IsAssembly != obj.IsAssembly) return false;
if (!AssemblyClass.Equals(obj.AssemblyClass)) return false;
if (!AssemblyName.Equals(obj.AssemblyName)) return false;
if (!CompareDefault(this, obj)) return false;
if (!CompareRule(this, obj)) return false;
return true;
}
}
}

View File

@@ -0,0 +1,138 @@
using System;
using System.Text.RegularExpressions;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model.Util
{
internal static class FormatCode
{
private static readonly char[] TrimCharacters = { ' ', '\r', '\n', '\t' };
private class SearchItem
{
public int FindPosition;
public string Body = "";
}
/// <summary>
/// Clears all unnecessary characters that are after the END statement of the body, and whitespaces at the beginning.
/// </summary>
private static string CleanLast(string body)
{
if (string.IsNullOrEmpty(body))
{
return string.Empty;
}
return body.TrimStart().TrimEnd(TrimCharacters);
}
/// <summary>
/// Inserta la sentencia GO dentro del body
/// </summary>
private static string SmartGO(string code)
{
string prevText = code;
try
{
if (!prevText.Substring(prevText.Length - 2, 2).Equals("\r\n"))
prevText += "\r\n";
return prevText + "GO\r\n";
}
catch
{
return prevText;
}
}
/// <summary>
/// Busca la primer entrada con el nombre completo dentro de una funcion, store, vista, trigger o rule.
/// Ignora los comentarios.
/// </summary>
private static SearchItem FindCreate(string ObjectType, ISchemaBase item, string prevText)
{
SearchItem sitem = new SearchItem();
Regex regex = new Regex(@"((/\*)(\w|\s|\d|\[|\]|\.)*(\*/))|((\-\-)(.)*)", RegexOptions.IgnoreCase);
Regex reg2 = new Regex(@"CREATE " + ObjectType + @"(\s|\r|\n|\t|\w|\/|\*|-|@|_|&|#)*((\[)?" + item.Owner + @"(\])?((\s)*)?\.)?((\s)*)?(\[)?" + item.Name + @"(\])?", (RegexOptions)((int)RegexOptions.IgnoreCase + (int)RegexOptions.Multiline));
Regex reg3 = new Regex(@"((\[)?" + item.Owner + @"(\])?\.)?((\s)+\.)?(\s)*(\[)?" + item.Name + @"(\])?", RegexOptions.IgnoreCase);
Regex reg4 = new Regex(@"( )*\[");
//Regex reg3 = new Regex(@"((\[)?" + item.Owner + @"(\])?.)?(\[)?" + item.Name + @"(\])?", RegexOptions.Multiline);
MatchCollection abiertas = regex.Matches(prevText);
Boolean finish = false;
int indexStart = 0;
int indexBegin = 0;
int iAux = -1;
while (!finish)
{
Match match = reg2.Match(prevText, indexBegin);
if (match.Success)
iAux = match.Index;
else
iAux = -1;
if ((abiertas.Count == indexStart) || (match.Success))
finish = true;
else
{
if ((iAux < abiertas[indexStart].Index) || (iAux > abiertas[indexStart].Index + abiertas[indexStart].Length))
finish = true;
else
{
//indexBegin = abiertas[indexStart].Index + abiertas[indexStart].Length;
indexBegin = iAux + 1;
indexStart++;
}
}
}
string result = reg3.Replace(prevText, " " + item.FullName, 1, iAux + 1);
if (iAux != -1)
sitem.Body = reg4.Replace(result, " [", 1, iAux);
sitem.FindPosition = iAux;
return sitem;
}
public static string FormatCreate(string ObjectType, string body, ISchemaBase item)
{
try
{
string prevText = (string)body.Clone();
prevText = FindCreate(ObjectType, item, prevText).Body;
if (String.IsNullOrEmpty(prevText))
prevText = body;
prevText = CleanLast(prevText);
return SmartGO(prevText);
}
catch
{
return SmartGO(CleanLast(body));
}
}
public static string FormatAlter(string ObjectType, string body, ISchemaBase item, Boolean quitSchemaBinding)
{
string prevText = null;
try
{
prevText = (string)body.Clone();
SearchItem sitem = FindCreate(ObjectType, item, prevText);
Regex regAlter = new Regex("CREATE");
if (!quitSchemaBinding)
return regAlter.Replace(sitem.Body, "ALTER", 1, sitem.FindPosition);
//return prevText.Substring(0, iFind) + "ALTER " + sitem.ObjectType + " " + prevText.Substring(iFind + sitem.ObjectType.Length + 7, prevText.Length - (iFind + sitem.ObjectType.Length + 7)).TrimStart();
else
{
string text = regAlter.Replace(sitem.Body, "ALTER", 1, sitem.FindPosition);
Regex regex = new Regex("WITH SCHEMABINDING", RegexOptions.IgnoreCase);
return regex.Replace(text, "");
}
//return "";
}
catch
{
return prevText;
}
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using OpenDBDiff.Schema.Attributes;
using OpenDBDiff.Schema.Model;
using OpenDBDiff.Schema.SQLServer.Generates.Model.Util;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class View : Code
{
public View(ISchemaBase parent)
: base(parent, ObjectType.View, ScriptAction.AddView, ScriptAction.DropView)
{
Indexes = new SchemaList<Index, View>(this, ((Database)parent).AllObjects);
Triggers = new SchemaList<Trigger, View>(this, ((Database)parent).AllObjects);
CLRTriggers = new SchemaList<CLRTrigger, View>(this, ((Database)parent).AllObjects);
}
/// <summary>
/// Clona el objeto en una nueva instancia.
/// </summary>
public override ISchemaBase Clone(ISchemaBase parent)
{
View item = new View(parent);
item.Text = this.Text;
item.Status = this.Status;
item.Name = this.Name;
item.Id = this.Id;
item.Owner = this.Owner;
item.IsSchemaBinding = this.IsSchemaBinding;
item.DependenciesIn = this.DependenciesIn;
item.DependenciesOut = this.DependenciesOut;
item.Indexes = this.Indexes.Clone(item);
item.Triggers = this.Triggers.Clone(item);
return item;
}
[SchemaNode("CLR Triggers")]
public SchemaList<CLRTrigger, View> CLRTriggers { get; set; }
[SchemaNode("Triggers")]
public SchemaList<Trigger, View> Triggers { get; set; }
[SchemaNode("Indexes", "Index")]
public SchemaList<Index, View> Indexes { get; set; }
public override Boolean IsCodeType
{
get { return true; }
}
public override string ToSqlAdd()
{
string sql = ToSql();
this.Indexes.ForEach(item =>
{
if (item.Status != ObjectStatus.Drop)
{
item.SetWasInsertInDiffList(ScriptAction.AddIndex);
sql += item.ToSql();
}
}
);
this.Triggers.ForEach(item =>
{
if (item.Status != ObjectStatus.Drop)
{
item.SetWasInsertInDiffList(ScriptAction.AddTrigger);
sql += item.ToSql();
}
}
);
sql += this.ExtendedProperties.ToSql();
return sql;
}
public string ToSQLAlter()
{
return ToSQLAlter(false);
}
public string ToSQLAlter(Boolean quitSchemaBinding)
{
return FormatCode.FormatAlter("VIEW", ToSql(), this, quitSchemaBinding);
}
/// <summary>
/// Devuelve el schema de diferencias del Schema en formato SQL.
/// </summary>
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.Status != ObjectStatus.Original)
RootParent.ActionMessage.Add(this);
if (this.HasState(ObjectStatus.Drop))
list.Add(Drop());
if (this.HasState(ObjectStatus.Create))
list.Add(Create());
if (this.HasState(ObjectStatus.Alter))
{
if (this.HasState(ObjectStatus.RebuildDependencies))
list.AddRange(RebuildDependencies());
if (this.HasState(ObjectStatus.Rebuild))
{
list.Add(Drop());
list.Add(Create());
}
if (this.HasState(ObjectStatus.AlterBody))
{
int iCount = DependenciesCount;
list.Add(ToSQLAlter(), iCount, ScriptAction.AlterView);
}
if (!this.GetWasInsertInDiffList(ScriptAction.DropFunction) && (!this.GetWasInsertInDiffList(ScriptAction.AddFunction)))
list.AddRange(Indexes.ToSqlDiff());
list.AddRange(Triggers.ToSqlDiff());
}
return list;
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using OpenDBDiff.Schema.Model;
namespace OpenDBDiff.Schema.SQLServer.Generates.Model
{
public class XMLSchema : SQLServerSchemaBase
{
public XMLSchema(ISchemaBase parent)
: base(parent, ObjectType.XMLSchema)
{
this.Dependencies = new List<ObjectDependency>();
}
/// <summary>
/// Clona el objeto en una nueva instancia.
/// </summary>
public new XMLSchema Clone(ISchemaBase parent)
{
XMLSchema item = new XMLSchema(parent);
item.Text = this.Text;
item.Status = this.Status;
item.Name = this.Name;
item.Id = this.Id;
item.Owner = this.Owner;
item.Guid = this.Guid;
item.Dependencies = this.Dependencies;
return item;
}
public List<ObjectDependency> Dependencies { get; set; }
public string Text { get; set; }
public override string ToSql()
{
StringBuilder sql = new StringBuilder();
sql.Append("CREATE XML SCHEMA COLLECTION ");
sql.Append(this.FullName + " AS ");
sql.Append("N'" + this.Text + "'");
sql.Append("\r\nGO\r\n");
return sql.ToString();
}
public override string ToSqlAdd()
{
return ToSql();
}
public override string ToSqlDrop()
{
return "DROP XML SCHEMA COLLECTION " + FullName + "\r\nGO\r\n";
}
private SQLScriptList ToSQLChangeColumns()
{
Hashtable fields = new Hashtable();
SQLScriptList list = new SQLScriptList();
if ((this.Status == ObjectStatus.Alter) || (this.Status == ObjectStatus.Rebuild))
{
foreach (ObjectDependency dependency in this.Dependencies)
{
ISchemaBase itemDepens = ((Database)this.Parent).Find(dependency.Name);
if (dependency.IsCodeType)
{
list.AddRange(((ICode)itemDepens).Rebuild());
}
if (dependency.Type == ObjectType.Table)
{
Column column = ((Table)itemDepens).Columns[dependency.ColumnName];
if ((column.Parent.Status != ObjectStatus.Drop) && (column.Parent.Status != ObjectStatus.Create) && ((column.Status != ObjectStatus.Create)))
{
if (!fields.ContainsKey(column.FullName))
{
if (column.HasToRebuildOnlyConstraint)
column.Parent.Status = ObjectStatus.RebuildDependencies;
list.AddRange(column.RebuildConstraint(true));
list.Add("ALTER TABLE " + column.Parent.FullName + " ALTER COLUMN " + column.ToSQLRedefine(null, 0, "") + "\r\nGO\r\n", 0, ScriptAction.AlterColumn);
/*Si la columna va a ser eliminada o la tabla va a ser reconstruida, no restaura la columna*/
if ((column.Status != ObjectStatus.Drop) && (column.Parent.Status != ObjectStatus.Rebuild))
list.AddRange(column.Alter(ScriptAction.AlterColumnRestore));
fields.Add(column.FullName, column.FullName);
}
}
}
}
}
return list;
}
/// <summary>
/// Devuelve el schema de diferencias del Schema en formato SQL.
/// </summary>
public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection<ISchemaBase> schemas)
{
SQLScriptList list = new SQLScriptList();
if (this.Status == ObjectStatus.Drop)
{
list.Add(ToSqlDrop(), 0, ScriptAction.DropXMLSchema);
}
if (this.Status == ObjectStatus.Create)
{
list.Add(ToSql(), 0, ScriptAction.AddXMLSchema);
}
if (this.Status == ObjectStatus.Alter)
{
list.AddRange(ToSQLChangeColumns());
list.Add(ToSqlDrop() + ToSql(), 0, ScriptAction.AddXMLSchema);
}
return list;
}
public bool Compare(XMLSchema obj)
{
if (obj == null) throw new ArgumentNullException("obj");
if (!this.Text.Equals(obj.Text)) return false;
return true;
}
}
}