commit 3afa4c82efec3fa2f07d337db8bb8ab0b687fcc1 Author: Stefan Hutter Date: Thu Aug 26 20:59:17 2021 +0200 Initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8c98cf3 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +end_of_line = crlf +insert_final_newline = true +trim_trailing_whitespace = true + +# 4 space indentation +[*.cs] +indent_style = space +indent_size = 4 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9a728e2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Declare files that will always have CRLF line endings on checkout. +# required for unit tests to pass on any platform +*.sql text eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a0abd89 --- /dev/null +++ b/.gitignore @@ -0,0 +1,352 @@ + +# Created by https://www.gitignore.io/api/csharp +# Edit at https://www.gitignore.io/?templates=csharp + +### Csharp ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates +.vs + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- Backup*.rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# End of https://www.gitignore.io/api/csharp \ No newline at end of file diff --git a/Git_Create.bat b/Git_Create.bat new file mode 100644 index 0000000..984c86c --- /dev/null +++ b/Git_Create.bat @@ -0,0 +1,7 @@ +rem cd %1 +git init +git remote add origin http://192.168.111.85:30000/shu/OpenDBDiff.git +git add . +git commit -m "Initial commit" +git push -u origin master +pause \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..23cb790 --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/OpenDBDiff.Abstractions.Schema/Attributes/SchemaNodeAttribute.cs b/OpenDBDiff.Abstractions.Schema/Attributes/SchemaNodeAttribute.cs new file mode 100644 index 0000000..a4fdfeb --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Attributes/SchemaNodeAttribute.cs @@ -0,0 +1,33 @@ +using System; + +namespace OpenDBDiff.Abstractions.Schema.Attributes +{ + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] + public sealed class SchemaNodeAttribute : Attribute + { + public SchemaNodeAttribute(string name) + { + this.Name = name; + this.Image = "Folder"; + } + + public SchemaNodeAttribute(string name, string image) + { + this.Name = name; + this.Image = image; + } + + public SchemaNodeAttribute(string name, string image, Boolean isFullName) + { + this.Name = name; + this.Image = image; + this.IsFullName = isFullName; + } + + public string Name { get; private set; } + + public string Image { get; private set; } + + public Boolean IsFullName { get; private set; } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Errors/MessageLog.cs b/OpenDBDiff.Abstractions.Schema/Errors/MessageLog.cs new file mode 100644 index 0000000..4c45bdb --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Errors/MessageLog.cs @@ -0,0 +1,25 @@ +namespace OpenDBDiff.Abstractions.Schema.Errors +{ + public class MessageLog + { + public enum LogType + { + Information = 0, + Warning = 1, + Error = 2 + } + + public MessageLog(string description, string fullDescription, LogType type) + { + this.Description = description; + this.FullDescription = fullDescription; + this.Type = type; + } + + public LogType Type { get; private set; } + + public string FullDescription { get; private set; } + + public string Description { get; private set; } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Events/ProgressEventArgs.cs b/OpenDBDiff.Abstractions.Schema/Events/ProgressEventArgs.cs new file mode 100644 index 0000000..0342d29 --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Events/ProgressEventArgs.cs @@ -0,0 +1,17 @@ +using System; + +namespace OpenDBDiff.Abstractions.Schema.Events +{ + public class ProgressEventArgs : EventArgs + { + public string Message { get; set; } + + public ProgressEventArgs(string message, int progress) + { + this.Progress = progress; + this.Message = message; + } + + public int Progress { get; set; } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Events/ProgressEventHandler.cs b/OpenDBDiff.Abstractions.Schema/Events/ProgressEventHandler.cs new file mode 100644 index 0000000..be31c79 --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Events/ProgressEventHandler.cs @@ -0,0 +1,14 @@ +namespace OpenDBDiff.Abstractions.Schema.Events +{ + public class ProgressEventHandler + { + public delegate void ProgressHandler(ProgressEventArgs e); + + public static event ProgressHandler OnProgress; + + public static void RaiseOnChange(ProgressEventArgs e) + { + if (OnProgress != null) OnProgress(e); + } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Misc/SchemaException.cs b/OpenDBDiff.Abstractions.Schema/Misc/SchemaException.cs new file mode 100644 index 0000000..acd30e6 --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Misc/SchemaException.cs @@ -0,0 +1,43 @@ +using System; +using System.Globalization; +using System.IO; +using System.Runtime.Serialization; +using System.Text; + +namespace OpenDBDiff.Abstractions.Schema.Misc +{ + [Serializable] + public class SchemaException : Exception + { + private static void Write(string message) + { + try + { + StreamWriter writer = new StreamWriter(Path.Combine(Path.GetTempPath(), "OpenDBDiff.log"), true, Encoding.ASCII); + writer.WriteLine("ERROR: " + DateTime.Now.ToString("yyyy/MM/dd hh:mm", CultureInfo.InvariantCulture) + "-" + message); + writer.Close(); + } + finally { } + } + + public SchemaException() : base() + { + } + + public SchemaException(string message) + : base(message) + { + Write(base.StackTrace); + } + + public SchemaException(string message, Exception exception) + : base(message, exception) + { + Write(exception.StackTrace); + } + + protected SchemaException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Model/IDatabase.cs b/OpenDBDiff.Abstractions.Schema/Model/IDatabase.cs new file mode 100644 index 0000000..111e62b --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Model/IDatabase.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace OpenDBDiff.Abstractions.Schema.Model +{ + public interface IDatabase : ISchemaBase + { + bool IsCaseSensitive { get; } + SqlAction ActionMessage { get; } + IOption Options { get; } + + new SQLScriptList ToSqlDiff(ICollection selectedSchemas); + ISchemaBase Find(string objectFullName); + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Model/IOption.cs b/OpenDBDiff.Abstractions.Schema/Model/IOption.cs new file mode 100644 index 0000000..185ee79 --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Model/IOption.cs @@ -0,0 +1,22 @@ +namespace OpenDBDiff.Abstractions.Schema.Model +{ + public interface IOption + { + IOptionFilter Filters { get; } + IOptionsContainer Defaults { get; } + IOptionsContainer Ignore { get; } + IOptionsContainer Script { get; } + IOptionComparison Comparison { get; } + + string Serialize(); + } + public interface IOptionsContainer + { + System.Collections.Generic.IDictionary GetOptions(); + } + + public interface IOptionComparison : IOptionsContainer + { + bool ReloadComparisonOnUpdate { get; set; } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Model/IOptionFilter.cs b/OpenDBDiff.Abstractions.Schema/Model/IOptionFilter.cs new file mode 100644 index 0000000..62baaf3 --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Model/IOptionFilter.cs @@ -0,0 +1,7 @@ +namespace OpenDBDiff.Abstractions.Schema.Model +{ + public interface IOptionFilter : IOptionsContainer + { + bool IsItemIncluded(ISchemaBase item); + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Model/ISchemaBase.cs b/OpenDBDiff.Abstractions.Schema/Model/ISchemaBase.cs new file mode 100644 index 0000000..c57671d --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Model/ISchemaBase.cs @@ -0,0 +1,31 @@ +using System; + +namespace OpenDBDiff.Abstractions.Schema.Model +{ + public interface ISchemaBase + { + ISchemaBase Clone(ISchemaBase parent); + int DependenciesCount { get; } + string FullName { get; } + int Id { get; set; } + Boolean HasState(ObjectStatus statusFind); + string Name { get; set; } + string Owner { get; set; } + ISchemaBase Parent { get; set; } + ObjectStatus Status { get; set; } + Boolean IsSystem { get; set; } + ObjectType ObjectType { get; set; } + Boolean GetWasInsertInDiffList(ScriptAction action); + void SetWasInsertInDiffList(ScriptAction action); + void ResetWasInsertInDiffList(); + string ToSqlDrop(); + string ToSqlAdd(); + string ToSql(); + SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection schemas); + SQLScript Create(); + SQLScript Drop(); + int CompareFullNameTo(string name, string myName); + Boolean IsCodeType { get; } + IDatabase RootParent { get; } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Model/ISchemaList.cs b/OpenDBDiff.Abstractions.Schema/Model/ISchemaList.cs new file mode 100644 index 0000000..4ce68a0 --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Model/ISchemaList.cs @@ -0,0 +1,16 @@ +namespace OpenDBDiff.Abstractions.Schema.Model +{ + public interface ISchemaList + where T : ISchemaBase + where P : ISchemaBase + { + void Add(T item); + SchemaList Clone(P parentObject); + bool Contains(string name); + T Find(int id); + T this[string name] { get; set; } + T this[int index] { get; set; } + P Parent { get; } + int Count { get; } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Model/SchemaBase.cs b/OpenDBDiff.Abstractions.Schema/Model/SchemaBase.cs new file mode 100644 index 0000000..baf5c2d --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Model/SchemaBase.cs @@ -0,0 +1,286 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace OpenDBDiff.Abstractions.Schema.Model +{ + [DebuggerDisplay("Id: {Id} - Name: {Name} - Status: {status}")] + public abstract class SchemaBase : ISchemaBase + { + private ObjectStatus status; + private ISchemaBase parent; + private string nameCharacterOpen; + private string nameCharacterClose; + private Hashtable wasInsertInDiffList; + private IDatabase rootParent = null; + + protected SchemaBase(string nameCharacterOpen, string nameCharacterClose, ObjectType objectType) + { + this.Guid = System.Guid.NewGuid().ToString(); + this.ObjectType = objectType; + this.status = ObjectStatus.Original; + this.nameCharacterClose = nameCharacterClose; + this.nameCharacterOpen = nameCharacterOpen; + } + + /*protected object Clone(object vObj, ISchemaBase parentObject) + { + if (vObj.GetType().IsValueType || vObj.GetType() == Type.GetType("System.String")) + return vObj; + else + { + object newObject = Activator.CreateInstance(vObj.GetType(), new object[] {parentObject }); + foreach (PropertyInfo Item in newObject.GetType().GetProperties()) + { + if (Item.GetType().GetInterface("ICloneable") != null) + { + ICloneable IClone = (ICloneable)Item.GetValue(vObj, null); + Item.SetValue(newObject, IClone.Clone(), null); + } + else + Item.SetValue(newObject, Clone(Item.GetValue(vObj, null),parentObject), null); + } + foreach (FieldInfo Item in newObject.GetType().GetFields()) + { + if (Item.GetType().GetInterface("ICloneable") != null) + { + ICloneable IClone = (ICloneable)Item.GetValue(vObj); + Item.SetValue(newObject, IClone.Clone()); + } + else + Item.SetValue(newObject, Clone(Item.GetValue(vObj),parentObject)); + } + return newObject; + } + } */ + + /// + /// Instance's parent object + /// + public ISchemaBase Parent + { + get { return parent; } + set + { + rootParent = null; + parent = value; + } + } + + public IDatabase RootParent + { + get + { + if (rootParent != null) return rootParent; + if (this.Parent != null) + { + if (this.Parent.Parent != null) + if (this.Parent.Parent.Parent != null) + rootParent = (IDatabase)this.Parent.Parent.Parent; + else + rootParent = (IDatabase)this.Parent.Parent; + else + rootParent = (IDatabase)this.Parent; + } + else if (this is IDatabase) + { + rootParent = (IDatabase)this; + } + return rootParent; + } + } + + public int CompareFullNameTo(string name, string myName) + { + if (!RootParent.IsCaseSensitive) + return myName.ToUpper().CompareTo(name.ToUpper()); + else + return myName.CompareTo(name); + } + + /// + /// SQL Code for the database object + /// + public abstract string ToSql(); + + /// + /// SQL Code for drop the database object + /// + public abstract string ToSqlDrop(); + + /// + /// SQL Code for add the database object + /// + public abstract string ToSqlAdd(); + + /// + /// Deep clone the object + /// + /// Parent of the object + /// + public virtual ISchemaBase Clone(ISchemaBase parent) + { + return null; + } + + /// + /// Returns the list of SQL Scripts to execute to sync for the specified schemas + /// + /// + /// A list () of scripts to run to sync + /// + public virtual SQLScriptList ToSqlDiff(ICollection schemas) + { + return null; + } + + public virtual SQLScript Create() + { + throw new NotImplementedException(); + } + + public virtual SQLScript Drop() + { + throw new NotImplementedException(); + } + + /// + /// Returns if the obecet was already inserted in the list of scripts with differencies + /// + /// The action to check in the list + /// True if is already inserted. False if it wasn't + public Boolean GetWasInsertInDiffList(ScriptAction action) + { + if (wasInsertInDiffList != null) + return (wasInsertInDiffList.ContainsKey(action)); + else + return false; + } + + /// + /// Sets the object as inserted in the list of differences script + /// + public void SetWasInsertInDiffList(ScriptAction action) + { + if (wasInsertInDiffList == null) wasInsertInDiffList = new Hashtable(); + if (!wasInsertInDiffList.ContainsKey(action)) + wasInsertInDiffList.Add(action, true); + } + + public void ResetWasInsertInDiffList() + { + this.wasInsertInDiffList = null; + } + + /// + /// Unique GUID identifying the object + /// + public string Guid { get; set; } + + /// + /// Object type. + /// + public ObjectType ObjectType { get; set; } + + /// + /// ID del objeto. + /// + public int Id { get; set; } + + /// + /// Nombre completo del objeto, incluyendo el owner. + /// + public virtual string FullName + { + get + { + if (String.IsNullOrEmpty(Owner)) + return nameCharacterOpen + Name + nameCharacterClose; + else + return nameCharacterOpen + Owner + nameCharacterClose + "." + nameCharacterOpen + Name + nameCharacterClose; + } + } + + /// + /// Username of the owner of the object + /// + public string Owner { get; set; } + + /// + /// Nombre of the object + /// + public string Name { get; set; } + + /// + /// Determine if the database object if a System object or not + /// + public Boolean IsSystem { get; set; } + + /// + /// Returns the status of the object. By default is set to . When setting a value, it also affects to the status. + /// + public virtual ObjectStatus Status + { + get { return status; } + set + { + if (status != ObjectStatus.Rebuild && status != ObjectStatus.RebuildDependencies) + status = value; + + if (Parent == null) return; + + // Si el estado de la tabla era el original, lo cambia, sino deja el actual estado. + // If the state of the table was the original, it changes it, but leaves the current state. (Google translated) + if (Parent.Status == ObjectStatus.Original + || value == ObjectStatus.Rebuild + || value == ObjectStatus.RebuildDependencies) + { + switch (value) + { + case ObjectStatus.RebuildDependencies: + case ObjectStatus.Rebuild: + Parent.Status = value; + break; + + case ObjectStatus.Original: + break; + + default: + Parent.Status = ObjectStatus.Alter; + break; + } + } + } + } + + public Boolean HasState(ObjectStatus statusFind) + { + return ((this.Status & statusFind) == statusFind); + } + + public virtual Boolean IsCodeType + { + get { return false; } + } + + public virtual int DependenciesCount + { + get { return 0; } + } + + public virtual bool HasDependencies + { + get { return DependenciesCount > 0; } + } + + /// + /// Get if the SQL commands for the collection must build in one single statement + /// or one statmente for each item of the collection. + /// + public virtual Boolean MustBuildSqlInLine + { + get { return false; } + } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Model/SchemaList.cs b/OpenDBDiff.Abstractions.Schema/Model/SchemaList.cs new file mode 100644 index 0000000..acddd9c --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Model/SchemaList.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenDBDiff.Abstractions.Schema.Model +{ + public class SchemaList : List, ISchemaList + where T : ISchemaBase + where P : ISchemaBase + { + private Dictionary nameMap = new Dictionary(); + private SearchSchemaBase allObjects = null; + private bool IsCaseSensitive = false; + + public SchemaList(P parent, SearchSchemaBase allObjects) + { + this.Parent = parent; + this.allObjects = allObjects; + this.Comparion = StringComparison.CurrentCultureIgnoreCase; + } + + public SchemaList Clone(P parentObject) + { + SchemaList options = new SchemaList(parentObject, allObjects); + this.ForEach(item => + { + object cloned = item.Clone(parentObject); + + //Not everything implements the clone methd, so make sure we got some actual cloned data before adding it back to the list + if (cloned != null) + options.Add((T)cloned); + }); + + return options; + } + + protected StringComparison Comparion { get; private set; } + + public SchemaList(P parent) + { + this.Parent = parent; + } + + public new void Add(T item) + { + var db = this.Parent.RootParent; + if (!db.Options.Filters.IsItemIncluded(item)) + return; + + base.Add(item); + if (allObjects != null) + allObjects.Add(item); + + string name = item.FullName; + IsCaseSensitive = item.RootParent.IsCaseSensitive; + if (!IsCaseSensitive) + name = name.ToUpper(); + + if (!nameMap.ContainsKey(name)) + nameMap.Add(name, base.Count - 1); + } + /// + /// Devuelve el objecto Padre perteneciente a la coleccion. + /// + public P Parent { get; private set; } + + /// + /// Devuelve el objeto correspondiente a un ID especifico. + /// + /// ID del objecto a buscar + /// Si no encontro nada, devuelve null, de lo contrario, el objeto + public T Find(int id) + { + return Find(Item => Item.Id == id); + } + + /// + /// Indica si el nombre del objecto existe en la coleccion de objectos del mismo tipo. + /// + /// + /// Nombre del objecto a buscar. + /// + /// + public Boolean Contains(string name) + { + if (IsCaseSensitive) + return nameMap.ContainsKey(name); + else + return nameMap.ContainsKey(name.ToUpper()); + } + + public virtual T this[string name] + { + get + { + try + { + if (IsCaseSensitive) + return this[nameMap[name]]; + else + return this[nameMap[name.ToUpper()]]; + } + catch + { + return default(T); + } + } + set + { + if (IsCaseSensitive) + base[nameMap[name]] = value; + else + base[nameMap[name.ToUpper()]] = value; + } + } + + public virtual SQLScriptList ToSqlDiff() + { + return ToSqlDiff(new List()); + } + public virtual SQLScriptList ToSqlDiff(ICollection schemas) + { + SQLScriptList listDiff = new SQLScriptList(); + foreach (var item in this.Where(item => (schemas.Count() == 0 || schemas.FirstOrDefault(sch => sch.Id == item.Id || (sch.Parent != null && sch.Parent.Id == item.Id)) != default(ISchemaBase)))) + { + item.ResetWasInsertInDiffList(); + var childrenSchemas = schemas.Where(s => s.Parent != null && s.Parent.Id == item.Id).ToList(); + listDiff.AddRange(item.ToSqlDiff(childrenSchemas).WarnMissingScript(item)); + } + return listDiff; + } + + + public virtual string ToSql() + { + return string.Join + ( + "\r\n", + this + .Where(item => !item.HasState(ObjectStatus.Drop)) + .Select(item => item.ToSql()) + ); + } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/Model/SearchSchemaBase.cs b/OpenDBDiff.Abstractions.Schema/Model/SearchSchemaBase.cs new file mode 100644 index 0000000..c0c919b --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Model/SearchSchemaBase.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.Abstractions.Schema.Model +{ + public class SearchSchemaBase + { + private Dictionary objectTypes; + private Dictionary objectParent; + private Dictionary objectId; + + public SearchSchemaBase() + { + objectTypes = new Dictionary(); + objectParent = new Dictionary(); + objectId = new Dictionary(); + } + + public void Add(ISchemaBase item) + { + if (objectTypes.ContainsKey(item.FullName.ToUpper())) + objectTypes.Remove(item.FullName.ToUpper()); + objectTypes.Add(item.FullName.ToUpper(), item.ObjectType); + if ((item.ObjectType == ObjectType.Constraint) || (item.ObjectType == ObjectType.Index) || (item.ObjectType == ObjectType.Trigger) || (item.ObjectType == ObjectType.CLRTrigger)) + { + if (objectParent.ContainsKey(item.FullName.ToUpper())) + objectParent.Remove(item.FullName.ToUpper()); + objectParent.Add(item.FullName.ToUpper(), item.Parent.FullName); + + if (objectId.ContainsKey(item.Id)) + objectId.Remove(item.Id); + objectId.Add(item.Id, item.FullName); + } + } + + + public Nullable GetType(string FullName) + { + if (objectTypes.ContainsKey(FullName.ToUpper())) + return objectTypes[FullName.ToUpper()]; + return null; + } + + public string GetParentName(string FullName) + { + return objectParent[FullName.ToUpper()]; + } + + public string GetFullName(int Id) + { + return objectId[Id]; + } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/OpenDBDiff.Abstractions.Schema.csproj b/OpenDBDiff.Abstractions.Schema/OpenDBDiff.Abstractions.Schema.csproj new file mode 100644 index 0000000..b4fb41f --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/OpenDBDiff.Abstractions.Schema.csproj @@ -0,0 +1,119 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {406558A0-1B98-4D0E-B8B6-2013700B065A} + Library + Properties + OpenDBDiff.Abstractions.Schema + OpenDBDiff.Abstractions.Schema + false + + + + + 3.5 + + + v4.5.2 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + true + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + .editorconfig + + + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + + + \ No newline at end of file diff --git a/OpenDBDiff.Abstractions.Schema/Properties/AssemblyInfo.cs b/OpenDBDiff.Abstractions.Schema/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e0ce1ea --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/Properties/AssemblyInfo.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.Abstractions.Schema")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.Abstractions.Schema")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("713fb09f-31e8-40a9-a6d0-93e28dc5ef67")] +[assembly: CLSCompliant(true)] diff --git a/OpenDBDiff.Abstractions.Schema/SQLScript.cs b/OpenDBDiff.Abstractions.Schema/SQLScript.cs new file mode 100644 index 0000000..9c7cb20 --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/SQLScript.cs @@ -0,0 +1,72 @@ +using System; + +namespace OpenDBDiff.Abstractions.Schema +{ + public class SQLScript : IComparable + { + public SQLScript(int deepvalue, string sqlScript, int dependenciesCount, ScriptAction action) + { + SQL = sqlScript; + Dependencies = dependenciesCount; + Status = action; + Deep = deepvalue; + //childs = new SQLScriptList(); + } + + public SQLScript(string sqlScript, int dependenciesCount, ScriptAction action) + { + SQL = sqlScript; + Dependencies = dependenciesCount; + Status = action; + //childs = new SQLScriptList(); + } + + /*public SQLScriptList Childs + { + get { return childs; } + set { childs = value; } + }*/ + + public int Deep { get; set; } + + public ScriptAction Status { get; set; } + + public int Dependencies { get; set; } + + public string SQL { get; set; } + + public bool IsDropAction + { + get + { + return ((Status == ScriptAction.DropView) || (Status == ScriptAction.DropFunction) || (Status == ScriptAction.DropStoredProcedure)); + } + } + + public bool IsAddAction + { + get + { + return ((Status == ScriptAction.AddView) || (Status == ScriptAction.AddFunction) || (Status == ScriptAction.AddStoredProcedure)); + } + } + + public int CompareTo(SQLScript other) + { + if (this.Deep == other.Deep) + { + if (this.Status == other.Status) + { + if (this.Status == ScriptAction.DropTable || this.Status == ScriptAction.DropConstraint || this.Status == ScriptAction.DropTrigger) + return other.Dependencies.CompareTo(this.Dependencies); + else + return this.Dependencies.CompareTo(other.Dependencies); + } + else + return this.Status.CompareTo(other.Status); + } + else + return this.Deep.CompareTo(other.Deep); + } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/SQLScriptList.cs b/OpenDBDiff.Abstractions.Schema/SQLScriptList.cs new file mode 100644 index 0000000..863cc6c --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/SQLScriptList.cs @@ -0,0 +1,135 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenDBDiff.Abstractions.Schema +{ + public class SQLScriptList + { + private List list; + + public void Sort() + { + if (list != null) list.Sort(); + } + + public void Add(SQLScript item, int deep) + { + if (list == null) list = new List(); + if (item != null) + { + item.Deep = deep; + list.Add(item); + } + } + + public void Add(SQLScript item) + { + if (list == null) list = new List(); + if (item != null) list.Add(item); + } + + public void Add(string SQL, int dependencies, ScriptAction type) + { + if (list == null) list = new List(); + list.Add(new SQLScript(SQL, dependencies, type)); + } + + public void AddRange(SQLScriptList items) + { + for (int j = 0; j < items.Count; j++) + { + if (list == null) list = new List(); + list.Add(items[j]); + } + } + + public int Count + { + get { return (list == null) ? 0 : list.Count; } + } + + public SQLScript this[int index] + { + get { return list[index]; } + } + + /*private string ToSqlDown(SQLScript item) + { + string sql = ""; + for (int i = 0; i < item.Childs.Count; i++) + { + for (int k = 0; k < item.Childs[i].Childs.Count; k++) + { + for (int h = 0; h < item.Childs[i].Childs[k].Childs.Count; h++) + { + for (int l = 0; l < item.Childs[i].Childs[k].Childs[h].Childs.Count; l++) + { + for (int m = 0; m < item.Childs[i].Childs[k].Childs[h].Childs[l].Childs.Count; m++) + { + sql += item.Childs[i].Childs[k].Childs[h].Childs[l].Childs[m].SQL; + } + sql += item.Childs[i].Childs[k].Childs[h].Childs[l].SQL; + } + sql += item.Childs[i].Childs[k].Childs[h].SQL; + } + sql += item.Childs[i].Childs[k].SQL; + } + sql += item.Childs[i].SQL; + } + sql += item.SQL; + return sql; + }*/ + + public string ToSQL() + { + StringBuilder sql = new StringBuilder(); + this.Sort(); /*Ordena la lista antes de generar el script*/ + if (list != null) + { + for (int j = 0; j < list.Count; j++) + { + //if ((list[j].IsDropAction) || (!list[j].IsAddAction)) + sql.Append(list[j].SQL); //ToSqlDown(list[j]); + } + /*for (int j = list.Count-1; j >= 0; j--) + { + if (list[j].IsAddAction) + sql.Append(list[j].SQL); + }*/ + + } + return sql.ToString(); + } + + public SQLScriptList FindAlter() + { + SQLScriptList alter = new SQLScriptList(); + list.ForEach(item => { if ((item.Status == ScriptAction.AlterView) || (item.Status == ScriptAction.AlterFunction) || (item.Status == ScriptAction.AlterProcedure)) alter.Add(item); }); + return alter; + } + } + + public static class SQLScriptListExtensionMethod + { + public static SQLScriptList WarnMissingScript(this SQLScriptList scriptList, ISchemaBase scriptSource) + { + if (scriptList == null || scriptSource == null || scriptSource.Status == ObjectStatus.Original) + { + return scriptList; + } + + for (int i = 0; i < scriptList.Count; ++i) + { + if (!String.IsNullOrEmpty(scriptList[i].SQL)) + { + return scriptList; + } + } + + scriptList.Add(String.Format("\r\n--\r\n-- DIFF-ERROR 0x{0:x8}.{1:d3}: Missing {2} script for {3} '{4}'\r\n--\r\n\r\n", (int)scriptSource.Status, (int)scriptSource.ObjectType, scriptSource.Status, scriptSource.ObjectType, scriptSource.Name), 0, ScriptAction.None); + return scriptList; + } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/SqlAction.cs b/OpenDBDiff.Abstractions.Schema/SqlAction.cs new file mode 100644 index 0000000..5a7c127 --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/SqlAction.cs @@ -0,0 +1,90 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System.Collections.Generic; + +namespace OpenDBDiff.Abstractions.Schema +{ + public class SqlAction + { + public SqlAction(ISchemaBase item) + { + if ((item.ObjectType == ObjectType.Column) || (item.ObjectType == ObjectType.Index) || (item.ObjectType == ObjectType.Constraint)) + this.Name = item.Name; + else + this.Name = item.FullName; + this.Action = item.Status; + this.Type = item.ObjectType; + Childs = new List(); + } + + public void Add(ISchemaBase item) + { + Childs.Add(new SqlAction(item)); + } + + public SqlAction this[string name] + { + get + { + for (int j = 0; j < Childs.Count; j++) + { + if (Childs[j].Name.Equals(name)) + return Childs[j]; + } + return null; + } + } + + public string Name { get; private set; } + + public ObjectType Type { get; set; } + + public ObjectStatus Action { get; set; } + + public List Childs { get; private set; } + + private string GetTypeName() + { + if (Type == ObjectType.Table) return "TABLE"; + if (Type == ObjectType.Column) return "COLUMN"; + if (Type == ObjectType.Constraint) return "CONSTRAINT"; + if (Type == ObjectType.Index) return "INDEX"; + if (Type == ObjectType.View) return "VIEW"; + if (Type == ObjectType.StoredProcedure) return "STORED PROCEDURE"; + if (Type == ObjectType.Synonym) return "SYNONYM"; + if (Type == ObjectType.Function) return "FUNCTION"; + if (Type == ObjectType.Assembly) return "ASSEMBLY"; + if (Type == ObjectType.Trigger) return "TRIGGER"; + return ""; + } + + private bool IsRoot + { + get + { + return ((this.Type != ObjectType.Function) && (this.Type != ObjectType.StoredProcedure) && (this.Type != ObjectType.View) && (this.Type != ObjectType.Table) && (this.Type != ObjectType.Database)); + } + } + + public string Message + { + get + { + string message = ""; + if (Action == ObjectStatus.Drop) + message = "DROP " + GetTypeName() + " " + Name + "\r\n"; + if (Action == ObjectStatus.Create) + message = "ADD " + GetTypeName() + " " + Name + "\r\n"; + if ((Action == ObjectStatus.Alter) || (Action == ObjectStatus.Rebuild) || (Action == ObjectStatus.RebuildDependencies)) + message = "MODIFY " + GetTypeName() + " " + Name + "\r\n"; + + Childs.ForEach(item => + { + if (item.IsRoot) + message += " "; + message += item.Message; + }); + return message; + } + } + } +} diff --git a/OpenDBDiff.Abstractions.Schema/StatusEnum.cs b/OpenDBDiff.Abstractions.Schema/StatusEnum.cs new file mode 100644 index 0000000..ea516d0 --- /dev/null +++ b/OpenDBDiff.Abstractions.Schema/StatusEnum.cs @@ -0,0 +1,231 @@ +using System; +using System.ComponentModel; + +namespace OpenDBDiff.Abstractions.Schema +{ + /// + /// Original = The object has no modifications. + /// Create = The object must be created. + /// Drop = The object must be deleted. + /// Alter = The object has modifications. + /// AlterRebuild = The object has modifications, but a DROP and ADD must be done too. + /// AlterProperties = The object has modifications in its properties, but not in its structure. + /// + [Flags] + public enum ObjectStatus + { + /// + /// The object is unaltered + /// + Original = 0, + + /// + /// The object was altered + /// + Alter = 2, + + AlterBody = 4, + + /// + /// The object was altered but requires a rebuild + /// + Rebuild = 8, + + /// + /// The object has properties altered, but not in it's structure + /// + RebuildDependencies = 16, + + Update = 32, + Create = 64, + + /// + /// The object should be dropped + /// + Drop = 128, + + Disabled = 256, + + /// + /// The owner of the object changed + /// + ChangeOwner = 512, + + DropOlder = 1024, + Bind = 2048, + + /// + /// The permission set of the object changed + /// + PermissionSet = 4096, + + AlterWhitespace = 8192 + } + + public enum ScriptAction + { + None = 0, + UseDatabase = 1, + AddFileGroup = 2, + AddFile = 3, + AlterFile = 4, + AlterFileGroup = 5, + UnbindRuleColumn = 6, + UnbindRuleType = 7, + DropRule = 8, + AddRule = 9, + + DropFullTextIndex = 10, + DropConstraintFK = 11, + DropConstraint = 12, + DropConstraintPK = 13, + DropSynonyms = 14, + DropStoredProcedure = 15, + DropTrigger = 16, + DropView = 17, + DropFunction = 17, + DropIndex = 18, + DropTable = 20, + AlterColumnFormula = 21, + AlterColumn = 22, + AddRole = 23, + AddUser = 24, + AddSchema = 25, + AddDefault = 26, + AddAssembly = 27, + AddAssemblyFile = 28, + AddUserDataType = 29, + AddTableType = 30, + AlterPartitionFunction = 31, + AddPartitionFunction = 32, + AddPartitionScheme = 33, + AddFullText = 34, + AddXMLSchema = 35, + AlterAssembly = 36, + UpdateTable = 37, + AlterTable = 38, + AlterIndex = 39, + AlterFullTextIndex = 40, + AddTable = 41, + RebuildTable = 42, + AlterColumnRestore = 43, + AlterColumnFormulaRestore = 44, + AlterFunction = 45, + AlterView = 46, + AlterProcedure = 47, + AddIndex = 48, + AddFunction = 49, + AddView = 49, /*AddFunction and AddView must have the same number!!!*/ + AddTrigger = 50, + AddConstraint = 51, + AddConstraintPK = 52, + AddConstraintFK = 53, + AlterConstraint = 54, + AddFullTextIndex = 55, + EnabledTrigger = 56, + AddSynonyms = 57, + AddStoredProcedure = 58, + DropOptions = 59, + AddOptions = 60, + + AlterTableChangeTracking = 61, + + DropFullText = 62, + DropTableType = 63, + DropUserDataType = 64, + DropXMLSchema = 65, + DropAssemblyUserDataType = 66, + DropAssemblyFile = 67, + DropAssembly = 68, + DropDefault = 69, + + DropPartitionScheme = 70, + DropPartitionFunction = 71, + + DropSchema = 72, + DropUser = 73, + DropRole = 74, + DropFile = 75, + DropFileGroup = 76, + AddExtendedProperty = 77, + DropExtendedProperty = 78 + } + + public enum ObjectType + { + None = 0, + Table = 1, + Column = 2, + Trigger = 3, + Constraint = 4, + + [Description("Constraint Column")] + ConstraintColumn = 5, + + Index = 6, + + [Description("Index Column")] + IndexColumn = 7, + + [Description("User Data Type")] + UserDataType = 8, + + [Description("XML Schema")] + XMLSchema = 9, + + View = 10, + Function = 11, + + [Description("Stored Procedure")] + StoredProcedure = 12, + + [Description("Table Option")] + TableOption = 13, + + Database = 14, + Schema = 15, + + [Description("File Group")] + FileGroup = 16, + + File = 17, + Default = 18, + Rule = 19, + Synonym = 20, + Assembly = 21, + User = 22, + Role = 23, + + [Description("Full Text")] + FullText = 24, + + [Description("Assembly File")] + AssemblyFile = 25, + + [Description("CLR Stored Procedure")] + CLRStoredProcedure = 26, + + [Description("CLR Trigger")] + CLRTrigger = 27, + + [Description("CLR Function")] + CLRFunction = 28, + + [Description("Extended Property")] + ExtendedProperty = 30, + + Partition = 31, + + [Description("Partition Function")] + PartitionFunction = 32, + + [Description("Partition Scheme")] + PartitionScheme = 33, + + [Description("Table Type")] + TableType = 34, + + [Description("Full Text Index")] + FullTextIndex = 35 + } +} diff --git a/OpenDBDiff.Abstractions.Ui/IDatabaseComparer.cs b/OpenDBDiff.Abstractions.Ui/IDatabaseComparer.cs new file mode 100644 index 0000000..6a4bd9b --- /dev/null +++ b/OpenDBDiff.Abstractions.Ui/IDatabaseComparer.cs @@ -0,0 +1,9 @@ +using OpenDBDiff.Abstractions.Schema.Model; + +namespace OpenDBDiff.Abstractions.Ui +{ + public interface IDatabaseComparer + { + IDatabase Compare(IDatabase origin, IDatabase destination); + } +} diff --git a/OpenDBDiff.Abstractions.Ui/IFront.cs b/OpenDBDiff.Abstractions.Ui/IFront.cs new file mode 100644 index 0000000..f80469e --- /dev/null +++ b/OpenDBDiff.Abstractions.Ui/IFront.cs @@ -0,0 +1,24 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace OpenDBDiff.Abstractions.Ui +{ + public interface IFront : ICloneable + { + Point Location { get; set; } + string Name { get; set; } + Size Size { get; set; } + int TabIndex { get; set; } + bool Visible { get; set; } + DockStyle Dock { get; set; } + Boolean TestConnection(); + string ConnectionString { get; set; } + string ErrorConnection { get; } + string DatabaseName { get; } + string Text { get; set; } + AnchorStyles Anchor { get; set; } + Control Control { get; } + void SetSettingsFrom(IFront other); + } +} diff --git a/OpenDBDiff.Abstractions.Ui/IGenerator.cs b/OpenDBDiff.Abstractions.Ui/IGenerator.cs new file mode 100644 index 0000000..f3727c7 --- /dev/null +++ b/OpenDBDiff.Abstractions.Ui/IGenerator.cs @@ -0,0 +1,13 @@ +using OpenDBDiff.Abstractions.Schema.Model; + +namespace OpenDBDiff.Abstractions.Ui +{ + + public interface IGenerator + { + event Schema.Events.ProgressEventHandler.ProgressHandler OnProgress; + + int GetMaxValue(); + IDatabase Process(); + } +} diff --git a/OpenDBDiff.Abstractions.Ui/IProjectHandler.cs b/OpenDBDiff.Abstractions.Ui/IProjectHandler.cs new file mode 100644 index 0000000..64046e6 --- /dev/null +++ b/OpenDBDiff.Abstractions.Ui/IProjectHandler.cs @@ -0,0 +1,24 @@ +using OpenDBDiff.Abstractions.Schema.Model; + +namespace OpenDBDiff.Abstractions.Ui +{ + public interface IProjectHandler + { + IFront CreateSourceSelector(); + IFront CreateDestinationSelector(); + string GetSourceConnectionString(); + string GetDestinationConnectionString(); + string GetSourceServerName(); + string GetSourceDatabaseName(); + string GetDestinationServerName(); + OptionControl CreateOptionControl(); + string GetDestinationDatabaseName(); + + IGenerator SetSourceGenerator(string connectionString, IOption options); + IGenerator SetDestinationGenerator(string connectionString, IOption options); + IDatabaseComparer GetDatabaseComparer(); + IOption GetDefaultProjectOptions(); + string GetScriptLanguage(); + void Unload(); + } +} diff --git a/OpenDBDiff.Abstractions.Ui/OpenDBDiff.Abstractions.Ui.csproj b/OpenDBDiff.Abstractions.Ui/OpenDBDiff.Abstractions.Ui.csproj new file mode 100644 index 0000000..4b9f5f5 --- /dev/null +++ b/OpenDBDiff.Abstractions.Ui/OpenDBDiff.Abstractions.Ui.csproj @@ -0,0 +1,117 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768} + Library + Properties + OpenDBDiff.Abstractions.Ui + OpenDBDiff.Abstractions.Ui + false + + + + + 3.5 + + + v4.5.2 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + true + + + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + UserControl + + + + + + .editorconfig + + + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + + + {406558a0-1b98-4d0e-b8b6-2013700b065a} + OpenDBDiff.Abstractions.Schema + + + + + \ No newline at end of file diff --git a/OpenDBDiff.Abstractions.Ui/OptionControl.cs b/OpenDBDiff.Abstractions.Ui/OptionControl.cs new file mode 100644 index 0000000..be6d35e --- /dev/null +++ b/OpenDBDiff.Abstractions.Ui/OptionControl.cs @@ -0,0 +1,25 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.Abstractions.Ui +{ + public class OptionControl : System.Windows.Forms.UserControl + { + public event OptionEventHandler OptionSaved; + public delegate void OptionEventHandler(IOption option); + public new virtual void Load(IOption option) + { + throw new NotImplementedException("Load option not implemented"); + } + + public virtual void Save() + { + throw new NotImplementedException("Save not implemented"); + } + + protected virtual void FireOptionChanged(IOption option) + { + OptionSaved?.Invoke(option); + } + } +} diff --git a/OpenDBDiff.Abstractions.Ui/Properties/AssemblyInfo.cs b/OpenDBDiff.Abstractions.Ui/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2d8cb15 --- /dev/null +++ b/OpenDBDiff.Abstractions.Ui/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.Abstractions.Ui")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.Abstractions.Ui")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cd2b11ca-bbad-48a4-98e2-eeac17dde7ad")] +[assembly: System.CLSCompliant(true)] diff --git a/OpenDBDiff.CLI/App.config b/OpenDBDiff.CLI/App.config new file mode 100644 index 0000000..d39d31b --- /dev/null +++ b/OpenDBDiff.CLI/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/OpenDBDiff.CLI/CommandlineOptions.cs b/OpenDBDiff.CLI/CommandlineOptions.cs new file mode 100644 index 0000000..2ecae0e --- /dev/null +++ b/OpenDBDiff.CLI/CommandlineOptions.cs @@ -0,0 +1,16 @@ +using CommandLine; + +namespace OpenDBDiff.CLI +{ + public class CommandlineOptions + { + [Option('b', "before", Required = true, HelpText = "Connection string of database before changes are applied.")] + public string Before { get; set; } + + [Option('a', "after", Required = true, HelpText = "Connection string of database after changes are applied.")] + public string After { get; set; } + + [Option('o', "outputfile", Required = false, HelpText = "Output file of action script. If omitted, script is written to the console.")] + public string OutputFile { get; set; } + } +} diff --git a/OpenDBDiff.CLI/OpenDBDiff.CLI.csproj b/OpenDBDiff.CLI/OpenDBDiff.CLI.csproj new file mode 100644 index 0000000..72c33ae --- /dev/null +++ b/OpenDBDiff.CLI/OpenDBDiff.CLI.csproj @@ -0,0 +1,90 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E794AA28-EE68-44BD-827B-1BFD9C106B65} + Exe + Properties + OpenDBDiff.CLI + OpenDBDiff.CLI + v4.5.2 + 512 + + + + + 3.5 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + false + + + true + + + + ..\packages\CommandLineParser.2.8.0\lib\net45\CommandLine.dll + + + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + + {406558a0-1b98-4d0e-b8b6-2013700b065a} + OpenDBDiff.Abstractions.Schema + + + {32ac9af6-db93-4354-b69f-6dbc65c70867} + OpenDBDiff.SqlServer.Schema + + + + + .editorconfig + + + + + + + \ No newline at end of file diff --git a/OpenDBDiff.CLI/Program.cs b/OpenDBDiff.CLI/Program.cs new file mode 100644 index 0000000..be98e72 --- /dev/null +++ b/OpenDBDiff.CLI/Program.cs @@ -0,0 +1,120 @@ +using CommandLine; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Generates; +using OpenDBDiff.SqlServer.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Data.SqlClient; +using System.Diagnostics; +using System.IO; + +namespace OpenDBDiff.CLI +{ + public class Program + { + private static SqlOption SqlFilter = new SqlOption(); + + protected Program() + { + } + + private static int Main(string[] args) + { + bool completedSuccessfully = false; + + Parser.Default.ParseArguments(args) + .WithParsed(options => + { + try + { + completedSuccessfully = Work(options); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + }); + + if (Debugger.IsAttached) + { + Console.WriteLine("Press any key to continue..."); + Console.ReadKey(false); + } + + return completedSuccessfully ? 0 : 1; + } + + private static Boolean TestConnection(string connectionString1) + { + using (SqlConnection connection = new SqlConnection()) + { + connection.ConnectionString = connectionString1; + connection.Open(); + connection.Close(); + return true; + } + } + + private static bool Work(CommandlineOptions options) + { + try + { + Database origin; + Database destination; + if (TestConnection(options.Before) + && TestConnection(options.After)) + { + Generate sql = new Generate(); + sql.ConnectionString = options.Before; + Console.WriteLine("Reading first database..."); + sql.Options = SqlFilter; + origin = sql.Process(); + + sql.ConnectionString = options.After; + Console.WriteLine("Reading second database..."); + destination = sql.Process(); + Console.WriteLine("Comparing databases schemas..."); + origin = Generate.Compare(origin, destination); + // temporary work-around: run twice just like GUI + origin.ToSqlDiff(new System.Collections.Generic.List()); + + Console.WriteLine("Generating SQL file..."); + var script = origin.ToSqlDiff(new System.Collections.Generic.List()).ToSQL(); + if (!string.IsNullOrWhiteSpace(options.OutputFile)) + { + Console.WriteLine("Writing action script to {0}", options.OutputFile); + SaveFile(options.OutputFile, script); + } + else + { + Console.WriteLine(); + Console.WriteLine(script); + Console.WriteLine(); + } + return true; + } + } + catch (Exception ex) + { + string newIssueUri = System.Configuration.ConfigurationManager.AppSettings["OpenDBDiff.NewIssueUri"]; + if (string.IsNullOrEmpty(newIssueUri)) + newIssueUri = "https://github.com/OpenDBDiff/OpenDBDiff/issues/new"; + + Console.WriteLine($"{ex.Message}\r\n{ex.StackTrace}\r\n\r\nPlease report this issue at {newIssueUri}."); + Console.WriteLine(); + } + + return false; + } + + private static void SaveFile(string filenmame, string sql) + { + if (!String.IsNullOrEmpty(filenmame)) + { + StreamWriter writer = new StreamWriter(filenmame, false); + writer.Write(sql); + writer.Close(); + } + } + } +} diff --git a/OpenDBDiff.CLI/Properties/AssemblyInfo.cs b/OpenDBDiff.CLI/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2d2224b --- /dev/null +++ b/OpenDBDiff.CLI/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff Console")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff Console")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("30c9b799-3cd9-4c83-9141-dc7782005ec1")] diff --git a/OpenDBDiff.CLI/packages.config b/OpenDBDiff.CLI/packages.config new file mode 100644 index 0000000..2f5d65c --- /dev/null +++ b/OpenDBDiff.CLI/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OpenDBDiff.Front/IDatabaseComparer.cs b/OpenDBDiff.Front/IDatabaseComparer.cs new file mode 100644 index 0000000..685f5f7 --- /dev/null +++ b/OpenDBDiff.Front/IDatabaseComparer.cs @@ -0,0 +1,9 @@ +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Front +{ + public interface IDatabaseComparer + { + IDatabase Compare(IDatabase origin, IDatabase destination); + } +} diff --git a/OpenDBDiff.Front/IFront.cs b/OpenDBDiff.Front/IFront.cs new file mode 100644 index 0000000..98d7c2f --- /dev/null +++ b/OpenDBDiff.Front/IFront.cs @@ -0,0 +1,23 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + public interface IFront + { + Point Location { get; set; } + string Name { get; set; } + Size Size { get; set; } + int TabIndex { get; set; } + bool Visible { get; set; } + DockStyle Dock { get; set; } + Boolean TestConnection(); + string ConnectionString { get; set; } + string ErrorConnection { get; } + string DatabaseName { get; } + string Text { get; set; } + AnchorStyles Anchor { get; set; } + Control Control { get; } + } +} diff --git a/OpenDBDiff.Front/IGenerator.cs b/OpenDBDiff.Front/IGenerator.cs new file mode 100644 index 0000000..5a1079f --- /dev/null +++ b/OpenDBDiff.Front/IGenerator.cs @@ -0,0 +1,13 @@ +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Front +{ + + public interface IGenerator + { + event Schema.Events.ProgressEventHandler.ProgressHandler OnProgress; + + int GetMaxValue(); + IDatabase Process(); + } +} \ No newline at end of file diff --git a/OpenDBDiff.Front/IProjectHandler.cs b/OpenDBDiff.Front/IProjectHandler.cs new file mode 100644 index 0000000..3a0061a --- /dev/null +++ b/OpenDBDiff.Front/IProjectHandler.cs @@ -0,0 +1,26 @@ +using System; +using System.Windows.Forms; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Front +{ + public interface IProjectHandler + { + IFront CreateSourceSelector(); + IFront CreateDestinationSelector(); + string GetSourceConnectionString(); + string GetDestinationConnectionString(); + string GetSourceServerName(); + string GetSourceDatabaseName(); + string GetDestinationServerName(); + OptionControl CreateOptionControl(); + string GetDestinationDatabaseName(); + + IGenerator SetSourceGenerator(string connectionString, IOption options); + IGenerator SetDestinationGenerator(string connectionString, IOption options); + IDatabaseComparer GetDatabaseComparer(); + IOption GetDefaultProjectOptions(); + string GetScriptLanguage(); + void Unload(); + } +} \ No newline at end of file diff --git a/OpenDBDiff.Front/OpenDBDiff.Front.csproj b/OpenDBDiff.Front/OpenDBDiff.Front.csproj new file mode 100644 index 0000000..c76a282 --- /dev/null +++ b/OpenDBDiff.Front/OpenDBDiff.Front.csproj @@ -0,0 +1,114 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768} + Library + Properties + OpenDBDiff.Front + OpenDBDiff.Front + true + OpenDBDiff.Front.snk + + + 3.5 + + + v4.5.2 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + UserControl + + + + + + .editorconfig + + + + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + + + {406558a0-1b98-4d0e-b8b6-2013700b065a} + DBDiff.Schema + + + + + diff --git a/OpenDBDiff.Front/OpenDBDiff.Front.snk b/OpenDBDiff.Front/OpenDBDiff.Front.snk new file mode 100644 index 0000000..0ea4f18 Binary files /dev/null and b/OpenDBDiff.Front/OpenDBDiff.Front.snk differ diff --git a/OpenDBDiff.Front/OptionControl.cs b/OpenDBDiff.Front/OptionControl.cs new file mode 100644 index 0000000..0b0b85b --- /dev/null +++ b/OpenDBDiff.Front/OptionControl.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Front +{ + public class OptionControl : System.Windows.Forms.UserControl + { + public event OptionEventHandler OptionSaved; + public delegate void OptionEventHandler(IOption option); + public new virtual void Load(IOption option) + { + throw new NotImplementedException("Load option not implemented"); + } + + public virtual void Save() + { + throw new NotImplementedException("Save not implemented"); + } + + protected virtual void FireOptionChanged(IOption option) + { + OptionSaved?.Invoke(option); + } + } +} diff --git a/OpenDBDiff.Front/Properties/AssemblyInfo.cs b/OpenDBDiff.Front/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8cc70d8 --- /dev/null +++ b/OpenDBDiff.Front/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.Front")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.Front")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cd2b11ca-bbad-48a4-98e2-eeac17dde7ad")] +[assembly: System.CLSCompliant(true)] diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareAssemblies.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareAssemblies.cs new file mode 100644 index 0000000..578dea8 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareAssemblies.cs @@ -0,0 +1,58 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareAssemblies : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Assembly node) + { + if (!node.Compare(originFields[node.FullName])) + { + Assembly newNode = (Assembly)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + + if (node.Text.Equals(originFields[node.FullName].Text)) + { + if (!node.PermissionSet.Equals(originFields[node.FullName].PermissionSet)) + newNode.Status += (int)ObjectStatus.PermissionSet; + if (!node.Owner.Equals(originFields[node.FullName].Owner)) + newNode.Status += (int)ObjectStatus.ChangeOwner; + } + else + newNode.Status = ObjectStatus.Rebuild; + + originFields[node.FullName].Files.ForEach(item => + { + if (!newNode.Files.Contains(item.FullName)) + newNode.Files.Add(new AssemblyFile(newNode, item, ObjectStatus.Drop)); + else + item.Status = ObjectStatus.Alter; + }); + newNode.Files.ForEach(item => + { + if (!originFields[node.FullName].Files.Contains(item.FullName)) + { + item.Status = ObjectStatus.Create; + } + }); + CompareExtendedProperties(originFields[node.FullName], newNode); + originFields[node.FullName] = newNode; + } + } + + protected override void DoNew(SchemaList originFields, Assembly node) + { + bool pass = true; + Assembly newNode = (Assembly)node.Clone(originFields.Parent); + if ((((Database)newNode.RootParent).Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2005) + && (((Database)node.RootParent).Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008)) + pass = node.FullName.Equals("Microsoft.SqlServer.Types"); + if (pass) + { + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareBase.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareBase.cs new file mode 100644 index 0000000..64d0d89 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareBase.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Generates; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal abstract class CompareBase where T : ISchemaBase + { + protected virtual void DoUpdate(SchemaList originFields, T node) where Root : ISchemaBase + { + + } + + protected virtual void DoNew(SchemaList originFields, T node) where Root : ISchemaBase + { + T newNode = node;//.Clone(originFields.Parent); + newNode.Parent = originFields.Parent; + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected void DoDelete(T node) + { + node.Status = ObjectStatus.Drop; + } + + public void GenerateDifferences(SchemaList originFields, SchemaList destinationFields) where Root : ISchemaBase + { + bool has = true; + int destinationIndex = 0; + int originIndex = 0; + int destinationCount = destinationFields.Count; + int originCount = originFields.Count; + T node; + + while (has) + { + has = false; + if (destinationCount > destinationIndex) + { + node = destinationFields[destinationIndex]; + Generate.RaiseOnCompareProgress("Comparing Destination {0}: [{1}]", node.ObjectType, node.Name); + if (!originFields.Contains(node.FullName)) + { + Generate.RaiseOnCompareProgress("Adding {0}: [{1}]", node.ObjectType, node.Name); + DoNew(originFields, node); + } + else + { + Generate.RaiseOnCompareProgress("Updating {0}: [{1}]", node.ObjectType, node.Name); + DoUpdate(originFields, node); + } + + destinationIndex++; + has = true; + } + + if (originCount > originIndex) + { + node = originFields[originIndex]; + Generate.RaiseOnCompareProgress("Comparing Source {0}: [{1}]", node.ObjectType, node.Name); + if (!destinationFields.Contains(node.FullName)) + { + Generate.RaiseOnCompareProgress("Deleting {0}: [{1}]", node.ObjectType, node.Name); + DoDelete(node); + } + + originIndex++; + has = true; + } + } + } + + protected static void CompareExtendedProperties(ISQLServerSchemaBase origin, ISQLServerSchemaBase destination) + { + List dropList = (from node in origin.ExtendedProperties + where !destination.ExtendedProperties.Exists(item => item.Name.Equals(node.Name, StringComparison.CurrentCultureIgnoreCase)) + select node).ToList(); + List addList = (from node in destination.ExtendedProperties + where !origin.ExtendedProperties.Exists(item => item.Name.Equals(node.Name, StringComparison.CurrentCultureIgnoreCase)) + select node).ToList(); + dropList.ForEach(item => { item.Status = ObjectStatus.Drop; }); + addList.ForEach(item => { item.Status = ObjectStatus.Create; }); + origin.ExtendedProperties.AddRange(addList); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareCLRFunction.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareCLRFunction.cs new file mode 100644 index 0000000..fb8ef41 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareCLRFunction.cs @@ -0,0 +1,18 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareCLRFunction : CompareBase + { + protected override void DoUpdate(SchemaList originFields, CLRFunction node) + { + if (!node.Compare(originFields[node.FullName])) + { + CLRFunction newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareCLRStoredProcedure.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareCLRStoredProcedure.cs new file mode 100644 index 0000000..6a19c3e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareCLRStoredProcedure.cs @@ -0,0 +1,18 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareCLRStoredProcedure : CompareBase + { + protected override void DoUpdate(SchemaList originFields, CLRStoredProcedure node) + { + if (!node.Compare(originFields[node.FullName])) + { + CLRStoredProcedure newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareCLRTriggers.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareCLRTriggers.cs new file mode 100644 index 0000000..f58887c --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareCLRTriggers.cs @@ -0,0 +1,19 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareCLRTriggers : CompareBase + { + protected override void DoUpdate(SchemaList originFields, CLRTrigger node) + { + if (!node.Compare(originFields[node.FullName])) + { + CLRTrigger newNode = node; + newNode.Status = ObjectStatus.Alter; + CompareExtendedProperties(newNode, originFields[node.FullName]); + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareColumns.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareColumns.cs new file mode 100644 index 0000000..def388b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareColumns.cs @@ -0,0 +1,91 @@ +using System; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + public class CompareColumns + { + public void GenerateDifferences(Columns originFields, Columns destinationFields) where T : ISchemaBase + { + int restPosition = 0; + int sumPosition = 0; + + foreach (Column node in originFields) + { + if (!destinationFields.Contains(node.FullName)) + { + node.Status = ObjectStatus.Drop; + restPosition++; + } + else + originFields[node.FullName].Position -= restPosition; + } + foreach (Column node in destinationFields) + { + if (!originFields.Contains(node.FullName)) + { + Column newNode = node.Clone(originFields.Parent); + if ((newNode.Position == 1) || ((newNode.DefaultConstraint == null) && (!newNode.IsNullable) && (!newNode.IsComputed) && (!newNode.IsIdentity) && (!newNode.IsIdentityForReplication))) + { + newNode.Status = ObjectStatus.Create; + newNode.Parent.Status = ObjectStatus.Rebuild; + } + else + newNode.Status = ObjectStatus.Create; + sumPosition++; + originFields.Add(newNode); + } + else + { + Column originField = originFields[node.FullName]; + /*ColumnConstraint oldDefault = null; + if (originField.DefaultConstraint != null) + oldDefault = originField.DefaultConstraint.Clone(originField);*/ + Boolean IsColumnEqual = Column.Compare(originField, node); + if ((!IsColumnEqual) || (originField.Position != node.Position)) + { + if (Column.CompareIdentity(originField, node)) + { + + if (node.HasToRebuildOnlyConstraint) + { + node.Status = ObjectStatus.Alter; + if ((originField.IsNullable) && (!node.IsNullable)) + node.Status += (int)ObjectStatus.Update; + } + else + { + if (node.HasToRebuild(originField.Position + sumPosition, originField.Type, originField.IsFileStream)) + node.Status = ObjectStatus.Rebuild; + else + { + if (!IsColumnEqual) + { + node.Status = ObjectStatus.Alter; + if ((originField.IsNullable) && (!node.IsNullable)) + node.Status += (int)ObjectStatus.Update; + } + } + } + if (node.Status != ObjectStatus.Rebuild) + { + if (!Column.CompareRule(originField, node)) + { + node.Status += (int)ObjectStatus.Bind; + } + } + } + else + { + node.Status = ObjectStatus.Rebuild; + } + originFields[node.FullName] = node.Clone(originFields.Parent); + } + originFields[node.FullName].DefaultConstraint = CompareColumnsConstraints.GenerateDifferences(originField, node); + } + } + } + } +} + diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareColumnsConstraints.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareColumnsConstraints.cs new file mode 100644 index 0000000..b65eb1e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareColumnsConstraints.cs @@ -0,0 +1,72 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareColumnsConstraints : CompareBase + { + public static ColumnConstraint GenerateDifferences(Column originFields, Column destinationFields) + { + if ((originFields.DefaultConstraint == null) && (destinationFields.DefaultConstraint != null)) + { + originFields.DefaultConstraint = destinationFields.DefaultConstraint.Clone(originFields); + originFields.DefaultConstraint.Status = ObjectStatus.Create; + originFields.DefaultConstraint.Parent.Status = ObjectStatus.Original; + originFields.DefaultConstraint.Parent.Parent.Status = ObjectStatus.Alter; + } + else + { + if ((originFields.DefaultConstraint != null) && (destinationFields.DefaultConstraint != null)) + { + if (!ColumnConstraint.Compare(originFields.DefaultConstraint, destinationFields.DefaultConstraint)) + { + originFields.DefaultConstraint = destinationFields.DefaultConstraint.Clone(originFields); + //Indico que hay un ALTER TABLE, pero sobre la columna, no seteo ningun estado. + originFields.DefaultConstraint.Status = ObjectStatus.Alter; + originFields.DefaultConstraint.Parent.Status = ObjectStatus.Original; + originFields.DefaultConstraint.Parent.Parent.Status = ObjectStatus.Alter; + } + } + else + if ((originFields.DefaultConstraint != null) && (destinationFields.DefaultConstraint == null)) + { + originFields.DefaultConstraint.Status = ObjectStatus.Drop; + originFields.DefaultConstraint.Parent.Status = ObjectStatus.Original; + originFields.DefaultConstraint.Parent.Parent.Status = ObjectStatus.Alter; + } + } + /*foreach (ColumnConstraint node in destinationFields) + { + if (!originFields.Exists(node.FullName)) + { + node.Status = ObjectStatusType.CreateStatus; + originFields.Parent.Status = ObjectStatusType.OriginalStatus; + originFields.Parent.Parent.Status = ObjectStatusType.AlterStatus; + originFields.Add(node); + } + else + { + if (!ColumnConstraint.Compare(originFields[node.FullName], node)) + { + ColumnConstraint newNode = node.Clone(originFields.Parent); + //Indico que hay un ALTER TABLE, pero sobre la columna, no seteo ningun estado. + newNode.Status = ObjectStatusType.AlterStatus; + newNode.Parent.Status = ObjectStatusType.OriginalStatus; + newNode.Parent.Parent.Status = ObjectStatusType.AlterStatus; + originFields[node.FullName] = newNode; + + } + } + } + + MarkDrop(originFields, destinationFields, node => + { + node.Status = ObjectStatusType.DropStatus; + originFields.Parent.Status = ObjectStatusType.OriginalStatus; + originFields.Parent.Parent.Status = ObjectStatusType.AlterStatus; + } + ); + */ + return originFields.DefaultConstraint; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareConstraints.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareConstraints.cs new file mode 100644 index 0000000..19089ba --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareConstraints.cs @@ -0,0 +1,40 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareConstraints : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Constraint node) + { + Constraint origin = originFields[node.FullName]; + if (!Constraint.Compare(origin, node)) + { + Constraint newNode = (Constraint)node.Clone(originFields.Parent); + if (node.IsDisabled == origin.IsDisabled) + { + newNode.Status = ObjectStatus.Alter; + } + else + newNode.Status = ObjectStatus.Alter + (int)ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + else + { + if (node.IsDisabled != origin.IsDisabled) + { + Constraint newNode = (Constraint)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + } + } + + protected override void DoNew(SchemaList originFields, Constraint node) + { + Constraint newNode = (Constraint)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareDDLTriggers.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareDDLTriggers.cs new file mode 100644 index 0000000..3780f12 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareDDLTriggers.cs @@ -0,0 +1,28 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareDDLTriggers : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Trigger node) + { + if (!node.Compare(originFields[node.FullName])) + { + Trigger newNode = (Trigger)node.Clone(originFields.Parent); + if (!newNode.Text.Equals(originFields[node.FullName].Text)) + newNode.Status = ObjectStatus.Alter; + if (node.IsDisabled != originFields[node.FullName].IsDisabled) + newNode.Status = newNode.Status + (int)ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + } + + protected override void DoNew(SchemaList originFields, Trigger node) + { + Trigger newNode = (Trigger)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareDatabase.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareDatabase.cs new file mode 100644 index 0000000..b9b2eaf --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareDatabase.cs @@ -0,0 +1,54 @@ +using OpenDBDiff.Schema.Misc; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal static class CompareDatabase + { + /// + /// Generates the differences to migrate a schema from origin to destination + /// + /// The Origin schema is the schema before our generated actions are applied. + /// The Destination schema is the schema after our actions are applied. + /// + /// + public static Database GenerateDifferences(Database origin, Database destination) + { + try + { + Database data = origin; + (new CompareTables()).GenerateDifferences(origin.Tables, destination.Tables); + (new CompareAssemblies()).GenerateDifferences(origin.Assemblies, destination.Assemblies); + (new CompareUserDataTypes()).GenerateDifferences(origin.UserTypes, destination.UserTypes); + (new CompareXMLSchemas()).GenerateDifferences(origin.XmlSchemas, destination.XmlSchemas); + (new CompareSchemas()).GenerateDifferences(origin.Schemas, destination.Schemas); + (new CompareFileGroups()).GenerateDifferences(origin.FileGroups, destination.FileGroups); + (new CompareRules()).GenerateDifferences(origin.Rules, destination.Rules); + (new CompareDDLTriggers()).GenerateDifferences(origin.DDLTriggers, destination.DDLTriggers); + (new CompareSynonyms()).GenerateDifferences(origin.Synonyms, destination.Synonyms); + (new CompareUsers()).GenerateDifferences(origin.Users, destination.Users); + (new CompareStoredProcedures()).GenerateDifferences(origin.Procedures, destination.Procedures); + (new CompareCLRStoredProcedure()).GenerateDifferences(origin.CLRProcedures, destination.CLRProcedures); + (new CompareCLRFunction()).GenerateDifferences(origin.CLRFunctions, destination.CLRFunctions); + (new CompareViews()).GenerateDifferences(origin.Views, destination.Views); + (new CompareFunctions()).GenerateDifferences(origin.Functions, destination.Functions); + (new CompareRoles()).GenerateDifferences(origin.Roles, destination.Roles); + (new ComparePartitionFunction()).GenerateDifferences(origin.PartitionFunctions, destination.PartitionFunctions); + (new ComparePartitionSchemes()).GenerateDifferences(origin.PartitionSchemes, destination.PartitionSchemes); + (new CompareTableType()).GenerateDifferences(origin.TablesTypes, destination.TablesTypes); + (new CompareFullText()).GenerateDifferences(origin.FullText, destination.FullText); + data.SourceInfo = destination.Info; + return data; + } + catch (SchemaException) + { + throw; + } + catch (Exception ex) + { + throw new SchemaException(ex.Message, ex); + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFileGroups.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFileGroups.cs new file mode 100644 index 0000000..cdbcd17 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFileGroups.cs @@ -0,0 +1,44 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareFileGroups : CompareBase + { + protected override void DoNew(SchemaList originFields, FileGroup node) + { + FileGroup newNode = (FileGroup)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + /*If the Logical File Name exists in another filegroup, + * we must change the new Logical File Name. + */ + originFields.ForEach(file => + { + if (file.Status != ObjectStatus.Drop) + { + file.Files.ForEach(group => + { + newNode.Files.ForEach(ngroup => + { + if (group.CompareFullNameTo(group.FullName, ngroup.FullName) == 0) + { + newNode.Files[ngroup.FullName].Name = group.Name + "_2"; + } + }); + }); + } + }); + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, FileGroup node) + { + if (!FileGroup.Compare(node, originFields[node.FullName])) + { + FileGroup newNode = (FileGroup)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFullText.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFullText.cs new file mode 100644 index 0000000..85481a1 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFullText.cs @@ -0,0 +1,23 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareFullText : CompareBase + { + protected override void DoUpdate(SchemaList originFields, FullText node) + { + if (!node.Compare(originFields[node.FullName])) + { + FullText newNode = node; //.Clone(originFields.Parent); + if (node.IsDefault != originFields[node.FullName].IsDefault) + newNode.Status += (int)ObjectStatus.Disabled; + if (!node.Owner.Equals(originFields[node.FullName].Owner)) + newNode.Status += (int)ObjectStatus.ChangeOwner; + if (node.IsAccentSensity != originFields[node.FullName].IsAccentSensity) + newNode.Status += (int)ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFullTextIndex.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFullTextIndex.cs new file mode 100644 index 0000000..8ff6a09 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFullTextIndex.cs @@ -0,0 +1,28 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareFullTextIndex : CompareBase + { + protected override void DoNew(SchemaList originFields, FullTextIndex node) + { + FullTextIndex newNode = (FullTextIndex)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, FullTextIndex node) + { + if (!node.Compare(originFields[node.FullName])) + { + FullTextIndex newNode = (FullTextIndex)node.Clone(originFields.Parent); + if (node.IsDisabled != originFields[node.FullName].IsDisabled) + newNode.Status += (int)ObjectStatus.Disabled; + else + newNode.Status += (int)ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFunctions.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFunctions.cs new file mode 100644 index 0000000..d067bd0 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareFunctions.cs @@ -0,0 +1,44 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareFunctions : CompareBase + { + protected override void DoNew(SchemaList originFields, Function node) + { + Function newNode = (Function)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + newNode.DependenciesIn.ForEach(dep => + { + ISchemaBase item = ((Database)((ISchemaBase)originFields.Parent)).Find(dep); + if (item != null) + { + if (item.IsCodeType) + ((ICode)item).DependenciesOut.Add(newNode.FullName); + } + } + ); + } + + protected override void DoUpdate(SchemaList originFields, Function node) + { + if (!node.Compare(originFields[node.FullName])) + { + Function newNode = (Function)node.Clone(originFields.Parent); + newNode.DependenciesIn.AddRange(originFields[node.FullName].DependenciesIn); + newNode.DependenciesOut.AddRange(originFields[node.FullName].DependenciesOut); + + newNode.Status = ObjectStatus.Alter; + if (newNode.IsSchemaBinding) + newNode.Status += (int)ObjectStatus.RebuildDependencies; + if (newNode.HasToRebuild) + newNode.Status += (int)ObjectStatus.Rebuild; + else + newNode.Status += (int)ObjectStatus.AlterBody; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareIndexes.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareIndexes.cs new file mode 100644 index 0000000..d70ee1a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareIndexes.cs @@ -0,0 +1,30 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareIndexes : CompareBase + { + protected override void DoNew(SchemaList originFields, Index node) + { + Index newNode = (Index)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, Index node) + { + if (!Index.Compare(node, originFields[node.FullName])) + { + Index newNode = (Index)node.Clone(originFields.Parent); + if (!Index.CompareExceptIsDisabled(node, originFields[node.FullName])) + { + newNode.Status = ObjectStatus.Alter; + } + else + newNode.Status = ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/ComparePartitionFunction.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/ComparePartitionFunction.cs new file mode 100644 index 0000000..88eb12c --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/ComparePartitionFunction.cs @@ -0,0 +1,31 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class ComparePartitionFunction : CompareBase + { + protected override void DoUpdate(SchemaList originFields, PartitionFunction node) + { + if (!PartitionFunction.Compare(node, originFields[node.FullName])) + { + PartitionFunction newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Rebuild; + originFields[node.FullName] = newNode; + } + else + { + if (!PartitionFunction.CompareValues(node, originFields[node.FullName])) + { + PartitionFunction newNode = node.Clone(originFields.Parent); + if (newNode.Values.Count == originFields[node.FullName].Values.Count) + newNode.Status = ObjectStatus.Rebuild; + else + newNode.Status = ObjectStatus.Alter; + newNode.Old = originFields[node.FullName].Clone(originFields.Parent); + originFields[node.FullName] = newNode; + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/ComparePartitionSchemes.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/ComparePartitionSchemes.cs new file mode 100644 index 0000000..058abdb --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/ComparePartitionSchemes.cs @@ -0,0 +1,18 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class ComparePartitionSchemes : CompareBase + { + protected override void DoUpdate(SchemaList originFields, PartitionScheme node) + { + if (!PartitionScheme.Compare(node, originFields[node.FullName])) + { + PartitionScheme newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Rebuild; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareRoles.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareRoles.cs new file mode 100644 index 0000000..3cd8ed0 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareRoles.cs @@ -0,0 +1,18 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareRoles : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Role node) + { + if (!node.Compare(originFields[node.FullName])) + { + Role newNode = node; + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareRules.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareRules.cs new file mode 100644 index 0000000..53b2f67 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareRules.cs @@ -0,0 +1,25 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareRules : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Rule node) + { + if (!node.Compare(originFields[node.FullName])) + { + Rule newNode = node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + + protected override void DoNew(SchemaList originFields, Rule node) + { + Rule newNode = node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareSchemas.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareSchemas.cs new file mode 100644 index 0000000..9911b8f --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareSchemas.cs @@ -0,0 +1,7 @@ +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareSchemas : CompareBase + { + + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareStoredProcedures.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareStoredProcedures.cs new file mode 100644 index 0000000..94eb43b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareStoredProcedures.cs @@ -0,0 +1,27 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareStoredProcedures : CompareBase + { + protected override void DoUpdate(SchemaList originFields, StoredProcedure node) + { + if (!node.Compare(originFields[node.FullName])) + { + StoredProcedure newNode = node; //.Clone(originFields.Parent); + + if (node.CompareExceptWhitespace(originFields[node.FullName])) + { + newNode.Status = ObjectStatus.AlterWhitespace; + } + else + { + newNode.Status = ObjectStatus.Alter; + } + + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareSynonyms.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareSynonyms.cs new file mode 100644 index 0000000..e97244e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareSynonyms.cs @@ -0,0 +1,18 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareSynonyms : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Synonym node) + { + if (!Synonym.Compare(node, originFields[node.FullName])) + { + Synonym newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTableType.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTableType.cs new file mode 100644 index 0000000..2551d23 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTableType.cs @@ -0,0 +1,44 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareTableType : CompareBase + { + protected override void DoUpdate(SchemaList originFields, TableType node) + { + if (node.Status != ObjectStatus.Drop) + { + TableType tablaOriginal = originFields[node.FullName]; + (new CompareColumns()).GenerateDifferences(tablaOriginal.Columns, node.Columns); + (new CompareConstraints()).GenerateDifferences(tablaOriginal.Constraints, node.Constraints); + (new CompareIndexes()).GenerateDifferences(tablaOriginal.Indexes, node.Indexes); + } + } + + /*public static void GenerateDifferences(SchemaList originTables, SchemaList destinationTables) + { + MarkDrop(originTables, destinationTables); + + foreach (TableType node in destinationTables) + { + if (!originTables.Exists(node.FullName)) + { + node.Status = ObjectStatusType.CreateStatus; + node.Parent = originTables.Parent; + originTables.Add(node); + } + else + { + if (node.Status != ObjectStatusType.DropStatus) + { + TableType tablaOriginal = originTables[node.FullName]; + CompareColumns.GenerateDifferences(tablaOriginal.Columns, node.Columns); + CompareConstraints.GenerateDifferences(tablaOriginal.Constraints, node.Constraints); + CompareIndexes.GenerateDifferences(tablaOriginal.Indexes, node.Indexes); + } + } + } + }*/ + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTables.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTables.cs new file mode 100644 index 0000000..646c240 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTables.cs @@ -0,0 +1,92 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareTables : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Table node) + { + if (node.Status != ObjectStatus.Drop) + { + Table tablaOriginal = originFields[node.FullName]; + tablaOriginal.OriginalTable = (Table)originFields[node.FullName].Clone((Database)tablaOriginal.Parent); + (new CompareColumns()).GenerateDifferences
(tablaOriginal.Columns, node.Columns); + (new CompareConstraints()).GenerateDifferences
(tablaOriginal.Constraints, node.Constraints); + (new CompareIndexes()).GenerateDifferences
(tablaOriginal.Indexes, node.Indexes); + (new CompareTablesOptions()).GenerateDifferences
(tablaOriginal.Options, node.Options); + (new CompareTriggers()).GenerateDifferences
(tablaOriginal.Triggers, node.Triggers); + (new CompareCLRTriggers()).GenerateDifferences
(tablaOriginal.CLRTriggers, node.CLRTriggers); + (new CompareFullTextIndex()).GenerateDifferences
(tablaOriginal.FullTextIndex, node.FullTextIndex); + if (!Table.CompareFileGroup(tablaOriginal, node)) + { + tablaOriginal.FileGroup = node.FileGroup; + /*Esto solo aplica a las tablas heap, el resto hace el campo en el filegroup del indice clustered*/ + if (!tablaOriginal.HasClusteredIndex) + tablaOriginal.Status = ObjectStatus.Rebuild; + } + if (!Table.CompareFileGroupText(tablaOriginal, node)) + { + tablaOriginal.FileGroupText = node.FileGroupText; + tablaOriginal.Status = ObjectStatus.Rebuild; + } + if (node.HasChangeTracking != tablaOriginal.HasChangeTracking) + { + tablaOriginal.HasChangeTracking = node.HasChangeTracking; + tablaOriginal.HasChangeTrackingTrackColumn = node.HasChangeTrackingTrackColumn; + tablaOriginal.Status += (int)ObjectStatus.Disabled; + } + } + } + + /// + /// Compara las colecciones de tablas de dos bases diferentes y marca el estado de los objetos + /// dependiendo si existen o si deben borrarse. + /// + /// + /// Tablas originales, donde se guardaran los estados de las tablas. + /// + /// Tablas comparativas, que se usa para comparar con la base original. + /// + /*public static void GenerateDifferences(SchemaList originTables, SchemaList destinationTables) + { + MarkDrop(originTables, destinationTables); + + foreach (Table node in destinationTables) + { + if (!originTables.Exists(node.FullName)) + { + node.Status = ObjectStatusType.CreateStatus; + node.Parent = originTables.Parent; + originTables.Add(node); + } + else + { + if (node.Status != ObjectStatusType.DropStatus) + { + Table tablaOriginal = originTables[node.FullName]; + tablaOriginal.OriginalTable = (Table)originTables[node.FullName].Clone((Database)tablaOriginal.Parent); + CompareColumns.GenerateDifferences
(tablaOriginal.Columns, node.Columns); + CompareConstraints.GenerateDifferences
(tablaOriginal.Constraints, node.Constraints); + CompareIndexes.GenerateDifferences(tablaOriginal.Indexes, node.Indexes); + CompareTablesOptions.GenerateDifferences(tablaOriginal.Options, node.Options); + (new CompareTriggers()).GenerateDifferences
(tablaOriginal.Triggers, node.Triggers); + (new CompareCLRTriggers()).GenerateDifferences
(tablaOriginal.CLRTriggers, node.CLRTriggers); + if (!Table.CompareFileGroup(tablaOriginal, node)) + { + tablaOriginal.FileGroup = node.FileGroup; + //Esto solo aplica a las tablas heap, el resto hace el campo en el filegroup del indice clustered + if (!tablaOriginal.HasClusteredIndex) + tablaOriginal.Status = ObjectStatusType.RebuildStatus; + } + if (!Table.CompareFileGroupText(tablaOriginal, node)) + { + tablaOriginal.FileGroupText = node.FileGroupText; + tablaOriginal.Status = ObjectStatusType.RebuildStatus; + } + } + } + } + }*/ + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTablesOptions.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTablesOptions.cs new file mode 100644 index 0000000..9e0f877 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTablesOptions.cs @@ -0,0 +1,25 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareTablesOptions : CompareBase + { + protected override void DoNew(SchemaList originFields, TableOption node) + { + TableOption newNode = (TableOption)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, TableOption node) + { + if (!TableOption.Compare(node, originFields[node.FullName])) + { + TableOption newNode = (TableOption)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTriggers.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTriggers.cs new file mode 100644 index 0000000..64b0f13 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareTriggers.cs @@ -0,0 +1,28 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareTriggers : CompareBase + { + protected override void DoNew(SchemaList originFields, Trigger node) + { + Trigger newNode = (Trigger)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, Trigger node) + { + if (!node.Compare(originFields[node.FullName])) + { + Trigger newNode = (Trigger)node.Clone(originFields.Parent); + if (!newNode.Text.Equals(originFields[node.FullName].Text)) + newNode.Status = ObjectStatus.Alter; + if (node.IsDisabled != originFields[node.FullName].IsDisabled) + newNode.Status = newNode.Status + (int)ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareUserDataTypes.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareUserDataTypes.cs new file mode 100644 index 0000000..997d050 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareUserDataTypes.cs @@ -0,0 +1,51 @@ +using System; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareUserDataTypes : CompareBase + { + protected override void DoNew(SchemaList originFields, UserDataType node) + { + UserDataType newNode = (UserDataType)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + Boolean HasAssembly = originFields.Exists(item => item.AssemblyFullName.Equals(node.AssemblyFullName) && item.IsAssembly); + if (HasAssembly) + newNode.Status += (int)ObjectStatus.DropOlder; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, UserDataType node) + { + if (!node.Compare(originFields[node.FullName])) + { + UserDataType newNode = (UserDataType)node.Clone(originFields.Parent); + newNode.Dependencies.AddRange(originFields[node.FullName].Dependencies); + + if (!UserDataType.CompareDefault(node, originFields[node.FullName])) + { + if (!String.IsNullOrEmpty(node.Default.Name)) + newNode.Default.Status = ObjectStatus.Create; + else + newNode.Default.Status = ObjectStatus.Drop; + newNode.Status = ObjectStatus.Alter; + } + else + { + if (!UserDataType.CompareRule(node, originFields[node.FullName])) + { + if (!String.IsNullOrEmpty(node.Rule.Name)) + newNode.Rule.Status = ObjectStatus.Create; + else + newNode.Rule.Status = ObjectStatus.Drop; + newNode.Status = ObjectStatus.Alter; + } + else + newNode.Status = ObjectStatus.Rebuild; + } + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareUsers.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareUsers.cs new file mode 100644 index 0000000..1811380 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareUsers.cs @@ -0,0 +1,8 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareUsers : CompareBase + { + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareViews.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareViews.cs new file mode 100644 index 0000000..093bcbd --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareViews.cs @@ -0,0 +1,52 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareViews : CompareBase + { + protected override void DoUpdate(SchemaList originFields, View node) + { + View original = originFields[node.FullName]; + if (!node.Compare(original)) + { + View newNode = (View)node.Clone(originFields.Parent); + newNode.DependenciesOut.AddRange(original.DependenciesOut); + newNode.DependenciesIn.AddRange(original.DependenciesIn); + + newNode.Status = ObjectStatus.Alter; + newNode.Indexes = original.Indexes; + newNode.Triggers = original.Triggers; + + if (newNode.IsSchemaBinding) + newNode.Status += (int)ObjectStatus.RebuildDependencies; + if (newNode.HasToRebuild) + newNode.Status += (int)ObjectStatus.Rebuild; + else + newNode.Status += (int)ObjectStatus.AlterBody; + + originFields[node.FullName] = newNode; + original = newNode; + } + (new CompareIndexes()).GenerateDifferences(original.Indexes, node.Indexes); + (new CompareTriggers()).GenerateDifferences(original.Triggers, node.Triggers); + } + + protected override void DoNew(SchemaList originFields, View node) + { + View newNode = (View)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + newNode.DependenciesIn.ForEach(dep => + { + ISchemaBase item = ((Database)((ISchemaBase)originFields.Parent)).Find(dep); + if (item != null) + { + if (item.IsCodeType) + ((ICode)item).DependenciesOut.Add(newNode.FullName); + } + } + ); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareXMLSchemas.cs b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareXMLSchemas.cs new file mode 100644 index 0000000..afa0498 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Compare/CompareXMLSchemas.cs @@ -0,0 +1,18 @@ +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Compare +{ + internal class CompareXMLSchemas : CompareBase + { + protected override void DoUpdate(SchemaList originFields, XMLSchema node) + { + if (!node.Compare(originFields[node.FullName])) + { + XMLSchema newNode = node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/Generate.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/Generate.cs new file mode 100644 index 0000000..367450a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/Generate.cs @@ -0,0 +1,191 @@ +using OpenDBDiff.Schema.Errors; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.Misc; +using OpenDBDiff.Schema.SQLServer.Generates.Compare; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Options; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class Generate + { + private readonly List messages; + private ProgressEventArgs currentlyReading; + + public Generate() + { + messages = new List(); + OnReading += Generate_OnReading; + } + + public static int MaxValue + { + get { return Constants.READING_MAX; } + } + + public string ConnectionString { get; set; } + + private string Name + { + get + { + string name; + using (var conn = new SqlConnection(ConnectionString)) + { + name = conn.Database; + } + return name; + } + } + + public SqlOption Options { get; set; } + + private event ProgressEventHandler.ProgressHandler OnReading; + + public event ProgressEventHandler.ProgressHandler OnProgress; + + private void Generate_OnReading(ProgressEventArgs e) + { + if (OnProgress != null) OnProgress(e); + } + + public void RaiseOnReading(ProgressEventArgs e) + { + this.currentlyReading = e; + if (OnReading != null) OnReading(e); + } + + public void RaiseOnReadingOne(object name) + { + if (name != null && this.OnReading != null && this.currentlyReading != null) + { + var eOne = new ProgressEventArgs(this.currentlyReading.Message, this.currentlyReading.Progress); + eOne.Message = eOne.Message.Replace("...", String.Format(": [{0}]", name)); + this.OnReading(eOne); + } + } + + /// + /// Genera el schema de la base de datos seleccionada y devuelve un objeto Database. + /// + public Database Process() + { + string error = ""; + var databaseSchema = new Database(); + + //tables.OnTableProgress += new Progress.ProgressHandler(tables_OnTableProgress); + databaseSchema.Options = Options; + databaseSchema.Name = Name; + databaseSchema.Info = (new GenerateDatabase(ConnectionString, Options)).Get(databaseSchema); + /*Thread t1 = new Thread(delegate() + { + try + {*/ + (new GenerateRules(this)).Fill(databaseSchema, ConnectionString); + (new GenerateTables(this)).Fill(databaseSchema, ConnectionString, messages); + (new GenerateViews(this)).Fill(databaseSchema, ConnectionString, messages); + + if (Options.Ignore.FilterIndex) + { + (new GenerateIndex(this)).Fill(databaseSchema, ConnectionString); + (new GenerateFullTextIndex(this)).Fill(databaseSchema, ConnectionString); + } + (new GenerateUserDataTypes(this)).Fill(databaseSchema, ConnectionString, messages); + (new GenerateXMLSchemas(this)).Fill(databaseSchema, ConnectionString); + (new GenerateSchemas(this)).Fill(databaseSchema, ConnectionString); + /*} + catch (Exception ex) + { + error = ex.StackTrace; + } + }); + Thread t2 = new Thread(delegate() + { + try + {*/ + + //not supported in azure yet + if (databaseSchema.Info.Version != DatabaseInfo.SQLServerVersion.SQLServerAzure10) + { + (new GeneratePartitionFunctions(this)).Fill(databaseSchema, ConnectionString); + (new GeneratePartitionScheme(this)).Fill(databaseSchema, ConnectionString); + (new GenerateFileGroups(this)).Fill(databaseSchema, ConnectionString); + } + + (new GenerateDDLTriggers(this)).Fill(databaseSchema, ConnectionString); + (new GenerateSynonyms(this)).Fill(databaseSchema, ConnectionString); + + //not supported in azure yet + if (databaseSchema.Info.Version != DatabaseInfo.SQLServerVersion.SQLServerAzure10) + { + (new GenerateAssemblies(this)).Fill(databaseSchema, ConnectionString); + (new GenerateFullText(this)).Fill(databaseSchema, ConnectionString); + } + /*} + catch (Exception ex) + { + error = ex.StackTrace; + } + }); + Thread t3 = new Thread(delegate() + { + try + {*/ + (new GenerateStoredProcedures(this)).Fill(databaseSchema, ConnectionString); + (new GenerateFunctions(this)).Fill(databaseSchema, ConnectionString); + (new GenerateTriggers(this)).Fill(databaseSchema, ConnectionString, messages); + (new GenerateTextObjects(this)).Fill(databaseSchema, ConnectionString); + (new GenerateUsers(this)).Fill(databaseSchema, ConnectionString); + /*} + catch (Exception ex) + { + error = ex.StackTrace; + } + }); + t1.Start(); + t2.Start(); + t3.Start(); + t1.Join(); + t2.Join(); + t3.Join();*/ + if (String.IsNullOrEmpty(error)) + { + /*Las propiedades extendidas deben ir despues de haber capturado el resto de los objetos de la base*/ + (new GenerateExtendedProperties(this)).Fill(databaseSchema, ConnectionString, messages); + databaseSchema.BuildDependency(); + return databaseSchema; + } + else + throw new SchemaException(error); + } + + private void tables_OnTableProgress(object sender, ProgressEventArgs e) + { + ProgressEventHandler.RaiseOnChange(e); + } + + // TODO: Static because Compare method is static; static events are not my favorite + public static event ProgressEventHandler.ProgressHandler OnCompareProgress; + + internal static void RaiseOnCompareProgress(string formatString, params object[] formatParams) + { + OnCompareProgress?.Invoke(new ProgressEventArgs(String.Format(formatString, formatParams), -1)); + } + + /// + /// Generates the differences to migrate a schema from origin to destination + /// + /// The Origin schema is the schema before our generated actions are applied. + /// The Destination schema is the schema after our actions are applied. + /// + public static Database Compare(Database origin, Database destination) + { + Database merge = CompareDatabase.GenerateDifferences(origin, destination); + return merge; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateAssemblies.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateAssemblies.cs new file mode 100644 index 0000000..ad84fda --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateAssemblies.cs @@ -0,0 +1,103 @@ +using System; +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateAssemblies + { + private Generate root; + + public GenerateAssemblies(Generate root) + { + this.root = root; + } + + private static string GetSQLFiles() + { + return SQLQueries.SQLQueryFactory.Get("GetAssemblyFiles"); + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetAssemblies"); + } + + private static string ToHex(byte[] stream) + { + return ByteToHexEncoder.ByteArrayToHex(stream); + } + + private static void FillFiles(Database database, string connectionString) + { + if (database.Options.Ignore.FilterAssemblies) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLFiles(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + if (((int)reader["FileId"]) != 1) + { + Assembly assem = database.Assemblies[reader["Name"].ToString()]; + AssemblyFile file = new AssemblyFile(assem, reader["FileName"].ToString(), ToHex((byte[])reader["FileContent"])); + assem.Files.Add(file); + } + } + } + } + } + } + } + public void Fill(Database database, string connectionString) + { + int lastViewId = 0; + if (database.Options.Ignore.FilterAssemblies) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Assembly item = null; + while (reader.Read()) + { + if (lastViewId != (int)reader["assembly_id"]) + { + item = new Assembly(database) + { + Id = (int)reader["assembly_id"], + Name = reader["Name"].ToString(), + Owner = reader["Owner"].ToString(), + CLRName = reader["clr_name"].ToString(), + PermissionSet = reader["permission_set_desc"].ToString(), + Text = ToHex((byte[])reader["content"]), + Visible = (bool)reader["is_visible"] + }; + lastViewId = item.Id; + database.Assemblies.Add(item); + } + if (!String.IsNullOrEmpty(reader["Dependency"].ToString())) + item.DependenciesOut.Add(reader["Dependency"].ToString()); + if (!String.IsNullOrEmpty(reader["ObjectDependency"].ToString())) + item.DependenciesOut.Add(reader["ObjectDependency"].ToString()); + if (!String.IsNullOrEmpty(reader["UDTName"].ToString())) + item.DependenciesOut.Add(reader["UDTName"].ToString()); + } + } + } + FillFiles(database, connectionString); + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateConstraint.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateConstraint.cs new file mode 100644 index 0000000..19858e1 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateConstraint.cs @@ -0,0 +1,303 @@ +using System; +using System.Data.SqlClient; +using System.Text; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateConstraint + { + private Generate root; + + public GenerateConstraint(Generate root) + { + this.root = root; + } + + #region Check Functions... + public void FillCheck(Database database, string connectionString) + { + int parentId = 0; + ISchemaBase table = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(ConstraintSQLCommand.GetCheck(database.Info.Version), conn)) + { + root.RaiseOnReading(new ProgressEventArgs("Reading constraint...", Constants.READING_CONSTRAINTS)); + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Constraint item = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + if (parentId != (int)reader["parent_object_id"]) + { + parentId = (int)reader["parent_object_id"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + table = database.Tables.Find(parentId); + else + table = database.TablesTypes.Find(parentId); + } + if (table != null) + { + item = new Constraint(table); + item.Id = (int)reader["id"]; + item.Name = reader["Name"].ToString(); + item.Type = Constraint.ConstraintType.Check; + item.Definition = reader["Definition"].ToString(); + item.WithNoCheck = (bool)reader["WithCheck"]; + item.IsDisabled = (bool)reader["is_disabled"]; + item.Owner = reader["Owner"].ToString(); + if (database.Options.Ignore.FilterNotForReplication) + item.NotForReplication = (bool)reader["is_not_for_replication"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + ((Table)table).Constraints.Add(item); + else + ((TableType)table).Constraints.Add(item); + } + } + } + } + } + } + + #endregion + + #region ForeignKey Functions... + + private static string GetSQLForeignKey() + { + return SQLQueries.SQLQueryFactory.Get("GetForeignKeys"); + } + + private static void FillForeignKey(Database database, string connectionString) + { + int lastid = 0; + int parentId = 0; + Table table = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLForeignKey(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Constraint con = null; + while (reader.Read()) + { + if (parentId != (int)reader["parent_object_id"]) + { + parentId = (int)reader["parent_object_id"]; + table = database.Tables.Find(parentId); + } + + if (table != null) + { + if (lastid != (int)reader["object_id"]) + { + con = new Constraint(table); + con.Id = (int)reader["object_id"]; + con.Name = reader["Name"].ToString(); + con.Type = Constraint.ConstraintType.ForeignKey; + con.WithNoCheck = (bool)reader["is_not_trusted"]; + con.RelationalTableFullName = "[" + reader["ReferenceOwner"].ToString() + "].[" + reader["TableRelationalName"].ToString() + "]"; + con.RelationalTableId = (int)reader["TableRelationalId"]; + con.Owner = reader["Owner"].ToString(); + con.IsDisabled = (bool)reader["is_disabled"]; + con.OnDeleteCascade = (byte)reader["delete_referential_action"]; + con.OnUpdateCascade = (byte)reader["update_referential_action"]; + if (database.Options.Ignore.FilterNotForReplication) + con.NotForReplication = (bool)reader["is_not_for_replication"]; + lastid = (int)reader["object_id"]; + table.Constraints.Add(con); + } + ConstraintColumn ccon = new ConstraintColumn(con); + ccon.Name = reader["ColumnName"].ToString(); + ccon.ColumnRelationalName = reader["ColumnRelationalName"].ToString(); + ccon.ColumnRelationalId = (int)reader["ColumnRelationalId"]; + ccon.Id = (int)reader["ColumnId"]; + ccon.KeyOrder = con.Columns.Count; + ccon.ColumnRelationalDataTypeId = (int)reader["user_type_id"]; + //table.DependenciesCount++; + con.Columns.Add(ccon); + } + } + } + } + } + } + #endregion + + #region UniqueKey Functions... + private static void FillUniqueKey(Database database, string connectionString) + { + int lastId = 0; + int parentId = 0; + bool change = false; + ISchemaBase table = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(ConstraintSQLCommand.GetUniqueKey(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Constraint con = null; + while (reader.Read()) + { + if (parentId != (int)reader["ID"]) + { + parentId = (int)reader["ID"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + table = database.Tables.Find(parentId); + else + table = database.TablesTypes.Find(parentId); + change = true; + } + else + change = false; + + if (table != null) + { + if ((lastId != (int)reader["Index_id"]) || (change)) + { + con = new Constraint(table); + con.Name = reader["Name"].ToString(); + con.Owner = (string)reader["Owner"]; + con.Id = (int)reader["Index_id"]; + con.Type = Constraint.ConstraintType.Unique; + con.Index.Id = (int)reader["Index_id"]; + con.Index.AllowPageLocks = (bool)reader["allow_page_locks"]; + con.Index.AllowRowLocks = (bool)reader["allow_row_locks"]; + con.Index.FillFactor = (byte)reader["fill_factor"]; + con.Index.IgnoreDupKey = (bool)reader["ignore_dup_key"]; + con.Index.IsAutoStatistics = (bool)reader["ignore_dup_key"]; + con.Index.IsDisabled = (bool)reader["is_disabled"]; + con.Index.IsPadded = (bool)reader["is_padded"]; + con.Index.IsPrimaryKey = false; + con.Index.IsUniqueKey = true; + con.Index.Type = (Index.IndexTypeEnum)(byte)reader["type"]; + con.Index.Name = con.Name; + if (database.Options.Ignore.FilterTableFileGroup) + con.Index.FileGroup = reader["FileGroup"].ToString(); + lastId = (int)reader["Index_id"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + ((Table)table).Constraints.Add(con); + else + ((TableType)table).Constraints.Add(con); + } + ConstraintColumn ccon = new ConstraintColumn(con); + ccon.Name = reader["ColumnName"].ToString(); + ccon.IsIncluded = (bool)reader["is_included_column"]; + ccon.Order = (bool)reader["is_descending_key"]; + ccon.Id = (int)reader["column_id"]; + ccon.DataTypeId = (int)reader["user_type_id"]; + con.Columns.Add(ccon); + } + } + } + } + } + } + #endregion + + #region PrimaryKey Functions... + private static void FillPrimaryKey(Database database, string connectionString) + { + int lastId = 0; + int parentId = 0; + bool change = false; + ISchemaBase table = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(ConstraintSQLCommand.GetPrimaryKey(database.Info.Version, null), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Constraint con = null; + while (reader.Read()) + { + if (parentId != (int)reader["ID"]) + { + parentId = (int)reader["ID"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + table = database.Tables.Find(parentId); + else + table = database.TablesTypes.Find(parentId); + change = true; + } + else + change = false; + + if (table != null) + { + if ((lastId != (int)reader["Index_id"]) || (change)) + { + con = new Constraint(table); + con.Id = (int)reader["Index_id"]; + con.Name = (string)reader["Name"]; + con.Owner = (string)reader["Owner"]; + con.Type = Constraint.ConstraintType.PrimaryKey; + con.Index.Id = (int)reader["Index_id"]; + con.Index.AllowPageLocks = (bool)reader["allow_page_locks"]; + con.Index.AllowRowLocks = (bool)reader["allow_row_locks"]; + con.Index.FillFactor = (byte)reader["fill_factor"]; + con.Index.IgnoreDupKey = (bool)reader["ignore_dup_key"]; + con.Index.IsAutoStatistics = (bool)reader["ignore_dup_key"]; + con.Index.IsDisabled = (bool)reader["is_disabled"]; + con.Index.IsPadded = (bool)reader["is_padded"]; + con.Index.IsPrimaryKey = true; + con.Index.IsUniqueKey = false; + con.Index.Type = (Index.IndexTypeEnum)(byte)reader["type"]; + con.Index.Name = con.Name; + if (database.Options.Ignore.FilterTableFileGroup) + con.Index.FileGroup = reader["FileGroup"].ToString(); + lastId = (int)reader["Index_id"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + ((Table)table).Constraints.Add(con); + else + ((TableType)table).Constraints.Add(con); + } + ConstraintColumn ccon = new ConstraintColumn(con); + ccon.Name = (string)reader["ColumnName"]; + ccon.IsIncluded = (bool)reader["is_included_column"]; + ccon.Order = (bool)reader["is_descending_key"]; + ccon.KeyOrder = (byte)reader["key_ordinal"]; + ccon.Id = (int)reader["column_id"]; + ccon.DataTypeId = (int)reader["user_type_id"]; + con.Columns.Add(ccon); + } + } + } + } + } + } + #endregion + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterConstraintPK) + FillPrimaryKey(database, connectionString); + if (database.Options.Ignore.FilterConstraintFK) + FillForeignKey(database, connectionString); + if (database.Options.Ignore.FilterConstraintUK) + FillUniqueKey(database, connectionString); + if (database.Options.Ignore.FilterConstraintCheck) + FillCheck(database, connectionString); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateDDLTriggers.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateDDLTriggers.cs new file mode 100644 index 0000000..874f851 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateDDLTriggers.cs @@ -0,0 +1,50 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateDDLTriggers + { + private Generate root; + + public GenerateDDLTriggers(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetDDLTriggers"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterDDLTriggers) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + conn.Open(); + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Trigger trigger = new Trigger(database); + trigger.Text = reader["Text"].ToString(); + trigger.Name = reader["Name"].ToString(); + trigger.InsteadOf = (bool)reader["is_instead_of_trigger"]; + trigger.IsDisabled = (bool)reader["is_disabled"]; + trigger.IsDDLTrigger = true; + trigger.NotForReplication = (bool)reader["is_not_for_replication"]; + trigger.Owner = ""; + database.DDLTriggers.Add(trigger); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateDatabase.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateDatabase.cs new file mode 100644 index 0000000..cd789ef --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateDatabase.cs @@ -0,0 +1,97 @@ +using System; +using System.Data.SqlClient; +using System.Globalization; +using OpenDBDiff.Schema.Misc; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Options; +#if DEBUG +using System.Runtime.InteropServices; +#endif + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateDatabase + { + private string connectioString; + private SqlOption objectFilter; + + public bool UseDefaultVersionOnVersionParseError { get; private set; } + + /// + /// Constructor de la clase. + /// + /// Connection string de la base + public GenerateDatabase(string connectioString, SqlOption filter) + { + this.connectioString = connectioString; + this.objectFilter = filter; + } + + public DatabaseInfo Get(Database database) + { + DatabaseInfo item = new DatabaseInfo(); + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(DatabaseSQLCommand.GetVersion(database), conn)) + { + conn.Open(); + + item.Server = conn.DataSource; + item.Database = conn.Database; + + using (SqlDataReader reader = command.ExecuteReader()) + { + if (reader.Read()) + { + string versionValue = reader["Version"] as string; + try + { + // used to use the decimal as well when Azure was 10.25 + var version = new Version(versionValue); + item.VersionNumber = float.Parse(String.Format("{0}.{1}", version.Major, version.Minor), CultureInfo.InvariantCulture); + + if (reader.FieldCount > 1 && !reader.IsDBNull(1)) + { + int edition; + if (int.TryParse(reader[1].ToString(), out edition) + && Enum.IsDefined(typeof(DatabaseInfo.SQLServerEdition), edition)) + { + item.SetEdition((DatabaseInfo.SQLServerEdition)edition); + } + } + + } + catch (Exception notAGoodIdeaToCatchAllErrors) + { + var exception = new SchemaException( + String.Format("Error parsing ProductVersion. ({0})", versionValue ?? "[null]") + , notAGoodIdeaToCatchAllErrors); + + if (!UseDefaultVersionOnVersionParseError) + { + throw exception; + } + } + } + } + } + + using (SqlCommand command = new SqlCommand(DatabaseSQLCommand.Get(item.Version, item.Edition, database), conn)) + { + using (SqlDataReader reader = command.ExecuteReader()) + { + if (reader.Read()) + { + item.Collation = reader["Collation"].ToString(); + item.HasFullTextEnabled = ((int)reader["IsFulltextEnabled"]) == 1; + } + } + } + + } + + return item; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateDefaults.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateDefaults.cs new file mode 100644 index 0000000..ae4b03b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateDefaults.cs @@ -0,0 +1,46 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateDefaults + { + private Generate root; + + public GenerateDefaults(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetDefaults"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterRules) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Default item = new Default(database); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["Owner"].ToString(); + item.Value = reader["Definition"].ToString(); + database.Defaults.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateExtendedProperties.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateExtendedProperties.cs new file mode 100644 index 0000000..b22b4ae --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateExtendedProperties.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using OpenDBDiff.Schema.Errors; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateExtendedProperties + { + private Generate root; + + public GenerateExtendedProperties(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetExtendedProperties"); + } + + private static string GetTypeDescription(string type) + { + if (type.Equals("PC")) return "PROCEDURE"; + if (type.Equals("P")) return "PROCEDURE"; + if (type.Equals("V")) return "VIEW"; + if (type.Equals("U")) return "TABLE"; + if (type.Equals("TR")) return "TRIGGER"; + if (type.Equals("TA")) return "TRIGGER"; + if (type.Equals("FS")) return "FUNCTION"; + if (type.Equals("FN")) return "FUNCTION"; + if (type.Equals("IF")) return "FUNCTION"; + if (type.Equals("TF")) return "FUNCTION"; + return ""; + } + + public void Fill(Database database, string connectionString, List messages) + { + ISQLServerSchemaBase parent; + try + { + if (database.Options.Ignore.FilterExtendedProperties) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + ExtendedProperty item = new ExtendedProperty(null); + if (((byte)reader["Class"]) == 5) + { + item.Level0type = "ASSEMBLY"; + item.Level0name = reader["AssemblyName"].ToString(); + } + if (((byte)reader["Class"]) == 1) + { + string ObjectType = GetTypeDescription(reader["type"].ToString().Trim()); + item.Level0type = "SCHEMA"; + item.Level0name = reader["Owner"].ToString(); + if (!ObjectType.Equals("TRIGGER")) + { + item.Level1name = reader["ObjectName"].ToString(); + item.Level1type = ObjectType; + } + else + { + item.Level1type = "TABLE"; + item.Level1name = reader["ParentName"].ToString(); + item.Level2name = reader["ObjectName"].ToString(); + item.Level2type = ObjectType; + } + } + if (((byte)reader["Class"]) == 6) + { + item.Level0type = "SCHEMA"; + item.Level0name = reader["OwnerType"].ToString(); + item.Level1name = reader["TypeName"].ToString(); + item.Level1type = "TYPE"; + } + if (((byte)reader["Class"]) == 7) + { + item.Level0type = "SCHEMA"; + item.Level0name = reader["Owner"].ToString(); + item.Level1type = "TABLE"; + item.Level1name = reader["ObjectName"].ToString(); + item.Level2type = reader["class_desc"].ToString(); + item.Level2name = reader["IndexName"].ToString(); + } + item.Value = reader["Value"].ToString(); + item.Name = reader["Name"].ToString(); + parent = ((ISQLServerSchemaBase)database.Find(item.FullName)); + if (parent != null) + { + item.Parent = (ISchemaBase)parent; + parent.ExtendedProperties.Add(item); + } + else + messages.Add(new MessageLog(item.FullName + " not found in extended properties.", "", MessageLog.LogType.Error)); + } + } + } + } + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFileGroups.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFileGroups.cs new file mode 100644 index 0000000..a727562 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFileGroups.cs @@ -0,0 +1,92 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateFileGroups + { + private Generate root; + + public GenerateFileGroups(Generate root) + { + this.root = root; + } + + private static string GetSQLFile(FileGroup filegroup) + { + string query = SQLQueries.SQLQueryFactory.Get("GetDatabaseFile"); + + return query.Replace("{ID}", filegroup.Id.ToString()); + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetFileGroups"); + } + + private static void FillFiles(FileGroup filegroup, string connectionString) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLFile(filegroup), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + FileGroupFile item = new FileGroupFile(filegroup); + item.Id = (int)reader["file_id"]; + item.Name = reader["name"].ToString(); + item.Owner = ""; + item.Growth = (int)reader["growth"]; + item.IsPercentGrowth = (bool)reader["is_percent_growth"]; + item.IsSparse = (bool)reader["is_sparse"]; + item.MaxSize = (int)reader["max_size"]; + item.PhysicalName = reader["physical_name"].ToString(); + item.Size = (int)reader["size"]; + item.Type = (byte)reader["type"]; + filegroup.Files.Add(item); + } + } + } + } + } + + public void Fill(Database database, string connectionString) + { + try + { + if (database.Options.Ignore.FilterTableFileGroup) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + FileGroup item = new FileGroup(database); + item.Id = (int)reader["ID"]; + item.Name = reader["name"].ToString(); + item.Owner = ""; + item.IsDefaultFileGroup = (bool)reader["is_default"]; + item.IsReadOnly = (bool)reader["is_read_only"]; + item.IsFileStream = reader["type"].Equals("FD"); + FillFiles(item, connectionString); + database.FileGroups.Add(item); + } + } + } + } + } + } + catch + { + throw; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFullText.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFullText.cs new file mode 100644 index 0000000..b25cc03 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFullText.cs @@ -0,0 +1,51 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateFullText + { + private Generate root; + + public GenerateFullText(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetFullTextCatalogs"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterFullText) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + FullText item = new FullText(database); + item.Id = (int)reader["fulltext_catalog_id"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["Owner"].ToString(); + item.IsAccentSensity = (bool)reader["is_accent_sensitivity_on"]; + item.IsDefault = (bool)reader["is_default"]; + if (!reader.IsDBNull(reader.GetOrdinal("path"))) + item.Path = reader["path"].ToString().Substring(0, reader["path"].ToString().Length - item.Name.Length); + if (!reader.IsDBNull(reader.GetOrdinal("FileGroupName"))) + item.FileGroupName = reader["FileGroupName"].ToString(); + database.FullText.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFullTextIndex.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFullTextIndex.cs new file mode 100644 index 0000000..d306588 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFullTextIndex.cs @@ -0,0 +1,70 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateFullTextIndex + { + private Generate root; + + public GenerateFullTextIndex(Generate root) + { + this.root = root; + } + + public void Fill(Database database, string connectionString) + { + //not supported in azure yet + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) return; + + int parentId = 0; + bool change = false; + Table parent = null; + root.RaiseOnReading(new ProgressEventArgs("Reading FullText Index...", Constants.READING_INDEXES)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(FullTextIndexSQLCommand.Get(database.Info.Version), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + FullTextIndex item = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + if (parentId != (int)reader["object_id"]) + { + parentId = (int)reader["object_id"]; + parent = database.Tables.Find(parentId); + change = true; + } + else + change = false; + if (change) + { + item = new FullTextIndex(parent); + item.Name = reader["Name"].ToString(); + item.Owner = parent.Owner; + item.FullText = reader["FullTextCatalogName"].ToString(); + item.Index = reader["IndexName"].ToString(); + item.IsDisabled = !(bool)reader["is_enabled"]; + item.ChangeTrackingState = reader["ChangeTracking"].ToString(); + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + item.FileGroup = reader["FileGroupName"].ToString(); + ((Table)parent).FullTextIndex.Add(item); + } + FullTextIndexColumn ccon = new FullTextIndexColumn(); + ccon.ColumnName = reader["ColumnName"].ToString(); + ccon.Language = reader["LanguageName"].ToString(); + item.Columns.Add(ccon); + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFunctions.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFunctions.cs new file mode 100644 index 0000000..6e3d44c --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateFunctions.cs @@ -0,0 +1,138 @@ +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System; +using System.Data.SqlClient; +using System.Linq; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateFunctions + { + private Generate root; + + public GenerateFunctions(Generate root) + { + this.root = root; + } + + private static string GetSQLParameters() + { + return SQLQueries.SQLQueryFactory.Get("GetParameters"); + } + + private static void FillParameters(Database database, string connectionString) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLParameters(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + var objectName = reader["ObjectName"].ToString(); + + if (database.CLRFunctions.Contains(objectName)) + { + Parameter param = new Parameter(); + param.Name = reader["Name"].ToString(); + param.Type = reader["TypeName"].ToString(); + param.Size = (short)reader["max_length"]; + param.Scale = (byte)reader["scale"]; + param.Precision = (byte)reader["precision"]; + param.Output = (bool)reader["is_output"]; + if (param.Type.Equals("nchar") || param.Type.Equals("nvarchar")) + { + if (param.Size != -1) + param.Size = param.Size / 2; + } + database.CLRFunctions[objectName].Parameters.Add(param); + } + } + } + } + } + } + + public void Fill(Database database, string connectionString) + { + int lastViewId = 0; + if ((database.Options.Ignore.FilterFunction) || (database.Options.Ignore.FilterCLRFunction)) + { + root.RaiseOnReading(new ProgressEventArgs("Reading functions...", Constants.READING_FUNCTIONS)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(FunctionSQLCommand.Get(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Function itemF = null; + CLRFunction itemC = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["name"]); + if ((!reader["type"].ToString().Trim().Equals("FS")) && (database.Options.Ignore.FilterFunction)) + { + if (lastViewId != (int)reader["object_id"]) + { + itemF = new Function(database); + itemF.Id = (int)reader["object_id"]; + itemF.Name = reader["name"].ToString(); + itemF.Owner = reader["owner"].ToString(); + itemF.IsSchemaBinding = reader["IsSchemaBound"].ToString().Equals("1"); + database.Functions.Add(itemF); + lastViewId = itemF.Id; + } + if (itemF.IsSchemaBinding) + { + if (!reader.IsDBNull(reader.GetOrdinal("referenced_major_id"))) + database.Dependencies.Add(database, (int)reader["referenced_major_id"], itemF); + if (!String.IsNullOrEmpty(reader["TableName"].ToString())) + itemF.DependenciesIn.Add(reader["TableName"].ToString()); + if (!String.IsNullOrEmpty(reader["DependOut"].ToString())) + itemF.DependenciesOut.Add(reader["DependOut"].ToString()); + } + } + if ((reader["type"].ToString().Trim().Equals("FS")) && (database.Options.Ignore.FilterCLRFunction)) + { + itemC = new CLRFunction(database); + if (lastViewId != (int)reader["object_id"]) + { + itemC.Id = (int)reader["object_id"]; + itemC.Name = reader["name"].ToString(); + itemC.Owner = reader["owner"].ToString(); + itemC.IsAssembly = true; + itemC.AssemblyId = (int)reader["assembly_id"]; + itemC.AssemblyName = reader["assembly_name"].ToString(); + itemC.AssemblyClass = reader["assembly_class"].ToString(); + itemC.AssemblyExecuteAs = reader["ExecuteAs"].ToString(); + itemC.AssemblyMethod = reader["assembly_method"].ToString(); + itemC.ReturnType.Type = reader["ReturnType"].ToString(); + itemC.ReturnType.Size = (short)reader["max_length"]; + itemC.ReturnType.Scale = (byte)reader["Scale"]; + itemC.ReturnType.Precision = (byte)reader["precision"]; + if (itemC.ReturnType.Type.Equals("nchar") || itemC.ReturnType.Type.Equals("nvarchar")) + { + if (itemC.ReturnType.Size != -1) + itemC.ReturnType.Size = itemC.ReturnType.Size / 2; + } + database.CLRFunctions.Add(itemC); + lastViewId = itemC.Id; + } + } + } + } + } + } + } + if (database.CLRFunctions.Any()) + FillParameters(database, connectionString); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateIndex.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateIndex.cs new file mode 100644 index 0000000..211242b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateIndex.cs @@ -0,0 +1,105 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateIndex + { + private Generate root; + + public GenerateIndex(Generate root) + { + this.root = root; + } + + public void Fill(Database database, string connectionString) + { + int indexid = 0; + int parentId = 0; + bool change = false; + string type; + ISchemaBase parent = null; + root.RaiseOnReading(new ProgressEventArgs("Reading Index...", Constants.READING_INDEXES)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(IndexSQLCommand.Get(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Index item = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + type = reader["ObjectType"].ToString().Trim(); + if (parentId != (int)reader["object_id"]) + { + parentId = (int)reader["object_id"]; + if (type.Equals("V")) + parent = database.Views.Find(parentId); + else + parent = database.Tables.Find(parentId); + change = true; + } + else + change = false; + + if (parent != null) + { + if (indexid != (int)reader["index_id"] || change) + { + item = new Index(parent); + item.Name = reader["Name"].ToString(); + item.Owner = parent.Owner; + item.Type = (Index.IndexTypeEnum)(byte)reader["type"]; + item.Id = (int)reader["index_id"]; + item.IgnoreDupKey = (bool)reader["ignore_dup_key"]; + item.IsAutoStatistics = (bool)reader["NoAutomaticRecomputation"]; + item.IsDisabled = (bool)reader["is_disabled"]; + item.IsPrimaryKey = (bool)reader["is_primary_key"]; + item.IsUniqueKey = (bool)reader["is_unique"]; + if (database.Options.Ignore.FilterIndexRowLock) + { + item.AllowPageLocks = (bool)reader["allow_page_locks"]; + item.AllowRowLocks = (bool)reader["allow_row_locks"]; + } + if (database.Options.Ignore.FilterIndexFillFactor) + { + item.FillFactor = (byte)reader["fill_factor"]; + item.IsPadded = (bool)reader["is_padded"]; + } + if ((database.Options.Ignore.FilterTableFileGroup) && (item.Type != Index.IndexTypeEnum.XML)) + item.FileGroup = reader["FileGroup"].ToString(); + + if ((database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) && (database.Options.Ignore.FilterIndexFilter)) + { + item.FilterDefintion = reader["FilterDefinition"].ToString(); + } + indexid = (int)reader["index_id"]; + if (type.Equals("V")) + ((View)parent).Indexes.Add(item); + else + ((Table)parent).Indexes.Add(item); + } + IndexColumn ccon = new IndexColumn(item.Parent); + ccon.Name = reader["ColumnName"].ToString(); + ccon.IsIncluded = (bool)reader["is_included_column"]; + ccon.Order = (bool)reader["is_descending_key"]; + ccon.Id = (int)reader["column_id"]; + ccon.KeyOrder = (byte)reader["key_ordinal"]; + ccon.DataTypeId = (int)reader["user_type_id"]; + if ((!ccon.IsIncluded) || (ccon.IsIncluded && database.Options.Ignore.FilterIndexIncludeColumns)) + item.Columns.Add(ccon); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GeneratePartitionFunctions.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GeneratePartitionFunctions.cs new file mode 100644 index 0000000..f3637dc --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GeneratePartitionFunctions.cs @@ -0,0 +1,84 @@ +using System; +using System.Data.SqlClient; +using System.Text; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GeneratePartitionFunctions + { + private Generate root; + + public GeneratePartitionFunctions(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetPartitionFunctions"); + } + + private static string ToHex(byte[] stream) + { + StringBuilder sHex = new StringBuilder(2 * stream.Length); + for (int i = 0; i < stream.Length; i++) + sHex.AppendFormat("{0:X2} ", stream[i]); + return "0x" + sHex.ToString().Replace(" ", String.Empty); + } + + public void Fill(Database database, string connectioString) + { + int lastObjectId = 0; + PartitionFunction item = null; + if (database.Options.Ignore.FilterPartitionFunction) + { + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + if (lastObjectId != (int)reader["function_id"]) + { + lastObjectId = (int)reader["function_id"]; + item = new PartitionFunction(database); + item.Id = (int)reader["function_id"]; + item.Name = reader["name"].ToString(); + item.IsBoundaryRight = (bool)reader["IsRight"]; + item.Precision = (byte)reader["precision"]; + item.Scale = (byte)reader["scale"]; + item.Size = (short)reader["max_length"]; + item.Type = reader["TypeName"].ToString(); + database.PartitionFunctions.Add(item); + } + + switch (item.Type) { + case "binary": + case "varbinary": + item.Values.Add(ToHex((byte[])reader["value"])); + break; + case "date": + item.Values.Add(String.Format("'{0:yyyy/MM/dd}'", (DateTime)reader["value"])); + break; + case "smalldatetime": + case "datetime": + item.Values.Add(String.Format("'{0:yyyy/MM/dd HH:mm:ss.fff}'", (DateTime)reader["value"])); + break; + default: + item.Values.Add(reader["value"].ToString()); + break; + } + + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GeneratePartitionScheme.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GeneratePartitionScheme.cs new file mode 100644 index 0000000..13c2baa --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GeneratePartitionScheme.cs @@ -0,0 +1,53 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GeneratePartitionScheme + { + private Generate root; + + public GeneratePartitionScheme(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetPartitionSchemes"); + } + + public void Fill(Database database, string connectioString) + { + int lastObjectId = 0; + PartitionScheme item = null; + if (database.Options.Ignore.FilterPartitionScheme) + { + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + if (lastObjectId != (int)reader["ID"]) + { + lastObjectId = (int)reader["ID"]; + item = new PartitionScheme(database); + item.Id = (int)reader["ID"]; + item.Name = reader["name"].ToString(); + item.PartitionFunction = reader["FunctionName"].ToString(); + database.PartitionSchemes.Add(item); + } + item.FileGroups.Add(reader["FileGroupName"].ToString()); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateRules.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateRules.cs new file mode 100644 index 0000000..abff5bd --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateRules.cs @@ -0,0 +1,46 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateRules + { + private Generate root; + + public GenerateRules(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetRules"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterRules) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Rule item = new Rule(database); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["Owner"].ToString(); + item.Text = reader["Definition"].ToString(); + database.Rules.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateSchemas.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateSchemas.cs new file mode 100644 index 0000000..afd139e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateSchemas.cs @@ -0,0 +1,46 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateSchemas + { + private Generate root; + + public GenerateSchemas(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetSchemas"); + } + + public void Fill(Database database, string connectioString) + { + if (database.Options.Ignore.FilterSchema) + { + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Model.Schema item = new Model.Schema(database); + item.Id = (int)reader["schema_id"]; + item.Name = reader["name"].ToString(); + item.Owner = reader["owner"].ToString(); + database.Schemas.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateStoredProcedures.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateStoredProcedures.cs new file mode 100644 index 0000000..d0df8e6 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateStoredProcedures.cs @@ -0,0 +1,145 @@ +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System.Data.SqlClient; +using System.Linq; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateStoredProcedures + { + private static int NameIndex = -1; + private static int object_idIndex = -1; + private static int ownerIndex = -1; + private static int typeIndex = -1; + + private Generate root; + + public GenerateStoredProcedures(Generate root) + { + this.root = root; + } + + private static void InitIndex(SqlDataReader reader) + { + if (NameIndex == -1) + { + object_idIndex = reader.GetOrdinal("object_id"); + NameIndex = reader.GetOrdinal("Name"); + ownerIndex = reader.GetOrdinal("owner"); + typeIndex = reader.GetOrdinal("type"); + } + } + + private static string GetSQLParameters() + { + return SQLQueries.SQLQueryFactory.Get("GetParameters"); + } + + private static string GetSQL(DatabaseInfo.SQLServerVersion version) + { + if (version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) + { + return SQLQueries.SQLQueryFactory.Get("GetProcedures", DatabaseInfo.SQLServerVersion.SQLServerAzure10); + } + else + { + return SQLQueries.SQLQueryFactory.Get("GetProcedures"); + } + } + + private static void FillParameters(Database database, string connectionString) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLParameters(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + var objectName = reader["ObjectName"].ToString(); + + if (database.CLRProcedures.Contains(objectName)) + { + Parameter param = new Parameter(); + param.Name = reader["Name"].ToString(); + param.Type = reader["TypeName"].ToString(); + param.Size = (short)reader["max_length"]; + param.Scale = (byte)reader["scale"]; + param.Precision = (byte)reader["precision"]; + param.Output = (bool)reader["is_output"]; + if (param.Type.Equals("nchar") || param.Type.Equals("nvarchar")) + { + if (param.Size != -1) + param.Size = param.Size / 2; + } + database.CLRProcedures[objectName].Parameters.Add(param); + } + } + } + } + } + } + + public void Fill(Database database, string connectionString) + { + if ((database.Options.Ignore.FilterStoredProcedure) || (database.Options.Ignore.FilterCLRStoredProcedure)) + { + root.RaiseOnReading(new ProgressEventArgs("Reading stored procedures...", Constants.READING_PROCEDURES)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(database.Info.Version), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + InitIndex(reader); + root.RaiseOnReadingOne(reader[NameIndex]); + + var objectType = reader[typeIndex].ToString().Trim(); + switch (objectType) + { + case "P": + if (database.Options.Ignore.FilterStoredProcedure) + { + StoredProcedure item = new StoredProcedure(database); + item.Id = (int)reader[object_idIndex]; + item.Name = (string)reader[NameIndex]; + item.Owner = (string)reader[ownerIndex]; + database.Procedures.Add(item); + } + break; + + case "PC": + if (database.Options.Ignore.FilterCLRStoredProcedure) + { + CLRStoredProcedure item = new CLRStoredProcedure(database); + item.Id = (int)reader[object_idIndex]; + item.Name = reader[NameIndex].ToString(); + item.Owner = reader[ownerIndex].ToString(); + item.IsAssembly = true; + item.AssemblyId = (int)reader["assembly_id"]; + item.AssemblyName = reader["assembly_name"].ToString(); + item.AssemblyClass = reader["assembly_class"].ToString(); + item.AssemblyExecuteAs = reader["ExecuteAs"].ToString(); + item.AssemblyMethod = reader["assembly_method"].ToString(); + database.CLRProcedures.Add(item); + } + break; + } + } + } + } + } + if (database.CLRProcedures.Any()) + FillParameters(database, connectionString); + } + } + } +} \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateSynonyms.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateSynonyms.cs new file mode 100644 index 0000000..26c4e27 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateSynonyms.cs @@ -0,0 +1,47 @@ +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateSynonyms + { + private Generate root; + + public GenerateSynonyms(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetSynonyms"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterSynonyms) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Synonym item = new Synonym(database); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["Owner"].ToString(); + item.Value = reader["base_object_name"].ToString(); + database.Synonyms.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateTables.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateTables.cs new file mode 100644 index 0000000..47b2aaa --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateTables.cs @@ -0,0 +1,313 @@ +using OpenDBDiff.Schema.Errors; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Globalization; +using System.Linq; +using Constraint = OpenDBDiff.Schema.SQLServer.Generates.Model.Constraint; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateTables + { + private int colIDIndex = -1; + private int colNameIndex = -1; + private int colFormulaIndex = -1; + private int colIsPersistedIndex = -1; + private int colIsComputedIndex = -1; + private int colNullableIndex = -1; + private int colXmlSchemaIndex = -1; + private int colIs_xml_documentIndex = -1; + private int colPrecisionIndex = -1; + private int colScaleIndex = -1; + private int colDataUserTypeIdIndex = -1; + private int colIsUserDefinedTypeIndex = -1; + private int colSizeIndex = -1; + private int colHasIndexIndex = -1; + private int colHasComputedFormulaIndex = -1; + private int colIsRowGuidIndex = -1; + private int colTypeIndex = -1; + private int colOwnerType = -1; + private int colis_sparseIndex = -1; + private int colIs_FileStream = -1; + private int colDefaultIdIndex = -1; + private int colDefaultNameIndex = -1; + private int colDefaultDefinitionIndex = -1; + private int colrule_object_idIndex = -1; + private int colIsIdentityReplIndex = -1; + private int colCollationIndex = -1; + private int colIsIdentityIndex = -1; + private int colIdentSeedIndex = -1; + private int colIdentIncrementIndex = -1; + private int TableIdIndex = -1; + private int TableNameIndex = -1; + private int TableOwnerIndex = -1; + private int TableHasChangeTracking = -1; + private int TableHasChangeTrackingTrackColumn = -1; + private int TableLockEscalation = -1; + private int Text_In_Row_limitIndex = -1; + private int HasClusteredIndexIndex = -1; + private int large_value_types_out_of_rowIndex = -1; + private int HasVarDecimalIndex = -1; + private int FileGroupIndex = -1; + private int FileGroupTextIndex = -1; + private int FileGroupStreamIndex = -1; + + private Generate root; + + public GenerateTables(Generate root) + { + this.root = root; + } + + private void InitTableIndex(Database database, IDataRecord reader) + { + if (reader == null) throw new ArgumentNullException("reader"); + if (TableIdIndex == -1) + { + TableIdIndex = reader.GetOrdinal("TableId"); + TableNameIndex = reader.GetOrdinal("TableName"); + TableOwnerIndex = reader.GetOrdinal("TableOwner"); + Text_In_Row_limitIndex = reader.GetOrdinal("Text_In_Row_limit"); + HasClusteredIndexIndex = reader.GetOrdinal("HasClusteredIndex"); + large_value_types_out_of_rowIndex = reader.GetOrdinal("large_value_types_out_of_row"); + HasVarDecimalIndex = reader.GetOrdinal("HasVarDecimal"); + FileGroupIndex = reader.GetOrdinal("FileGroup"); + FileGroupTextIndex = reader.GetOrdinal("FileGroupText"); + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + { + FileGroupStreamIndex = reader.GetOrdinal("FileGroupStream"); + TableHasChangeTracking = reader.GetOrdinal("HasChangeTracking"); + TableHasChangeTrackingTrackColumn = reader.GetOrdinal("HasChangeTrackingTrackColumn"); + TableLockEscalation = reader.GetOrdinal("lock_escalation_desc"); + } + } + } + + private void InitColIndex(Database database, IDataRecord reader) + { + if (reader == null) throw new ArgumentNullException("reader"); + if (colNameIndex == -1) + { + colIDIndex = reader.GetOrdinal("ID"); + colNameIndex = reader.GetOrdinal("Name"); + colFormulaIndex = reader.GetOrdinal("Formula"); + colIsPersistedIndex = reader.GetOrdinal("FormulaPersisted"); + colIsComputedIndex = reader.GetOrdinal("IsComputed"); + colNullableIndex = reader.GetOrdinal("IsNullable"); + colOwnerType = reader.GetOrdinal("OwnerType"); + colXmlSchemaIndex = reader.GetOrdinal("XmlSchema"); + colIs_xml_documentIndex = reader.GetOrdinal("Is_xml_document"); + colPrecisionIndex = reader.GetOrdinal("Precision"); + colScaleIndex = reader.GetOrdinal("Scale"); + colDataUserTypeIdIndex = reader.GetOrdinal("user_type_id"); + colIsUserDefinedTypeIndex = reader.GetOrdinal("is_user_defined"); + colSizeIndex = reader.GetOrdinal("Size"); + colHasIndexIndex = reader.GetOrdinal("HasIndex"); + colHasComputedFormulaIndex = reader.GetOrdinal("HasComputedFormula"); + colIsRowGuidIndex = reader.GetOrdinal("IsRowGuid"); + colTypeIndex = reader.GetOrdinal("Type"); + colDefaultIdIndex = reader.GetOrdinal("DefaultId"); + colDefaultNameIndex = reader.GetOrdinal("DefaultName"); + colDefaultDefinitionIndex = reader.GetOrdinal("DefaultDefinition"); + colrule_object_idIndex = reader.GetOrdinal("rule_object_id"); + colIsIdentityReplIndex = reader.GetOrdinal("IsIdentityRepl"); + colCollationIndex = reader.GetOrdinal("Collation"); + colIsIdentityIndex = reader.GetOrdinal("IsIdentity"); + colIdentSeedIndex = reader.GetOrdinal("IdentSeed"); + colIdentIncrementIndex = reader.GetOrdinal("IdentIncrement"); + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + { + colis_sparseIndex = reader.GetOrdinal("is_sparse"); + colIs_FileStream = reader.GetOrdinal("is_filestream"); + } + } + } + + private void FillColumn(ITable table, SqlDataReader reader) where T : ISchemaBase + { + Database database = (Database)table.Parent; + + InitColIndex(database, reader); + Column col = new Column((ISchemaBase)table); + col.Id = (int)reader[colIDIndex]; + if (database.Options.Ignore.FilterColumnOrder) + col.Position = table.Columns.Count + 1; + + if (database.Options.Ignore.FilterColumnCollation) + col.Collation = (string)reader[colCollationIndex]; + + if (database.Options.Ignore.FilterColumnIdentity) + { + col.IsIdentity = (bool)reader[colIsIdentityIndex]; + if ((col.IsIdentity) || (col.IsIdentityForReplication)) + { + if (!reader.IsDBNull(colIdentSeedIndex)) + col.IdentitySeed = (long)(decimal)reader[colIdentSeedIndex]; + else + col.IdentitySeed = 1; + + if (!reader.IsDBNull(colIdentIncrementIndex)) + col.IdentityIncrement = (int)(decimal)reader[colIdentIncrementIndex]; + else + col.IdentityIncrement = 1; + } + if (database.Options.Ignore.FilterNotForReplication) + col.IsIdentityForReplication = ((int)reader[colIsIdentityReplIndex] == 1); + } + col.Name = (string)reader[colNameIndex]; + col.Owner = table.Owner; + col.ComputedFormula = (string)reader[colFormulaIndex]; + col.IsPersisted = (bool)reader[colIsPersistedIndex]; + col.IsComputed = (bool)reader[colIsComputedIndex]; + col.IsNullable = (bool)reader[colNullableIndex]; + col.XmlSchema = reader[colXmlSchemaIndex].ToString(); + col.IsXmlDocument = (bool)reader[colIs_xml_documentIndex]; + col.Precision = (byte)reader[colPrecisionIndex]; + col.Scale = (byte)reader[colScaleIndex]; + col.DataUserTypeId = (int)reader[colDataUserTypeIdIndex]; + col.IsUserDefinedType = (bool)reader[colIsUserDefinedTypeIndex]; + if (!String.IsNullOrEmpty(reader[colSizeIndex].ToString())) + col.Size = (short)reader[colSizeIndex]; + col.HasIndexDependencies = ((int)reader[colHasIndexIndex] == 1); + col.HasComputedDependencies = ((int)reader[colHasComputedFormulaIndex] == 1); + col.IsRowGuid = (bool)reader[colIsRowGuidIndex]; + if (col.IsUserDefinedType) + col.Type = "[" + (string)reader[colOwnerType] + "].[" + (string)reader[colTypeIndex] + "]"; + else + col.Type = (string)reader[colTypeIndex]; + if (((Database)table.Parent).Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + { + col.IsSparse = (bool)reader[colis_sparseIndex]; + col.IsFileStream = (bool)reader[colIs_FileStream]; + } + if ((int)reader[colDefaultIdIndex] != 0) + { + col.DefaultConstraint = new ColumnConstraint(col) + { + Id = (int)reader[colDefaultIdIndex], + Owner = table.Owner, + Name = (string)reader[colDefaultNameIndex], + Type = Constraint.ConstraintType.Default, + Definition = (string)reader[colDefaultDefinitionIndex] + }; + } + if ((int)reader[colrule_object_idIndex] != 0) + col.Rule = ((Database)table.Parent).Rules.Find((int)reader[colrule_object_idIndex]); + table.Columns.Add(col); + } + + public void Fill(Database database, string connectionString, List messages) + { + try + { + root.RaiseOnReading(new ProgressEventArgs("Reading tables...", Constants.READING_TABLES)); + FillTables(database, connectionString); + if (database.Tables.Any() || database.TablesTypes.Any()) + { + if (database.Options.Ignore.FilterConstraint) + (new GenerateConstraint(root)).Fill(database, connectionString); + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + + private void FillTables(Database database, string connectionString) + { + int textInRow; + Boolean largeValues; + Boolean varDecimal; + int lastObjectId = 0; + bool isTable = true; + ISchemaBase item = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(TableSQLCommand.GetTableDetail(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + InitTableIndex(database, reader); + root.RaiseOnReadingOne(reader[TableNameIndex]); + if (lastObjectId != (int)reader[TableIdIndex]) + { + lastObjectId = (int)reader[TableIdIndex]; + isTable = reader["ObjectType"].ToString().Trim().Equals("U"); + if (isTable) + { + item = new Table(database); + item.Id = (int)reader[TableIdIndex]; + item.Name = (string)reader[TableNameIndex]; + item.Owner = (string)reader[TableOwnerIndex]; + ((Table)item).HasClusteredIndex = (int)reader[HasClusteredIndexIndex] == 1; + textInRow = (int)reader[Text_In_Row_limitIndex]; + largeValues = (Boolean)reader[large_value_types_out_of_rowIndex]; + varDecimal = ((int)reader[HasVarDecimalIndex]) == 1; + if (database.Options.Ignore.FilterTableFileGroup) + { + ((Table)item).FileGroup = (string)reader[FileGroupIndex]; + ((Table)item).FileGroupText = (string)reader[FileGroupTextIndex]; + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + { + if (database.Options.Ignore.FilterTableChangeTracking) + { + ((Table)item).FileGroupStream = (string)reader[FileGroupStreamIndex]; + ((Table)item).HasChangeTracking = ((int)reader[TableHasChangeTracking]) == 1; + ((Table)item).HasChangeTrackingTrackColumn = ((int)reader[TableHasChangeTrackingTrackColumn]) == 1; + } + } + } + if (database.Options.Ignore.FilterTableOption) + { + if (textInRow > 0) ((Table)item).Options.Add(new TableOption("TextInRow", textInRow.ToString(CultureInfo.InvariantCulture), item)); + if (largeValues) ((Table)item).Options.Add(new TableOption("LargeValues", "1", item)); + if (varDecimal) ((Table)item).Options.Add(new TableOption("VarDecimal", "1", item)); + } + if ((database.Options.Ignore.FilterTableLockEscalation) && (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008)) + ((Table)item).Options.Add(new TableOption("LockEscalation", (string)reader[TableLockEscalation], item)); + else + ((Table)item).Options.Add(new TableOption("LockEscalation", "TABLE", item)); + database.Tables.Add((Table)item); + } + else + { + item = new TableType(database) + { + Id = (int)reader[TableIdIndex], + Name = (string)reader[TableNameIndex], + Owner = (string)reader[TableOwnerIndex] + }; + database.TablesTypes.Add((TableType)item); + } + } + if (isTable) + { + if (database.Options.Ignore.FilterTable) + FillColumn((ITable
)item, reader); + } + else + { + if (database.Options.Ignore.FilterUserDataType) + FillColumn((ITable)item, reader); + } + } + } + } + } + //tables.ToSQL(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateTextObjects.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateTextObjects.cs new file mode 100644 index 0000000..e779111 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateTextObjects.cs @@ -0,0 +1,120 @@ +using System; +using System.Data.SqlClient; +using System.Text.RegularExpressions; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Options; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateTextObjects + { + private Generate root; + + public GenerateTextObjects(Generate root) + { + this.root = root; + } + + private static string GetSQL(SqlOption options) + { + var filterQuery = SQLQueries.SQLQueryFactory.Get("GetTextObjectsQuery"); + string filter = ""; + if (options.Ignore.FilterStoredProcedure) + filter += "O.type = 'P' OR "; + if (options.Ignore.FilterView) + filter += "O.type = 'V' OR "; + if (options.Ignore.FilterTrigger) + filter += "O.type = 'TR' OR "; + if (options.Ignore.FilterFunction) + filter += "O.type IN ('IF','FN','TF') OR "; + filter = filter.Substring(0, filter.Length - 4); + return filterQuery.Replace("{FILTER}", filter); + } + + public void Fill(Database database, string connectionString) + { + ICode code = null; + try + { + if ((database.Options.Ignore.FilterStoredProcedure) || (database.Options.Ignore.FilterView) || (database.Options.Ignore.FilterFunction) || (database.Options.Ignore.FilterTrigger)) + { + root.RaiseOnReading(new ProgressEventArgs("Reading Text Objects...", Constants.READING_TEXTOBJECTS)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(database.Options), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + code = null; + root.RaiseOnReadingOne(reader["name"]); + string type = reader["Type"].ToString().Trim(); + string name = reader["name"].ToString(); + string definition = reader["Text"].ToString(); + int id = (int)reader["object_id"]; + if (type.Equals("V")) + code = (ICode)database.Views.Find(id); + + if (type.Equals("TR")) + code = (ICode)database.Find(id); + + if (type.Equals("P")) + { + var procedure = database.Procedures.Find(id); + if (procedure != null) + ((ICode)procedure).Text = GetObjectDefinition(type, name, definition); + } + + if (type.Equals("IF") || type.Equals("FN") || type.Equals("TF")) + code = (ICode)database.Functions.Find(id); + + if (code != null) + code.Text = reader["Text"].ToString(); + } + } + } + } + } + } + catch (Exception ex) + { + throw ex; + } + } + + private string GetObjectDefinition(string type, string name, string definition) + { + string rv = definition; + + string sqlDelimiters = @"(\r|\n|\s)+?"; + RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.Multiline; + Regex re = new Regex(@"CREATE" + sqlDelimiters + @"PROC(EDURE)?" + sqlDelimiters + @"(\w+\.|\[\w+\]\.)?\[?(?\w+)\]?" + sqlDelimiters, options); + switch (type) + { + case "P": + Match match = re.Match(definition); + if (match != null && match.Success) + { + // Try to replace the name saved in the definition when the object was created by the one used for the object in sys.object + string oldName = match.Groups["spname"].Value; + //if (String.IsNullOrEmpty(oldName)) System.Diagnostics.Debugger.Break(); + if (String.Compare(oldName, name) != 0) + { + rv = rv.Replace(oldName, name); + } + } + break; + default: + //TODO : Add the logic used for other objects than procedures + break; + } + + return rv; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateTriggers.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateTriggers.cs new file mode 100644 index 0000000..3a3bdbd --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateTriggers.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using OpenDBDiff.Schema.Errors; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Options; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateTriggers + { + private Generate root; + + public GenerateTriggers(Generate root) + { + this.root = root; + } + + private static string GetSQL(DatabaseInfo.SQLServerVersion version, SqlOption options) + { + if (version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) + { + return SQLQueries.SQLQueryFactory.Get("GetTriggers", version); + } + else + { + return SQLQueries.SQLQueryFactory.Get("GetTriggers"); + } + } + + public void Fill(Database database, string connectionString, List messages) + { + int parentId = 0; + ISchemaBase parent = null; + string type; + try + { + if (database.Options.Ignore.FilterTrigger) + { + root.RaiseOnReading(new ProgressEventArgs("Reading Triggers...", Constants.READING_TRIGGERS)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(database.Info.Version, database.Options), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + type = reader["ObjectType"].ToString().Trim(); + if (parentId != (int)reader["parent_id"]) + { + parentId = (int)reader["parent_id"]; + if (type.Equals("V")) + parent = database.Views.Find(parentId); + else + parent = database.Tables.Find(parentId); + } + if (reader["type"].Equals("TR")) + { + Trigger item = new Trigger(parent); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.InsteadOf = (bool)reader["is_instead_of_trigger"]; + item.IsDisabled = (bool)reader["is_disabled"]; + item.IsDDLTrigger = false; + item.Owner = reader["Owner"].ToString(); + if (database.Options.Ignore.FilterNotForReplication) + item.NotForReplication = (bool)reader["is_not_for_replication"]; + if (type.Equals("V")) + ((View)parent).Triggers.Add(item); + else + ((Table)parent).Triggers.Add(item); + } + else + { + CLRTrigger item = new CLRTrigger(parent); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.IsDelete = (bool)reader["IsDelete"]; + item.IsUpdate = (bool)reader["IsUpdate"]; + item.IsInsert = (bool)reader["IsInsert"]; + item.Owner = reader["Owner"].ToString(); + item.IsAssembly = true; + item.AssemblyId = (int)reader["assembly_id"]; + item.AssemblyName = reader["assembly_name"].ToString(); + item.AssemblyClass = reader["assembly_class"].ToString(); + item.AssemblyExecuteAs = reader["ExecuteAs"].ToString(); + item.AssemblyMethod = reader["assembly_method"].ToString(); + if (type.Equals("V")) + ((View)parent).CLRTriggers.Add(item); + else + ((Table)parent).CLRTriggers.Add(item); + /*if (!database.Options.Ignore.FilterIgnoreNotForReplication) + trigger.NotForReplication = (bool)reader["is_not_for_replication"];*/ + } + } + } + } + } + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateUserDataTypes.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateUserDataTypes.cs new file mode 100644 index 0000000..d3353de --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateUserDataTypes.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using OpenDBDiff.Schema.Errors; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateUserDataTypes + { + private readonly Generate root; + + public GenerateUserDataTypes(Generate root) + { + this.root = root; + } + + private static string GetSQLColumnsDependencies() + { + return SQLQueries.SQLQueryFactory.Get("GetSQLColumnsDependencies"); + } + + private static void FillColumnsDependencies(SchemaList types, string connectionString) + { + if (types == null) throw new ArgumentNullException("types"); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLColumnsDependencies(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + types[reader["TypeName"].ToString()].Dependencies.Add(new ObjectDependency(reader["TableName"].ToString(), reader["ColumnName"].ToString(), ConvertType.GetObjectType(reader["Type"].ToString()))); + } + } + } + } + } + + public void Fill(Database database, string connectionString, List messages) + { + //not supported in azure yet http://msdn.microsoft.com/en-us/library/ee336233.aspx + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) return; + + try + { + if (database.Options.Ignore.FilterUserDataType) + { + root.RaiseOnReading(new ProgressEventArgs("Reading UDT...", Constants.READING_UDT)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(UserDataTypeCommand.Get(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + UserDataType item = new UserDataType(database); + item.Id = (int)reader["tid"]; + item.AllowNull = (bool)reader["is_nullable"]; + item.Size = (short)reader["max_length"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["owner"].ToString(); + item.Precision = int.Parse(reader["precision"].ToString()); + item.Scale = int.Parse(reader["scale"].ToString()); + if (!String.IsNullOrEmpty(reader["defaultname"].ToString())) + { + item.Default.Name = reader["defaultname"].ToString(); + item.Default.Owner = reader["defaultowner"].ToString(); + } + if (!String.IsNullOrEmpty(reader["rulename"].ToString())) + { + item.Rule.Name = reader["rulename"].ToString(); + item.Rule.Owner = reader["ruleowner"].ToString(); + } + item.Type = reader["basetypename"].ToString(); + item.IsAssembly = (bool)reader["is_assembly_type"]; + item.AssemblyId = (int)reader["assembly_id"]; + item.AssemblyName = reader["assembly_name"].ToString(); + item.AssemblyClass = reader["assembly_class"].ToString(); + database.UserTypes.Add(item); + } + } + } + } + if (database.Options.Ignore.FilterTable) + FillColumnsDependencies(database.UserTypes, connectionString); + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateUsers.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateUsers.cs new file mode 100644 index 0000000..0f04052 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateUsers.cs @@ -0,0 +1,63 @@ +using System; +using System.Data.SqlClient; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateUsers + { + private Generate root; + + public GenerateUsers(Generate root) + { + this.root = root; + } + + public void Fill(Database database, string connectioString) + { + string type; + if ((database.Options.Ignore.FilterUsers) || (database.Options.Ignore.FilterRoles)) + { + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(UserSQLCommand.Get(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + type = reader["type"].ToString(); + if (database.Options.Ignore.FilterUsers && (type.Equals("S") || type.Equals("U"))) + { + User item = new User(database); + item.Id = (int)reader["principal_id"]; + item.Name = reader["name"].ToString(); + item.Login = reader["Login"].ToString(); + item.Owner = reader["default_schema_name"].ToString(); + database.Users.Add(item); + } + if (database.Options.Ignore.FilterRoles && (type.Equals("A") || type.Equals("R"))) + { + Role item = new Role(database); + item.Id = (int)reader["principal_id"]; + item.Name = reader["name"].ToString(); + item.Owner = reader["default_schema_name"].ToString(); + item.Password = ""; + item.IsSystem = (Boolean)reader["is_fixed_role"]; + if (type.Equals("A")) + item.Type = Role.RoleTypeEnum.ApplicationRole; + else + item.Type = Role.RoleTypeEnum.DatabaseRole; + database.Roles.Add(item); + } + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateViews.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateViews.cs new file mode 100644 index 0000000..b235e13 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateViews.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using OpenDBDiff.Schema.Errors; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateViews + { + private Generate root; + + public GenerateViews(Generate root) + { + this.root = root; + } + + public void Fill(Database database, string connectionString, List messages) + { + try + { + root.RaiseOnReading(new ProgressEventArgs("Reading views...", Constants.READING_VIEWS)); + if (database.Options.Ignore.FilterView) + { + FillView(database, connectionString); + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + + private void FillView(Database database, string connectionString) + { + int lastViewId = 0; + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(ViewSQLCommand.GetView(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + View item = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["name"]); + if (lastViewId != (int)reader["object_id"]) + { + item = new View(database); + item.Id = (int)reader["object_id"]; + item.Name = reader["name"].ToString(); + item.Owner = reader["owner"].ToString(); + item.IsSchemaBinding = reader["IsSchemaBound"].ToString().Equals("1"); + database.Views.Add(item); + lastViewId = item.Id; + } + if (item.IsSchemaBinding) + { + if (!reader.IsDBNull(reader.GetOrdinal("referenced_major_id"))) + database.Dependencies.Add(database, (int)reader["referenced_major_id"], item); + if (!String.IsNullOrEmpty(reader["TableName"].ToString())) + item.DependenciesIn.Add(reader["TableName"].ToString()); + if (!String.IsNullOrEmpty(reader["DependOut"].ToString())) + item.DependenciesOut.Add(reader["DependOut"].ToString()); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateXMLSchemas.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateXMLSchemas.cs new file mode 100644 index 0000000..150bcd7 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/GenerateXMLSchemas.cs @@ -0,0 +1,85 @@ +using System.Data.SqlClient; +using System.Text; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates +{ + public class GenerateXMLSchemas + { + private Generate root; + + public GenerateXMLSchemas(Generate root) + { + this.root = root; + } + + private static string GetSQLColumnsDependencies() + { + return SQLQueries.SQLQueryFactory.Get("GetXMLSchemaCollections"); + } + + private static string GetSQLXMLSchema() + { + return SQLQueries.SQLQueryFactory.Get("GetSQLXMLSchema"); + } + + private static void FillColumnsDependencies(SchemaList items, string connectionString) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLColumnsDependencies(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + items[reader["XMLName"].ToString()].Dependencies.Add(new ObjectDependency(reader["TableName"].ToString(), reader["ColumnName"].ToString(), ConvertType.GetObjectType(reader["Type"].ToString()))); + } + } + } + } + } + + public void Fill(Database database, string connectionString) + { + //TODO XML_SCHEMA_NAMESPACE function not supported in Azure, is there a workaround? + //not supported in azure yet + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) return; + + + if (database.Options.Ignore.FilterXMLSchema) + { + root.RaiseOnReading(new ProgressEventArgs("Reading XML Schema...", Constants.READING_XMLSCHEMAS)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLXMLSchema(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["name"]); + XMLSchema item = new XMLSchema(database); + item.Id = (int)reader["ID"]; + item.Name = reader["name"].ToString(); + item.Owner = reader["owner"].ToString(); + item.Text = reader["Text"].ToString(); + database.XmlSchemas.Add(item); + + } + } + } + } + if (database.Options.Ignore.FilterTable) + FillColumnsDependencies(database.XmlSchemas, connectionString); + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/ConstraintSQLCommand.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/ConstraintSQLCommand.cs new file mode 100644 index 0000000..802c0fd --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/ConstraintSQLCommand.cs @@ -0,0 +1,192 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System.Text; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands +{ + internal static class ConstraintSQLCommand + { + public static string GetUniqueKey(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return GetUniqueKey2005(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetUniqueKeyAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetUniqueKeyAzure(); + else + return GetUniqueKey2008(); + } + } + + public static string GetCheck(DatabaseInfo.SQLServerVersion version) + { + if (version == DatabaseInfo.SQLServerVersion.SQLServer2005) return GetCheck2005(); + //Fall back to highest compatible version + return GetCheck2008(); + } + + public static string GetPrimaryKey(DatabaseInfo.SQLServerVersion version, Table table) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + return GetPrimaryKey2000(table); + + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return GetPrimaryKey2005(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetPrimaryKeyAzure(); + + default: + return GetPrimaryKey2008(); + } + } + + private static string GetUniqueKeyAzure() + { + //File Groups not supported in Azure + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, I.object_Id AS id,'' as FileGroup, C.user_type_id, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + //sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_unique_constraint = 1 AND O.type <> 'TF' ORDER BY I.object_id,I.Name"); + return sql.ToString(); + } + + private static string GetUniqueKey2008() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, I.object_Id AS id,dsidx.Name as FileGroup, C.user_type_id, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_unique_constraint = 1 AND O.type <> 'TF' ORDER BY I.object_id,I.Name"); + return sql.ToString(); + } + + private static string GetUniqueKey2005() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, I.object_Id AS id,dsidx.Name as FileGroup, C.user_type_id, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_unique_constraint = 1 AND O.type <> 'TF' ORDER BY I.object_id,I.Name"); + return sql.ToString(); + } + + private static string GetCheck2008() + { + string sql; + sql = "SELECT "; + sql += "CC.parent_object_id, "; + sql += "O.type as ObjectType, "; + sql += "CC.object_id AS ID, "; + sql += "CC.parent_column_id, "; + sql += "CC.name, "; + sql += "CC.type, "; + sql += "CC.definition, "; + sql += "CC.is_disabled, "; + sql += "CC.is_not_trusted AS WithCheck, "; + sql += "CC.is_not_for_replication, "; + sql += "0, "; + sql += "schema_name(CC.schema_id) AS Owner "; + sql += "FROM sys.check_constraints CC "; + sql += "INNER JOIN sys.objects O ON O.object_id = CC.parent_object_id "; + sql += "ORDER BY CC.parent_object_id,CC.name"; + return sql; + } + + private static string GetCheck2005() + { + string sql; + sql = "SELECT "; + sql += "CC.parent_object_id, "; + sql += "O.Type as ObjectType, "; + sql += "CC.object_id AS ID, "; + sql += "CC.parent_column_id, "; + sql += "CC.name, "; + sql += "CC.type, "; + sql += "CC.definition, "; + sql += "CC.is_disabled, "; + sql += "CC.is_not_trusted AS WithCheck, "; + sql += "CC.is_not_for_replication, "; + sql += "0, "; + sql += "schema_name(CC.schema_id) AS Owner "; + sql += "FROM sys.check_constraints CC "; + sql += "INNER JOIN sys.objects O ON O.object_id = CC.parent_object_id "; + sql += "ORDER BY CC.parent_object_id,CC.name"; + return sql; + } + + private static string GetPrimaryKeyAzure() + { + //File Groups not supported in Azure + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, IC.key_ordinal, C.user_type_id, I.object_id AS ID, '' AS FileGroup, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column, CONVERT(bit,INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics')) AS IsAutoStatistics "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + //sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_primary_key = 1 AND O.type <> 'TF' ORDER BY I.object_id"); + return sql.ToString(); + } + + private static string GetPrimaryKey2008() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, IC.key_ordinal, C.user_type_id, I.object_id AS ID, dsidx.Name AS FileGroup, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column, CONVERT(bit,INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics')) AS IsAutoStatistics "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_primary_key = 1 AND O.type <> 'TF' ORDER BY I.object_id"); + return sql.ToString(); + } + + private static string GetPrimaryKey2005() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, IC.key_ordinal, C.user_type_id, I.object_id AS ID, dsidx.Name AS FileGroup, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column, CONVERT(bit,INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics')) AS IsAutoStatistics "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("INNER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_primary_key = 1 AND O.type <> 'TF' ORDER BY I.object_id"); + return sql.ToString(); + } + + private static string GetPrimaryKey2000(Table table) + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT CONVERT(tinyint,CASE WHEN SI.indid = 0 THEN 0 WHEN SI.indid = 1 THEN 1 WHEN SI.indid > 1 THEN 2 END) AS Type,f.groupname AS FileGroup,CONVERT(int,SI.indid) AS Index_id, CONVERT(int,SI.indid) AS ID, SI.name, SC.colid, SC.Name AS ColumnName, CONVERT(bit,0) AS is_included_column, SIK.keyno AS key_ordinal, CONVERT(bit,INDEXPROPERTY(SI.id,SI.name,'IsPadIndex')) AS is_padded, CONVERT(bit,INDEXPROPERTY(SI.id,SI.name,'IsRowLockDisallowed')) AS allow_row_locks, CONVERT(bit,INDEXPROPERTY(SI.id,SI.name,'IsPageLockDisallowed')) AS allow_page_locks, CONVERT(bit,INDEXPROPERTY(SI.id,SI.name,'IsAutoStatistics')) AS IsAutoStatistics, CONVERT(tinyint,INDEXPROPERTY(SI.id,SI.name,'IndexFillFactor')) AS fill_factor, INDEXKEY_PROPERTY(SI.id, SI.indid,SC.colid,'IsDescending') AS is_descending_key, CONVERT(bit,0) AS is_disabled, CONVERT(bit,0) AS is_included_column "); + sql.Append("FROM sysindexes SI INNER JOIN sysindexkeys SIK ON SI.indid = SIK.indid AND SIK.id = SI.ID "); + sql.Append("INNER JOIN syscolumns SC ON SC.colid = SIK.colid AND SC.id = SI.ID "); + sql.Append("inner join sysfilegroups f on f.groupid = SI.groupid "); + sql.Append("WHERE (SI.status & 0x800) = 0x800 AND SI.id = " + table.Id.ToString() + " ORDER BY SIK.keyno"); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/DatabaseSQLCommand.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/DatabaseSQLCommand.cs new file mode 100644 index 0000000..bc39519 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/DatabaseSQLCommand.cs @@ -0,0 +1,67 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands +{ + internal class DatabaseSQLCommand + { + public static string GetVersion(Database databaseSchema) + { + string sql; + sql = "SELECT SERVERPROPERTY('productversion') AS Version, SERVERPROPERTY('EngineEdition') AS Edition"; + return sql; + } + + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition, Database databaseSchema) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(databaseSchema); + + case DatabaseInfo.SQLServerVersion.SQLServer2008: + return Get2008(databaseSchema); + + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return Get2008R2(databaseSchema); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetAzure(databaseSchema); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetAzure(databaseSchema); + else + return Get2008R2(databaseSchema); + } + } + + private static string Get2005(Database databaseSchema) + { + string sql; + sql = "SELECT DATABASEPROPERTYEX('" + databaseSchema.Name + "','IsFulltextEnabled') AS IsFullTextEnabled, DATABASEPROPERTYEX('" + databaseSchema.Name + "','Collation') AS Collation"; + return sql; + } + + private static string Get2008(Database databaseSchema) + { + string sql; + sql = "SELECT DATABASEPROPERTYEX('" + databaseSchema.Name + "','IsFulltextEnabled') AS IsFullTextEnabled, DATABASEPROPERTYEX('" + databaseSchema.Name + "','Collation') AS Collation"; + return sql; + } + + private static string Get2008R2(Database databaseSchema) + { + string sql; + sql = "SELECT DATABASEPROPERTYEX('" + databaseSchema.Name + "','IsFulltextEnabled') AS IsFullTextEnabled, DATABASEPROPERTYEX('" + databaseSchema.Name + "','Collation') AS Collation"; + return sql; + } + + private static string GetAzure(Database databaseSchema) + { + string sql; + //DATABASEPROPERTYEX('IsFullTextEnabled') is deprecated http://technet.microsoft.com/en-us/library/cc646010(SQL.110).aspx + sql = "SELECT 0 AS IsFullTextEnabled, DATABASEPROPERTYEX('" + databaseSchema.Name + "','Collation') AS Collation"; + return sql; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/FullTextIndexSQLCommand.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/FullTextIndexSQLCommand.cs new file mode 100644 index 0000000..c9c2ea9 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/FullTextIndexSQLCommand.cs @@ -0,0 +1,72 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System.Text; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands +{ + internal static class FullTextIndexSQLCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(); + + default: + return Get2008(); + } + } + + private static string Get2005() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT "); + sql.Append("FI.object_id, "); + sql.Append("T.Name AS TableName, "); + sql.Append("FC.name AS FullTextCatalogName, "); + sql.Append("I.name AS IndexName, "); + sql.Append("FI.is_enabled, "); + sql.Append("'['+ S.name + '].['+ T.name + '].[' + FC.name + ']' AS Name, "); + sql.Append("C.name as ColumnName, "); + sql.Append("FI.change_tracking_state_desc AS ChangeTracking, "); + sql.Append("FL.name AS LanguageName "); + sql.Append("FROM sys.fulltext_indexes FI "); + sql.Append("INNER JOIN sys.fulltext_catalogs FC ON FC.fulltext_catalog_id = FI.fulltext_catalog_id "); + sql.Append("INNER JOIN sys.indexes I ON I.index_id = FI.unique_index_id and I.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.tables T ON T.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = T.schema_id "); + sql.Append("INNER JOIN sys.fulltext_index_columns FIC ON FIC.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.object_id = FIC.object_id AND C.column_id = FIC.column_id "); + sql.Append("INNER JOIN sys.fulltext_languages FL ON FL.lcid = FIC.language_id "); + sql.Append("ORDER BY OBJECT_NAME(FI.object_id), I.name "); + return sql.ToString(); + } + + private static string Get2008() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT "); + sql.Append("FI.object_id, "); + sql.Append("T.Name AS TableName, "); + sql.Append("FC.name AS FullTextCatalogName, "); + sql.Append("I.name AS IndexName, "); + sql.Append("FI.is_enabled, "); + sql.Append("'['+ S.name + '].['+ T.name + '].[' + FC.name + ']' AS Name, "); + sql.Append("C.name as ColumnName, "); + sql.Append("FL.name AS LanguageName,"); + sql.Append("DS.name AS FileGroupName, "); + sql.Append("FI.change_tracking_state_desc AS ChangeTracking "); + sql.Append("FROM sys.fulltext_indexes FI "); + sql.Append("INNER JOIN sys.fulltext_catalogs FC ON FC.fulltext_catalog_id = FI.fulltext_catalog_id "); + sql.Append("INNER JOIN sys.indexes I ON I.index_id = FI.unique_index_id and I.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.tables T ON T.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = T.schema_id "); + sql.Append("INNER JOIN sys.fulltext_index_columns FIC ON FIC.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.object_id = FIC.object_id AND C.column_id = FIC.column_id "); + sql.Append("INNER JOIN sys.data_spaces DS ON DS.data_space_id = FI.data_space_id "); + sql.Append("INNER JOIN sys.fulltext_languages FL ON FL.lcid = FIC.language_id "); + sql.Append("ORDER BY OBJECT_NAME(FI.object_id), I.name "); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/FunctionSQLCommand.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/FunctionSQLCommand.cs new file mode 100644 index 0000000..53f0704 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/FunctionSQLCommand.cs @@ -0,0 +1,111 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System.Text; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands +{ + internal static class FunctionSQLCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(); + + case DatabaseInfo.SQLServerVersion.SQLServer2008: + return Get2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetAzure(); + else + return Get2008(); + } + } + + private static string Get2005() + { + string sql = ""; + sql += "select distinct "; + sql += "T.name AS ReturnType, PP.max_length, PP.precision, PP.Scale, "; + sql += "ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, "; + sql += "P.type, "; + sql += "AF.name AS assembly_name, "; + sql += "AM.assembly_class, "; + sql += "AM.assembly_id, "; + sql += "AM.assembly_method, "; + sql += "ISNULL('[' + S3.Name + '].[' + object_name(D2.object_id) + ']','') AS DependOut, '[' + S2.Name + '].[' + object_name(D.referenced_major_id) + ']' AS TableName, D.referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, P.object_id, S.name as owner, P.name as name from sys.objects P "; + sql += "INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "; + sql += "LEFT JOIN sys.sql_dependencies D ON P.object_id = D.object_id "; + sql += "LEFT JOIN sys.objects O ON O.object_id = D.referenced_major_id "; + sql += "LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "; + sql += "LEFT JOIN sys.sql_dependencies D2 ON P.object_id = D2.referenced_major_id "; + sql += "LEFT JOIN sys.objects O2 ON O2.object_id = D2.object_id "; + sql += "LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "; + sql += "LEFT JOIN sys.assembly_modules AM ON AM.object_id = P.object_id "; + sql += "LEFT JOIN sys.assemblies AF ON AF.assembly_id = AM.assembly_id "; + sql += "LEFT JOIN sys.parameters PP ON PP.object_id = AM.object_id AND PP.parameter_id = 0 and PP.is_output = 1 "; + sql += "LEFT JOIN sys.types T ON T.system_type_id = PP.system_type_id "; + sql += "WHERE P.type IN ('IF','FN','TF','FS') ORDER BY P.object_id"; + return sql; + } + + private static string Get2008() + { + var sql = new StringBuilder(); + sql.AppendLine("SELECT DISTINCT "); + sql.AppendLine("T.name AS ReturnType, PP.max_length, PP.precision, PP.Scale, "); + sql.AppendLine("ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, "); + sql.AppendLine("P.type, "); + sql.AppendLine("AF.name AS assembly_name, "); + sql.AppendLine("AM.assembly_class, "); + sql.AppendLine("AM.assembly_id, "); + sql.AppendLine("AM.assembly_method, "); + sql.AppendLine("ISNULL('[' + S3.Name + '].[' + object_name(D2.object_id) + ']','') AS DependOut, '[' + S2.Name + '].[' + object_name(D.referenced_major_id) + ']' AS TableName, D.referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, P.object_id, S.name as owner, P.name as name from sys.objects P "); + sql.AppendLine("INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "); + sql.AppendLine("LEFT JOIN sys.sql_dependencies D ON P.object_id = D.object_id "); + sql.AppendLine("LEFT JOIN sys.objects O ON O.object_id = D.referenced_major_id "); + sql.AppendLine("LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "); + sql.AppendLine("LEFT JOIN sys.sql_dependencies D2 ON P.object_id = D2.referenced_major_id "); + sql.AppendLine("LEFT JOIN sys.objects O2 ON O2.object_id = D2.object_id "); + sql.AppendLine("LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "); + sql.AppendLine("LEFT JOIN sys.assembly_modules AM ON AM.object_id = P.object_id "); + sql.AppendLine("LEFT JOIN sys.assemblies AF ON AF.assembly_id = AM.assembly_id "); + sql.AppendLine("LEFT JOIN sys.parameters PP ON PP.object_id = AM.object_id AND PP.parameter_id = 0 and PP.is_output = 1 "); + sql.AppendLine("LEFT JOIN sys.types T ON T.system_type_id = PP.system_type_id "); + sql.AppendLine("WHERE P.type IN ('IF','FN','TF','FS') ORDER BY P.object_id"); + return sql.ToString(); + } + + private static string GetAzure() + { + var sql = new StringBuilder(); + sql.AppendLine("SELECT DISTINCT "); + sql.AppendLine("T.name AS ReturnType, PP.max_length, PP.precision, PP.Scale, "); + sql.AppendLine("ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, "); + sql.AppendLine("P.type, "); + sql.AppendLine("AF.name AS assembly_name, "); + sql.AppendLine("AM.assembly_class, "); + sql.AppendLine("AM.assembly_id, "); + sql.AppendLine("AM.assembly_method, "); + sql.AppendLine("ISNULL('[' + S3.Name + '].[' + object_name(D2.referencing_id) + ']','') AS DependOut, "); + sql.AppendLine("'[' + S2.Name + '].[' + object_name(D.referenced_id) + ']' AS TableName, D.referenced_id AS referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, P.object_id, S.name as owner, P.name as name from sys.objects P "); + sql.AppendLine("INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "); + sql.AppendLine("LEFT JOIN sys.sql_expression_dependencies D ON P.object_id = D.referencing_id "); + sql.AppendLine("LEFT JOIN sys.objects O ON O.object_id = D.referenced_id "); + sql.AppendLine("LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "); + sql.AppendLine("LEFT JOIN sys.sql_expression_dependencies D2 ON P.object_id = D2.referenced_id "); + sql.AppendLine("LEFT JOIN sys.objects O2 ON O2.object_id = D2.referencing_id "); + sql.AppendLine("LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "); + sql.AppendLine("CROSS JOIN (SELECT null as object_id, null as execute_as_principal_id, null as assembly_class, null as assembly_id, null as assembly_method) AS AM "); + sql.AppendLine("CROSS JOIN (SELECT null AS name) AS AF"); + sql.AppendLine("LEFT JOIN sys.parameters PP ON PP.object_id = AM.object_id AND PP.parameter_id = 0 and PP.is_output = 1 "); + sql.AppendLine("LEFT JOIN sys.types T ON T.system_type_id = PP.system_type_id "); + sql.AppendLine("WHERE P.type IN ('IF','FN','TF','FS') ORDER BY P.object_id"); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/IndexSQLCommand.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/IndexSQLCommand.cs new file mode 100644 index 0000000..be851b3 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/IndexSQLCommand.cs @@ -0,0 +1,81 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System.Text; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands +{ + internal static class IndexSQLCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(); + + case DatabaseInfo.SQLServerVersion.SQLServer2008: + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return Get2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetAzure(); + else + return Get2008(); + } + } + + private static string Get2005() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT OO.type AS ObjectType, IC.key_ordinal, C.user_type_id, I.object_id, dsidx.Name as FileGroup, C.column_id,C.Name AS ColumnName, I.Name, I.index_id, I.type, is_unique, ignore_dup_key, is_primary_key, is_unique_constraint, fill_factor, is_padded, is_disabled, allow_row_locks, allow_page_locks, IC.is_descending_key, IC.is_included_column, ISNULL(ST.no_recompute,0) AS NoAutomaticRecomputation "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects OO ON OO.object_id = I.object_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.stats AS ST ON ST.stats_id = I.index_id AND ST.object_id = I.object_id "); + sql.Append("WHERE I.type IN (1,2,3) "); + sql.Append("AND is_unique_constraint = 0 AND is_primary_key = 0 "); //AND I.object_id = " + table.Id.ToString(CultureInfo.InvariantCulture) + " "); + sql.Append("AND objectproperty(I.object_id, 'IsMSShipped') <> 1 "); + sql.Append("ORDER BY I.object_id, I.Name, IC.column_id"); + return sql.ToString(); + } + + private static string Get2008() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT ISNULL(I.filter_definition,'') AS FilterDefinition, OO.type AS ObjectType, IC.key_ordinal, C.user_type_id, I.object_id, dsidx.Name as FileGroup, C.column_id,C.Name AS ColumnName, I.Name, I.index_id, I.type, is_unique, ignore_dup_key, is_primary_key, is_unique_constraint, fill_factor, is_padded, is_disabled, allow_row_locks, allow_page_locks, IC.is_descending_key, IC.is_included_column, ISNULL(ST.no_recompute,0) AS NoAutomaticRecomputation "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects OO ON OO.object_id = I.object_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.stats AS ST ON ST.stats_id = I.index_id AND ST.object_id = I.object_id "); + sql.Append("WHERE I.type IN (1,2,3) "); + sql.Append("AND is_unique_constraint = 0 AND is_primary_key = 0 "); //AND I.object_id = " + table.Id.ToString(CultureInfo.InvariantCulture) + " "); + sql.Append("AND objectproperty(I.object_id, 'IsMSShipped') <> 1 "); + sql.Append("ORDER BY I.object_id, I.Name, IC.column_id"); + return sql.ToString(); + } + + private static string GetAzure() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT ISNULL(I.filter_definition,'') AS FilterDefinition, OO.type AS ObjectType, IC.key_ordinal, C.user_type_id, I.object_id, '' as FileGroup, C.column_id,C.Name AS ColumnName, I.Name, I.index_id, I.type, is_unique, ignore_dup_key, is_primary_key, is_unique_constraint, fill_factor, is_padded, is_disabled, allow_row_locks, allow_page_locks, IC.is_descending_key, IC.is_included_column, ISNULL(ST.no_recompute,0) AS NoAutomaticRecomputation "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects OO ON OO.object_id = I.object_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + //sql.Append("INNER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.stats AS ST ON ST.stats_id = I.index_id AND ST.object_id = I.object_id "); + sql.Append("WHERE I.type IN (1,2,3) "); + sql.Append("AND is_unique_constraint = 0 AND is_primary_key = 0 "); //AND I.object_id = " + table.Id.ToString(CultureInfo.InvariantCulture) + " "); + sql.Append("AND objectproperty(I.object_id, 'IsMSShipped') <> 1 "); + sql.Append("ORDER BY I.object_id, I.Name, IC.column_id"); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/TableSQLCommand.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/TableSQLCommand.cs new file mode 100644 index 0000000..2a6e8cf --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/TableSQLCommand.cs @@ -0,0 +1,166 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System.Text; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands +{ + internal static class TableSQLCommand + { + #region Table Count + + public static string GetTableCount(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + return GetTableCount2000(); + + default: + return GetTableCount2005(); + } + } + + private static string GetTableCount2000() + { + return "SELECT Count(*) FROM sysobjects SO WHERE type = 'U'"; + } + + private static string GetTableCount2005() + { + return "SELECT Count(*) from sys.tables"; + } + + #endregion Table Count + + #region Table Detail + + public static string GetTableDetail(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + return GetTableDetail2000(); + + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return GetTableDetail2005(); + + case DatabaseInfo.SQLServerVersion.SQLServer2008: + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return GetTableDetail2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetTableDetailAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetTableDetailAzure(); + else + return GetTableDetail2008(); + } + } + + private static string GetTableDetailAzure() + { + var sql = new StringBuilder(); + sql.AppendLine("SELECT DISTINCT 0 AS HasChangeTrackingTrackColumn, 0 AS HasChangeTracking, TTT.lock_escalation_desc, T.type AS ObjectType, C.Name, C.is_filestream, C.is_sparse, S4.Name as OwnerType,C.user_type_id, C.Column_Id AS ID, C.max_length AS Size, C.Precision, C.Scale, ISNULL(C.Collation_Name,'') as Collation, C.Is_nullable AS IsNullable, C.Is_RowGuidcol AS IsRowGuid, C.Is_Computed AS IsComputed, C.Is_Identity AS IsIdentity, COLUMNPROPERTY(T.object_id,C.name,'IsIdNotForRepl') AS IsIdentityRepl,IDENT_SEED('[' + S1.name + '].[' + T.Name + ']') AS IdentSeed, IDENT_INCR('[' + S1.name + '].[' + T.Name + ']') AS IdentIncrement, ISNULL(CC.Definition,'') AS Formula, ISNULL(CC.Is_Persisted,0) AS FormulaPersisted, "); + sql.AppendLine("CASE WHEN ISNULL(DEP.referencing_minor_id,0) = 0 THEN 0 ELSE 1 END AS HasComputedFormula, CASE WHEN ISNULL(IC.column_id,0) = 0 THEN 0 ELSE 1 END AS HasIndex, TY.Name AS Type, '[' + S3.Name + '].' + XSC.Name AS XMLSchema, C.Is_xml_document, TY.is_user_defined, "); + sql.AppendLine("ISNULL(TT.Name,T.Name) AS TableName, T.object_id AS TableId,S1.name AS TableOwner,Text_In_Row_limit, large_value_types_out_of_row,ISNULL(objectproperty(T.object_id, N'TableHasVarDecimalStorageFormat'),0) AS HasVarDecimal,OBJECTPROPERTY(T.OBJECT_ID,'TableHasClustIndex') AS HasClusteredIndex, "); + sql.AppendLine(" '' AS FileGroup, '' AS FileGroupText, '' AS FileGroupStream,ISNULL(DC.object_id,0) AS DefaultId, DC.name AS DefaultName, DC.definition AS DefaultDefinition, C.rule_object_id, C.default_object_id "); + sql.AppendLine("FROM sys.columns C "); + sql.AppendLine("INNER JOIN sys.objects T ON T.object_id = C.object_id "); + sql.AppendLine("INNER JOIN sys.types TY ON TY.user_type_id = C.user_type_id "); + sql.AppendLine("LEFT JOIN sys.indexes IDX ON IDX.object_id = T.object_id and IDX.index_id < 2 "); + //sql.Append("LEFT JOIN sys.data_spaces AS DSIDX ON DSIDX.data_space_id = IDX.data_space_id "); + sql.AppendLine("LEFT JOIN sys.table_types TT ON TT.type_table_object_id = C.object_id "); + sql.AppendLine("LEFT JOIN sys.tables TTT ON TTT.object_id = C.object_id "); + sql.AppendLine("LEFT JOIN sys.schemas S1 ON (S1.schema_id = TTT.schema_id and T.type = 'U') OR (S1.schema_id = TT.schema_id and T.type = 'TT')"); + sql.AppendLine("LEFT JOIN sys.xml_schema_collections XSC ON XSC.xml_collection_id = C.xml_collection_id "); + sql.AppendLine("LEFT JOIN sys.schemas S3 ON S3.schema_id = XSC.schema_id "); + sql.AppendLine("LEFT JOIN sys.schemas S4 ON S4.schema_id = TY.schema_id "); + sql.AppendLine("LEFT JOIN sys.computed_columns CC ON CC.column_id = C.column_Id AND C.object_id = CC.object_id "); + sql.AppendLine("LEFT JOIN sys.sql_expression_dependencies DEP ON DEP.referenced_id = C.object_id AND DEP.referenced_minor_id = C.column_Id AND DEP.referencing_id = C.object_id "); + sql.AppendLine("LEFT JOIN sys.index_columns IC ON IC.object_id = T.object_id AND IC.column_Id = C.column_Id "); + //sql.Append("LEFT JOIN sys.data_spaces AS lob ON lob.data_space_id = TTT.lob_data_space_id "); + //sql.Append("LEFT JOIN sys.data_spaces AS filestr ON filestr.data_space_id = TTT.filestream_data_space_id "); + sql.AppendLine("LEFT JOIN sys.default_constraints DC ON DC.parent_object_id = T.object_id AND parent_column_id = C.Column_Id "); + //sql.Append("LEFT JOIN sys.change_tracking_tables CTT ON CTT.object_id = T.object_id "); + sql.AppendLine("WHERE T.type IN ('U','TT') "); + sql.AppendLine("ORDER BY ISNULL(TT.Name,T.Name),T.object_id,C.column_id"); + return sql.ToString(); + } + + private static string GetTableDetail2008() + { + string sql = ""; + sql += "SELECT DISTINCT (CASE WHEN ISNULL(CTT.is_track_columns_updated_on,0) <> 0 THEN is_track_columns_updated_on ELSE 0 END) AS HasChangeTrackingTrackColumn, (CASE WHEN ISNULL(CTT.object_id,0) <> 0 THEN 1 ELSE 0 END) AS HasChangeTracking, TTT.lock_escalation_desc, T.type AS ObjectType, C.Name, C.is_filestream, C.is_sparse, S4.Name as OwnerType,C.user_type_id, C.Column_Id AS ID, C.max_length AS Size, C.Precision, C.Scale, ISNULL(C.Collation_Name,'') as Collation, C.Is_nullable AS IsNullable, C.Is_RowGuidcol AS IsRowGuid, C.Is_Computed AS IsComputed, C.Is_Identity AS IsIdentity, COLUMNPROPERTY(T.object_id,C.name,'IsIdNotForRepl') AS IsIdentityRepl,IDENT_SEED('[' + S1.name + '].[' + T.Name + ']') AS IdentSeed, IDENT_INCR('[' + S1.name + '].[' + T.Name + ']') AS IdentIncrement, ISNULL(CC.Definition,'') AS Formula, ISNULL(CC.Is_Persisted,0) AS FormulaPersisted, CASE WHEN ISNULL(DEP.column_id,0) = 0 THEN 0 ELSE 1 END AS HasComputedFormula, CASE WHEN ISNULL(IC.column_id,0) = 0 THEN 0 ELSE 1 END AS HasIndex, TY.Name AS Type, '[' + S3.Name + '].' + XSC.Name AS XMLSchema, C.Is_xml_document, TY.is_user_defined, ISNULL(TT.Name,T.Name) AS TableName, T.object_id AS TableId,S1.name AS TableOwner,Text_In_Row_limit, large_value_types_out_of_row,ISNULL(objectproperty(T.object_id, N'TableHasVarDecimalStorageFormat'),0) AS HasVarDecimal,OBJECTPROPERTY(T.OBJECT_ID,'TableHasClustIndex') AS HasClusteredIndex,DSIDX.Name AS FileGroup,ISNULL(lob.Name,'') AS FileGroupText, ISNULL(filestr.Name,'') AS FileGroupStream,ISNULL(DC.object_id,0) AS DefaultId, DC.name AS DefaultName, DC.definition AS DefaultDefinition, C.rule_object_id, C.default_object_id "; + sql += "FROM sys.columns C "; + sql += "INNER JOIN sys.objects T ON T.object_id = C.object_id "; + sql += "INNER JOIN sys.types TY ON TY.user_type_id = C.user_type_id "; + sql += "LEFT JOIN sys.indexes IDX ON IDX.object_id = T.object_id and IDX.index_id < 2 "; + sql += "LEFT JOIN sys.data_spaces AS DSIDX ON DSIDX.data_space_id = IDX.data_space_id "; + sql += "LEFT JOIN sys.table_types TT ON TT.type_table_object_id = C.object_id "; + sql += "LEFT JOIN sys.tables TTT ON TTT.object_id = C.object_id "; + sql += "LEFT JOIN sys.schemas S1 ON (S1.schema_id = TTT.schema_id and T.type = 'U') OR (S1.schema_id = TT.schema_id and T.type = 'TT')"; + sql += "LEFT JOIN sys.xml_schema_collections XSC ON XSC.xml_collection_id = C.xml_collection_id "; + sql += "LEFT JOIN sys.schemas S3 ON S3.schema_id = XSC.schema_id "; + sql += "LEFT JOIN sys.schemas S4 ON S4.schema_id = TY.schema_id "; + sql += "LEFT JOIN sys.computed_columns CC ON CC.column_id = C.column_Id AND C.object_id = CC.object_id "; + sql += "LEFT JOIN sys.sql_dependencies DEP ON DEP.referenced_major_id = C.object_id AND DEP.referenced_minor_id = C.column_Id AND DEP.object_id = C.object_id "; + sql += "LEFT JOIN sys.index_columns IC ON IC.object_id = T.object_id AND IC.column_Id = C.column_Id "; + sql += "LEFT JOIN sys.data_spaces AS lob ON lob.data_space_id = TTT.lob_data_space_id "; + sql += "LEFT JOIN sys.data_spaces AS filestr ON filestr.data_space_id = TTT.filestream_data_space_id "; + sql += "LEFT JOIN sys.default_constraints DC ON DC.parent_object_id = T.object_id AND parent_column_id = C.Column_Id "; + sql += "LEFT JOIN sys.change_tracking_tables CTT ON CTT.object_id = T.object_id "; + sql += "WHERE T.type IN ('U','TT') "; + sql += "ORDER BY ISNULL(TT.Name,T.Name),T.object_id,C.column_id"; + return sql; + } + + private static string GetTableDetail2005() + { + string sql = ""; + sql += "SELECT DISTINCT T.type AS ObjectType, C.Name, S4.Name as OwnerType,"; + sql += "C.user_type_id, C.Column_Id AS ID, C.max_length AS Size, C.Precision, C.Scale, ISNULL(C.Collation_Name,'') as Collation, C.Is_nullable AS IsNullable, C.Is_RowGuidcol AS IsRowGuid, C.Is_Computed AS IsComputed, C.Is_Identity AS IsIdentity, COLUMNPROPERTY(T.object_id,C.name,'IsIdNotForRepl') AS IsIdentityRepl,IDENT_SEED('[' + S1.name + '].[' + T.Name + ']') AS IdentSeed, IDENT_INCR('[' + S1.name + '].[' + T.Name + ']') AS IdentIncrement, ISNULL(CC.Definition,'') AS Formula, ISNULL(CC.Is_Persisted,0) AS FormulaPersisted, CASE WHEN ISNULL(DEP.column_id,0) = 0 THEN 0 ELSE 1 END AS HasComputedFormula, CASE WHEN ISNULL(IC.column_id,0) = 0 THEN 0 ELSE 1 END AS HasIndex, TY.Name AS Type, '[' + S3.Name + '].' + XSC.Name AS XMLSchema, C.Is_xml_document, TY.is_user_defined, "; + sql += "T.Name AS TableName, T.object_id AS TableId,S1.name AS TableOwner,Text_In_Row_limit, large_value_types_out_of_row,ISNULL(objectproperty(T.object_id, N'TableHasVarDecimalStorageFormat'),0) AS HasVarDecimal,OBJECTPROPERTY(T.OBJECT_ID,'TableHasClustIndex') AS HasClusteredIndex,DSIDX.Name AS FileGroup,ISNULL(LOB.Name,'') AS FileGroupText, "; + sql += "ISNULL(DC.object_id,0) AS DefaultId, DC.name AS DefaultName, DC.definition AS DefaultDefinition, C.rule_object_id, C.default_object_id "; + sql += "FROM sys.columns C "; + sql += "INNER JOIN sys.tables T ON T.object_id = C.object_id "; + sql += "INNER JOIN sys.types TY ON TY.user_type_id = C.user_type_id "; + sql += "INNER JOIN sys.schemas S1 ON S1.schema_id = T.schema_id "; + sql += "INNER JOIN sys.indexes IDX ON IDX.object_id = T.object_id and IDX.index_id < 2 "; + sql += "INNER JOIN sys.data_spaces AS DSIDX ON DSIDX.data_space_id = IDX.data_space_id "; + sql += "LEFT JOIN sys.xml_schema_collections XSC ON XSC.xml_collection_id = C.xml_collection_id "; + sql += "LEFT JOIN sys.schemas S3 ON S3.schema_id = XSC.schema_id "; + sql += "LEFT JOIN sys.schemas S4 ON S4.schema_id = TY.schema_id "; + sql += "LEFT JOIN sys.computed_columns CC ON CC.column_id = C.column_Id AND C.object_id = CC.object_id "; + sql += "LEFT JOIN sys.sql_dependencies DEP ON DEP.referenced_major_id = C.object_id AND DEP.referenced_minor_id = C.column_Id AND DEP.object_id = C.object_id "; + sql += "LEFT JOIN sys.index_columns IC ON IC.object_id = T.object_id AND IC.column_Id = C.column_Id "; + sql += "LEFT JOIN sys.data_spaces AS LOB ON LOB.data_space_id = T.lob_data_space_id "; + sql += "LEFT JOIN sys.default_constraints DC ON DC.parent_object_id = T.object_id AND parent_column_id = C.Column_Id "; + sql += "ORDER BY T.Name,T.object_id,C.column_id"; + return sql; + } + + private static string GetTableDetail2000() + { + string sql = ""; + sql += "SELECT SO.name, "; + sql += "SO.id as object_id, "; + sql += "SU.name as Owner, "; + sql += "OBJECTPROPERTY(SO.ID,'TableTextInRowLimit') AS Text_In_Row_limit,"; + sql += "0 AS HasVarDecimal, "; + sql += "CONVERT(bit,0) AS large_value_types_out_of_row, "; + sql += "F.groupname AS FileGroup, "; + sql += "ISNULL(F2.groupname,'') AS FileGroupText, "; + sql += "OBJECTPROPERTY(SO.ID,'TableHasClustIndex') AS HasClusteredIndex "; + sql += "FROM sysobjects SO "; + sql += "inner join sysindexes I ON I.id = SO.id and I.indid < 2 "; + sql += "inner join sysfilegroups f on f.groupid = i.groupid "; + sql += "left join sysindexes I2 ON I2.id = SO.id and I2.indid = 255 "; + sql += "left join sysfilegroups f2 on f2.groupid = i2.groupid "; + sql += "INNER JOIN sysusers SU ON SU.uid = SO.uid WHERE type = 'U' ORDER BY SO.name"; + return sql; + } + + #endregion Table Detail + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/UserDataTypeCommand.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/UserDataTypeCommand.cs new file mode 100644 index 0000000..2bba8d2 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/UserDataTypeCommand.cs @@ -0,0 +1,58 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands +{ + internal static class UserDataTypeCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + return Get2000(); + + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(); + + default: + return Get2008(); + } + } + + public static string Get2008() + { + string sql = "SELECT ISNULL(AF.name,'') AS assembly_name, ISNULL(AT.assembly_id,0) AS assembly_id, ISNULL(assembly_class,'') AS assembly_class, T.max_length, S2.name as defaultowner, O2.name as defaultname, S1.name as ruleowner, O.name as rulename, ISNULL(T2.Name,'') AS basetypename, S.Name AS Owner, T.Name, T.is_assembly_type, T.user_type_id AS tid, T.is_nullable, T.precision, T.scale "; + sql += "FROM sys.types T "; + sql += "INNER JOIN sys.schemas S ON S.schema_id = T.schema_id "; + sql += "LEFT JOIN sys.types T2 ON T2.user_type_id = T.system_type_id "; + sql += "LEFT JOIN sys.objects O ON O.type = 'R' and O.object_id = T.rule_object_id "; + sql += "LEFT JOIN sys.schemas S1 ON S1.schema_id = O.schema_id "; + sql += "LEFT JOIN sys.objects O2 ON O2.type = 'D' and O2.object_id = T.default_object_id "; + sql += "LEFT JOIN sys.schemas S2 ON S2.schema_id = O2.schema_id "; + sql += "LEFT JOIN sys.assembly_types AT ON AT.user_type_id = T.user_type_id AND T.is_assembly_type = 1 "; + sql += "LEFT JOIN sys.assemblies AF ON AF.assembly_id = AT.assembly_id "; + sql += "WHERE T.is_user_defined = 1 AND T.is_table_type = 0 ORDER BY T.Name"; + return sql; + } + + public static string Get2005() + { + string sql = "select ISNULL(AF.name,'') AS assembly_name, ISNULL(AT.assembly_id,0) AS assembly_id, ISNULL(assembly_class,'') AS assembly_class, T.max_length, S2.name as defaultowner, O2.name as defaultname, S1.name as ruleowner, O.name as rulename, ISNULL(T2.Name,'') AS basetypename, S.Name AS Owner, T.Name, T.is_assembly_type, T.user_type_id AS tid, T.is_nullable, T.precision, T.scale from sys.types T "; + sql += "INNER JOIN sys.schemas S ON S.schema_id = T.schema_id "; + sql += "LEFT JOIN sys.types T2 ON T2.user_type_id = T.system_type_id "; + sql += "LEFT JOIN sys.objects O ON O.type = 'R' and O.object_id = T.rule_object_id "; + sql += "LEFT JOIN sys.schemas S1 ON S1.schema_id = O.schema_id "; + sql += "LEFT JOIN sys.objects O2 ON O2.type = 'D' and O2.object_id = T.default_object_id "; + sql += "LEFT JOIN sys.schemas S2 ON S2.schema_id = O2.schema_id "; + sql += "LEFT JOIN sys.assembly_types AT ON AT.user_type_id = T.user_type_id AND T.is_assembly_type = 1 "; + sql += "LEFT JOIN sys.assemblies AF ON AF.assembly_id = AT.assembly_id "; + sql += "WHERE T.is_user_defined = 1 ORDER BY T.Name"; + return sql; + } + + public static string Get2000() + { + return ""; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/UserSQLCommand.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/UserSQLCommand.cs new file mode 100644 index 0000000..65a34aa --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/UserSQLCommand.cs @@ -0,0 +1,51 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System.Text; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands +{ + internal static class UserSQLCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + case DatabaseInfo.SQLServerVersion.SQLServer2005: + case DatabaseInfo.SQLServerVersion.SQLServer2008: + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return Get2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetAzure(); + else + return Get2008(); + } + } + + private static string Get2008() + { + var sql = new StringBuilder(); + sql.AppendLine("SELECT is_fixed_role, type, ISNULL(suser_sname(sid),'') AS Login,Name,principal_id, ISNULL(default_schema_name,'') AS default_schema_name "); + sql.AppendLine("FROM sys.database_principals "); + sql.AppendLine("WHERE type IN ('S','U','A','R') "); + sql.AppendLine("ORDER BY Name"); + return sql.ToString(); + } + + private static string GetAzure() + { + var sql = new StringBuilder(); + //to get LoginName in Azure (asside for the current login) you would have to link to master and query sys.sysusers or sys.sql_users + //the CASE test below will at least get you the Current login + sql.AppendLine("SELECT is_fixed_role, type, CASE WHEN suser_sid()=sid THEN suser_sname() ELSE '' END AS Login,Name,principal_id, ISNULL(default_schema_name,'') AS default_schema_name "); + sql.AppendLine("FROM sys.database_principals "); + sql.AppendLine("WHERE type IN ('S','U','A','R') "); + sql.AppendLine("ORDER BY Name"); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/ViewSQLCommand.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/ViewSQLCommand.cs new file mode 100644 index 0000000..03d8f8e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/SQLCommands/ViewSQLCommand.cs @@ -0,0 +1,68 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System.Text; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.SQLCommands +{ + internal static class ViewSQLCommand + { + #region View + + public static string GetView(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + case DatabaseInfo.SQLServerVersion.SQLServer2005: + case DatabaseInfo.SQLServerVersion.SQLServer2008: + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return GetViewSql2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetViewSqlAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetViewSqlAzure(); + else + return GetViewSql2008(); + } + } + + private static string GetViewSql2008() + { + string sql = ""; + sql += "select distinct ISNULL('[' + S3.Name + '].[' + object_name(D2.object_id) + ']','') AS DependOut, '[' + S2.Name + '].[' + object_name(D.referenced_major_id) + ']' AS TableName, D.referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, P.object_id, S.name as owner, P.name as name from sys.views P "; + sql += "INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "; + sql += "LEFT JOIN sys.sql_dependencies D ON P.object_id = D.object_id "; + sql += "LEFT JOIN sys.objects O ON O.object_id = D.referenced_major_id "; + sql += "LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "; + sql += "LEFT JOIN sys.sql_dependencies D2 ON P.object_id = D2.referenced_major_id "; + sql += "LEFT JOIN sys.objects O2 ON O2.object_id = D2.object_id "; + sql += "LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "; + sql += "ORDER BY P.object_id"; + return sql; + } + + private static string GetViewSqlAzure() + { + var sql = new StringBuilder(); + //Avoid using sql_dependencies. Use sys.sql_expression_dependencies instead. http://msdn.microsoft.com/en-us/library/ms174402.aspx + sql.Append("SELECT DISTINCT ISNULL('[' + S3.Name + '].[' + object_name(D2.referencing_id) + ']','') AS DependOut, "); + sql.Append("'[' + S2.Name + '].[' + object_name(D.referenced_id) + ']' AS TableName, "); + sql.Append("D.referenced_id AS referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, "); + sql.Append("P.object_id, S.name as owner, P.name as name "); + sql.Append("FROM sys.views P "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "); + sql.Append("LEFT JOIN sys.sql_expression_dependencies D ON P.object_id = D.referencing_id "); + sql.Append("LEFT JOIN sys.objects O ON O.object_id = D.referenced_id "); + sql.Append("LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "); + sql.Append("LEFT JOIN sys.sql_expression_dependencies D2 ON P.object_id = D2.referenced_id "); + sql.Append("LEFT JOIN sys.objects O2 ON O2.object_id = D2.referencing_id "); + sql.Append("LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "); + sql.Append("ORDER BY P.object_id "); + return sql.ToString(); + } + + #endregion View + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/Util/ByteToHexEncoder.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/Util/ByteToHexEncoder.cs new file mode 100644 index 0000000..064a49b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/Util/ByteToHexEncoder.cs @@ -0,0 +1,38 @@ +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.Util +{ + /// + /// This class implements a fast conversion from a byte array to an hex string. + /// + public class ByteToHexEncoder + { + private static readonly uint[] _lookup32 = CreateLookup32(); + + private static uint[] CreateLookup32() + { + var result = new uint[256]; + for (int i = 0; i < 256; i++) + { + var s = i.ToString("X2"); + result[i] = ((uint)s[0]) + ((uint)s[1] << 16); + } + return result; + } + + public static string ByteArrayToHex(byte[] bytes) + { + var result = new char[2 + bytes.Length * 2]; + + result[0] = '0'; + result[1] = 'x'; + + for (int i = 0; i < bytes.Length; i++) + { + var val = _lookup32[bytes[i]]; + result[2 * i + 2] = (char)val; + result[2 * i + 3] = (char)(val >> 16); + } + + return new string(result); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/Util/Constants.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/Util/Constants.cs new file mode 100644 index 0000000..2775fef --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/Util/Constants.cs @@ -0,0 +1,28 @@ +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.Util +{ + internal class Constants + { + public const int READING_RULES = 0; + public const int READING_TABLES = 1; + public const int READING_CONSTRAINTS = 2; + public const int READING_UDT = 3; + public const int READING_XMLSCHEMAS = 4; + public const int READING_SCHEMAS = 5; + public const int READING_USER = 6; + public const int READING_PARTITIONFUNCTION = 7; + public const int READING_PARTITIONSCHEME = 8; + public const int READING_FILEGROUPS = 9; + public const int READING_DLLTRIGGERS = 10; + public const int READING_SYNONYMS = 11; + public const int READING_ASSEMBLIES = 12; + public const int READING_PROCEDURES = 13; + public const int READING_VIEWS = 14; + public const int READING_FUNCTIONS = 15; + public const int READING_INDEXES = 16; + public const int READING_TRIGGERS = 17; + public const int READING_TEXTOBJECTS = 18; + public const int READING_EXTENDED_PROPERTIES = 19; + public const int READING_MAX = 20; + + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Generates/Util/ConvertType.cs b/OpenDBDiff.Schema.SQLServer.Generates/Generates/Util/ConvertType.cs new file mode 100644 index 0000000..27c94be --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Generates/Util/ConvertType.cs @@ -0,0 +1,17 @@ +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.Util +{ + internal static class ConvertType + { + public static ObjectType GetObjectType(string type) + { + if (type.Trim().Equals("V")) return ObjectType.View; + if (type.Trim().Equals("U")) return ObjectType.Table; + if (type.Trim().Equals("FN")) return ObjectType.Function; + if (type.Trim().Equals("TF")) return ObjectType.Function; + if (type.Trim().Equals("IF")) return ObjectType.Function; + if (type.Trim().Equals("P")) return ObjectType.StoredProcedure; + if (type.Trim().Equals("TR")) return ObjectType.Trigger; + return ObjectType.None; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Assembly.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Assembly.cs new file mode 100644 index 0000000..f6ab07a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Assembly.cs @@ -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(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 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 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; } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/AssemblyFile.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/AssemblyFile.cs new file mode 100644 index 0000000..b83ac2a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/AssemblyFile.cs @@ -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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRCode.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRCode.cs new file mode 100644 index 0000000..9bd3d7e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRCode.cs @@ -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; } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRFunction.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRFunction.cs new file mode 100644 index 0000000..b26ac1f --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRFunction.cs @@ -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(); + ReturnType = new Parameter(); + } + + public List 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRStoredProcedure.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRStoredProcedure.cs new file mode 100644 index 0000000..baf7d76 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRStoredProcedure.cs @@ -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(); + } + + public List 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRTrigger.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRTrigger.cs new file mode 100644 index 0000000..d004233 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/CLRTrigger.cs @@ -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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Code.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Code.cs new file mode 100644 index 0000000..54732fe --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Code.cs @@ -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(); + DependenciesOut = new List(); + 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 ""; + } + + /// + /// Names collection of dependant objects of the object + /// + public List DependenciesOut { get; set; } + + /// + /// Names collection of objects which the object depends on + /// + public List 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 depencyTracker = new Dictionary(); + iCount = DependenciesCountFilter(this.FullName, depencyTracker); + } + return iCount; + } + } + + private int DependenciesCountFilter(string FullName, Dictionary 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; + } + } + + /// + /// Indicates if there are dependant tables on the object which must be rebuild + /// + /// + 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 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; + } + + /// + /// Rebuilds the object and all its dependant objects. + /// + /// + 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; + } + + /// + /// Rebuilds the dependant objects. + /// + /// + 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)); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Column.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Column.cs new file mode 100644 index 0000000..53aa157 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Column.cs @@ -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 + { + public Column(ISchemaBase parent) + : base(parent, ObjectType.Column) + { + ComputedFormula = ""; + Collation = ""; + this.Default = new Default(this); + this.Rule = new Rule(this); + this.DefaultConstraint = null; + } + + /// + /// Clona el objeto Column en una nueva instancia. + /// + 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; } + + /// + /// Gets or sets a value indicating whether this instance is XML document. + /// + /// + /// true if this instance is XML document; otherwise, false. + /// + public Boolean IsXmlDocument { get; set; } + + /// + /// Gets or sets the XML schema. + /// + /// The XML schema. + public string XmlSchema { get; set; } + + public Boolean IsSparse { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is user defined type. + /// + /// + /// true if this instance is user defined type; otherwise, false. + /// + public Boolean IsUserDefinedType { get; set; } + + public int DataUserTypeId { get; set; } + + /// + /// Gets or sets the column position. + /// + /// The position. + public int Position { get; set; } + + /// + /// Gets or sets the scale (only in numeric or decimal datatypes). + /// + /// The scale. + public int Scale { get; set; } + + /// + /// Gets or sets the precision (only in numeric or decimal datatypes). + /// + /// The precision. + public int Precision { get; set; } + + /// + /// Gets or sets the collation (only in text datatypes). + /// + /// The collation. + public string Collation { get; set; } + + /// + /// Gets or sets a value indicating whether this is nullable. + /// + /// true if nullable; otherwise, false. + public Boolean IsNullable { get; set; } + + /// + /// Gets or sets the size. + /// + /// The size. + public int Size { get; set; } + + /// + /// Gets or sets the type. + /// + /// The type. + public string Type { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is persisted (only in Computed columns). + /// + /// + /// true if this instance is persisted; otherwise, false. + /// + public Boolean IsPersisted { get; set; } + + /// + /// Gets or sets a value indicating whether this instance has index dependencies. + /// + /// + /// true if this instance has index dependencies; otherwise, false. + /// + public Boolean HasIndexDependencies { get; set; } + + /// + /// Gets or sets a value indicating whether this instance has computed dependencies. + /// + /// + /// true if this instance has computed dependencies; otherwise, false. + /// + public Boolean HasComputedDependencies { get; set; } + + /// + /// Gets a value indicating whether this instance has to rebuild only constraint. + /// + /// + /// true if this instance has to rebuild only constraint; otherwise, false. + /// + public Boolean HasToRebuildOnlyConstraint + { + get + { + return (HasIndexDependencies && !HasComputedDependencies && !IsComputed); + } + } + /// + /// Gets a value indicating whether this instance has to rebuild. + /// + /// + /// true if this instance has to rebuild; otherwise, false. + /// + 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")); + } + + /// + /// Gets or sets the computed formula (only in Computed columns). + /// + /// The computed formula. + public string ComputedFormula { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is computed. + /// + /// + /// true if this instance is computed; otherwise, false. + /// + public Boolean IsComputed { get; set; } + + /// + /// Gets a value indicating whether this column is BLOB. + /// + /// true if this column is BLOB; otherwise, false. + 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"); + } + } + /// + /// Gets or sets a value indicating whether this field is identity for replication. + /// + /// + /// true if this field is identity for replication; otherwise, false. + /// + public Boolean IsIdentityForReplication { get; set; } + + /// + /// Gets or sets a value indicating whether this field is identity. + /// + /// + /// true if this field is identity; otherwise, false. + /// + public Boolean IsIdentity { get; set; } + + /// + /// Gets or sets the identity increment (only if the field is Identity). + /// + /// The identity increment. + public int IdentityIncrement { get; set; } + + /// + /// Gets or sets the identity seed (only if the field is Identity). + /// + /// The identity seed. + public long IdentitySeed { get; set; } + + /// + /// Indica si el campo es Row Guid + /// + public Boolean IsRowGuid { get; set; } + + /// + /// Nombre completo del objeto, incluyendo el owner. + /// + public override string FullName + { + get + { + return Parent.FullName + ".[" + Name + "]"; + } + } + + /// + /// Convierte el schema de la tabla en XML. + /// + public string ToXML() + { + /*string xml = ""; + xml += "\n"; + xml += "" + type + ""; + xml += "" + OriginalType + ""; + xml += "" + size.ToString() + ""; + xml += "" + (nullable ? "1":"0") + ""; + xml += "" + precision.ToString() + ""; + xml += "" + scale.ToString() + ""; + if (this.identity) + xml += ""; + if (this.identityForReplication) + xml += ""; + xml += constraints.ToXML(); + xml += "\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)); + } + } + + /// + /// Gets the default force value. + /// + /// The default force 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 ""; + } + } + + + /// + /// Toes the SQL drop. + /// + /// + public override string ToSqlDrop() + { + string sql = "ALTER TABLE " + Parent.FullName + " DROP COLUMN [" + Name + "]\r\nGO\r\n"; + return sql; + } + + /// + /// Toes the SQL add. + /// + /// + 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; + } + /// + /// Devuelve el schema de la columna en formato SQL. + /// + 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 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; + } + + /// + /// Compara solo las propiedades de dos campos relacionadas con los Identity. Si existen + /// diferencias, devuelve falso, caso contrario, true. + /// + 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; + } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/ColumnConstraint.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/ColumnConstraint.cs new file mode 100644 index 0000000..4b314a5 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/ColumnConstraint.cs @@ -0,0 +1,171 @@ +using System; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Model +{ + /// + /// Clase de constraints de Columnas (Default Constraint y Check Constraint) + /// + public class ColumnConstraint : SQLServerSchemaBase + { + public ColumnConstraint(Column parent) + : base(parent, ObjectType.Constraint) + { + } + + /// + /// Clona el objeto ColumnConstraint en una nueva instancia. + /// + 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; + } + + /// + /// Indica si la constraint esta deshabilitada. + /// + public Boolean Disabled { get; set; } + + /// + /// Indica si la constraint va a ser usada en replicacion. + /// + public Boolean NotForReplication { get; set; } + + + /// + /// Gets or sets a value indicating whether [with no check]. + /// + /// true if [with no check]; otherwise, false. + public Boolean WithNoCheck { get; set; } + + /// + /// Valor de la constraint. + /// + public string Definition { get; set; } + + /// + /// Indica el tipo de constraint (Default o Check constraint). + /// + public Constraint.ConstraintType Type { get; set; } + + /// + /// Convierte el schema de la constraint en XML. + /// + public string ToXML() + { + string xml = ""; + if (this.Type == Constraint.ConstraintType.Default) + { + xml += "\n"; + } + if (this.Type == Constraint.ConstraintType.Check) + { + xml += "\n"; + } + return xml; + } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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))); + } + } + + /// + /// Devuelve el schema de la constraint en formato SQL. + /// + public override string ToSql() + { + string sql = ""; + if (this.Type == Constraint.ConstraintType.Default) + sql = " CONSTRAINT [" + Name + "] DEFAULT " + Definition; + return sql; + } + + /// + /// Toes the SQL add. + /// + /// + 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 ""; + } + + /// + /// Toes the SQL drop. + /// + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Columns.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Columns.cs new file mode 100644 index 0000000..58ace05 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Columns.cs @@ -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 : SchemaList where T : ISchemaBase + { + public Columns(T parent) : base(parent) + { + } + + /// + /// Clona el objeto Columns en una nueva instancia. + /// + public new Columns Clone(T parentObject) + { + Columns columns = new Columns(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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Constraint.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Constraint.cs new file mode 100644 index 0000000..cb6d9f3 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Constraint.cs @@ -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); + } + + /// + /// Clona el objeto Column en una nueva instancia. + /// + 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; + } + + /// + /// Informacion sobre le indice asociado al Constraint. + /// + public Index Index { get; set; } + + /// + /// Coleccion de columnas de la constraint. + /// + public ConstraintColumns Columns { get; set; } + + /// + /// Indica si la constraint tiene asociada un indice Clustered. + /// + public Boolean HasClusteredIndex + { + get + { + if (Index != null) + return (Index.Type == Index.IndexTypeEnum.Clustered); + return false; + } + } + + /// + /// Gets or sets a value indicating whether this constraint is disabled. + /// + /// + /// true if this constraint is disabled; otherwise, false. + /// + public Boolean IsDisabled { get; set; } + + /// + /// Gets or sets the on delete cascade (only for FK). + /// + /// The on delete cascade. + public int OnDeleteCascade { get; set; } + + /// + /// Gets or sets the on update cascade (only for FK). + /// + /// The on update cascade. + public int OnUpdateCascade { get; set; } + + /// + /// Valor de la constraint (se usa para los Check Constraint). + /// + public string Definition { get; set; } + + /// + /// Indica si la constraint va a ser usada en replicacion. + /// + public Boolean NotForReplication { get; set; } + + /// + /// Gets or sets a value indicating whether [with no check]. + /// + /// true if [with no check]; otherwise, false. + public Boolean WithNoCheck { get; set; } + + /// + /// Indica el tipo de constraint (PrimaryKey, ForeignKey, Unique o Default). + /// + public ConstraintType Type { get; set; } + + /// + /// ID de la tabla relacionada a la que hace referencia (solo aplica a FK) + /// + public int RelationalTableId { get; set; } + + /// + /// Nombre de la tabla relacionada a la que hace referencia (solo aplica a FK) + /// + public string RelationalTableFullName { get; set; } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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(); + } + + /// + /// Devuelve el schema de la tabla en formato SQL. + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/ConstraintColumn.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/ConstraintColumn.cs new file mode 100644 index 0000000..f9fc33e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/ConstraintColumn.cs @@ -0,0 +1,89 @@ +using System; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Model +{ + public class ConstraintColumn : SQLServerSchemaBase, IComparable + { + 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; } + + /// + /// Gets or sets the column key order in the index. + /// + /// The key order. + public int KeyOrder { get; set; } + + /// + /// Gets or sets a value indicating whether this column is included in the index leaf page. + /// + /// + /// true if this column is included; otherwise, false. + /// + public Boolean IsIncluded { get; set; } + + /// + /// Orden de la columna (Ascendente o Descendente). Se usa solo en Primary Keys. + /// + 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); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/ConstraintColumns.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/ConstraintColumns.cs new file mode 100644 index 0000000..bcbdcc5 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/ConstraintColumns.cs @@ -0,0 +1,53 @@ +using System; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Model +{ + public class ConstraintColumns : SchemaList + { + public ConstraintColumns(Constraint parent) + : base(parent) + { + } + + /// + /// Clona el objeto ColumnConstraints en una nueva instancia. + /// + public ConstraintColumns Clone() + { + ConstraintColumns columns = new ConstraintColumns(this.Parent); + for (int index = 0; index < this.Count; index++) + { + columns.Add(this[index].Clone()); + } + return columns; + } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Database.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Database.cs new file mode 100644 index 0000000..5382e2b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Database.cs @@ -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 _changesOptions; + + public Database() : base(null, ObjectType.Database) + { + AllObjects = new SearchSchemaBase(); + _changesOptions = new List(); + Dependencies = new Dependencies(); + TablesTypes = new SchemaList(this, AllObjects); + UserTypes = new SchemaList(this, AllObjects); + XmlSchemas = new SchemaList(this, AllObjects); + Schemas = new SchemaList(this, AllObjects); + Procedures = new SchemaList(this, AllObjects); + CLRProcedures = new SchemaList(this, AllObjects); + CLRFunctions = new SchemaList(this, AllObjects); + FileGroups = new SchemaList(this); + Rules = new SchemaList(this, AllObjects); + DDLTriggers = new SchemaList(this, AllObjects); + Synonyms = new SchemaList(this, AllObjects); + Assemblies = new SchemaList(this, AllObjects); + Views = new SchemaList(this, AllObjects); + Users = new SchemaList(this, AllObjects); + FullText = new SchemaList(this, AllObjects); + Functions = new SchemaList(this, AllObjects); + PartitionFunctions = new SchemaList(this, AllObjects); + PartitionSchemes = new SchemaList(this, AllObjects); + Roles = new SchemaList(this); + Tables = new SchemaList(this, AllObjects); + Defaults = new SchemaList(this, AllObjects); + ActionMessage = new SqlAction(this); + } + + internal SearchSchemaBase AllObjects { get; private set; } + + [SchemaNode("Full Text Catalog", "FullText")] + public SchemaList FullText { get; private set; } + + [SchemaNode("Table Type", "Table")] + public SchemaList TablesTypes { get; private set; } + + [SchemaNode("Partition Scheme", "PartitionScheme")] + public SchemaList PartitionSchemes { get; private set; } + + [SchemaNode("Partition Functions", "PartitionFunction")] + public SchemaList PartitionFunctions { get; private set; } + + [SchemaNode("Defaults")] + public SchemaList Defaults { get; private set; } + + [SchemaNode("Roles", "Rol")] + public SchemaList Roles { get; private set; } + + [SchemaNode("Functions", "Function", true)] + public SchemaList Functions { get; private set; } + + [SchemaNode("Users", "User")] + public SchemaList Users { get; private set; } + + [SchemaNode("Views", "View", true)] + public SchemaList Views { get; private set; } + + [SchemaNode("Assemblies", "Assembly")] + public SchemaList Assemblies { get; private set; } + + [SchemaNode("Synonyms", "Assembly")] // We don't have an icon for synonyms at the moment. + public SchemaList Synonyms { get; private set; } + + [SchemaNode("DLL Triggers")] + public SchemaList DDLTriggers { get; private set; } + + [SchemaNode("File Groups")] + public SchemaList FileGroups { get; private set; } + + [SchemaNode("Rules")] + public SchemaList Rules { get; private set; } + + [SchemaNode("Stored Procedures", "Procedure", true)] + public SchemaList Procedures { get; private set; } + + [SchemaNode("CLR Stored Procedures", "CLRProcedure", true)] + public SchemaList CLRProcedures { get; private set; } + + [SchemaNode("CLR Functions", "CLRFunction", true)] + public SchemaList CLRFunctions { get; private set; } + + [SchemaNode("Schemas", "Schema")] + public SchemaList Schemas { get; private set; } + + [SchemaNode("XML Schemas", "XMLSchema")] + public SchemaList XmlSchemas { get; private set; } + + [SchemaNode("Tables", "Table", true)] + public SchemaList Tables { get; private set; } + + [SchemaNode("User Types", "UDT")] + public SchemaList 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; + } + + /// + /// Coleccion de dependencias de constraints. + /// + internal Dependencies Dependencies { get; set; } + + private List 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).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 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(); + var constraints = new List(); + + 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 + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/DatabaseInfo.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/DatabaseInfo.cs new file mode 100644 index 0000000..753e35f --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/DatabaseInfo.cs @@ -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; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Default.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Default.cs new file mode 100644 index 0000000..934e25d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Default.cs @@ -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 ""; + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Dependencies.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Dependencies.cs new file mode 100644 index 0000000..0ddf4ac --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Dependencies.cs @@ -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 + { + 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); + } + + /// + /// Devuelve todos las constraints dependientes de una tabla. + /// + public List FindNotOwner(int tableId, ObjectType type) + { + try + { + List cons = new List(); + 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; + } + } + + + /// + /// Devuelve todos las constraints dependientes de una tabla. + /// + /*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; + }); + }*/ + + /// + /// Devuelve todos las constraints dependientes de una tabla. + /// + public List Find(int tableId) + { + return Find(tableId, 0, 0); + } + + public int DependenciesCount(int objectId, ObjectType type) + { + Dictionary depencyTracker = new Dictionary(); + return DependenciesCount(objectId, type, depencyTracker); + } + + private int DependenciesCount(int tableId, ObjectType type, Dictionary depencyTracker) + { + int count = 0; + bool putItem = false; + int relationalTableId; + List 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; + } + + /// + /// Devuelve todos las constraints dependientes de una tabla y una columna. + /// + public List Find(int tableId, int columnId, int dataTypeId) + { + List cons = new List(); + List real = new List(); + + 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Dependency.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Dependency.cs new file mode 100644 index 0000000..d0465ca --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Dependency.cs @@ -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; } + + /// + /// ID de la tabla a la que hace referencia la constraint. + /// + public int ObjectId { get; set; } + + /// + /// ID de la tabla a la que pertenece la constraint. + /// + public int OwnerTableId { get; set; } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/ExtendedProperty.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/ExtendedProperty.cs new file mode 100644 index 0000000..d6e574c --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/ExtendedProperty.cs @@ -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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/FileGroup.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/FileGroup.cs new file mode 100644 index 0000000..baa2d8b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/FileGroup.cs @@ -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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/FileGroupFile.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/FileGroupFile.cs new file mode 100644 index 0000000..1c08e78 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/FileGroupFile.cs @@ -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; + } + + /// + /// Compara dos triggers y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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"; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/FileGroupFiles.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/FileGroupFiles.cs new file mode 100644 index 0000000..a263ed2 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/FileGroupFiles.cs @@ -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 + { + private Hashtable hash = new Hashtable(); + + /// + /// Constructor de la clase. + /// + /// + /// Objeto Database padre. + /// + public FileGroupFiles(FileGroup parent) + { + this.Parent = parent; + } + + /// + /// Clona el objeto FileGroups en una nueva instancia. + /// + 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; + } + + /// + /// Indica si el nombre del FileGroup existe en la coleccion de tablas del objeto. + /// + /// + /// Nombre de la tabla a buscar. + /// + /// + public Boolean Find(string table) + { + return hash.ContainsKey(table); + } + + /// + /// Agrega un objeto columna a la coleccion de columnas. + /// + 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; + } + } + } + } + + /// + /// Devuelve la tabla perteneciente a la coleccion de campos. + /// + 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(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/FullText.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/FullText.cs new file mode 100644 index 0000000..a30453d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/FullText.cs @@ -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 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; + } + + /// + /// Compara dos Synonyms y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/FullTextIndex.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/FullTextIndex.cs new file mode 100644 index 0000000..d6c053a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/FullTextIndex.cs @@ -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(); + } + + 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 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/FullTextIndexColumn.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/FullTextIndexColumn.cs new file mode 100644 index 0000000..ecd4cbc --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/FullTextIndexColumn.cs @@ -0,0 +1,9 @@ +namespace OpenDBDiff.Schema.SQLServer.Generates.Model +{ + public class FullTextIndexColumn + { + public string Language { get; set; } + + public string ColumnName { get; set; } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Function.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Function.cs new file mode 100644 index 0000000..a66960a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Function.cs @@ -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) + { + + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/ITableType.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/ITableType.cs new file mode 100644 index 0000000..c23c144 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/ITableType.cs @@ -0,0 +1,13 @@ +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Model +{ + public interface ITable where T : ISchemaBase + { + Columns Columns { get; } + SchemaList Constraints { get; } + SchemaList Indexes { get; } + ISchemaBase Parent { get; set; } + string Owner { get; set; } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Index.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Index.cs new file mode 100644 index 0000000..f3f1774 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Index.cs @@ -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 + "]"; + } + } + + /// + /// Compara dos indices y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/IndexColumn.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/IndexColumn.cs new file mode 100644 index 0000000..7355f91 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/IndexColumn.cs @@ -0,0 +1,72 @@ +using System; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Model +{ + public class IndexColumn : SQLServerSchemaBase, IComparable + { + 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);*/ + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/IndexColumns.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/IndexColumns.cs new file mode 100644 index 0000000..ed8a299 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/IndexColumns.cs @@ -0,0 +1,53 @@ +using System; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Model +{ + public class IndexColumns : SchemaList + { + public IndexColumns(ISchemaBase parent) + : base(parent) + { + } + + /// + /// Clona el objeto ColumnConstraints en una nueva instancia. + /// + public IndexColumns Clone() + { + IndexColumns columns = new IndexColumns(Parent); + for (int index = 0; index < this.Count; index++) + { + columns.Add(this[index].Clone(Parent)); + } + return columns; + } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Interfaces/ICode.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Interfaces/ICode.cs new file mode 100644 index 0000000..6d2c997 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Interfaces/ICode.cs @@ -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 DependenciesIn { get; set; } + List DependenciesOut { get; set; } + bool IsSchemaBinding { get; set; } + string Text { get; set; } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Interfaces/ISQLServerSchemaBase.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Interfaces/ISQLServerSchemaBase.cs new file mode 100644 index 0000000..a583030 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Interfaces/ISQLServerSchemaBase.cs @@ -0,0 +1,9 @@ +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Model +{ + public interface ISQLServerSchemaBase + { + SchemaList ExtendedProperties { get; } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/ObjectDependency.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/ObjectDependency.cs new file mode 100644 index 0000000..dc80103 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/ObjectDependency.cs @@ -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)); } + + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Parameter.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Parameter.cs new file mode 100644 index 0000000..7808268 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Parameter.cs @@ -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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/PartitionFunction.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/PartitionFunction.cs new file mode 100644 index 0000000..44ae6ab --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/PartitionFunction.cs @@ -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(); + } + + 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 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 items = Old.Values.Except(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 items2 = this.Values.Except(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(); + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/PartitionScheme.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/PartitionScheme.cs new file mode 100644 index 0000000..6ac358b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/PartitionScheme.cs @@ -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(); + } + + public List 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Role.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Role.cs new file mode 100644 index 0000000..8edfe52 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Role.cs @@ -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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Rule.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Rule.cs new file mode 100644 index 0000000..ea5a35c --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Rule.cs @@ -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 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; + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/SQLServerSchemaBase.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/SQLServerSchemaBase.cs new file mode 100644 index 0000000..4998dba --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/SQLServerSchemaBase.cs @@ -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(parent); + } + + public SchemaList ExtendedProperties { get; private set; } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Schema.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Schema.cs new file mode 100644 index 0000000..518cb59 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Schema.cs @@ -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"; + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/StoredProcedure.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/StoredProcedure.cs new file mode 100644 index 0000000..a6c7b5c --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/StoredProcedure.cs @@ -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) + { + + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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); + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Synonym.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Synonym.cs new file mode 100644 index 0000000..9edaabb --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Synonym.cs @@ -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(); + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + + /// + /// Compara dos Synonyms y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Table.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Table.cs new file mode 100644 index 0000000..0b4b498 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Table.cs @@ -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
, ITable
+ { + private int dependenciesCount; + private List dependencies; + private Boolean? hasFileStream; + + public Table(ISchemaBase parent) + : base(parent, ObjectType.Table) + { + dependenciesCount = -1; + Columns = new Columns
(this); + Constraints = new SchemaList(this, ((Database)parent).AllObjects); + Options = new SchemaList(this); + Triggers = new SchemaList(this, ((Database)parent).AllObjects); + CLRTriggers = new SchemaList(this, ((Database)parent).AllObjects); + Indexes = new SchemaList(this, ((Database)parent).AllObjects); + Partitions = new SchemaList(this, ((Database)parent).AllObjects); + FullTextIndex = new SchemaList(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 Constraints { get; private set; } + + [SchemaNode("Indexes", "Index")] + public SchemaList Indexes { get; private set; } + + [SchemaNode("CLR Triggers")] + public SchemaList CLRTriggers { get; private set; } + + [SchemaNode("Triggers")] + public SchemaList Triggers { get; private set; } + + public SchemaList FullTextIndex { get; private set; } + + public SchemaList Partitions { get; set; } + + public SchemaList Options { get; set; } + + /// + /// Indica si la tabla tiene alguna columna que sea Identity. + /// + 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; + } + } + + /// + /// Indica la cantidad de Constraints dependientes de otra tabla (FK) que tiene + /// la tabla. + /// + public override int DependenciesCount + { + get + { + if (dependenciesCount == -1) + dependenciesCount = ((Database)Parent).Dependencies.DependenciesCount(Id, + ObjectType.Constraint); + return dependenciesCount; + } + } + + #region IComparable
Members + + /// + /// 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. + /// + 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
Members + + #region ITable
Members + + /// + /// Coleccion de campos de la tabla. + /// + [SchemaNode("Columns", "Column")] + public Columns
Columns { get; set; } + + #endregion ITable
Members + + /// + /// Clona el objeto Table en una nueva instancia. + /// + 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); + } + + /// + /// Devuelve el schema de la tabla en formato SQL. + /// + 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; + } + */ + + /// + /// Devuelve el schema de diferencias de la tabla en formato SQL. + /// + public override SQLScriptList ToSqlDiff(ICollection 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 myDependencies; + /*Si el estado es AlterRebuildDependeciesStatus, busca las dependencias solamente en las columnas que fueron modificadas*/ + if (Status == ObjectStatus.RebuildDependencies) + { + myDependencies = new List(); + 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(); + 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); + } + } + + /// + /// 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. + /// + 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; + } + + /// + /// 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. + /// + 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; + } + + /// + /// Compara dos tablas y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + + /// + /// Compara dos tablas y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/TableOption.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/TableOption.cs new file mode 100644 index 0000000..e0691c3 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/TableOption.cs @@ -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) + { + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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; } + + /// + /// Compara dos indices y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/TablePartition.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/TablePartition.cs new file mode 100644 index 0000000..5bddbbb --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/TablePartition.cs @@ -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(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/TableType.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/TableType.cs new file mode 100644 index 0000000..2fc9385 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/TableType.cs @@ -0,0 +1,116 @@ +using OpenDBDiff.Schema.Model; +using System.Linq; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Model +{ + public class TableType : SQLServerSchemaBase, ITable + { + public TableType(ISchemaBase parent) + : base(parent, ObjectType.TableType) + { + Columns = new Columns(this); + Constraints = new SchemaList(this, ((Database)parent).AllObjects); + Indexes = new SchemaList(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 Columns { get; private set; } + + public SchemaList Constraints { get; private set; } + + public SchemaList 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 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; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Trigger.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Trigger.cs new file mode 100644 index 0000000..88a0241 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Trigger.cs @@ -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; + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/User.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/User.cs new file mode 100644 index 0000000..3c302a5 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/User.cs @@ -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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/UserDataType.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/UserDataType.cs new file mode 100644 index 0000000..1249aae --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/UserDataType.cs @@ -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(); + } + + public List 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; } + + /// + /// Cantidad de digitos que permite el campo (solo para campos Numeric). + /// + public int Scale { get; set; } + + /// + /// Cantidad de decimales que permite el campo (solo para campos Numeric). + /// + 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 ""; + } + } + + /// + /// Clona el objeto Column en una nueva instancia. + /// + 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 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 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 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/Util/FormatCode.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/Util/FormatCode.cs new file mode 100644 index 0000000..3a28349 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/Util/FormatCode.cs @@ -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 = ""; + } + + /// + /// Clears all unnecessary characters that are after the END statement of the body, and whitespaces at the beginning. + /// + private static string CleanLast(string body) + { + if (string.IsNullOrEmpty(body)) + { + return string.Empty; + } + + return body.TrimStart().TrimEnd(TrimCharacters); + } + + /// + /// Inserta la sentencia GO dentro del body + /// + 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; + } + } + + /// + /// Busca la primer entrada con el nombre completo dentro de una funcion, store, vista, trigger o rule. + /// Ignora los comentarios. + /// + 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; + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/View.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/View.cs new file mode 100644 index 0000000..4d8ab54 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/View.cs @@ -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(this, ((Database)parent).AllObjects); + Triggers = new SchemaList(this, ((Database)parent).AllObjects); + CLRTriggers = new SchemaList(this, ((Database)parent).AllObjects); + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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 CLRTriggers { get; set; } + + [SchemaNode("Triggers")] + public SchemaList Triggers { get; set; } + + [SchemaNode("Indexes", "Index")] + public SchemaList 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); + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Model/XMLSchema.cs b/OpenDBDiff.Schema.SQLServer.Generates/Model/XMLSchema.cs new file mode 100644 index 0000000..7b45b94 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Model/XMLSchema.cs @@ -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(); + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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 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; + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/OpenDBDiff.Schema.SQLServer.Generates.csproj b/OpenDBDiff.Schema.SQLServer.Generates/OpenDBDiff.Schema.SQLServer.Generates.csproj new file mode 100644 index 0000000..68dcd5a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/OpenDBDiff.Schema.SQLServer.Generates.csproj @@ -0,0 +1,269 @@ + + + + + Debug + AnyCPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867} + Library + Properties + OpenDBDiff.Schema.SQLServer.Generates + OpenDBDiff.Schema.SQLServer.Generates + v4.5.2 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + OpenDBDiff.Schema.SQLServer.Generates.snk + + + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {406558A0-1B98-4D0E-B8B6-2013700B065A} + DBDiff.Schema + + + + + .editorconfig + + + + + + \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/OpenDBDiff.Schema.SQLServer.Generates.snk b/OpenDBDiff.Schema.SQLServer.Generates/OpenDBDiff.Schema.SQLServer.Generates.snk new file mode 100644 index 0000000..d9686a0 Binary files /dev/null and b/OpenDBDiff.Schema.SQLServer.Generates/OpenDBDiff.Schema.SQLServer.Generates.snk differ diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOption.cs b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOption.cs new file mode 100644 index 0000000..7748f52 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOption.cs @@ -0,0 +1,66 @@ +using OpenDBDiff.Schema.Model; +using System; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Options +{ + public class SqlOption : IOption + { + public SqlOption() + { + Defaults = new SqlOptionDefault(); + Ignore = new SqlOptionIgnore(true); + Script = new SqlOptionScript(); + Filters = new SqlOptionFilter(); + Comparison = new SqlOptionComparison(); + } + + public SqlOption(Boolean defaultFilter) + { + Defaults = new SqlOptionDefault(); + Ignore = new SqlOptionIgnore(defaultFilter); + Script = new SqlOptionScript(); + Filters = new SqlOptionFilter(); + Comparison = new SqlOptionComparison(); + } + + public SqlOption(IOption option) + { + Defaults = new SqlOptionDefault(option.Defaults); + Ignore = new SqlOptionIgnore(option.Ignore); + Script = new SqlOptionScript(option.Script); + Filters = new SqlOptionFilter(option.Filters); + Comparison = new SqlOptionComparison(option.Comparison); + } + + public SqlOptionComparison Comparison { get; set; } + + public SqlOptionFilter Filters { get; set; } + + /// + /// Gets or sets the option filter. + /// + /// The option filter. + public SqlOptionIgnore Ignore { get; set; } + + /// + /// Gets or sets the option default. + /// + /// The option default. + public SqlOptionDefault Defaults { get; set; } + + public SqlOptionScript Script { get; set; } + + IOptionFilter IOption.Filters { get { return Filters; } } + IOptionsContainer IOption.Defaults { get { return Defaults; } } + IOptionsContainer IOption.Ignore { get { return Ignore; } } + + IOptionsContainer IOption.Script { get { return Script; } } + + IOptionComparison IOption.Comparison { get { return Comparison; } } + + public string Serialize() + { + return this.ToString(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionComparison.cs b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionComparison.cs new file mode 100644 index 0000000..5f0a90e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionComparison.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Options +{ + public class SqlOptionComparison : Schema.Model.IOptionComparison + { + + public enum CaseSensityOptions + { + Automatic = 0, + CaseInsensity = 1, + CaseSensity = 2 + } + + public SqlOptionComparison() + { + CaseSensityInCode = CaseSensityOptions.CaseInsensity; + IgnoreWhiteSpacesInCode = false; + } + + public SqlOptionComparison(IOptionComparison comparison) + { + this.ReloadComparisonOnUpdate = comparison.ReloadComparisonOnUpdate; + var options = comparison.GetOptions(); + IgnoreWhiteSpacesInCode = bool.Parse(options["IgnoreWhiteSpacesInCode"]); + CaseSensityInCode = (CaseSensityOptions)Enum.Parse(typeof(CaseSensityOptions), options["CaseSensityInCode"], true); + CaseSensityType = (CaseSensityOptions)Enum.Parse(typeof(CaseSensityOptions), options["CaseSensityType"], true); + } + + public bool IgnoreWhiteSpacesInCode { get; set; } + public bool ReloadComparisonOnUpdate { get; set; } + + + public CaseSensityOptions CaseSensityInCode { get; set; } + + public CaseSensityOptions CaseSensityType { get; set; } + + public IDictionary GetOptions() + { + Dictionary options = new Dictionary(); + options.Add("IgnoreWhiteSpacesInCode", IgnoreWhiteSpacesInCode.ToString()); + options.Add("ReloadComparisonOnUpdate", ReloadComparisonOnUpdate.ToString()); + options.Add("CaseSensityInCode", CaseSensityInCode.ToString()); + options.Add("CaseSensityType", CaseSensityType.ToString()); + return options; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionDefault.cs b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionDefault.cs new file mode 100644 index 0000000..8b3e0a8 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionDefault.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Options +{ + public class SqlOptionDefault : Schema.Model.IOptionsContainer + { + private string defaultIntegerValue = "0"; + private string defaultRealValue = "0.0"; + private string defaultTextValue = "''"; + private string defaultDateValue = "getdate()"; + private string defaultVariantValue = "''"; + private string defaultNTextValue = "N''"; + private string defaultBlobValue = "0x"; + private string defaultUniqueValue = "NEWID()"; + private Boolean useDefaultValueIfExists = true; + private string defaultTime = "00:00:00"; + private string defaultXml = ""; + + public SqlOptionDefault(IOptionsContainer optionsContainer) + { + var options = optionsContainer.GetOptions(); + defaultIntegerValue = options["defaultIntegerValue"]; + defaultRealValue = options["defaultRealValue"]; + defaultTextValue = options["defaultTextValue"]; + defaultDateValue = options["defaultDateValue"]; + defaultVariantValue = options["defaultVariantValue"]; + defaultNTextValue = options["defaultNTextValue"]; + defaultBlobValue = options["defaultBlobValue"]; + defaultUniqueValue = options["defaultUniqueValue"]; + useDefaultValueIfExists = bool.Parse(options["useDefaultValueIfExists"]); + defaultTime = options["defaultTime"]; + defaultXml = options["defaultXml"]; + } + + public SqlOptionDefault() + { + } + + public string DefaultXml + { + get { return defaultXml; } + set { defaultXml = value; } + } + + public string DefaultTime + { + get { return defaultTime; } + set { defaultTime = value; } + } + + public IDictionary GetOptions() + { + Dictionary options = new Dictionary(); + options.Add("defaultIntegerValue", defaultIntegerValue); + options.Add("defaultRealValue", defaultRealValue); + options.Add("defaultTextValue", defaultTextValue); + options.Add("defaultDateValue", defaultDateValue); + options.Add("defaultVariantValue", defaultVariantValue); + options.Add("defaultNTextValue", defaultNTextValue); + options.Add("defaultBlobValue", defaultBlobValue); + options.Add("defaultUniqueValue", defaultUniqueValue); + options.Add("useDefaultValueIfExists", useDefaultValueIfExists.ToString()); + options.Add("defaultTime", defaultTime); + options.Add("defaultXml", defaultXml); + return options; + } + /// + /// Gets or sets a value indicating whether use default value if exists. + /// + /// + /// true if use default value if exists; otherwise, false. + /// + public Boolean UseDefaultValueIfExists + { + get { return useDefaultValueIfExists; } + set { useDefaultValueIfExists = value; } + } + + /// + /// Gets or sets the default unique (uniqueidentifier) values. + /// + /// The default unique value. + public string DefaultUniqueValue + { + get { return defaultUniqueValue; } + set { defaultUniqueValue = value; } + } + + /// + /// Gets or sets the default BLOB (varbinary,image, bynary) values. + /// + /// The default BLOB value. + public string DefaultBlobValue + { + get { return defaultBlobValue; } + set { defaultBlobValue = value; } + } + + /// + /// Gets or sets the default Unicode text (nvarchar,nchar,ntext) values. + /// + /// The default N text value. + public string DefaultNTextValue + { + get { return defaultNTextValue; } + set { defaultNTextValue = value; } + } + + /// + /// Gets or sets the default sql_variant values. + /// + /// The default variant value. + public string DefaultVariantValue + { + get { return defaultVariantValue; } + set { defaultVariantValue = value; } + } + + /// + /// Gets or sets the default date (datetime,smalldatetime) values. + /// + /// The default date value. + public string DefaultDateValue + { + get { return defaultDateValue; } + set { defaultDateValue = value; } + } + + /// + /// Gets or sets the default text (varchar,char,text) values. + /// + /// The default text value. + public string DefaultTextValue + { + get { return defaultTextValue; } + set { defaultTextValue = value; } + } + + /// + /// Gets or sets the default real (decimal,money,numeric,float) value. + /// + /// The default real value. + public string DefaultRealValue + { + get { return defaultRealValue; } + set { defaultRealValue = value; } + } + + /// + /// Gets or sets the default integer (int, smallint, bigint, tinyint, bit) value. + /// + /// The default integer value. + public string DefaultIntegerValue + { + get { return defaultIntegerValue; } + set { defaultIntegerValue = value; } + } + + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionFilter.cs b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionFilter.cs new file mode 100644 index 0000000..8206a62 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionFilter.cs @@ -0,0 +1,64 @@ +using OpenDBDiff.Schema.Model; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Options +{ + public class SqlOptionFilter : IOptionFilter + { + public SqlOptionFilter() + { + Items = new List + { + new SqlOptionFilterItem(ObjectType.Table, "dbo.dtproperties"), + new SqlOptionFilterItem(ObjectType.Assembly, "Microsoft.SqlServer.Types"), + new SqlOptionFilterItem(ObjectType.Schema, "db_accessadmin"), + new SqlOptionFilterItem(ObjectType.Schema, "db_backupoperator"), + new SqlOptionFilterItem(ObjectType.Schema, "db_datareader"), + new SqlOptionFilterItem(ObjectType.Schema, "db_datawriter"), + new SqlOptionFilterItem(ObjectType.Schema, "db_ddladmin"), + new SqlOptionFilterItem(ObjectType.Schema, "db_denydatareader"), + new SqlOptionFilterItem(ObjectType.Schema, "db_denydatawriter"), + new SqlOptionFilterItem(ObjectType.Schema, "db_owner"), + new SqlOptionFilterItem(ObjectType.Schema, "db_securityadmin"), + //new SqlOptionFilterItem(ObjectType.Schema, "dbo"), + new SqlOptionFilterItem(ObjectType.Schema, "guest"), + new SqlOptionFilterItem(ObjectType.Schema, "INFORMATION_SCHEMA"), + new SqlOptionFilterItem(ObjectType.Schema, "sys") + }; + } + + public SqlOptionFilter(IOptionFilter optionFilter) + { + Items = new List(); + var options = optionFilter.GetOptions(); + foreach (var pair in options) + { + Items.Add( + new SqlOptionFilterItem( + objectType: (ObjectType)Enum.Parse(typeof(ObjectType), pair.Value, true), + filterPattern: pair.Key + ) + ); + } + } + + public IList Items { get; private set; } + + public IDictionary GetOptions() + { + Dictionary values = new Dictionary(); + for (int i = 0; i < Items.Count; i++) + { + values.Add(Items[i].FilterPattern, Items[i].ObjectType.ToString()); + } + return values; + } + + public bool IsItemIncluded(ISchemaBase item) + { + return !Items.Any(i => i.IsMatch(item)); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionFilterItem.cs b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionFilterItem.cs new file mode 100644 index 0000000..7bc508e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionFilterItem.cs @@ -0,0 +1,110 @@ +using OpenDBDiff.Schema.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Options +{ + public class SqlOptionFilterItem + { + public SqlOptionFilterItem(ObjectType objectType, string filterPattern) + { + this.ObjectType = objectType; + this.FilterPattern = filterPattern; + } + + public ObjectType ObjectType { get; set; } + + public string FilterPattern { get; set; } + + public bool IsMatch(ISchemaBase item) + { + if (item.ObjectType.Equals(this.ObjectType) && ValueSatisfiesCriteria(item.Name, this.FilterPattern)) + return true; + else if (this.IsSchemaMatch(item)) + return true; + else + return false; + } + + private bool IsSchemaMatch(ISchemaBase item) + { + if (item.Owner == null) return false; + return this.ObjectType.Equals(ObjectType.Schema) && ValueSatisfiesCriteria(item.Owner, this.FilterPattern); + } + + private static Lazy>> patternReplacements = + new Lazy>>(() => + { + return new Dictionary> + { + // key: the literal string to match + // value: a tuple: first item: the search pattern, second item: the replacement + { @"~~", new Tuple(@"~~", "~") }, + { @"~*", new Tuple(@"~\*", @"\*") }, + { @"~?", new Tuple(@"~\?", @"\?") }, + { @"?", new Tuple(@"\?", ".?") }, + { @"*", new Tuple(@"\*", ".*") } + }; + }); + + private static bool ValueSatisfiesCriteria(string value, string pattern) + { + if (string.IsNullOrWhiteSpace(value) || string.IsNullOrWhiteSpace(pattern)) return false; + + // if criteria is a regular expression, use regex + if (pattern.IndexOfAny(new[] { '*', '?' }) > -1) + { + var regex = Regex.Replace( + pattern, + "(" + string.Join( + "|", + patternReplacements.Value.Values.Select(t => t.Item1)) + + ")", + m => patternReplacements.Value[m.Value].Item2); + regex = $"^{regex}$"; + + return Regex.IsMatch(value, regex, RegexOptions.IgnoreCase); + } + + // straight string comparison + return string.Equals(value, pattern, StringComparison.OrdinalIgnoreCase); + } + + #region Overrides + + public static bool operator ==(SqlOptionFilterItem x, SqlOptionFilterItem y) + { + return Object.Equals(x, y); + } + + public static bool operator !=(SqlOptionFilterItem x, SqlOptionFilterItem y) + { + return !(x == y); + } + + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + SqlOptionFilterItem fi = obj as SqlOptionFilterItem; + if (fi == null) + { + return false; + } + return this.ObjectType.Equals(fi.ObjectType) && this.FilterPattern.Equals(fi.FilterPattern, StringComparison.OrdinalIgnoreCase); + } + + public override int GetHashCode() + { + long hash = 13; + hash = hash + this.ObjectType.GetHashCode() + this.FilterPattern.ToLowerInvariant().GetHashCode(); + return Convert.ToInt32(hash & 0x7fffffff); + } + + #endregion Overrides + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionIgnore.cs b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionIgnore.cs new file mode 100644 index 0000000..a1c8897 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionIgnore.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections.Generic; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Options +{ + public class SqlOptionIgnore : Schema.Model.IOptionsContainer + { + public SqlOptionIgnore(bool defaultValue) + { + FilterPartitionFunction = true; + FilterPartitionScheme = true; + FilterIndexFilter = true; + FilterIndex = true; + FilterConstraintPK = true; + FilterConstraintFK = true; + FilterConstraintUK = true; + FilterConstraintCheck = true; + FilterIndexFillFactor = true; + FilterIndexIncludeColumns = true; + FilterIndexRowLock = true; + FilterColumnOrder = true; + FilterColumnIdentity = true; + FilterColumnCollation = true; + FilterNotForReplication = true; + FilterUsers = true; + FilterRoles = true; + FilterCLRFunction = true; + FilterCLRTrigger = true; + FilterCLRUDT = true; + FilterCLRStoredProcedure = true; + FilterFullText = true; + FilterFullTextPath = false; + FilterTableLockEscalation = true; + FilterTableChangeTracking = true; + FilterConstraint = defaultValue; + FilterFunction = defaultValue; + FilterStoredProcedure = defaultValue; + FilterView = defaultValue; + FilterTable = defaultValue; + FilterTableOption = defaultValue; + FilterUserDataType = defaultValue; + FilterTrigger = defaultValue; + FilterSchema = defaultValue; + FilterXMLSchema = defaultValue; + FilterTableFileGroup = defaultValue; + FilterExtendedProperties = defaultValue; + FilterDDLTriggers = defaultValue; + FilterSynonyms = defaultValue; + FilterRules = defaultValue; + FilterAssemblies = defaultValue; + } + + public SqlOptionIgnore(IOptionsContainer optionsContainer) + { + var options = optionsContainer.GetOptions(); + FilterPartitionFunction = options["FilterPartitionFunction"]; + FilterPartitionScheme = options["FilterPartitionScheme"]; + FilterIndexFilter = options["FilterIndexFilter"]; + FilterIndex = options["FilterIndex"]; + FilterConstraintPK = options["FilterConstraintPK"]; + FilterConstraintFK = options["FilterConstraintFK"]; + FilterConstraintUK = options["FilterConstraintUK"]; + FilterConstraintCheck = options["FilterConstraintCheck"]; + FilterIndexFillFactor = options["FilterIndexFillFactor"]; + FilterIndexIncludeColumns = options["FilterIndexIncludeColumns"]; + FilterIndexRowLock = options["FilterIndexRowLock"]; + FilterColumnOrder = options["FilterColumnOrder"]; + FilterColumnIdentity = options["FilterColumnIdentity"]; + FilterColumnCollation = options["FilterColumnCollation"]; + FilterNotForReplication = options["FilterNotForReplication"]; + FilterUsers = options["FilterUsers"]; + FilterRoles = options["FilterRoles"]; + FilterCLRFunction = options["FilterCLRFunction"]; + FilterCLRTrigger = options["FilterCLRTrigger"]; + FilterCLRUDT = options["FilterCLRUDT"]; + FilterCLRStoredProcedure = options["FilterCLRStoredProcedure"]; + FilterFullText = options["FilterFullText"]; + FilterFullTextPath = options["FilterFullTextPath"]; + FilterTableLockEscalation = options["FilterTableLockEscalation"]; + FilterTableChangeTracking = options["FilterTableChangeTracking"]; + FilterConstraint = options["FilterConstraint"]; + FilterFunction = options["FilterFunction"]; + FilterStoredProcedure = options["FilterStoredProcedure"]; + FilterView = options["FilterView"]; + FilterTable = options["FilterTable"]; + FilterTableOption = options["FilterTableOption"]; + FilterUserDataType = options["FilterUserDataType"]; + FilterTrigger = options["FilterTrigger"]; + FilterSchema = options["FilterSchema"]; + FilterXMLSchema = options["FilterXMLSchema"]; + FilterTableFileGroup = options["FilterTableFileGroup"]; + FilterExtendedProperties = options["FilterExtendedProperties"]; + FilterDDLTriggers = options["FilterDDLTriggers"]; + FilterSynonyms = options["FilterSynonyms"]; + FilterRules = options["FilterRules"]; + FilterAssemblies = options["FilterAssemblies"]; + + } + + public Boolean FilterTableChangeTracking { get; set; } + + public Boolean FilterTableLockEscalation { get; set; } + + public Boolean FilterFullTextPath { get; set; } + + public Boolean FilterFullText { get; set; } + + public Boolean FilterCLRStoredProcedure { get; set; } + + public Boolean FilterCLRUDT { get; set; } + + public Boolean FilterCLRTrigger { get; set; } + + public Boolean FilterCLRFunction { get; set; } + + public Boolean FilterRoles { get; set; } + + public Boolean FilterUsers { get; set; } + + public Boolean FilterNotForReplication { get; set; } + + public Boolean FilterColumnCollation { get; set; } + + public Boolean FilterColumnIdentity { get; set; } + + public Boolean FilterColumnOrder { get; set; } + + public Boolean FilterIndexRowLock { get; set; } + + public Boolean FilterIndexIncludeColumns { get; set; } + + public Boolean FilterIndexFillFactor { get; set; } + + public Boolean FilterAssemblies { get; set; } + + public Boolean FilterRules { get; set; } + + public Boolean FilterSynonyms { get; set; } + + public Boolean FilterDDLTriggers { get; set; } + + public Boolean FilterExtendedProperties { get; set; } + + public Boolean FilterTableFileGroup { get; set; } + + public Boolean FilterFunction { get; set; } + + public Boolean FilterStoredProcedure { get; set; } + + public Boolean FilterView { get; set; } + + public Boolean FilterTable { get; set; } + + public Boolean FilterTableOption { get; set; } + + public Boolean FilterUserDataType { get; set; } + + public Boolean FilterTrigger { get; set; } + + public Boolean FilterXMLSchema { get; set; } + + public Boolean FilterSchema { get; set; } + + public Boolean FilterConstraint { get; set; } + + public Boolean FilterConstraintCheck { get; set; } + + public Boolean FilterConstraintUK { get; set; } + + public Boolean FilterConstraintFK { get; set; } + + public Boolean FilterConstraintPK { get; set; } + + public Boolean FilterIndex { get; set; } + + public Boolean FilterIndexFilter { get; set; } + + public Boolean FilterPartitionScheme { get; set; } + + public Boolean FilterPartitionFunction { get; set; } + + public IDictionary GetOptions() + { + + Dictionary options = new Dictionary(); + options.Add("FilterPartitionFunction", FilterPartitionFunction); + options.Add("FilterPartitionScheme", FilterPartitionScheme); + options.Add("FilterIndexFilter", FilterIndexFilter); + options.Add("FilterIndex", FilterIndex); + options.Add("FilterConstraintPK", FilterConstraintPK); + options.Add("FilterConstraintFK", FilterConstraintFK); + options.Add("FilterConstraintUK", FilterConstraintUK); + options.Add("FilterConstraintCheck", FilterConstraintCheck); + options.Add("FilterIndexFillFactor", FilterIndexFillFactor); + options.Add("FilterIndexIncludeColumns", FilterIndexIncludeColumns); + options.Add("FilterIndexRowLock", FilterIndexRowLock); + options.Add("FilterColumnOrder", FilterColumnOrder); + options.Add("FilterColumnIdentity", FilterColumnIdentity); + options.Add("FilterColumnCollation", FilterColumnCollation); + options.Add("FilterNotForReplication", FilterNotForReplication); + options.Add("FilterUsers", FilterUsers); + options.Add("FilterRoles", FilterRoles); + options.Add("FilterCLRFunction", FilterCLRFunction); + options.Add("FilterCLRTrigger", FilterCLRTrigger); + options.Add("FilterCLRUDT", FilterCLRUDT); + options.Add("FilterCLRStoredProcedure", FilterCLRStoredProcedure); + options.Add("FilterFullText", FilterFullText); + options.Add("FilterFullTextPath", FilterFullTextPath); + options.Add("FilterTableLockEscalation", FilterTableLockEscalation); + options.Add("FilterTableChangeTracking", FilterTableChangeTracking); + options.Add("FilterConstraint", FilterConstraint); + options.Add("FilterFunction", FilterFunction); + options.Add("FilterStoredProcedure", FilterStoredProcedure); + options.Add("FilterView", FilterView); + options.Add("FilterTable", FilterTable); + options.Add("FilterTableOption", FilterTableOption); + options.Add("FilterUserDataType", FilterUserDataType); + options.Add("FilterTrigger", FilterTrigger); + options.Add("FilterSchema", FilterSchema); + options.Add("FilterXMLSchema", FilterXMLSchema); + options.Add("FilterTableFileGroup", FilterTableFileGroup); + options.Add("FilterExtendedProperties", FilterExtendedProperties); + options.Add("FilterDDLTriggers", FilterDDLTriggers); + options.Add("FilterSynonyms", FilterSynonyms); + options.Add("FilterRules", FilterRules); + options.Add("FilterAssemblies", FilterAssemblies); + return options; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionScript.cs b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionScript.cs new file mode 100644 index 0000000..63b02a5 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Options/SqlOptionScript.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Options +{ + public class SqlOptionScript : Schema.Model.IOptionsContainer + { + private Boolean alterObjectOnSchemaBinding = true; + + public SqlOptionScript() + { + } + + public SqlOptionScript(IOptionsContainer optionsContainer) + { + AlterObjectOnSchemaBinding = optionsContainer.GetOptions()["AlterObjectOnSchemaBinding"]; + } + + public Boolean AlterObjectOnSchemaBinding + { + get { return alterObjectOnSchemaBinding; } + set { alterObjectOnSchemaBinding = value; } + } + + public IDictionary GetOptions() + { + return new Dictionary() { { "AlterObjectOnSchemaBinding", AlterObjectOnSchemaBinding } }; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/Properties/AssemblyInfo.cs b/OpenDBDiff.Schema.SQLServer.Generates/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..8b337f6 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/Properties/AssemblyInfo.cs @@ -0,0 +1,25 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.Schema.SQLServer.Generates")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.Schema.SQLServer.Generates")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("32ac9af6-db93-4354-b69f-6dbc65c70867")] + +[assembly: System.CLSCompliant(true)] diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetAssemblies.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetAssemblies.sql new file mode 100644 index 0000000..f7e5530 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetAssemblies.sql @@ -0,0 +1,16 @@ +select DISTINCT '[' + S2.Name + '].[' + AT.Name + ']' as UDTName, +ISNULL('[' + A2.name + ']','') AS Dependency, +ISNULL('[' + S3.Name + '].[' + A3.name + ']','') AS ObjectDependency, +AF.assembly_id, A.clr_name,A.name,S.name AS Owner, A.permission_set_desc, A.is_visible, content +FROM sys.assemblies A +INNER JOIN sys.assembly_files AF ON AF.assembly_id = A.assembly_id +LEFT JOIN sys.assembly_references AR ON A.assembly_id = AR.referenced_assembly_id +LEFT JOIN sys.assemblies A2 ON A2.assembly_id = AR.assembly_id +LEFT JOIN sys.schemas S1 ON S1.schema_id = A2.principal_id +INNER JOIN sys.schemas S ON S.schema_id = A.principal_id +LEFT JOIN sys.assembly_types AT ON AT.assembly_id = A.assembly_id +LEFT JOIN sys.schemas S2 ON S2.schema_id = AT.schema_id +LEFT JOIN sys.assembly_modules AM ON AM.assembly_id = A.assembly_id +LEFT JOIN sys.objects A3 ON A3.object_id = AM.object_id +LEFT JOIN sys.schemas S3 ON S3.schema_id = A3.schema_id +ORDER BY A.name \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetAssemblyFiles.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetAssemblyFiles.sql new file mode 100644 index 0000000..e765057 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetAssemblyFiles.sql @@ -0,0 +1,4 @@ +select '[' + A.Name + ']' AS Name, AF.content AS FileContent, AF.File_Id AS FileId, AF.Name AS FileName +FROM sys.assemblies A +INNER JOIN sys.assembly_files AF ON AF.assembly_id = A.assembly_id +ORDER BY A.Name \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetDDLTriggers.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetDDLTriggers.sql new file mode 100644 index 0000000..1649a92 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetDDLTriggers.sql @@ -0,0 +1,3 @@ +SELECT OBJECT_DEFINITION(T.object_id) AS Text,T.name,is_disabled,is_not_for_replication,is_instead_of_trigger +FROM sys.triggers T +WHERE T.parent_id = 0 AND T.parent_class = 0 \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetDatabaseFile.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetDatabaseFile.sql new file mode 100644 index 0000000..dc3ba8b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetDatabaseFile.sql @@ -0,0 +1,10 @@ +select file_id, +type, +name, +physical_name, +size, +max_size, +growth, +is_sparse, +is_percent_growth +from sys.database_files WHERE data_space_id = {ID} diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetDefaults.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetDefaults.sql new file mode 100644 index 0000000..5cd113d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetDefaults.sql @@ -0,0 +1,5 @@ +SELECT obj.object_id, Name, SCHEMA_NAME(obj.schema_id) AS Owner, ISNULL(smobj.definition, ssmobj.definition) AS [Definition] from sys.objects obj +LEFT OUTER JOIN sys.sql_modules AS smobj ON smobj.object_id = obj.object_id +LEFT OUTER JOIN sys.system_sql_modules AS ssmobj ON ssmobj.object_id = obj.object_id +where obj.type='D' +return sql; \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetExtendedProperties.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetExtendedProperties.sql new file mode 100644 index 0000000..d045d2a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetExtendedProperties.sql @@ -0,0 +1,9 @@ +SELECT DISTINCT T2.Name as ParentName, S1.name AS OwnerType, T.name AS TypeName, O.type, A.name AS AssemblyName, EP.*,S.name as Owner, O.name AS ObjectName, I1.name AS IndexName FROM sys.extended_properties EP +LEFT JOIN sys.objects O ON O.object_id = EP.major_id +LEFT JOIN sys.schemas S ON S.schema_id = O.schema_id +LEFT JOIN sys.assemblies A ON A.assembly_id = EP.major_id +LEFT JOIN sys.types T ON T.user_type_id = EP.major_id +LEFT JOIN sys.schemas S1 ON S1.schema_id = T.schema_id +LEFT JOIN sys.indexes I1 ON I1.index_id = EP.minor_id AND I1.object_id = O.object_ID AND class = 7 +LEFT JOIN sys.tables T2 ON T2.object_id = O.parent_object_id AND class = 1 +ORDER BY major_id \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetFileGroups.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetFileGroups.sql new file mode 100644 index 0000000..1eae46c --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetFileGroups.sql @@ -0,0 +1,7 @@ +SELECT +name, +data_space_id AS [ID], +is_default, +is_read_only, +type +FROM sys.filegroups ORDER BY name \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetForeignKeys.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetForeignKeys.sql new file mode 100644 index 0000000..89b8f1d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetForeignKeys.sql @@ -0,0 +1,9 @@ +SELECT FK.object_id, C.user_type_id ,FK.parent_object_id,S.Name AS Owner, S2.Name AS ReferenceOwner, C2.Name AS ColumnName, C2.column_id AS ColumnId, C.name AS ColumnRelationalName, C.column_id AS ColumnRelationalId, T.object_id AS TableRelationalId, FK.Parent_object_id AS TableId, T.Name AS TableRelationalName, FK.Name, FK.is_disabled, FK.is_not_for_replication, FK.is_not_trusted, FK.delete_referential_action, FK.update_referential_action +FROM sys.foreign_keys FK +INNER JOIN sys.tables T ON T.object_id = FK.referenced_object_id +INNER JOIN sys.schemas S2 ON S2.schema_id = T.schema_id +INNER JOIN sys.foreign_key_columns FKC ON FKC.constraint_object_id = FK.object_id +INNER JOIN sys.columns C ON C.object_id = FKC.referenced_object_id AND C.column_id = referenced_column_id +INNER JOIN sys.columns C2 ON C2.object_id = FKC.parent_object_id AND C2.column_id = parent_column_id +INNER JOIN sys.schemas S ON S.schema_id = FK.schema_id +ORDER BY FK.parent_object_id, FK.Name, ColumnId \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetFullTextCatalogs.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetFullTextCatalogs.sql new file mode 100644 index 0000000..a9ae1c5 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetFullTextCatalogs.sql @@ -0,0 +1,5 @@ +SELECT S.Name as Owner,F.name AS FileGroupName, fulltext_catalog_id, FC.Name, path, FC.is_default, is_accent_sensitivity_on +FROM + sys.fulltext_catalogs FC + LEFT JOIN sys.filegroups F ON F.data_space_id = FC.data_space_id + INNER JOIN sys.schemas S ON S.schema_id = FC.principal_id \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetParameters.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetParameters.sql new file mode 100644 index 0000000..ec19d01 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetParameters.sql @@ -0,0 +1,4 @@ +select AP.is_output, AP.scale, AP.precision, '[' + SCHEMA_NAME(O.schema_id) + '].['+ O.name + ']' AS ObjectName, AP.name, TT.name AS TypeName, AP.max_length from sys.all_parameters AP +INNER JOIN sys.types TT ON TT.user_type_id = AP.user_type_id +INNER JOIN sys.objects O ON O.object_id = AP.object_id +WHERE type in ('PC', 'FS', 'FT') AND AP.name <> '' ORDER BY O.object_id, AP.parameter_id diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetPartitionFunctions.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetPartitionFunctions.sql new file mode 100644 index 0000000..a8cf2b1 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetPartitionFunctions.sql @@ -0,0 +1,6 @@ +select PRV.value, T.name AS TypeName, PP.max_length, PP.precision, PP.scale, PF.Name, PF.function_id, fanout, boundary_value_on_right AS IsRight +from sys.partition_functions PF +INNER JOIN sys.partition_parameters PP ON PP.function_id = PF.function_id +INNER JOIN sys.types T ON T.system_type_id = PP.system_type_id +INNER JOIN sys.partition_range_values PRV ON PRV.parameter_id = PP.parameter_id and PP.function_id = PRV.function_id +ORDER BY PP.function_id, PRV.parameter_id, boundary_id diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetPartitionSchemes.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetPartitionSchemes.sql new file mode 100644 index 0000000..3cfafd0 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetPartitionSchemes.sql @@ -0,0 +1,6 @@ +select P.data_space_id AS ID, DS.Name AS FileGroupName,P.Name, F.name AS FunctionName +from sys.partition_schemes P +INNER JOIN sys.partition_functions F ON F.function_id = P.function_id +INNER JOIN sys.destination_data_spaces DF ON DF.partition_scheme_id = P.data_space_id +INNER JOIN sys.data_spaces DS ON DS.data_space_id = DF.data_space_id +ORDER BY P.data_space_id, DF.destination_id \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetProcedures.SQLServerAzure10.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetProcedures.SQLServerAzure10.sql new file mode 100644 index 0000000..e6d9d7d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetProcedures.SQLServerAzure10.sql @@ -0,0 +1,5 @@ +SELECT ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, P.type, AF.name AS assembly_name, AM.assembly_class, AM.assembly_id, AM.assembly_method, P.object_id, S.name as owner, P.name as name +FROM sys.procedures P +INNER JOIN sys.schemas S ON S.schema_id = P.schema_id +,(SELECT null as execute_as_principal_id, null as assembly_class, null as assembly_id, null as assembly_method) AS AM, +(SELECT null AS name) AS AF \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetProcedures.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetProcedures.sql new file mode 100644 index 0000000..957b2ba --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetProcedures.sql @@ -0,0 +1,5 @@ +SELECT ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, P.type, AF.name AS assembly_name, AM.assembly_class, AM.assembly_id, AM.assembly_method, P.object_id, S.name as owner, P.name as name +FROM sys.procedures P +INNER JOIN sys.schemas S ON S.schema_id = P.schema_id +LEFT JOIN sys.assembly_modules AM ON AM.object_id = P.object_id +LEFT JOIN sys.assemblies AF ON AF.assembly_id = AM.assembly_id \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetRules.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetRules.sql new file mode 100644 index 0000000..17aa68c --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetRules.sql @@ -0,0 +1,5 @@ + +select obj.object_id, Name, SCHEMA_NAME(obj.schema_id) AS Owner, ISNULL(smobj.definition, ssmobj.definition) AS [Definition] from sys.objects obj +LEFT OUTER JOIN sys.sql_modules AS smobj ON smobj.object_id = obj.object_id +LEFT OUTER JOIN sys.system_sql_modules AS ssmobj ON ssmobj.object_id = obj.object_id +where obj.type='R' \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSQLColumnsDependencies.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSQLColumnsDependencies.sql new file mode 100644 index 0000000..ea83bb3 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSQLColumnsDependencies.sql @@ -0,0 +1,26 @@ +SELECT TT.type, 0 AS IsComputed, T.user_type_id,'[' + S.Name + '].[' + TT.Name + ']' AS TableName, '[' + S.Name + '].[' + TT.Name + '].[' + C.Name + ']' AS ColumnName,'[' + S2.Name + '].[' + T.Name + ']' AS TypeName FROM sys.types T +INNER JOIN sys.columns C ON C.user_type_id = T.user_type_id +INNER JOIN sys.objects TT ON TT.object_id = C.object_id +INNER JOIN sys.schemas S ON S.schema_id = TT.schema_id +INNER JOIN sys.schemas S2 ON S2.schema_id = T.schema_id +WHERE is_user_defined = 1 +UNION +SELECT TT.type, 1 AS IsComputed, T.user_type_id, '[' + S.Name + '].[' + TT.Name + ']' AS TableName, '[' + S.Name + '].[' + TT.Name + '].[' + C2.Name + ']' AS ColumnName, '[' + S2.Name + '].[' + T.Name + ']' AS TypeName FROM sys.types T +INNER JOIN sys.columns C ON C.user_type_id = T.user_type_id +INNER JOIN sys.sql_dependencies DEP ON DEP.referenced_major_id = C.object_id AND DEP.referenced_minor_id = C.column_Id AND DEP.object_id = C.object_id +INNER JOIN sys.columns C2 ON C2.column_id = DEP.column_id AND C2.object_id = DEP.object_id +INNER JOIN sys.objects TT ON TT.object_id = C2.object_id +INNER JOIN sys.schemas S ON S.schema_id = TT.schema_id +INNER JOIN sys.schemas S2 ON S2.schema_id = T.schema_id +WHERE is_user_defined = 1 + +UNION +SELECT TT.type, 0 AS IsComputed, T.user_type_id,'[' + S.Name + '].[' + TT.Name + ']' AS TableName, '[' + S.Name + '].[' + TT.Name + '].[' + C.Name + ']' AS ColumnName,'[' + S2.Name + '].[' + T.Name + ']' AS TypeName from sys.sql_dependencies DEP +INNER JOIN sys.objects TT ON DEP.object_id = TT.object_id +INNER JOIN sys.schemas S ON S.schema_id = TT.schema_id +INNER JOIN sys.parameters C ON C.object_id = TT.object_id AND C.parameter_id = DEP.referenced_minor_id +INNER JOIN sys.types T ON C.user_type_id = T.user_type_id +INNER JOIN sys.schemas S2 ON S2.schema_id = T.schema_id +WHERE is_user_defined = 1 + +ORDER BY IsComputed DESC,T.user_type_id \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSQLXMLSchema.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSQLXMLSchema.sql new file mode 100644 index 0000000..4f0fa31 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSQLXMLSchema.sql @@ -0,0 +1,8 @@ +SELECT +xsc.name, +xsc.xml_collection_id AS [ID], +sch.name AS Owner, +XML_SCHEMA_NAMESPACE(sch.Name, xsc.name) AS Text +FROM sys.xml_schema_collections AS xsc +INNER JOIN sys.schemas AS sch ON xsc.schema_id = sch.schema_id +WHERE xsc.schema_id <> 4 \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSchemas.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSchemas.sql new file mode 100644 index 0000000..3c80dbe --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSchemas.sql @@ -0,0 +1,3 @@ + +SELECT S1.name,S1.schema_id, S2.name AS Owner FROM sys.schemas S1 +INNER JOIN sys.database_principals S2 ON S2.principal_id = S1.principal_id \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSynonyms.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSynonyms.sql new file mode 100644 index 0000000..fc61d3d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetSynonyms.sql @@ -0,0 +1 @@ +SELECT SCHEMA_NAME(schema_id) AS Owner,name,object_id,base_object_name from sys.synonyms ORDER BY Name \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetTextObjectsQuery.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetTextObjectsQuery.sql new file mode 100644 index 0000000..6b1360d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetTextObjectsQuery.sql @@ -0,0 +1,3 @@ +SELECT O.name, O.type, M.object_id, OBJECT_DEFINITION(M.object_id) AS Text FROM sys.sql_modules M +INNER JOIN sys.objects O ON O.object_id = M.object_id +WHERE {FILTER} \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetTriggers.SQLServerAzure10.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetTriggers.SQLServerAzure10.sql new file mode 100644 index 0000000..1e97c0f --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetTriggers.SQLServerAzure10.sql @@ -0,0 +1,11 @@ +SELECT T.object_id, O.type AS ObjectType, ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, AF.name AS assembly_name, AM.assembly_class, AM.assembly_id, AM.assembly_method, T.type, CAST(ISNULL(tei.object_id,0) AS bit) AS IsInsert, CAST(ISNULL(teu.object_id,0) AS bit) AS IsUpdate, CAST(ISNULL(ted.object_id,0) AS bit) AS IsDelete, T.parent_id, S.name AS Owner,T.name,is_disabled,is_not_for_replication,is_instead_of_trigger +FROM sys.triggers T +INNER JOIN sys.objects O ON O.object_id = T.parent_id +INNER JOIN sys.schemas S ON S.schema_id = O.schema_id +LEFT JOIN sys.trigger_events AS tei ON tei.object_id = T.object_id and tei.type=1 +LEFT JOIN sys.trigger_events AS teu ON teu.object_id = T.object_id and teu.type=2 +LEFT JOIN sys.trigger_events AS ted ON ted.object_id = T.object_id and ted.type=3 + +,(SELECT null as execute_as_principal_id, null as assembly_class, null as assembly_id, null as assembly_method) AS AM, +(SELECT null AS name) AS AF +ORDER BY T.parent_id \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetTriggers.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetTriggers.sql new file mode 100644 index 0000000..f07adbe --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetTriggers.sql @@ -0,0 +1,11 @@ +SELECT T.object_id, O.type AS ObjectType, ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, AF.name AS assembly_name, AM.assembly_class, AM.assembly_id, AM.assembly_method, T.type, CAST(ISNULL(tei.object_id,0) AS bit) AS IsInsert, CAST(ISNULL(teu.object_id,0) AS bit) AS IsUpdate, CAST(ISNULL(ted.object_id,0) AS bit) AS IsDelete, T.parent_id, S.name AS Owner,T.name,is_disabled,is_not_for_replication,is_instead_of_trigger +FROM sys.triggers T +INNER JOIN sys.objects O ON O.object_id = T.parent_id +INNER JOIN sys.schemas S ON S.schema_id = O.schema_id +LEFT JOIN sys.trigger_events AS tei ON tei.object_id = T.object_id and tei.type=1 +LEFT JOIN sys.trigger_events AS teu ON teu.object_id = T.object_id and teu.type=2 +LEFT JOIN sys.trigger_events AS ted ON ted.object_id = T.object_id and ted.type=3 + +LEFT JOIN sys.assembly_modules AM ON AM.object_id = T.object_id +LEFT JOIN sys.assemblies AF ON AF.assembly_id = AM.assembly_id +ORDER BY T.parent_id \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetXMLSchemaCollections.sql b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetXMLSchemaCollections.sql new file mode 100644 index 0000000..b9e592d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/GetXMLSchemaCollections.sql @@ -0,0 +1,6 @@ +SELECT O.Type, '[' + S1.Name + '].[' + XS.Name +']' AS XMLName, '[' + S.Name + '].[' + O.Name +']' AS TableName, '[' + S.Name + '].[' + O.Name + '].[' + C.Name + ']' AS ColumnName from sys.columns C +INNER JOIN sys.xml_schema_collections XS ON XS.xml_collection_id = C.xml_collection_id +INNER JOIN sys.objects O ON O.object_id = C.object_id +INNER JOIN sys.schemas S ON S.schema_id = O.schema_id +INNER JOIN sys.schemas S1 ON S1.schema_id = XS.schema_id +ORDER BY XS.xml_collection_id \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/SQLQueryFactory.cs b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/SQLQueryFactory.cs new file mode 100644 index 0000000..496579f --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.Generates/SQLQueries/SQLQueryFactory.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenDBDiff.Schema.SQLServer.Generates.SQLQueries +{ + public static class SQLQueryFactory + { + private static Dictionary queries = new Dictionary(); + + public static string Get(string queryFullName, Model.DatabaseInfo.SQLServerVersion version) + { + return Get($"{queryFullName}.{version}"); + } + + public static string Get(string queryClass) + { + var ns = typeof(SQLQueryFactory).Namespace; + var qualifiedQueryClass = string.Concat(ns, '.', queryClass); + + if (queries.ContainsKey(qualifiedQueryClass)) + { + return queries[qualifiedQueryClass]; + } + else + { + string query = FetchQuery(qualifiedQueryClass); + queries.Add(qualifiedQueryClass, query); + return query; + } + } + + private static string FetchQuery(string queryFullName) + { + string resourceName = queryFullName + ".sql"; + using (System.IO.Stream stream = typeof(SQLQueryFactory).Assembly.GetManifestResourceStream(resourceName)) + { + if (stream == null) throw new InvalidOperationException("The Query " + queryFullName + " cannot be found"); + using (System.IO.StreamReader reader = new System.IO.StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.GeneratesTests/Generates/Util/ByteToHexEncoderTests.cs b/OpenDBDiff.Schema.SQLServer.GeneratesTests/Generates/Util/ByteToHexEncoderTests.cs new file mode 100644 index 0000000..856e049 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.GeneratesTests/Generates/Util/ByteToHexEncoderTests.cs @@ -0,0 +1,19 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenDBDiff.Schema.SQLServer.Generates.Generates.Util; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Generates.Utils.Tests +{ + [TestClass] + public class ByteToHexEncoderTests + { + [TestMethod] + public void EncodesBytesIntoHex() + { + byte[] bytes = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 255 }; + + var hex = ByteToHexEncoder.ByteArrayToHex(bytes); + + Assert.AreEqual("0x000102040810204080FF", hex); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer.GeneratesTests/Model/ColumnsTests.cs b/OpenDBDiff.Schema.SQLServer.GeneratesTests/Model/ColumnsTests.cs new file mode 100644 index 0000000..5ebef80 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.GeneratesTests/Model/ColumnsTests.cs @@ -0,0 +1,237 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Compare; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Model.Tests +{ + [TestClass()] + public class ColumnsTests + { + [TestMethod()] + public void OriginHasExtraColumn_NothingSelected_ShouldDropExtraColumn() + { + int idStorage = 1; + System.Func getId = new Func(()=>++idStorage); + + Database originDatabase = new Database(); + originDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS", + }; + originDatabase.Options = new Options.SqlOption(); + originDatabase.Id = getId(); + Table originTable = new Table(originDatabase); + originTable.Name = "Example"; + originTable.Id = getId(); + var originColumn1 = new Column(originTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var originColumn2 = new Column(originTable) + { + Name = "Test2", + Type = "varchar(20)", + Id = getId() + }; + var originColumn3 = new Column(originTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + originTable.Columns.Add(originColumn1); + originTable.Columns.Add(originColumn3); + originTable.Columns.Add(originColumn2); + originDatabase.Tables.Add(originTable); + + + Database destinationDatabase = new Database(); + destinationDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + destinationDatabase.Id = getId(); + destinationDatabase.Options = new Options.SqlOption(); + Table destinationTable = new Table(destinationDatabase); + destinationTable.Name = "Example"; + destinationTable.Id = getId(); + var destinationColumn1 = new Column(destinationTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var destinationColumn3 = new Column(destinationTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + destinationTable.Columns.Add(destinationColumn1); + destinationTable.Columns.Add(destinationColumn3); + destinationDatabase.Tables.Add(destinationTable); + + + originTable.OriginalTable = (Table)originTable.Clone((Database)originTable.Parent); + new CompareColumns().GenerateDifferences
(originTable.Columns, destinationTable.Columns); + + SQLScriptList sqlList = originTable.ToSqlDiff(new List()); + string sql = sqlList.ToSQL(); + Assert.AreEqual(originColumn2.ToSqlDrop(), sql); + } + [TestMethod()] + public void OriginHasExtraColumn_NotChangedColumnSelected_ShouldBeEmptyScript() + { + int idStorage = 1; + System.Func getId = new Func(() => ++idStorage); + Database originDatabase = new Database(); + originDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + originDatabase.Id = getId(); + originDatabase.Options = new Options.SqlOption(); + Table originTable = new Table(originDatabase); + originTable.Name = "Example"; + originTable.Id = getId(); + var originColumn1 = new Column(originTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var originColumn2 = new Column(originTable) + { + Name = "Test2", + Type = "varchar(20)", + Id = getId() + }; + var originColumn3 = new Column(originTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + originTable.Columns.Add(originColumn1); + originTable.Columns.Add(originColumn3); + originTable.Columns.Add(originColumn2); + originDatabase.Tables.Add(originTable); + + + Database destinationDatabase = new Database(); + destinationDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + destinationDatabase.Id = getId(); + destinationDatabase.Options = new Options.SqlOption(); + Table destinationTable = new Table(destinationDatabase); + destinationTable.Name = "Example"; + destinationTable.Id = getId(); + var destinationColumn1 = new Column(destinationTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var destinationColumn3 = new Column(destinationTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + destinationTable.Columns.Add(destinationColumn1); + destinationTable.Columns.Add(destinationColumn3); + destinationDatabase.Tables.Add(destinationTable); + + + originTable.OriginalTable = (Table)originTable.Clone((Database)originTable.Parent); + new CompareColumns().GenerateDifferences
(originTable.Columns, destinationTable.Columns); + + SQLScriptList sqlList = originTable.ToSqlDiff(new List() { originColumn3 }); + string sql = sqlList.ToSQL(); + Assert.AreEqual("", sql); + } + [TestMethod()] + public void OriginHasExtraColumn_ExtraColumnSelected_ShouldBeDropColumnScript() + { + int idStorage = 1; + System.Func getId = new Func(() => ++idStorage); + Database originDatabase = new Database(); + originDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + originDatabase.Id = getId(); + originDatabase.Options = new Options.SqlOption(); + Table originTable = new Table(originDatabase); + originTable.Name = "Example"; + originTable.Id = getId(); + var originColumn1 = new Column(originTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var originColumn2 = new Column(originTable) + { + Name = "Test2", + Type = "varchar(20)", + Id = getId() + }; + var originColumn3 = new Column(originTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + originTable.Columns.Add(originColumn1); + originTable.Columns.Add(originColumn3); + originTable.Columns.Add(originColumn2); + originDatabase.Tables.Add(originTable); + + + Database destinationDatabase = new Database(); + destinationDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + destinationDatabase.Id = getId(); + destinationDatabase.Options = new Options.SqlOption(); + Table destinationTable = new Table(destinationDatabase); + destinationTable.Name = "Example"; + destinationTable.Id = getId(); + var destinationColumn1 = new Column(destinationTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var destinationColumn3 = new Column(destinationTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + destinationTable.Columns.Add(destinationColumn1); + destinationTable.Columns.Add(destinationColumn3); + destinationDatabase.Tables.Add(destinationTable); + + + originTable.OriginalTable = (Table)originTable.Clone((Database)originTable.Parent); + new CompareColumns().GenerateDifferences
(originTable.Columns, destinationTable.Columns); + + SQLScriptList sqlList = originTable.ToSqlDiff(new List() { originColumn2 }); + string sql = sqlList.ToSQL(); + Assert.AreEqual(originColumn2.ToSqlDrop(), sql); + } + } +} \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.GeneratesTests/OpenDBDiff.Schema.SQLServer.GeneratesTests.csproj b/OpenDBDiff.Schema.SQLServer.GeneratesTests/OpenDBDiff.Schema.SQLServer.GeneratesTests.csproj new file mode 100644 index 0000000..e047b9a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.GeneratesTests/OpenDBDiff.Schema.SQLServer.GeneratesTests.csproj @@ -0,0 +1,102 @@ + + + + Debug + AnyCPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F} + Library + Properties + OpenDBDiff.Schema.SQLServer.GeneratesTests + OpenDBDiff.Schema.SQLServer.GeneratesTests + v4.5.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + + {32AC9AF6-DB93-4354-B69F-6DBC65C70867} + DBDiff.Schema.SQLServer.Generates + + + {406558A0-1B98-4D0E-B8B6-2013700B065A} + DBDiff.Schema + + + + + .editorconfig + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer.GeneratesTests/Properties/AssemblyInfo.cs b/OpenDBDiff.Schema.SQLServer.GeneratesTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4fd694e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer.GeneratesTests/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.Schema.SQLServer.GeneratesTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.Schema.SQLServer.GeneratesTests")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("94f5c91a-6268-41e9-a15e-fa5451bb2b6f")] diff --git a/OpenDBDiff.Schema.SQLServer2005/ClassDiagrams.cd b/OpenDBDiff.Schema.SQLServer2005/ClassDiagrams.cd new file mode 100644 index 0000000..ffe9990 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/ClassDiagrams.cd @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AAIAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAQAAEABA= + Model\Columns.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/AddExclusionPatternForm.Designer.cs b/OpenDBDiff.Schema.SQLServer2005/Front/AddExclusionPatternForm.Designer.cs new file mode 100644 index 0000000..9f981a2 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/AddExclusionPatternForm.Designer.cs @@ -0,0 +1,154 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + partial class AddExclusionPatternForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label2 = new System.Windows.Forms.Label(); + this.cboObjects = new System.Windows.Forms.ComboBox(); + this.txtFilter = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.ApplyButton = new System.Windows.Forms.Button(); + this.CancelFormButton = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.cboObjects); + this.groupBox1.Controls.Add(this.txtFilter); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.ForeColor = System.Drawing.SystemColors.HotTrack; + this.groupBox1.Location = new System.Drawing.Point(7, 3); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(310, 71); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Filter"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.ForeColor = System.Drawing.SystemColors.ControlText; + this.label2.Location = new System.Drawing.Point(7, 43); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(68, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Object Type:"; + // + // cboObjects + // + this.cboObjects.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.cboObjects.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cboObjects.FormattingEnabled = true; + this.cboObjects.Location = new System.Drawing.Point(82, 40); + this.cboObjects.Name = "cboObjects"; + this.cboObjects.Size = new System.Drawing.Size(223, 21); + this.cboObjects.TabIndex = 2; + // + // txtFilter + // + this.txtFilter.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtFilter.Location = new System.Drawing.Point(82, 13); + this.txtFilter.Name = "txtFilter"; + this.txtFilter.Size = new System.Drawing.Size(222, 20); + this.txtFilter.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.ForeColor = System.Drawing.SystemColors.ControlText; + this.label1.Location = new System.Drawing.Point(6, 16); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(69, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Filter Pattern:"; + // + // ApplyButton + // + this.ApplyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.ApplyButton.Location = new System.Drawing.Point(242, 80); + this.ApplyButton.Name = "ApplyButton"; + this.ApplyButton.Size = new System.Drawing.Size(75, 23); + this.ApplyButton.TabIndex = 1; + this.ApplyButton.Text = "Apply"; + this.ApplyButton.UseVisualStyleBackColor = true; + this.ApplyButton.Click += new System.EventHandler(this.ApplyButton_Click); + // + // CancelFormButton + // + this.CancelFormButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.CancelFormButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.CancelFormButton.Location = new System.Drawing.Point(161, 80); + this.CancelFormButton.Name = "CancelFormButton"; + this.CancelFormButton.Size = new System.Drawing.Size(75, 23); + this.CancelFormButton.TabIndex = 2; + this.CancelFormButton.Text = "Cancel"; + this.CancelFormButton.UseVisualStyleBackColor = true; + this.CancelFormButton.Click += new System.EventHandler(this.CancelFormButton_Click); + // + // AddExclusionPatternForm + // + this.AcceptButton = this.ApplyButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.CancelFormButton; + this.ClientSize = new System.Drawing.Size(324, 107); + this.ControlBox = false; + this.Controls.Add(this.CancelFormButton); + this.Controls.Add(this.ApplyButton); + this.Controls.Add(this.groupBox1); + this.Name = "AddExclusionPatternForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Filters"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private GroupBox groupBox1; + private TextBox txtFilter; + private Label label1; + private ComboBox cboObjects; + private Label label2; + private Button ApplyButton; + private Button CancelFormButton; + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/AddExclusionPatternForm.cs b/OpenDBDiff.Schema.SQLServer2005/Front/AddExclusionPatternForm.cs new file mode 100644 index 0000000..11d3574 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/AddExclusionPatternForm.cs @@ -0,0 +1,95 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Options; +using System; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + public partial class AddExclusionPatternForm : Form + { + private SqlOption sqlOption; + private int indexFilter; + + public AddExclusionPatternForm(SqlOption sqlOption) + : this(sqlOption, -1) + { } + + public AddExclusionPatternForm(SqlOption sqlOption, int Index) + { + InitializeComponent(); + + PopulateObjectTypeDropDownList(); + + this.sqlOption = sqlOption; + indexFilter = Index; + if (indexFilter != -1) + { + txtFilter.Text = sqlOption.Filters.Items[indexFilter].FilterPattern; + cboObjects.SelectedValue = sqlOption.Filters.Items[indexFilter].ObjectType; + } + } + + private string GetEnumDescription(Enum value) + { + FieldInfo fi = value.GetType().GetField(value.ToString()); + + DescriptionAttribute[] attributes = + (DescriptionAttribute[])fi.GetCustomAttributes( + typeof(DescriptionAttribute), + false); + + if (attributes != null && + attributes.Length > 0) + return attributes[0].Description; + else + return value.ToString(); + } + + private void PopulateObjectTypeDropDownList() + { + var data = Enum.GetValues(typeof(ObjectType)).Cast() + .Select(ot => new { ObjectType = ot, Description = GetEnumDescription(ot) }) + .OrderBy(a => a.Description) + .ToList(); + + cboObjects.DataSource = data; + cboObjects.DisplayMember = "Description"; + cboObjects.ValueMember = "ObjectType"; + } + + private void CancelFormButton_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void ApplyButton_Click(object sender, EventArgs e) + { + if (cboObjects.SelectedItem == null) + { + MessageBox.Show(this, "All fields are required.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + var fi = new SqlOptionFilterItem((ObjectType)Enum.Parse(typeof(ObjectType), cboObjects.SelectedValue.ToString(), true), txtFilter.Text); + + if (sqlOption.Filters.Items.Contains(fi)) + { + MessageBox.Show(this, string.Format("The list of name filters already includes an entry for text '{0}' of type '{1}'", fi.FilterPattern, fi.ObjectType.ToString()), "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + if (indexFilter == -1) + sqlOption.Filters.Items.Add(fi); + else + { + sqlOption.Filters.Items[indexFilter].FilterPattern = fi.FilterPattern; + sqlOption.Filters.Items[indexFilter].ObjectType = fi.ObjectType; + } + HandlerHelper.RaiseOnChange(); + + this.Close(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/AddExclusionPatternForm.resx b/OpenDBDiff.Schema.SQLServer2005/Front/AddExclusionPatternForm.resx new file mode 100644 index 0000000..d58980a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/AddExclusionPatternForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/HandlerHelper.cs b/OpenDBDiff.Schema.SQLServer2005/Front/HandlerHelper.cs new file mode 100644 index 0000000..6a31af4 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/HandlerHelper.cs @@ -0,0 +1,13 @@ +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + public static class HandlerHelper + { + public delegate void SaveFilterHandler(); + public static event SaveFilterHandler OnChange; + + public static void RaiseOnChange() + { + OnChange?.Invoke(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/SQLServerComparer.cs b/OpenDBDiff.Schema.SQLServer2005/Front/SQLServerComparer.cs new file mode 100644 index 0000000..5281578 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/SQLServerComparer.cs @@ -0,0 +1,26 @@ +using OpenDBDiff.Front; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Generates; +using System; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + public class SQLServerComparer : IDatabaseComparer + { + public IDatabase Compare(IDatabase origin, IDatabase destination) + { + if (origin is Model.Database && destination is Model.Database) + { + return Generate.Compare(origin as Model.Database, destination as Model.Database); + } + else if (!(origin is Model.Database)) + { + throw new NotSupportedException("Origin database type not supported: " + origin.GetType()); + } + else + { + throw new NotSupportedException("Destination database type not supported: " + destination.GetType()); + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/SQLServerGenerator.cs b/OpenDBDiff.Schema.SQLServer2005/Front/SQLServerGenerator.cs new file mode 100644 index 0000000..2f2168e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/SQLServerGenerator.cs @@ -0,0 +1,39 @@ +using OpenDBDiff.Front; +using OpenDBDiff.Schema.Events; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Generates; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + public class SQLServerGenerator : IGenerator + { + private readonly Generate Generate; + + public event ProgressEventHandler.ProgressHandler OnProgress; + + public SQLServerGenerator(string connectionString, IOption option) + { + this.Generate = new Generate() + { + ConnectionString = connectionString, + Options = new Options.SqlOption(option) + }; + this.Generate.OnProgress += new ProgressEventHandler.ProgressHandler(args => + { + if (OnProgress != null) + OnProgress.Invoke(args); + }); + + } + + public int GetMaxValue() + { + return Generate.MaxValue; + } + + public IDatabase Process() + { + return this.Generate.Process(); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/SQLServerProjectHandler.cs b/OpenDBDiff.Schema.SQLServer2005/Front/SQLServerProjectHandler.cs new file mode 100644 index 0000000..fc4910b --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/SQLServerProjectHandler.cs @@ -0,0 +1,151 @@ +using OpenDBDiff.Front; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Options; +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + public class SQLServerProjectHandler : IProjectHandler + { + private SqlServerConnectFront DestinationControl; + private SqlServerConnectFront SourceControl; + private SQLServerGenerator SourceGenerator; + private SQLServerGenerator DestinationGenerator; + + private SqlOption Option; + + public IFront CreateDestinationSelector() + { + this.DestinationControl = new SqlServerConnectFront + { + ServerName = "(local)", + UseWindowsAuthentication = true, + UserName = "sa", + Password = "", + DatabaseName = "" + }; + + this.DestinationControl.Location = new Point(1, 1); + this.DestinationControl.Name = "DestinationControl"; + this.DestinationControl.Anchor = (AnchorStyles)((int)AnchorStyles.Bottom + (int)AnchorStyles.Left + (int)AnchorStyles.Right); + this.DestinationControl.TabIndex = 10; + this.DestinationControl.Text = "Destination database:"; + + return this.DestinationControl; + } + + public IFront CreateSourceSelector() + { + this.SourceControl = new SqlServerConnectFront + { + ServerName = "(local)", + UseWindowsAuthentication = true, + UserName = "sa", + Password = "", + DatabaseName = "" + }; + + SourceControl.Location = new Point(1, 1); + SourceControl.Name = "SourceControl"; + SourceControl.Anchor = (AnchorStyles)((int)AnchorStyles.Bottom + (int)AnchorStyles.Left + (int)AnchorStyles.Right); + SourceControl.TabIndex = 10; + SourceControl.Text = "Source database:"; + + return SourceControl; + } + + public IDatabaseComparer GetDatabaseComparer() + { + return new SQLServerComparer(); + } + + public IGenerator SetDestinationGenerator(string connectionString, IOption options) + { + DestinationGenerator = new SQLServerGenerator(connectionString, options); + return DestinationGenerator; + } + + public IGenerator SetSourceGenerator(string connectionString, IOption options) + { + SourceGenerator = new SQLServerGenerator(connectionString, options); + return SourceGenerator; + } + + public string GetDestinationConnectionString() + { + return DestinationControl.ConnectionString; + } + + public string GetDestinationDatabaseName() + { + return DestinationControl.DatabaseName; + } + + public string GetDestinationServerName() + { + return DestinationControl.ServerName; + } + + public string GetSourceConnectionString() + { + return SourceControl.ConnectionString; + } + + public string GetSourceDatabaseName() + { + return SourceControl.DatabaseName; + } + + public string GetSourceServerName() + { + return SourceControl.ServerName; + } + + public IOption GetDefaultProjectOptions() + { + if (Option == null) + { + Option = new Options.SqlOption(); + } + return Option; + } + + public void SetProjectOptions(IOption option) + { + if (option == null) + { + throw new ArgumentNullException(nameof(option)); + } + else if (!(option is SqlOption)) + { + throw new NotSupportedException($"This project handler only supports {nameof(SqlOption)} options. {option.GetType().Name} not supported"); + } + Option = option as SqlOption; + } + + public OptionControl CreateOptionControl() + { + return new SqlOptionsFront(); + } + + public string GetScriptLanguage() + { + return "mssql"; + } + + public void Unload() + { + this.SourceControl.Dispose(); + this.DestinationControl.Dispose(); + this.SourceControl = null; + this.DestinationControl = null; + } + + public override string ToString() + { + return "SQLServer 2005 or higher"; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/SqlOptionsFront.Designer.cs b/OpenDBDiff.Schema.SQLServer2005/Front/SqlOptionsFront.Designer.cs new file mode 100644 index 0000000..5180fc3 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/SqlOptionsFront.Designer.cs @@ -0,0 +1,1576 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + partial class SqlOptionsFront + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.chkFullTextPath = new System.Windows.Forms.CheckBox(); + this.chkIndexFilter = new System.Windows.Forms.CheckBox(); + this.chkConstraintsCheck = new System.Windows.Forms.CheckBox(); + this.chkConstraintsUK = new System.Windows.Forms.CheckBox(); + this.chkConstraintsFK = new System.Windows.Forms.CheckBox(); + this.chkConstraintsPK = new System.Windows.Forms.CheckBox(); + this.checkBox5 = new System.Windows.Forms.CheckBox(); + this.checkPartitionFunction = new System.Windows.Forms.CheckBox(); + this.checkBox4 = new System.Windows.Forms.CheckBox(); + this.chkCompCLRUDT = new System.Windows.Forms.CheckBox(); + this.chkCompCLRFunctions = new System.Windows.Forms.CheckBox(); + this.chkCompCLRTrigger = new System.Windows.Forms.CheckBox(); + this.chkCompCLRStore = new System.Windows.Forms.CheckBox(); + this.chkIndexRowLock = new System.Windows.Forms.CheckBox(); + this.chkFullText = new System.Windows.Forms.CheckBox(); + this.chkCompRules = new System.Windows.Forms.CheckBox(); + this.chkCompRoles = new System.Windows.Forms.CheckBox(); + this.chkCompUsers = new System.Windows.Forms.CheckBox(); + this.chkIndexIncludeColumns = new System.Windows.Forms.CheckBox(); + this.chkCompTriggersDDL = new System.Windows.Forms.CheckBox(); + this.chkIndexFillFactor = new System.Windows.Forms.CheckBox(); + this.chkTablesColumnOrder = new System.Windows.Forms.CheckBox(); + this.chkCompAssemblys = new System.Windows.Forms.CheckBox(); + this.chkFileGroups = new System.Windows.Forms.CheckBox(); + this.chkTablesColumnIdentity = new System.Windows.Forms.CheckBox(); + this.chkTablesColumnCollation = new System.Windows.Forms.CheckBox(); + this.chkConstraints = new System.Windows.Forms.CheckBox(); + this.chkCompSchemas = new System.Windows.Forms.CheckBox(); + this.chkCompUDT = new System.Windows.Forms.CheckBox(); + this.chkIndex = new System.Windows.Forms.CheckBox(); + this.chkTableOption = new System.Windows.Forms.CheckBox(); + this.chkCompXMLSchemas = new System.Windows.Forms.CheckBox(); + this.chkCompFunciones = new System.Windows.Forms.CheckBox(); + this.chkCompStoredProcedure = new System.Windows.Forms.CheckBox(); + this.chkTables = new System.Windows.Forms.CheckBox(); + this.chkCompTriggers = new System.Windows.Forms.CheckBox(); + this.chkCompVistas = new System.Windows.Forms.CheckBox(); + this.chkCompExtendedProperties = new System.Windows.Forms.CheckBox(); + this.txtXML = new System.Windows.Forms.TextBox(); + this.label10 = new System.Windows.Forms.Label(); + this.txtTime = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); + this.txtVariant = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.txtNText = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.txtBlob = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.txtDate = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.txtText = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.txtDefaultReal = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.txtDefaultInteger = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.gradientPanel6 = new System.Windows.Forms.Panel(); + this.chkIgnoreNotForReplication = new System.Windows.Forms.CheckBox(); + this.gradientPanel5 = new System.Windows.Forms.Panel(); + this.gradientPanel4 = new System.Windows.Forms.Panel(); + this.gradientPanel3 = new System.Windows.Forms.Panel(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + this.gradientPanel2 = new System.Windows.Forms.Panel(); + this.chkTableChangeTracking = new System.Windows.Forms.CheckBox(); + this.chkTableLockEscalation = new System.Windows.Forms.CheckBox(); + this.gradientPanel1 = new System.Windows.Forms.Panel(); + this.label11 = new System.Windows.Forms.Label(); + this.tabPage4 = new System.Windows.Forms.TabPage(); + this.DeleteNameFilterButton = new System.Windows.Forms.Button(); + this.btnAdd = new System.Windows.Forms.Button(); + this.gradientPanel10 = new System.Windows.Forms.Panel(); + this.lstFilters = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.btnApply = new System.Windows.Forms.Button(); + this.gradientPanel9 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.gradientPanel8 = new System.Windows.Forms.Panel(); + this.gradientPanel7 = new System.Windows.Forms.Panel(); + this.label12 = new System.Windows.Forms.Label(); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.optScriptSchemaBindingAlter = new System.Windows.Forms.RadioButton(); + this.optScriptSchemaDrop = new System.Windows.Forms.RadioButton(); + this.gradientPanel16 = new System.Windows.Forms.Panel(); + this.label15 = new System.Windows.Forms.Label(); + this.tabPage5 = new System.Windows.Forms.TabPage(); + this.gradientPanel15 = new System.Windows.Forms.Panel(); + this.chkIgnoreWhiteSpaceInCode = new System.Windows.Forms.CheckBox(); + this.gradientPanel14 = new System.Windows.Forms.Panel(); + this.label14 = new System.Windows.Forms.Label(); + this.gradientPanel13 = new System.Windows.Forms.Panel(); + this.rdoCaseSensityInCode = new System.Windows.Forms.RadioButton(); + this.rdoCaseInsensityInCode = new System.Windows.Forms.RadioButton(); + this.gradientPanel12 = new System.Windows.Forms.Panel(); + this.label13 = new System.Windows.Forms.Label(); + this.gradientPanel11 = new System.Windows.Forms.Panel(); + this.rdoCaseSensitive = new System.Windows.Forms.RadioButton(); + this.rdoCaseAutomatic = new System.Windows.Forms.RadioButton(); + this.rdoCaseInsensitive = new System.Windows.Forms.RadioButton(); + this.chkReloadDB = new System.Windows.Forms.CheckBox(); + this.IncludeSynonymsCheckBox = new System.Windows.Forms.CheckBox(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.gradientPanel6.SuspendLayout(); + this.gradientPanel5.SuspendLayout(); + this.gradientPanel4.SuspendLayout(); + this.gradientPanel3.SuspendLayout(); + this.gradientPanel2.SuspendLayout(); + this.gradientPanel1.SuspendLayout(); + this.tabPage4.SuspendLayout(); + this.gradientPanel10.SuspendLayout(); + this.gradientPanel9.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.gradientPanel8.SuspendLayout(); + this.gradientPanel7.SuspendLayout(); + this.tabPage3.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.gradientPanel16.SuspendLayout(); + this.tabPage5.SuspendLayout(); + this.gradientPanel15.SuspendLayout(); + this.gradientPanel14.SuspendLayout(); + this.gradientPanel13.SuspendLayout(); + this.gradientPanel12.SuspendLayout(); + this.gradientPanel11.SuspendLayout(); + this.SuspendLayout(); + // + // chkFullTextPath + // + this.chkFullTextPath.AutoSize = true; + this.chkFullTextPath.Checked = true; + this.chkFullTextPath.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkFullTextPath.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkFullTextPath.Location = new System.Drawing.Point(28, 44); + this.chkFullTextPath.Name = "chkFullTextPath"; + this.chkFullTextPath.Size = new System.Drawing.Size(85, 17); + this.chkFullTextPath.TabIndex = 36; + this.chkFullTextPath.Text = "Include path"; + this.chkFullTextPath.UseVisualStyleBackColor = true; + // + // chkIndexFilter + // + this.chkIndexFilter.AutoSize = true; + this.chkIndexFilter.Checked = true; + this.chkIndexFilter.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndexFilter.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndexFilter.Location = new System.Drawing.Point(30, 215); + this.chkIndexFilter.Name = "chkIndexFilter"; + this.chkIndexFilter.Size = new System.Drawing.Size(90, 17); + this.chkIndexFilter.TabIndex = 9; + this.chkIndexFilter.Text = "Filter columns"; + this.chkIndexFilter.UseVisualStyleBackColor = true; + // + // chkConstraintsCheck + // + this.chkConstraintsCheck.AutoSize = true; + this.chkConstraintsCheck.Checked = true; + this.chkConstraintsCheck.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraintsCheck.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraintsCheck.Location = new System.Drawing.Point(30, 310); + this.chkConstraintsCheck.Name = "chkConstraintsCheck"; + this.chkConstraintsCheck.Size = new System.Drawing.Size(57, 17); + this.chkConstraintsCheck.TabIndex = 14; + this.chkConstraintsCheck.Text = "Check"; + this.chkConstraintsCheck.UseVisualStyleBackColor = true; + // + // chkConstraintsUK + // + this.chkConstraintsUK.AutoSize = true; + this.chkConstraintsUK.Checked = true; + this.chkConstraintsUK.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraintsUK.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraintsUK.Location = new System.Drawing.Point(30, 291); + this.chkConstraintsUK.Name = "chkConstraintsUK"; + this.chkConstraintsUK.Size = new System.Drawing.Size(80, 17); + this.chkConstraintsUK.TabIndex = 13; + this.chkConstraintsUK.Text = "Unique key"; + this.chkConstraintsUK.UseVisualStyleBackColor = true; + // + // chkConstraintsFK + // + this.chkConstraintsFK.AutoSize = true; + this.chkConstraintsFK.Checked = true; + this.chkConstraintsFK.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraintsFK.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraintsFK.Location = new System.Drawing.Point(30, 272); + this.chkConstraintsFK.Name = "chkConstraintsFK"; + this.chkConstraintsFK.Size = new System.Drawing.Size(81, 17); + this.chkConstraintsFK.TabIndex = 12; + this.chkConstraintsFK.Text = "Foreign key"; + this.chkConstraintsFK.UseVisualStyleBackColor = true; + // + // chkConstraintsPK + // + this.chkConstraintsPK.AutoSize = true; + this.chkConstraintsPK.Checked = true; + this.chkConstraintsPK.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraintsPK.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraintsPK.Location = new System.Drawing.Point(30, 253); + this.chkConstraintsPK.Name = "chkConstraintsPK"; + this.chkConstraintsPK.Size = new System.Drawing.Size(80, 17); + this.chkConstraintsPK.TabIndex = 11; + this.chkConstraintsPK.Text = "Primary key"; + this.chkConstraintsPK.UseVisualStyleBackColor = true; + // + // checkBox5 + // + this.checkBox5.AutoSize = true; + this.checkBox5.Checked = true; + this.checkBox5.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox5.ForeColor = System.Drawing.SystemColors.ControlText; + this.checkBox5.Location = new System.Drawing.Point(13, 75); + this.checkBox5.Name = "checkBox5"; + this.checkBox5.Size = new System.Drawing.Size(109, 17); + this.checkBox5.TabIndex = 27; + this.checkBox5.Text = "Partition schemas"; + this.checkBox5.UseVisualStyleBackColor = true; + // + // checkPartitionFunction + // + this.checkPartitionFunction.AutoSize = true; + this.checkPartitionFunction.Checked = true; + this.checkPartitionFunction.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkPartitionFunction.ForeColor = System.Drawing.SystemColors.ControlText; + this.checkPartitionFunction.Location = new System.Drawing.Point(13, 52); + this.checkPartitionFunction.Name = "checkPartitionFunction"; + this.checkPartitionFunction.Size = new System.Drawing.Size(110, 17); + this.checkPartitionFunction.TabIndex = 26; + this.checkPartitionFunction.Text = "Partition functions"; + this.checkPartitionFunction.UseVisualStyleBackColor = true; + // + // checkBox4 + // + this.checkBox4.AutoSize = true; + this.checkBox4.Checked = true; + this.checkBox4.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox4.ForeColor = System.Drawing.SystemColors.ControlText; + this.checkBox4.Location = new System.Drawing.Point(28, 27); + this.checkBox4.Name = "checkBox4"; + this.checkBox4.Size = new System.Drawing.Size(103, 17); + this.checkBox4.TabIndex = 35; + this.checkBox4.Text = "CLR aggregates"; + this.checkBox4.UseVisualStyleBackColor = true; + // + // chkCompCLRUDT + // + this.chkCompCLRUDT.AutoSize = true; + this.chkCompCLRUDT.Checked = true; + this.chkCompCLRUDT.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompCLRUDT.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompCLRUDT.Location = new System.Drawing.Point(28, 84); + this.chkCompCLRUDT.Name = "chkCompCLRUDT"; + this.chkCompCLRUDT.Size = new System.Drawing.Size(122, 17); + this.chkCompCLRUDT.TabIndex = 34; + this.chkCompCLRUDT.Text = "CLR user data types"; + this.chkCompCLRUDT.UseVisualStyleBackColor = true; + // + // chkCompCLRFunctions + // + this.chkCompCLRFunctions.AutoSize = true; + this.chkCompCLRFunctions.Checked = true; + this.chkCompCLRFunctions.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompCLRFunctions.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompCLRFunctions.Location = new System.Drawing.Point(28, 46); + this.chkCompCLRFunctions.Name = "chkCompCLRFunctions"; + this.chkCompCLRFunctions.Size = new System.Drawing.Size(93, 17); + this.chkCompCLRFunctions.TabIndex = 33; + this.chkCompCLRFunctions.Text = "CLR functions"; + this.chkCompCLRFunctions.UseVisualStyleBackColor = true; + // + // chkCompCLRTrigger + // + this.chkCompCLRTrigger.AutoSize = true; + this.chkCompCLRTrigger.Checked = true; + this.chkCompCLRTrigger.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompCLRTrigger.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompCLRTrigger.Location = new System.Drawing.Point(28, 103); + this.chkCompCLRTrigger.Name = "chkCompCLRTrigger"; + this.chkCompCLRTrigger.Size = new System.Drawing.Size(84, 17); + this.chkCompCLRTrigger.TabIndex = 32; + this.chkCompCLRTrigger.Text = "CLR triggers"; + this.chkCompCLRTrigger.UseVisualStyleBackColor = true; + // + // chkCompCLRStore + // + this.chkCompCLRStore.AutoSize = true; + this.chkCompCLRStore.Checked = true; + this.chkCompCLRStore.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompCLRStore.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompCLRStore.Location = new System.Drawing.Point(28, 65); + this.chkCompCLRStore.Name = "chkCompCLRStore"; + this.chkCompCLRStore.Size = new System.Drawing.Size(135, 17); + this.chkCompCLRStore.TabIndex = 31; + this.chkCompCLRStore.Text = "CLR stored procedures"; + this.chkCompCLRStore.UseVisualStyleBackColor = true; + // + // chkIndexRowLock + // + this.chkIndexRowLock.AutoSize = true; + this.chkIndexRowLock.Checked = true; + this.chkIndexRowLock.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndexRowLock.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndexRowLock.Location = new System.Drawing.Point(30, 158); + this.chkIndexRowLock.Name = "chkIndexRowLock"; + this.chkIndexRowLock.Size = new System.Drawing.Size(76, 17); + this.chkIndexRowLock.TabIndex = 6; + this.chkIndexRowLock.Text = "Row locks"; + this.chkIndexRowLock.UseVisualStyleBackColor = true; + // + // chkFullText + // + this.chkFullText.AutoSize = true; + this.chkFullText.Checked = true; + this.chkFullText.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkFullText.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkFullText.Location = new System.Drawing.Point(10, 25); + this.chkFullText.Name = "chkFullText"; + this.chkFullText.Size = new System.Drawing.Size(62, 17); + this.chkFullText.TabIndex = 29; + this.chkFullText.Text = "Full text"; + this.chkFullText.UseVisualStyleBackColor = true; + this.chkFullText.CheckedChanged += new System.EventHandler(this.chkFullText_CheckedChanged); + // + // chkCompRules + // + this.chkCompRules.AutoSize = true; + this.chkCompRules.Checked = true; + this.chkCompRules.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompRules.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompRules.Location = new System.Drawing.Point(13, 98); + this.chkCompRules.Name = "chkCompRules"; + this.chkCompRules.Size = new System.Drawing.Size(53, 17); + this.chkCompRules.TabIndex = 22; + this.chkCompRules.Text = "Rules"; + this.chkCompRules.UseVisualStyleBackColor = true; + // + // chkCompRoles + // + this.chkCompRoles.AutoSize = true; + this.chkCompRoles.Checked = true; + this.chkCompRoles.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompRoles.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompRoles.Location = new System.Drawing.Point(10, 82); + this.chkCompRoles.Name = "chkCompRoles"; + this.chkCompRoles.Size = new System.Drawing.Size(53, 17); + this.chkCompRoles.TabIndex = 28; + this.chkCompRoles.Text = "Roles"; + this.chkCompRoles.UseVisualStyleBackColor = true; + // + // chkCompUsers + // + this.chkCompUsers.AutoSize = true; + this.chkCompUsers.Checked = true; + this.chkCompUsers.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompUsers.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompUsers.Location = new System.Drawing.Point(10, 63); + this.chkCompUsers.Name = "chkCompUsers"; + this.chkCompUsers.Size = new System.Drawing.Size(53, 17); + this.chkCompUsers.TabIndex = 23; + this.chkCompUsers.Text = "Users"; + this.chkCompUsers.UseVisualStyleBackColor = true; + // + // chkIndexIncludeColumns + // + this.chkIndexIncludeColumns.AutoSize = true; + this.chkIndexIncludeColumns.Checked = true; + this.chkIndexIncludeColumns.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndexIncludeColumns.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndexIncludeColumns.Location = new System.Drawing.Point(30, 196); + this.chkIndexIncludeColumns.Name = "chkIndexIncludeColumns"; + this.chkIndexIncludeColumns.Size = new System.Drawing.Size(103, 17); + this.chkIndexIncludeColumns.TabIndex = 8; + this.chkIndexIncludeColumns.Text = "Include columns"; + this.chkIndexIncludeColumns.UseVisualStyleBackColor = true; + // + // chkCompTriggersDDL + // + this.chkCompTriggersDDL.AutoSize = true; + this.chkCompTriggersDDL.Checked = true; + this.chkCompTriggersDDL.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompTriggersDDL.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompTriggersDDL.Location = new System.Drawing.Point(13, 6); + this.chkCompTriggersDDL.Name = "chkCompTriggersDDL"; + this.chkCompTriggersDDL.Size = new System.Drawing.Size(85, 17); + this.chkCompTriggersDDL.TabIndex = 19; + this.chkCompTriggersDDL.Text = "DDL triggers"; + this.chkCompTriggersDDL.UseVisualStyleBackColor = true; + // + // chkIndexFillFactor + // + this.chkIndexFillFactor.AutoSize = true; + this.chkIndexFillFactor.Checked = true; + this.chkIndexFillFactor.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndexFillFactor.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndexFillFactor.Location = new System.Drawing.Point(30, 177); + this.chkIndexFillFactor.Name = "chkIndexFillFactor"; + this.chkIndexFillFactor.Size = new System.Drawing.Size(68, 17); + this.chkIndexFillFactor.TabIndex = 7; + this.chkIndexFillFactor.Text = "Fill factor"; + this.chkIndexFillFactor.UseVisualStyleBackColor = true; + // + // chkTablesColumnOrder + // + this.chkTablesColumnOrder.AutoSize = true; + this.chkTablesColumnOrder.Checked = true; + this.chkTablesColumnOrder.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTablesColumnOrder.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTablesColumnOrder.Location = new System.Drawing.Point(30, 44); + this.chkTablesColumnOrder.Name = "chkTablesColumnOrder"; + this.chkTablesColumnOrder.Size = new System.Drawing.Size(88, 17); + this.chkTablesColumnOrder.TabIndex = 3; + this.chkTablesColumnOrder.Text = "Column order"; + this.chkTablesColumnOrder.UseVisualStyleBackColor = true; + // + // chkCompAssemblys + // + this.chkCompAssemblys.AutoSize = true; + this.chkCompAssemblys.Checked = true; + this.chkCompAssemblys.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompAssemblys.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.chkCompAssemblys.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompAssemblys.Location = new System.Drawing.Point(10, 8); + this.chkCompAssemblys.Name = "chkCompAssemblys"; + this.chkCompAssemblys.Size = new System.Drawing.Size(88, 17); + this.chkCompAssemblys.TabIndex = 30; + this.chkCompAssemblys.Text = "Assemblies"; + this.chkCompAssemblys.UseVisualStyleBackColor = true; + this.chkCompAssemblys.CheckedChanged += new System.EventHandler(this.chkCompAssemblys_CheckedChanged); + // + // chkFileGroups + // + this.chkFileGroups.AutoSize = true; + this.chkFileGroups.Checked = true; + this.chkFileGroups.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkFileGroups.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkFileGroups.Location = new System.Drawing.Point(10, 6); + this.chkFileGroups.Name = "chkFileGroups"; + this.chkFileGroups.Size = new System.Drawing.Size(77, 17); + this.chkFileGroups.TabIndex = 25; + this.chkFileGroups.Text = "File groups"; + this.chkFileGroups.UseVisualStyleBackColor = true; + // + // chkTablesColumnIdentity + // + this.chkTablesColumnIdentity.AutoSize = true; + this.chkTablesColumnIdentity.Checked = true; + this.chkTablesColumnIdentity.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTablesColumnIdentity.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTablesColumnIdentity.Location = new System.Drawing.Point(30, 63); + this.chkTablesColumnIdentity.Name = "chkTablesColumnIdentity"; + this.chkTablesColumnIdentity.Size = new System.Drawing.Size(97, 17); + this.chkTablesColumnIdentity.TabIndex = 2; + this.chkTablesColumnIdentity.Text = "Identity options"; + this.chkTablesColumnIdentity.UseVisualStyleBackColor = true; + // + // chkTablesColumnCollation + // + this.chkTablesColumnCollation.AutoSize = true; + this.chkTablesColumnCollation.Checked = true; + this.chkTablesColumnCollation.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTablesColumnCollation.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTablesColumnCollation.Location = new System.Drawing.Point(30, 25); + this.chkTablesColumnCollation.Name = "chkTablesColumnCollation"; + this.chkTablesColumnCollation.Size = new System.Drawing.Size(103, 17); + this.chkTablesColumnCollation.TabIndex = 1; + this.chkTablesColumnCollation.Text = "Column collation"; + this.chkTablesColumnCollation.UseVisualStyleBackColor = true; + // + // chkConstraints + // + this.chkConstraints.AutoSize = true; + this.chkConstraints.Checked = true; + this.chkConstraints.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraints.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.chkConstraints.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraints.Location = new System.Drawing.Point(10, 234); + this.chkConstraints.Name = "chkConstraints"; + this.chkConstraints.Size = new System.Drawing.Size(89, 17); + this.chkConstraints.TabIndex = 10; + this.chkConstraints.Text = "Constraints"; + this.chkConstraints.UseVisualStyleBackColor = true; + this.chkConstraints.CheckedChanged += new System.EventHandler(this.chkConstraints_CheckedChanged); + // + // chkCompSchemas + // + this.chkCompSchemas.AutoSize = true; + this.chkCompSchemas.Checked = true; + this.chkCompSchemas.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompSchemas.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompSchemas.Location = new System.Drawing.Point(10, 101); + this.chkCompSchemas.Name = "chkCompSchemas"; + this.chkCompSchemas.Size = new System.Drawing.Size(70, 17); + this.chkCompSchemas.TabIndex = 24; + this.chkCompSchemas.Text = "Schemas"; + this.chkCompSchemas.UseVisualStyleBackColor = true; + // + // chkCompUDT + // + this.chkCompUDT.AutoSize = true; + this.chkCompUDT.Checked = true; + this.chkCompUDT.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompUDT.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompUDT.Location = new System.Drawing.Point(13, 190); + this.chkCompUDT.Name = "chkCompUDT"; + this.chkCompUDT.Size = new System.Drawing.Size(100, 17); + this.chkCompUDT.TabIndex = 20; + this.chkCompUDT.Text = "User data types"; + this.chkCompUDT.UseVisualStyleBackColor = true; + // + // chkIndex + // + this.chkIndex.AutoSize = true; + this.chkIndex.Checked = true; + this.chkIndex.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndex.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.chkIndex.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndex.Location = new System.Drawing.Point(10, 139); + this.chkIndex.Name = "chkIndex"; + this.chkIndex.Size = new System.Drawing.Size(70, 17); + this.chkIndex.TabIndex = 5; + this.chkIndex.Text = "Indexes"; + this.chkIndex.UseVisualStyleBackColor = true; + this.chkIndex.CheckedChanged += new System.EventHandler(this.chkCompIndices_CheckedChanged); + // + // chkTableOption + // + this.chkTableOption.AutoSize = true; + this.chkTableOption.Checked = true; + this.chkTableOption.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTableOption.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTableOption.Location = new System.Drawing.Point(30, 82); + this.chkTableOption.Name = "chkTableOption"; + this.chkTableOption.Size = new System.Drawing.Size(90, 17); + this.chkTableOption.TabIndex = 4; + this.chkTableOption.Text = "Table options"; + this.chkTableOption.UseVisualStyleBackColor = true; + // + // chkCompXMLSchemas + // + this.chkCompXMLSchemas.AutoSize = true; + this.chkCompXMLSchemas.Checked = true; + this.chkCompXMLSchemas.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompXMLSchemas.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompXMLSchemas.Location = new System.Drawing.Point(13, 236); + this.chkCompXMLSchemas.Name = "chkCompXMLSchemas"; + this.chkCompXMLSchemas.Size = new System.Drawing.Size(93, 17); + this.chkCompXMLSchemas.TabIndex = 21; + this.chkCompXMLSchemas.Text = "XML schemas"; + this.chkCompXMLSchemas.UseVisualStyleBackColor = true; + // + // chkCompFunciones + // + this.chkCompFunciones.AutoSize = true; + this.chkCompFunciones.Checked = true; + this.chkCompFunciones.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompFunciones.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompFunciones.Location = new System.Drawing.Point(13, 29); + this.chkCompFunciones.Name = "chkCompFunciones"; + this.chkCompFunciones.Size = new System.Drawing.Size(72, 17); + this.chkCompFunciones.TabIndex = 15; + this.chkCompFunciones.Text = "Functions"; + this.chkCompFunciones.UseVisualStyleBackColor = true; + // + // chkCompStoredProcedure + // + this.chkCompStoredProcedure.AutoSize = true; + this.chkCompStoredProcedure.Checked = true; + this.chkCompStoredProcedure.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompStoredProcedure.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompStoredProcedure.Location = new System.Drawing.Point(13, 121); + this.chkCompStoredProcedure.Name = "chkCompStoredProcedure"; + this.chkCompStoredProcedure.Size = new System.Drawing.Size(113, 17); + this.chkCompStoredProcedure.TabIndex = 16; + this.chkCompStoredProcedure.Text = "Stored procedures"; + this.chkCompStoredProcedure.UseVisualStyleBackColor = true; + // + // chkTables + // + this.chkTables.AutoSize = true; + this.chkTables.Checked = true; + this.chkTables.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTables.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.chkTables.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTables.Location = new System.Drawing.Point(10, 6); + this.chkTables.Name = "chkTables"; + this.chkTables.Size = new System.Drawing.Size(64, 17); + this.chkTables.TabIndex = 0; + this.chkTables.Text = "Tables"; + this.chkTables.UseVisualStyleBackColor = true; + this.chkTables.CheckedChanged += new System.EventHandler(this.chkCompTablas_CheckedChanged); + // + // chkCompTriggers + // + this.chkCompTriggers.AutoSize = true; + this.chkCompTriggers.Checked = true; + this.chkCompTriggers.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompTriggers.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompTriggers.Location = new System.Drawing.Point(13, 167); + this.chkCompTriggers.Name = "chkCompTriggers"; + this.chkCompTriggers.Size = new System.Drawing.Size(64, 17); + this.chkCompTriggers.TabIndex = 18; + this.chkCompTriggers.Text = "Triggers"; + this.chkCompTriggers.UseVisualStyleBackColor = true; + // + // chkCompVistas + // + this.chkCompVistas.AutoSize = true; + this.chkCompVistas.Checked = true; + this.chkCompVistas.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompVistas.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompVistas.Location = new System.Drawing.Point(13, 213); + this.chkCompVistas.Name = "chkCompVistas"; + this.chkCompVistas.Size = new System.Drawing.Size(54, 17); + this.chkCompVistas.TabIndex = 17; + this.chkCompVistas.Text = "Views"; + this.chkCompVistas.UseVisualStyleBackColor = true; + // + // chkCompExtendedProperties + // + this.chkCompExtendedProperties.AutoSize = true; + this.chkCompExtendedProperties.Checked = true; + this.chkCompExtendedProperties.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompExtendedProperties.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompExtendedProperties.Location = new System.Drawing.Point(177, 7); + this.chkCompExtendedProperties.Name = "chkCompExtendedProperties"; + this.chkCompExtendedProperties.Size = new System.Drawing.Size(120, 17); + this.chkCompExtendedProperties.TabIndex = 1; + this.chkCompExtendedProperties.Text = "Extended properties"; + this.chkCompExtendedProperties.UseVisualStyleBackColor = true; + // + // txtXML + // + this.txtXML.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtXML.Location = new System.Drawing.Point(16, 257); + this.txtXML.Name = "txtXML"; + this.txtXML.Size = new System.Drawing.Size(388, 20); + this.txtXML.TabIndex = 18; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.ForeColor = System.Drawing.SystemColors.ControlText; + this.label10.Location = new System.Drawing.Point(13, 241); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(29, 13); + this.label10.TabIndex = 17; + this.label10.Text = "XML"; + // + // txtTime + // + this.txtTime.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtTime.Location = new System.Drawing.Point(268, 116); + this.txtTime.Name = "txtTime"; + this.txtTime.Size = new System.Drawing.Size(237, 20); + this.txtTime.TabIndex = 16; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.ForeColor = System.Drawing.SystemColors.ControlText; + this.label9.Location = new System.Drawing.Point(268, 100); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(26, 13); + this.label9.TabIndex = 15; + this.label9.Text = "time"; + // + // txtVariant + // + this.txtVariant.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtVariant.Location = new System.Drawing.Point(16, 209); + this.txtVariant.Name = "txtVariant"; + this.txtVariant.Size = new System.Drawing.Size(388, 20); + this.txtVariant.TabIndex = 14; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.ForeColor = System.Drawing.SystemColors.ControlText; + this.label8.Location = new System.Drawing.Point(13, 193); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(58, 13); + this.label8.TabIndex = 13; + this.label8.Text = "sql_variant"; + // + // txtNText + // + this.txtNText.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtNText.Location = new System.Drawing.Point(268, 68); + this.txtNText.Name = "txtNText"; + this.txtNText.Size = new System.Drawing.Size(237, 20); + this.txtNText.TabIndex = 12; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.ForeColor = System.Drawing.SystemColors.ControlText; + this.label7.Location = new System.Drawing.Point(268, 52); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(184, 13); + this.label7.TabIndex = 11; + this.label7.Text = "nchar, nvarchar, nvarchar(max), ntext"; + // + // txtBlob + // + this.txtBlob.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtBlob.Location = new System.Drawing.Point(16, 164); + this.txtBlob.Name = "txtBlob"; + this.txtBlob.Size = new System.Drawing.Size(388, 20); + this.txtBlob.TabIndex = 10; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.ForeColor = System.Drawing.SystemColors.ControlText; + this.label6.Location = new System.Drawing.Point(13, 148); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(192, 13); + this.label6.TabIndex = 9; + this.label6.Text = "binary, image, varbinary, varbinary(max)"; + // + // txtDate + // + this.txtDate.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtDate.Location = new System.Drawing.Point(16, 116); + this.txtDate.Name = "txtDate"; + this.txtDate.Size = new System.Drawing.Size(237, 20); + this.txtDate.TabIndex = 8; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.ForeColor = System.Drawing.SystemColors.ControlText; + this.label5.Location = new System.Drawing.Point(13, 100); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(240, 13); + this.label5.TabIndex = 7; + this.label5.Text = "datetime, smalldatetime, datetime2, datetimeoffset"; + // + // txtText + // + this.txtText.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtText.Location = new System.Drawing.Point(16, 68); + this.txtText.Name = "txtText"; + this.txtText.Size = new System.Drawing.Size(237, 20); + this.txtText.TabIndex = 6; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.ForeColor = System.Drawing.SystemColors.ControlText; + this.label4.Location = new System.Drawing.Point(13, 52); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(160, 13); + this.label4.TabIndex = 5; + this.label4.Text = "char, varchar, varchar(max), text"; + // + // txtDefaultReal + // + this.txtDefaultReal.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtDefaultReal.Location = new System.Drawing.Point(268, 25); + this.txtDefaultReal.Name = "txtDefaultReal"; + this.txtDefaultReal.Size = new System.Drawing.Size(237, 20); + this.txtDefaultReal.TabIndex = 4; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.ForeColor = System.Drawing.SystemColors.ControlText; + this.label3.Location = new System.Drawing.Point(265, 9); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(232, 13); + this.label3.TabIndex = 3; + this.label3.Text = "float, real, numeric, decimal, money, smallmoney"; + // + // txtDefaultInteger + // + this.txtDefaultInteger.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtDefaultInteger.Location = new System.Drawing.Point(16, 25); + this.txtDefaultInteger.Name = "txtDefaultInteger"; + this.txtDefaultInteger.Size = new System.Drawing.Size(237, 20); + this.txtDefaultInteger.TabIndex = 2; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.ForeColor = System.Drawing.SystemColors.ControlText; + this.label2.Location = new System.Drawing.Point(13, 9); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(160, 13); + this.label2.TabIndex = 1; + this.label2.Text = "integer, smallint, bigint, tinyint, bit"; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage4); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Controls.Add(this.tabPage5); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 0); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(545, 442); + this.tabControl1.TabIndex = 2; + // + // tabPage1 + // + this.tabPage1.BackColor = System.Drawing.Color.White; + this.tabPage1.Controls.Add(this.gradientPanel6); + this.tabPage1.Controls.Add(this.gradientPanel5); + this.tabPage1.Controls.Add(this.gradientPanel4); + this.tabPage1.Controls.Add(this.gradientPanel3); + this.tabPage1.Controls.Add(this.gradientPanel2); + this.tabPage1.Controls.Add(this.gradientPanel1); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Margin = new System.Windows.Forms.Padding(0); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(537, 416); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "Filter by type"; + // + // gradientPanel6 + // + this.gradientPanel6.Controls.Add(this.chkIgnoreNotForReplication); + this.gradientPanel6.Controls.Add(this.chkCompExtendedProperties); + this.gradientPanel6.Location = new System.Drawing.Point(5, 377); + this.gradientPanel6.Name = "gradientPanel6"; + this.gradientPanel6.Size = new System.Drawing.Size(525, 33); + this.gradientPanel6.TabIndex = 7; + // + // chkIgnoreNotForReplication + // + this.chkIgnoreNotForReplication.AutoSize = true; + this.chkIgnoreNotForReplication.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIgnoreNotForReplication.Location = new System.Drawing.Point(12, 7); + this.chkIgnoreNotForReplication.Name = "chkIgnoreNotForReplication"; + this.chkIgnoreNotForReplication.Size = new System.Drawing.Size(140, 17); + this.chkIgnoreNotForReplication.TabIndex = 0; + this.chkIgnoreNotForReplication.Text = "Ignore not for replication"; + this.chkIgnoreNotForReplication.UseVisualStyleBackColor = true; + // + // gradientPanel5 + // + this.gradientPanel5.Controls.Add(this.IncludeSynonymsCheckBox); + this.gradientPanel5.Controls.Add(this.checkBox5); + this.gradientPanel5.Controls.Add(this.chkCompFunciones); + this.gradientPanel5.Controls.Add(this.checkPartitionFunction); + this.gradientPanel5.Controls.Add(this.chkCompVistas); + this.gradientPanel5.Controls.Add(this.chkCompRules); + this.gradientPanel5.Controls.Add(this.chkCompTriggers); + this.gradientPanel5.Controls.Add(this.chkCompTriggersDDL); + this.gradientPanel5.Controls.Add(this.chkCompStoredProcedure); + this.gradientPanel5.Controls.Add(this.chkCompUDT); + this.gradientPanel5.Controls.Add(this.chkCompXMLSchemas); + this.gradientPanel5.Location = new System.Drawing.Point(359, 33); + this.gradientPanel5.Name = "gradientPanel5"; + this.gradientPanel5.Size = new System.Drawing.Size(171, 338); + this.gradientPanel5.TabIndex = 6; + // + // gradientPanel4 + // + this.gradientPanel4.Controls.Add(this.chkCompCLRStore); + this.gradientPanel4.Controls.Add(this.chkCompAssemblys); + this.gradientPanel4.Controls.Add(this.checkBox4); + this.gradientPanel4.Controls.Add(this.chkCompCLRTrigger); + this.gradientPanel4.Controls.Add(this.chkCompCLRUDT); + this.gradientPanel4.Controls.Add(this.chkCompCLRFunctions); + this.gradientPanel4.Location = new System.Drawing.Point(182, 176); + this.gradientPanel4.Name = "gradientPanel4"; + this.gradientPanel4.Size = new System.Drawing.Size(171, 195); + this.gradientPanel4.TabIndex = 5; + // + // gradientPanel3 + // + this.gradientPanel3.Controls.Add(this.checkBox1); + this.gradientPanel3.Controls.Add(this.chkFullTextPath); + this.gradientPanel3.Controls.Add(this.chkCompUsers); + this.gradientPanel3.Controls.Add(this.chkCompSchemas); + this.gradientPanel3.Controls.Add(this.chkFileGroups); + this.gradientPanel3.Controls.Add(this.chkCompRoles); + this.gradientPanel3.Controls.Add(this.chkFullText); + this.gradientPanel3.Location = new System.Drawing.Point(182, 33); + this.gradientPanel3.Name = "gradientPanel3"; + this.gradientPanel3.Size = new System.Drawing.Size(171, 137); + this.gradientPanel3.TabIndex = 4; + // + // checkBox1 + // + this.checkBox1.AutoSize = true; + this.checkBox1.Checked = true; + this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox1.ForeColor = System.Drawing.SystemColors.ControlText; + this.checkBox1.Location = new System.Drawing.Point(10, 120); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.Size = new System.Drawing.Size(81, 17); + this.checkBox1.TabIndex = 37; + this.checkBox1.Text = "Permissions"; + this.checkBox1.UseVisualStyleBackColor = true; + // + // gradientPanel2 + // + this.gradientPanel2.Controls.Add(this.chkTableChangeTracking); + this.gradientPanel2.Controls.Add(this.chkTableLockEscalation); + this.gradientPanel2.Controls.Add(this.chkTables); + this.gradientPanel2.Controls.Add(this.chkIndexFilter); + this.gradientPanel2.Controls.Add(this.chkTableOption); + this.gradientPanel2.Controls.Add(this.chkConstraintsCheck); + this.gradientPanel2.Controls.Add(this.chkIndex); + this.gradientPanel2.Controls.Add(this.chkConstraintsUK); + this.gradientPanel2.Controls.Add(this.chkConstraints); + this.gradientPanel2.Controls.Add(this.chkConstraintsFK); + this.gradientPanel2.Controls.Add(this.chkTablesColumnCollation); + this.gradientPanel2.Controls.Add(this.chkConstraintsPK); + this.gradientPanel2.Controls.Add(this.chkTablesColumnIdentity); + this.gradientPanel2.Controls.Add(this.chkTablesColumnOrder); + this.gradientPanel2.Controls.Add(this.chkIndexFillFactor); + this.gradientPanel2.Controls.Add(this.chkIndexIncludeColumns); + this.gradientPanel2.Controls.Add(this.chkIndexRowLock); + this.gradientPanel2.Location = new System.Drawing.Point(5, 33); + this.gradientPanel2.Name = "gradientPanel2"; + this.gradientPanel2.Size = new System.Drawing.Size(171, 338); + this.gradientPanel2.TabIndex = 3; + // + // chkTableChangeTracking + // + this.chkTableChangeTracking.AutoSize = true; + this.chkTableChangeTracking.Checked = true; + this.chkTableChangeTracking.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTableChangeTracking.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTableChangeTracking.Location = new System.Drawing.Point(30, 120); + this.chkTableChangeTracking.Name = "chkTableChangeTracking"; + this.chkTableChangeTracking.Size = new System.Drawing.Size(104, 17); + this.chkTableChangeTracking.TabIndex = 16; + this.chkTableChangeTracking.Text = "Change tracking"; + this.chkTableChangeTracking.UseVisualStyleBackColor = true; + // + // chkTableLockEscalation + // + this.chkTableLockEscalation.AutoSize = true; + this.chkTableLockEscalation.Checked = true; + this.chkTableLockEscalation.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTableLockEscalation.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTableLockEscalation.Location = new System.Drawing.Point(30, 101); + this.chkTableLockEscalation.Name = "chkTableLockEscalation"; + this.chkTableLockEscalation.Size = new System.Drawing.Size(101, 17); + this.chkTableLockEscalation.TabIndex = 15; + this.chkTableLockEscalation.Text = "Lock escalation"; + this.chkTableLockEscalation.UseVisualStyleBackColor = true; + // + // gradientPanel1 + // + this.gradientPanel1.Controls.Add(this.label11); + this.gradientPanel1.Location = new System.Drawing.Point(5, 6); + this.gradientPanel1.Name = "gradientPanel1"; + this.gradientPanel1.Size = new System.Drawing.Size(525, 21); + this.gradientPanel1.TabIndex = 2; + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label11.Location = new System.Drawing.Point(4, 4); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(113, 13); + this.label11.TabIndex = 3; + this.label11.Text = "Filter items by type"; + // + // tabPage4 + // + this.tabPage4.BackColor = System.Drawing.Color.White; + this.tabPage4.Controls.Add(this.DeleteNameFilterButton); + this.tabPage4.Controls.Add(this.btnAdd); + this.tabPage4.Controls.Add(this.gradientPanel10); + this.tabPage4.Controls.Add(this.btnApply); + this.tabPage4.Controls.Add(this.gradientPanel9); + this.tabPage4.Location = new System.Drawing.Point(4, 22); + this.tabPage4.Name = "tabPage4"; + this.tabPage4.Padding = new System.Windows.Forms.Padding(3); + this.tabPage4.Size = new System.Drawing.Size(537, 416); + this.tabPage4.TabIndex = 3; + this.tabPage4.Text = "Exclude by name"; + // + // DeleteNameFilterButton + // + this.DeleteNameFilterButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.DeleteNameFilterButton.ForeColor = System.Drawing.SystemColors.ControlText; + this.DeleteNameFilterButton.Location = new System.Drawing.Point(464, 387); + this.DeleteNameFilterButton.Name = "DeleteNameFilterButton"; + this.DeleteNameFilterButton.Size = new System.Drawing.Size(58, 23); + this.DeleteNameFilterButton.TabIndex = 6; + this.DeleteNameFilterButton.Text = "Delete"; + this.DeleteNameFilterButton.UseVisualStyleBackColor = true; + this.DeleteNameFilterButton.Click += new System.EventHandler(this.DeleteNameFilterButton_Click); + // + // btnAdd + // + this.btnAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnAdd.ForeColor = System.Drawing.SystemColors.ControlText; + this.btnAdd.Location = new System.Drawing.Point(336, 387); + this.btnAdd.Name = "btnAdd"; + this.btnAdd.Size = new System.Drawing.Size(58, 23); + this.btnAdd.TabIndex = 3; + this.btnAdd.Text = "Add"; + this.btnAdd.UseVisualStyleBackColor = true; + this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click); + // + // gradientPanel10 + // + this.gradientPanel10.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gradientPanel10.Controls.Add(this.lstFilters); + this.gradientPanel10.Location = new System.Drawing.Point(6, 33); + this.gradientPanel10.Name = "gradientPanel10"; + this.gradientPanel10.Size = new System.Drawing.Size(524, 348); + this.gradientPanel10.TabIndex = 5; + // + // lstFilters + // + this.lstFilters.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lstFilters.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2, + this.columnHeader3, + this.columnHeader4}); + this.lstFilters.FullRowSelect = true; + this.lstFilters.Location = new System.Drawing.Point(7, 8); + this.lstFilters.Name = "lstFilters"; + this.lstFilters.Size = new System.Drawing.Size(509, 333); + this.lstFilters.TabIndex = 0; + this.lstFilters.UseCompatibleStateImageBehavior = false; + this.lstFilters.View = System.Windows.Forms.View.Details; + this.lstFilters.DoubleClick += new System.EventHandler(this.lstFilters_DoubleClick); + // + // columnHeader1 + // + this.columnHeader1.Text = "Exclusion pattern"; + this.columnHeader1.Width = 250; + // + // columnHeader2 + // + this.columnHeader2.Text = "Item type"; + this.columnHeader2.Width = 100; + // + // columnHeader3 + // + this.columnHeader3.Width = 0; + // + // columnHeader4 + // + this.columnHeader4.Text = ""; + // + // btnApply + // + this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnApply.ForeColor = System.Drawing.SystemColors.ControlText; + this.btnApply.Location = new System.Drawing.Point(400, 387); + this.btnApply.Name = "btnApply"; + this.btnApply.Size = new System.Drawing.Size(58, 23); + this.btnApply.TabIndex = 2; + this.btnApply.Text = "Edit"; + this.btnApply.UseVisualStyleBackColor = true; + this.btnApply.Click += new System.EventHandler(this.btnApply_Click); + // + // gradientPanel9 + // + this.gradientPanel9.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gradientPanel9.Controls.Add(this.label1); + this.gradientPanel9.Location = new System.Drawing.Point(5, 6); + this.gradientPanel9.Name = "gradientPanel9"; + this.gradientPanel9.Size = new System.Drawing.Size(525, 21); + this.gradientPanel9.TabIndex = 4; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(4, 4); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(136, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Exclude items by name"; + // + // tabPage2 + // + this.tabPage2.BackColor = System.Drawing.Color.White; + this.tabPage2.Controls.Add(this.gradientPanel8); + this.tabPage2.Controls.Add(this.gradientPanel7); + this.tabPage2.Location = new System.Drawing.Point(4, 22); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(537, 416); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "Defaults"; + // + // gradientPanel8 + // + this.gradientPanel8.Controls.Add(this.txtXML); + this.gradientPanel8.Controls.Add(this.label2); + this.gradientPanel8.Controls.Add(this.label10); + this.gradientPanel8.Controls.Add(this.txtDefaultInteger); + this.gradientPanel8.Controls.Add(this.txtTime); + this.gradientPanel8.Controls.Add(this.label3); + this.gradientPanel8.Controls.Add(this.label9); + this.gradientPanel8.Controls.Add(this.txtDefaultReal); + this.gradientPanel8.Controls.Add(this.txtVariant); + this.gradientPanel8.Controls.Add(this.label4); + this.gradientPanel8.Controls.Add(this.label8); + this.gradientPanel8.Controls.Add(this.txtText); + this.gradientPanel8.Controls.Add(this.txtNText); + this.gradientPanel8.Controls.Add(this.label5); + this.gradientPanel8.Controls.Add(this.label7); + this.gradientPanel8.Controls.Add(this.txtDate); + this.gradientPanel8.Controls.Add(this.txtBlob); + this.gradientPanel8.Controls.Add(this.label6); + this.gradientPanel8.Location = new System.Drawing.Point(5, 33); + this.gradientPanel8.Name = "gradientPanel8"; + this.gradientPanel8.Size = new System.Drawing.Size(525, 377); + this.gradientPanel8.TabIndex = 4; + // + // gradientPanel7 + // + this.gradientPanel7.Controls.Add(this.label12); + this.gradientPanel7.Location = new System.Drawing.Point(5, 6); + this.gradientPanel7.Name = "gradientPanel7"; + this.gradientPanel7.Size = new System.Drawing.Size(525, 21); + this.gradientPanel7.TabIndex = 3; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label12.Location = new System.Drawing.Point(4, 4); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(89, 13); + this.label12.TabIndex = 3; + this.label12.Text = "Default values"; + // + // tabPage3 + // + this.tabPage3.BackColor = System.Drawing.Color.White; + this.tabPage3.Controls.Add(this.groupBox4); + this.tabPage3.Controls.Add(this.gradientPanel16); + this.tabPage3.Location = new System.Drawing.Point(4, 22); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.Size = new System.Drawing.Size(537, 416); + this.tabPage3.TabIndex = 2; + this.tabPage3.Text = "Script"; + // + // groupBox4 + // + this.groupBox4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox4.Controls.Add(this.optScriptSchemaBindingAlter); + this.groupBox4.Controls.Add(this.optScriptSchemaDrop); + this.groupBox4.Location = new System.Drawing.Point(5, 33); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(525, 66); + this.groupBox4.TabIndex = 4; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "When rebuilding a view with schema binding"; + // + // optScriptSchemaBindingAlter + // + this.optScriptSchemaBindingAlter.AutoSize = true; + this.optScriptSchemaBindingAlter.Checked = true; + this.optScriptSchemaBindingAlter.ForeColor = System.Drawing.SystemColors.ControlText; + this.optScriptSchemaBindingAlter.Location = new System.Drawing.Point(18, 42); + this.optScriptSchemaBindingAlter.Name = "optScriptSchemaBindingAlter"; + this.optScriptSchemaBindingAlter.Size = new System.Drawing.Size(120, 17); + this.optScriptSchemaBindingAlter.TabIndex = 1; + this.optScriptSchemaBindingAlter.TabStop = true; + this.optScriptSchemaBindingAlter.Text = "ALTER object twice"; + this.optScriptSchemaBindingAlter.UseVisualStyleBackColor = true; + // + // optScriptSchemaDrop + // + this.optScriptSchemaDrop.AutoSize = true; + this.optScriptSchemaDrop.ForeColor = System.Drawing.SystemColors.ControlText; + this.optScriptSchemaDrop.Location = new System.Drawing.Point(18, 19); + this.optScriptSchemaDrop.Name = "optScriptSchemaDrop"; + this.optScriptSchemaDrop.Size = new System.Drawing.Size(136, 17); + this.optScriptSchemaDrop.TabIndex = 0; + this.optScriptSchemaDrop.TabStop = true; + this.optScriptSchemaDrop.Text = "DROP/CREATE object"; + this.optScriptSchemaDrop.UseVisualStyleBackColor = true; + // + // gradientPanel16 + // + this.gradientPanel16.Controls.Add(this.label15); + this.gradientPanel16.Location = new System.Drawing.Point(5, 6); + this.gradientPanel16.Name = "gradientPanel16"; + this.gradientPanel16.Size = new System.Drawing.Size(525, 21); + this.gradientPanel16.TabIndex = 3; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label15.Location = new System.Drawing.Point(4, 4); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(144, 13); + this.label15.TabIndex = 3; + this.label15.Text = "Advanced script options"; + // + // tabPage5 + // + this.tabPage5.BackColor = System.Drawing.Color.White; + this.tabPage5.Controls.Add(this.gradientPanel15); + this.tabPage5.Controls.Add(this.gradientPanel14); + this.tabPage5.Controls.Add(this.gradientPanel13); + this.tabPage5.Controls.Add(this.gradientPanel12); + this.tabPage5.Controls.Add(this.gradientPanel11); + this.tabPage5.Controls.Add(this.chkReloadDB); + this.tabPage5.Location = new System.Drawing.Point(4, 22); + this.tabPage5.Name = "tabPage5"; + this.tabPage5.Padding = new System.Windows.Forms.Padding(3); + this.tabPage5.Size = new System.Drawing.Size(537, 416); + this.tabPage5.TabIndex = 4; + this.tabPage5.Text = "Comparison"; + // + // gradientPanel15 + // + this.gradientPanel15.Controls.Add(this.chkIgnoreWhiteSpaceInCode); + this.gradientPanel15.Location = new System.Drawing.Point(5, 232); + this.gradientPanel15.Name = "gradientPanel15"; + this.gradientPanel15.Size = new System.Drawing.Size(525, 31); + this.gradientPanel15.TabIndex = 7; + // + // chkIgnoreWhiteSpaceInCode + // + this.chkIgnoreWhiteSpaceInCode.AutoSize = true; + this.chkIgnoreWhiteSpaceInCode.Location = new System.Drawing.Point(7, 7); + this.chkIgnoreWhiteSpaceInCode.Name = "chkIgnoreWhiteSpaceInCode"; + this.chkIgnoreWhiteSpaceInCode.Size = new System.Drawing.Size(327, 17); + this.chkIgnoreWhiteSpaceInCode.TabIndex = 2; + this.chkIgnoreWhiteSpaceInCode.Text = "Ignore white spaces in stored procedures, triggers and functions"; + this.chkIgnoreWhiteSpaceInCode.UseVisualStyleBackColor = true; + // + // gradientPanel14 + // + this.gradientPanel14.Controls.Add(this.label14); + this.gradientPanel14.Location = new System.Drawing.Point(5, 135); + this.gradientPanel14.Name = "gradientPanel14"; + this.gradientPanel14.Size = new System.Drawing.Size(525, 21); + this.gradientPanel14.TabIndex = 6; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label14.Location = new System.Drawing.Point(4, 4); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(247, 13); + this.label14.TabIndex = 3; + this.label14.Text = "Procedures, functions and triggers options"; + // + // gradientPanel13 + // + this.gradientPanel13.Controls.Add(this.rdoCaseSensityInCode); + this.gradientPanel13.Controls.Add(this.rdoCaseInsensityInCode); + this.gradientPanel13.Location = new System.Drawing.Point(5, 162); + this.gradientPanel13.Name = "gradientPanel13"; + this.gradientPanel13.Size = new System.Drawing.Size(525, 64); + this.gradientPanel13.TabIndex = 5; + // + // rdoCaseSensityInCode + // + this.rdoCaseSensityInCode.AutoSize = true; + this.rdoCaseSensityInCode.Location = new System.Drawing.Point(13, 36); + this.rdoCaseSensityInCode.Name = "rdoCaseSensityInCode"; + this.rdoCaseSensityInCode.Size = new System.Drawing.Size(93, 17); + this.rdoCaseSensityInCode.TabIndex = 2; + this.rdoCaseSensityInCode.Text = "Case sensitive"; + this.rdoCaseSensityInCode.UseVisualStyleBackColor = true; + // + // rdoCaseInsensityInCode + // + this.rdoCaseInsensityInCode.AutoSize = true; + this.rdoCaseInsensityInCode.Checked = true; + this.rdoCaseInsensityInCode.Location = new System.Drawing.Point(13, 13); + this.rdoCaseInsensityInCode.Name = "rdoCaseInsensityInCode"; + this.rdoCaseInsensityInCode.Size = new System.Drawing.Size(101, 17); + this.rdoCaseInsensityInCode.TabIndex = 1; + this.rdoCaseInsensityInCode.TabStop = true; + this.rdoCaseInsensityInCode.Text = "Case insensitive"; + this.rdoCaseInsensityInCode.UseVisualStyleBackColor = true; + // + // gradientPanel12 + // + this.gradientPanel12.Controls.Add(this.label13); + this.gradientPanel12.Location = new System.Drawing.Point(5, 6); + this.gradientPanel12.Name = "gradientPanel12"; + this.gradientPanel12.Size = new System.Drawing.Size(525, 21); + this.gradientPanel12.TabIndex = 4; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label13.Location = new System.Drawing.Point(4, 4); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(192, 13); + this.label13.TabIndex = 3; + this.label13.Text = "Collation case sensitivity options"; + // + // gradientPanel11 + // + this.gradientPanel11.Controls.Add(this.rdoCaseSensitive); + this.gradientPanel11.Controls.Add(this.rdoCaseAutomatic); + this.gradientPanel11.Controls.Add(this.rdoCaseInsensitive); + this.gradientPanel11.Location = new System.Drawing.Point(5, 33); + this.gradientPanel11.Name = "gradientPanel11"; + this.gradientPanel11.Size = new System.Drawing.Size(525, 87); + this.gradientPanel11.TabIndex = 3; + // + // rdoCaseSensitive + // + this.rdoCaseSensitive.AutoSize = true; + this.rdoCaseSensitive.Location = new System.Drawing.Point(14, 59); + this.rdoCaseSensitive.Name = "rdoCaseSensitive"; + this.rdoCaseSensitive.Size = new System.Drawing.Size(93, 17); + this.rdoCaseSensitive.TabIndex = 2; + this.rdoCaseSensitive.Text = "Case sensitive"; + this.rdoCaseSensitive.UseVisualStyleBackColor = true; + // + // rdoCaseAutomatic + // + this.rdoCaseAutomatic.AutoSize = true; + this.rdoCaseAutomatic.Checked = true; + this.rdoCaseAutomatic.Location = new System.Drawing.Point(14, 13); + this.rdoCaseAutomatic.Name = "rdoCaseAutomatic"; + this.rdoCaseAutomatic.Size = new System.Drawing.Size(200, 17); + this.rdoCaseAutomatic.TabIndex = 0; + this.rdoCaseAutomatic.TabStop = true; + this.rdoCaseAutomatic.Text = "Automatic (detect database collation)"; + this.rdoCaseAutomatic.UseVisualStyleBackColor = true; + // + // rdoCaseInsensitive + // + this.rdoCaseInsensitive.AutoSize = true; + this.rdoCaseInsensitive.Location = new System.Drawing.Point(14, 36); + this.rdoCaseInsensitive.Name = "rdoCaseInsensitive"; + this.rdoCaseInsensitive.Size = new System.Drawing.Size(101, 17); + this.rdoCaseInsensitive.TabIndex = 1; + this.rdoCaseInsensitive.Text = "Case insensitive"; + this.rdoCaseInsensitive.UseVisualStyleBackColor = true; + // + // chkReloadDB + // + this.chkReloadDB.AutoSize = true; + this.chkReloadDB.Location = new System.Drawing.Point(12, 393); + this.chkReloadDB.Name = "chkReloadDB"; + this.chkReloadDB.Size = new System.Drawing.Size(251, 17); + this.chkReloadDB.TabIndex = 8; + this.chkReloadDB.Text = "Reload database comparison after each update"; + this.chkReloadDB.UseVisualStyleBackColor = false; + // + // IncludeSynonymsCheckBox + // + this.IncludeSynonymsCheckBox.AutoSize = true; + this.IncludeSynonymsCheckBox.Checked = true; + this.IncludeSynonymsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.IncludeSynonymsCheckBox.ForeColor = System.Drawing.SystemColors.ControlText; + this.IncludeSynonymsCheckBox.Location = new System.Drawing.Point(13, 144); + this.IncludeSynonymsCheckBox.Name = "IncludeSynonymsCheckBox"; + this.IncludeSynonymsCheckBox.Size = new System.Drawing.Size(74, 17); + this.IncludeSynonymsCheckBox.TabIndex = 28; + this.IncludeSynonymsCheckBox.Text = "Synonyms"; + this.IncludeSynonymsCheckBox.UseVisualStyleBackColor = true; + // + // SqlOptionsFront + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tabControl1); + this.Name = "SqlOptionsFront"; + this.Size = new System.Drawing.Size(545, 442); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.gradientPanel6.ResumeLayout(false); + this.gradientPanel6.PerformLayout(); + this.gradientPanel5.ResumeLayout(false); + this.gradientPanel5.PerformLayout(); + this.gradientPanel4.ResumeLayout(false); + this.gradientPanel4.PerformLayout(); + this.gradientPanel3.ResumeLayout(false); + this.gradientPanel3.PerformLayout(); + this.gradientPanel2.ResumeLayout(false); + this.gradientPanel2.PerformLayout(); + this.gradientPanel1.ResumeLayout(false); + this.gradientPanel1.PerformLayout(); + this.tabPage4.ResumeLayout(false); + this.gradientPanel10.ResumeLayout(false); + this.gradientPanel9.ResumeLayout(false); + this.gradientPanel9.PerformLayout(); + this.tabPage2.ResumeLayout(false); + this.gradientPanel8.ResumeLayout(false); + this.gradientPanel8.PerformLayout(); + this.gradientPanel7.ResumeLayout(false); + this.gradientPanel7.PerformLayout(); + this.tabPage3.ResumeLayout(false); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); + this.gradientPanel16.ResumeLayout(false); + this.gradientPanel16.PerformLayout(); + this.tabPage5.ResumeLayout(false); + this.tabPage5.PerformLayout(); + this.gradientPanel15.ResumeLayout(false); + this.gradientPanel15.PerformLayout(); + this.gradientPanel14.ResumeLayout(false); + this.gradientPanel14.PerformLayout(); + this.gradientPanel13.ResumeLayout(false); + this.gradientPanel13.PerformLayout(); + this.gradientPanel12.ResumeLayout(false); + this.gradientPanel12.PerformLayout(); + this.gradientPanel11.ResumeLayout(false); + this.gradientPanel11.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private CheckBox chkCompExtendedProperties; + private CheckBox chkConstraints; + private CheckBox chkCompSchemas; + private CheckBox chkCompUDT; + private CheckBox chkIndex; + private CheckBox chkTableOption; + private CheckBox chkCompXMLSchemas; + private CheckBox chkCompFunciones; + private CheckBox chkCompStoredProcedure; + private CheckBox chkTables; + private CheckBox chkCompTriggers; + private CheckBox chkCompVistas; + private Label label2; + private TextBox txtDefaultReal; + private Label label3; + private TextBox txtDefaultInteger; + private TextBox txtText; + private Label label4; + private TextBox txtNText; + private Label label7; + private TextBox txtBlob; + private Label label6; + private TextBox txtDate; + private Label label5; + private TextBox txtVariant; + private Label label8; + private CheckBox chkTablesColumnIdentity; + private CheckBox chkTablesColumnCollation; + private CheckBox chkFileGroups; + private CheckBox chkCompAssemblys; + private TabControl tabControl1; + private TabPage tabPage1; + private TabPage tabPage2; + private CheckBox chkTablesColumnOrder; + private CheckBox chkIndexFillFactor; + private CheckBox chkCompTriggersDDL; + private CheckBox chkIndexIncludeColumns; + private CheckBox chkCompUsers; + private TabPage tabPage3; + private CheckBox chkCompRoles; + private TabPage tabPage4; + private ListView lstFilters; + private ColumnHeader columnHeader1; + private ColumnHeader columnHeader2; + private ColumnHeader columnHeader3; + private ColumnHeader columnHeader4; + private Button btnApply; + private Button btnAdd; + private CheckBox chkIgnoreNotForReplication; + private CheckBox chkCompRules; + private CheckBox chkFullText; + private CheckBox chkIndexRowLock; + private CheckBox chkCompCLRStore; + private CheckBox chkCompCLRTrigger; + private CheckBox chkCompCLRFunctions; + private CheckBox chkCompCLRUDT; + private CheckBox checkBox4; + private CheckBox checkPartitionFunction; + private CheckBox checkBox5; + private TabPage tabPage5; + private RadioButton rdoCaseAutomatic; + private RadioButton rdoCaseSensitive; + private RadioButton rdoCaseInsensitive; + private TextBox txtTime; + private Label label9; + private TextBox txtXML; + private Label label10; + private CheckBox chkConstraintsPK; + private CheckBox chkConstraintsFK; + private CheckBox chkConstraintsUK; + private CheckBox chkConstraintsCheck; + private CheckBox chkIndexFilter; + private CheckBox chkFullTextPath; + private RadioButton rdoCaseSensityInCode; + private RadioButton rdoCaseInsensityInCode; + private CheckBox chkIgnoreWhiteSpaceInCode; + private Panel gradientPanel1; + private Label label11; + private Panel gradientPanel2; + private Panel gradientPanel3; + private Panel gradientPanel4; + private Panel gradientPanel5; + private Panel gradientPanel6; + private Panel gradientPanel8; + private Panel gradientPanel7; + private Label label12; + private Panel gradientPanel9; + private Label label1; + private Panel gradientPanel10; + private CheckBox chkTableLockEscalation; + private CheckBox chkTableChangeTracking; + private CheckBox checkBox1; + private Panel gradientPanel12; + private Label label13; + private Panel gradientPanel11; + private Panel gradientPanel13; + private Panel gradientPanel14; + private Label label14; + private Panel gradientPanel15; + private Panel gradientPanel16; + private Label label15; + private GroupBox groupBox4; + private RadioButton optScriptSchemaBindingAlter; + private RadioButton optScriptSchemaDrop; + private CheckBox chkReloadDB; + private Button DeleteNameFilterButton; + private CheckBox IncludeSynonymsCheckBox; + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/SqlOptionsFront.cs b/OpenDBDiff.Schema.SQLServer2005/Front/SqlOptionsFront.cs new file mode 100644 index 0000000..b15e26e --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/SqlOptionsFront.cs @@ -0,0 +1,279 @@ +using System; +using System.Linq; +using System.Windows.Forms; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Options; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + public partial class SqlOptionsFront : OpenDBDiff.Front.OptionControl + { + private SqlOption SQLOption; + + public SqlOptionsFront() + { + InitializeComponent(); + HandlerHelper.OnChange += new HandlerHelper.SaveFilterHandler(HandlerHelper_OnChange); + } + + public void HandlerHelper_OnChange() + { + LoadFilters(); + } + + private void LoadFilters() + { + lstFilters.Items.Clear(); + foreach (SqlOptionFilterItem item in SQLOption.Filters.Items) + { + var lview = new ListViewItem(item.FilterPattern); + lview.SubItems.Add(item.ObjectType.ToString()); + lstFilters.Items.Add(lview); + }; + } + + public override void Load(Schema.Model.IOption option) + { + this.SQLOption = new SqlOption(option); + txtBlob.Text = SQLOption.Defaults.DefaultBlobValue; + txtDate.Text = SQLOption.Defaults.DefaultDateValue; + txtDefaultInteger.Text = SQLOption.Defaults.DefaultIntegerValue; + txtDefaultReal.Text = SQLOption.Defaults.DefaultRealValue; + txtNText.Text = SQLOption.Defaults.DefaultNTextValue; + txtText.Text = SQLOption.Defaults.DefaultTextValue; + txtVariant.Text = SQLOption.Defaults.DefaultVariantValue; + txtTime.Text = SQLOption.Defaults.DefaultTime; + txtXML.Text = SQLOption.Defaults.DefaultXml; + + chkCompAssemblys.Checked = SQLOption.Ignore.FilterAssemblies; + chkCompCLRFunctions.Checked = SQLOption.Ignore.FilterCLRFunction; + chkCompCLRStore.Checked = SQLOption.Ignore.FilterCLRStoredProcedure; + chkCompCLRTrigger.Checked = SQLOption.Ignore.FilterCLRTrigger; + chkCompCLRUDT.Checked = SQLOption.Ignore.FilterCLRUDT; + + chkConstraints.Checked = SQLOption.Ignore.FilterConstraint; + chkConstraintsPK.Checked = SQLOption.Ignore.FilterConstraintPK; + chkConstraintsFK.Checked = SQLOption.Ignore.FilterConstraintFK; + chkConstraintsUK.Checked = SQLOption.Ignore.FilterConstraintUK; + chkConstraintsCheck.Checked = SQLOption.Ignore.FilterConstraintCheck; + + chkCompExtendedProperties.Checked = SQLOption.Ignore.FilterExtendedProperties; + chkCompFunciones.Checked = SQLOption.Ignore.FilterFunction; + chkIndex.Checked = SQLOption.Ignore.FilterIndex; + chkIndexFillFactor.Checked = SQLOption.Ignore.FilterIndexFillFactor; + chkIndexIncludeColumns.Checked = SQLOption.Ignore.FilterIndexIncludeColumns; + chkIndexFilter.Checked = SQLOption.Ignore.FilterIndexFilter; + chkFullText.Checked = SQLOption.Ignore.FilterFullText; + chkFullTextPath.Checked = SQLOption.Ignore.FilterFullTextPath; + + chkCompSchemas.Checked = SQLOption.Ignore.FilterSchema; + chkCompStoredProcedure.Checked = SQLOption.Ignore.FilterStoredProcedure; + chkTableOption.Checked = SQLOption.Ignore.FilterTableOption; + chkTables.Checked = SQLOption.Ignore.FilterTable; + chkTablesColumnIdentity.Checked = SQLOption.Ignore.FilterColumnIdentity; + chkTablesColumnCollation.Checked = SQLOption.Ignore.FilterColumnCollation; + chkTableLockEscalation.Checked = SQLOption.Ignore.FilterTableLockEscalation; + chkTableChangeTracking.Checked = SQLOption.Ignore.FilterTableChangeTracking; + + chkTablesColumnOrder.Checked = SQLOption.Ignore.FilterColumnOrder; + chkIgnoreNotForReplication.Checked = SQLOption.Ignore.FilterNotForReplication; + + chkCompTriggersDDL.Checked = SQLOption.Ignore.FilterDDLTriggers; + chkCompTriggers.Checked = SQLOption.Ignore.FilterTrigger; + chkCompUDT.Checked = SQLOption.Ignore.FilterUserDataType; + chkCompVistas.Checked = SQLOption.Ignore.FilterView; + chkCompXMLSchemas.Checked = SQLOption.Ignore.FilterXMLSchema; + chkFileGroups.Checked = SQLOption.Ignore.FilterTableFileGroup; + chkCompUsers.Checked = SQLOption.Ignore.FilterUsers; + chkCompRoles.Checked = SQLOption.Ignore.FilterRoles; + chkCompRules.Checked = SQLOption.Ignore.FilterRules; + + IncludeSynonymsCheckBox.Checked = SQLOption.Ignore.FilterSynonyms; + + if (SQLOption.Script.AlterObjectOnSchemaBinding) + optScriptSchemaBindingAlter.Checked = true; + else + optScriptSchemaDrop.Checked = true; + + if (SQLOption.Comparison.CaseSensityType == SqlOptionComparison.CaseSensityOptions.Automatic) + rdoCaseAutomatic.Checked = true; + if (SQLOption.Comparison.CaseSensityType == SqlOptionComparison.CaseSensityOptions.CaseInsensity) + rdoCaseInsensitive.Checked = true; + if (SQLOption.Comparison.CaseSensityType == SqlOptionComparison.CaseSensityOptions.CaseSensity) + rdoCaseSensitive.Checked = true; + + if (SQLOption.Comparison.CaseSensityInCode == SqlOptionComparison.CaseSensityOptions.CaseInsensity) + rdoCaseInsensityInCode.Checked = true; + if (SQLOption.Comparison.CaseSensityInCode == SqlOptionComparison.CaseSensityOptions.CaseSensity) + rdoCaseSensityInCode.Checked = true; + + chkIgnoreWhiteSpaceInCode.Checked = SQLOption.Comparison.IgnoreWhiteSpacesInCode; + + chkReloadDB.Checked = SQLOption.Comparison.ReloadComparisonOnUpdate; + + LoadFilters(); + } + + public override void Save() + { + SQLOption.Defaults.DefaultBlobValue = txtBlob.Text; + SQLOption.Defaults.DefaultDateValue = txtDate.Text; + SQLOption.Defaults.DefaultIntegerValue = txtDefaultInteger.Text; + SQLOption.Defaults.DefaultNTextValue = txtNText.Text; + SQLOption.Defaults.DefaultRealValue = txtDefaultReal.Text; + SQLOption.Defaults.DefaultTextValue = txtText.Text; + SQLOption.Defaults.DefaultVariantValue = txtVariant.Text; + SQLOption.Defaults.DefaultTime = txtTime.Text; + SQLOption.Defaults.DefaultXml = txtXML.Text; + + SQLOption.Ignore.FilterAssemblies = chkCompAssemblys.Checked; + SQLOption.Ignore.FilterCLRFunction = chkCompCLRFunctions.Checked && chkCompAssemblys.Checked; + SQLOption.Ignore.FilterCLRStoredProcedure = chkCompCLRStore.Checked && chkCompAssemblys.Checked; + SQLOption.Ignore.FilterCLRTrigger = chkCompCLRTrigger.Checked && chkCompAssemblys.Checked; + SQLOption.Ignore.FilterCLRUDT = chkCompCLRUDT.Checked && chkCompAssemblys.Checked; + + SQLOption.Ignore.FilterConstraint = chkConstraints.Checked; + SQLOption.Ignore.FilterConstraintPK = chkConstraintsPK.Checked; + SQLOption.Ignore.FilterConstraintFK = chkConstraintsFK.Checked; + SQLOption.Ignore.FilterConstraintUK = chkConstraintsUK.Checked; + SQLOption.Ignore.FilterConstraintCheck = chkConstraintsCheck.Checked; + + SQLOption.Ignore.FilterFunction = chkCompFunciones.Checked; + + SQLOption.Ignore.FilterIndex = chkIndex.Checked; + SQLOption.Ignore.FilterIndexFillFactor = chkIndexFillFactor.Checked && chkIndex.Checked; + SQLOption.Ignore.FilterIndexIncludeColumns = chkIndexIncludeColumns.Checked && chkIndex.Checked; + SQLOption.Ignore.FilterIndexFilter = chkIndexFilter.Checked && chkIndex.Checked; + + SQLOption.Ignore.FilterSchema = chkCompSchemas.Checked; + SQLOption.Ignore.FilterStoredProcedure = chkCompStoredProcedure.Checked; + + SQLOption.Ignore.FilterTable = chkTables.Checked; + SQLOption.Ignore.FilterColumnIdentity = chkTablesColumnIdentity.Checked && chkTables.Checked; + SQLOption.Ignore.FilterColumnCollation = chkTablesColumnCollation.Checked && chkTables.Checked; + SQLOption.Ignore.FilterColumnOrder = chkTablesColumnOrder.Checked && chkTables.Checked; + SQLOption.Ignore.FilterTableOption = chkTableOption.Checked && chkTables.Checked; + SQLOption.Ignore.FilterTableLockEscalation = chkTableLockEscalation.Checked && chkTables.Checked; + SQLOption.Ignore.FilterTableChangeTracking = chkTableChangeTracking.Checked && chkTables.Checked; + + SQLOption.Ignore.FilterTableFileGroup = chkFileGroups.Checked; + SQLOption.Ignore.FilterTrigger = chkCompTriggers.Checked; + SQLOption.Ignore.FilterDDLTriggers = chkCompTriggersDDL.Checked; + SQLOption.Ignore.FilterUserDataType = chkCompUDT.Checked; + SQLOption.Ignore.FilterView = chkCompVistas.Checked; + SQLOption.Ignore.FilterXMLSchema = chkCompXMLSchemas.Checked; + SQLOption.Ignore.FilterExtendedProperties = chkCompExtendedProperties.Checked; + SQLOption.Ignore.FilterUsers = chkCompUsers.Checked; + SQLOption.Ignore.FilterRoles = chkCompRoles.Checked; + SQLOption.Ignore.FilterRules = chkCompRules.Checked; + SQLOption.Ignore.FilterFullText = chkFullText.Checked; + SQLOption.Ignore.FilterFullTextPath = chkFullTextPath.Checked; + SQLOption.Ignore.FilterSynonyms = IncludeSynonymsCheckBox.Checked; + + SQLOption.Ignore.FilterNotForReplication = chkIgnoreNotForReplication.Checked; + SQLOption.Script.AlterObjectOnSchemaBinding = optScriptSchemaBindingAlter.Checked; + + if (rdoCaseAutomatic.Checked) + SQLOption.Comparison.CaseSensityType = SqlOptionComparison.CaseSensityOptions.Automatic; + if (rdoCaseInsensitive.Checked) + SQLOption.Comparison.CaseSensityType = SqlOptionComparison.CaseSensityOptions.CaseInsensity; + if (rdoCaseSensitive.Checked) + SQLOption.Comparison.CaseSensityType = SqlOptionComparison.CaseSensityOptions.CaseSensity; + + if (rdoCaseInsensityInCode.Checked) + SQLOption.Comparison.CaseSensityInCode = SqlOptionComparison.CaseSensityOptions.CaseInsensity; + if (rdoCaseSensityInCode.Checked) + SQLOption.Comparison.CaseSensityInCode = SqlOptionComparison.CaseSensityOptions.CaseSensity; + + SQLOption.Comparison.IgnoreWhiteSpacesInCode = chkIgnoreWhiteSpaceInCode.Checked; + SQLOption.Comparison.ReloadComparisonOnUpdate = chkReloadDB.Checked; + + FireOptionChanged(SQLOption); + } + public Schema.Model.IOption GetOption() + { + return SQLOption; + } + + private void chkCompIndices_CheckedChanged(object sender, EventArgs e) + { + chkIndexFillFactor.Enabled = chkIndex.Checked; + chkIndexIncludeColumns.Enabled = chkIndex.Checked; + chkIndexFilter.Enabled = chkIndex.Checked; + chkIndexRowLock.Enabled = chkIndex.Checked; + } + + private void chkCompTablas_CheckedChanged(object sender, EventArgs e) + { + chkTablesColumnCollation.Enabled = chkTables.Checked; + chkTablesColumnIdentity.Enabled = chkTables.Checked; + chkTablesColumnOrder.Enabled = chkTables.Checked; + chkTableChangeTracking.Enabled = chkTables.Checked; + chkTableLockEscalation.Enabled = chkTables.Checked; + chkTableOption.Enabled = chkTables.Checked; + } + + private void btnApply_Click(object sender, EventArgs e) + { + if (lstFilters.SelectedItems.Count > 0) + { + AddExclusionPatternForm itemForm = new AddExclusionPatternForm(SQLOption, lstFilters.SelectedItems[0].Index); + itemForm.ShowDialog(this); + } + } + + private void btnAdd_Click(object sender, EventArgs e) + { + AddExclusionPatternForm itemForm = new AddExclusionPatternForm(SQLOption); + itemForm.ShowDialog(this); + } + + private void chkConstraints_CheckedChanged(object sender, EventArgs e) + { + chkConstraintsFK.Enabled = chkConstraints.Checked; + chkConstraintsPK.Enabled = chkConstraints.Checked; + chkConstraintsUK.Enabled = chkConstraints.Checked; + chkConstraintsCheck.Enabled = chkConstraints.Checked; + } + + private void chkFullText_CheckedChanged(object sender, EventArgs e) + { + chkFullTextPath.Enabled = chkFullText.Checked; + } + + private void chkCompAssemblys_CheckedChanged(object sender, EventArgs e) + { + chkCompCLRStore.Enabled = chkCompAssemblys.Checked; + chkCompCLRTrigger.Enabled = chkCompAssemblys.Checked; + chkCompCLRFunctions.Enabled = chkCompAssemblys.Checked; + chkCompCLRUDT.Enabled = chkCompAssemblys.Checked; + } + + private void DeleteNameFilterButton_Click(object sender, EventArgs e) + { + if (lstFilters.SelectedItems.Count > 0) + { + foreach (ListViewItem item in lstFilters.Items) + { + if (item.Selected) + { + var type = (ObjectType)Enum.Parse(typeof(ObjectType), item.SubItems[1].Text); + var fi = new SqlOptionFilterItem(type, item.Text); + if (SQLOption.Filters.Items.Contains(fi)) + SQLOption.Filters.Items.Remove(fi); + } + } + LoadFilters(); + } + } + + private void lstFilters_DoubleClick(object sender, EventArgs e) + { + if (lstFilters.SelectedItems.Count > 0) + { + AddExclusionPatternForm itemForm = new AddExclusionPatternForm(SQLOption, lstFilters.SelectedItems[0].Index); + itemForm.ShowDialog(this); + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/SqlOptionsFront.resx b/OpenDBDiff.Schema.SQLServer2005/Front/SqlOptionsFront.resx new file mode 100644 index 0000000..d58980a --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/SqlOptionsFront.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/SqlServerConnectFront.Designer.cs b/OpenDBDiff.Schema.SQLServer2005/Front/SqlServerConnectFront.Designer.cs new file mode 100644 index 0000000..80a4dfe --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/SqlServerConnectFront.Designer.cs @@ -0,0 +1,237 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + partial class SqlServerConnectFront + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.txtPassword = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.cboServer = new System.Windows.Forms.ComboBox(); + this.cboAuthentication = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); + this.cboDatabase = new System.Windows.Forms.ComboBox(); + this.label6 = new System.Windows.Forms.Label(); + this.txtUsername = new System.Windows.Forms.TextBox(); + this.btnTest = new System.Windows.Forms.Button(); + this.lblName = new System.Windows.Forms.Label(); + this.gradientPanel1 = new System.Windows.Forms.Panel(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.gradientPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // txtPassword + // + this.txtPassword.Location = new System.Drawing.Point(82, 107); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.PasswordChar = '*'; + this.txtPassword.Size = new System.Drawing.Size(180, 20); + this.txtPassword.TabIndex = 3; + this.txtPassword.TextChanged += new System.EventHandler(this.txtPassword_TextChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(3, 110); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(56, 13); + this.label4.TabIndex = 16; + this.label4.Text = "Password:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(3, 84); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(58, 13); + this.label3.TabIndex = 15; + this.label3.Text = "Username:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(3, 31); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(66, 13); + this.label2.TabIndex = 14; + this.label2.Text = "Server Host:"; + // + // cboServer + // + this.cboServer.FormattingEnabled = true; + this.cboServer.Items.AddRange(new object[] { + "(local)"}); + this.cboServer.Location = new System.Drawing.Point(82, 28); + this.cboServer.Name = "cboServer"; + this.cboServer.Size = new System.Drawing.Size(180, 21); + this.cboServer.TabIndex = 0; + this.cboServer.SelectedIndexChanged += new System.EventHandler(this.cboServer_SelectedIndexChanged); + this.cboServer.DropDown += new System.EventHandler(this.cboServer_DropDown); + this.cboServer.TextChanged += new System.EventHandler(this.cboServer_TextChanged); + // + // cboAuthentication + // + this.cboAuthentication.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cboAuthentication.FormattingEnabled = true; + this.cboAuthentication.Items.AddRange(new object[] { + "Windows Authentication", + "SQL Server Authentication"}); + this.cboAuthentication.Location = new System.Drawing.Point(82, 55); + this.cboAuthentication.Name = "cboAuthentication"; + this.cboAuthentication.Size = new System.Drawing.Size(180, 21); + this.cboAuthentication.TabIndex = 1; + this.cboAuthentication.SelectedIndexChanged += new System.EventHandler(this.cboAuthentication_SelectedIndexChanged); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(3, 58); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(75, 13); + this.label5.TabIndex = 20; + this.label5.Text = "Authentication"; + // + // cboDatabase + // + this.cboDatabase.FormattingEnabled = true; + this.cboDatabase.Location = new System.Drawing.Point(82, 133); + this.cboDatabase.Name = "cboDatabase"; + this.cboDatabase.Size = new System.Drawing.Size(223, 21); + this.cboDatabase.TabIndex = 4; + this.cboDatabase.DropDown += new System.EventHandler(this.cboDatabase_DropDown); + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(3, 136); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(56, 13); + this.label6.TabIndex = 23; + this.label6.Text = "Database:"; + // + // txtUsername + // + this.txtUsername.Location = new System.Drawing.Point(82, 81); + this.txtUsername.Name = "txtUsername"; + this.txtUsername.Size = new System.Drawing.Size(180, 20); + this.txtUsername.TabIndex = 2; + this.txtUsername.TextChanged += new System.EventHandler(this.txtUsername_TextChanged); + // + // btnTest + // + this.btnTest.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnTest.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.btnTest.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnTest.Location = new System.Drawing.Point(327, 126); + this.btnTest.Name = "btnTest"; + this.btnTest.Size = new System.Drawing.Size(54, 28); + this.btnTest.TabIndex = 5; + this.btnTest.Text = "Test"; + this.btnTest.UseVisualStyleBackColor = true; + this.btnTest.Click += new System.EventHandler(this.btnTest_Click); + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblName.Location = new System.Drawing.Point(17, 5); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(105, 13); + this.lblName.TabIndex = 24; + this.lblName.Text = "Source Database"; + // + // gradientPanel1 + // + this.gradientPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gradientPanel1.Controls.Add(this.pictureBox1); + this.gradientPanel1.Controls.Add(this.lblName); + this.gradientPanel1.Location = new System.Drawing.Point(0, 0); + this.gradientPanel1.Name = "gradientPanel1"; + this.gradientPanel1.Size = new System.Drawing.Size(384, 24); + this.gradientPanel1.TabIndex = 26; + // + // pictureBox1 + // + this.pictureBox1.BackColor = System.Drawing.Color.Transparent; + this.pictureBox1.Image = global::OpenDBDiff.Schema.SQLServer.Generates.Properties.Resources.database_yellow; + this.pictureBox1.Location = new System.Drawing.Point(2, 3); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(15, 18); + this.pictureBox1.TabIndex = 27; + this.pictureBox1.TabStop = false; + // + // SqlServerConnectFront + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.White; + this.Controls.Add(this.gradientPanel1); + this.Controls.Add(this.cboDatabase); + this.Controls.Add(this.label6); + this.Controls.Add(this.btnTest); + this.Controls.Add(this.cboAuthentication); + this.Controls.Add(this.label5); + this.Controls.Add(this.cboServer); + this.Controls.Add(this.txtPassword); + this.Controls.Add(this.txtUsername); + this.Controls.Add(this.label4); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Name = "SqlServerConnectFront"; + this.Size = new System.Drawing.Size(384, 156); + this.gradientPanel1.ResumeLayout(false); + this.gradientPanel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private TextBox txtPassword; + private TextBox txtUsername; + private Label label4; + private Label label3; + private Label label2; + private ComboBox cboServer; + private ComboBox cboAuthentication; + private Label label5; + private Button btnTest; + private ComboBox cboDatabase; + private Label label6; + private Label lblName; + private Panel gradientPanel1; + private PictureBox pictureBox1; + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/SqlServerConnectFront.cs b/OpenDBDiff.Schema.SQLServer2005/Front/SqlServerConnectFront.cs new file mode 100644 index 0000000..96e353d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/SqlServerConnectFront.cs @@ -0,0 +1,309 @@ +using OpenDBDiff.Front; +using OpenDBDiff.Schema.SQLServer.Generates.Front.Util; +using System; +using System.Data.SqlClient; +using System.Windows.Forms; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front +{ + public partial class SqlServerConnectFront : UserControl, IFront + { + private Boolean isDatabaseFilled = false; + private Boolean isServerFilled = false; + + private delegate void clearCombo(); + + private delegate void addCombo(string item); + + public SqlServerConnectFront() + { + InitializeComponent(); + cboAuthentication.SelectedIndex = 1; + } + + private void cboAuthentication_SelectedIndexChanged(object sender, EventArgs e) + { + txtUsername.Enabled = cboAuthentication.SelectedIndex == 1; + txtPassword.Enabled = cboAuthentication.SelectedIndex == 1; + isDatabaseFilled = false; + ClearDatabase(); + } + + public string ErrorConnection { get; private set; } + + public bool UseWindowsAuthentication + { + get + { + return cboAuthentication.SelectedIndex == 0; + } + set + { + cboAuthentication.SelectedIndex = (value ? 0 : 1); + } + } + + public string DatabaseName + { + get { return cboDatabase.Text; } + set { cboDatabase.Text = value; } + } + + public string UserName + { + get { return txtUsername.Text; } + set { txtUsername.Text = value; } + } + + public string Password + { + get { return txtPassword.Text; } + set { txtPassword.Text = value; } + } + + public override string Text + { + get { return lblName.Text; } + set { lblName.Text = value; } + } + + public string ServerName + { + get { return cboServer.Text; } + set { cboServer.Text = value; } + } + + public Boolean TestConnection() + { + try + { + using (SqlConnection connection = new SqlConnection()) + { + connection.ConnectionString = this.ConnectionString; + connection.Open(); + connection.Close(); + return true; + } + } + catch (Exception ex) + { + ErrorConnection = ex.Message; + return false; + } + } + + private string BuildConnectionString(string server, string database) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + builder.DataSource = server.Trim(); + + // if database is ommitted the connection will be established to the default database for the user + if (!string.IsNullOrEmpty(database)) + builder.InitialCatalog = database.Trim(); + + builder.IntegratedSecurity = true; + return builder.ConnectionString; + } + + private string BuildConnectionString(string server, string database, string username, string password) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(BuildConnectionString(server, database)); + + builder.IntegratedSecurity = false; + builder.UserID = username; + builder.Password = password; + return builder.ConnectionString; + } + + public string ConnectionStringToDefaultDatabase + { + get + { + if (cboAuthentication.SelectedIndex == 1) + return BuildConnectionString(cboServer.Text, null, txtUsername.Text, txtPassword.Text); + else + return BuildConnectionString(cboServer.Text, null); + } + } + + public string ConnectionStringToMasterDatabase + { + get + { + if (cboAuthentication.SelectedIndex == 1) + return BuildConnectionString(cboServer.Text, "master", txtUsername.Text, txtPassword.Text); + else + return BuildConnectionString(cboServer.Text, "master"); + } + } + + public string ConnectionString + { + get + { + if (cboAuthentication.SelectedIndex == 1) + return BuildConnectionString(cboServer.Text, cboDatabase.Text, txtUsername.Text, txtPassword.Text); + else + return BuildConnectionString(cboServer.Text, cboDatabase.Text); + } + set + { + if (!String.IsNullOrWhiteSpace(value)) + { + var builder = new SqlConnectionStringBuilder(value); + + ServerName = builder.DataSource; + UseWindowsAuthentication = builder.IntegratedSecurity; + if (UseWindowsAuthentication) + { + UserName = ""; + Password = ""; + } + else + { + UserName = builder.UserID; + Password = builder.Password; + } + DatabaseName = builder.InitialCatalog; + } + else + { + cboAuthentication.SelectedIndex = 1; + UserName = ""; + Password = ""; + ServerName = "(local)"; + DatabaseName = ""; + } + } + } + + public Control Control + { + get + { + return this; + } + } + + private void btnTest_Click(object sender, EventArgs e) + { + if (TestConnection()) + MessageBox.Show(this, "Test successful!", "Test", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show(this, "Test failed!\r\n" + ErrorConnection, "Test", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + private void AddComboItem(string item) + { + if (!InvokeRequired) + cboDatabase.Items.Add(item); + else + { + addCombo add = new addCombo(AddComboItem); + Invoke(add, new string[] { item }); + } + } + + private void ClearDatabase() + { + if (!InvokeRequired) + cboDatabase.Items.Clear(); + else + { + clearCombo clear = new clearCombo(ClearDatabase); + Invoke(clear); + } + } + + private void FillDatabase() + { + if (!isDatabaseFilled) + { + String connectionString = ConnectionStringToDefaultDatabase; + ClearDatabase(); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + conn.Open(); + using (SqlCommand command = new SqlCommand("SELECT name,database_id FROM sys.databases ORDER BY Name", conn)) + { + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + AddComboItem(reader["Name"].ToString()); + } + isDatabaseFilled = true; + } + } + } + } + } + + private void cboServer_SelectedIndexChanged(object sender, EventArgs e) + { + isDatabaseFilled = false; + } + + private void txtUsername_TextChanged(object sender, EventArgs e) + { + isDatabaseFilled = false; + ClearDatabase(); + } + + private void txtPassword_TextChanged(object sender, EventArgs e) + { + isDatabaseFilled = false; + ClearDatabase(); + } + + private void cboServer_DropDown(object sender, EventArgs e) + { + try + { + if (!isServerFilled) + { + this.Cursor = Cursors.WaitCursor; + SqlServerList.Get().ForEach(item => cboServer.Items.Add(item)); + isServerFilled = true; + } + } + catch (Exception ex) + { + MessageBox.Show(this, ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + Cursor = Cursors.Default; + } + } + + private void cboDatabase_DropDown(object sender, EventArgs e) + { + try + { + this.Cursor = Cursors.WaitCursor; + FillDatabase(); + } + catch (Exception ex) + { + this.Cursor = Cursors.Default; + cboDatabase.Items.Clear(); + MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; + } + } + + private void cboServer_TextChanged(object sender, EventArgs e) + { + isDatabaseFilled = false; + } + + public override string ToString() + { + return string.Format($"Server: {ServerName}, Database: {DatabaseName}"); + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/SqlServerConnectFront.resx b/OpenDBDiff.Schema.SQLServer2005/Front/SqlServerConnectFront.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/SqlServerConnectFront.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer2005/Front/Util/SqlServerList.cs b/OpenDBDiff.Schema.SQLServer2005/Front/Util/SqlServerList.cs new file mode 100644 index 0000000..bb23dbb --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Front/Util/SqlServerList.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Data; +using System.Data.Sql; + +namespace OpenDBDiff.Schema.SQLServer.Generates.Front.Util +{ + internal static class SqlServerList + { + public static List Get() + { + SqlDataSourceEnumerator sqlSource = SqlDataSourceEnumerator.Instance; + DataTable dt = sqlSource.GetDataSources(); + + List serverList = new List(); + string serverName = null; + string instanceName = null; + + foreach (DataRow dr in dt.Rows) + { + serverName = dr["ServerName"].ToString(); + instanceName = dr["InstanceName"] != null ? dr["InstanceName"].ToString() : null; + + if (string.IsNullOrEmpty(instanceName)) + serverList.Add(serverName); + else + serverList.Add(string.Format("{0}\\{1}", serverName, instanceName)); + } + + return serverList; + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/OpenDBDiff.Schema.SQLServer.csproj b/OpenDBDiff.Schema.SQLServer2005/OpenDBDiff.Schema.SQLServer.csproj new file mode 100644 index 0000000..f278503 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/OpenDBDiff.Schema.SQLServer.csproj @@ -0,0 +1,171 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {EF2F571E-A7AD-40BE-8500-50A039159FC1} + Library + Properties + OpenDBDiff.Schema.SQLServer.Generates + OpenDBDiff.Schema.SQLServer + true + OpenDBDiff.Schema.SQLServer.snk + + + 3.5 + + + v4.5.2 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + -Microsoft.Naming#CA1702;-Microsoft.Naming#CA1700;-Microsoft.Naming#CA1712;-Microsoft.Naming#CA1713;-Microsoft.Naming#CA1714;-Microsoft.Naming#CA1709;-Microsoft.Naming#CA1704;-Microsoft.Naming#CA1708;-Microsoft.Naming#CA1715;-Microsoft.Naming#CA1710;-Microsoft.Naming#CA1720;-Microsoft.Naming#CA1707;-Microsoft.Naming#CA1722;-Microsoft.Naming#CA1711;-Microsoft.Naming#CA1716;-Microsoft.Naming#CA1717;-Microsoft.Naming#CA1725;-Microsoft.Naming#CA1719;-Microsoft.Naming#CA1721;-Microsoft.Naming#CA1701;-Microsoft.Naming#CA1703;-Microsoft.Naming#CA1724;-Microsoft.Naming#CA1726 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + -Microsoft.Naming#CA1702;-Microsoft.Naming#CA1700;-Microsoft.Naming#CA1712;-Microsoft.Naming#CA1713;-Microsoft.Naming#CA1714;-Microsoft.Naming#CA1709;-Microsoft.Naming#CA1704;-Microsoft.Naming#CA1708;-Microsoft.Naming#CA1715;-Microsoft.Naming#CA1710;-Microsoft.Naming#CA1720;-Microsoft.Naming#CA1707;-Microsoft.Naming#CA1722;-Microsoft.Naming#CA1711;-Microsoft.Naming#CA1716;-Microsoft.Naming#CA1717;-Microsoft.Naming#CA1725;-Microsoft.Naming#CA1719;-Microsoft.Naming#CA1721;-Microsoft.Naming#CA1701;-Microsoft.Naming#CA1703;-Microsoft.Naming#CA1724;-Microsoft.Naming#CA1726 + AnyCPU + + + + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + Form + + + AddExclusionPatternForm.cs + + + + UserControl + + + SqlOptionsFront.cs + + + + UserControl + + + SqlServerConnectFront.cs + + + + + + + True + True + Resources.resx + + + + + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768} + DBDiff.Front + + + {32ac9af6-db93-4354-b69f-6dbc65c70867} + DBDiff.Schema.SQLServer.Generates + + + {406558A0-1B98-4D0E-B8B6-2013700B065A} + DBDiff.Schema + + + + + .editorconfig + + + + + + AddExclusionPatternForm.cs + Designer + + + Designer + SqlOptionsFront.cs + + + SqlServerConnectFront.cs + Designer + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + + + + + + + + + \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer2005/OpenDBDiff.Schema.SQLServer.snk b/OpenDBDiff.Schema.SQLServer2005/OpenDBDiff.Schema.SQLServer.snk new file mode 100644 index 0000000..87f17f7 Binary files /dev/null and b/OpenDBDiff.Schema.SQLServer2005/OpenDBDiff.Schema.SQLServer.snk differ diff --git a/OpenDBDiff.Schema.SQLServer2005/Properties/AssemblyInfo.cs b/OpenDBDiff.Schema.SQLServer2005/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..695467d --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.Schema.SQLServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.Schema.SQLServer")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4f1e8d72-25ec-41e6-b56a-0091796271c8")] + +[assembly: CLSCompliant(true)] +[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)] diff --git a/OpenDBDiff.Schema.SQLServer2005/Properties/Resources.Designer.cs b/OpenDBDiff.Schema.SQLServer2005/Properties/Resources.Designer.cs new file mode 100644 index 0000000..25fd663 --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace OpenDBDiff.Schema.SQLServer.Generates.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OpenDBDiff.Schema.SQLServer.Generates.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap database_yellow { + get { + object obj = ResourceManager.GetObject("database_yellow", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/OpenDBDiff.Schema.SQLServer2005/Properties/Resources.resx b/OpenDBDiff.Schema.SQLServer2005/Properties/Resources.resx new file mode 100644 index 0000000..2ea7dea --- /dev/null +++ b/OpenDBDiff.Schema.SQLServer2005/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\database_yellow.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/OpenDBDiff.Schema.SQLServer2005/Resources/database_yellow.png b/OpenDBDiff.Schema.SQLServer2005/Resources/database_yellow.png new file mode 100644 index 0000000..45858a1 Binary files /dev/null and b/OpenDBDiff.Schema.SQLServer2005/Resources/database_yellow.png differ diff --git a/OpenDBDiff.Schema/Attributes/SchemaNodeAttribute.cs b/OpenDBDiff.Schema/Attributes/SchemaNodeAttribute.cs new file mode 100644 index 0000000..5f8f199 --- /dev/null +++ b/OpenDBDiff.Schema/Attributes/SchemaNodeAttribute.cs @@ -0,0 +1,33 @@ +using System; + +namespace OpenDBDiff.Schema.Attributes +{ + [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] + public sealed class SchemaNodeAttribute : Attribute + { + public SchemaNodeAttribute(string name) + { + this.Name = name; + this.Image = "Folder"; + } + + public SchemaNodeAttribute(string name, string image) + { + this.Name = name; + this.Image = image; + } + + public SchemaNodeAttribute(string name, string image, Boolean isFullName) + { + this.Name = name; + this.Image = image; + this.IsFullName = isFullName; + } + + public string Name { get; private set; } + + public string Image { get; private set; } + + public Boolean IsFullName { get; private set; } + } +} diff --git a/OpenDBDiff.Schema/Errors/MessageLog.cs b/OpenDBDiff.Schema/Errors/MessageLog.cs new file mode 100644 index 0000000..a0e09a4 --- /dev/null +++ b/OpenDBDiff.Schema/Errors/MessageLog.cs @@ -0,0 +1,25 @@ +namespace OpenDBDiff.Schema.Errors +{ + public class MessageLog + { + public enum LogType + { + Information = 0, + Warning = 1, + Error = 2 + } + + public MessageLog(string description, string fullDescription, LogType type) + { + this.Description = description; + this.FullDescription = fullDescription; + this.Type = type; + } + + public LogType Type { get; private set; } + + public string FullDescription { get; private set; } + + public string Description { get; private set; } + } +} diff --git a/OpenDBDiff.Schema/Events/ProgressEventArgs.cs b/OpenDBDiff.Schema/Events/ProgressEventArgs.cs new file mode 100644 index 0000000..95538b3 --- /dev/null +++ b/OpenDBDiff.Schema/Events/ProgressEventArgs.cs @@ -0,0 +1,17 @@ +using System; + +namespace OpenDBDiff.Schema.Events +{ + public class ProgressEventArgs : EventArgs + { + public string Message { get; set; } + + public ProgressEventArgs(string message, int progress) + { + this.Progress = progress; + this.Message = message; + } + + public int Progress { get; set; } + } +} diff --git a/OpenDBDiff.Schema/Events/ProgressEventHandler.cs b/OpenDBDiff.Schema/Events/ProgressEventHandler.cs new file mode 100644 index 0000000..c0bb2e1 --- /dev/null +++ b/OpenDBDiff.Schema/Events/ProgressEventHandler.cs @@ -0,0 +1,14 @@ +namespace OpenDBDiff.Schema.Events +{ + public class ProgressEventHandler + { + public delegate void ProgressHandler(ProgressEventArgs e); + + public static event ProgressHandler OnProgress; + + public static void RaiseOnChange(ProgressEventArgs e) + { + if (OnProgress != null) OnProgress(e); + } + } +} diff --git a/OpenDBDiff.Schema/Misc/SchemaException.cs b/OpenDBDiff.Schema/Misc/SchemaException.cs new file mode 100644 index 0000000..6c5db3e --- /dev/null +++ b/OpenDBDiff.Schema/Misc/SchemaException.cs @@ -0,0 +1,43 @@ +using System; +using System.Globalization; +using System.IO; +using System.Runtime.Serialization; +using System.Text; + +namespace OpenDBDiff.Schema.Misc +{ + [Serializable] + public class SchemaException : Exception + { + private static void Write(string message) + { + try + { + StreamWriter writer = new StreamWriter(Path.Combine(Path.GetTempPath(), "OpenDBDiff.log"), true, Encoding.ASCII); + writer.WriteLine("ERROR: " + DateTime.Now.ToString("yyyy/MM/dd hh:mm", CultureInfo.InvariantCulture) + "-" + message); + writer.Close(); + } + finally { } + } + + public SchemaException() : base() + { + } + + public SchemaException(string message) + : base(message) + { + Write(base.StackTrace); + } + + public SchemaException(string message, Exception exception) + : base(message, exception) + { + Write(exception.StackTrace); + } + + protected SchemaException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/OpenDBDiff.Schema/Model/IDatabase.cs b/OpenDBDiff.Schema/Model/IDatabase.cs new file mode 100644 index 0000000..b54fd3f --- /dev/null +++ b/OpenDBDiff.Schema/Model/IDatabase.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace OpenDBDiff.Schema.Model +{ + public interface IDatabase : ISchemaBase + { + bool IsCaseSensitive { get; } + SqlAction ActionMessage { get; } + IOption Options { get; } + + new SQLScriptList ToSqlDiff(ICollection selectedSchemas); + ISchemaBase Find(string objectFullName); + } +} diff --git a/OpenDBDiff.Schema/Model/IOption.cs b/OpenDBDiff.Schema/Model/IOption.cs new file mode 100644 index 0000000..38f4c79 --- /dev/null +++ b/OpenDBDiff.Schema/Model/IOption.cs @@ -0,0 +1,22 @@ +namespace OpenDBDiff.Schema.Model +{ + public interface IOption + { + IOptionFilter Filters { get; } + IOptionsContainer Defaults { get; } + IOptionsContainer Ignore { get; } + IOptionsContainer Script { get; } + IOptionComparison Comparison { get; } + + string Serialize(); + } + public interface IOptionsContainer + { + System.Collections.Generic.IDictionary GetOptions(); + } + + public interface IOptionComparison : IOptionsContainer + { + bool ReloadComparisonOnUpdate { get; set; } + } +} diff --git a/OpenDBDiff.Schema/Model/IOptionFilter.cs b/OpenDBDiff.Schema/Model/IOptionFilter.cs new file mode 100644 index 0000000..8f92e32 --- /dev/null +++ b/OpenDBDiff.Schema/Model/IOptionFilter.cs @@ -0,0 +1,7 @@ +namespace OpenDBDiff.Schema.Model +{ + public interface IOptionFilter : IOptionsContainer + { + bool IsItemIncluded(ISchemaBase item); + } +} diff --git a/OpenDBDiff.Schema/Model/ISchemaBase.cs b/OpenDBDiff.Schema/Model/ISchemaBase.cs new file mode 100644 index 0000000..8ba8f98 --- /dev/null +++ b/OpenDBDiff.Schema/Model/ISchemaBase.cs @@ -0,0 +1,31 @@ +using System; + +namespace OpenDBDiff.Schema.Model +{ + public interface ISchemaBase + { + ISchemaBase Clone(ISchemaBase parent); + int DependenciesCount { get; } + string FullName { get; } + int Id { get; set; } + Boolean HasState(ObjectStatus statusFind); + string Name { get; set; } + string Owner { get; set; } + ISchemaBase Parent { get; set; } + ObjectStatus Status { get; set; } + Boolean IsSystem { get; set; } + ObjectType ObjectType { get; set; } + Boolean GetWasInsertInDiffList(ScriptAction action); + void SetWasInsertInDiffList(ScriptAction action); + void ResetWasInsertInDiffList(); + string ToSqlDrop(); + string ToSqlAdd(); + string ToSql(); + SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection schemas); + SQLScript Create(); + SQLScript Drop(); + int CompareFullNameTo(string name, string myName); + Boolean IsCodeType { get; } + IDatabase RootParent { get; } + } +} diff --git a/OpenDBDiff.Schema/Model/ISchemaList.cs b/OpenDBDiff.Schema/Model/ISchemaList.cs new file mode 100644 index 0000000..0d27f4f --- /dev/null +++ b/OpenDBDiff.Schema/Model/ISchemaList.cs @@ -0,0 +1,16 @@ +namespace OpenDBDiff.Schema.Model +{ + public interface ISchemaList + where T : ISchemaBase + where P : ISchemaBase + { + void Add(T item); + SchemaList Clone(P parentObject); + bool Contains(string name); + T Find(int id); + T this[string name] { get; set; } + T this[int index] { get; set; } + P Parent { get; } + int Count { get; } + } +} diff --git a/OpenDBDiff.Schema/Model/SchemaBase.cs b/OpenDBDiff.Schema/Model/SchemaBase.cs new file mode 100644 index 0000000..a122164 --- /dev/null +++ b/OpenDBDiff.Schema/Model/SchemaBase.cs @@ -0,0 +1,286 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace OpenDBDiff.Schema.Model +{ + [DebuggerDisplay("Id: {Id} - Name: {Name} - Status: {status}")] + public abstract class SchemaBase : ISchemaBase + { + private ObjectStatus status; + private ISchemaBase parent; + private string nameCharacterOpen; + private string nameCharacterClose; + private Hashtable wasInsertInDiffList; + private IDatabase rootParent = null; + + protected SchemaBase(string nameCharacterOpen, string nameCharacterClose, ObjectType objectType) + { + this.Guid = System.Guid.NewGuid().ToString(); + this.ObjectType = objectType; + this.status = ObjectStatus.Original; + this.nameCharacterClose = nameCharacterClose; + this.nameCharacterOpen = nameCharacterOpen; + } + + /*protected object Clone(object vObj, ISchemaBase parentObject) + { + if (vObj.GetType().IsValueType || vObj.GetType() == Type.GetType("System.String")) + return vObj; + else + { + object newObject = Activator.CreateInstance(vObj.GetType(), new object[] {parentObject }); + foreach (PropertyInfo Item in newObject.GetType().GetProperties()) + { + if (Item.GetType().GetInterface("ICloneable") != null) + { + ICloneable IClone = (ICloneable)Item.GetValue(vObj, null); + Item.SetValue(newObject, IClone.Clone(), null); + } + else + Item.SetValue(newObject, Clone(Item.GetValue(vObj, null),parentObject), null); + } + foreach (FieldInfo Item in newObject.GetType().GetFields()) + { + if (Item.GetType().GetInterface("ICloneable") != null) + { + ICloneable IClone = (ICloneable)Item.GetValue(vObj); + Item.SetValue(newObject, IClone.Clone()); + } + else + Item.SetValue(newObject, Clone(Item.GetValue(vObj),parentObject)); + } + return newObject; + } + } */ + + /// + /// Instance's parent object + /// + public ISchemaBase Parent + { + get { return parent; } + set + { + rootParent = null; + parent = value; + } + } + + public IDatabase RootParent + { + get + { + if (rootParent != null) return rootParent; + if (this.Parent != null) + { + if (this.Parent.Parent != null) + if (this.Parent.Parent.Parent != null) + rootParent = (IDatabase)this.Parent.Parent.Parent; + else + rootParent = (IDatabase)this.Parent.Parent; + else + rootParent = (IDatabase)this.Parent; + } + else if (this is IDatabase) + { + rootParent = (IDatabase)this; + } + return rootParent; + } + } + + public int CompareFullNameTo(string name, string myName) + { + if (!RootParent.IsCaseSensitive) + return myName.ToUpper().CompareTo(name.ToUpper()); + else + return myName.CompareTo(name); + } + + /// + /// SQL Code for the database object + /// + public abstract string ToSql(); + + /// + /// SQL Code for drop the database object + /// + public abstract string ToSqlDrop(); + + /// + /// SQL Code for add the database object + /// + public abstract string ToSqlAdd(); + + /// + /// Deep clone the object + /// + /// Parent of the object + /// + public virtual ISchemaBase Clone(ISchemaBase parent) + { + return null; + } + + /// + /// Returns the list of SQL Scripts to execute to sync for the specified schemas + /// + /// + /// A list () of scripts to run to sync + /// + public virtual SQLScriptList ToSqlDiff(ICollection schemas) + { + return null; + } + + public virtual SQLScript Create() + { + throw new NotImplementedException(); + } + + public virtual SQLScript Drop() + { + throw new NotImplementedException(); + } + + /// + /// Returns if the obecet was already inserted in the list of scripts with differencies + /// + /// The action to check in the list + /// True if is already inserted. False if it wasn't + public Boolean GetWasInsertInDiffList(ScriptAction action) + { + if (wasInsertInDiffList != null) + return (wasInsertInDiffList.ContainsKey(action)); + else + return false; + } + + /// + /// Sets the object as inserted in the list of differences script + /// + public void SetWasInsertInDiffList(ScriptAction action) + { + if (wasInsertInDiffList == null) wasInsertInDiffList = new Hashtable(); + if (!wasInsertInDiffList.ContainsKey(action)) + wasInsertInDiffList.Add(action, true); + } + + public void ResetWasInsertInDiffList() + { + this.wasInsertInDiffList = null; + } + + /// + /// Unique GUID identifying the object + /// + public string Guid { get; set; } + + /// + /// Object type. + /// + public ObjectType ObjectType { get; set; } + + /// + /// ID del objeto. + /// + public int Id { get; set; } + + /// + /// Nombre completo del objeto, incluyendo el owner. + /// + public virtual string FullName + { + get + { + if (String.IsNullOrEmpty(Owner)) + return nameCharacterOpen + Name + nameCharacterClose; + else + return nameCharacterOpen + Owner + nameCharacterClose + "." + nameCharacterOpen + Name + nameCharacterClose; + } + } + + /// + /// Username of the owner of the object + /// + public string Owner { get; set; } + + /// + /// Nombre of the object + /// + public string Name { get; set; } + + /// + /// Determine if the database object if a System object or not + /// + public Boolean IsSystem { get; set; } + + /// + /// Returns the status of the object. By default is set to . When setting a value, it also affects to the status. + /// + public virtual ObjectStatus Status + { + get { return status; } + set + { + if (status != ObjectStatus.Rebuild && status != ObjectStatus.RebuildDependencies) + status = value; + + if (Parent == null) return; + + // Si el estado de la tabla era el original, lo cambia, sino deja el actual estado. + // If the state of the table was the original, it changes it, but leaves the current state. (Google translated) + if (Parent.Status == ObjectStatus.Original + || value == ObjectStatus.Rebuild + || value == ObjectStatus.RebuildDependencies) + { + switch (value) + { + case ObjectStatus.RebuildDependencies: + case ObjectStatus.Rebuild: + Parent.Status = value; + break; + + case ObjectStatus.Original: + break; + + default: + Parent.Status = ObjectStatus.Alter; + break; + } + } + } + } + + public Boolean HasState(ObjectStatus statusFind) + { + return ((this.Status & statusFind) == statusFind); + } + + public virtual Boolean IsCodeType + { + get { return false; } + } + + public virtual int DependenciesCount + { + get { return 0; } + } + + public virtual bool HasDependencies + { + get { return DependenciesCount > 0; } + } + + /// + /// Get if the SQL commands for the collection must build in one single statement + /// or one statmente for each item of the collection. + /// + public virtual Boolean MustBuildSqlInLine + { + get { return false; } + } + } +} diff --git a/OpenDBDiff.Schema/Model/SchemaList.cs b/OpenDBDiff.Schema/Model/SchemaList.cs new file mode 100644 index 0000000..fb9d1bf --- /dev/null +++ b/OpenDBDiff.Schema/Model/SchemaList.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenDBDiff.Schema.Model +{ + public class SchemaList : List, ISchemaList + where T : ISchemaBase + where P : ISchemaBase + { + private Dictionary nameMap = new Dictionary(); + private SearchSchemaBase allObjects = null; + private bool IsCaseSensitive = false; + + public SchemaList(P parent, SearchSchemaBase allObjects) + { + this.Parent = parent; + this.allObjects = allObjects; + this.Comparion = StringComparison.CurrentCultureIgnoreCase; + } + + public SchemaList Clone(P parentObject) + { + SchemaList options = new SchemaList(parentObject, allObjects); + this.ForEach(item => + { + object cloned = item.Clone(parentObject); + + //Not everything implements the clone methd, so make sure we got some actual cloned data before adding it back to the list + if (cloned != null) + options.Add((T)cloned); + }); + + return options; + } + + protected StringComparison Comparion { get; private set; } + + public SchemaList(P parent) + { + this.Parent = parent; + } + + public new void Add(T item) + { + var db = this.Parent.RootParent; + if (!db.Options.Filters.IsItemIncluded(item)) + return; + + base.Add(item); + if (allObjects != null) + allObjects.Add(item); + + string name = item.FullName; + IsCaseSensitive = item.RootParent.IsCaseSensitive; + if (!IsCaseSensitive) + name = name.ToUpper(); + + if (!nameMap.ContainsKey(name)) + nameMap.Add(name, base.Count - 1); + } + /// + /// Devuelve el objecto Padre perteneciente a la coleccion. + /// + public P Parent { get; private set; } + + /// + /// Devuelve el objeto correspondiente a un ID especifico. + /// + /// ID del objecto a buscar + /// Si no encontro nada, devuelve null, de lo contrario, el objeto + public T Find(int id) + { + return Find(Item => Item.Id == id); + } + + /// + /// Indica si el nombre del objecto existe en la coleccion de objectos del mismo tipo. + /// + /// + /// Nombre del objecto a buscar. + /// + /// + public Boolean Contains(string name) + { + if (IsCaseSensitive) + return nameMap.ContainsKey(name); + else + return nameMap.ContainsKey(name.ToUpper()); + } + + public virtual T this[string name] + { + get + { + try + { + if (IsCaseSensitive) + return this[nameMap[name]]; + else + return this[nameMap[name.ToUpper()]]; + } + catch + { + return default(T); + } + } + set + { + if (IsCaseSensitive) + base[nameMap[name]] = value; + else + base[nameMap[name.ToUpper()]] = value; + } + } + + public virtual SQLScriptList ToSqlDiff() + { + return ToSqlDiff(new List()); + } + public virtual SQLScriptList ToSqlDiff(ICollection schemas) + { + SQLScriptList listDiff = new SQLScriptList(); + foreach (var item in this.Where(item => (schemas.Count() == 0 || schemas.FirstOrDefault(sch => sch.Id == item.Id || (sch.Parent != null && sch.Parent.Id == item.Id)) != default(ISchemaBase)))) + { + item.ResetWasInsertInDiffList(); + var childrenSchemas = schemas.Where(s => s.Parent != null && s.Parent.Id == item.Id).ToList(); + listDiff.AddRange(item.ToSqlDiff(childrenSchemas).WarnMissingScript(item)); + } + return listDiff; + } + + + public virtual string ToSql() + { + return string.Join + ( + "\r\n", + this + .Where(item => !item.HasState(ObjectStatus.Drop)) + .Select(item => item.ToSql()) + ); + } + } +} diff --git a/OpenDBDiff.Schema/Model/SearchSchemaBase.cs b/OpenDBDiff.Schema/Model/SearchSchemaBase.cs new file mode 100644 index 0000000..f3da459 --- /dev/null +++ b/OpenDBDiff.Schema/Model/SearchSchemaBase.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.Schema.Model +{ + public class SearchSchemaBase + { + private Dictionary objectTypes; + private Dictionary objectParent; + private Dictionary objectId; + + public SearchSchemaBase() + { + objectTypes = new Dictionary(); + objectParent = new Dictionary(); + objectId = new Dictionary(); + } + + public void Add(ISchemaBase item) + { + if (objectTypes.ContainsKey(item.FullName.ToUpper())) + objectTypes.Remove(item.FullName.ToUpper()); + objectTypes.Add(item.FullName.ToUpper(), item.ObjectType); + if ((item.ObjectType == ObjectType.Constraint) || (item.ObjectType == ObjectType.Index) || (item.ObjectType == ObjectType.Trigger) || (item.ObjectType == ObjectType.CLRTrigger)) + { + if (objectParent.ContainsKey(item.FullName.ToUpper())) + objectParent.Remove(item.FullName.ToUpper()); + objectParent.Add(item.FullName.ToUpper(), item.Parent.FullName); + + if (objectId.ContainsKey(item.Id)) + objectId.Remove(item.Id); + objectId.Add(item.Id, item.FullName); + } + } + + + public Nullable GetType(string FullName) + { + if (objectTypes.ContainsKey(FullName.ToUpper())) + return objectTypes[FullName.ToUpper()]; + return null; + } + + public string GetParentName(string FullName) + { + return objectParent[FullName.ToUpper()]; + } + + public string GetFullName(int Id) + { + return objectId[Id]; + } + } +} diff --git a/OpenDBDiff.Schema/OpenDBDiff.Schema.csproj b/OpenDBDiff.Schema/OpenDBDiff.Schema.csproj new file mode 100644 index 0000000..8c75e8d --- /dev/null +++ b/OpenDBDiff.Schema/OpenDBDiff.Schema.csproj @@ -0,0 +1,116 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {406558A0-1B98-4D0E-B8B6-2013700B065A} + Library + Properties + OpenDBDiff.Schema + OpenDBDiff.Schema + true + OpenDBDiff.Schema.snk + + + 3.5 + + + v4.5.2 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + .editorconfig + + + + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + + + \ No newline at end of file diff --git a/OpenDBDiff.Schema/OpenDBDiff.Schema.snk b/OpenDBDiff.Schema/OpenDBDiff.Schema.snk new file mode 100644 index 0000000..4e2a065 Binary files /dev/null and b/OpenDBDiff.Schema/OpenDBDiff.Schema.snk differ diff --git a/OpenDBDiff.Schema/Properties/AssemblyInfo.cs b/OpenDBDiff.Schema/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5040499 --- /dev/null +++ b/OpenDBDiff.Schema/Properties/AssemblyInfo.cs @@ -0,0 +1,24 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.Schema")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.Schema")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("713fb09f-31e8-40a9-a6d0-93e28dc5ef67")] +[assembly: CLSCompliant(true)] diff --git a/OpenDBDiff.Schema/SQLScript.cs b/OpenDBDiff.Schema/SQLScript.cs new file mode 100644 index 0000000..f18a273 --- /dev/null +++ b/OpenDBDiff.Schema/SQLScript.cs @@ -0,0 +1,72 @@ +using System; + +namespace OpenDBDiff.Schema +{ + public class SQLScript : IComparable + { + public SQLScript(int deepvalue, string sqlScript, int dependenciesCount, ScriptAction action) + { + SQL = sqlScript; + Dependencies = dependenciesCount; + Status = action; + Deep = deepvalue; + //childs = new SQLScriptList(); + } + + public SQLScript(string sqlScript, int dependenciesCount, ScriptAction action) + { + SQL = sqlScript; + Dependencies = dependenciesCount; + Status = action; + //childs = new SQLScriptList(); + } + + /*public SQLScriptList Childs + { + get { return childs; } + set { childs = value; } + }*/ + + public int Deep { get; set; } + + public ScriptAction Status { get; set; } + + public int Dependencies { get; set; } + + public string SQL { get; set; } + + public bool IsDropAction + { + get + { + return ((Status == ScriptAction.DropView) || (Status == ScriptAction.DropFunction) || (Status == ScriptAction.DropStoredProcedure)); + } + } + + public bool IsAddAction + { + get + { + return ((Status == ScriptAction.AddView) || (Status == ScriptAction.AddFunction) || (Status == ScriptAction.AddStoredProcedure)); + } + } + + public int CompareTo(SQLScript other) + { + if (this.Deep == other.Deep) + { + if (this.Status == other.Status) + { + if (this.Status == ScriptAction.DropTable || this.Status == ScriptAction.DropConstraint || this.Status == ScriptAction.DropTrigger) + return other.Dependencies.CompareTo(this.Dependencies); + else + return this.Dependencies.CompareTo(other.Dependencies); + } + else + return this.Status.CompareTo(other.Status); + } + else + return this.Deep.CompareTo(other.Deep); + } + } +} diff --git a/OpenDBDiff.Schema/SQLScriptList.cs b/OpenDBDiff.Schema/SQLScriptList.cs new file mode 100644 index 0000000..4206a03 --- /dev/null +++ b/OpenDBDiff.Schema/SQLScriptList.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Text; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema +{ + public class SQLScriptList + { + private List list; + + public void Sort() + { + if (list != null) list.Sort(); + } + + public void Add(SQLScript item, int deep) + { + if (list == null) list = new List(); + if (item != null) + { + item.Deep = deep; + list.Add(item); + } + } + + public void Add(SQLScript item) + { + if (list == null) list = new List(); + if (item != null) list.Add(item); + } + + public void Add(string SQL, int dependencies, ScriptAction type) + { + if (list == null) list = new List(); + list.Add(new SQLScript(SQL, dependencies, type)); + } + + public void AddRange(SQLScriptList items) + { + for (int j = 0; j < items.Count; j++) + { + if (list == null) list = new List(); + list.Add(items[j]); + } + } + + public int Count + { + get { return (list == null) ? 0 : list.Count; } + } + + public SQLScript this[int index] + { + get { return list[index]; } + } + + /*private string ToSqlDown(SQLScript item) + { + string sql = ""; + for (int i = 0; i < item.Childs.Count; i++) + { + for (int k = 0; k < item.Childs[i].Childs.Count; k++) + { + for (int h = 0; h < item.Childs[i].Childs[k].Childs.Count; h++) + { + for (int l = 0; l < item.Childs[i].Childs[k].Childs[h].Childs.Count; l++) + { + for (int m = 0; m < item.Childs[i].Childs[k].Childs[h].Childs[l].Childs.Count; m++) + { + sql += item.Childs[i].Childs[k].Childs[h].Childs[l].Childs[m].SQL; + } + sql += item.Childs[i].Childs[k].Childs[h].Childs[l].SQL; + } + sql += item.Childs[i].Childs[k].Childs[h].SQL; + } + sql += item.Childs[i].Childs[k].SQL; + } + sql += item.Childs[i].SQL; + } + sql += item.SQL; + return sql; + }*/ + + public string ToSQL() + { + StringBuilder sql = new StringBuilder(); + this.Sort(); /*Ordena la lista antes de generar el script*/ + if (list != null) + { + for (int j = 0; j < list.Count; j++) + { + //if ((list[j].IsDropAction) || (!list[j].IsAddAction)) + sql.Append(list[j].SQL); //ToSqlDown(list[j]); + } + /*for (int j = list.Count-1; j >= 0; j--) + { + if (list[j].IsAddAction) + sql.Append(list[j].SQL); + }*/ + + } + return sql.ToString(); + } + + public SQLScriptList FindAlter() + { + SQLScriptList alter = new SQLScriptList(); + list.ForEach(item => { if ((item.Status == ScriptAction.AlterView) || (item.Status == ScriptAction.AlterFunction) || (item.Status == ScriptAction.AlterProcedure)) alter.Add(item); }); + return alter; + } + } + + public static class SQLScriptListExtensionMethod + { + public static SQLScriptList WarnMissingScript(this SQLScriptList scriptList, ISchemaBase scriptSource) + { + if (scriptList == null || scriptSource == null || scriptSource.Status == ObjectStatus.Original) + { + return scriptList; + } + + for (int i = 0; i < scriptList.Count; ++i) + { + if (!String.IsNullOrEmpty(scriptList[i].SQL)) + { + return scriptList; + } + } + + scriptList.Add(String.Format("\r\n--\r\n-- DIFF-ERROR 0x{0:x8}.{1:d3}: Missing {2} script for {3} '{4}'\r\n--\r\n\r\n", (int)scriptSource.Status, (int)scriptSource.ObjectType, scriptSource.Status, scriptSource.ObjectType, scriptSource.Name), 0, ScriptAction.None); + return scriptList; + } + } +} diff --git a/OpenDBDiff.Schema/SqlAction.cs b/OpenDBDiff.Schema/SqlAction.cs new file mode 100644 index 0000000..743745f --- /dev/null +++ b/OpenDBDiff.Schema/SqlAction.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Schema +{ + public class SqlAction + { + public SqlAction(ISchemaBase item) + { + if ((item.ObjectType == ObjectType.Column) || (item.ObjectType == ObjectType.Index) || (item.ObjectType == ObjectType.Constraint)) + this.Name = item.Name; + else + this.Name = item.FullName; + this.Action = item.Status; + this.Type = item.ObjectType; + Childs = new List(); + } + + public void Add(ISchemaBase item) + { + Childs.Add(new SqlAction(item)); + } + + public SqlAction this[string name] + { + get + { + for (int j = 0; j < Childs.Count; j++) + { + if (Childs[j].Name.Equals(name)) + return Childs[j]; + } + return null; + } + } + + public string Name { get; private set; } + + public ObjectType Type { get; set; } + + public ObjectStatus Action { get; set; } + + public List Childs { get; private set; } + + private string GetTypeName() + { + if (Type == ObjectType.Table) return "TABLE"; + if (Type == ObjectType.Column) return "COLUMN"; + if (Type == ObjectType.Constraint) return "CONSTRAINT"; + if (Type == ObjectType.Index) return "INDEX"; + if (Type == ObjectType.View) return "VIEW"; + if (Type == ObjectType.StoredProcedure) return "STORED PROCEDURE"; + if (Type == ObjectType.Synonym) return "SYNONYM"; + if (Type == ObjectType.Function) return "FUNCTION"; + if (Type == ObjectType.Assembly) return "ASSEMBLY"; + if (Type == ObjectType.Trigger) return "TRIGGER"; + return ""; + } + + private bool IsRoot + { + get + { + return ((this.Type != ObjectType.Function) && (this.Type != ObjectType.StoredProcedure) && (this.Type != ObjectType.View) && (this.Type != ObjectType.Table) && (this.Type != ObjectType.Database)); + } + } + + public string Message + { + get + { + string message = ""; + if (Action == ObjectStatus.Drop) + message = "DROP " + GetTypeName() + " " + Name + "\r\n"; + if (Action == ObjectStatus.Create) + message = "ADD " + GetTypeName() + " " + Name + "\r\n"; + if ((Action == ObjectStatus.Alter) || (Action == ObjectStatus.Rebuild) || (Action == ObjectStatus.RebuildDependencies)) + message = "MODIFY " + GetTypeName() + " " + Name + "\r\n"; + + Childs.ForEach(item => + { + if (item.IsRoot) + message += " "; + message += item.Message; + }); + return message; + } + } + } +} diff --git a/OpenDBDiff.Schema/StatusEnum.cs b/OpenDBDiff.Schema/StatusEnum.cs new file mode 100644 index 0000000..5f05199 --- /dev/null +++ b/OpenDBDiff.Schema/StatusEnum.cs @@ -0,0 +1,231 @@ +using System; +using System.ComponentModel; + +namespace OpenDBDiff.Schema +{ + /// + /// Original = The object has no modifications. + /// Create = The object must be created. + /// Drop = The object must be deleted. + /// Alter = The object has modifications. + /// AlterRebuild = The object has modifications, but a DROP and ADD must be done too. + /// AlterProperties = The object has modifications in its properties, but not in its structure. + /// + [Flags] + public enum ObjectStatus + { + /// + /// The object is unaltered + /// + Original = 0, + + /// + /// The object was altered + /// + Alter = 2, + + AlterBody = 4, + + /// + /// The object was altered but requires a rebuild + /// + Rebuild = 8, + + /// + /// The object has properties altered, but not in it's structure + /// + RebuildDependencies = 16, + + Update = 32, + Create = 64, + + /// + /// The object should be dropped + /// + Drop = 128, + + Disabled = 256, + + /// + /// The owner of the object changed + /// + ChangeOwner = 512, + + DropOlder = 1024, + Bind = 2048, + + /// + /// The permission set of the object changed + /// + PermissionSet = 4096, + + AlterWhitespace = 8192 + } + + public enum ScriptAction + { + None = 0, + UseDatabase = 1, + AddFileGroup = 2, + AddFile = 3, + AlterFile = 4, + AlterFileGroup = 5, + UnbindRuleColumn = 6, + UnbindRuleType = 7, + DropRule = 8, + AddRule = 9, + + DropFullTextIndex = 10, + DropConstraintFK = 11, + DropConstraint = 12, + DropConstraintPK = 13, + DropSynonyms = 14, + DropStoredProcedure = 15, + DropTrigger = 16, + DropView = 17, + DropFunction = 17, + DropIndex = 18, + DropTable = 20, + AlterColumnFormula = 21, + AlterColumn = 22, + AddRole = 23, + AddUser = 24, + AddSchema = 25, + AddDefault = 26, + AddAssembly = 27, + AddAssemblyFile = 28, + AddUserDataType = 29, + AddTableType = 30, + AlterPartitionFunction = 31, + AddPartitionFunction = 32, + AddPartitionScheme = 33, + AddFullText = 34, + AddXMLSchema = 35, + AlterAssembly = 36, + UpdateTable = 37, + AlterTable = 38, + AlterIndex = 39, + AlterFullTextIndex = 40, + AddTable = 41, + RebuildTable = 42, + AlterColumnRestore = 43, + AlterColumnFormulaRestore = 44, + AlterFunction = 45, + AlterView = 46, + AlterProcedure = 47, + AddIndex = 48, + AddFunction = 49, + AddView = 49, /*AddFunction and AddView must have the same number!!!*/ + AddTrigger = 50, + AddConstraint = 51, + AddConstraintPK = 52, + AddConstraintFK = 53, + AlterConstraint = 54, + AddFullTextIndex = 55, + EnabledTrigger = 56, + AddSynonyms = 57, + AddStoredProcedure = 58, + DropOptions = 59, + AddOptions = 60, + + AlterTableChangeTracking = 61, + + DropFullText = 62, + DropTableType = 63, + DropUserDataType = 64, + DropXMLSchema = 65, + DropAssemblyUserDataType = 66, + DropAssemblyFile = 67, + DropAssembly = 68, + DropDefault = 69, + + DropPartitionScheme = 70, + DropPartitionFunction = 71, + + DropSchema = 72, + DropUser = 73, + DropRole = 74, + DropFile = 75, + DropFileGroup = 76, + AddExtendedProperty = 77, + DropExtendedProperty = 78 + } + + public enum ObjectType + { + None = 0, + Table = 1, + Column = 2, + Trigger = 3, + Constraint = 4, + + [Description("Constraint Column")] + ConstraintColumn = 5, + + Index = 6, + + [Description("Index Column")] + IndexColumn = 7, + + [Description("User Data Type")] + UserDataType = 8, + + [Description("XML Schema")] + XMLSchema = 9, + + View = 10, + Function = 11, + + [Description("Stored Procedure")] + StoredProcedure = 12, + + [Description("Table Option")] + TableOption = 13, + + Database = 14, + Schema = 15, + + [Description("File Group")] + FileGroup = 16, + + File = 17, + Default = 18, + Rule = 19, + Synonym = 20, + Assembly = 21, + User = 22, + Role = 23, + + [Description("Full Text")] + FullText = 24, + + [Description("Assembly File")] + AssemblyFile = 25, + + [Description("CLR Stored Procedure")] + CLRStoredProcedure = 26, + + [Description("CLR Trigger")] + CLRTrigger = 27, + + [Description("CLR Function")] + CLRFunction = 28, + + [Description("Extended Property")] + ExtendedProperty = 30, + + Partition = 31, + + [Description("Partition Function")] + PartitionFunction = 32, + + [Description("Partition Scheme")] + PartitionScheme = 33, + + [Description("Table Type")] + TableType = 34, + + [Description("Full Text Index")] + FullTextIndex = 35 + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareAssemblies.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareAssemblies.cs new file mode 100644 index 0000000..52a8695 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareAssemblies.cs @@ -0,0 +1,59 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareAssemblies : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Assembly node) + { + if (!node.Compare(originFields[node.FullName])) + { + Assembly newNode = (Assembly)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + + if (node.Text.Equals(originFields[node.FullName].Text)) + { + if (!node.PermissionSet.Equals(originFields[node.FullName].PermissionSet)) + newNode.Status += (int)ObjectStatus.PermissionSet; + if (!node.Owner.Equals(originFields[node.FullName].Owner)) + newNode.Status += (int)ObjectStatus.ChangeOwner; + } + else + newNode.Status = ObjectStatus.Rebuild; + + originFields[node.FullName].Files.ForEach(item => + { + if (!newNode.Files.Contains(item.FullName)) + newNode.Files.Add(new AssemblyFile(newNode, item, ObjectStatus.Drop)); + else + item.Status = ObjectStatus.Alter; + }); + newNode.Files.ForEach(item => + { + if (!originFields[node.FullName].Files.Contains(item.FullName)) + { + item.Status = ObjectStatus.Create; + } + }); + CompareExtendedProperties(originFields[node.FullName], newNode); + originFields[node.FullName] = newNode; + } + } + + protected override void DoNew(SchemaList originFields, Assembly node) + { + bool pass = true; + Assembly newNode = (Assembly)node.Clone(originFields.Parent); + if ((((Database)newNode.RootParent).Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2005) + && (((Database)node.RootParent).Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008)) + pass = node.FullName.Equals("Microsoft.SqlServer.Types"); + if (pass) + { + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareBase.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareBase.cs new file mode 100644 index 0000000..e81bca4 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareBase.cs @@ -0,0 +1,91 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Generates; +using OpenDBDiff.SqlServer.Schema.Model; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal abstract class CompareBase where T : ISchemaBase + { + protected virtual void DoUpdate(SchemaList originFields, T node) where Root : ISchemaBase + { + + } + + protected virtual void DoNew(SchemaList originFields, T node) where Root : ISchemaBase + { + T newNode = node;//.Clone(originFields.Parent); + newNode.Parent = originFields.Parent; + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected void DoDelete(T node) + { + node.Status = ObjectStatus.Drop; + } + + public void GenerateDifferences(SchemaList originFields, SchemaList destinationFields) where Root : ISchemaBase + { + bool has = true; + int destinationIndex = 0; + int originIndex = 0; + int destinationCount = destinationFields.Count; + int originCount = originFields.Count; + T node; + + while (has) + { + has = false; + if (destinationCount > destinationIndex) + { + node = destinationFields[destinationIndex]; + Generate.RaiseOnCompareProgress("Comparing Destination {0}: [{1}]", node.ObjectType, node.Name); + if (!originFields.Contains(node.FullName)) + { + Generate.RaiseOnCompareProgress("Adding {0}: [{1}]", node.ObjectType, node.Name); + DoNew(originFields, node); + } + else + { + Generate.RaiseOnCompareProgress("Updating {0}: [{1}]", node.ObjectType, node.Name); + DoUpdate(originFields, node); + } + + destinationIndex++; + has = true; + } + + if (originCount > originIndex) + { + node = originFields[originIndex]; + Generate.RaiseOnCompareProgress("Comparing Source {0}: [{1}]", node.ObjectType, node.Name); + if (!destinationFields.Contains(node.FullName)) + { + Generate.RaiseOnCompareProgress("Deleting {0}: [{1}]", node.ObjectType, node.Name); + DoDelete(node); + } + + originIndex++; + has = true; + } + } + } + + protected static void CompareExtendedProperties(ISQLServerSchemaBase origin, ISQLServerSchemaBase destination) + { + List dropList = (from node in origin.ExtendedProperties + where !destination.ExtendedProperties.Exists(item => item.Name.Equals(node.Name, StringComparison.CurrentCultureIgnoreCase)) + select node).ToList(); + List addList = (from node in destination.ExtendedProperties + where !origin.ExtendedProperties.Exists(item => item.Name.Equals(node.Name, StringComparison.CurrentCultureIgnoreCase)) + select node).ToList(); + dropList.ForEach(item => { item.Status = ObjectStatus.Drop; }); + addList.ForEach(item => { item.Status = ObjectStatus.Create; }); + origin.ExtendedProperties.AddRange(addList); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareCLRFunction.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareCLRFunction.cs new file mode 100644 index 0000000..6617b92 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareCLRFunction.cs @@ -0,0 +1,19 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareCLRFunction : CompareBase + { + protected override void DoUpdate(SchemaList originFields, CLRFunction node) + { + if (!node.Compare(originFields[node.FullName])) + { + CLRFunction newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareCLRStoredProcedure.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareCLRStoredProcedure.cs new file mode 100644 index 0000000..aab90d4 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareCLRStoredProcedure.cs @@ -0,0 +1,19 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareCLRStoredProcedure : CompareBase + { + protected override void DoUpdate(SchemaList originFields, CLRStoredProcedure node) + { + if (!node.Compare(originFields[node.FullName])) + { + CLRStoredProcedure newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareCLRTriggers.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareCLRTriggers.cs new file mode 100644 index 0000000..cb6e5a7 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareCLRTriggers.cs @@ -0,0 +1,20 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareCLRTriggers : CompareBase + { + protected override void DoUpdate(SchemaList originFields, CLRTrigger node) + { + if (!node.Compare(originFields[node.FullName])) + { + CLRTrigger newNode = node; + newNode.Status = ObjectStatus.Alter; + CompareExtendedProperties(newNode, originFields[node.FullName]); + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareColumns.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareColumns.cs new file mode 100644 index 0000000..1934f6b --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareColumns.cs @@ -0,0 +1,92 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + public class CompareColumns + { + public void GenerateDifferences(Columns originFields, Columns destinationFields) where T : ISchemaBase + { + int restPosition = 0; + int sumPosition = 0; + + foreach (Column node in originFields) + { + if (!destinationFields.Contains(node.FullName)) + { + node.Status = ObjectStatus.Drop; + restPosition++; + } + else + originFields[node.FullName].Position -= restPosition; + } + foreach (Column node in destinationFields) + { + if (!originFields.Contains(node.FullName)) + { + Column newNode = node.Clone(originFields.Parent); + if ((newNode.Position == 1) || ((newNode.DefaultConstraint == null) && (!newNode.IsNullable) && (!newNode.IsComputed) && (!newNode.IsIdentity) && (!newNode.IsIdentityForReplication))) + { + newNode.Status = ObjectStatus.Create; + newNode.Parent.Status = ObjectStatus.Rebuild; + } + else + newNode.Status = ObjectStatus.Create; + sumPosition++; + originFields.Add(newNode); + } + else + { + Column originField = originFields[node.FullName]; + /*ColumnConstraint oldDefault = null; + if (originField.DefaultConstraint != null) + oldDefault = originField.DefaultConstraint.Clone(originField);*/ + Boolean IsColumnEqual = Column.Compare(originField, node); + if ((!IsColumnEqual) || (originField.Position != node.Position)) + { + if (Column.CompareIdentity(originField, node)) + { + + if (node.HasToRebuildOnlyConstraint) + { + node.Status = ObjectStatus.Alter; + if ((originField.IsNullable) && (!node.IsNullable)) + node.Status += (int)ObjectStatus.Update; + } + else + { + if (node.HasToRebuild(originField.Position + sumPosition, originField.Type, originField.IsFileStream)) + node.Status = ObjectStatus.Rebuild; + else + { + if (!IsColumnEqual) + { + node.Status = ObjectStatus.Alter; + if ((originField.IsNullable) && (!node.IsNullable)) + node.Status += (int)ObjectStatus.Update; + } + } + } + if (node.Status != ObjectStatus.Rebuild) + { + if (!Column.CompareRule(originField, node)) + { + node.Status += (int)ObjectStatus.Bind; + } + } + } + else + { + node.Status = ObjectStatus.Rebuild; + } + originFields[node.FullName] = node.Clone(originFields.Parent); + } + originFields[node.FullName].DefaultConstraint = CompareColumnsConstraints.GenerateDifferences(originField, node); + } + } + } + } +} + diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareColumnsConstraints.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareColumnsConstraints.cs new file mode 100644 index 0000000..fff3b19 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareColumnsConstraints.cs @@ -0,0 +1,73 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareColumnsConstraints : CompareBase + { + public static ColumnConstraint GenerateDifferences(Column originFields, Column destinationFields) + { + if ((originFields.DefaultConstraint == null) && (destinationFields.DefaultConstraint != null)) + { + originFields.DefaultConstraint = destinationFields.DefaultConstraint.Clone(originFields); + originFields.DefaultConstraint.Status = ObjectStatus.Create; + originFields.DefaultConstraint.Parent.Status = ObjectStatus.Original; + originFields.DefaultConstraint.Parent.Parent.Status = ObjectStatus.Alter; + } + else + { + if ((originFields.DefaultConstraint != null) && (destinationFields.DefaultConstraint != null)) + { + if (!ColumnConstraint.Compare(originFields.DefaultConstraint, destinationFields.DefaultConstraint)) + { + originFields.DefaultConstraint = destinationFields.DefaultConstraint.Clone(originFields); + //Indico que hay un ALTER TABLE, pero sobre la columna, no seteo ningun estado. + originFields.DefaultConstraint.Status = ObjectStatus.Alter; + originFields.DefaultConstraint.Parent.Status = ObjectStatus.Original; + originFields.DefaultConstraint.Parent.Parent.Status = ObjectStatus.Alter; + } + } + else + if ((originFields.DefaultConstraint != null) && (destinationFields.DefaultConstraint == null)) + { + originFields.DefaultConstraint.Status = ObjectStatus.Drop; + originFields.DefaultConstraint.Parent.Status = ObjectStatus.Original; + originFields.DefaultConstraint.Parent.Parent.Status = ObjectStatus.Alter; + } + } + /*foreach (ColumnConstraint node in destinationFields) + { + if (!originFields.Exists(node.FullName)) + { + node.Status = ObjectStatusType.CreateStatus; + originFields.Parent.Status = ObjectStatusType.OriginalStatus; + originFields.Parent.Parent.Status = ObjectStatusType.AlterStatus; + originFields.Add(node); + } + else + { + if (!ColumnConstraint.Compare(originFields[node.FullName], node)) + { + ColumnConstraint newNode = node.Clone(originFields.Parent); + //Indico que hay un ALTER TABLE, pero sobre la columna, no seteo ningun estado. + newNode.Status = ObjectStatusType.AlterStatus; + newNode.Parent.Status = ObjectStatusType.OriginalStatus; + newNode.Parent.Parent.Status = ObjectStatusType.AlterStatus; + originFields[node.FullName] = newNode; + + } + } + } + + MarkDrop(originFields, destinationFields, node => + { + node.Status = ObjectStatusType.DropStatus; + originFields.Parent.Status = ObjectStatusType.OriginalStatus; + originFields.Parent.Parent.Status = ObjectStatusType.AlterStatus; + } + ); + */ + return originFields.DefaultConstraint; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareConstraints.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareConstraints.cs new file mode 100644 index 0000000..a4dffd5 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareConstraints.cs @@ -0,0 +1,41 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareConstraints : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Constraint node) + { + Constraint origin = originFields[node.FullName]; + if (!Constraint.Compare(origin, node)) + { + Constraint newNode = (Constraint)node.Clone(originFields.Parent); + if (node.IsDisabled == origin.IsDisabled) + { + newNode.Status = ObjectStatus.Alter; + } + else + newNode.Status = ObjectStatus.Alter + (int)ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + else + { + if (node.IsDisabled != origin.IsDisabled) + { + Constraint newNode = (Constraint)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + } + } + + protected override void DoNew(SchemaList originFields, Constraint node) + { + Constraint newNode = (Constraint)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareDDLTriggers.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareDDLTriggers.cs new file mode 100644 index 0000000..54a4c6b --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareDDLTriggers.cs @@ -0,0 +1,29 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareDDLTriggers : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Trigger node) + { + if (!node.Compare(originFields[node.FullName])) + { + Trigger newNode = (Trigger)node.Clone(originFields.Parent); + if (!newNode.Text.Equals(originFields[node.FullName].Text)) + newNode.Status = ObjectStatus.Alter; + if (node.IsDisabled != originFields[node.FullName].IsDisabled) + newNode.Status = newNode.Status + (int)ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + } + + protected override void DoNew(SchemaList originFields, Trigger node) + { + Trigger newNode = (Trigger)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareDatabase.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareDatabase.cs new file mode 100644 index 0000000..812074c --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareDatabase.cs @@ -0,0 +1,50 @@ +using OpenDBDiff.Abstractions.Schema.Misc; +using OpenDBDiff.SqlServer.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal static class CompareDatabase + { + /// + /// Generates the differences to migrate a schema from origin to destination + /// + /// The Origin schema is the schema before our generated actions are applied. + /// The Destination schema is the schema after our actions are applied. + /// + /// + public static Database GenerateDifferences(Database origin, Database destination) + { + try + { + Database data = origin; + (new CompareTables()).GenerateDifferences(origin.Tables, destination.Tables); + (new CompareAssemblies()).GenerateDifferences(origin.Assemblies, destination.Assemblies); + (new CompareUserDataTypes()).GenerateDifferences(origin.UserTypes, destination.UserTypes); + (new CompareXMLSchemas()).GenerateDifferences(origin.XmlSchemas, destination.XmlSchemas); + (new CompareSchemas()).GenerateDifferences(origin.Schemas, destination.Schemas); + (new CompareFileGroups()).GenerateDifferences(origin.FileGroups, destination.FileGroups); + (new CompareRules()).GenerateDifferences(origin.Rules, destination.Rules); + (new CompareDDLTriggers()).GenerateDifferences(origin.DDLTriggers, destination.DDLTriggers); + (new CompareSynonyms()).GenerateDifferences(origin.Synonyms, destination.Synonyms); + (new CompareUsers()).GenerateDifferences(origin.Users, destination.Users); + (new CompareStoredProcedures()).GenerateDifferences(origin.Procedures, destination.Procedures); + (new CompareCLRStoredProcedure()).GenerateDifferences(origin.CLRProcedures, destination.CLRProcedures); + (new CompareCLRFunction()).GenerateDifferences(origin.CLRFunctions, destination.CLRFunctions); + (new CompareViews()).GenerateDifferences(origin.Views, destination.Views); + (new CompareFunctions()).GenerateDifferences(origin.Functions, destination.Functions); + (new CompareRoles()).GenerateDifferences(origin.Roles, destination.Roles); + (new ComparePartitionFunction()).GenerateDifferences(origin.PartitionFunctions, destination.PartitionFunctions); + (new ComparePartitionSchemes()).GenerateDifferences(origin.PartitionSchemes, destination.PartitionSchemes); + (new CompareTableType()).GenerateDifferences(origin.TablesTypes, destination.TablesTypes); + (new CompareFullText()).GenerateDifferences(origin.FullText, destination.FullText); + data.SourceInfo = destination.Info; + return data; + } + catch (Exception ex) + { + throw new SchemaException(ex.Message, ex); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareFileGroups.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareFileGroups.cs new file mode 100644 index 0000000..6a77661 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareFileGroups.cs @@ -0,0 +1,45 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareFileGroups : CompareBase + { + protected override void DoNew(SchemaList originFields, FileGroup node) + { + FileGroup newNode = (FileGroup)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + /*If the Logical File Name exists in another filegroup, + * we must change the new Logical File Name. + */ + originFields.ForEach(file => + { + if (file.Status != ObjectStatus.Drop) + { + file.Files.ForEach(group => + { + newNode.Files.ForEach(ngroup => + { + if (group.CompareFullNameTo(group.FullName, ngroup.FullName) == 0) + { + newNode.Files[ngroup.FullName].Name = group.Name + "_2"; + } + }); + }); + } + }); + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, FileGroup node) + { + if (!FileGroup.Compare(node, originFields[node.FullName])) + { + FileGroup newNode = (FileGroup)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareFullText.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareFullText.cs new file mode 100644 index 0000000..889f020 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareFullText.cs @@ -0,0 +1,24 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareFullText : CompareBase + { + protected override void DoUpdate(SchemaList originFields, FullText node) + { + if (!node.Compare(originFields[node.FullName])) + { + FullText newNode = node; //.Clone(originFields.Parent); + if (node.IsDefault != originFields[node.FullName].IsDefault) + newNode.Status += (int)ObjectStatus.Disabled; + if (!node.Owner.Equals(originFields[node.FullName].Owner)) + newNode.Status += (int)ObjectStatus.ChangeOwner; + if (node.IsAccentSensity != originFields[node.FullName].IsAccentSensity) + newNode.Status += (int)ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareFullTextIndex.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareFullTextIndex.cs new file mode 100644 index 0000000..96d9868 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareFullTextIndex.cs @@ -0,0 +1,29 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareFullTextIndex : CompareBase + { + protected override void DoNew(SchemaList originFields, FullTextIndex node) + { + FullTextIndex newNode = (FullTextIndex)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, FullTextIndex node) + { + if (!node.Compare(originFields[node.FullName])) + { + FullTextIndex newNode = (FullTextIndex)node.Clone(originFields.Parent); + if (node.IsDisabled != originFields[node.FullName].IsDisabled) + newNode.Status += (int)ObjectStatus.Disabled; + else + newNode.Status += (int)ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareFunctions.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareFunctions.cs new file mode 100644 index 0000000..06e91be --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareFunctions.cs @@ -0,0 +1,45 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareFunctions : CompareBase + { + protected override void DoNew(SchemaList originFields, Function node) + { + Function newNode = (Function)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + newNode.DependenciesIn.ForEach(dep => + { + ISchemaBase item = ((Database)((ISchemaBase)originFields.Parent)).Find(dep); + if (item != null) + { + if (item.IsCodeType) + ((ICode)item).DependenciesOut.Add(newNode.FullName); + } + } + ); + } + + protected override void DoUpdate(SchemaList originFields, Function node) + { + if (!node.Compare(originFields[node.FullName])) + { + Function newNode = (Function)node.Clone(originFields.Parent); + newNode.DependenciesIn.AddRange(originFields[node.FullName].DependenciesIn); + newNode.DependenciesOut.AddRange(originFields[node.FullName].DependenciesOut); + + newNode.Status = ObjectStatus.Alter; + if (newNode.IsSchemaBinding) + newNode.Status += (int)ObjectStatus.RebuildDependencies; + if (newNode.HasToRebuild) + newNode.Status += (int)ObjectStatus.Rebuild; + else + newNode.Status += (int)ObjectStatus.AlterBody; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareIndexes.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareIndexes.cs new file mode 100644 index 0000000..bfb92b2 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareIndexes.cs @@ -0,0 +1,31 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareIndexes : CompareBase + { + protected override void DoNew(SchemaList originFields, Index node) + { + Index newNode = (Index)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, Index node) + { + if (!Index.Compare(node, originFields[node.FullName])) + { + Index newNode = (Index)node.Clone(originFields.Parent); + if (!Index.CompareExceptIsDisabled(node, originFields[node.FullName])) + { + newNode.Status = ObjectStatus.Alter; + } + else + newNode.Status = ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/ComparePartitionFunction.cs b/OpenDBDiff.SqlServer.Schema/Compare/ComparePartitionFunction.cs new file mode 100644 index 0000000..76117cf --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/ComparePartitionFunction.cs @@ -0,0 +1,32 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class ComparePartitionFunction : CompareBase + { + protected override void DoUpdate(SchemaList originFields, PartitionFunction node) + { + if (!PartitionFunction.Compare(node, originFields[node.FullName])) + { + PartitionFunction newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Rebuild; + originFields[node.FullName] = newNode; + } + else + { + if (!PartitionFunction.CompareValues(node, originFields[node.FullName])) + { + PartitionFunction newNode = node.Clone(originFields.Parent); + if (newNode.Values.Count == originFields[node.FullName].Values.Count) + newNode.Status = ObjectStatus.Rebuild; + else + newNode.Status = ObjectStatus.Alter; + newNode.Old = originFields[node.FullName].Clone(originFields.Parent); + originFields[node.FullName] = newNode; + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/ComparePartitionSchemes.cs b/OpenDBDiff.SqlServer.Schema/Compare/ComparePartitionSchemes.cs new file mode 100644 index 0000000..8c2fda3 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/ComparePartitionSchemes.cs @@ -0,0 +1,19 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class ComparePartitionSchemes : CompareBase + { + protected override void DoUpdate(SchemaList originFields, PartitionScheme node) + { + if (!PartitionScheme.Compare(node, originFields[node.FullName])) + { + PartitionScheme newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Rebuild; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareRoles.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareRoles.cs new file mode 100644 index 0000000..9d9bdc9 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareRoles.cs @@ -0,0 +1,19 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareRoles : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Role node) + { + if (!node.Compare(originFields[node.FullName])) + { + Role newNode = node; + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareRules.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareRules.cs new file mode 100644 index 0000000..4ea4197 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareRules.cs @@ -0,0 +1,26 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareRules : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Rule node) + { + if (!node.Compare(originFields[node.FullName])) + { + Rule newNode = node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + + protected override void DoNew(SchemaList originFields, Rule node) + { + Rule newNode = node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareSchemas.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareSchemas.cs new file mode 100644 index 0000000..9ceff65 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareSchemas.cs @@ -0,0 +1,7 @@ +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareSchemas : CompareBase + { + + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareStoredProcedures.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareStoredProcedures.cs new file mode 100644 index 0000000..2583c04 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareStoredProcedures.cs @@ -0,0 +1,28 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareStoredProcedures : CompareBase + { + protected override void DoUpdate(SchemaList originFields, StoredProcedure node) + { + if (!node.Compare(originFields[node.FullName])) + { + StoredProcedure newNode = node; //.Clone(originFields.Parent); + + if (node.CompareExceptWhitespace(originFields[node.FullName])) + { + newNode.Status = ObjectStatus.AlterWhitespace; + } + else + { + newNode.Status = ObjectStatus.Alter; + } + + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareSynonyms.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareSynonyms.cs new file mode 100644 index 0000000..990cb33 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareSynonyms.cs @@ -0,0 +1,19 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareSynonyms : CompareBase + { + protected override void DoUpdate(SchemaList originFields, Synonym node) + { + if (!Synonym.Compare(node, originFields[node.FullName])) + { + Synonym newNode = node; //.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareTableType.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareTableType.cs new file mode 100644 index 0000000..a792cea --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareTableType.cs @@ -0,0 +1,45 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareTableType : CompareBase + { + protected override void DoUpdate(SchemaList originFields, TableType node) + { + if (node.Status != ObjectStatus.Drop) + { + TableType tablaOriginal = originFields[node.FullName]; + (new CompareColumns()).GenerateDifferences(tablaOriginal.Columns, node.Columns); + (new CompareConstraints()).GenerateDifferences(tablaOriginal.Constraints, node.Constraints); + (new CompareIndexes()).GenerateDifferences(tablaOriginal.Indexes, node.Indexes); + } + } + + /*public static void GenerateDifferences(SchemaList originTables, SchemaList destinationTables) + { + MarkDrop(originTables, destinationTables); + + foreach (TableType node in destinationTables) + { + if (!originTables.Exists(node.FullName)) + { + node.Status = ObjectStatusType.CreateStatus; + node.Parent = originTables.Parent; + originTables.Add(node); + } + else + { + if (node.Status != ObjectStatusType.DropStatus) + { + TableType tablaOriginal = originTables[node.FullName]; + CompareColumns.GenerateDifferences(tablaOriginal.Columns, node.Columns); + CompareConstraints.GenerateDifferences(tablaOriginal.Constraints, node.Constraints); + CompareIndexes.GenerateDifferences(tablaOriginal.Indexes, node.Indexes); + } + } + } + }*/ + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareTables.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareTables.cs new file mode 100644 index 0000000..0c17734 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareTables.cs @@ -0,0 +1,93 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareTables : CompareBase
+ { + protected override void DoUpdate(SchemaList originFields, Table node) + { + if (node.Status != ObjectStatus.Drop) + { + Table tablaOriginal = originFields[node.FullName]; + tablaOriginal.OriginalTable = (Table)originFields[node.FullName].Clone((Database)tablaOriginal.Parent); + (new CompareColumns()).GenerateDifferences
(tablaOriginal.Columns, node.Columns); + (new CompareConstraints()).GenerateDifferences
(tablaOriginal.Constraints, node.Constraints); + (new CompareIndexes()).GenerateDifferences
(tablaOriginal.Indexes, node.Indexes); + (new CompareTablesOptions()).GenerateDifferences
(tablaOriginal.Options, node.Options); + (new CompareTriggers()).GenerateDifferences
(tablaOriginal.Triggers, node.Triggers); + (new CompareCLRTriggers()).GenerateDifferences
(tablaOriginal.CLRTriggers, node.CLRTriggers); + (new CompareFullTextIndex()).GenerateDifferences
(tablaOriginal.FullTextIndex, node.FullTextIndex); + if (!Table.CompareFileGroup(tablaOriginal, node)) + { + tablaOriginal.FileGroup = node.FileGroup; + /*Esto solo aplica a las tablas heap, el resto hace el campo en el filegroup del indice clustered*/ + if (!tablaOriginal.HasClusteredIndex) + tablaOriginal.Status = ObjectStatus.Rebuild; + } + if (!Table.CompareFileGroupText(tablaOriginal, node)) + { + tablaOriginal.FileGroupText = node.FileGroupText; + tablaOriginal.Status = ObjectStatus.Rebuild; + } + if (node.HasChangeTracking != tablaOriginal.HasChangeTracking) + { + tablaOriginal.HasChangeTracking = node.HasChangeTracking; + tablaOriginal.HasChangeTrackingTrackColumn = node.HasChangeTrackingTrackColumn; + tablaOriginal.Status += (int)ObjectStatus.Disabled; + } + } + } + + /// + /// Compara las colecciones de tablas de dos bases diferentes y marca el estado de los objetos + /// dependiendo si existen o si deben borrarse. + /// + /// + /// Tablas originales, donde se guardaran los estados de las tablas. + /// + /// Tablas comparativas, que se usa para comparar con la base original. + /// + /*public static void GenerateDifferences(SchemaList originTables, SchemaList destinationTables) + { + MarkDrop(originTables, destinationTables); + + foreach (Table node in destinationTables) + { + if (!originTables.Exists(node.FullName)) + { + node.Status = ObjectStatusType.CreateStatus; + node.Parent = originTables.Parent; + originTables.Add(node); + } + else + { + if (node.Status != ObjectStatusType.DropStatus) + { + Table tablaOriginal = originTables[node.FullName]; + tablaOriginal.OriginalTable = (Table)originTables[node.FullName].Clone((Database)tablaOriginal.Parent); + CompareColumns.GenerateDifferences
(tablaOriginal.Columns, node.Columns); + CompareConstraints.GenerateDifferences
(tablaOriginal.Constraints, node.Constraints); + CompareIndexes.GenerateDifferences(tablaOriginal.Indexes, node.Indexes); + CompareTablesOptions.GenerateDifferences(tablaOriginal.Options, node.Options); + (new CompareTriggers()).GenerateDifferences
(tablaOriginal.Triggers, node.Triggers); + (new CompareCLRTriggers()).GenerateDifferences
(tablaOriginal.CLRTriggers, node.CLRTriggers); + if (!Table.CompareFileGroup(tablaOriginal, node)) + { + tablaOriginal.FileGroup = node.FileGroup; + //Esto solo aplica a las tablas heap, el resto hace el campo en el filegroup del indice clustered + if (!tablaOriginal.HasClusteredIndex) + tablaOriginal.Status = ObjectStatusType.RebuildStatus; + } + if (!Table.CompareFileGroupText(tablaOriginal, node)) + { + tablaOriginal.FileGroupText = node.FileGroupText; + tablaOriginal.Status = ObjectStatusType.RebuildStatus; + } + } + } + } + }*/ + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareTablesOptions.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareTablesOptions.cs new file mode 100644 index 0000000..705bb2f --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareTablesOptions.cs @@ -0,0 +1,26 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareTablesOptions : CompareBase + { + protected override void DoNew(SchemaList originFields, TableOption node) + { + TableOption newNode = (TableOption)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, TableOption node) + { + if (!TableOption.Compare(node, originFields[node.FullName])) + { + TableOption newNode = (TableOption)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareTriggers.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareTriggers.cs new file mode 100644 index 0000000..181e139 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareTriggers.cs @@ -0,0 +1,29 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareTriggers : CompareBase + { + protected override void DoNew(SchemaList originFields, Trigger node) + { + Trigger newNode = (Trigger)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, Trigger node) + { + if (!node.Compare(originFields[node.FullName])) + { + Trigger newNode = (Trigger)node.Clone(originFields.Parent); + if (!newNode.Text.Equals(originFields[node.FullName].Text)) + newNode.Status = ObjectStatus.Alter; + if (node.IsDisabled != originFields[node.FullName].IsDisabled) + newNode.Status = newNode.Status + (int)ObjectStatus.Disabled; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareUserDataTypes.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareUserDataTypes.cs new file mode 100644 index 0000000..0dfb84d --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareUserDataTypes.cs @@ -0,0 +1,52 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareUserDataTypes : CompareBase + { + protected override void DoNew(SchemaList originFields, UserDataType node) + { + UserDataType newNode = (UserDataType)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + Boolean HasAssembly = originFields.Exists(item => item.AssemblyFullName.Equals(node.AssemblyFullName) && item.IsAssembly); + if (HasAssembly) + newNode.Status += (int)ObjectStatus.DropOlder; + originFields.Add(newNode); + } + + protected override void DoUpdate(SchemaList originFields, UserDataType node) + { + if (!node.Compare(originFields[node.FullName])) + { + UserDataType newNode = (UserDataType)node.Clone(originFields.Parent); + newNode.Dependencies.AddRange(originFields[node.FullName].Dependencies); + + if (!UserDataType.CompareDefault(node, originFields[node.FullName])) + { + if (!String.IsNullOrEmpty(node.Default.Name)) + newNode.Default.Status = ObjectStatus.Create; + else + newNode.Default.Status = ObjectStatus.Drop; + newNode.Status = ObjectStatus.Alter; + } + else + { + if (!UserDataType.CompareRule(node, originFields[node.FullName])) + { + if (!String.IsNullOrEmpty(node.Rule.Name)) + newNode.Rule.Status = ObjectStatus.Create; + else + newNode.Rule.Status = ObjectStatus.Drop; + newNode.Status = ObjectStatus.Alter; + } + else + newNode.Status = ObjectStatus.Rebuild; + } + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareUsers.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareUsers.cs new file mode 100644 index 0000000..c45b186 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareUsers.cs @@ -0,0 +1,8 @@ +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareUsers : CompareBase + { + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareViews.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareViews.cs new file mode 100644 index 0000000..6130cec --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareViews.cs @@ -0,0 +1,53 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareViews : CompareBase + { + protected override void DoUpdate(SchemaList originFields, View node) + { + View original = originFields[node.FullName]; + if (!node.Compare(original)) + { + View newNode = (View)node.Clone(originFields.Parent); + newNode.DependenciesOut.AddRange(original.DependenciesOut); + newNode.DependenciesIn.AddRange(original.DependenciesIn); + + newNode.Status = ObjectStatus.Alter; + newNode.Indexes = original.Indexes; + newNode.Triggers = original.Triggers; + + if (newNode.IsSchemaBinding) + newNode.Status += (int)ObjectStatus.RebuildDependencies; + if (newNode.HasToRebuild) + newNode.Status += (int)ObjectStatus.Rebuild; + else + newNode.Status += (int)ObjectStatus.AlterBody; + + originFields[node.FullName] = newNode; + original = newNode; + } + (new CompareIndexes()).GenerateDifferences(original.Indexes, node.Indexes); + (new CompareTriggers()).GenerateDifferences(original.Triggers, node.Triggers); + } + + protected override void DoNew(SchemaList originFields, View node) + { + View newNode = (View)node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Create; + originFields.Add(newNode); + newNode.DependenciesIn.ForEach(dep => + { + ISchemaBase item = ((Database)((ISchemaBase)originFields.Parent)).Find(dep); + if (item != null) + { + if (item.IsCodeType) + ((ICode)item).DependenciesOut.Add(newNode.FullName); + } + } + ); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Compare/CompareXMLSchemas.cs b/OpenDBDiff.SqlServer.Schema/Compare/CompareXMLSchemas.cs new file mode 100644 index 0000000..e679367 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Compare/CompareXMLSchemas.cs @@ -0,0 +1,19 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Compare +{ + internal class CompareXMLSchemas : CompareBase + { + protected override void DoUpdate(SchemaList originFields, XMLSchema node) + { + if (!node.Compare(originFields[node.FullName])) + { + XMLSchema newNode = node.Clone(originFields.Parent); + newNode.Status = ObjectStatus.Alter; + originFields[node.FullName] = newNode; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/Generate.cs b/OpenDBDiff.SqlServer.Schema/Generates/Generate.cs new file mode 100644 index 0000000..c7caa4a --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/Generate.cs @@ -0,0 +1,191 @@ +using OpenDBDiff.Abstractions.Schema.Errors; +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.Abstractions.Schema.Misc; +using OpenDBDiff.SqlServer.Schema.Compare; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class Generate + { + private readonly List messages; + private ProgressEventArgs currentlyReading; + + public Generate() + { + messages = new List(); + OnReading += Generate_OnReading; + } + + public static int MaxValue + { + get { return Constants.READING_MAX; } + } + + public string ConnectionString { get; set; } + + private string Name + { + get + { + string name; + using (var conn = new SqlConnection(ConnectionString)) + { + name = conn.Database; + } + return name; + } + } + + public SqlOption Options { get; set; } + + private event ProgressEventHandler.ProgressHandler OnReading; + + public event ProgressEventHandler.ProgressHandler OnProgress; + + private void Generate_OnReading(ProgressEventArgs e) + { + if (OnProgress != null) OnProgress(e); + } + + public void RaiseOnReading(ProgressEventArgs e) + { + this.currentlyReading = e; + if (OnReading != null) OnReading(e); + } + + public void RaiseOnReadingOne(object name) + { + if (name != null && this.OnReading != null && this.currentlyReading != null) + { + var eOne = new ProgressEventArgs(this.currentlyReading.Message, this.currentlyReading.Progress); + eOne.Message = eOne.Message.Replace("...", String.Format(": [{0}]", name)); + this.OnReading(eOne); + } + } + + /// + /// Genera el schema de la base de datos seleccionada y devuelve un objeto Database. + /// + public Database Process() + { + string error = ""; + var databaseSchema = new Database(); + + //tables.OnTableProgress += new Progress.ProgressHandler(tables_OnTableProgress); + databaseSchema.Options = Options; + databaseSchema.Name = Name; + databaseSchema.Info = (new GenerateDatabase(ConnectionString, Options)).Get(databaseSchema); + /*Thread t1 = new Thread(delegate() + { + try + {*/ + (new GenerateRules(this)).Fill(databaseSchema, ConnectionString); + (new GenerateTables(this)).Fill(databaseSchema, ConnectionString, messages); + (new GenerateViews(this)).Fill(databaseSchema, ConnectionString, messages); + + if (Options.Ignore.FilterIndex) + { + (new GenerateIndex(this)).Fill(databaseSchema, ConnectionString); + (new GenerateFullTextIndex(this)).Fill(databaseSchema, ConnectionString); + } + (new GenerateUserDataTypes(this)).Fill(databaseSchema, ConnectionString, messages); + (new GenerateXMLSchemas(this)).Fill(databaseSchema, ConnectionString); + (new GenerateSchemas(this)).Fill(databaseSchema, ConnectionString); + /*} + catch (Exception ex) + { + error = ex.StackTrace; + } + }); + Thread t2 = new Thread(delegate() + { + try + {*/ + + //not supported in azure yet + if (databaseSchema.Info.Version != DatabaseInfo.SQLServerVersion.SQLServerAzure10) + { + (new GeneratePartitionFunctions(this)).Fill(databaseSchema, ConnectionString); + (new GeneratePartitionScheme(this)).Fill(databaseSchema, ConnectionString); + (new GenerateFileGroups(this)).Fill(databaseSchema, ConnectionString); + } + + (new GenerateDDLTriggers(this)).Fill(databaseSchema, ConnectionString); + (new GenerateSynonyms(this)).Fill(databaseSchema, ConnectionString); + + //not supported in azure yet + if (databaseSchema.Info.Version != DatabaseInfo.SQLServerVersion.SQLServerAzure10) + { + (new GenerateAssemblies(this)).Fill(databaseSchema, ConnectionString); + (new GenerateFullText(this)).Fill(databaseSchema, ConnectionString); + } + /*} + catch (Exception ex) + { + error = ex.StackTrace; + } + }); + Thread t3 = new Thread(delegate() + { + try + {*/ + (new GenerateStoredProcedures(this)).Fill(databaseSchema, ConnectionString); + (new GenerateFunctions(this)).Fill(databaseSchema, ConnectionString); + (new GenerateTriggers(this)).Fill(databaseSchema, ConnectionString, messages); + (new GenerateTextObjects(this)).Fill(databaseSchema, ConnectionString); + (new GenerateUsers(this)).Fill(databaseSchema, ConnectionString); + /*} + catch (Exception ex) + { + error = ex.StackTrace; + } + }); + t1.Start(); + t2.Start(); + t3.Start(); + t1.Join(); + t2.Join(); + t3.Join();*/ + if (String.IsNullOrEmpty(error)) + { + /*Las propiedades extendidas deben ir despues de haber capturado el resto de los objetos de la base*/ + (new GenerateExtendedProperties(this)).Fill(databaseSchema, ConnectionString, messages); + databaseSchema.BuildDependency(); + return databaseSchema; + } + else + throw new SchemaException(error); + } + + private void tables_OnTableProgress(object sender, ProgressEventArgs e) + { + ProgressEventHandler.RaiseOnChange(e); + } + + // TODO: Static because Compare method is static; static events are not my favorite + public static event ProgressEventHandler.ProgressHandler OnCompareProgress; + + internal static void RaiseOnCompareProgress(string formatString, params object[] formatParams) + { + OnCompareProgress?.Invoke(new ProgressEventArgs(String.Format(formatString, formatParams), -1)); + } + + /// + /// Generates the differences to migrate a schema from origin to destination + /// + /// The Origin schema is the schema before our generated actions are applied. + /// The Destination schema is the schema after our actions are applied. + /// + public static Database Compare(Database origin, Database destination) + { + Database merge = CompareDatabase.GenerateDifferences(origin, destination); + return merge; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateAssemblies.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateAssemblies.cs new file mode 100644 index 0000000..414fd1d --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateAssemblies.cs @@ -0,0 +1,103 @@ +using System; +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateAssemblies + { + private Generate root; + + public GenerateAssemblies(Generate root) + { + this.root = root; + } + + private static string GetSQLFiles() + { + return SQLQueries.SQLQueryFactory.Get("GetAssemblyFiles"); + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetAssemblies"); + } + + private static string ToHex(byte[] stream) + { + return ByteToHexEncoder.ByteArrayToHex(stream); + } + + private static void FillFiles(Database database, string connectionString) + { + if (database.Options.Ignore.FilterAssemblies) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLFiles(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + if (((int)reader["FileId"]) != 1) + { + Assembly assem = database.Assemblies[reader["Name"].ToString()]; + AssemblyFile file = new AssemblyFile(assem, reader["FileName"].ToString(), ToHex((byte[])reader["FileContent"])); + assem.Files.Add(file); + } + } + } + } + } + } + } + public void Fill(Database database, string connectionString) + { + int lastViewId = 0; + if (database.Options.Ignore.FilterAssemblies) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Assembly item = null; + while (reader.Read()) + { + if (lastViewId != (int)reader["assembly_id"]) + { + item = new Assembly(database) + { + Id = (int)reader["assembly_id"], + Name = reader["Name"].ToString(), + Owner = reader["Owner"].ToString(), + CLRName = reader["clr_name"].ToString(), + PermissionSet = reader["permission_set_desc"].ToString(), + Text = ToHex((byte[])reader["content"]), + Visible = (bool)reader["is_visible"] + }; + lastViewId = item.Id; + database.Assemblies.Add(item); + } + if (!String.IsNullOrEmpty(reader["Dependency"].ToString())) + item.DependenciesOut.Add(reader["Dependency"].ToString()); + if (!String.IsNullOrEmpty(reader["ObjectDependency"].ToString())) + item.DependenciesOut.Add(reader["ObjectDependency"].ToString()); + if (!String.IsNullOrEmpty(reader["UDTName"].ToString())) + item.DependenciesOut.Add(reader["UDTName"].ToString()); + } + } + } + FillFiles(database, connectionString); + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateConstraint.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateConstraint.cs new file mode 100644 index 0000000..71fb4db --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateConstraint.cs @@ -0,0 +1,327 @@ +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Generates.SQLCommands; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using System.Data.SqlClient; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateConstraint + { + private Generate root; + + public GenerateConstraint(Generate root) + { + this.root = root; + } + + #region Check Functions... + public void FillCheck(Database database, string connectionString) + { + int parentId = 0; + ISchemaBase table = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(ConstraintSQLCommand.GetCheck(database.Info.Version), conn)) + { + root.RaiseOnReading(new ProgressEventArgs("Reading constraint...", Constants.READING_CONSTRAINTS)); + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Constraint item = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + if (parentId != (int)reader["parent_object_id"]) + { + parentId = (int)reader["parent_object_id"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + table = database.Tables.Find(parentId); + else + table = database.TablesTypes.Find(parentId); + } + if (table != null) + { + item = new Constraint(table); + item.Id = (int)reader["id"]; + item.Name = reader["Name"].ToString(); + item.Type = Constraint.ConstraintType.Check; + item.Definition = reader["Definition"].ToString(); + item.WithNoCheck = (bool)reader["WithCheck"]; + item.IsDisabled = (bool)reader["is_disabled"]; + item.Owner = reader["Owner"].ToString(); + if (database.Options.Ignore.FilterNotForReplication) + item.NotForReplication = (bool)reader["is_not_for_replication"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + ((Table)table).Constraints.Add(item); + else + ((TableType)table).Constraints.Add(item); + } + } + } + } + } + } + + #endregion + + #region ForeignKey Functions... + + private static string GetSQLForeignKey() + { + return SQLQueries.SQLQueryFactory.Get("GetForeignKeys"); + } + + private static void FillForeignKey(Database database, string connectionString) + { + int lastid = 0; + int parentId = 0; + Table table = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLForeignKey(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Constraint con = null; + while (reader.Read()) + { + if (parentId != (int)reader["parent_object_id"]) + { + parentId = (int)reader["parent_object_id"]; + table = database.Tables.Find(parentId); + } + + if (table != null) + { + if (lastid != (int)reader["object_id"]) + { + con = new Constraint(table); + con.Id = (int)reader["object_id"]; + con.Name = reader["Name"].ToString(); + con.Type = Constraint.ConstraintType.ForeignKey; + con.WithNoCheck = (bool)reader["is_not_trusted"]; + con.RelationalTableFullName = "[" + reader["ReferenceOwner"].ToString() + "].[" + reader["TableRelationalName"].ToString() + "]"; + con.RelationalTableId = (int)reader["TableRelationalId"]; + con.Owner = reader["Owner"].ToString(); + con.IsDisabled = (bool)reader["is_disabled"]; + con.OnDeleteCascade = (byte)reader["delete_referential_action"]; + con.OnUpdateCascade = (byte)reader["update_referential_action"]; + if (database.Options.Ignore.FilterNotForReplication) + con.NotForReplication = (bool)reader["is_not_for_replication"]; + lastid = (int)reader["object_id"]; + table.Constraints.Add(con); + } + ConstraintColumn ccon = new ConstraintColumn(con); + ccon.Name = reader["ColumnName"].ToString(); + ccon.ColumnRelationalName = reader["ColumnRelationalName"].ToString(); + ccon.ColumnRelationalId = (int)reader["ColumnRelationalId"]; + ccon.Id = (int)reader["ColumnId"]; + ccon.KeyOrder = con.Columns.Count; + ccon.ColumnRelationalDataTypeId = (int)reader["user_type_id"]; + //table.DependenciesCount++; + con.Columns.Add(ccon); + } + } + } + } + } + } + #endregion + + #region UniqueKey Functions... + private static void FillUniqueKey(Database database, string connectionString) + { + int lastId = 0; + int parentId = 0; + bool change = false; + ISchemaBase table = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(ConstraintSQLCommand.GetUniqueKey(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Constraint con = null; + while (reader.Read()) + { + if (parentId != (int)reader["ID"]) + { + parentId = (int)reader["ID"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + table = database.Tables.Find(parentId); + else + table = database.TablesTypes.Find(parentId); + change = true; + } + else + change = false; + + if (table != null) + { + if ((lastId != (int)reader["Index_id"]) || (change)) + { + con = new Constraint(table, database.Options.Ignore.FilterIndex); + con.Name = reader["Name"].ToString(); + con.Owner = (string)reader["Owner"]; + con.Id = (int)reader["Index_id"]; + con.Type = Constraint.ConstraintType.Unique; + + if (database.Options.Ignore.FilterIndex) + { + con.Index.Id = (int)reader["Index_id"]; + if (database.Options.Ignore.FilterIndexRowLock) + { + con.Index.AllowPageLocks = (bool)reader["allow_page_locks"]; + con.Index.AllowRowLocks = (bool)reader["allow_row_locks"]; + } + + if (database.Options.Ignore.FilterIndexFillFactor) + { + con.Index.FillFactor = (byte)reader["fill_factor"]; + con.Index.IsPadded = (bool)reader["is_padded"]; + } + con.Index.IgnoreDupKey = (bool)reader["ignore_dup_key"]; + con.Index.IsAutoStatistics = (bool)reader["ignore_dup_key"]; + con.Index.IsDisabled = (bool)reader["is_disabled"]; + con.Index.IsPrimaryKey = false; + con.Index.IsUniqueKey = true; + con.Index.Type = (Index.IndexTypeEnum)(byte)reader["type"]; + con.Index.Name = con.Name; + if (database.Options.Ignore.FilterTableFileGroup) + con.Index.FileGroup = reader["FileGroup"].ToString(); + } + + lastId = (int)reader["Index_id"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + ((Table)table).Constraints.Add(con); + else + ((TableType)table).Constraints.Add(con); + } + ConstraintColumn ccon = new ConstraintColumn(con); + ccon.Name = reader["ColumnName"].ToString(); + ccon.IsIncluded = (bool)reader["is_included_column"]; + ccon.Order = (bool)reader["is_descending_key"]; + ccon.Id = (int)reader["column_id"]; + ccon.DataTypeId = (int)reader["user_type_id"]; + con.Columns.Add(ccon); + } + } + } + } + } + } + #endregion + + #region PrimaryKey Functions... + private static void FillPrimaryKey(Database database, string connectionString) + { + int lastId = 0; + int parentId = 0; + bool change = false; + ISchemaBase table = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(ConstraintSQLCommand.GetPrimaryKey(database.Info.Version, null), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Constraint con = null; + while (reader.Read()) + { + if (parentId != (int)reader["ID"]) + { + parentId = (int)reader["ID"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + table = database.Tables.Find(parentId); + else + table = database.TablesTypes.Find(parentId); + change = true; + } + else + change = false; + + if (table != null) + { + if ((lastId != (int)reader["Index_id"]) || (change)) + { + con = new Constraint(table, database.Options.Ignore.FilterIndex); + con.Id = (int)reader["Index_id"]; + con.Name = (string)reader["Name"]; + con.Owner = (string)reader["Owner"]; + con.Type = Constraint.ConstraintType.PrimaryKey; + + if (database.Options.Ignore.FilterIndex) + { + con.Index.Id = (int)reader["Index_id"]; + + if (database.Options.Ignore.FilterIndexRowLock) + { + con.Index.AllowPageLocks = (bool)reader["allow_page_locks"]; + con.Index.AllowRowLocks = (bool)reader["allow_row_locks"]; + } + + if (database.Options.Ignore.FilterIndexFillFactor) + { + con.Index.FillFactor = (byte)reader["fill_factor"]; + con.Index.IsPadded = (bool)reader["is_padded"]; + } + + con.Index.IgnoreDupKey = (bool)reader["ignore_dup_key"]; + con.Index.IsAutoStatistics = (bool)reader["ignore_dup_key"]; + con.Index.IsDisabled = (bool)reader["is_disabled"]; + con.Index.IsPrimaryKey = true; + con.Index.IsUniqueKey = false; + con.Index.Type = (Index.IndexTypeEnum)(byte)reader["type"]; + con.Index.Name = con.Name; + if (database.Options.Ignore.FilterTableFileGroup) + con.Index.FileGroup = reader["FileGroup"].ToString(); + } + + lastId = (int)reader["Index_id"]; + if (reader["ObjectType"].ToString().Trim().Equals("U")) + ((Table)table).Constraints.Add(con); + else + ((TableType)table).Constraints.Add(con); + } + ConstraintColumn ccon = new ConstraintColumn(con); + ccon.Name = (string)reader["ColumnName"]; + ccon.IsIncluded = (bool)reader["is_included_column"]; + ccon.Order = (bool)reader["is_descending_key"]; + ccon.KeyOrder = (byte)reader["key_ordinal"]; + ccon.Id = (int)reader["column_id"]; + ccon.DataTypeId = (int)reader["user_type_id"]; + con.Columns.Add(ccon); + } + } + } + } + } + } + #endregion + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterConstraintPK) + FillPrimaryKey(database, connectionString); + if (database.Options.Ignore.FilterConstraintFK) + FillForeignKey(database, connectionString); + if (database.Options.Ignore.FilterConstraintUK) + FillUniqueKey(database, connectionString); + if (database.Options.Ignore.FilterConstraintCheck) + FillCheck(database, connectionString); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateDDLTriggers.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateDDLTriggers.cs new file mode 100644 index 0000000..31eb50b --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateDDLTriggers.cs @@ -0,0 +1,50 @@ +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateDDLTriggers + { + private Generate root; + + public GenerateDDLTriggers(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetDDLTriggers"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterDDLTriggers) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + conn.Open(); + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Trigger trigger = new Trigger(database); + trigger.Text = reader["Text"].ToString(); + trigger.Name = reader["Name"].ToString(); + trigger.InsteadOf = (bool)reader["is_instead_of_trigger"]; + trigger.IsDisabled = (bool)reader["is_disabled"]; + trigger.IsDDLTrigger = true; + trigger.NotForReplication = (bool)reader["is_not_for_replication"]; + trigger.Owner = ""; + database.DDLTriggers.Add(trigger); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateDatabase.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateDatabase.cs new file mode 100644 index 0000000..62d4736 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateDatabase.cs @@ -0,0 +1,96 @@ +using OpenDBDiff.Abstractions.Schema.Misc; +using OpenDBDiff.SqlServer.Schema.Generates.SQLCommands; +using OpenDBDiff.SqlServer.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Data.SqlClient; +using System.Globalization; +#if DEBUG +#endif + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateDatabase + { + private string connectioString; + private SqlOption objectFilter; + + public bool UseDefaultVersionOnVersionParseError { get; private set; } + + /// + /// Constructor de la clase. + /// + /// Connection string de la base + public GenerateDatabase(string connectioString, SqlOption filter) + { + this.connectioString = connectioString; + this.objectFilter = filter; + } + + public DatabaseInfo Get(Database database) + { + DatabaseInfo item = new DatabaseInfo(); + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(DatabaseSQLCommand.GetVersion(database), conn)) + { + conn.Open(); + + item.Server = conn.DataSource; + item.Database = conn.Database; + + using (SqlDataReader reader = command.ExecuteReader()) + { + if (reader.Read()) + { + string versionValue = reader["Version"] as string; + try + { + // used to use the decimal as well when Azure was 10.25 + var version = new Version(versionValue); + item.VersionNumber = float.Parse(String.Format("{0}.{1}", version.Major, version.Minor), CultureInfo.InvariantCulture); + + if (reader.FieldCount > 1 && !reader.IsDBNull(1)) + { + int edition; + if (int.TryParse(reader[1].ToString(), out edition) + && Enum.IsDefined(typeof(DatabaseInfo.SQLServerEdition), edition)) + { + item.SetEdition((DatabaseInfo.SQLServerEdition)edition); + } + } + + } + catch (Exception notAGoodIdeaToCatchAllErrors) + { + var exception = new SchemaException( + String.Format("Error parsing ProductVersion. ({0})", versionValue ?? "[null]") + , notAGoodIdeaToCatchAllErrors); + + if (!UseDefaultVersionOnVersionParseError) + { + throw exception; + } + } + } + } + } + + using (SqlCommand command = new SqlCommand(DatabaseSQLCommand.Get(item.Version, item.Edition, database), conn)) + { + using (SqlDataReader reader = command.ExecuteReader()) + { + if (reader.Read()) + { + item.Collation = reader["Collation"].ToString(); + item.HasFullTextEnabled = ((int)reader["IsFulltextEnabled"]) == 1; + } + } + } + + } + + return item; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateDefaults.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateDefaults.cs new file mode 100644 index 0000000..1ad5a34 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateDefaults.cs @@ -0,0 +1,46 @@ +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateDefaults + { + private Generate root; + + public GenerateDefaults(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetDefaults"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterRules) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Default item = new Default(database); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["Owner"].ToString(); + item.Value = reader["Definition"].ToString(); + database.Defaults.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateExtendedProperties.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateExtendedProperties.cs new file mode 100644 index 0000000..e1b7270 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateExtendedProperties.cs @@ -0,0 +1,118 @@ +using OpenDBDiff.Abstractions.Schema.Errors; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateExtendedProperties + { + private Generate root; + + public GenerateExtendedProperties(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetExtendedProperties"); + } + + private static string GetTypeDescription(string type) + { + if (type.Equals("PC")) return "PROCEDURE"; + if (type.Equals("P")) return "PROCEDURE"; + if (type.Equals("V")) return "VIEW"; + if (type.Equals("U")) return "TABLE"; + if (type.Equals("TR")) return "TRIGGER"; + if (type.Equals("TA")) return "TRIGGER"; + if (type.Equals("FS")) return "FUNCTION"; + if (type.Equals("FN")) return "FUNCTION"; + if (type.Equals("IF")) return "FUNCTION"; + if (type.Equals("TF")) return "FUNCTION"; + return ""; + } + + public void Fill(Database database, string connectionString, List messages) + { + ISQLServerSchemaBase parent; + try + { + if (database.Options.Ignore.FilterExtendedProperties) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + ExtendedProperty item = new ExtendedProperty(null); + if (((byte)reader["Class"]) == 5) + { + item.Level0type = "ASSEMBLY"; + item.Level0name = reader["AssemblyName"].ToString(); + } + if (((byte)reader["Class"]) == 1) + { + string ObjectType = GetTypeDescription(reader["type"].ToString().Trim()); + item.Level0type = "SCHEMA"; + item.Level0name = reader["Owner"].ToString(); + if (!ObjectType.Equals("TRIGGER")) + { + item.Level1name = reader["ObjectName"].ToString(); + item.Level1type = ObjectType; + } + else + { + item.Level1type = "TABLE"; + item.Level1name = reader["ParentName"].ToString(); + item.Level2name = reader["ObjectName"].ToString(); + item.Level2type = ObjectType; + } + } + if (((byte)reader["Class"]) == 6) + { + item.Level0type = "SCHEMA"; + item.Level0name = reader["OwnerType"].ToString(); + item.Level1name = reader["TypeName"].ToString(); + item.Level1type = "TYPE"; + } + if (((byte)reader["Class"]) == 7) + { + item.Level0type = "SCHEMA"; + item.Level0name = reader["Owner"].ToString(); + item.Level1type = "TABLE"; + item.Level1name = reader["ObjectName"].ToString(); + item.Level2type = reader["class_desc"].ToString(); + item.Level2name = reader["IndexName"].ToString(); + } + item.Value = reader["Value"].ToString(); + item.Name = reader["Name"].ToString(); + parent = ((ISQLServerSchemaBase)database.Find(item.FullName)); + if (parent != null) + { + item.Parent = (ISchemaBase)parent; + parent.ExtendedProperties.Add(item); + } + else + messages.Add(new MessageLog(item.FullName + " not found in extended properties.", "", MessageLog.LogType.Error)); + } + } + } + } + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateFileGroups.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateFileGroups.cs new file mode 100644 index 0000000..26b1700 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateFileGroups.cs @@ -0,0 +1,92 @@ +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateFileGroups + { + private Generate root; + + public GenerateFileGroups(Generate root) + { + this.root = root; + } + + private static string GetSQLFile(FileGroup filegroup) + { + string query = SQLQueries.SQLQueryFactory.Get("GetDatabaseFile"); + + return query.Replace("{ID}", filegroup.Id.ToString()); + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetFileGroups"); + } + + private static void FillFiles(FileGroup filegroup, string connectionString) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLFile(filegroup), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + FileGroupFile item = new FileGroupFile(filegroup); + item.Id = (int)reader["file_id"]; + item.Name = reader["name"].ToString(); + item.Owner = ""; + item.Growth = (int)reader["growth"]; + item.IsPercentGrowth = (bool)reader["is_percent_growth"]; + item.IsSparse = (bool)reader["is_sparse"]; + item.MaxSize = (int)reader["max_size"]; + item.PhysicalName = reader["physical_name"].ToString(); + item.Size = (int)reader["size"]; + item.Type = (byte)reader["type"]; + filegroup.Files.Add(item); + } + } + } + } + } + + public void Fill(Database database, string connectionString) + { + try + { + if (database.Options.Ignore.FilterTableFileGroup) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + FileGroup item = new FileGroup(database); + item.Id = (int)reader["ID"]; + item.Name = reader["name"].ToString(); + item.Owner = ""; + item.IsDefaultFileGroup = (bool)reader["is_default"]; + item.IsReadOnly = (bool)reader["is_read_only"]; + item.IsFileStream = reader["type"].Equals("FD"); + FillFiles(item, connectionString); + database.FileGroups.Add(item); + } + } + } + } + } + } + catch + { + throw; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateFullText.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateFullText.cs new file mode 100644 index 0000000..34e2362 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateFullText.cs @@ -0,0 +1,51 @@ +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateFullText + { + private Generate root; + + public GenerateFullText(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetFullTextCatalogs"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterFullText) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + FullText item = new FullText(database); + item.Id = (int)reader["fulltext_catalog_id"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["Owner"].ToString(); + item.IsAccentSensity = (bool)reader["is_accent_sensitivity_on"]; + item.IsDefault = (bool)reader["is_default"]; + if (!reader.IsDBNull(reader.GetOrdinal("path"))) + item.Path = reader["path"].ToString().Substring(0, reader["path"].ToString().Length - item.Name.Length); + if (!reader.IsDBNull(reader.GetOrdinal("FileGroupName"))) + item.FileGroupName = reader["FileGroupName"].ToString(); + database.FullText.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateFullTextIndex.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateFullTextIndex.cs new file mode 100644 index 0000000..44f94c5 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateFullTextIndex.cs @@ -0,0 +1,70 @@ +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.SqlServer.Schema.Generates.SQLCommands; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using System.Data.SqlClient; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateFullTextIndex + { + private Generate root; + + public GenerateFullTextIndex(Generate root) + { + this.root = root; + } + + public void Fill(Database database, string connectionString) + { + //not supported in azure yet + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) return; + + int parentId = 0; + bool change = false; + Table parent = null; + root.RaiseOnReading(new ProgressEventArgs("Reading FullText Index...", Constants.READING_INDEXES)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(FullTextIndexSQLCommand.Get(database.Info.Version), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + FullTextIndex item = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + if (parentId != (int)reader["object_id"]) + { + parentId = (int)reader["object_id"]; + parent = database.Tables.Find(parentId); + change = true; + } + else + change = false; + if (change) + { + item = new FullTextIndex(parent); + item.Name = reader["Name"].ToString(); + item.Owner = parent.Owner; + item.FullText = reader["FullTextCatalogName"].ToString(); + item.Index = reader["IndexName"].ToString(); + item.IsDisabled = !(bool)reader["is_enabled"]; + item.ChangeTrackingState = reader["ChangeTracking"].ToString(); + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + item.FileGroup = reader["FileGroupName"].ToString(); + ((Table)parent).FullTextIndex.Add(item); + } + FullTextIndexColumn ccon = new FullTextIndexColumn(); + ccon.ColumnName = reader["ColumnName"].ToString(); + ccon.Language = reader["LanguageName"].ToString(); + item.Columns.Add(ccon); + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateFunctions.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateFunctions.cs new file mode 100644 index 0000000..4f1594a --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateFunctions.cs @@ -0,0 +1,138 @@ +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.SqlServer.Schema.Generates.SQLCommands; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using System; +using System.Data.SqlClient; +using System.Linq; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateFunctions + { + private Generate root; + + public GenerateFunctions(Generate root) + { + this.root = root; + } + + private static string GetSQLParameters() + { + return SQLQueries.SQLQueryFactory.Get("GetParameters"); + } + + private static void FillParameters(Database database, string connectionString) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLParameters(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + var objectName = reader["ObjectName"].ToString(); + + if (database.CLRFunctions.Contains(objectName)) + { + Parameter param = new Parameter(); + param.Name = reader["Name"].ToString(); + param.Type = reader["TypeName"].ToString(); + param.Size = (short)reader["max_length"]; + param.Scale = (byte)reader["scale"]; + param.Precision = (byte)reader["precision"]; + param.Output = (bool)reader["is_output"]; + if (param.Type.Equals("nchar") || param.Type.Equals("nvarchar")) + { + if (param.Size != -1) + param.Size = param.Size / 2; + } + database.CLRFunctions[objectName].Parameters.Add(param); + } + } + } + } + } + } + + public void Fill(Database database, string connectionString) + { + int lastViewId = 0; + if ((database.Options.Ignore.FilterFunction) || (database.Options.Ignore.FilterCLRFunction)) + { + root.RaiseOnReading(new ProgressEventArgs("Reading functions...", Constants.READING_FUNCTIONS)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(FunctionSQLCommand.Get(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Function itemF = null; + CLRFunction itemC = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["name"]); + if ((!reader["type"].ToString().Trim().Equals("FS")) && (database.Options.Ignore.FilterFunction)) + { + if (lastViewId != (int)reader["object_id"]) + { + itemF = new Function(database); + itemF.Id = (int)reader["object_id"]; + itemF.Name = reader["name"].ToString(); + itemF.Owner = reader["owner"].ToString(); + itemF.IsSchemaBinding = reader["IsSchemaBound"].ToString().Equals("1"); + database.Functions.Add(itemF); + lastViewId = itemF.Id; + } + if (itemF.IsSchemaBinding) + { + if (!reader.IsDBNull(reader.GetOrdinal("referenced_major_id"))) + database.Dependencies.Add(database, (int)reader["referenced_major_id"], itemF); + if (!String.IsNullOrEmpty(reader["TableName"].ToString())) + itemF.DependenciesIn.Add(reader["TableName"].ToString()); + if (!String.IsNullOrEmpty(reader["DependOut"].ToString())) + itemF.DependenciesOut.Add(reader["DependOut"].ToString()); + } + } + if ((reader["type"].ToString().Trim().Equals("FS")) && (database.Options.Ignore.FilterCLRFunction)) + { + itemC = new CLRFunction(database); + if (lastViewId != (int)reader["object_id"]) + { + itemC.Id = (int)reader["object_id"]; + itemC.Name = reader["name"].ToString(); + itemC.Owner = reader["owner"].ToString(); + itemC.IsAssembly = true; + itemC.AssemblyId = (int)reader["assembly_id"]; + itemC.AssemblyName = reader["assembly_name"].ToString(); + itemC.AssemblyClass = reader["assembly_class"].ToString(); + itemC.AssemblyExecuteAs = reader["ExecuteAs"].ToString(); + itemC.AssemblyMethod = reader["assembly_method"].ToString(); + itemC.ReturnType.Type = reader["ReturnType"].ToString(); + itemC.ReturnType.Size = (short)reader["max_length"]; + itemC.ReturnType.Scale = (byte)reader["Scale"]; + itemC.ReturnType.Precision = (byte)reader["precision"]; + if (itemC.ReturnType.Type.Equals("nchar") || itemC.ReturnType.Type.Equals("nvarchar")) + { + if (itemC.ReturnType.Size != -1) + itemC.ReturnType.Size = itemC.ReturnType.Size / 2; + } + database.CLRFunctions.Add(itemC); + lastViewId = itemC.Id; + } + } + } + } + } + } + } + if (database.CLRFunctions.Any()) + FillParameters(database, connectionString); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateIndex.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateIndex.cs new file mode 100644 index 0000000..f5ff3f8 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateIndex.cs @@ -0,0 +1,105 @@ +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Generates.SQLCommands; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using System.Data.SqlClient; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateIndex + { + private Generate root; + + public GenerateIndex(Generate root) + { + this.root = root; + } + + public void Fill(Database database, string connectionString) + { + int indexid = 0; + int parentId = 0; + bool change = false; + string type; + ISchemaBase parent = null; + root.RaiseOnReading(new ProgressEventArgs("Reading Index...", Constants.READING_INDEXES)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(IndexSQLCommand.Get(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + Index item = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + type = reader["ObjectType"].ToString().Trim(); + if (parentId != (int)reader["object_id"]) + { + parentId = (int)reader["object_id"]; + if (type.Equals("V")) + parent = database.Views.Find(parentId); + else + parent = database.Tables.Find(parentId); + change = true; + } + else + change = false; + + if (parent != null) + { + if (indexid != (int)reader["index_id"] || change) + { + item = new Index(parent); + item.Name = reader["Name"].ToString(); + item.Owner = parent.Owner; + item.Type = (Index.IndexTypeEnum)(byte)reader["type"]; + item.Id = (int)reader["index_id"]; + item.IgnoreDupKey = (bool)reader["ignore_dup_key"]; + item.IsAutoStatistics = (bool)reader["NoAutomaticRecomputation"]; + item.IsDisabled = (bool)reader["is_disabled"]; + item.IsPrimaryKey = (bool)reader["is_primary_key"]; + item.IsUniqueKey = (bool)reader["is_unique"]; + if (database.Options.Ignore.FilterIndexRowLock) + { + item.AllowPageLocks = (bool)reader["allow_page_locks"]; + item.AllowRowLocks = (bool)reader["allow_row_locks"]; + } + if (database.Options.Ignore.FilterIndexFillFactor) + { + item.FillFactor = (byte)reader["fill_factor"]; + item.IsPadded = (bool)reader["is_padded"]; + } + if ((database.Options.Ignore.FilterTableFileGroup) && (item.Type != Index.IndexTypeEnum.XML)) + item.FileGroup = reader["FileGroup"].ToString(); + + if ((database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) && (database.Options.Ignore.FilterIndexFilter)) + { + item.FilterDefintion = reader["FilterDefinition"].ToString(); + } + indexid = (int)reader["index_id"]; + if (type.Equals("V")) + ((View)parent).Indexes.Add(item); + else + ((Table)parent).Indexes.Add(item); + } + IndexColumn ccon = new IndexColumn(item.Parent); + ccon.Name = reader["ColumnName"].ToString(); + ccon.IsIncluded = (bool)reader["is_included_column"]; + ccon.Order = (bool)reader["is_descending_key"]; + ccon.Id = (int)reader["column_id"]; + ccon.KeyOrder = (byte)reader["key_ordinal"]; + ccon.DataTypeId = (int)reader["user_type_id"]; + if ((!ccon.IsIncluded) || (ccon.IsIncluded && database.Options.Ignore.FilterIndexIncludeColumns)) + item.Columns.Add(ccon); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GeneratePartitionFunctions.cs b/OpenDBDiff.SqlServer.Schema/Generates/GeneratePartitionFunctions.cs new file mode 100644 index 0000000..8029442 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GeneratePartitionFunctions.cs @@ -0,0 +1,84 @@ +using System; +using System.Data.SqlClient; +using System.Text; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GeneratePartitionFunctions + { + private Generate root; + + public GeneratePartitionFunctions(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetPartitionFunctions"); + } + + private static string ToHex(byte[] stream) + { + StringBuilder sHex = new StringBuilder(2 * stream.Length); + for (int i = 0; i < stream.Length; i++) + sHex.AppendFormat("{0:X2} ", stream[i]); + return "0x" + sHex.ToString().Replace(" ", String.Empty); + } + + public void Fill(Database database, string connectioString) + { + int lastObjectId = 0; + PartitionFunction item = null; + if (database.Options.Ignore.FilterPartitionFunction) + { + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + if (lastObjectId != (int)reader["function_id"]) + { + lastObjectId = (int)reader["function_id"]; + item = new PartitionFunction(database); + item.Id = (int)reader["function_id"]; + item.Name = reader["name"].ToString(); + item.IsBoundaryRight = (bool)reader["IsRight"]; + item.Precision = (byte)reader["precision"]; + item.Scale = (byte)reader["scale"]; + item.Size = (short)reader["max_length"]; + item.Type = reader["TypeName"].ToString(); + database.PartitionFunctions.Add(item); + } + + switch (item.Type) { + case "binary": + case "varbinary": + item.Values.Add(ToHex((byte[])reader["value"])); + break; + case "date": + item.Values.Add(String.Format("'{0:yyyy/MM/dd}'", (DateTime)reader["value"])); + break; + case "smalldatetime": + case "datetime": + item.Values.Add(String.Format("'{0:yyyy/MM/dd HH:mm:ss.fff}'", (DateTime)reader["value"])); + break; + default: + item.Values.Add(reader["value"].ToString()); + break; + } + + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GeneratePartitionScheme.cs b/OpenDBDiff.SqlServer.Schema/Generates/GeneratePartitionScheme.cs new file mode 100644 index 0000000..4c9452f --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GeneratePartitionScheme.cs @@ -0,0 +1,53 @@ +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GeneratePartitionScheme + { + private Generate root; + + public GeneratePartitionScheme(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetPartitionSchemes"); + } + + public void Fill(Database database, string connectioString) + { + int lastObjectId = 0; + PartitionScheme item = null; + if (database.Options.Ignore.FilterPartitionScheme) + { + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + if (lastObjectId != (int)reader["ID"]) + { + lastObjectId = (int)reader["ID"]; + item = new PartitionScheme(database); + item.Id = (int)reader["ID"]; + item.Name = reader["name"].ToString(); + item.PartitionFunction = reader["FunctionName"].ToString(); + database.PartitionSchemes.Add(item); + } + item.FileGroups.Add(reader["FileGroupName"].ToString()); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateRules.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateRules.cs new file mode 100644 index 0000000..09bdd77 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateRules.cs @@ -0,0 +1,46 @@ +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateRules + { + private Generate root; + + public GenerateRules(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetRules"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterRules) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Rule item = new Rule(database); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["Owner"].ToString(); + item.Text = reader["Definition"].ToString(); + database.Rules.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateSchemas.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateSchemas.cs new file mode 100644 index 0000000..42be070 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateSchemas.cs @@ -0,0 +1,46 @@ +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateSchemas + { + private Generate root; + + public GenerateSchemas(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetSchemas"); + } + + public void Fill(Database database, string connectioString) + { + if (database.Options.Ignore.FilterSchema) + { + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Model.Schema item = new Model.Schema(database); + item.Id = (int)reader["schema_id"]; + item.Name = reader["name"].ToString(); + item.Owner = reader["owner"].ToString(); + database.Schemas.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateStoredProcedures.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateStoredProcedures.cs new file mode 100644 index 0000000..01d36fc --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateStoredProcedures.cs @@ -0,0 +1,145 @@ +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using System.Data.SqlClient; +using System.Linq; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateStoredProcedures + { + private static int NameIndex = -1; + private static int object_idIndex = -1; + private static int ownerIndex = -1; + private static int typeIndex = -1; + + private Generate root; + + public GenerateStoredProcedures(Generate root) + { + this.root = root; + } + + private static void InitIndex(SqlDataReader reader) + { + if (NameIndex == -1) + { + object_idIndex = reader.GetOrdinal("object_id"); + NameIndex = reader.GetOrdinal("Name"); + ownerIndex = reader.GetOrdinal("owner"); + typeIndex = reader.GetOrdinal("type"); + } + } + + private static string GetSQLParameters() + { + return SQLQueries.SQLQueryFactory.Get("GetParameters"); + } + + private static string GetSQL(DatabaseInfo.SQLServerVersion version) + { + if (version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) + { + return SQLQueries.SQLQueryFactory.Get("GetProcedures", DatabaseInfo.SQLServerVersion.SQLServerAzure10); + } + else + { + return SQLQueries.SQLQueryFactory.Get("GetProcedures"); + } + } + + private static void FillParameters(Database database, string connectionString) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLParameters(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + var objectName = reader["ObjectName"].ToString(); + + if (database.CLRProcedures.Contains(objectName)) + { + Parameter param = new Parameter(); + param.Name = reader["Name"].ToString(); + param.Type = reader["TypeName"].ToString(); + param.Size = (short)reader["max_length"]; + param.Scale = (byte)reader["scale"]; + param.Precision = (byte)reader["precision"]; + param.Output = (bool)reader["is_output"]; + if (param.Type.Equals("nchar") || param.Type.Equals("nvarchar")) + { + if (param.Size != -1) + param.Size = param.Size / 2; + } + database.CLRProcedures[objectName].Parameters.Add(param); + } + } + } + } + } + } + + public void Fill(Database database, string connectionString) + { + if ((database.Options.Ignore.FilterStoredProcedure) || (database.Options.Ignore.FilterCLRStoredProcedure)) + { + root.RaiseOnReading(new ProgressEventArgs("Reading stored procedures...", Constants.READING_PROCEDURES)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(database.Info.Version), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + InitIndex(reader); + root.RaiseOnReadingOne(reader[NameIndex]); + + var objectType = reader[typeIndex].ToString().Trim(); + switch (objectType) + { + case "P": + if (database.Options.Ignore.FilterStoredProcedure) + { + StoredProcedure item = new StoredProcedure(database); + item.Id = (int)reader[object_idIndex]; + item.Name = (string)reader[NameIndex]; + item.Owner = (string)reader[ownerIndex]; + database.Procedures.Add(item); + } + break; + + case "PC": + if (database.Options.Ignore.FilterCLRStoredProcedure) + { + CLRStoredProcedure item = new CLRStoredProcedure(database); + item.Id = (int)reader[object_idIndex]; + item.Name = reader[NameIndex].ToString(); + item.Owner = reader[ownerIndex].ToString(); + item.IsAssembly = true; + item.AssemblyId = (int)reader["assembly_id"]; + item.AssemblyName = reader["assembly_name"].ToString(); + item.AssemblyClass = reader["assembly_class"].ToString(); + item.AssemblyExecuteAs = reader["ExecuteAs"].ToString(); + item.AssemblyMethod = reader["assembly_method"].ToString(); + database.CLRProcedures.Add(item); + } + break; + } + } + } + } + } + if (database.CLRProcedures.Any()) + FillParameters(database, connectionString); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateSynonyms.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateSynonyms.cs new file mode 100644 index 0000000..072712e --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateSynonyms.cs @@ -0,0 +1,47 @@ +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateSynonyms + { + private Generate root; + + public GenerateSynonyms(Generate root) + { + this.root = root; + } + + private static string GetSQL() + { + return SQLQueries.SQLQueryFactory.Get("GetSynonyms"); + } + + public void Fill(Database database, string connectionString) + { + if (database.Options.Ignore.FilterSynonyms) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + Synonym item = new Synonym(database); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["Owner"].ToString(); + item.Value = reader["base_object_name"].ToString(); + database.Synonyms.Add(item); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateTables.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateTables.cs new file mode 100644 index 0000000..2ddbddd --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateTables.cs @@ -0,0 +1,313 @@ +using OpenDBDiff.Abstractions.Schema.Errors; +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Generates.SQLCommands; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Globalization; +using System.Linq; +using Constraint = OpenDBDiff.SqlServer.Schema.Model.Constraint; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateTables + { + private int colIDIndex = -1; + private int colNameIndex = -1; + private int colFormulaIndex = -1; + private int colIsPersistedIndex = -1; + private int colIsComputedIndex = -1; + private int colNullableIndex = -1; + private int colXmlSchemaIndex = -1; + private int colIs_xml_documentIndex = -1; + private int colPrecisionIndex = -1; + private int colScaleIndex = -1; + private int colDataUserTypeIdIndex = -1; + private int colIsUserDefinedTypeIndex = -1; + private int colSizeIndex = -1; + private int colHasIndexIndex = -1; + private int colHasComputedFormulaIndex = -1; + private int colIsRowGuidIndex = -1; + private int colTypeIndex = -1; + private int colOwnerType = -1; + private int colis_sparseIndex = -1; + private int colIs_FileStream = -1; + private int colDefaultIdIndex = -1; + private int colDefaultNameIndex = -1; + private int colDefaultDefinitionIndex = -1; + private int colrule_object_idIndex = -1; + private int colIsIdentityReplIndex = -1; + private int colCollationIndex = -1; + private int colIsIdentityIndex = -1; + private int colIdentSeedIndex = -1; + private int colIdentIncrementIndex = -1; + private int TableIdIndex = -1; + private int TableNameIndex = -1; + private int TableOwnerIndex = -1; + private int TableHasChangeTracking = -1; + private int TableHasChangeTrackingTrackColumn = -1; + private int TableLockEscalation = -1; + private int Text_In_Row_limitIndex = -1; + private int HasClusteredIndexIndex = -1; + private int large_value_types_out_of_rowIndex = -1; + private int HasVarDecimalIndex = -1; + private int FileGroupIndex = -1; + private int FileGroupTextIndex = -1; + private int FileGroupStreamIndex = -1; + + private Generate root; + + public GenerateTables(Generate root) + { + this.root = root; + } + + private void InitTableIndex(Database database, IDataRecord reader) + { + if (reader == null) throw new ArgumentNullException("reader"); + if (TableIdIndex == -1) + { + TableIdIndex = reader.GetOrdinal("TableId"); + TableNameIndex = reader.GetOrdinal("TableName"); + TableOwnerIndex = reader.GetOrdinal("TableOwner"); + Text_In_Row_limitIndex = reader.GetOrdinal("Text_In_Row_limit"); + HasClusteredIndexIndex = reader.GetOrdinal("HasClusteredIndex"); + large_value_types_out_of_rowIndex = reader.GetOrdinal("large_value_types_out_of_row"); + HasVarDecimalIndex = reader.GetOrdinal("HasVarDecimal"); + FileGroupIndex = reader.GetOrdinal("FileGroup"); + FileGroupTextIndex = reader.GetOrdinal("FileGroupText"); + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + { + FileGroupStreamIndex = reader.GetOrdinal("FileGroupStream"); + TableHasChangeTracking = reader.GetOrdinal("HasChangeTracking"); + TableHasChangeTrackingTrackColumn = reader.GetOrdinal("HasChangeTrackingTrackColumn"); + TableLockEscalation = reader.GetOrdinal("lock_escalation_desc"); + } + } + } + + private void InitColIndex(Database database, IDataRecord reader) + { + if (reader == null) throw new ArgumentNullException("reader"); + if (colNameIndex == -1) + { + colIDIndex = reader.GetOrdinal("ID"); + colNameIndex = reader.GetOrdinal("Name"); + colFormulaIndex = reader.GetOrdinal("Formula"); + colIsPersistedIndex = reader.GetOrdinal("FormulaPersisted"); + colIsComputedIndex = reader.GetOrdinal("IsComputed"); + colNullableIndex = reader.GetOrdinal("IsNullable"); + colOwnerType = reader.GetOrdinal("OwnerType"); + colXmlSchemaIndex = reader.GetOrdinal("XmlSchema"); + colIs_xml_documentIndex = reader.GetOrdinal("Is_xml_document"); + colPrecisionIndex = reader.GetOrdinal("Precision"); + colScaleIndex = reader.GetOrdinal("Scale"); + colDataUserTypeIdIndex = reader.GetOrdinal("user_type_id"); + colIsUserDefinedTypeIndex = reader.GetOrdinal("is_user_defined"); + colSizeIndex = reader.GetOrdinal("Size"); + colHasIndexIndex = reader.GetOrdinal("HasIndex"); + colHasComputedFormulaIndex = reader.GetOrdinal("HasComputedFormula"); + colIsRowGuidIndex = reader.GetOrdinal("IsRowGuid"); + colTypeIndex = reader.GetOrdinal("Type"); + colDefaultIdIndex = reader.GetOrdinal("DefaultId"); + colDefaultNameIndex = reader.GetOrdinal("DefaultName"); + colDefaultDefinitionIndex = reader.GetOrdinal("DefaultDefinition"); + colrule_object_idIndex = reader.GetOrdinal("rule_object_id"); + colIsIdentityReplIndex = reader.GetOrdinal("IsIdentityRepl"); + colCollationIndex = reader.GetOrdinal("Collation"); + colIsIdentityIndex = reader.GetOrdinal("IsIdentity"); + colIdentSeedIndex = reader.GetOrdinal("IdentSeed"); + colIdentIncrementIndex = reader.GetOrdinal("IdentIncrement"); + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + { + colis_sparseIndex = reader.GetOrdinal("is_sparse"); + colIs_FileStream = reader.GetOrdinal("is_filestream"); + } + } + } + + private void FillColumn(ITable table, SqlDataReader reader) where T : ISchemaBase + { + Database database = (Database)table.Parent; + + InitColIndex(database, reader); + Column col = new Column((ISchemaBase)table); + col.Id = (int)reader[colIDIndex]; + if (database.Options.Ignore.FilterColumnOrder) + col.Position = table.Columns.Count + 1; + + if (database.Options.Ignore.FilterColumnCollation) + col.Collation = (string)reader[colCollationIndex]; + + if (database.Options.Ignore.FilterColumnIdentity) + { + col.IsIdentity = (bool)reader[colIsIdentityIndex]; + if ((col.IsIdentity) || (col.IsIdentityForReplication)) + { + if (!reader.IsDBNull(colIdentSeedIndex)) + col.IdentitySeed = (long)(decimal)reader[colIdentSeedIndex]; + else + col.IdentitySeed = 1; + + if (!reader.IsDBNull(colIdentIncrementIndex)) + col.IdentityIncrement = (int)(decimal)reader[colIdentIncrementIndex]; + else + col.IdentityIncrement = 1; + } + if (database.Options.Ignore.FilterNotForReplication) + col.IsIdentityForReplication = ((int)reader[colIsIdentityReplIndex] == 1); + } + col.Name = (string)reader[colNameIndex]; + col.Owner = table.Owner; + col.ComputedFormula = (string)reader[colFormulaIndex]; + col.IsPersisted = (bool)reader[colIsPersistedIndex]; + col.IsComputed = (bool)reader[colIsComputedIndex]; + col.IsNullable = (bool)reader[colNullableIndex]; + col.XmlSchema = reader[colXmlSchemaIndex].ToString(); + col.IsXmlDocument = (bool)reader[colIs_xml_documentIndex]; + col.Precision = (byte)reader[colPrecisionIndex]; + col.Scale = (byte)reader[colScaleIndex]; + col.DataUserTypeId = (int)reader[colDataUserTypeIdIndex]; + col.IsUserDefinedType = (bool)reader[colIsUserDefinedTypeIndex]; + if (!String.IsNullOrEmpty(reader[colSizeIndex].ToString())) + col.Size = (short)reader[colSizeIndex]; + col.HasIndexDependencies = ((int)reader[colHasIndexIndex] == 1); + col.HasComputedDependencies = ((int)reader[colHasComputedFormulaIndex] == 1); + col.IsRowGuid = (bool)reader[colIsRowGuidIndex]; + if (col.IsUserDefinedType) + col.Type = "[" + (string)reader[colOwnerType] + "].[" + (string)reader[colTypeIndex] + "]"; + else + col.Type = (string)reader[colTypeIndex]; + if (((Database)table.Parent).Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + { + col.IsSparse = (bool)reader[colis_sparseIndex]; + col.IsFileStream = (bool)reader[colIs_FileStream]; + } + if ((int)reader[colDefaultIdIndex] != 0) + { + col.DefaultConstraint = new ColumnConstraint(col) + { + Id = (int)reader[colDefaultIdIndex], + Owner = table.Owner, + Name = (string)reader[colDefaultNameIndex], + Type = Constraint.ConstraintType.Default, + Definition = (string)reader[colDefaultDefinitionIndex] + }; + } + if ((int)reader[colrule_object_idIndex] != 0) + col.Rule = ((Database)table.Parent).Rules.Find((int)reader[colrule_object_idIndex]); + table.Columns.Add(col); + } + + public void Fill(Database database, string connectionString, List messages) + { + try + { + root.RaiseOnReading(new ProgressEventArgs("Reading tables...", Constants.READING_TABLES)); + FillTables(database, connectionString); + if (database.Tables.Any() || database.TablesTypes.Any()) + { + if (database.Options.Ignore.FilterConstraint) + (new GenerateConstraint(root)).Fill(database, connectionString); + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + + private void FillTables(Database database, string connectionString) + { + int textInRow; + Boolean largeValues; + Boolean varDecimal; + int lastObjectId = 0; + bool isTable = true; + ISchemaBase item = null; + + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(TableSQLCommand.GetTableDetail(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + InitTableIndex(database, reader); + root.RaiseOnReadingOne(reader[TableNameIndex]); + if (lastObjectId != (int)reader[TableIdIndex]) + { + lastObjectId = (int)reader[TableIdIndex]; + isTable = reader["ObjectType"].ToString().Trim().Equals("U"); + if (isTable) + { + item = new Table(database); + item.Id = (int)reader[TableIdIndex]; + item.Name = (string)reader[TableNameIndex]; + item.Owner = (string)reader[TableOwnerIndex]; + ((Table)item).HasClusteredIndex = (int)reader[HasClusteredIndexIndex] == 1; + textInRow = (int)reader[Text_In_Row_limitIndex]; + largeValues = (Boolean)reader[large_value_types_out_of_rowIndex]; + varDecimal = ((int)reader[HasVarDecimalIndex]) == 1; + if (database.Options.Ignore.FilterTableFileGroup) + { + ((Table)item).FileGroup = (string)reader[FileGroupIndex]; + ((Table)item).FileGroupText = (string)reader[FileGroupTextIndex]; + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008) + { + if (database.Options.Ignore.FilterTableChangeTracking) + { + ((Table)item).FileGroupStream = (string)reader[FileGroupStreamIndex]; + ((Table)item).HasChangeTracking = ((int)reader[TableHasChangeTracking]) == 1; + ((Table)item).HasChangeTrackingTrackColumn = ((int)reader[TableHasChangeTrackingTrackColumn]) == 1; + } + } + } + if (database.Options.Ignore.FilterTableOption) + { + if (textInRow > 0) ((Table)item).Options.Add(new TableOption("TextInRow", textInRow.ToString(CultureInfo.InvariantCulture), item)); + if (largeValues) ((Table)item).Options.Add(new TableOption("LargeValues", "1", item)); + if (varDecimal) ((Table)item).Options.Add(new TableOption("VarDecimal", "1", item)); + } + if ((database.Options.Ignore.FilterTableLockEscalation) && (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServer2008)) + ((Table)item).Options.Add(new TableOption("LockEscalation", (string)reader[TableLockEscalation], item)); + else + ((Table)item).Options.Add(new TableOption("LockEscalation", "TABLE", item)); + database.Tables.Add((Table)item); + } + else + { + item = new TableType(database) + { + Id = (int)reader[TableIdIndex], + Name = (string)reader[TableNameIndex], + Owner = (string)reader[TableOwnerIndex] + }; + database.TablesTypes.Add((TableType)item); + } + } + if (isTable) + { + if (database.Options.Ignore.FilterTable) + FillColumn((ITable
)item, reader); + } + else + { + if (database.Options.Ignore.FilterUserDataType) + FillColumn((ITable)item, reader); + } + } + } + } + } + //tables.ToSQL(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateTextObjects.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateTextObjects.cs new file mode 100644 index 0000000..7e6a446 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateTextObjects.cs @@ -0,0 +1,120 @@ +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Data.SqlClient; +using System.Text.RegularExpressions; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateTextObjects + { + private Generate root; + + public GenerateTextObjects(Generate root) + { + this.root = root; + } + + private static string GetSQL(SqlOption options) + { + var filterQuery = SQLQueries.SQLQueryFactory.Get("GetTextObjectsQuery"); + string filter = ""; + if (options.Ignore.FilterStoredProcedure) + filter += "O.type = 'P' OR "; + if (options.Ignore.FilterView) + filter += "O.type = 'V' OR "; + if (options.Ignore.FilterTrigger) + filter += "O.type = 'TR' OR "; + if (options.Ignore.FilterFunction) + filter += "O.type IN ('IF','FN','TF') OR "; + filter = filter.Substring(0, filter.Length - 4); + return filterQuery.Replace("{FILTER}", filter); + } + + public void Fill(Database database, string connectionString) + { + ICode code = null; + try + { + if ((database.Options.Ignore.FilterStoredProcedure) || (database.Options.Ignore.FilterView) || (database.Options.Ignore.FilterFunction) || (database.Options.Ignore.FilterTrigger)) + { + root.RaiseOnReading(new ProgressEventArgs("Reading Text Objects...", Constants.READING_TEXTOBJECTS)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(database.Options), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + code = null; + root.RaiseOnReadingOne(reader["name"]); + string type = reader["Type"].ToString().Trim(); + string name = reader["name"].ToString(); + string definition = reader["Text"].ToString(); + int id = (int)reader["object_id"]; + if (type.Equals("V")) + code = (ICode)database.Views.Find(id); + + if (type.Equals("TR")) + code = (ICode)database.Find(id); + + if (type.Equals("P")) + { + var procedure = database.Procedures.Find(id); + if (procedure != null) + ((ICode)procedure).Text = GetObjectDefinition(type, name, definition); + } + + if (type.Equals("IF") || type.Equals("FN") || type.Equals("TF")) + code = (ICode)database.Functions.Find(id); + + if (code != null) + code.Text = reader["Text"].ToString(); + } + } + } + } + } + } + catch (Exception ex) + { + throw ex; + } + } + + private string GetObjectDefinition(string type, string name, string definition) + { + string rv = definition; + + string sqlDelimiters = @"(\r|\n|\s)+?"; + RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.Multiline; + Regex re = new Regex(@"CREATE" + sqlDelimiters + @"PROC(EDURE)?" + sqlDelimiters + @"(\w+\.|\[\w+\]\.)?\[?(?\w+)\]?" + sqlDelimiters, options); + switch (type) + { + case "P": + Match match = re.Match(definition); + if (match != null && match.Success) + { + // Try to replace the name saved in the definition when the object was created by the one used for the object in sys.object + string oldName = match.Groups["spname"].Value; + //if (String.IsNullOrEmpty(oldName)) System.Diagnostics.Debugger.Break(); + if (String.Compare(oldName, name) != 0) + { + rv = rv.Replace(oldName, name); + } + } + break; + default: + //TODO : Add the logic used for other objects than procedures + break; + } + + return rv; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateTriggers.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateTriggers.cs new file mode 100644 index 0000000..b8279bf --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateTriggers.cs @@ -0,0 +1,115 @@ +using OpenDBDiff.Abstractions.Schema.Errors; +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateTriggers + { + private Generate root; + + public GenerateTriggers(Generate root) + { + this.root = root; + } + + private static string GetSQL(DatabaseInfo.SQLServerVersion version, SqlOption options) + { + if (version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) + { + return SQLQueries.SQLQueryFactory.Get("GetTriggers", version); + } + else + { + return SQLQueries.SQLQueryFactory.Get("GetTriggers"); + } + } + + public void Fill(Database database, string connectionString, List messages) + { + int parentId = 0; + ISchemaBase parent = null; + string type; + try + { + if (database.Options.Ignore.FilterTrigger) + { + root.RaiseOnReading(new ProgressEventArgs("Reading Triggers...", Constants.READING_TRIGGERS)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQL(database.Info.Version, database.Options), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + type = reader["ObjectType"].ToString().Trim(); + if (parentId != (int)reader["parent_id"]) + { + parentId = (int)reader["parent_id"]; + if (type.Equals("V")) + parent = database.Views.Find(parentId); + else + parent = database.Tables.Find(parentId); + } + if (parent == null) { continue; } + if (reader["type"].Equals("TR")) + { + Trigger item = new Trigger(parent); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.InsteadOf = (bool)reader["is_instead_of_trigger"]; + item.IsDisabled = (bool)reader["is_disabled"]; + item.IsDDLTrigger = false; + item.Owner = reader["Owner"].ToString(); + if (database.Options.Ignore.FilterNotForReplication) + item.NotForReplication = (bool)reader["is_not_for_replication"]; + if (type.Equals("V")) + ((View)parent).Triggers.Add(item); + else + ((Table)parent).Triggers.Add(item); + } + else + { + CLRTrigger item = new CLRTrigger(parent); + item.Id = (int)reader["object_id"]; + item.Name = reader["Name"].ToString(); + item.IsDelete = (bool)reader["IsDelete"]; + item.IsUpdate = (bool)reader["IsUpdate"]; + item.IsInsert = (bool)reader["IsInsert"]; + item.Owner = reader["Owner"].ToString(); + item.IsAssembly = true; + item.AssemblyId = (int)reader["assembly_id"]; + item.AssemblyName = reader["assembly_name"].ToString(); + item.AssemblyClass = reader["assembly_class"].ToString(); + item.AssemblyExecuteAs = reader["ExecuteAs"].ToString(); + item.AssemblyMethod = reader["assembly_method"].ToString(); + if (type.Equals("V")) + ((View)parent).CLRTriggers.Add(item); + else + ((Table)parent).CLRTriggers.Add(item); + /*if (!database.Options.Ignore.FilterIgnoreNotForReplication) + trigger.NotForReplication = (bool)reader["is_not_for_replication"];*/ + } + } + } + } + } + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateUserDataTypes.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateUserDataTypes.cs new file mode 100644 index 0000000..351e924 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateUserDataTypes.cs @@ -0,0 +1,106 @@ +using OpenDBDiff.Abstractions.Schema.Errors; +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Generates.SQLCommands; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateUserDataTypes + { + private readonly Generate root; + + public GenerateUserDataTypes(Generate root) + { + this.root = root; + } + + private static string GetSQLColumnsDependencies() + { + return SQLQueries.SQLQueryFactory.Get("GetSQLColumnsDependencies"); + } + + private static void FillColumnsDependencies(SchemaList types, string connectionString) + { + if (types == null) throw new ArgumentNullException("types"); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLColumnsDependencies(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + types[reader["TypeName"].ToString()].Dependencies.Add(new ObjectDependency(reader["TableName"].ToString(), reader["ColumnName"].ToString(), ConvertType.GetObjectType(reader["Type"].ToString()))); + } + } + } + } + } + + public void Fill(Database database, string connectionString, List messages) + { + //not supported in azure yet http://msdn.microsoft.com/en-us/library/ee336233.aspx + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) return; + + try + { + if (database.Options.Ignore.FilterUserDataType) + { + root.RaiseOnReading(new ProgressEventArgs("Reading UDT...", Constants.READING_UDT)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(UserDataTypeCommand.Get(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["Name"]); + UserDataType item = new UserDataType(database); + item.Id = (int)reader["tid"]; + item.AllowNull = (bool)reader["is_nullable"]; + item.Size = (short)reader["max_length"]; + item.Name = reader["Name"].ToString(); + item.Owner = reader["owner"].ToString(); + item.Precision = int.Parse(reader["precision"].ToString()); + item.Scale = int.Parse(reader["scale"].ToString()); + if (!String.IsNullOrEmpty(reader["defaultname"].ToString())) + { + item.Default.Name = reader["defaultname"].ToString(); + item.Default.Owner = reader["defaultowner"].ToString(); + } + if (!String.IsNullOrEmpty(reader["rulename"].ToString())) + { + item.Rule.Name = reader["rulename"].ToString(); + item.Rule.Owner = reader["ruleowner"].ToString(); + } + item.Type = reader["basetypename"].ToString(); + item.IsAssembly = (bool)reader["is_assembly_type"]; + item.AssemblyId = (int)reader["assembly_id"]; + item.AssemblyName = reader["assembly_name"].ToString(); + item.AssemblyClass = reader["assembly_class"].ToString(); + database.UserTypes.Add(item); + } + } + } + } + if (database.Options.Ignore.FilterTable) + FillColumnsDependencies(database.UserTypes, connectionString); + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateUsers.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateUsers.cs new file mode 100644 index 0000000..9d4065a --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateUsers.cs @@ -0,0 +1,63 @@ +using System; +using System.Data.SqlClient; +using OpenDBDiff.SqlServer.Schema.Generates.SQLCommands; +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateUsers + { + private Generate root; + + public GenerateUsers(Generate root) + { + this.root = root; + } + + public void Fill(Database database, string connectioString) + { + string type; + if ((database.Options.Ignore.FilterUsers) || (database.Options.Ignore.FilterRoles)) + { + using (SqlConnection conn = new SqlConnection(connectioString)) + { + using (SqlCommand command = new SqlCommand(UserSQLCommand.Get(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + type = reader["type"].ToString(); + if (database.Options.Ignore.FilterUsers && (type.Equals("S") || type.Equals("U"))) + { + User item = new User(database); + item.Id = (int)reader["principal_id"]; + item.Name = reader["name"].ToString(); + item.Login = reader["Login"].ToString(); + item.Owner = reader["default_schema_name"].ToString(); + database.Users.Add(item); + } + if (database.Options.Ignore.FilterRoles && (type.Equals("A") || type.Equals("R"))) + { + Role item = new Role(database); + item.Id = (int)reader["principal_id"]; + item.Name = reader["name"].ToString(); + item.Owner = reader["default_schema_name"].ToString(); + item.Password = ""; + item.IsSystem = (Boolean)reader["is_fixed_role"]; + if (type.Equals("A")) + item.Type = Role.RoleTypeEnum.ApplicationRole; + else + item.Type = Role.RoleTypeEnum.DatabaseRole; + database.Roles.Add(item); + } + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateViews.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateViews.cs new file mode 100644 index 0000000..75deffe --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateViews.cs @@ -0,0 +1,77 @@ +using OpenDBDiff.Abstractions.Schema.Errors; +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.SqlServer.Schema.Generates.SQLCommands; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using System; +using System.Collections.Generic; +using System.Data.SqlClient; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateViews + { + private Generate root; + + public GenerateViews(Generate root) + { + this.root = root; + } + + public void Fill(Database database, string connectionString, List messages) + { + try + { + root.RaiseOnReading(new ProgressEventArgs("Reading views...", Constants.READING_VIEWS)); + if (database.Options.Ignore.FilterView) + { + FillView(database, connectionString); + } + } + catch (Exception ex) + { + messages.Add(new MessageLog(ex.Message, ex.StackTrace, MessageLog.LogType.Error)); + } + } + + private void FillView(Database database, string connectionString) + { + int lastViewId = 0; + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(ViewSQLCommand.GetView(database.Info.Version, database.Info.Edition), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + View item = null; + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["name"]); + if (lastViewId != (int)reader["object_id"]) + { + item = new View(database); + item.Id = (int)reader["object_id"]; + item.Name = reader["name"].ToString(); + item.Owner = reader["owner"].ToString(); + item.IsSchemaBinding = reader["IsSchemaBound"].ToString().Equals("1"); + database.Views.Add(item); + lastViewId = item.Id; + } + if (item.IsSchemaBinding) + { + if (!reader.IsDBNull(reader.GetOrdinal("referenced_major_id"))) + database.Dependencies.Add(database, (int)reader["referenced_major_id"], item); + if (!String.IsNullOrEmpty(reader["TableName"].ToString())) + item.DependenciesIn.Add(reader["TableName"].ToString()); + if (!String.IsNullOrEmpty(reader["DependOut"].ToString())) + item.DependenciesOut.Add(reader["DependOut"].ToString()); + } + } + } + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/GenerateXMLSchemas.cs b/OpenDBDiff.SqlServer.Schema/Generates/GenerateXMLSchemas.cs new file mode 100644 index 0000000..02fc927 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/GenerateXMLSchemas.cs @@ -0,0 +1,84 @@ +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Generates.Util; +using OpenDBDiff.SqlServer.Schema.Model; +using System.Data.SqlClient; + +namespace OpenDBDiff.SqlServer.Schema.Generates +{ + public class GenerateXMLSchemas + { + private Generate root; + + public GenerateXMLSchemas(Generate root) + { + this.root = root; + } + + private static string GetSQLColumnsDependencies() + { + return SQLQueries.SQLQueryFactory.Get("GetXMLSchemaCollections"); + } + + private static string GetSQLXMLSchema() + { + return SQLQueries.SQLQueryFactory.Get("GetSQLXMLSchema"); + } + + private static void FillColumnsDependencies(SchemaList items, string connectionString) + { + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLColumnsDependencies(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + items[reader["XMLName"].ToString()].Dependencies.Add(new ObjectDependency(reader["TableName"].ToString(), reader["ColumnName"].ToString(), ConvertType.GetObjectType(reader["Type"].ToString()))); + } + } + } + } + } + + public void Fill(Database database, string connectionString) + { + //TODO XML_SCHEMA_NAMESPACE function not supported in Azure, is there a workaround? + //not supported in azure yet + if (database.Info.Version == DatabaseInfo.SQLServerVersion.SQLServerAzure10) return; + + + if (database.Options.Ignore.FilterXMLSchema) + { + root.RaiseOnReading(new ProgressEventArgs("Reading XML Schema...", Constants.READING_XMLSCHEMAS)); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + using (SqlCommand command = new SqlCommand(GetSQLXMLSchema(), conn)) + { + conn.Open(); + command.CommandTimeout = 0; + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + root.RaiseOnReadingOne(reader["name"]); + XMLSchema item = new XMLSchema(database); + item.Id = (int)reader["ID"]; + item.Name = reader["name"].ToString(); + item.Owner = reader["owner"].ToString(); + item.Text = reader["Text"].ToString(); + database.XmlSchemas.Add(item); + + } + } + } + } + if (database.Options.Ignore.FilterTable) + FillColumnsDependencies(database.XmlSchemas, connectionString); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/ConstraintSQLCommand.cs b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/ConstraintSQLCommand.cs new file mode 100644 index 0000000..0c28f90 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/ConstraintSQLCommand.cs @@ -0,0 +1,192 @@ +using OpenDBDiff.SqlServer.Schema.Model; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Generates.SQLCommands +{ + internal static class ConstraintSQLCommand + { + public static string GetUniqueKey(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return GetUniqueKey2005(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetUniqueKeyAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetUniqueKeyAzure(); + else + return GetUniqueKey2008(); + } + } + + public static string GetCheck(DatabaseInfo.SQLServerVersion version) + { + if (version == DatabaseInfo.SQLServerVersion.SQLServer2005) return GetCheck2005(); + //Fall back to highest compatible version + return GetCheck2008(); + } + + public static string GetPrimaryKey(DatabaseInfo.SQLServerVersion version, Table table) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + return GetPrimaryKey2000(table); + + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return GetPrimaryKey2005(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetPrimaryKeyAzure(); + + default: + return GetPrimaryKey2008(); + } + } + + private static string GetUniqueKeyAzure() + { + //File Groups not supported in Azure + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, I.object_Id AS id,'' as FileGroup, C.user_type_id, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + //sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_unique_constraint = 1 AND O.type <> 'TF' ORDER BY I.object_id,I.Name"); + return sql.ToString(); + } + + private static string GetUniqueKey2008() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, I.object_Id AS id,dsidx.Name as FileGroup, C.user_type_id, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_unique_constraint = 1 AND O.type <> 'TF' ORDER BY I.object_id,I.Name"); + return sql.ToString(); + } + + private static string GetUniqueKey2005() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, I.object_Id AS id,dsidx.Name as FileGroup, C.user_type_id, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_unique_constraint = 1 AND O.type <> 'TF' ORDER BY I.object_id,I.Name"); + return sql.ToString(); + } + + private static string GetCheck2008() + { + string sql; + sql = "SELECT "; + sql += "CC.parent_object_id, "; + sql += "O.type as ObjectType, "; + sql += "CC.object_id AS ID, "; + sql += "CC.parent_column_id, "; + sql += "CC.name, "; + sql += "CC.type, "; + sql += "CC.definition, "; + sql += "CC.is_disabled, "; + sql += "CC.is_not_trusted AS WithCheck, "; + sql += "CC.is_not_for_replication, "; + sql += "0, "; + sql += "schema_name(CC.schema_id) AS Owner "; + sql += "FROM sys.check_constraints CC "; + sql += "INNER JOIN sys.objects O ON O.object_id = CC.parent_object_id "; + sql += "ORDER BY CC.parent_object_id,CC.name"; + return sql; + } + + private static string GetCheck2005() + { + string sql; + sql = "SELECT "; + sql += "CC.parent_object_id, "; + sql += "O.Type as ObjectType, "; + sql += "CC.object_id AS ID, "; + sql += "CC.parent_column_id, "; + sql += "CC.name, "; + sql += "CC.type, "; + sql += "CC.definition, "; + sql += "CC.is_disabled, "; + sql += "CC.is_not_trusted AS WithCheck, "; + sql += "CC.is_not_for_replication, "; + sql += "0, "; + sql += "schema_name(CC.schema_id) AS Owner "; + sql += "FROM sys.check_constraints CC "; + sql += "INNER JOIN sys.objects O ON O.object_id = CC.parent_object_id "; + sql += "ORDER BY CC.parent_object_id,CC.name"; + return sql; + } + + private static string GetPrimaryKeyAzure() + { + //File Groups not supported in Azure + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, IC.key_ordinal, C.user_type_id, I.object_id AS ID, '' AS FileGroup, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column, CONVERT(bit,INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics')) AS IsAutoStatistics "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + //sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_primary_key = 1 AND O.type <> 'TF' ORDER BY I.object_id"); + return sql.ToString(); + } + + private static string GetPrimaryKey2008() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, IC.key_ordinal, C.user_type_id, I.object_id AS ID, dsidx.Name AS FileGroup, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column, CONVERT(bit,INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics')) AS IsAutoStatistics "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_primary_key = 1 AND O.type <> 'TF' ORDER BY I.object_id"); + return sql.ToString(); + } + + private static string GetPrimaryKey2005() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT O.type as ObjectType, S.Name as Owner, IC.key_ordinal, C.user_type_id, I.object_id AS ID, dsidx.Name AS FileGroup, C.column_id, I.Index_id, C.Name AS ColumnName, I.Name, I.type, I.fill_factor, I.is_padded, I.allow_row_locks, I.allow_page_locks, I.ignore_dup_key, I.is_disabled, IC.is_descending_key, IC.is_included_column, CONVERT(bit,INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics')) AS IsAutoStatistics "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects O ON O.object_id = I.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = O.schema_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("INNER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("WHERE is_primary_key = 1 AND O.type <> 'TF' ORDER BY I.object_id"); + return sql.ToString(); + } + + private static string GetPrimaryKey2000(Table table) + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT CONVERT(tinyint,CASE WHEN SI.indid = 0 THEN 0 WHEN SI.indid = 1 THEN 1 WHEN SI.indid > 1 THEN 2 END) AS Type,f.groupname AS FileGroup,CONVERT(int,SI.indid) AS Index_id, CONVERT(int,SI.indid) AS ID, SI.name, SC.colid, SC.Name AS ColumnName, CONVERT(bit,0) AS is_included_column, SIK.keyno AS key_ordinal, CONVERT(bit,INDEXPROPERTY(SI.id,SI.name,'IsPadIndex')) AS is_padded, CONVERT(bit,INDEXPROPERTY(SI.id,SI.name,'IsRowLockDisallowed')) AS allow_row_locks, CONVERT(bit,INDEXPROPERTY(SI.id,SI.name,'IsPageLockDisallowed')) AS allow_page_locks, CONVERT(bit,INDEXPROPERTY(SI.id,SI.name,'IsAutoStatistics')) AS IsAutoStatistics, CONVERT(tinyint,INDEXPROPERTY(SI.id,SI.name,'IndexFillFactor')) AS fill_factor, INDEXKEY_PROPERTY(SI.id, SI.indid,SC.colid,'IsDescending') AS is_descending_key, CONVERT(bit,0) AS is_disabled, CONVERT(bit,0) AS is_included_column "); + sql.Append("FROM sysindexes SI INNER JOIN sysindexkeys SIK ON SI.indid = SIK.indid AND SIK.id = SI.ID "); + sql.Append("INNER JOIN syscolumns SC ON SC.colid = SIK.colid AND SC.id = SI.ID "); + sql.Append("inner join sysfilegroups f on f.groupid = SI.groupid "); + sql.Append("WHERE (SI.status & 0x800) = 0x800 AND SI.id = " + table.Id.ToString() + " ORDER BY SIK.keyno"); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/DatabaseSQLCommand.cs b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/DatabaseSQLCommand.cs new file mode 100644 index 0000000..cd03fc8 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/DatabaseSQLCommand.cs @@ -0,0 +1,67 @@ +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates.SQLCommands +{ + internal class DatabaseSQLCommand + { + public static string GetVersion(Database databaseSchema) + { + string sql; + sql = "SELECT SERVERPROPERTY('productversion') AS Version, SERVERPROPERTY('EngineEdition') AS Edition"; + return sql; + } + + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition, Database databaseSchema) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(databaseSchema); + + case DatabaseInfo.SQLServerVersion.SQLServer2008: + return Get2008(databaseSchema); + + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return Get2008R2(databaseSchema); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetAzure(databaseSchema); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetAzure(databaseSchema); + else + return Get2008R2(databaseSchema); + } + } + + private static string Get2005(Database databaseSchema) + { + string sql; + sql = "SELECT DATABASEPROPERTYEX('" + databaseSchema.Name + "','IsFulltextEnabled') AS IsFullTextEnabled, DATABASEPROPERTYEX('" + databaseSchema.Name + "','Collation') AS Collation"; + return sql; + } + + private static string Get2008(Database databaseSchema) + { + string sql; + sql = "SELECT DATABASEPROPERTYEX('" + databaseSchema.Name + "','IsFulltextEnabled') AS IsFullTextEnabled, DATABASEPROPERTYEX('" + databaseSchema.Name + "','Collation') AS Collation"; + return sql; + } + + private static string Get2008R2(Database databaseSchema) + { + string sql; + sql = "SELECT DATABASEPROPERTYEX('" + databaseSchema.Name + "','IsFulltextEnabled') AS IsFullTextEnabled, DATABASEPROPERTYEX('" + databaseSchema.Name + "','Collation') AS Collation"; + return sql; + } + + private static string GetAzure(Database databaseSchema) + { + string sql; + //DATABASEPROPERTYEX('IsFullTextEnabled') is deprecated http://technet.microsoft.com/en-us/library/cc646010(SQL.110).aspx + sql = "SELECT 0 AS IsFullTextEnabled, DATABASEPROPERTYEX('" + databaseSchema.Name + "','Collation') AS Collation"; + return sql; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/FullTextIndexSQLCommand.cs b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/FullTextIndexSQLCommand.cs new file mode 100644 index 0000000..11d05a4 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/FullTextIndexSQLCommand.cs @@ -0,0 +1,72 @@ +using OpenDBDiff.SqlServer.Schema.Model; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Generates.SQLCommands +{ + internal static class FullTextIndexSQLCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(); + + default: + return Get2008(); + } + } + + private static string Get2005() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT "); + sql.Append("FI.object_id, "); + sql.Append("T.Name AS TableName, "); + sql.Append("FC.name AS FullTextCatalogName, "); + sql.Append("I.name AS IndexName, "); + sql.Append("FI.is_enabled, "); + sql.Append("'['+ S.name + '].['+ T.name + '].[' + FC.name + ']' AS Name, "); + sql.Append("C.name as ColumnName, "); + sql.Append("FI.change_tracking_state_desc AS ChangeTracking, "); + sql.Append("FL.name AS LanguageName "); + sql.Append("FROM sys.fulltext_indexes FI "); + sql.Append("INNER JOIN sys.fulltext_catalogs FC ON FC.fulltext_catalog_id = FI.fulltext_catalog_id "); + sql.Append("INNER JOIN sys.indexes I ON I.index_id = FI.unique_index_id and I.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.tables T ON T.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = T.schema_id "); + sql.Append("INNER JOIN sys.fulltext_index_columns FIC ON FIC.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.object_id = FIC.object_id AND C.column_id = FIC.column_id "); + sql.Append("INNER JOIN sys.fulltext_languages FL ON FL.lcid = FIC.language_id "); + sql.Append("ORDER BY OBJECT_NAME(FI.object_id), I.name "); + return sql.ToString(); + } + + private static string Get2008() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT "); + sql.Append("FI.object_id, "); + sql.Append("T.Name AS TableName, "); + sql.Append("FC.name AS FullTextCatalogName, "); + sql.Append("I.name AS IndexName, "); + sql.Append("FI.is_enabled, "); + sql.Append("'['+ S.name + '].['+ T.name + '].[' + FC.name + ']' AS Name, "); + sql.Append("C.name as ColumnName, "); + sql.Append("FL.name AS LanguageName,"); + sql.Append("DS.name AS FileGroupName, "); + sql.Append("FI.change_tracking_state_desc AS ChangeTracking "); + sql.Append("FROM sys.fulltext_indexes FI "); + sql.Append("INNER JOIN sys.fulltext_catalogs FC ON FC.fulltext_catalog_id = FI.fulltext_catalog_id "); + sql.Append("INNER JOIN sys.indexes I ON I.index_id = FI.unique_index_id and I.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.tables T ON T.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = T.schema_id "); + sql.Append("INNER JOIN sys.fulltext_index_columns FIC ON FIC.object_id = FI.object_id "); + sql.Append("INNER JOIN sys.columns C ON C.object_id = FIC.object_id AND C.column_id = FIC.column_id "); + sql.Append("INNER JOIN sys.data_spaces DS ON DS.data_space_id = FI.data_space_id "); + sql.Append("INNER JOIN sys.fulltext_languages FL ON FL.lcid = FIC.language_id "); + sql.Append("ORDER BY OBJECT_NAME(FI.object_id), I.name "); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/FunctionSQLCommand.cs b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/FunctionSQLCommand.cs new file mode 100644 index 0000000..858e625 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/FunctionSQLCommand.cs @@ -0,0 +1,111 @@ +using OpenDBDiff.SqlServer.Schema.Model; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Generates.SQLCommands +{ + internal static class FunctionSQLCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(); + + case DatabaseInfo.SQLServerVersion.SQLServer2008: + return Get2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetAzure(); + else + return Get2008(); + } + } + + private static string Get2005() + { + string sql = ""; + sql += "select distinct "; + sql += "T.name AS ReturnType, PP.max_length, PP.precision, PP.Scale, "; + sql += "ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, "; + sql += "P.type, "; + sql += "AF.name AS assembly_name, "; + sql += "AM.assembly_class, "; + sql += "AM.assembly_id, "; + sql += "AM.assembly_method, "; + sql += "ISNULL('[' + S3.Name + '].[' + object_name(D2.object_id) + ']','') AS DependOut, '[' + S2.Name + '].[' + object_name(D.referenced_major_id) + ']' AS TableName, D.referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, P.object_id, S.name as owner, P.name as name from sys.objects P "; + sql += "INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "; + sql += "LEFT JOIN sys.sql_dependencies D ON P.object_id = D.object_id "; + sql += "LEFT JOIN sys.objects O ON O.object_id = D.referenced_major_id "; + sql += "LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "; + sql += "LEFT JOIN sys.sql_dependencies D2 ON P.object_id = D2.referenced_major_id "; + sql += "LEFT JOIN sys.objects O2 ON O2.object_id = D2.object_id "; + sql += "LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "; + sql += "LEFT JOIN sys.assembly_modules AM ON AM.object_id = P.object_id "; + sql += "LEFT JOIN sys.assemblies AF ON AF.assembly_id = AM.assembly_id "; + sql += "LEFT JOIN sys.parameters PP ON PP.object_id = AM.object_id AND PP.parameter_id = 0 and PP.is_output = 1 "; + sql += "LEFT JOIN sys.types T ON T.system_type_id = PP.system_type_id "; + sql += "WHERE P.type IN ('IF','FN','TF','FS') ORDER BY P.object_id"; + return sql; + } + + private static string Get2008() + { + var sql = new StringBuilder(); + sql.AppendLine("SELECT DISTINCT "); + sql.AppendLine("T.name AS ReturnType, PP.max_length, PP.precision, PP.Scale, "); + sql.AppendLine("ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, "); + sql.AppendLine("P.type, "); + sql.AppendLine("AF.name AS assembly_name, "); + sql.AppendLine("AM.assembly_class, "); + sql.AppendLine("AM.assembly_id, "); + sql.AppendLine("AM.assembly_method, "); + sql.AppendLine("ISNULL('[' + S3.Name + '].[' + object_name(D2.object_id) + ']','') AS DependOut, '[' + S2.Name + '].[' + object_name(D.referenced_major_id) + ']' AS TableName, D.referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, P.object_id, S.name as owner, P.name as name from sys.objects P "); + sql.AppendLine("INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "); + sql.AppendLine("LEFT JOIN sys.sql_dependencies D ON P.object_id = D.object_id "); + sql.AppendLine("LEFT JOIN sys.objects O ON O.object_id = D.referenced_major_id "); + sql.AppendLine("LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "); + sql.AppendLine("LEFT JOIN sys.sql_dependencies D2 ON P.object_id = D2.referenced_major_id "); + sql.AppendLine("LEFT JOIN sys.objects O2 ON O2.object_id = D2.object_id "); + sql.AppendLine("LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "); + sql.AppendLine("LEFT JOIN sys.assembly_modules AM ON AM.object_id = P.object_id "); + sql.AppendLine("LEFT JOIN sys.assemblies AF ON AF.assembly_id = AM.assembly_id "); + sql.AppendLine("LEFT JOIN sys.parameters PP ON PP.object_id = AM.object_id AND PP.parameter_id = 0 and PP.is_output = 1 "); + sql.AppendLine("LEFT JOIN sys.types T ON T.system_type_id = PP.system_type_id "); + sql.AppendLine("WHERE P.type IN ('IF','FN','TF','FS') ORDER BY P.object_id"); + return sql.ToString(); + } + + private static string GetAzure() + { + var sql = new StringBuilder(); + sql.AppendLine("SELECT DISTINCT "); + sql.AppendLine("T.name AS ReturnType, PP.max_length, PP.precision, PP.Scale, "); + sql.AppendLine("ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, "); + sql.AppendLine("P.type, "); + sql.AppendLine("AF.name AS assembly_name, "); + sql.AppendLine("AM.assembly_class, "); + sql.AppendLine("AM.assembly_id, "); + sql.AppendLine("AM.assembly_method, "); + sql.AppendLine("ISNULL('[' + S3.Name + '].[' + object_name(D2.referencing_id) + ']','') AS DependOut, "); + sql.AppendLine("'[' + S2.Name + '].[' + object_name(D.referenced_id) + ']' AS TableName, D.referenced_id AS referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, P.object_id, S.name as owner, P.name as name from sys.objects P "); + sql.AppendLine("INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "); + sql.AppendLine("LEFT JOIN sys.sql_expression_dependencies D ON P.object_id = D.referencing_id "); + sql.AppendLine("LEFT JOIN sys.objects O ON O.object_id = D.referenced_id "); + sql.AppendLine("LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "); + sql.AppendLine("LEFT JOIN sys.sql_expression_dependencies D2 ON P.object_id = D2.referenced_id "); + sql.AppendLine("LEFT JOIN sys.objects O2 ON O2.object_id = D2.referencing_id "); + sql.AppendLine("LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "); + sql.AppendLine("CROSS JOIN (SELECT null as object_id, null as execute_as_principal_id, null as assembly_class, null as assembly_id, null as assembly_method) AS AM "); + sql.AppendLine("CROSS JOIN (SELECT null AS name) AS AF"); + sql.AppendLine("LEFT JOIN sys.parameters PP ON PP.object_id = AM.object_id AND PP.parameter_id = 0 and PP.is_output = 1 "); + sql.AppendLine("LEFT JOIN sys.types T ON T.system_type_id = PP.system_type_id "); + sql.AppendLine("WHERE P.type IN ('IF','FN','TF','FS') ORDER BY P.object_id"); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/IndexSQLCommand.cs b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/IndexSQLCommand.cs new file mode 100644 index 0000000..b801c67 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/IndexSQLCommand.cs @@ -0,0 +1,81 @@ +using OpenDBDiff.SqlServer.Schema.Model; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Generates.SQLCommands +{ + internal static class IndexSQLCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(); + + case DatabaseInfo.SQLServerVersion.SQLServer2008: + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return Get2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetAzure(); + else + return Get2008(); + } + } + + private static string Get2005() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT OO.type AS ObjectType, IC.key_ordinal, C.user_type_id, I.object_id, dsidx.Name as FileGroup, C.column_id,C.Name AS ColumnName, I.Name, I.index_id, I.type, is_unique, ignore_dup_key, is_primary_key, is_unique_constraint, fill_factor, is_padded, is_disabled, allow_row_locks, allow_page_locks, IC.is_descending_key, IC.is_included_column, ISNULL(ST.no_recompute,0) AS NoAutomaticRecomputation "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects OO ON OO.object_id = I.object_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.stats AS ST ON ST.stats_id = I.index_id AND ST.object_id = I.object_id "); + sql.Append("WHERE I.type IN (1,2,3) "); + sql.Append("AND is_unique_constraint = 0 AND is_primary_key = 0 "); //AND I.object_id = " + table.Id.ToString(CultureInfo.InvariantCulture) + " "); + sql.Append("AND objectproperty(I.object_id, 'IsMSShipped') <> 1 "); + sql.Append("ORDER BY I.object_id, I.Name, IC.column_id"); + return sql.ToString(); + } + + private static string Get2008() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT ISNULL(I.filter_definition,'') AS FilterDefinition, OO.type AS ObjectType, IC.key_ordinal, C.user_type_id, I.object_id, dsidx.Name as FileGroup, C.column_id,C.Name AS ColumnName, I.Name, I.index_id, I.type, is_unique, ignore_dup_key, is_primary_key, is_unique_constraint, fill_factor, is_padded, is_disabled, allow_row_locks, allow_page_locks, IC.is_descending_key, IC.is_included_column, ISNULL(ST.no_recompute,0) AS NoAutomaticRecomputation "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects OO ON OO.object_id = I.object_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + sql.Append("INNER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.stats AS ST ON ST.stats_id = I.index_id AND ST.object_id = I.object_id "); + sql.Append("WHERE I.type IN (1,2,3) "); + sql.Append("AND is_unique_constraint = 0 AND is_primary_key = 0 "); //AND I.object_id = " + table.Id.ToString(CultureInfo.InvariantCulture) + " "); + sql.Append("AND objectproperty(I.object_id, 'IsMSShipped') <> 1 "); + sql.Append("ORDER BY I.object_id, I.Name, IC.column_id"); + return sql.ToString(); + } + + private static string GetAzure() + { + StringBuilder sql = new StringBuilder(); + sql.Append("SELECT ISNULL(I.filter_definition,'') AS FilterDefinition, OO.type AS ObjectType, IC.key_ordinal, C.user_type_id, I.object_id, '' as FileGroup, C.column_id,C.Name AS ColumnName, I.Name, I.index_id, I.type, is_unique, ignore_dup_key, is_primary_key, is_unique_constraint, fill_factor, is_padded, is_disabled, allow_row_locks, allow_page_locks, IC.is_descending_key, IC.is_included_column, ISNULL(ST.no_recompute,0) AS NoAutomaticRecomputation "); + sql.Append("FROM sys.indexes I "); + sql.Append("INNER JOIN sys.objects OO ON OO.object_id = I.object_id "); + sql.Append("INNER JOIN sys.index_columns IC ON IC.index_id = I.index_id AND IC.object_id = I.object_id "); + //sql.Append("INNER JOIN sys.data_spaces AS dsidx ON dsidx.data_space_id = I.data_space_id "); + sql.Append("INNER JOIN sys.columns C ON C.column_id = IC.column_id AND IC.object_id = C.object_id "); + sql.Append("LEFT JOIN sys.stats AS ST ON ST.stats_id = I.index_id AND ST.object_id = I.object_id "); + sql.Append("WHERE I.type IN (1,2,3) "); + sql.Append("AND is_unique_constraint = 0 AND is_primary_key = 0 "); //AND I.object_id = " + table.Id.ToString(CultureInfo.InvariantCulture) + " "); + sql.Append("AND objectproperty(I.object_id, 'IsMSShipped') <> 1 "); + sql.Append("ORDER BY I.object_id, I.Name, IC.column_id"); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/TableSQLCommand.cs b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/TableSQLCommand.cs new file mode 100644 index 0000000..89db79b --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/TableSQLCommand.cs @@ -0,0 +1,166 @@ +using OpenDBDiff.SqlServer.Schema.Model; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Generates.SQLCommands +{ + internal static class TableSQLCommand + { + #region Table Count + + public static string GetTableCount(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + return GetTableCount2000(); + + default: + return GetTableCount2005(); + } + } + + private static string GetTableCount2000() + { + return "SELECT Count(*) FROM sysobjects SO WHERE type = 'U'"; + } + + private static string GetTableCount2005() + { + return "SELECT Count(*) from sys.tables"; + } + + #endregion Table Count + + #region Table Detail + + public static string GetTableDetail(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + return GetTableDetail2000(); + + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return GetTableDetail2005(); + + case DatabaseInfo.SQLServerVersion.SQLServer2008: + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return GetTableDetail2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetTableDetailAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetTableDetailAzure(); + else + return GetTableDetail2008(); + } + } + + private static string GetTableDetailAzure() + { + var sql = new StringBuilder(); + sql.AppendLine("SELECT DISTINCT 0 AS HasChangeTrackingTrackColumn, 0 AS HasChangeTracking, TTT.lock_escalation_desc, T.type AS ObjectType, C.Name, C.is_filestream, C.is_sparse, S4.Name as OwnerType,C.user_type_id, C.Column_Id AS ID, C.max_length AS Size, C.Precision, C.Scale, ISNULL(C.Collation_Name,'') as Collation, C.Is_nullable AS IsNullable, C.Is_RowGuidcol AS IsRowGuid, C.Is_Computed AS IsComputed, C.Is_Identity AS IsIdentity, COLUMNPROPERTY(T.object_id,C.name,'IsIdNotForRepl') AS IsIdentityRepl,IDENT_SEED('[' + S1.name + '].[' + T.Name + ']') AS IdentSeed, IDENT_INCR('[' + S1.name + '].[' + T.Name + ']') AS IdentIncrement, ISNULL(CC.Definition,'') AS Formula, ISNULL(CC.Is_Persisted,0) AS FormulaPersisted, "); + sql.AppendLine("CASE WHEN ISNULL(DEP.referencing_minor_id,0) = 0 THEN 0 ELSE 1 END AS HasComputedFormula, CASE WHEN ISNULL(IC.column_id,0) = 0 THEN 0 ELSE 1 END AS HasIndex, TY.Name AS Type, '[' + S3.Name + '].' + XSC.Name AS XMLSchema, C.Is_xml_document, TY.is_user_defined, "); + sql.AppendLine("ISNULL(TT.Name,T.Name) AS TableName, T.object_id AS TableId,S1.name AS TableOwner,Text_In_Row_limit, large_value_types_out_of_row,ISNULL(objectproperty(T.object_id, N'TableHasVarDecimalStorageFormat'),0) AS HasVarDecimal,OBJECTPROPERTY(T.OBJECT_ID,'TableHasClustIndex') AS HasClusteredIndex, "); + sql.AppendLine(" '' AS FileGroup, '' AS FileGroupText, '' AS FileGroupStream,ISNULL(DC.object_id,0) AS DefaultId, DC.name AS DefaultName, DC.definition AS DefaultDefinition, C.rule_object_id, C.default_object_id "); + sql.AppendLine("FROM sys.columns C "); + sql.AppendLine("INNER JOIN sys.objects T ON T.object_id = C.object_id "); + sql.AppendLine("INNER JOIN sys.types TY ON TY.user_type_id = C.user_type_id "); + sql.AppendLine("LEFT JOIN sys.indexes IDX ON IDX.object_id = T.object_id and IDX.index_id < 2 "); + //sql.Append("LEFT JOIN sys.data_spaces AS DSIDX ON DSIDX.data_space_id = IDX.data_space_id "); + sql.AppendLine("LEFT JOIN sys.table_types TT ON TT.type_table_object_id = C.object_id "); + sql.AppendLine("LEFT JOIN sys.tables TTT ON TTT.object_id = C.object_id "); + sql.AppendLine("LEFT JOIN sys.schemas S1 ON (S1.schema_id = TTT.schema_id and T.type = 'U') OR (S1.schema_id = TT.schema_id and T.type = 'TT')"); + sql.AppendLine("LEFT JOIN sys.xml_schema_collections XSC ON XSC.xml_collection_id = C.xml_collection_id "); + sql.AppendLine("LEFT JOIN sys.schemas S3 ON S3.schema_id = XSC.schema_id "); + sql.AppendLine("LEFT JOIN sys.schemas S4 ON S4.schema_id = TY.schema_id "); + sql.AppendLine("LEFT JOIN sys.computed_columns CC ON CC.column_id = C.column_Id AND C.object_id = CC.object_id "); + sql.AppendLine("LEFT JOIN sys.sql_expression_dependencies DEP ON DEP.referenced_id = C.object_id AND DEP.referenced_minor_id = C.column_Id AND DEP.referencing_id = C.object_id "); + sql.AppendLine("LEFT JOIN sys.index_columns IC ON IC.object_id = T.object_id AND IC.column_Id = C.column_Id "); + //sql.Append("LEFT JOIN sys.data_spaces AS lob ON lob.data_space_id = TTT.lob_data_space_id "); + //sql.Append("LEFT JOIN sys.data_spaces AS filestr ON filestr.data_space_id = TTT.filestream_data_space_id "); + sql.AppendLine("LEFT JOIN sys.default_constraints DC ON DC.parent_object_id = T.object_id AND parent_column_id = C.Column_Id "); + //sql.Append("LEFT JOIN sys.change_tracking_tables CTT ON CTT.object_id = T.object_id "); + sql.AppendLine("WHERE T.type IN ('U','TT') "); + sql.AppendLine("ORDER BY ISNULL(TT.Name,T.Name),T.object_id,C.column_id"); + return sql.ToString(); + } + + private static string GetTableDetail2008() + { + string sql = ""; + sql += "SELECT DISTINCT (CASE WHEN ISNULL(CTT.is_track_columns_updated_on,0) <> 0 THEN is_track_columns_updated_on ELSE 0 END) AS HasChangeTrackingTrackColumn, (CASE WHEN ISNULL(CTT.object_id,0) <> 0 THEN 1 ELSE 0 END) AS HasChangeTracking, TTT.lock_escalation_desc, T.type AS ObjectType, C.Name, C.is_filestream, C.is_sparse, S4.Name as OwnerType,C.user_type_id, C.Column_Id AS ID, C.max_length AS Size, C.Precision, C.Scale, ISNULL(C.Collation_Name,'') as Collation, C.Is_nullable AS IsNullable, C.Is_RowGuidcol AS IsRowGuid, C.Is_Computed AS IsComputed, C.Is_Identity AS IsIdentity, COLUMNPROPERTY(T.object_id,C.name,'IsIdNotForRepl') AS IsIdentityRepl,IDENT_SEED('[' + S1.name + '].[' + T.Name + ']') AS IdentSeed, IDENT_INCR('[' + S1.name + '].[' + T.Name + ']') AS IdentIncrement, ISNULL(CC.Definition,'') AS Formula, ISNULL(CC.Is_Persisted,0) AS FormulaPersisted, CASE WHEN ISNULL(DEP.column_id,0) = 0 THEN 0 ELSE 1 END AS HasComputedFormula, CASE WHEN ISNULL(IC.column_id,0) = 0 THEN 0 ELSE 1 END AS HasIndex, TY.Name AS Type, '[' + S3.Name + '].' + XSC.Name AS XMLSchema, C.Is_xml_document, TY.is_user_defined, ISNULL(TT.Name,T.Name) AS TableName, T.object_id AS TableId,S1.name AS TableOwner,Text_In_Row_limit, large_value_types_out_of_row,ISNULL(objectproperty(T.object_id, N'TableHasVarDecimalStorageFormat'),0) AS HasVarDecimal,OBJECTPROPERTY(T.OBJECT_ID,'TableHasClustIndex') AS HasClusteredIndex,DSIDX.Name AS FileGroup,ISNULL(lob.Name,'') AS FileGroupText, ISNULL(filestr.Name,'') AS FileGroupStream,ISNULL(DC.object_id,0) AS DefaultId, DC.name AS DefaultName, DC.definition AS DefaultDefinition, C.rule_object_id, C.default_object_id "; + sql += "FROM sys.columns C "; + sql += "INNER JOIN sys.objects T ON T.object_id = C.object_id "; + sql += "INNER JOIN sys.types TY ON TY.user_type_id = C.user_type_id "; + sql += "LEFT JOIN sys.indexes IDX ON IDX.object_id = T.object_id and IDX.index_id < 2 "; + sql += "LEFT JOIN sys.data_spaces AS DSIDX ON DSIDX.data_space_id = IDX.data_space_id "; + sql += "LEFT JOIN sys.table_types TT ON TT.type_table_object_id = C.object_id "; + sql += "LEFT JOIN sys.tables TTT ON TTT.object_id = C.object_id "; + sql += "LEFT JOIN sys.schemas S1 ON (S1.schema_id = TTT.schema_id and T.type = 'U') OR (S1.schema_id = TT.schema_id and T.type = 'TT')"; + sql += "LEFT JOIN sys.xml_schema_collections XSC ON XSC.xml_collection_id = C.xml_collection_id "; + sql += "LEFT JOIN sys.schemas S3 ON S3.schema_id = XSC.schema_id "; + sql += "LEFT JOIN sys.schemas S4 ON S4.schema_id = TY.schema_id "; + sql += "LEFT JOIN sys.computed_columns CC ON CC.column_id = C.column_Id AND C.object_id = CC.object_id "; + sql += "LEFT JOIN sys.sql_dependencies DEP ON DEP.referenced_major_id = C.object_id AND DEP.referenced_minor_id = C.column_Id AND DEP.object_id = C.object_id "; + sql += "LEFT JOIN sys.index_columns IC ON IC.object_id = T.object_id AND IC.column_Id = C.column_Id "; + sql += "LEFT JOIN sys.data_spaces AS lob ON lob.data_space_id = TTT.lob_data_space_id "; + sql += "LEFT JOIN sys.data_spaces AS filestr ON filestr.data_space_id = TTT.filestream_data_space_id "; + sql += "LEFT JOIN sys.default_constraints DC ON DC.parent_object_id = T.object_id AND parent_column_id = C.Column_Id "; + sql += "LEFT JOIN sys.change_tracking_tables CTT ON CTT.object_id = T.object_id "; + sql += "WHERE T.type IN ('U','TT') "; + sql += "ORDER BY ISNULL(TT.Name,T.Name),T.object_id,C.column_id"; + return sql; + } + + private static string GetTableDetail2005() + { + string sql = ""; + sql += "SELECT DISTINCT T.type AS ObjectType, C.Name, S4.Name as OwnerType,"; + sql += "C.user_type_id, C.Column_Id AS ID, C.max_length AS Size, C.Precision, C.Scale, ISNULL(C.Collation_Name,'') as Collation, C.Is_nullable AS IsNullable, C.Is_RowGuidcol AS IsRowGuid, C.Is_Computed AS IsComputed, C.Is_Identity AS IsIdentity, COLUMNPROPERTY(T.object_id,C.name,'IsIdNotForRepl') AS IsIdentityRepl,IDENT_SEED('[' + S1.name + '].[' + T.Name + ']') AS IdentSeed, IDENT_INCR('[' + S1.name + '].[' + T.Name + ']') AS IdentIncrement, ISNULL(CC.Definition,'') AS Formula, ISNULL(CC.Is_Persisted,0) AS FormulaPersisted, CASE WHEN ISNULL(DEP.column_id,0) = 0 THEN 0 ELSE 1 END AS HasComputedFormula, CASE WHEN ISNULL(IC.column_id,0) = 0 THEN 0 ELSE 1 END AS HasIndex, TY.Name AS Type, '[' + S3.Name + '].' + XSC.Name AS XMLSchema, C.Is_xml_document, TY.is_user_defined, "; + sql += "T.Name AS TableName, T.object_id AS TableId,S1.name AS TableOwner,Text_In_Row_limit, large_value_types_out_of_row,ISNULL(objectproperty(T.object_id, N'TableHasVarDecimalStorageFormat'),0) AS HasVarDecimal,OBJECTPROPERTY(T.OBJECT_ID,'TableHasClustIndex') AS HasClusteredIndex,DSIDX.Name AS FileGroup,ISNULL(LOB.Name,'') AS FileGroupText, "; + sql += "ISNULL(DC.object_id,0) AS DefaultId, DC.name AS DefaultName, DC.definition AS DefaultDefinition, C.rule_object_id, C.default_object_id "; + sql += "FROM sys.columns C "; + sql += "INNER JOIN sys.tables T ON T.object_id = C.object_id "; + sql += "INNER JOIN sys.types TY ON TY.user_type_id = C.user_type_id "; + sql += "INNER JOIN sys.schemas S1 ON S1.schema_id = T.schema_id "; + sql += "INNER JOIN sys.indexes IDX ON IDX.object_id = T.object_id and IDX.index_id < 2 "; + sql += "INNER JOIN sys.data_spaces AS DSIDX ON DSIDX.data_space_id = IDX.data_space_id "; + sql += "LEFT JOIN sys.xml_schema_collections XSC ON XSC.xml_collection_id = C.xml_collection_id "; + sql += "LEFT JOIN sys.schemas S3 ON S3.schema_id = XSC.schema_id "; + sql += "LEFT JOIN sys.schemas S4 ON S4.schema_id = TY.schema_id "; + sql += "LEFT JOIN sys.computed_columns CC ON CC.column_id = C.column_Id AND C.object_id = CC.object_id "; + sql += "LEFT JOIN sys.sql_dependencies DEP ON DEP.referenced_major_id = C.object_id AND DEP.referenced_minor_id = C.column_Id AND DEP.object_id = C.object_id "; + sql += "LEFT JOIN sys.index_columns IC ON IC.object_id = T.object_id AND IC.column_Id = C.column_Id "; + sql += "LEFT JOIN sys.data_spaces AS LOB ON LOB.data_space_id = T.lob_data_space_id "; + sql += "LEFT JOIN sys.default_constraints DC ON DC.parent_object_id = T.object_id AND parent_column_id = C.Column_Id "; + sql += "ORDER BY T.Name,T.object_id,C.column_id"; + return sql; + } + + private static string GetTableDetail2000() + { + string sql = ""; + sql += "SELECT SO.name, "; + sql += "SO.id as object_id, "; + sql += "SU.name as Owner, "; + sql += "OBJECTPROPERTY(SO.ID,'TableTextInRowLimit') AS Text_In_Row_limit,"; + sql += "0 AS HasVarDecimal, "; + sql += "CONVERT(bit,0) AS large_value_types_out_of_row, "; + sql += "F.groupname AS FileGroup, "; + sql += "ISNULL(F2.groupname,'') AS FileGroupText, "; + sql += "OBJECTPROPERTY(SO.ID,'TableHasClustIndex') AS HasClusteredIndex "; + sql += "FROM sysobjects SO "; + sql += "inner join sysindexes I ON I.id = SO.id and I.indid < 2 "; + sql += "inner join sysfilegroups f on f.groupid = i.groupid "; + sql += "left join sysindexes I2 ON I2.id = SO.id and I2.indid = 255 "; + sql += "left join sysfilegroups f2 on f2.groupid = i2.groupid "; + sql += "INNER JOIN sysusers SU ON SU.uid = SO.uid WHERE type = 'U' ORDER BY SO.name"; + return sql; + } + + #endregion Table Detail + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/UserDataTypeCommand.cs b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/UserDataTypeCommand.cs new file mode 100644 index 0000000..861f75c --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/UserDataTypeCommand.cs @@ -0,0 +1,58 @@ +using OpenDBDiff.SqlServer.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Generates.SQLCommands +{ + internal static class UserDataTypeCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + return Get2000(); + + case DatabaseInfo.SQLServerVersion.SQLServer2005: + return Get2005(); + + default: + return Get2008(); + } + } + + public static string Get2008() + { + string sql = "SELECT ISNULL(AF.name,'') AS assembly_name, ISNULL(AT.assembly_id,0) AS assembly_id, ISNULL(assembly_class,'') AS assembly_class, T.max_length, S2.name as defaultowner, O2.name as defaultname, S1.name as ruleowner, O.name as rulename, ISNULL(T2.Name,'') AS basetypename, S.Name AS Owner, T.Name, T.is_assembly_type, T.user_type_id AS tid, T.is_nullable, T.precision, T.scale "; + sql += "FROM sys.types T "; + sql += "INNER JOIN sys.schemas S ON S.schema_id = T.schema_id "; + sql += "LEFT JOIN sys.types T2 ON T2.user_type_id = T.system_type_id "; + sql += "LEFT JOIN sys.objects O ON O.type = 'R' and O.object_id = T.rule_object_id "; + sql += "LEFT JOIN sys.schemas S1 ON S1.schema_id = O.schema_id "; + sql += "LEFT JOIN sys.objects O2 ON O2.type = 'D' and O2.object_id = T.default_object_id "; + sql += "LEFT JOIN sys.schemas S2 ON S2.schema_id = O2.schema_id "; + sql += "LEFT JOIN sys.assembly_types AT ON AT.user_type_id = T.user_type_id AND T.is_assembly_type = 1 "; + sql += "LEFT JOIN sys.assemblies AF ON AF.assembly_id = AT.assembly_id "; + sql += "WHERE T.is_user_defined = 1 AND T.is_table_type = 0 ORDER BY T.Name"; + return sql; + } + + public static string Get2005() + { + string sql = "select ISNULL(AF.name,'') AS assembly_name, ISNULL(AT.assembly_id,0) AS assembly_id, ISNULL(assembly_class,'') AS assembly_class, T.max_length, S2.name as defaultowner, O2.name as defaultname, S1.name as ruleowner, O.name as rulename, ISNULL(T2.Name,'') AS basetypename, S.Name AS Owner, T.Name, T.is_assembly_type, T.user_type_id AS tid, T.is_nullable, T.precision, T.scale from sys.types T "; + sql += "INNER JOIN sys.schemas S ON S.schema_id = T.schema_id "; + sql += "LEFT JOIN sys.types T2 ON T2.user_type_id = T.system_type_id "; + sql += "LEFT JOIN sys.objects O ON O.type = 'R' and O.object_id = T.rule_object_id "; + sql += "LEFT JOIN sys.schemas S1 ON S1.schema_id = O.schema_id "; + sql += "LEFT JOIN sys.objects O2 ON O2.type = 'D' and O2.object_id = T.default_object_id "; + sql += "LEFT JOIN sys.schemas S2 ON S2.schema_id = O2.schema_id "; + sql += "LEFT JOIN sys.assembly_types AT ON AT.user_type_id = T.user_type_id AND T.is_assembly_type = 1 "; + sql += "LEFT JOIN sys.assemblies AF ON AF.assembly_id = AT.assembly_id "; + sql += "WHERE T.is_user_defined = 1 ORDER BY T.Name"; + return sql; + } + + public static string Get2000() + { + return ""; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/UserSQLCommand.cs b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/UserSQLCommand.cs new file mode 100644 index 0000000..568f77a --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/UserSQLCommand.cs @@ -0,0 +1,51 @@ +using OpenDBDiff.SqlServer.Schema.Model; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Generates.SQLCommands +{ + internal static class UserSQLCommand + { + public static string Get(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + case DatabaseInfo.SQLServerVersion.SQLServer2005: + case DatabaseInfo.SQLServerVersion.SQLServer2008: + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return Get2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetAzure(); + else + return Get2008(); + } + } + + private static string Get2008() + { + var sql = new StringBuilder(); + sql.AppendLine("SELECT is_fixed_role, type, ISNULL(suser_sname(sid),'') AS Login,Name,principal_id, ISNULL(default_schema_name,'') AS default_schema_name "); + sql.AppendLine("FROM sys.database_principals "); + sql.AppendLine("WHERE type IN ('S','U','A','R') "); + sql.AppendLine("ORDER BY Name"); + return sql.ToString(); + } + + private static string GetAzure() + { + var sql = new StringBuilder(); + //to get LoginName in Azure (asside for the current login) you would have to link to master and query sys.sysusers or sys.sql_users + //the CASE test below will at least get you the Current login + sql.AppendLine("SELECT is_fixed_role, type, CASE WHEN suser_sid()=sid THEN suser_sname() ELSE '' END AS Login,Name,principal_id, ISNULL(default_schema_name,'') AS default_schema_name "); + sql.AppendLine("FROM sys.database_principals "); + sql.AppendLine("WHERE type IN ('S','U','A','R') "); + sql.AppendLine("ORDER BY Name"); + return sql.ToString(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/ViewSQLCommand.cs b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/ViewSQLCommand.cs new file mode 100644 index 0000000..d426405 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/SQLCommands/ViewSQLCommand.cs @@ -0,0 +1,68 @@ +using OpenDBDiff.SqlServer.Schema.Model; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Generates.SQLCommands +{ + internal static class ViewSQLCommand + { + #region View + + public static string GetView(DatabaseInfo.SQLServerVersion version, DatabaseInfo.SQLServerEdition edition) + { + switch (version) + { + case DatabaseInfo.SQLServerVersion.SQLServer2000: + case DatabaseInfo.SQLServerVersion.SQLServer2005: + case DatabaseInfo.SQLServerVersion.SQLServer2008: + case DatabaseInfo.SQLServerVersion.SQLServer2008R2: + return GetViewSql2008(); + + case DatabaseInfo.SQLServerVersion.SQLServerAzure10: + return GetViewSqlAzure(); + + default: + if (edition == DatabaseInfo.SQLServerEdition.Azure) + return GetViewSqlAzure(); + else + return GetViewSql2008(); + } + } + + private static string GetViewSql2008() + { + string sql = ""; + sql += "select distinct ISNULL('[' + S3.Name + '].[' + object_name(D2.object_id) + ']','') AS DependOut, '[' + S2.Name + '].[' + object_name(D.referenced_major_id) + ']' AS TableName, D.referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, P.object_id, S.name as owner, P.name as name from sys.views P "; + sql += "INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "; + sql += "LEFT JOIN sys.sql_dependencies D ON P.object_id = D.object_id "; + sql += "LEFT JOIN sys.objects O ON O.object_id = D.referenced_major_id "; + sql += "LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "; + sql += "LEFT JOIN sys.sql_dependencies D2 ON P.object_id = D2.referenced_major_id "; + sql += "LEFT JOIN sys.objects O2 ON O2.object_id = D2.object_id "; + sql += "LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "; + sql += "ORDER BY P.object_id"; + return sql; + } + + private static string GetViewSqlAzure() + { + var sql = new StringBuilder(); + //Avoid using sql_dependencies. Use sys.sql_expression_dependencies instead. http://msdn.microsoft.com/en-us/library/ms174402.aspx + sql.Append("SELECT DISTINCT ISNULL('[' + S3.Name + '].[' + object_name(D2.referencing_id) + ']','') AS DependOut, "); + sql.Append("'[' + S2.Name + '].[' + object_name(D.referenced_id) + ']' AS TableName, "); + sql.Append("D.referenced_id AS referenced_major_id, OBJECTPROPERTY (P.object_id,'IsSchemaBound') AS IsSchemaBound, "); + sql.Append("P.object_id, S.name as owner, P.name as name "); + sql.Append("FROM sys.views P "); + sql.Append("INNER JOIN sys.schemas S ON S.schema_id = P.schema_id "); + sql.Append("LEFT JOIN sys.sql_expression_dependencies D ON P.object_id = D.referencing_id "); + sql.Append("LEFT JOIN sys.objects O ON O.object_id = D.referenced_id "); + sql.Append("LEFT JOIN sys.schemas S2 ON S2.schema_id = O.schema_id "); + sql.Append("LEFT JOIN sys.sql_expression_dependencies D2 ON P.object_id = D2.referenced_id "); + sql.Append("LEFT JOIN sys.objects O2 ON O2.object_id = D2.referencing_id "); + sql.Append("LEFT JOIN sys.schemas S3 ON S3.schema_id = O2.schema_id "); + sql.Append("ORDER BY P.object_id "); + return sql.ToString(); + } + + #endregion View + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/Util/ByteToHexEncoder.cs b/OpenDBDiff.SqlServer.Schema/Generates/Util/ByteToHexEncoder.cs new file mode 100644 index 0000000..6efc750 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/Util/ByteToHexEncoder.cs @@ -0,0 +1,38 @@ +namespace OpenDBDiff.SqlServer.Schema.Generates.Util +{ + /// + /// This class implements a fast conversion from a byte array to an hex string. + /// + public class ByteToHexEncoder + { + private static readonly uint[] _lookup32 = CreateLookup32(); + + private static uint[] CreateLookup32() + { + var result = new uint[256]; + for (int i = 0; i < 256; i++) + { + var s = i.ToString("X2"); + result[i] = ((uint)s[0]) + ((uint)s[1] << 16); + } + return result; + } + + public static string ByteArrayToHex(byte[] bytes) + { + var result = new char[2 + bytes.Length * 2]; + + result[0] = '0'; + result[1] = 'x'; + + for (int i = 0; i < bytes.Length; i++) + { + var val = _lookup32[bytes[i]]; + result[2 * i + 2] = (char)val; + result[2 * i + 3] = (char)(val >> 16); + } + + return new string(result); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/Util/Constants.cs b/OpenDBDiff.SqlServer.Schema/Generates/Util/Constants.cs new file mode 100644 index 0000000..49dfa91 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/Util/Constants.cs @@ -0,0 +1,28 @@ +namespace OpenDBDiff.SqlServer.Schema.Generates.Util +{ + internal class Constants + { + public const int READING_RULES = 0; + public const int READING_TABLES = 1; + public const int READING_CONSTRAINTS = 2; + public const int READING_UDT = 3; + public const int READING_XMLSCHEMAS = 4; + public const int READING_SCHEMAS = 5; + public const int READING_USER = 6; + public const int READING_PARTITIONFUNCTION = 7; + public const int READING_PARTITIONSCHEME = 8; + public const int READING_FILEGROUPS = 9; + public const int READING_DLLTRIGGERS = 10; + public const int READING_SYNONYMS = 11; + public const int READING_ASSEMBLIES = 12; + public const int READING_PROCEDURES = 13; + public const int READING_VIEWS = 14; + public const int READING_FUNCTIONS = 15; + public const int READING_INDEXES = 16; + public const int READING_TRIGGERS = 17; + public const int READING_TEXTOBJECTS = 18; + public const int READING_EXTENDED_PROPERTIES = 19; + public const int READING_MAX = 20; + + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Generates/Util/ConvertType.cs b/OpenDBDiff.SqlServer.Schema/Generates/Util/ConvertType.cs new file mode 100644 index 0000000..8ca5874 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Generates/Util/ConvertType.cs @@ -0,0 +1,19 @@ +using OpenDBDiff.Abstractions.Schema; + +namespace OpenDBDiff.SqlServer.Schema.Generates.Util +{ + internal static class ConvertType + { + public static ObjectType GetObjectType(string type) + { + if (type.Trim().Equals("V")) return ObjectType.View; + if (type.Trim().Equals("U")) return ObjectType.Table; + if (type.Trim().Equals("FN")) return ObjectType.Function; + if (type.Trim().Equals("TF")) return ObjectType.Function; + if (type.Trim().Equals("IF")) return ObjectType.Function; + if (type.Trim().Equals("P")) return ObjectType.StoredProcedure; + if (type.Trim().Equals("TR")) return ObjectType.Trigger; + return ObjectType.None; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Assembly.cs b/OpenDBDiff.SqlServer.Schema/Model/Assembly.cs new file mode 100644 index 0000000..b121724 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Assembly.cs @@ -0,0 +1,127 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class Assembly : Code + { + public Assembly(ISchemaBase parent) + : base(parent, ObjectType.Assembly, ScriptAction.AddAssembly, ScriptAction.DropAssembly) + { + Files = new SchemaList(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 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 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; } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/AssemblyFile.cs b/OpenDBDiff.SqlServer.Schema/Model/AssemblyFile.cs new file mode 100644 index 0000000..2188b0e --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/AssemblyFile.cs @@ -0,0 +1,68 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/CLRCode.cs b/OpenDBDiff.SqlServer.Schema/Model/CLRCode.cs new file mode 100644 index 0000000..30a0140 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/CLRCode.cs @@ -0,0 +1,31 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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; } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/CLRFunction.cs b/OpenDBDiff.SqlServer.Schema/Model/CLRFunction.cs new file mode 100644 index 0000000..e6efbe0 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/CLRFunction.cs @@ -0,0 +1,57 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class CLRFunction : CLRCode + { + public CLRFunction(ISchemaBase parent) + : base(parent, ObjectType.CLRFunction, ScriptAction.AddFunction, ScriptAction.DropFunction) + { + Parameters = new List(); + ReturnType = new Parameter(); + } + + public List 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/CLRStoredProcedure.cs b/OpenDBDiff.SqlServer.Schema/Model/CLRStoredProcedure.cs new file mode 100644 index 0000000..b8e4bf4 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/CLRStoredProcedure.cs @@ -0,0 +1,48 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class CLRStoredProcedure : CLRCode + { + public CLRStoredProcedure(ISchemaBase parent) + : base(parent, ObjectType.CLRStoredProcedure, ScriptAction.AddStoredProcedure, ScriptAction.DropStoredProcedure) + { + Parameters = new List(); + } + + public List 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/CLRTrigger.cs b/OpenDBDiff.SqlServer.Schema/Model/CLRTrigger.cs new file mode 100644 index 0000000..24e48c2 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/CLRTrigger.cs @@ -0,0 +1,49 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Code.cs b/OpenDBDiff.SqlServer.Schema/Model/Code.cs new file mode 100644 index 0000000..906ad17 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Code.cs @@ -0,0 +1,257 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model.Util; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace OpenDBDiff.SqlServer.Schema.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(); + DependenciesOut = new List(); + 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 ""; + } + + /// + /// Names collection of dependant objects of the object + /// + public List DependenciesOut { get; set; } + + /// + /// Names collection of objects which the object depends on + /// + public List 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 depencyTracker = new Dictionary(); + iCount = DependenciesCountFilter(this.FullName, depencyTracker); + } + return iCount; + } + } + + private int DependenciesCountFilter(string FullName, Dictionary 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; + } + } + + /// + /// Indicates if there are dependant tables on the object which must be rebuild + /// + /// + 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 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; + } + + /// + /// Rebuilds the object and all its dependant objects. + /// + /// + 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; + } + + /// + /// Rebuilds the dependant objects. + /// + /// + 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)); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Column.cs b/OpenDBDiff.SqlServer.Schema/Model/Column.cs new file mode 100644 index 0000000..0f4893f --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Column.cs @@ -0,0 +1,642 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Xml.Serialization; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class Column : SQLServerSchemaBase, IComparable + { + public Column(ISchemaBase parent) + : base(parent, ObjectType.Column) + { + ComputedFormula = ""; + Collation = ""; + this.Default = new Default(this); + this.Rule = new Rule(this); + this.DefaultConstraint = null; + } + + /// + /// Clona el objeto Column en una nueva instancia. + /// + 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; } + + /// + /// Gets or sets a value indicating whether this instance is XML document. + /// + /// + /// true if this instance is XML document; otherwise, false. + /// + public Boolean IsXmlDocument { get; set; } + + /// + /// Gets or sets the XML schema. + /// + /// The XML schema. + public string XmlSchema { get; set; } + + public Boolean IsSparse { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is user defined type. + /// + /// + /// true if this instance is user defined type; otherwise, false. + /// + public Boolean IsUserDefinedType { get; set; } + + public int DataUserTypeId { get; set; } + + /// + /// Gets or sets the column position. + /// + /// The position. + public int Position { get; set; } + + /// + /// Gets or sets the scale (only in numeric or decimal datatypes). + /// + /// The scale. + public int Scale { get; set; } + + /// + /// Gets or sets the precision (only in numeric or decimal datatypes). + /// + /// The precision. + public int Precision { get; set; } + + /// + /// Gets or sets the collation (only in text datatypes). + /// + /// The collation. + public string Collation { get; set; } + + /// + /// Gets or sets a value indicating whether this is nullable. + /// + /// true if nullable; otherwise, false. + public Boolean IsNullable { get; set; } + + /// + /// Gets or sets the size. + /// + /// The size. + public int Size { get; set; } + + /// + /// Gets or sets the type. + /// + /// The type. + public string Type { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is persisted (only in Computed columns). + /// + /// + /// true if this instance is persisted; otherwise, false. + /// + public Boolean IsPersisted { get; set; } + + /// + /// Gets or sets a value indicating whether this instance has index dependencies. + /// + /// + /// true if this instance has index dependencies; otherwise, false. + /// + public Boolean HasIndexDependencies { get; set; } + + /// + /// Gets or sets a value indicating whether this instance has computed dependencies. + /// + /// + /// true if this instance has computed dependencies; otherwise, false. + /// + public Boolean HasComputedDependencies { get; set; } + + /// + /// Gets a value indicating whether this instance has to rebuild only constraint. + /// + /// + /// true if this instance has to rebuild only constraint; otherwise, false. + /// + public Boolean HasToRebuildOnlyConstraint + { + get + { + return (HasIndexDependencies && !HasComputedDependencies && !IsComputed); + } + } + /// + /// Gets a value indicating whether this instance has to rebuild. + /// + /// + /// true if this instance has to rebuild; otherwise, false. + /// + 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")); + } + + /// + /// Gets or sets the computed formula (only in Computed columns). + /// + /// The computed formula. + public string ComputedFormula { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is computed. + /// + /// + /// true if this instance is computed; otherwise, false. + /// + public Boolean IsComputed { get; set; } + + /// + /// Gets a value indicating whether this column is BLOB. + /// + /// true if this column is BLOB; otherwise, false. + 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"); + } + } + /// + /// Gets or sets a value indicating whether this field is identity for replication. + /// + /// + /// true if this field is identity for replication; otherwise, false. + /// + public Boolean IsIdentityForReplication { get; set; } + + /// + /// Gets or sets a value indicating whether this field is identity. + /// + /// + /// true if this field is identity; otherwise, false. + /// + public Boolean IsIdentity { get; set; } + + /// + /// Gets or sets the identity increment (only if the field is Identity). + /// + /// The identity increment. + public int IdentityIncrement { get; set; } + + /// + /// Gets or sets the identity seed (only if the field is Identity). + /// + /// The identity seed. + public long IdentitySeed { get; set; } + + /// + /// Indica si el campo es Row Guid + /// + public Boolean IsRowGuid { get; set; } + + /// + /// Nombre completo del objeto, incluyendo el owner. + /// + public override string FullName + { + get + { + return Parent.FullName + ".[" + Name + "]"; + } + } + + /// + /// Convierte el schema de la tabla en XML. + /// + public string ToXML() + { + /*string xml = ""; + xml += "\n"; + xml += "" + type + ""; + xml += "" + OriginalType + ""; + xml += "" + size.ToString() + ""; + xml += "" + (nullable ? "1":"0") + ""; + xml += "" + precision.ToString() + ""; + xml += "" + scale.ToString() + ""; + if (this.identity) + xml += ""; + if (this.identityForReplication) + xml += ""; + xml += constraints.ToXML(); + xml += "\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)); + } + } + + /// + /// Gets the default force value. + /// + /// The default force 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 ""; + } + } + + + /// + /// Toes the SQL drop. + /// + /// + public override string ToSqlDrop() + { + string sql = "ALTER TABLE " + Parent.FullName + " DROP COLUMN [" + Name + "]\r\nGO\r\n"; + return sql; + } + + /// + /// Toes the SQL add. + /// + /// + 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; + } + /// + /// Devuelve el schema de la columna en formato SQL. + /// + 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 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; + } + + /// + /// Compara solo las propiedades de dos campos relacionadas con los Identity. Si existen + /// diferencias, devuelve falso, caso contrario, true. + /// + 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; + } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/ColumnConstraint.cs b/OpenDBDiff.SqlServer.Schema/Model/ColumnConstraint.cs new file mode 100644 index 0000000..a6ed0bb --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/ColumnConstraint.cs @@ -0,0 +1,173 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + /// + /// Clase de constraints de Columnas (Default Constraint y Check Constraint) + /// + public class ColumnConstraint : SQLServerSchemaBase + { + public ColumnConstraint(Column parent) + : base(parent, ObjectType.Constraint) + { + } + + /// + /// Clona el objeto ColumnConstraint en una nueva instancia. + /// + 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; + } + + /// + /// Indica si la constraint esta deshabilitada. + /// + public Boolean Disabled { get; set; } + + /// + /// Indica si la constraint va a ser usada en replicacion. + /// + public Boolean NotForReplication { get; set; } + + + /// + /// Gets or sets a value indicating whether [with no check]. + /// + /// true if [with no check]; otherwise, false. + public Boolean WithNoCheck { get; set; } + + /// + /// Valor de la constraint. + /// + public string Definition { get; set; } + + /// + /// Indica el tipo de constraint (Default o Check constraint). + /// + public Constraint.ConstraintType Type { get; set; } + + /// + /// Convierte el schema de la constraint en XML. + /// + public string ToXML() + { + string xml = ""; + if (this.Type == Constraint.ConstraintType.Default) + { + xml += "\n"; + } + if (this.Type == Constraint.ConstraintType.Check) + { + xml += "\n"; + } + return xml; + } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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))); + } + } + + /// + /// Devuelve el schema de la constraint en formato SQL. + /// + public override string ToSql() + { + string sql = ""; + if (this.Type == Constraint.ConstraintType.Default) + sql = " CONSTRAINT [" + Name + "] DEFAULT " + Definition; + return sql; + } + + /// + /// Toes the SQL add. + /// + /// + 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 ""; + } + + /// + /// Toes the SQL drop. + /// + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Columns.cs b/OpenDBDiff.SqlServer.Schema/Model/Columns.cs new file mode 100644 index 0000000..9e0620c --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Columns.cs @@ -0,0 +1,114 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Linq; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class Columns : SchemaList where T : ISchemaBase + { + public Columns(T parent) : base(parent) + { + } + + /// + /// Clona el objeto Columns en una nueva instancia. + /// + public new Columns Clone(T parentObject) + { + Columns columns = new Columns(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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Constraint.cs b/OpenDBDiff.SqlServer.Schema/Model/Constraint.cs new file mode 100644 index 0000000..a61c8a3 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Constraint.cs @@ -0,0 +1,376 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Globalization; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class Constraint : SQLServerSchemaBase + { + public enum ConstraintType + { + None = 0, + PrimaryKey = 1, + ForeignKey = 2, + Default = 3, + Unique = 4, + Check = 5 + } + + public Constraint(ISchemaBase parent) + : this(parent, false) + { + } + + public Constraint(ISchemaBase parent, bool hasIndex) + : base(parent, ObjectType.Constraint) + { + this.Columns = new ConstraintColumns(this); + if (hasIndex) + this.Index = new Index(parent); + } + + /// + /// Clona el objeto Column en una nueva instancia. + /// + 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; + } + + /// + /// Informacion sobre le indice asociado al Constraint. + /// + public Index Index { get; set; } + + /// + /// Coleccion de columnas de la constraint. + /// + public ConstraintColumns Columns { get; set; } + + /// + /// Indica si la constraint tiene asociada un indice Clustered. + /// + public Boolean HasClusteredIndex + { + get + { + if (Index != null) + return (Index.Type == Index.IndexTypeEnum.Clustered); + return false; + } + } + + /// + /// Gets or sets a value indicating whether this constraint is disabled. + /// + /// + /// true if this constraint is disabled; otherwise, false. + /// + public Boolean IsDisabled { get; set; } + + /// + /// Gets or sets the on delete cascade (only for FK). + /// + /// The on delete cascade. + public int OnDeleteCascade { get; set; } + + /// + /// Gets or sets the on update cascade (only for FK). + /// + /// The on update cascade. + public int OnUpdateCascade { get; set; } + + /// + /// Valor de la constraint (se usa para los Check Constraint). + /// + public string Definition { get; set; } + + /// + /// Indica si la constraint va a ser usada en replicacion. + /// + public Boolean NotForReplication { get; set; } + + /// + /// Gets or sets a value indicating whether [with no check]. + /// + /// true if [with no check]; otherwise, false. + public Boolean WithNoCheck { get; set; } + + /// + /// Indica el tipo de constraint (PrimaryKey, ForeignKey, Unique o Default). + /// + public ConstraintType Type { get; set; } + + /// + /// ID de la tabla relacionada a la que hace referencia (solo aplica a FK) + /// + public int RelationalTableId { get; set; } + + /// + /// Nombre de la tabla relacionada a la que hace referencia (solo aplica a FK) + /// + public string RelationalTableFullName { get; set; } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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 (Parent.ObjectType != ObjectType.TableType) + sql.Append("CONSTRAINT [" + Name + "] "); + else + sql.Append("\t"); + + if (consType == ConstraintType.PrimaryKey) + sql.Append("PRIMARY KEY"); + else + sql.Append("UNIQUE"); + + if (Index != null) + { + sql.Append(" "); + sql.Append(Index.Type.ToString().ToUpperInvariant()); + } + + sql.Append("\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.AppendLine(); + } + sql.Append("\t)"); + + if (Index != null) + { + 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(); + } + + /// + /// Devuelve el schema de la tabla en formato SQL. + /// + 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.AppendLine(); + sqlReference.AppendLine(); + 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/ConstraintColumn.cs b/OpenDBDiff.SqlServer.Schema/Model/ConstraintColumn.cs new file mode 100644 index 0000000..bdc1e57 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/ConstraintColumn.cs @@ -0,0 +1,90 @@ +using OpenDBDiff.Abstractions.Schema; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class ConstraintColumn : SQLServerSchemaBase, IComparable + { + 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; } + + /// + /// Gets or sets the column key order in the index. + /// + /// The key order. + public int KeyOrder { get; set; } + + /// + /// Gets or sets a value indicating whether this column is included in the index leaf page. + /// + /// + /// true if this column is included; otherwise, false. + /// + public Boolean IsIncluded { get; set; } + + /// + /// Orden de la columna (Ascendente o Descendente). Se usa solo en Primary Keys. + /// + 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); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/ConstraintColumns.cs b/OpenDBDiff.SqlServer.Schema/Model/ConstraintColumns.cs new file mode 100644 index 0000000..da72c60 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/ConstraintColumns.cs @@ -0,0 +1,53 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class ConstraintColumns : SchemaList + { + public ConstraintColumns(Constraint parent) + : base(parent) + { + } + + /// + /// Clona el objeto ColumnConstraints en una nueva instancia. + /// + public ConstraintColumns Clone() + { + ConstraintColumns columns = new ConstraintColumns(this.Parent); + for (int index = 0; index < this.Count; index++) + { + columns.Add(this[index].Clone()); + } + return columns; + } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Database.cs b/OpenDBDiff.SqlServer.Schema/Model/Database.cs new file mode 100644 index 0000000..a8092d8 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Database.cs @@ -0,0 +1,447 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Attributes; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class Database : SQLServerSchemaBase, IDatabase + { + private readonly List _changesOptions; + + public Database() : base(null, ObjectType.Database) + { + AllObjects = new SearchSchemaBase(); + _changesOptions = new List(); + Dependencies = new Dependencies(); + TablesTypes = new SchemaList(this, AllObjects); + UserTypes = new SchemaList(this, AllObjects); + XmlSchemas = new SchemaList(this, AllObjects); + Schemas = new SchemaList(this, AllObjects); + Procedures = new SchemaList(this, AllObjects); + CLRProcedures = new SchemaList(this, AllObjects); + CLRFunctions = new SchemaList(this, AllObjects); + FileGroups = new SchemaList(this); + Rules = new SchemaList(this, AllObjects); + DDLTriggers = new SchemaList(this, AllObjects); + Synonyms = new SchemaList(this, AllObjects); + Assemblies = new SchemaList(this, AllObjects); + Views = new SchemaList(this, AllObjects); + Users = new SchemaList(this, AllObjects); + FullText = new SchemaList(this, AllObjects); + Functions = new SchemaList(this, AllObjects); + PartitionFunctions = new SchemaList(this, AllObjects); + PartitionSchemes = new SchemaList(this, AllObjects); + Roles = new SchemaList(this); + Tables = new SchemaList(this, AllObjects); + Defaults = new SchemaList(this, AllObjects); + ActionMessage = new SqlAction(this); + } + + internal SearchSchemaBase AllObjects { get; private set; } + + [SchemaNode("Full Text Catalog", "FullText")] + public SchemaList FullText { get; private set; } + + [SchemaNode("Table Type", "Table")] + public SchemaList TablesTypes { get; private set; } + + [SchemaNode("Partition Scheme", "PartitionScheme")] + public SchemaList PartitionSchemes { get; private set; } + + [SchemaNode("Partition Functions", "PartitionFunction")] + public SchemaList PartitionFunctions { get; private set; } + + [SchemaNode("Defaults")] + public SchemaList Defaults { get; private set; } + + [SchemaNode("Roles", "Rol")] + public SchemaList Roles { get; private set; } + + [SchemaNode("Functions", "Function", true)] + public SchemaList Functions { get; private set; } + + [SchemaNode("Users", "User")] + public SchemaList Users { get; private set; } + + [SchemaNode("Views", "View", true)] + public SchemaList Views { get; private set; } + + [SchemaNode("Assemblies", "Assembly")] + public SchemaList Assemblies { get; private set; } + + [SchemaNode("Synonyms", "Assembly")] // We don't have an icon for synonyms at the moment. + public SchemaList Synonyms { get; private set; } + + [SchemaNode("DLL Triggers")] + public SchemaList DDLTriggers { get; private set; } + + [SchemaNode("File Groups")] + public SchemaList FileGroups { get; private set; } + + [SchemaNode("Rules")] + public SchemaList Rules { get; private set; } + + [SchemaNode("Stored Procedures", "Procedure", true)] + public SchemaList Procedures { get; private set; } + + [SchemaNode("CLR Stored Procedures", "CLRProcedure", true)] + public SchemaList CLRProcedures { get; private set; } + + [SchemaNode("CLR Functions", "CLRFunction", true)] + public SchemaList CLRFunctions { get; private set; } + + [SchemaNode("Schemas", "Schema")] + public SchemaList Schemas { get; private set; } + + [SchemaNode("XML Schemas", "XMLSchema")] + public SchemaList XmlSchemas { get; private set; } + + [SchemaNode("Tables", "Table", true)] + public SchemaList Tables { get; private set; } + + [SchemaNode("User Types", "UDT")] + public SchemaList 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; + } + + /// + /// Coleccion de dependencias de constraints. + /// + internal Dependencies Dependencies { get; set; } + + private List 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).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 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(); + var constraints = new List(); + + 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 + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/DatabaseInfo.cs b/OpenDBDiff.SqlServer.Schema/Model/DatabaseInfo.cs new file mode 100644 index 0000000..e5a56a0 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/DatabaseInfo.cs @@ -0,0 +1,94 @@ +namespace OpenDBDiff.SqlServer.Schema.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; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Default.cs b/OpenDBDiff.SqlServer.Schema/Model/Default.cs new file mode 100644 index 0000000..c78fddc --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Default.cs @@ -0,0 +1,77 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.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 ""; + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Dependencies.cs b/OpenDBDiff.SqlServer.Schema/Model/Dependencies.cs new file mode 100644 index 0000000..ca2ba38 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Dependencies.cs @@ -0,0 +1,152 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + internal class Dependencies : List + { + 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); + } + + /// + /// Devuelve todos las constraints dependientes de una tabla. + /// + public List FindNotOwner(int tableId, ObjectType type) + { + try + { + List cons = new List(); + 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; + } + } + + + /// + /// Devuelve todos las constraints dependientes de una tabla. + /// + /*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; + }); + }*/ + + /// + /// Devuelve todos las constraints dependientes de una tabla. + /// + public List Find(int tableId) + { + return Find(tableId, 0, 0); + } + + public int DependenciesCount(int objectId, ObjectType type) + { + Dictionary depencyTracker = new Dictionary(); + return DependenciesCount(objectId, type, depencyTracker); + } + + private int DependenciesCount(int tableId, ObjectType type, Dictionary depencyTracker) + { + int count = 0; + bool putItem = false; + int relationalTableId; + List 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; + } + + /// + /// Devuelve todos las constraints dependientes de una tabla y una columna. + /// + public List Find(int tableId, int columnId, int dataTypeId) + { + List cons = new List(); + List real = new List(); + + 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Dependency.cs b/OpenDBDiff.SqlServer.Schema/Model/Dependency.cs new file mode 100644 index 0000000..0d614a3 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Dependency.cs @@ -0,0 +1,25 @@ +using OpenDBDiff.Abstractions.Schema; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + internal class Dependency + { + public string FullName { get; set; } + + public int DataTypeId { get; set; } + + public ObjectType Type { get; set; } + + public int SubObjectId { get; set; } + + /// + /// ID de la tabla a la que hace referencia la constraint. + /// + public int ObjectId { get; set; } + + /// + /// ID de la tabla a la que pertenece la constraint. + /// + public int OwnerTableId { get; set; } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/ExtendedProperty.cs b/OpenDBDiff.SqlServer.Schema/Model/ExtendedProperty.cs new file mode 100644 index 0000000..75a6979 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/ExtendedProperty.cs @@ -0,0 +1,98 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/FileGroup.cs b/OpenDBDiff.SqlServer.Schema/Model/FileGroup.cs new file mode 100644 index 0000000..9b4446a --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/FileGroup.cs @@ -0,0 +1,107 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/FileGroupFile.cs b/OpenDBDiff.SqlServer.Schema/Model/FileGroupFile.cs new file mode 100644 index 0000000..5cadc63 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/FileGroupFile.cs @@ -0,0 +1,112 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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; + } + + /// + /// Compara dos triggers y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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"; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/FileGroupFiles.cs b/OpenDBDiff.SqlServer.Schema/Model/FileGroupFiles.cs new file mode 100644 index 0000000..5c809ac --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/FileGroupFiles.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class FileGroupFiles : List + { + private Hashtable hash = new Hashtable(); + + /// + /// Constructor de la clase. + /// + /// + /// Objeto Database padre. + /// + public FileGroupFiles(FileGroup parent) + { + this.Parent = parent; + } + + /// + /// Clona el objeto FileGroups en una nueva instancia. + /// + 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; + } + + /// + /// Indica si el nombre del FileGroup existe en la coleccion de tablas del objeto. + /// + /// + /// Nombre de la tabla a buscar. + /// + /// + public Boolean Find(string table) + { + return hash.ContainsKey(table); + } + + /// + /// Agrega un objeto columna a la coleccion de columnas. + /// + 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; + } + } + } + } + + /// + /// Devuelve la tabla perteneciente a la coleccion de campos. + /// + 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(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/FullText.cs b/OpenDBDiff.SqlServer.Schema/Model/FullText.cs new file mode 100644 index 0000000..c2662b1 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/FullText.cs @@ -0,0 +1,132 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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 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; + } + + /// + /// Compara dos Synonyms y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/FullTextIndex.cs b/OpenDBDiff.SqlServer.Schema/Model/FullTextIndex.cs new file mode 100644 index 0000000..e4813e1 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/FullTextIndex.cs @@ -0,0 +1,160 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class FullTextIndex : SQLServerSchemaBase + { + public FullTextIndex(ISchemaBase parent) + : base(parent, ObjectType.FullTextIndex) + { + Columns = new List(); + } + + 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 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/FullTextIndexColumn.cs b/OpenDBDiff.SqlServer.Schema/Model/FullTextIndexColumn.cs new file mode 100644 index 0000000..a43f666 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/FullTextIndexColumn.cs @@ -0,0 +1,9 @@ +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class FullTextIndexColumn + { + public string Language { get; set; } + + public string ColumnName { get; set; } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Function.cs b/OpenDBDiff.SqlServer.Schema/Model/Function.cs new file mode 100644 index 0000000..9cee6f4 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Function.cs @@ -0,0 +1,81 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model.Util; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class Function : Code + { + public Function(ISchemaBase parent) + : base(parent, ObjectType.Function, ScriptAction.AddFunction, ScriptAction.DropFunction) + { + + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/ITableType.cs b/OpenDBDiff.SqlServer.Schema/Model/ITableType.cs new file mode 100644 index 0000000..f04fa34 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/ITableType.cs @@ -0,0 +1,13 @@ +using OpenDBDiff.Abstractions.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public interface ITable where T : ISchemaBase + { + Columns Columns { get; } + SchemaList Constraints { get; } + SchemaList Indexes { get; } + ISchemaBase Parent { get; set; } + string Owner { get; set; } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Index.cs b/OpenDBDiff.SqlServer.Schema/Model/Index.cs new file mode 100644 index 0000000..0fb1d02 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Index.cs @@ -0,0 +1,301 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.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 + "]"; + } + } + + /// + /// Compara dos indices y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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.AppendLine("INDEX [" + Name + "] ON " + Parent.FullName + "\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.AppendLine(); + } + 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.AppendLine("\r\n WHERE " + FilterDefintion); + 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.AppendLine("\r\nGO"); + if (IsDisabled) + sql.AppendLine("ALTER INDEX [" + Name + "] ON " + ((Table)Parent).FullName + " DISABLE\r\nGO"); + + 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) + { + var sql = new StringBuilder("DROP INDEX [" + Name + "] ON " + Parent.FullName); + if (!String.IsNullOrEmpty(FileGroupName)) sql.Append(" WITH (MOVE TO [" + FileGroupName + "])"); + sql.AppendLine("\r\nGO"); + return sql.ToString(); + } + + 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/IndexColumn.cs b/OpenDBDiff.SqlServer.Schema/Model/IndexColumn.cs new file mode 100644 index 0000000..72ace0d --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/IndexColumn.cs @@ -0,0 +1,73 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class IndexColumn : SQLServerSchemaBase, IComparable + { + 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);*/ + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/IndexColumns.cs b/OpenDBDiff.SqlServer.Schema/Model/IndexColumns.cs new file mode 100644 index 0000000..96d5e07 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/IndexColumns.cs @@ -0,0 +1,53 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class IndexColumns : SchemaList + { + public IndexColumns(ISchemaBase parent) + : base(parent) + { + } + + /// + /// Clona el objeto ColumnConstraints en una nueva instancia. + /// + public IndexColumns Clone() + { + IndexColumns columns = new IndexColumns(Parent); + for (int index = 0; index < this.Count; index++) + { + columns.Add(this[index].Clone(Parent)); + } + return columns; + } + + /// + /// Compara dos campos y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Interfaces/ICode.cs b/OpenDBDiff.SqlServer.Schema/Model/Interfaces/ICode.cs new file mode 100644 index 0000000..4f34e7f --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Interfaces/ICode.cs @@ -0,0 +1,15 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public interface ICode : ISchemaBase + { + SQLScriptList Rebuild(); + List DependenciesIn { get; set; } + List DependenciesOut { get; set; } + bool IsSchemaBinding { get; set; } + string Text { get; set; } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Interfaces/ISQLServerSchemaBase.cs b/OpenDBDiff.SqlServer.Schema/Model/Interfaces/ISQLServerSchemaBase.cs new file mode 100644 index 0000000..db8181f --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Interfaces/ISQLServerSchemaBase.cs @@ -0,0 +1,9 @@ +using OpenDBDiff.Abstractions.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public interface ISQLServerSchemaBase + { + SchemaList ExtendedProperties { get; } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/ObjectDependency.cs b/OpenDBDiff.SqlServer.Schema/Model/ObjectDependency.cs new file mode 100644 index 0000000..6d739a6 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/ObjectDependency.cs @@ -0,0 +1,32 @@ +using OpenDBDiff.Abstractions.Schema; + +namespace OpenDBDiff.SqlServer.Schema.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)); } + + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Parameter.cs b/OpenDBDiff.SqlServer.Schema/Model/Parameter.cs new file mode 100644 index 0000000..c97535c --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Parameter.cs @@ -0,0 +1,36 @@ +using System.Globalization; + +namespace OpenDBDiff.SqlServer.Schema.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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/PartitionFunction.cs b/OpenDBDiff.SqlServer.Schema/Model/PartitionFunction.cs new file mode 100644 index 0000000..a06b97c --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/PartitionFunction.cs @@ -0,0 +1,215 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.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(); + } + + 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 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 items = Old.Values.Except(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 items2 = this.Values.Except(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(); + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/PartitionScheme.cs b/OpenDBDiff.SqlServer.Schema/Model/PartitionScheme.cs new file mode 100644 index 0000000..90bbb9e --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/PartitionScheme.cs @@ -0,0 +1,75 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class PartitionScheme : SQLServerSchemaBase + { + public PartitionScheme(ISchemaBase parent) + : base(parent, ObjectType.PartitionFunction) + { + FileGroups = new List(); + } + + public List 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Role.cs b/OpenDBDiff.SqlServer.Schema/Model/Role.cs new file mode 100644 index 0000000..682d44a --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Role.cs @@ -0,0 +1,80 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Rule.cs b/OpenDBDiff.SqlServer.Schema/Model/Rule.cs new file mode 100644 index 0000000..fb2a72e --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Rule.cs @@ -0,0 +1,94 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.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 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; + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/SQLServerSchemaBase.cs b/OpenDBDiff.SqlServer.Schema/Model/SQLServerSchemaBase.cs new file mode 100644 index 0000000..9af3914 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/SQLServerSchemaBase.cs @@ -0,0 +1,16 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public abstract class SQLServerSchemaBase : SchemaBase, ISQLServerSchemaBase + { + protected SQLServerSchemaBase(ISchemaBase parent, ObjectType objectType) : base("[", "]", objectType) + { + this.Parent = parent; + ExtendedProperties = new SchemaList(parent); + } + + public SchemaList ExtendedProperties { get; private set; } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Schema.cs b/OpenDBDiff.SqlServer.Schema/Model/Schema.cs new file mode 100644 index 0000000..4aa3987 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Schema.cs @@ -0,0 +1,51 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.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"; + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/StoredProcedure.cs b/OpenDBDiff.SqlServer.Schema/Model/StoredProcedure.cs new file mode 100644 index 0000000..2545301 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/StoredProcedure.cs @@ -0,0 +1,68 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model.Util; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class StoredProcedure : Code + { + public StoredProcedure(ISchemaBase parent) + : base(parent, ObjectType.StoredProcedure, ScriptAction.AddStoredProcedure, ScriptAction.DropStoredProcedure) + { + + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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); + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Synonym.cs b/OpenDBDiff.SqlServer.Schema/Model/Synonym.cs new file mode 100644 index 0000000..b76f142 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Synonym.cs @@ -0,0 +1,77 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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(); + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + + /// + /// Compara dos Synonyms y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Table.cs b/OpenDBDiff.SqlServer.Schema/Model/Table.cs new file mode 100644 index 0000000..feb4e3a --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Table.cs @@ -0,0 +1,733 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Attributes; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class Table : SQLServerSchemaBase, IComparable
, ITable
+ { + private int dependenciesCount; + private List dependencies; + private Boolean? hasFileStream; + + public Table(ISchemaBase parent) + : base(parent, ObjectType.Table) + { + dependenciesCount = -1; + Columns = new Columns
(this); + Constraints = new SchemaList(this, ((Database)parent).AllObjects); + Options = new SchemaList(this); + Triggers = new SchemaList(this, ((Database)parent).AllObjects); + CLRTriggers = new SchemaList(this, ((Database)parent).AllObjects); + Indexes = new SchemaList(this, ((Database)parent).AllObjects); + Partitions = new SchemaList(this, ((Database)parent).AllObjects); + FullTextIndex = new SchemaList(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 Constraints { get; private set; } + + [SchemaNode("Indexes", "Index")] + public SchemaList Indexes { get; private set; } + + [SchemaNode("CLR Triggers")] + public SchemaList CLRTriggers { get; private set; } + + [SchemaNode("Triggers")] + public SchemaList Triggers { get; private set; } + + public SchemaList FullTextIndex { get; private set; } + + public SchemaList Partitions { get; set; } + + public SchemaList Options { get; set; } + + /// + /// Indica si la tabla tiene alguna columna que sea Identity. + /// + 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; + } + } + + /// + /// Indica la cantidad de Constraints dependientes de otra tabla (FK) que tiene + /// la tabla. + /// + public override int DependenciesCount + { + get + { + if (dependenciesCount == -1) + dependenciesCount = ((Database)Parent).Dependencies.DependenciesCount(Id, + ObjectType.Constraint); + return dependenciesCount; + } + } + + #region IComparable
Members + + /// + /// 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. + /// + 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
Members + + #region ITable
Members + + /// + /// Coleccion de campos de la tabla. + /// + [SchemaNode("Columns", "Column")] + public Columns
Columns { get; set; } + + #endregion ITable
Members + + /// + /// Clona el objeto Table en una nueva instancia. + /// + 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); + } + + /// + /// Devuelve el schema de la tabla en formato SQL. + /// + 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; + + var sql = new StringBuilder(); + string sqlPK = ""; + string sqlUC = ""; + string sqlFK = ""; + if (Columns.Any()) + { + sql.AppendLine("CREATE TABLE " + FullName + "\r\n("); + sql.Append(Columns.ToSql()); + if (Constraints.Any()) + { + sql.AppendLine(","); + 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.Append(sqlPK + sqlUC + sqlFK); + sql = new StringBuilder(sql.ToString(0, sql.Length - 3)).AppendLine(); + } + else + { + sql.AppendLine(); + if (!String.IsNullOrEmpty(CompressType)) + sql.AppendLine("WITH (DATA_COMPRESSION = " + CompressType + ")"); + } + sql.Append(")"); + + if (!isAzure10) + { + if (!String.IsNullOrEmpty(FileGroup)) sql.Append(" ON [" + FileGroup + "]"); + + if (!String.IsNullOrEmpty(FileGroupText)) + { + if (HasBlobColumn) + sql.Append(" TEXTIMAGE_ON [" + FileGroupText + "]"); + } + if ((!String.IsNullOrEmpty(FileGroupStream)) && (HasFileStream)) + sql.Append(" FILESTREAM_ON [" + FileGroupStream + "]"); + } + sql.AppendLine(); + sql.AppendLine("GO"); + Constraints.ForEach(item => + { + if (item.Type == Constraint.ConstraintType.Check) + sql.AppendLine(item.ToSqlAdd()); + }); + if (HasChangeTracking) + sql.Append(ToSqlChangeTracking()); + sql.Append(Indexes.ToSql()); + sql.Append(FullTextIndex.ToSql()); + sql.Append(Options.ToSql()); + sql.Append(Triggers.ToSql()); + } + return sql.ToString(); + } + + private string ToSqlChangeTracking() + { + var sql = new StringBuilder(); + if (HasChangeTracking) + { + sql.Append("ALTER TABLE " + FullName + " ENABLE CHANGE_TRACKING"); + if (HasChangeTrackingTrackColumn) + sql.Append(" WITH(TRACK_COLUMNS_UPDATED = ON)"); + } + else + sql.Append("ALTER TABLE " + FullName + " DISABLE CHANGE_TRACKING"); + + return sql.Append("\r\nGO\r\n").ToString(); + } + + 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; + } + */ + + /// + /// Devuelve el schema de diferencias de la tabla en formato SQL. + /// + public override SQLScriptList ToSqlDiff(ICollection 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) + { + var sql = new StringBuilder(); + Constraints.ForEach(item => + { + if (item.Type == Constraint.ConstraintType.ForeignKey) + sql.AppendLine(item.ToSqlAdd()); + }); + listDiff.Add(ToSql(false), dependenciesCount, ScriptAction.AddTable); + listDiff.Add(sql.ToString(), 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() + { + var sql = new StringBuilder(); + 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.AppendLine(ToSQLTemp(tempTable)); + if ((HasIdentityColumn) && (!IsIdentityNew)) + sql.AppendLine("SET IDENTITY_INSERT [" + Owner + "].[" + tempTable + "] ON"); + sql.AppendLine("INSERT INTO [" + Owner + "].[" + tempTable + "] (" + listColumns + ")" + " SELECT " + + listValues + " FROM " + FullName ); + if ((HasIdentityColumn) && (!IsIdentityNew)) + sql.AppendLine("SET IDENTITY_INSERT [" + Owner + "].[" + tempTable + "] OFF\r\nGO\r\n"); + sql.AppendLine("DROP TABLE " + FullName + "\r\nGO"); + + if (HasFileStream) + { + Constraints.ForEach(item => + { + if (item.Type == Constraint.ConstraintType.Unique && + item.Status != ObjectStatus.Drop) + { + sql.AppendLine("EXEC sp_rename N'[" + Owner + "].[Temp_XX_" + item.Name + + "]',N'" + item.Name + "', 'OBJECT'\r\nGO"); + } + }); + } + sql.AppendLine("EXEC sp_rename N'[" + Owner + "].[" + tempTable + "]',N'" + Name + + "', 'OBJECT'\r\nGO\r\n"); + sql.Append(OriginalTable.Options.ToSql()); + } + else + sql = new StringBuilder(); + return sql.ToString(); + } + + 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) + { + var sql = new StringBuilder(); + + // Drop constraints first, to avoid duplicate constraints created in temp table + foreach (var column in Columns.Where(c => !string.IsNullOrWhiteSpace(c.DefaultConstraint?.Name))) + { + sql.Append($"ALTER TABLE {this.FullName} DROP CONSTRAINT [{column.DefaultConstraint.Name}]\r\n"); + } + + if (!string.IsNullOrWhiteSpace(sql.ToString())) + sql.AppendLine(); + + sql.AppendLine("CREATE TABLE [" + Owner + "].[" + TableName + "]\r\n("); + + Columns.Sort(); + + for (int index = 0; index < Columns.Count; index++) + { + if (Columns[index].Status != ObjectStatus.Drop) + { + sql.Append("\t" + Columns[index].ToSql(true)); + if (index != Columns.Count - 1) + sql.Append(","); + sql.AppendLine(); + } + } + if (HasFileStream) + { + sql = new StringBuilder(sql.ToString(0, sql.Length - 2)); + sql.AppendLine(","); + Constraints.ForEach(item => + { + if (item.Type == Constraint.ConstraintType.Unique && + item.Status != ObjectStatus.Drop) + { + item.Name = "Temp_XX_" + item.Name; + sql.AppendLine("\t" + item.ToSql() + ","); + item.SetWasInsertInDiffList(ScriptAction.AddConstraint); + item.Name = item.Name.Substring(8, item.Name.Length - 8); + } + }); + sql = new StringBuilder(sql.ToString(0, sql.Length - 3)).AppendLine(); + } + else + { + sql.AppendLine(); + if (!String.IsNullOrEmpty(CompressType)) + sql.AppendLine("WITH (DATA_COMPRESSION = " + CompressType + ")"); + } + sql.Append(")"); + + if (!String.IsNullOrEmpty(FileGroup)) sql.Append(" ON [" + FileGroup + "]"); + + if (!String.IsNullOrEmpty(FileGroupText) && HasBlobColumn) + sql.Append(" TEXTIMAGE_ON [" + FileGroupText + "]"); + + if (!String.IsNullOrEmpty(FileGroupStream) && HasFileStream) + sql.Append(" FILESTREAM_ON [" + FileGroupStream + "]"); + + sql.AppendLine(); + sql.AppendLine("GO"); + + return sql.ToString(); + } + + private void GenerateDependencies() + { + List myDependencies; + /*Si el estado es AlterRebuildDependeciesStatus, busca las dependencias solamente en las columnas que fueron modificadas*/ + if (Status == ObjectStatus.RebuildDependencies) + { + myDependencies = new List(); + 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(); + 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); + } + } + + /// + /// 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. + /// + 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; + } + + /// + /// 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. + /// + 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; + } + + /// + /// Compara dos tablas y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + + /// + /// Compara dos tablas y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/TableOption.cs b/OpenDBDiff.SqlServer.Schema/Model/TableOption.cs new file mode 100644 index 0000000..0d839c5 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/TableOption.cs @@ -0,0 +1,96 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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) + { + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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; } + + /// + /// Compara dos indices y devuelve true si son iguales, caso contrario, devuelve false. + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/TablePartition.cs b/OpenDBDiff.SqlServer.Schema/Model/TablePartition.cs new file mode 100644 index 0000000..419c9c0 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/TablePartition.cs @@ -0,0 +1,31 @@ +using OpenDBDiff.Abstractions.Schema; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/TableType.cs b/OpenDBDiff.SqlServer.Schema/Model/TableType.cs new file mode 100644 index 0000000..7e74552 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/TableType.cs @@ -0,0 +1,117 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System.Linq; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class TableType : SQLServerSchemaBase, ITable + { + public TableType(ISchemaBase parent) + : base(parent, ObjectType.TableType) + { + Columns = new Columns(this); + Constraints = new SchemaList(this, ((Database)parent).AllObjects); + Indexes = new SchemaList(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 Columns { get; private set; } + + public SchemaList Constraints { get; private set; } + + public SchemaList 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 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; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Trigger.cs b/OpenDBDiff.SqlServer.Schema/Model/Trigger.cs new file mode 100644 index 0000000..2483c35 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Trigger.cs @@ -0,0 +1,97 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class Trigger : Code + { + public Trigger(ISchemaBase parent) + : base(parent, ObjectType.Trigger, ScriptAction.AddTrigger, ScriptAction.DropTrigger) + { + this.Parent = parent; + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/User.cs b/OpenDBDiff.SqlServer.Schema/Model/User.cs new file mode 100644 index 0000000..017470b --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/User.cs @@ -0,0 +1,73 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/UserDataType.cs b/OpenDBDiff.SqlServer.Schema/Model/UserDataType.cs new file mode 100644 index 0000000..1f11a9a --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/UserDataType.cs @@ -0,0 +1,357 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class UserDataType : SQLServerSchemaBase + { + public UserDataType(ISchemaBase parent) + : base(parent, ObjectType.UserDataType) + { + Default = new Default(this); + Rule = new Rule(this); + Dependencies = new List(); + } + + public List 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; } + + /// + /// Cantidad de digitos que permite el campo (solo para campos Numeric). + /// + public int Scale { get; set; } + + /// + /// Cantidad de decimales que permite el campo (solo para campos Numeric). + /// + 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 ""; + } + } + + /// + /// Clona el objeto Column en una nueva instancia. + /// + 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 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 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 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/Util/FormatCode.cs b/OpenDBDiff.SqlServer.Schema/Model/Util/FormatCode.cs new file mode 100644 index 0000000..dc74270 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/Util/FormatCode.cs @@ -0,0 +1,163 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Text.RegularExpressions; +using TSQL; +using TSQL.Tokens; + +namespace OpenDBDiff.SqlServer.Schema.Model.Util +{ + internal static class FormatCode + { + private static readonly Regex RegCreateAlter = new Regex("CREATE", RegexOptions.Compiled); + private static readonly Regex SchemaBindingRegex = new Regex("WITH SCHEMABINDING", RegexOptions.IgnoreCase | RegexOptions.Compiled); + private static readonly char[] TrimCharacters = { ' ', '\r', '\n', '\t' }; + + /// + /// Find the first entry with the full name within a function, store, view, trigger or rule. + /// Ignore comments. + /// + public static SearchItem FindAndNormalizeCreate(ISchemaBase item, string prevText) + { + var result = FindCreate(prevText) ?? throw new InvalidOperationException($"Could not find the CREATE statement for object '{item.Name}'"); + + // normalize the object name for better comparison + var body = prevText.Substring(0, result.TypeEndPosition + 1) + " " + item.FullName + prevText.Substring(result.NameEndPosition + 1); + + return new SearchItem { Body = body, FindPosition = result.CreateBeginPosition }; + } + + public static FindCreateStatementResult FindCreate(string body) + { + var tokenizer = new TSQLTokenizer(body); + + tokenizer.MoveNext(); + + while (tokenizer.Current != null && tokenizer.Current.AsKeyword?.Keyword != TSQLKeywords.CREATE) + { + tokenizer.MoveNext(); + } + + if (tokenizer.Current == null) + // Oops, we reached the end of the file and did not find the CREATE! + return null; + + var createToken = tokenizer.Current.AsKeyword; + + tokenizer.MoveNext(); + + var typeKeyword = tokenizer.Current.AsKeyword; + + tokenizer.MoveNext(); + + // the object owner is optional + var token0 = tokenizer.Current; + tokenizer.MoveNext(); + var token1 = tokenizer.Current; + tokenizer.MoveNext(); + var token2 = tokenizer.Current; + tokenizer.MoveNext(); + + TSQLIdentifier entityNameToken; + if (token1.AsCharacter?.Text == ".") + { + entityNameToken = token2.AsIdentifier; + } + else + { + entityNameToken = token0.AsIdentifier; + } + + return new FindCreateStatementResult + { + CreateBeginPosition = createToken.BeginPosition, + TypeEndPosition = typeKeyword.EndPosition, + NameEndPosition = entityNameToken.EndPosition + }; + } + + public static string FormatAlter(string ObjectType, string body, ISchemaBase item, Boolean quitSchemaBinding) + { + string prevText = null; + try + { + prevText = (string)body.Clone(); + SearchItem sitem = FindAndNormalizeCreate(item, prevText); + + if (!quitSchemaBinding) + return RegCreateAlter.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 = RegCreateAlter.Replace(sitem.Body, "ALTER", 1, sitem.FindPosition); + return SchemaBindingRegex.Replace(text, ""); + } + //return ""; + } + catch + { + return prevText; + } + } + + public static string FormatCreate(string ObjectType, string body, ISchemaBase item) + { + try + { + string prevText = (string)body.Clone(); + prevText = FindAndNormalizeCreate(item, prevText).Body; + if (String.IsNullOrEmpty(prevText)) + prevText = body; + prevText = CleanLast(prevText); + return SmartGO(prevText); + } + catch + { + return SmartGO(CleanLast(body)); + } + } + + /// + /// Clears all unnecessary characters that are after the END statement of the body, and whitespaces at the beginning. + /// + private static string CleanLast(string body) + { + if (string.IsNullOrEmpty(body)) + { + return string.Empty; + } + + return body.TrimStart().TrimEnd(TrimCharacters); + } + + /// + /// Ensure statement ends with a GO statement + /// + private static string SmartGO(string code) + { + string prevText = code; + try + { + if (!prevText.EndsWith("\r\n")) + prevText += "\r\n"; + return prevText + "GO\r\n"; + } + catch + { + return prevText; + } + } + + internal struct SearchItem + { + public string Body; + public int FindPosition; + } + + internal class FindCreateStatementResult + { + public int CreateBeginPosition; + public int NameEndPosition; + public int TypeEndPosition; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/View.cs b/OpenDBDiff.SqlServer.Schema/Model/View.cs new file mode 100644 index 0000000..bd20889 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/View.cs @@ -0,0 +1,124 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Attributes; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model.Util; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class View : Code + { + public View(ISchemaBase parent) + : base(parent, ObjectType.View, ScriptAction.AddView, ScriptAction.DropView) + { + Indexes = new SchemaList(this, ((Database)parent).AllObjects); + Triggers = new SchemaList(this, ((Database)parent).AllObjects); + CLRTriggers = new SchemaList(this, ((Database)parent).AllObjects); + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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 CLRTriggers { get; set; } + + [SchemaNode("Triggers")] + public SchemaList Triggers { get; set; } + + [SchemaNode("Indexes", "Index")] + public SchemaList 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); + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Model/XMLSchema.cs b/OpenDBDiff.SqlServer.Schema/Model/XMLSchema.cs new file mode 100644 index 0000000..ca3ec46 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Model/XMLSchema.cs @@ -0,0 +1,124 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.Model +{ + public class XMLSchema : SQLServerSchemaBase + { + public XMLSchema(ISchemaBase parent) + : base(parent, ObjectType.XMLSchema) + { + this.Dependencies = new List(); + } + + /// + /// Clona el objeto en una nueva instancia. + /// + 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 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; + } + + /// + /// Devuelve el schema de diferencias del Schema en formato SQL. + /// + public override SQLScriptList ToSqlDiff(System.Collections.Generic.ICollection 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; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/OpenDBDiff.SqlServer.Schema.csproj b/OpenDBDiff.SqlServer.Schema/OpenDBDiff.SqlServer.Schema.csproj new file mode 100644 index 0000000..c6a0560 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/OpenDBDiff.SqlServer.Schema.csproj @@ -0,0 +1,276 @@ + + + + + Debug + AnyCPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867} + Library + Properties + OpenDBDiff.SqlServer.Schema + OpenDBDiff.SqlServer.Schema + v4.5.2 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + false + + + + + + + true + + + + + + + + + + ..\packages\TSQL.Parser.1.5.2\lib\net452\TSQL_Parser.dll + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + .editorconfig + + + + + + {406558a0-1b98-4d0e-b8b6-2013700b065a} + OpenDBDiff.Abstractions.Schema + + + + + \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/Options/SqlOption.cs b/OpenDBDiff.SqlServer.Schema/Options/SqlOption.cs new file mode 100644 index 0000000..a29d171 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Options/SqlOption.cs @@ -0,0 +1,66 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Schema.Options +{ + public class SqlOption : IOption + { + public SqlOption() + { + Defaults = new SqlOptionDefault(); + Ignore = new SqlOptionIgnore(true); + Script = new SqlOptionScript(); + Filters = new SqlOptionFilter(); + Comparison = new SqlOptionComparison(); + } + + public SqlOption(Boolean defaultFilter) + { + Defaults = new SqlOptionDefault(); + Ignore = new SqlOptionIgnore(defaultFilter); + Script = new SqlOptionScript(); + Filters = new SqlOptionFilter(); + Comparison = new SqlOptionComparison(); + } + + public SqlOption(IOption option) + { + Defaults = new SqlOptionDefault(option.Defaults); + Ignore = new SqlOptionIgnore(option.Ignore); + Script = new SqlOptionScript(option.Script); + Filters = new SqlOptionFilter(option.Filters); + Comparison = new SqlOptionComparison(option.Comparison); + } + + public SqlOptionComparison Comparison { get; set; } + + public SqlOptionFilter Filters { get; set; } + + /// + /// Gets or sets the option filter. + /// + /// The option filter. + public SqlOptionIgnore Ignore { get; set; } + + /// + /// Gets or sets the option default. + /// + /// The option default. + public SqlOptionDefault Defaults { get; set; } + + public SqlOptionScript Script { get; set; } + + IOptionFilter IOption.Filters { get { return Filters; } } + IOptionsContainer IOption.Defaults { get { return Defaults; } } + IOptionsContainer IOption.Ignore { get { return Ignore; } } + + IOptionsContainer IOption.Script { get { return Script; } } + + IOptionComparison IOption.Comparison { get { return Comparison; } } + + public string Serialize() + { + return this.ToString(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Options/SqlOptionComparison.cs b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionComparison.cs new file mode 100644 index 0000000..8926fa7 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionComparison.cs @@ -0,0 +1,50 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.Options +{ + public class SqlOptionComparison : IOptionComparison + { + + public enum CaseSensityOptions + { + Automatic = 0, + CaseInsensity = 1, + CaseSensity = 2 + } + + public SqlOptionComparison() + { + CaseSensityInCode = CaseSensityOptions.CaseInsensity; + IgnoreWhiteSpacesInCode = false; + } + + public SqlOptionComparison(IOptionComparison comparison) + { + this.ReloadComparisonOnUpdate = comparison.ReloadComparisonOnUpdate; + var options = comparison.GetOptions(); + IgnoreWhiteSpacesInCode = bool.Parse(options["IgnoreWhiteSpacesInCode"]); + CaseSensityInCode = (CaseSensityOptions)Enum.Parse(typeof(CaseSensityOptions), options["CaseSensityInCode"], true); + CaseSensityType = (CaseSensityOptions)Enum.Parse(typeof(CaseSensityOptions), options["CaseSensityType"], true); + } + + public bool IgnoreWhiteSpacesInCode { get; set; } + public bool ReloadComparisonOnUpdate { get; set; } + + + public CaseSensityOptions CaseSensityInCode { get; set; } + + public CaseSensityOptions CaseSensityType { get; set; } + + public IDictionary GetOptions() + { + Dictionary options = new Dictionary(); + options.Add("IgnoreWhiteSpacesInCode", IgnoreWhiteSpacesInCode.ToString()); + options.Add("ReloadComparisonOnUpdate", ReloadComparisonOnUpdate.ToString()); + options.Add("CaseSensityInCode", CaseSensityInCode.ToString()); + options.Add("CaseSensityType", CaseSensityType.ToString()); + return options; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Options/SqlOptionDefault.cs b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionDefault.cs new file mode 100644 index 0000000..868a5fe --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionDefault.cs @@ -0,0 +1,162 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.Options +{ + public class SqlOptionDefault : IOptionsContainer + { + private string defaultIntegerValue = "0"; + private string defaultRealValue = "0.0"; + private string defaultTextValue = "''"; + private string defaultDateValue = "getdate()"; + private string defaultVariantValue = "''"; + private string defaultNTextValue = "N''"; + private string defaultBlobValue = "0x"; + private string defaultUniqueValue = "NEWID()"; + private Boolean useDefaultValueIfExists = true; + private string defaultTime = "00:00:00"; + private string defaultXml = ""; + + public SqlOptionDefault(IOptionsContainer optionsContainer) + { + var options = optionsContainer.GetOptions(); + defaultIntegerValue = options["defaultIntegerValue"]; + defaultRealValue = options["defaultRealValue"]; + defaultTextValue = options["defaultTextValue"]; + defaultDateValue = options["defaultDateValue"]; + defaultVariantValue = options["defaultVariantValue"]; + defaultNTextValue = options["defaultNTextValue"]; + defaultBlobValue = options["defaultBlobValue"]; + defaultUniqueValue = options["defaultUniqueValue"]; + useDefaultValueIfExists = bool.Parse(options["useDefaultValueIfExists"]); + defaultTime = options["defaultTime"]; + defaultXml = options["defaultXml"]; + } + + public SqlOptionDefault() + { + } + + public string DefaultXml + { + get { return defaultXml; } + set { defaultXml = value; } + } + + public string DefaultTime + { + get { return defaultTime; } + set { defaultTime = value; } + } + + public IDictionary GetOptions() + { + Dictionary options = new Dictionary(); + options.Add("defaultIntegerValue", defaultIntegerValue); + options.Add("defaultRealValue", defaultRealValue); + options.Add("defaultTextValue", defaultTextValue); + options.Add("defaultDateValue", defaultDateValue); + options.Add("defaultVariantValue", defaultVariantValue); + options.Add("defaultNTextValue", defaultNTextValue); + options.Add("defaultBlobValue", defaultBlobValue); + options.Add("defaultUniqueValue", defaultUniqueValue); + options.Add("useDefaultValueIfExists", useDefaultValueIfExists.ToString()); + options.Add("defaultTime", defaultTime); + options.Add("defaultXml", defaultXml); + return options; + } + /// + /// Gets or sets a value indicating whether use default value if exists. + /// + /// + /// true if use default value if exists; otherwise, false. + /// + public Boolean UseDefaultValueIfExists + { + get { return useDefaultValueIfExists; } + set { useDefaultValueIfExists = value; } + } + + /// + /// Gets or sets the default unique (uniqueidentifier) values. + /// + /// The default unique value. + public string DefaultUniqueValue + { + get { return defaultUniqueValue; } + set { defaultUniqueValue = value; } + } + + /// + /// Gets or sets the default BLOB (varbinary,image, bynary) values. + /// + /// The default BLOB value. + public string DefaultBlobValue + { + get { return defaultBlobValue; } + set { defaultBlobValue = value; } + } + + /// + /// Gets or sets the default Unicode text (nvarchar,nchar,ntext) values. + /// + /// The default N text value. + public string DefaultNTextValue + { + get { return defaultNTextValue; } + set { defaultNTextValue = value; } + } + + /// + /// Gets or sets the default sql_variant values. + /// + /// The default variant value. + public string DefaultVariantValue + { + get { return defaultVariantValue; } + set { defaultVariantValue = value; } + } + + /// + /// Gets or sets the default date (datetime,smalldatetime) values. + /// + /// The default date value. + public string DefaultDateValue + { + get { return defaultDateValue; } + set { defaultDateValue = value; } + } + + /// + /// Gets or sets the default text (varchar,char,text) values. + /// + /// The default text value. + public string DefaultTextValue + { + get { return defaultTextValue; } + set { defaultTextValue = value; } + } + + /// + /// Gets or sets the default real (decimal,money,numeric,float) value. + /// + /// The default real value. + public string DefaultRealValue + { + get { return defaultRealValue; } + set { defaultRealValue = value; } + } + + /// + /// Gets or sets the default integer (int, smallint, bigint, tinyint, bit) value. + /// + /// The default integer value. + public string DefaultIntegerValue + { + get { return defaultIntegerValue; } + set { defaultIntegerValue = value; } + } + + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Options/SqlOptionFilter.cs b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionFilter.cs new file mode 100644 index 0000000..bf08e52 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionFilter.cs @@ -0,0 +1,65 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenDBDiff.SqlServer.Schema.Options +{ + public class SqlOptionFilter : IOptionFilter + { + public SqlOptionFilter() + { + Items = new List + { + new SqlOptionFilterItem(ObjectType.Table, "dbo.dtproperties"), + new SqlOptionFilterItem(ObjectType.Assembly, "Microsoft.SqlServer.Types"), + new SqlOptionFilterItem(ObjectType.Schema, "db_accessadmin"), + new SqlOptionFilterItem(ObjectType.Schema, "db_backupoperator"), + new SqlOptionFilterItem(ObjectType.Schema, "db_datareader"), + new SqlOptionFilterItem(ObjectType.Schema, "db_datawriter"), + new SqlOptionFilterItem(ObjectType.Schema, "db_ddladmin"), + new SqlOptionFilterItem(ObjectType.Schema, "db_denydatareader"), + new SqlOptionFilterItem(ObjectType.Schema, "db_denydatawriter"), + new SqlOptionFilterItem(ObjectType.Schema, "db_owner"), + new SqlOptionFilterItem(ObjectType.Schema, "db_securityadmin"), + //new SqlOptionFilterItem(ObjectType.Schema, "dbo"), + new SqlOptionFilterItem(ObjectType.Schema, "guest"), + new SqlOptionFilterItem(ObjectType.Schema, "INFORMATION_SCHEMA"), + new SqlOptionFilterItem(ObjectType.Schema, "sys") + }; + } + + public SqlOptionFilter(IOptionFilter optionFilter) + { + Items = new List(); + var options = optionFilter.GetOptions(); + foreach (var pair in options) + { + Items.Add( + new SqlOptionFilterItem( + objectType: (ObjectType)Enum.Parse(typeof(ObjectType), pair.Value, true), + filterPattern: pair.Key + ) + ); + } + } + + public IList Items { get; private set; } + + public IDictionary GetOptions() + { + Dictionary values = new Dictionary(); + for (int i = 0; i < Items.Count; i++) + { + values.Add(Items[i].FilterPattern, Items[i].ObjectType.ToString()); + } + return values; + } + + public bool IsItemIncluded(ISchemaBase item) + { + return !Items.Any(i => i.IsMatch(item)); + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Options/SqlOptionFilterItem.cs b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionFilterItem.cs new file mode 100644 index 0000000..acc0a8c --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionFilterItem.cs @@ -0,0 +1,113 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; + +namespace OpenDBDiff.SqlServer.Schema.Options +{ + public class SqlOptionFilterItem + { + public SqlOptionFilterItem() { } + + public SqlOptionFilterItem(ObjectType objectType, string filterPattern) + { + this.ObjectType = objectType; + this.FilterPattern = filterPattern; + } + + public ObjectType ObjectType { get; set; } + + public string FilterPattern { get; set; } + + public bool IsMatch(ISchemaBase item) + { + if (item.ObjectType.Equals(this.ObjectType) && ValueSatisfiesCriteria(item.Name, this.FilterPattern)) + return true; + else if (this.IsSchemaMatch(item)) + return true; + else + return false; + } + + private bool IsSchemaMatch(ISchemaBase item) + { + if (item.Owner == null) return false; + return this.ObjectType.Equals(ObjectType.Schema) && ValueSatisfiesCriteria(item.Owner, this.FilterPattern); + } + + private static Lazy>> patternReplacements = + new Lazy>>(() => + { + return new Dictionary> + { + // key: the literal string to match + // value: a tuple: first item: the search pattern, second item: the replacement + { @"~~", new Tuple(@"~~", "~") }, + { @"~*", new Tuple(@"~\*", @"\*") }, + { @"~?", new Tuple(@"~\?", @"\?") }, + { @"?", new Tuple(@"\?", ".?") }, + { @"*", new Tuple(@"\*", ".*") } + }; + }); + + private static bool ValueSatisfiesCriteria(string value, string pattern) + { + if (string.IsNullOrWhiteSpace(value) || string.IsNullOrWhiteSpace(pattern)) return false; + + // if criteria is a regular expression, use regex + if (pattern.IndexOfAny(new[] { '*', '?' }) > -1) + { + var regex = Regex.Replace( + pattern, + "(" + string.Join( + "|", + patternReplacements.Value.Values.Select(t => t.Item1)) + + ")", + m => patternReplacements.Value[m.Value].Item2); + regex = $"^{regex}$"; + + return Regex.IsMatch(value, regex, RegexOptions.IgnoreCase); + } + + // straight string comparison + return string.Equals(value, pattern, StringComparison.OrdinalIgnoreCase); + } + + #region Overrides + + public static bool operator ==(SqlOptionFilterItem x, SqlOptionFilterItem y) + { + return Object.Equals(x, y); + } + + public static bool operator !=(SqlOptionFilterItem x, SqlOptionFilterItem y) + { + return !(x == y); + } + + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + SqlOptionFilterItem fi = obj as SqlOptionFilterItem; + if (fi == null) + { + return false; + } + return this.ObjectType.Equals(fi.ObjectType) && this.FilterPattern.Equals(fi.FilterPattern, StringComparison.OrdinalIgnoreCase); + } + + public override int GetHashCode() + { + long hash = 13; + hash = hash + this.ObjectType.GetHashCode() + this.FilterPattern.ToLowerInvariant().GetHashCode(); + return Convert.ToInt32(hash & 0x7fffffff); + } + + #endregion Overrides + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Options/SqlOptionIgnore.cs b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionIgnore.cs new file mode 100644 index 0000000..ab1d933 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionIgnore.cs @@ -0,0 +1,231 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.Options +{ + public class SqlOptionIgnore : IOptionsContainer + { + public SqlOptionIgnore(bool defaultValue) + { + FilterPartitionFunction = true; + FilterPartitionScheme = true; + FilterIndexFilter = true; + FilterIndex = true; + FilterConstraintPK = true; + FilterConstraintFK = true; + FilterConstraintUK = true; + FilterConstraintCheck = true; + FilterIndexFillFactor = true; + FilterIndexIncludeColumns = true; + FilterIndexRowLock = true; + FilterColumnOrder = true; + FilterColumnIdentity = true; + FilterColumnCollation = true; + FilterNotForReplication = true; + FilterUsers = true; + FilterRoles = true; + FilterCLRFunction = true; + FilterCLRTrigger = true; + FilterCLRUDT = true; + FilterCLRStoredProcedure = true; + FilterFullText = true; + FilterFullTextPath = false; + FilterTableLockEscalation = true; + FilterTableChangeTracking = true; + FilterConstraint = defaultValue; + FilterFunction = defaultValue; + FilterStoredProcedure = defaultValue; + FilterView = defaultValue; + FilterTable = defaultValue; + FilterTableOption = defaultValue; + FilterUserDataType = defaultValue; + FilterTrigger = defaultValue; + FilterSchema = defaultValue; + FilterXMLSchema = defaultValue; + FilterTableFileGroup = defaultValue; + FilterExtendedProperties = defaultValue; + FilterDDLTriggers = defaultValue; + FilterSynonyms = defaultValue; + FilterRules = defaultValue; + FilterAssemblies = defaultValue; + } + + public SqlOptionIgnore(IOptionsContainer optionsContainer) + { + var options = optionsContainer.GetOptions(); + FilterPartitionFunction = options["FilterPartitionFunction"]; + FilterPartitionScheme = options["FilterPartitionScheme"]; + FilterIndexFilter = options["FilterIndexFilter"]; + FilterIndex = options["FilterIndex"]; + FilterConstraintPK = options["FilterConstraintPK"]; + FilterConstraintFK = options["FilterConstraintFK"]; + FilterConstraintUK = options["FilterConstraintUK"]; + FilterConstraintCheck = options["FilterConstraintCheck"]; + FilterIndexFillFactor = options["FilterIndexFillFactor"]; + FilterIndexIncludeColumns = options["FilterIndexIncludeColumns"]; + FilterIndexRowLock = options["FilterIndexRowLock"]; + FilterColumnOrder = options["FilterColumnOrder"]; + FilterColumnIdentity = options["FilterColumnIdentity"]; + FilterColumnCollation = options["FilterColumnCollation"]; + FilterNotForReplication = options["FilterNotForReplication"]; + FilterUsers = options["FilterUsers"]; + FilterRoles = options["FilterRoles"]; + FilterCLRFunction = options["FilterCLRFunction"]; + FilterCLRTrigger = options["FilterCLRTrigger"]; + FilterCLRUDT = options["FilterCLRUDT"]; + FilterCLRStoredProcedure = options["FilterCLRStoredProcedure"]; + FilterFullText = options["FilterFullText"]; + FilterFullTextPath = options["FilterFullTextPath"]; + FilterTableLockEscalation = options["FilterTableLockEscalation"]; + FilterTableChangeTracking = options["FilterTableChangeTracking"]; + FilterConstraint = options["FilterConstraint"]; + FilterFunction = options["FilterFunction"]; + FilterStoredProcedure = options["FilterStoredProcedure"]; + FilterView = options["FilterView"]; + FilterTable = options["FilterTable"]; + FilterTableOption = options["FilterTableOption"]; + FilterUserDataType = options["FilterUserDataType"]; + FilterTrigger = options["FilterTrigger"]; + FilterSchema = options["FilterSchema"]; + FilterXMLSchema = options["FilterXMLSchema"]; + FilterTableFileGroup = options["FilterTableFileGroup"]; + FilterExtendedProperties = options["FilterExtendedProperties"]; + FilterDDLTriggers = options["FilterDDLTriggers"]; + FilterSynonyms = options["FilterSynonyms"]; + FilterRules = options["FilterRules"]; + FilterAssemblies = options["FilterAssemblies"]; + + } + + public Boolean FilterTableChangeTracking { get; set; } + + public Boolean FilterTableLockEscalation { get; set; } + + public Boolean FilterFullTextPath { get; set; } + + public Boolean FilterFullText { get; set; } + + public Boolean FilterCLRStoredProcedure { get; set; } + + public Boolean FilterCLRUDT { get; set; } + + public Boolean FilterCLRTrigger { get; set; } + + public Boolean FilterCLRFunction { get; set; } + + public Boolean FilterRoles { get; set; } + + public Boolean FilterUsers { get; set; } + + public Boolean FilterNotForReplication { get; set; } + + public Boolean FilterColumnCollation { get; set; } + + public Boolean FilterColumnIdentity { get; set; } + + public Boolean FilterColumnOrder { get; set; } + + public Boolean FilterIndexRowLock { get; set; } + + public Boolean FilterIndexIncludeColumns { get; set; } + + public Boolean FilterIndexFillFactor { get; set; } + + public Boolean FilterAssemblies { get; set; } + + public Boolean FilterRules { get; set; } + + public Boolean FilterSynonyms { get; set; } + + public Boolean FilterDDLTriggers { get; set; } + + public Boolean FilterExtendedProperties { get; set; } + + public Boolean FilterTableFileGroup { get; set; } + + public Boolean FilterFunction { get; set; } + + public Boolean FilterStoredProcedure { get; set; } + + public Boolean FilterView { get; set; } + + public Boolean FilterTable { get; set; } + + public Boolean FilterTableOption { get; set; } + + public Boolean FilterUserDataType { get; set; } + + public Boolean FilterTrigger { get; set; } + + public Boolean FilterXMLSchema { get; set; } + + public Boolean FilterSchema { get; set; } + + public Boolean FilterConstraint { get; set; } + + public Boolean FilterConstraintCheck { get; set; } + + public Boolean FilterConstraintUK { get; set; } + + public Boolean FilterConstraintFK { get; set; } + + public Boolean FilterConstraintPK { get; set; } + + public Boolean FilterIndex { get; set; } + + public Boolean FilterIndexFilter { get; set; } + + public Boolean FilterPartitionScheme { get; set; } + + public Boolean FilterPartitionFunction { get; set; } + + public IDictionary GetOptions() + { + + Dictionary options = new Dictionary(); + options.Add("FilterPartitionFunction", FilterPartitionFunction); + options.Add("FilterPartitionScheme", FilterPartitionScheme); + options.Add("FilterIndexFilter", FilterIndexFilter); + options.Add("FilterIndex", FilterIndex); + options.Add("FilterConstraintPK", FilterConstraintPK); + options.Add("FilterConstraintFK", FilterConstraintFK); + options.Add("FilterConstraintUK", FilterConstraintUK); + options.Add("FilterConstraintCheck", FilterConstraintCheck); + options.Add("FilterIndexFillFactor", FilterIndexFillFactor); + options.Add("FilterIndexIncludeColumns", FilterIndexIncludeColumns); + options.Add("FilterIndexRowLock", FilterIndexRowLock); + options.Add("FilterColumnOrder", FilterColumnOrder); + options.Add("FilterColumnIdentity", FilterColumnIdentity); + options.Add("FilterColumnCollation", FilterColumnCollation); + options.Add("FilterNotForReplication", FilterNotForReplication); + options.Add("FilterUsers", FilterUsers); + options.Add("FilterRoles", FilterRoles); + options.Add("FilterCLRFunction", FilterCLRFunction); + options.Add("FilterCLRTrigger", FilterCLRTrigger); + options.Add("FilterCLRUDT", FilterCLRUDT); + options.Add("FilterCLRStoredProcedure", FilterCLRStoredProcedure); + options.Add("FilterFullText", FilterFullText); + options.Add("FilterFullTextPath", FilterFullTextPath); + options.Add("FilterTableLockEscalation", FilterTableLockEscalation); + options.Add("FilterTableChangeTracking", FilterTableChangeTracking); + options.Add("FilterConstraint", FilterConstraint); + options.Add("FilterFunction", FilterFunction); + options.Add("FilterStoredProcedure", FilterStoredProcedure); + options.Add("FilterView", FilterView); + options.Add("FilterTable", FilterTable); + options.Add("FilterTableOption", FilterTableOption); + options.Add("FilterUserDataType", FilterUserDataType); + options.Add("FilterTrigger", FilterTrigger); + options.Add("FilterSchema", FilterSchema); + options.Add("FilterXMLSchema", FilterXMLSchema); + options.Add("FilterTableFileGroup", FilterTableFileGroup); + options.Add("FilterExtendedProperties", FilterExtendedProperties); + options.Add("FilterDDLTriggers", FilterDDLTriggers); + options.Add("FilterSynonyms", FilterSynonyms); + options.Add("FilterRules", FilterRules); + options.Add("FilterAssemblies", FilterAssemblies); + return options; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Options/SqlOptionScript.cs b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionScript.cs new file mode 100644 index 0000000..4aec5f0 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Options/SqlOptionScript.cs @@ -0,0 +1,31 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.SqlServer.Schema.Options +{ + public class SqlOptionScript : IOptionsContainer + { + private Boolean alterObjectOnSchemaBinding = true; + + public SqlOptionScript() + { + } + + public SqlOptionScript(IOptionsContainer optionsContainer) + { + AlterObjectOnSchemaBinding = optionsContainer.GetOptions()["AlterObjectOnSchemaBinding"]; + } + + public Boolean AlterObjectOnSchemaBinding + { + get { return alterObjectOnSchemaBinding; } + set { alterObjectOnSchemaBinding = value; } + } + + public IDictionary GetOptions() + { + return new Dictionary() { { "AlterObjectOnSchemaBinding", AlterObjectOnSchemaBinding } }; + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/Properties/AssemblyInfo.cs b/OpenDBDiff.SqlServer.Schema/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a708a22 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.SqlServer.Schema")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.SqlServer.Schema")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("32ac9af6-db93-4354-b69f-6dbc65c70867")] + +[assembly: System.CLSCompliant(true)] + +[assembly:InternalsVisibleTo("OpenDBDiff.Tests")] diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetAssemblies.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetAssemblies.sql new file mode 100644 index 0000000..f7e5530 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetAssemblies.sql @@ -0,0 +1,16 @@ +select DISTINCT '[' + S2.Name + '].[' + AT.Name + ']' as UDTName, +ISNULL('[' + A2.name + ']','') AS Dependency, +ISNULL('[' + S3.Name + '].[' + A3.name + ']','') AS ObjectDependency, +AF.assembly_id, A.clr_name,A.name,S.name AS Owner, A.permission_set_desc, A.is_visible, content +FROM sys.assemblies A +INNER JOIN sys.assembly_files AF ON AF.assembly_id = A.assembly_id +LEFT JOIN sys.assembly_references AR ON A.assembly_id = AR.referenced_assembly_id +LEFT JOIN sys.assemblies A2 ON A2.assembly_id = AR.assembly_id +LEFT JOIN sys.schemas S1 ON S1.schema_id = A2.principal_id +INNER JOIN sys.schemas S ON S.schema_id = A.principal_id +LEFT JOIN sys.assembly_types AT ON AT.assembly_id = A.assembly_id +LEFT JOIN sys.schemas S2 ON S2.schema_id = AT.schema_id +LEFT JOIN sys.assembly_modules AM ON AM.assembly_id = A.assembly_id +LEFT JOIN sys.objects A3 ON A3.object_id = AM.object_id +LEFT JOIN sys.schemas S3 ON S3.schema_id = A3.schema_id +ORDER BY A.name \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetAssemblyFiles.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetAssemblyFiles.sql new file mode 100644 index 0000000..e765057 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetAssemblyFiles.sql @@ -0,0 +1,4 @@ +select '[' + A.Name + ']' AS Name, AF.content AS FileContent, AF.File_Id AS FileId, AF.Name AS FileName +FROM sys.assemblies A +INNER JOIN sys.assembly_files AF ON AF.assembly_id = A.assembly_id +ORDER BY A.Name \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetDDLTriggers.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetDDLTriggers.sql new file mode 100644 index 0000000..1649a92 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetDDLTriggers.sql @@ -0,0 +1,3 @@ +SELECT OBJECT_DEFINITION(T.object_id) AS Text,T.name,is_disabled,is_not_for_replication,is_instead_of_trigger +FROM sys.triggers T +WHERE T.parent_id = 0 AND T.parent_class = 0 \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetDatabaseFile.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetDatabaseFile.sql new file mode 100644 index 0000000..dc3ba8b --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetDatabaseFile.sql @@ -0,0 +1,10 @@ +select file_id, +type, +name, +physical_name, +size, +max_size, +growth, +is_sparse, +is_percent_growth +from sys.database_files WHERE data_space_id = {ID} diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetDefaults.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetDefaults.sql new file mode 100644 index 0000000..5cd113d --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetDefaults.sql @@ -0,0 +1,5 @@ +SELECT obj.object_id, Name, SCHEMA_NAME(obj.schema_id) AS Owner, ISNULL(smobj.definition, ssmobj.definition) AS [Definition] from sys.objects obj +LEFT OUTER JOIN sys.sql_modules AS smobj ON smobj.object_id = obj.object_id +LEFT OUTER JOIN sys.system_sql_modules AS ssmobj ON ssmobj.object_id = obj.object_id +where obj.type='D' +return sql; \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetExtendedProperties.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetExtendedProperties.sql new file mode 100644 index 0000000..d045d2a --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetExtendedProperties.sql @@ -0,0 +1,9 @@ +SELECT DISTINCT T2.Name as ParentName, S1.name AS OwnerType, T.name AS TypeName, O.type, A.name AS AssemblyName, EP.*,S.name as Owner, O.name AS ObjectName, I1.name AS IndexName FROM sys.extended_properties EP +LEFT JOIN sys.objects O ON O.object_id = EP.major_id +LEFT JOIN sys.schemas S ON S.schema_id = O.schema_id +LEFT JOIN sys.assemblies A ON A.assembly_id = EP.major_id +LEFT JOIN sys.types T ON T.user_type_id = EP.major_id +LEFT JOIN sys.schemas S1 ON S1.schema_id = T.schema_id +LEFT JOIN sys.indexes I1 ON I1.index_id = EP.minor_id AND I1.object_id = O.object_ID AND class = 7 +LEFT JOIN sys.tables T2 ON T2.object_id = O.parent_object_id AND class = 1 +ORDER BY major_id \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetFileGroups.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetFileGroups.sql new file mode 100644 index 0000000..1eae46c --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetFileGroups.sql @@ -0,0 +1,7 @@ +SELECT +name, +data_space_id AS [ID], +is_default, +is_read_only, +type +FROM sys.filegroups ORDER BY name \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetForeignKeys.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetForeignKeys.sql new file mode 100644 index 0000000..89b8f1d --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetForeignKeys.sql @@ -0,0 +1,9 @@ +SELECT FK.object_id, C.user_type_id ,FK.parent_object_id,S.Name AS Owner, S2.Name AS ReferenceOwner, C2.Name AS ColumnName, C2.column_id AS ColumnId, C.name AS ColumnRelationalName, C.column_id AS ColumnRelationalId, T.object_id AS TableRelationalId, FK.Parent_object_id AS TableId, T.Name AS TableRelationalName, FK.Name, FK.is_disabled, FK.is_not_for_replication, FK.is_not_trusted, FK.delete_referential_action, FK.update_referential_action +FROM sys.foreign_keys FK +INNER JOIN sys.tables T ON T.object_id = FK.referenced_object_id +INNER JOIN sys.schemas S2 ON S2.schema_id = T.schema_id +INNER JOIN sys.foreign_key_columns FKC ON FKC.constraint_object_id = FK.object_id +INNER JOIN sys.columns C ON C.object_id = FKC.referenced_object_id AND C.column_id = referenced_column_id +INNER JOIN sys.columns C2 ON C2.object_id = FKC.parent_object_id AND C2.column_id = parent_column_id +INNER JOIN sys.schemas S ON S.schema_id = FK.schema_id +ORDER BY FK.parent_object_id, FK.Name, ColumnId \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetFullTextCatalogs.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetFullTextCatalogs.sql new file mode 100644 index 0000000..a9ae1c5 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetFullTextCatalogs.sql @@ -0,0 +1,5 @@ +SELECT S.Name as Owner,F.name AS FileGroupName, fulltext_catalog_id, FC.Name, path, FC.is_default, is_accent_sensitivity_on +FROM + sys.fulltext_catalogs FC + LEFT JOIN sys.filegroups F ON F.data_space_id = FC.data_space_id + INNER JOIN sys.schemas S ON S.schema_id = FC.principal_id \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetParameters.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetParameters.sql new file mode 100644 index 0000000..ec19d01 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetParameters.sql @@ -0,0 +1,4 @@ +select AP.is_output, AP.scale, AP.precision, '[' + SCHEMA_NAME(O.schema_id) + '].['+ O.name + ']' AS ObjectName, AP.name, TT.name AS TypeName, AP.max_length from sys.all_parameters AP +INNER JOIN sys.types TT ON TT.user_type_id = AP.user_type_id +INNER JOIN sys.objects O ON O.object_id = AP.object_id +WHERE type in ('PC', 'FS', 'FT') AND AP.name <> '' ORDER BY O.object_id, AP.parameter_id diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetPartitionFunctions.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetPartitionFunctions.sql new file mode 100644 index 0000000..a8cf2b1 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetPartitionFunctions.sql @@ -0,0 +1,6 @@ +select PRV.value, T.name AS TypeName, PP.max_length, PP.precision, PP.scale, PF.Name, PF.function_id, fanout, boundary_value_on_right AS IsRight +from sys.partition_functions PF +INNER JOIN sys.partition_parameters PP ON PP.function_id = PF.function_id +INNER JOIN sys.types T ON T.system_type_id = PP.system_type_id +INNER JOIN sys.partition_range_values PRV ON PRV.parameter_id = PP.parameter_id and PP.function_id = PRV.function_id +ORDER BY PP.function_id, PRV.parameter_id, boundary_id diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetPartitionSchemes.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetPartitionSchemes.sql new file mode 100644 index 0000000..3cfafd0 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetPartitionSchemes.sql @@ -0,0 +1,6 @@ +select P.data_space_id AS ID, DS.Name AS FileGroupName,P.Name, F.name AS FunctionName +from sys.partition_schemes P +INNER JOIN sys.partition_functions F ON F.function_id = P.function_id +INNER JOIN sys.destination_data_spaces DF ON DF.partition_scheme_id = P.data_space_id +INNER JOIN sys.data_spaces DS ON DS.data_space_id = DF.data_space_id +ORDER BY P.data_space_id, DF.destination_id \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetProcedures.SQLServerAzure10.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetProcedures.SQLServerAzure10.sql new file mode 100644 index 0000000..e6d9d7d --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetProcedures.SQLServerAzure10.sql @@ -0,0 +1,5 @@ +SELECT ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, P.type, AF.name AS assembly_name, AM.assembly_class, AM.assembly_id, AM.assembly_method, P.object_id, S.name as owner, P.name as name +FROM sys.procedures P +INNER JOIN sys.schemas S ON S.schema_id = P.schema_id +,(SELECT null as execute_as_principal_id, null as assembly_class, null as assembly_id, null as assembly_method) AS AM, +(SELECT null AS name) AS AF \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetProcedures.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetProcedures.sql new file mode 100644 index 0000000..957b2ba --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetProcedures.sql @@ -0,0 +1,5 @@ +SELECT ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, P.type, AF.name AS assembly_name, AM.assembly_class, AM.assembly_id, AM.assembly_method, P.object_id, S.name as owner, P.name as name +FROM sys.procedures P +INNER JOIN sys.schemas S ON S.schema_id = P.schema_id +LEFT JOIN sys.assembly_modules AM ON AM.object_id = P.object_id +LEFT JOIN sys.assemblies AF ON AF.assembly_id = AM.assembly_id \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetRules.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetRules.sql new file mode 100644 index 0000000..17aa68c --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetRules.sql @@ -0,0 +1,5 @@ + +select obj.object_id, Name, SCHEMA_NAME(obj.schema_id) AS Owner, ISNULL(smobj.definition, ssmobj.definition) AS [Definition] from sys.objects obj +LEFT OUTER JOIN sys.sql_modules AS smobj ON smobj.object_id = obj.object_id +LEFT OUTER JOIN sys.system_sql_modules AS ssmobj ON ssmobj.object_id = obj.object_id +where obj.type='R' \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSQLColumnsDependencies.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSQLColumnsDependencies.sql new file mode 100644 index 0000000..ea83bb3 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSQLColumnsDependencies.sql @@ -0,0 +1,26 @@ +SELECT TT.type, 0 AS IsComputed, T.user_type_id,'[' + S.Name + '].[' + TT.Name + ']' AS TableName, '[' + S.Name + '].[' + TT.Name + '].[' + C.Name + ']' AS ColumnName,'[' + S2.Name + '].[' + T.Name + ']' AS TypeName FROM sys.types T +INNER JOIN sys.columns C ON C.user_type_id = T.user_type_id +INNER JOIN sys.objects TT ON TT.object_id = C.object_id +INNER JOIN sys.schemas S ON S.schema_id = TT.schema_id +INNER JOIN sys.schemas S2 ON S2.schema_id = T.schema_id +WHERE is_user_defined = 1 +UNION +SELECT TT.type, 1 AS IsComputed, T.user_type_id, '[' + S.Name + '].[' + TT.Name + ']' AS TableName, '[' + S.Name + '].[' + TT.Name + '].[' + C2.Name + ']' AS ColumnName, '[' + S2.Name + '].[' + T.Name + ']' AS TypeName FROM sys.types T +INNER JOIN sys.columns C ON C.user_type_id = T.user_type_id +INNER JOIN sys.sql_dependencies DEP ON DEP.referenced_major_id = C.object_id AND DEP.referenced_minor_id = C.column_Id AND DEP.object_id = C.object_id +INNER JOIN sys.columns C2 ON C2.column_id = DEP.column_id AND C2.object_id = DEP.object_id +INNER JOIN sys.objects TT ON TT.object_id = C2.object_id +INNER JOIN sys.schemas S ON S.schema_id = TT.schema_id +INNER JOIN sys.schemas S2 ON S2.schema_id = T.schema_id +WHERE is_user_defined = 1 + +UNION +SELECT TT.type, 0 AS IsComputed, T.user_type_id,'[' + S.Name + '].[' + TT.Name + ']' AS TableName, '[' + S.Name + '].[' + TT.Name + '].[' + C.Name + ']' AS ColumnName,'[' + S2.Name + '].[' + T.Name + ']' AS TypeName from sys.sql_dependencies DEP +INNER JOIN sys.objects TT ON DEP.object_id = TT.object_id +INNER JOIN sys.schemas S ON S.schema_id = TT.schema_id +INNER JOIN sys.parameters C ON C.object_id = TT.object_id AND C.parameter_id = DEP.referenced_minor_id +INNER JOIN sys.types T ON C.user_type_id = T.user_type_id +INNER JOIN sys.schemas S2 ON S2.schema_id = T.schema_id +WHERE is_user_defined = 1 + +ORDER BY IsComputed DESC,T.user_type_id \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSQLXMLSchema.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSQLXMLSchema.sql new file mode 100644 index 0000000..4f0fa31 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSQLXMLSchema.sql @@ -0,0 +1,8 @@ +SELECT +xsc.name, +xsc.xml_collection_id AS [ID], +sch.name AS Owner, +XML_SCHEMA_NAMESPACE(sch.Name, xsc.name) AS Text +FROM sys.xml_schema_collections AS xsc +INNER JOIN sys.schemas AS sch ON xsc.schema_id = sch.schema_id +WHERE xsc.schema_id <> 4 \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSchemas.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSchemas.sql new file mode 100644 index 0000000..3c80dbe --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSchemas.sql @@ -0,0 +1,3 @@ + +SELECT S1.name,S1.schema_id, S2.name AS Owner FROM sys.schemas S1 +INNER JOIN sys.database_principals S2 ON S2.principal_id = S1.principal_id \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSynonyms.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSynonyms.sql new file mode 100644 index 0000000..fc61d3d --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetSynonyms.sql @@ -0,0 +1 @@ +SELECT SCHEMA_NAME(schema_id) AS Owner,name,object_id,base_object_name from sys.synonyms ORDER BY Name \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetTextObjectsQuery.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetTextObjectsQuery.sql new file mode 100644 index 0000000..6b1360d --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetTextObjectsQuery.sql @@ -0,0 +1,3 @@ +SELECT O.name, O.type, M.object_id, OBJECT_DEFINITION(M.object_id) AS Text FROM sys.sql_modules M +INNER JOIN sys.objects O ON O.object_id = M.object_id +WHERE {FILTER} \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetTriggers.SQLServerAzure10.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetTriggers.SQLServerAzure10.sql new file mode 100644 index 0000000..1e97c0f --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetTriggers.SQLServerAzure10.sql @@ -0,0 +1,11 @@ +SELECT T.object_id, O.type AS ObjectType, ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, AF.name AS assembly_name, AM.assembly_class, AM.assembly_id, AM.assembly_method, T.type, CAST(ISNULL(tei.object_id,0) AS bit) AS IsInsert, CAST(ISNULL(teu.object_id,0) AS bit) AS IsUpdate, CAST(ISNULL(ted.object_id,0) AS bit) AS IsDelete, T.parent_id, S.name AS Owner,T.name,is_disabled,is_not_for_replication,is_instead_of_trigger +FROM sys.triggers T +INNER JOIN sys.objects O ON O.object_id = T.parent_id +INNER JOIN sys.schemas S ON S.schema_id = O.schema_id +LEFT JOIN sys.trigger_events AS tei ON tei.object_id = T.object_id and tei.type=1 +LEFT JOIN sys.trigger_events AS teu ON teu.object_id = T.object_id and teu.type=2 +LEFT JOIN sys.trigger_events AS ted ON ted.object_id = T.object_id and ted.type=3 + +,(SELECT null as execute_as_principal_id, null as assembly_class, null as assembly_id, null as assembly_method) AS AM, +(SELECT null AS name) AS AF +ORDER BY T.parent_id \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetTriggers.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetTriggers.sql new file mode 100644 index 0000000..f07adbe --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetTriggers.sql @@ -0,0 +1,11 @@ +SELECT T.object_id, O.type AS ObjectType, ISNULL(CONVERT(varchar,AM.execute_as_principal_id),'CALLER') as ExecuteAs, AF.name AS assembly_name, AM.assembly_class, AM.assembly_id, AM.assembly_method, T.type, CAST(ISNULL(tei.object_id,0) AS bit) AS IsInsert, CAST(ISNULL(teu.object_id,0) AS bit) AS IsUpdate, CAST(ISNULL(ted.object_id,0) AS bit) AS IsDelete, T.parent_id, S.name AS Owner,T.name,is_disabled,is_not_for_replication,is_instead_of_trigger +FROM sys.triggers T +INNER JOIN sys.objects O ON O.object_id = T.parent_id +INNER JOIN sys.schemas S ON S.schema_id = O.schema_id +LEFT JOIN sys.trigger_events AS tei ON tei.object_id = T.object_id and tei.type=1 +LEFT JOIN sys.trigger_events AS teu ON teu.object_id = T.object_id and teu.type=2 +LEFT JOIN sys.trigger_events AS ted ON ted.object_id = T.object_id and ted.type=3 + +LEFT JOIN sys.assembly_modules AM ON AM.object_id = T.object_id +LEFT JOIN sys.assemblies AF ON AF.assembly_id = AM.assembly_id +ORDER BY T.parent_id \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/GetXMLSchemaCollections.sql b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetXMLSchemaCollections.sql new file mode 100644 index 0000000..b9e592d --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/GetXMLSchemaCollections.sql @@ -0,0 +1,6 @@ +SELECT O.Type, '[' + S1.Name + '].[' + XS.Name +']' AS XMLName, '[' + S.Name + '].[' + O.Name +']' AS TableName, '[' + S.Name + '].[' + O.Name + '].[' + C.Name + ']' AS ColumnName from sys.columns C +INNER JOIN sys.xml_schema_collections XS ON XS.xml_collection_id = C.xml_collection_id +INNER JOIN sys.objects O ON O.object_id = C.object_id +INNER JOIN sys.schemas S ON S.schema_id = O.schema_id +INNER JOIN sys.schemas S1 ON S1.schema_id = XS.schema_id +ORDER BY XS.xml_collection_id \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Schema/SQLQueries/SQLQueryFactory.cs b/OpenDBDiff.SqlServer.Schema/SQLQueries/SQLQueryFactory.cs new file mode 100644 index 0000000..2f2bc14 --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/SQLQueries/SQLQueryFactory.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenDBDiff.SqlServer.Schema.SQLQueries +{ + public static class SQLQueryFactory + { + private static Dictionary queries = new Dictionary(); + + public static string Get(string queryFullName, Model.DatabaseInfo.SQLServerVersion version) + { + return Get($"{queryFullName}.{version}"); + } + + public static string Get(string queryClass) + { + var ns = typeof(SQLQueryFactory).Namespace; + var qualifiedQueryClass = string.Concat(ns, '.', queryClass); + + if (queries.ContainsKey(qualifiedQueryClass)) + { + return queries[qualifiedQueryClass]; + } + else + { + string query = FetchQuery(qualifiedQueryClass); + queries.Add(qualifiedQueryClass, query); + return query; + } + } + + private static string FetchQuery(string queryFullName) + { + string resourceName = queryFullName + ".sql"; + using (System.IO.Stream stream = typeof(SQLQueryFactory).Assembly.GetManifestResourceStream(resourceName)) + { + if (stream == null) throw new InvalidOperationException("The Query " + queryFullName + " cannot be found"); + using (System.IO.StreamReader reader = new System.IO.StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Schema/packages.config b/OpenDBDiff.SqlServer.Schema/packages.config new file mode 100644 index 0000000..2b25d7b --- /dev/null +++ b/OpenDBDiff.SqlServer.Schema/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Ui/Front/AddExclusionPatternForm.Designer.cs b/OpenDBDiff.SqlServer.Ui/Front/AddExclusionPatternForm.Designer.cs new file mode 100644 index 0000000..d213150 --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/AddExclusionPatternForm.Designer.cs @@ -0,0 +1,154 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.SqlServer.Ui +{ + partial class AddExclusionPatternForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label2 = new System.Windows.Forms.Label(); + this.cboObjects = new System.Windows.Forms.ComboBox(); + this.txtFilter = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.ApplyButton = new System.Windows.Forms.Button(); + this.CancelFormButton = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.cboObjects); + this.groupBox1.Controls.Add(this.txtFilter); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.ForeColor = System.Drawing.SystemColors.HotTrack; + this.groupBox1.Location = new System.Drawing.Point(7, 3); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(310, 71); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Filter"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.ForeColor = System.Drawing.SystemColors.ControlText; + this.label2.Location = new System.Drawing.Point(7, 43); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(68, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Object Type:"; + // + // cboObjects + // + this.cboObjects.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.cboObjects.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cboObjects.FormattingEnabled = true; + this.cboObjects.Location = new System.Drawing.Point(82, 40); + this.cboObjects.Name = "cboObjects"; + this.cboObjects.Size = new System.Drawing.Size(223, 21); + this.cboObjects.TabIndex = 2; + // + // txtFilter + // + this.txtFilter.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtFilter.Location = new System.Drawing.Point(82, 13); + this.txtFilter.Name = "txtFilter"; + this.txtFilter.Size = new System.Drawing.Size(222, 20); + this.txtFilter.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.ForeColor = System.Drawing.SystemColors.ControlText; + this.label1.Location = new System.Drawing.Point(6, 16); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(69, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Filter Pattern:"; + // + // ApplyButton + // + this.ApplyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.ApplyButton.Location = new System.Drawing.Point(242, 80); + this.ApplyButton.Name = "ApplyButton"; + this.ApplyButton.Size = new System.Drawing.Size(75, 23); + this.ApplyButton.TabIndex = 1; + this.ApplyButton.Text = "Apply"; + this.ApplyButton.UseVisualStyleBackColor = true; + this.ApplyButton.Click += new System.EventHandler(this.ApplyButton_Click); + // + // CancelFormButton + // + this.CancelFormButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.CancelFormButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.CancelFormButton.Location = new System.Drawing.Point(161, 80); + this.CancelFormButton.Name = "CancelFormButton"; + this.CancelFormButton.Size = new System.Drawing.Size(75, 23); + this.CancelFormButton.TabIndex = 2; + this.CancelFormButton.Text = "Cancel"; + this.CancelFormButton.UseVisualStyleBackColor = true; + this.CancelFormButton.Click += new System.EventHandler(this.CancelFormButton_Click); + // + // AddExclusionPatternForm + // + this.AcceptButton = this.ApplyButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.CancelFormButton; + this.ClientSize = new System.Drawing.Size(324, 107); + this.ControlBox = false; + this.Controls.Add(this.CancelFormButton); + this.Controls.Add(this.ApplyButton); + this.Controls.Add(this.groupBox1); + this.Name = "AddExclusionPatternForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Filters"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private GroupBox groupBox1; + private TextBox txtFilter; + private Label label1; + private ComboBox cboObjects; + private Label label2; + private Button ApplyButton; + private Button CancelFormButton; + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/AddExclusionPatternForm.cs b/OpenDBDiff.SqlServer.Ui/Front/AddExclusionPatternForm.cs new file mode 100644 index 0000000..2bc8a3f --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/AddExclusionPatternForm.cs @@ -0,0 +1,96 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace OpenDBDiff.SqlServer.Ui +{ + public partial class AddExclusionPatternForm : Form + { + private SqlOption sqlOption; + private int indexFilter; + + public AddExclusionPatternForm(SqlOption sqlOption) + : this(sqlOption, -1) + { } + + public AddExclusionPatternForm(SqlOption sqlOption, int Index) + { + InitializeComponent(); + + PopulateObjectTypeDropDownList(); + + this.sqlOption = sqlOption; + indexFilter = Index; + if (indexFilter != -1) + { + txtFilter.Text = sqlOption.Filters.Items[indexFilter].FilterPattern; + cboObjects.SelectedValue = sqlOption.Filters.Items[indexFilter].ObjectType; + } + } + + private string GetEnumDescription(Enum value) + { + FieldInfo fi = value.GetType().GetField(value.ToString()); + + DescriptionAttribute[] attributes = + (DescriptionAttribute[])fi.GetCustomAttributes( + typeof(DescriptionAttribute), + false); + + if (attributes != null && + attributes.Length > 0) + return attributes[0].Description; + else + return value.ToString(); + } + + private void PopulateObjectTypeDropDownList() + { + var data = Enum.GetValues(typeof(ObjectType)).Cast() + .Select(ot => new { ObjectType = ot, Description = GetEnumDescription(ot) }) + .OrderBy(a => a.Description) + .ToList(); + + cboObjects.DataSource = data; + cboObjects.DisplayMember = "Description"; + cboObjects.ValueMember = "ObjectType"; + } + + private void CancelFormButton_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void ApplyButton_Click(object sender, EventArgs e) + { + if (cboObjects.SelectedItem == null) + { + MessageBox.Show(this, "All fields are required.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + var fi = new SqlOptionFilterItem((ObjectType)Enum.Parse(typeof(ObjectType), cboObjects.SelectedValue.ToString(), true), txtFilter.Text); + + if (sqlOption.Filters.Items.Contains(fi)) + { + MessageBox.Show(this, string.Format("The list of name filters already includes an entry for text '{0}' of type '{1}'", fi.FilterPattern, fi.ObjectType.ToString()), "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + if (indexFilter == -1) + sqlOption.Filters.Items.Add(fi); + else + { + sqlOption.Filters.Items[indexFilter].FilterPattern = fi.FilterPattern; + sqlOption.Filters.Items[indexFilter].ObjectType = fi.ObjectType; + } + HandlerHelper.RaiseOnChange(); + + this.Close(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/AddExclusionPatternForm.resx b/OpenDBDiff.SqlServer.Ui/Front/AddExclusionPatternForm.resx new file mode 100644 index 0000000..d58980a --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/AddExclusionPatternForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Ui/Front/HandlerHelper.cs b/OpenDBDiff.SqlServer.Ui/Front/HandlerHelper.cs new file mode 100644 index 0000000..070575e --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/HandlerHelper.cs @@ -0,0 +1,13 @@ +namespace OpenDBDiff.SqlServer.Ui +{ + public static class HandlerHelper + { + public delegate void SaveFilterHandler(); + public static event SaveFilterHandler OnChange; + + public static void RaiseOnChange() + { + OnChange?.Invoke(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/SQLServerComparer.cs b/OpenDBDiff.SqlServer.Ui/Front/SQLServerComparer.cs new file mode 100644 index 0000000..6f0b77c --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/SQLServerComparer.cs @@ -0,0 +1,27 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.Abstractions.Ui; +using OpenDBDiff.SqlServer.Schema.Generates; +using OpenDBDiff.SqlServer.Schema.Model; +using System; + +namespace OpenDBDiff.SqlServer.Ui +{ + public class SQLServerComparer : IDatabaseComparer + { + public IDatabase Compare(IDatabase origin, IDatabase destination) + { + if (origin is Database && destination is Database) + { + return Generate.Compare(origin as Database, destination as Database); + } + else if (!(origin is Database)) + { + throw new NotSupportedException("Origin database type not supported: " + origin.GetType()); + } + else + { + throw new NotSupportedException("Destination database type not supported: " + destination.GetType()); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/SQLServerGenerator.cs b/OpenDBDiff.SqlServer.Ui/Front/SQLServerGenerator.cs new file mode 100644 index 0000000..95033ba --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/SQLServerGenerator.cs @@ -0,0 +1,40 @@ +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.Abstractions.Ui; +using OpenDBDiff.SqlServer.Schema.Generates; +using OpenDBDiff.SqlServer.Schema.Options; + +namespace OpenDBDiff.SqlServer.Ui +{ + public class SQLServerGenerator : IGenerator + { + private readonly Generate Generate; + + public event ProgressEventHandler.ProgressHandler OnProgress; + + public SQLServerGenerator(string connectionString, IOption option) + { + this.Generate = new Generate() + { + ConnectionString = connectionString, + Options = new SqlOption(option) + }; + this.Generate.OnProgress += new ProgressEventHandler.ProgressHandler(args => + { + if (OnProgress != null) + OnProgress.Invoke(args); + }); + + } + + public int GetMaxValue() + { + return Generate.MaxValue; + } + + public IDatabase Process() + { + return this.Generate.Process(); + } + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/SQLServerProjectHandler.cs b/OpenDBDiff.SqlServer.Ui/Front/SQLServerProjectHandler.cs new file mode 100644 index 0000000..282cba8 --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/SQLServerProjectHandler.cs @@ -0,0 +1,151 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.Abstractions.Ui; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace OpenDBDiff.SqlServer.Ui +{ + public class SQLServerProjectHandler : IProjectHandler + { + private SqlServerConnectFront DestinationControl; + private SqlServerConnectFront SourceControl; + private SQLServerGenerator SourceGenerator; + private SQLServerGenerator DestinationGenerator; + + private SqlOption Option; + + public IFront CreateDestinationSelector() + { + this.DestinationControl = new SqlServerConnectFront + { + ServerName = "(local)", + UseWindowsAuthentication = true, + UserName = "sa", + Password = "", + DatabaseName = "" + }; + + this.DestinationControl.Location = new Point(1, 1); + this.DestinationControl.Name = "DestinationControl"; + this.DestinationControl.Anchor = (AnchorStyles)((int)AnchorStyles.Bottom + (int)AnchorStyles.Left + (int)AnchorStyles.Right); + this.DestinationControl.TabIndex = 10; + this.DestinationControl.Text = "Destination database:"; + + return this.DestinationControl; + } + + public IFront CreateSourceSelector() + { + this.SourceControl = new SqlServerConnectFront + { + ServerName = "(local)", + UseWindowsAuthentication = true, + UserName = "sa", + Password = "", + DatabaseName = "" + }; + + SourceControl.Location = new Point(1, 1); + SourceControl.Name = "SourceControl"; + SourceControl.Anchor = (AnchorStyles)((int)AnchorStyles.Bottom + (int)AnchorStyles.Left + (int)AnchorStyles.Right); + SourceControl.TabIndex = 10; + SourceControl.Text = "Source database:"; + + return SourceControl; + } + + public IDatabaseComparer GetDatabaseComparer() + { + return new SQLServerComparer(); + } + + public IGenerator SetDestinationGenerator(string connectionString, IOption options) + { + DestinationGenerator = new SQLServerGenerator(connectionString, options); + return DestinationGenerator; + } + + public IGenerator SetSourceGenerator(string connectionString, IOption options) + { + SourceGenerator = new SQLServerGenerator(connectionString, options); + return SourceGenerator; + } + + public string GetDestinationConnectionString() + { + return DestinationControl.ConnectionString; + } + + public string GetDestinationDatabaseName() + { + return DestinationControl.DatabaseName; + } + + public string GetDestinationServerName() + { + return DestinationControl.ServerName; + } + + public string GetSourceConnectionString() + { + return SourceControl.ConnectionString; + } + + public string GetSourceDatabaseName() + { + return SourceControl.DatabaseName; + } + + public string GetSourceServerName() + { + return SourceControl.ServerName; + } + + public IOption GetDefaultProjectOptions() + { + if (Option == null) + { + Option = new SqlOption(); + } + return Option; + } + + public void SetProjectOptions(IOption option) + { + if (option == null) + { + throw new ArgumentNullException(nameof(option)); + } + else if (!(option is SqlOption)) + { + throw new NotSupportedException($"This project handler only supports {nameof(SqlOption)} options. {option.GetType().Name} not supported"); + } + Option = option as SqlOption; + } + + public OptionControl CreateOptionControl() + { + return new SqlOptionsFront(); + } + + public string GetScriptLanguage() + { + return "mssql"; + } + + public void Unload() + { + this.SourceControl.Dispose(); + this.DestinationControl.Dispose(); + this.SourceControl = null; + this.DestinationControl = null; + } + + public override string ToString() + { + return "SQLServer 2005 or higher"; + } + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/SqlOptionsFront.Designer.cs b/OpenDBDiff.SqlServer.Ui/Front/SqlOptionsFront.Designer.cs new file mode 100644 index 0000000..96f7f00 --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/SqlOptionsFront.Designer.cs @@ -0,0 +1,1576 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.SqlServer.Ui +{ + partial class SqlOptionsFront + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.chkFullTextPath = new System.Windows.Forms.CheckBox(); + this.chkIndexFilter = new System.Windows.Forms.CheckBox(); + this.chkConstraintsCheck = new System.Windows.Forms.CheckBox(); + this.chkConstraintsUK = new System.Windows.Forms.CheckBox(); + this.chkConstraintsFK = new System.Windows.Forms.CheckBox(); + this.chkConstraintsPK = new System.Windows.Forms.CheckBox(); + this.checkBox5 = new System.Windows.Forms.CheckBox(); + this.checkPartitionFunction = new System.Windows.Forms.CheckBox(); + this.checkBox4 = new System.Windows.Forms.CheckBox(); + this.chkCompCLRUDT = new System.Windows.Forms.CheckBox(); + this.chkCompCLRFunctions = new System.Windows.Forms.CheckBox(); + this.chkCompCLRTrigger = new System.Windows.Forms.CheckBox(); + this.chkCompCLRStore = new System.Windows.Forms.CheckBox(); + this.chkIndexRowLock = new System.Windows.Forms.CheckBox(); + this.chkFullText = new System.Windows.Forms.CheckBox(); + this.chkCompRules = new System.Windows.Forms.CheckBox(); + this.chkCompRoles = new System.Windows.Forms.CheckBox(); + this.chkCompUsers = new System.Windows.Forms.CheckBox(); + this.chkIndexIncludeColumns = new System.Windows.Forms.CheckBox(); + this.chkCompTriggersDDL = new System.Windows.Forms.CheckBox(); + this.chkIndexFillFactor = new System.Windows.Forms.CheckBox(); + this.chkTablesColumnOrder = new System.Windows.Forms.CheckBox(); + this.chkCompAssemblys = new System.Windows.Forms.CheckBox(); + this.chkFileGroups = new System.Windows.Forms.CheckBox(); + this.chkTablesColumnIdentity = new System.Windows.Forms.CheckBox(); + this.chkTablesColumnCollation = new System.Windows.Forms.CheckBox(); + this.chkConstraints = new System.Windows.Forms.CheckBox(); + this.chkCompSchemas = new System.Windows.Forms.CheckBox(); + this.chkCompUDT = new System.Windows.Forms.CheckBox(); + this.chkIndex = new System.Windows.Forms.CheckBox(); + this.chkTableOption = new System.Windows.Forms.CheckBox(); + this.chkCompXMLSchemas = new System.Windows.Forms.CheckBox(); + this.chkCompFunciones = new System.Windows.Forms.CheckBox(); + this.chkCompStoredProcedure = new System.Windows.Forms.CheckBox(); + this.chkTables = new System.Windows.Forms.CheckBox(); + this.chkCompTriggers = new System.Windows.Forms.CheckBox(); + this.chkCompVistas = new System.Windows.Forms.CheckBox(); + this.chkCompExtendedProperties = new System.Windows.Forms.CheckBox(); + this.txtXML = new System.Windows.Forms.TextBox(); + this.label10 = new System.Windows.Forms.Label(); + this.txtTime = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); + this.txtVariant = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.txtNText = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.txtBlob = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.txtDate = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.txtText = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.txtDefaultReal = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.txtDefaultInteger = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.gradientPanel6 = new System.Windows.Forms.Panel(); + this.chkIgnoreNotForReplication = new System.Windows.Forms.CheckBox(); + this.gradientPanel5 = new System.Windows.Forms.Panel(); + this.gradientPanel4 = new System.Windows.Forms.Panel(); + this.gradientPanel3 = new System.Windows.Forms.Panel(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + this.gradientPanel2 = new System.Windows.Forms.Panel(); + this.chkTableChangeTracking = new System.Windows.Forms.CheckBox(); + this.chkTableLockEscalation = new System.Windows.Forms.CheckBox(); + this.gradientPanel1 = new System.Windows.Forms.Panel(); + this.label11 = new System.Windows.Forms.Label(); + this.tabPage4 = new System.Windows.Forms.TabPage(); + this.DeleteNameFilterButton = new System.Windows.Forms.Button(); + this.btnAdd = new System.Windows.Forms.Button(); + this.gradientPanel10 = new System.Windows.Forms.Panel(); + this.lstFilters = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.btnApply = new System.Windows.Forms.Button(); + this.gradientPanel9 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.gradientPanel8 = new System.Windows.Forms.Panel(); + this.gradientPanel7 = new System.Windows.Forms.Panel(); + this.label12 = new System.Windows.Forms.Label(); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.optScriptSchemaBindingAlter = new System.Windows.Forms.RadioButton(); + this.optScriptSchemaDrop = new System.Windows.Forms.RadioButton(); + this.gradientPanel16 = new System.Windows.Forms.Panel(); + this.label15 = new System.Windows.Forms.Label(); + this.tabPage5 = new System.Windows.Forms.TabPage(); + this.gradientPanel15 = new System.Windows.Forms.Panel(); + this.chkIgnoreWhiteSpaceInCode = new System.Windows.Forms.CheckBox(); + this.gradientPanel14 = new System.Windows.Forms.Panel(); + this.label14 = new System.Windows.Forms.Label(); + this.gradientPanel13 = new System.Windows.Forms.Panel(); + this.rdoCaseSensityInCode = new System.Windows.Forms.RadioButton(); + this.rdoCaseInsensityInCode = new System.Windows.Forms.RadioButton(); + this.gradientPanel12 = new System.Windows.Forms.Panel(); + this.label13 = new System.Windows.Forms.Label(); + this.gradientPanel11 = new System.Windows.Forms.Panel(); + this.rdoCaseSensitive = new System.Windows.Forms.RadioButton(); + this.rdoCaseAutomatic = new System.Windows.Forms.RadioButton(); + this.rdoCaseInsensitive = new System.Windows.Forms.RadioButton(); + this.chkReloadDB = new System.Windows.Forms.CheckBox(); + this.IncludeSynonymsCheckBox = new System.Windows.Forms.CheckBox(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.gradientPanel6.SuspendLayout(); + this.gradientPanel5.SuspendLayout(); + this.gradientPanel4.SuspendLayout(); + this.gradientPanel3.SuspendLayout(); + this.gradientPanel2.SuspendLayout(); + this.gradientPanel1.SuspendLayout(); + this.tabPage4.SuspendLayout(); + this.gradientPanel10.SuspendLayout(); + this.gradientPanel9.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.gradientPanel8.SuspendLayout(); + this.gradientPanel7.SuspendLayout(); + this.tabPage3.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.gradientPanel16.SuspendLayout(); + this.tabPage5.SuspendLayout(); + this.gradientPanel15.SuspendLayout(); + this.gradientPanel14.SuspendLayout(); + this.gradientPanel13.SuspendLayout(); + this.gradientPanel12.SuspendLayout(); + this.gradientPanel11.SuspendLayout(); + this.SuspendLayout(); + // + // chkFullTextPath + // + this.chkFullTextPath.AutoSize = true; + this.chkFullTextPath.Checked = true; + this.chkFullTextPath.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkFullTextPath.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkFullTextPath.Location = new System.Drawing.Point(28, 44); + this.chkFullTextPath.Name = "chkFullTextPath"; + this.chkFullTextPath.Size = new System.Drawing.Size(85, 17); + this.chkFullTextPath.TabIndex = 36; + this.chkFullTextPath.Text = "Include path"; + this.chkFullTextPath.UseVisualStyleBackColor = true; + // + // chkIndexFilter + // + this.chkIndexFilter.AutoSize = true; + this.chkIndexFilter.Checked = true; + this.chkIndexFilter.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndexFilter.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndexFilter.Location = new System.Drawing.Point(30, 215); + this.chkIndexFilter.Name = "chkIndexFilter"; + this.chkIndexFilter.Size = new System.Drawing.Size(90, 17); + this.chkIndexFilter.TabIndex = 9; + this.chkIndexFilter.Text = "Filter columns"; + this.chkIndexFilter.UseVisualStyleBackColor = true; + // + // chkConstraintsCheck + // + this.chkConstraintsCheck.AutoSize = true; + this.chkConstraintsCheck.Checked = true; + this.chkConstraintsCheck.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraintsCheck.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraintsCheck.Location = new System.Drawing.Point(30, 310); + this.chkConstraintsCheck.Name = "chkConstraintsCheck"; + this.chkConstraintsCheck.Size = new System.Drawing.Size(57, 17); + this.chkConstraintsCheck.TabIndex = 14; + this.chkConstraintsCheck.Text = "Check"; + this.chkConstraintsCheck.UseVisualStyleBackColor = true; + // + // chkConstraintsUK + // + this.chkConstraintsUK.AutoSize = true; + this.chkConstraintsUK.Checked = true; + this.chkConstraintsUK.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraintsUK.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraintsUK.Location = new System.Drawing.Point(30, 291); + this.chkConstraintsUK.Name = "chkConstraintsUK"; + this.chkConstraintsUK.Size = new System.Drawing.Size(80, 17); + this.chkConstraintsUK.TabIndex = 13; + this.chkConstraintsUK.Text = "Unique key"; + this.chkConstraintsUK.UseVisualStyleBackColor = true; + // + // chkConstraintsFK + // + this.chkConstraintsFK.AutoSize = true; + this.chkConstraintsFK.Checked = true; + this.chkConstraintsFK.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraintsFK.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraintsFK.Location = new System.Drawing.Point(30, 272); + this.chkConstraintsFK.Name = "chkConstraintsFK"; + this.chkConstraintsFK.Size = new System.Drawing.Size(81, 17); + this.chkConstraintsFK.TabIndex = 12; + this.chkConstraintsFK.Text = "Foreign key"; + this.chkConstraintsFK.UseVisualStyleBackColor = true; + // + // chkConstraintsPK + // + this.chkConstraintsPK.AutoSize = true; + this.chkConstraintsPK.Checked = true; + this.chkConstraintsPK.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraintsPK.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraintsPK.Location = new System.Drawing.Point(30, 253); + this.chkConstraintsPK.Name = "chkConstraintsPK"; + this.chkConstraintsPK.Size = new System.Drawing.Size(80, 17); + this.chkConstraintsPK.TabIndex = 11; + this.chkConstraintsPK.Text = "Primary key"; + this.chkConstraintsPK.UseVisualStyleBackColor = true; + // + // checkBox5 + // + this.checkBox5.AutoSize = true; + this.checkBox5.Checked = true; + this.checkBox5.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox5.ForeColor = System.Drawing.SystemColors.ControlText; + this.checkBox5.Location = new System.Drawing.Point(13, 75); + this.checkBox5.Name = "checkBox5"; + this.checkBox5.Size = new System.Drawing.Size(109, 17); + this.checkBox5.TabIndex = 27; + this.checkBox5.Text = "Partition schemas"; + this.checkBox5.UseVisualStyleBackColor = true; + // + // checkPartitionFunction + // + this.checkPartitionFunction.AutoSize = true; + this.checkPartitionFunction.Checked = true; + this.checkPartitionFunction.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkPartitionFunction.ForeColor = System.Drawing.SystemColors.ControlText; + this.checkPartitionFunction.Location = new System.Drawing.Point(13, 52); + this.checkPartitionFunction.Name = "checkPartitionFunction"; + this.checkPartitionFunction.Size = new System.Drawing.Size(110, 17); + this.checkPartitionFunction.TabIndex = 26; + this.checkPartitionFunction.Text = "Partition functions"; + this.checkPartitionFunction.UseVisualStyleBackColor = true; + // + // checkBox4 + // + this.checkBox4.AutoSize = true; + this.checkBox4.Checked = true; + this.checkBox4.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox4.ForeColor = System.Drawing.SystemColors.ControlText; + this.checkBox4.Location = new System.Drawing.Point(28, 27); + this.checkBox4.Name = "checkBox4"; + this.checkBox4.Size = new System.Drawing.Size(103, 17); + this.checkBox4.TabIndex = 35; + this.checkBox4.Text = "CLR aggregates"; + this.checkBox4.UseVisualStyleBackColor = true; + // + // chkCompCLRUDT + // + this.chkCompCLRUDT.AutoSize = true; + this.chkCompCLRUDT.Checked = true; + this.chkCompCLRUDT.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompCLRUDT.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompCLRUDT.Location = new System.Drawing.Point(28, 84); + this.chkCompCLRUDT.Name = "chkCompCLRUDT"; + this.chkCompCLRUDT.Size = new System.Drawing.Size(122, 17); + this.chkCompCLRUDT.TabIndex = 34; + this.chkCompCLRUDT.Text = "CLR user data types"; + this.chkCompCLRUDT.UseVisualStyleBackColor = true; + // + // chkCompCLRFunctions + // + this.chkCompCLRFunctions.AutoSize = true; + this.chkCompCLRFunctions.Checked = true; + this.chkCompCLRFunctions.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompCLRFunctions.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompCLRFunctions.Location = new System.Drawing.Point(28, 46); + this.chkCompCLRFunctions.Name = "chkCompCLRFunctions"; + this.chkCompCLRFunctions.Size = new System.Drawing.Size(93, 17); + this.chkCompCLRFunctions.TabIndex = 33; + this.chkCompCLRFunctions.Text = "CLR functions"; + this.chkCompCLRFunctions.UseVisualStyleBackColor = true; + // + // chkCompCLRTrigger + // + this.chkCompCLRTrigger.AutoSize = true; + this.chkCompCLRTrigger.Checked = true; + this.chkCompCLRTrigger.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompCLRTrigger.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompCLRTrigger.Location = new System.Drawing.Point(28, 103); + this.chkCompCLRTrigger.Name = "chkCompCLRTrigger"; + this.chkCompCLRTrigger.Size = new System.Drawing.Size(84, 17); + this.chkCompCLRTrigger.TabIndex = 32; + this.chkCompCLRTrigger.Text = "CLR triggers"; + this.chkCompCLRTrigger.UseVisualStyleBackColor = true; + // + // chkCompCLRStore + // + this.chkCompCLRStore.AutoSize = true; + this.chkCompCLRStore.Checked = true; + this.chkCompCLRStore.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompCLRStore.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompCLRStore.Location = new System.Drawing.Point(28, 65); + this.chkCompCLRStore.Name = "chkCompCLRStore"; + this.chkCompCLRStore.Size = new System.Drawing.Size(135, 17); + this.chkCompCLRStore.TabIndex = 31; + this.chkCompCLRStore.Text = "CLR stored procedures"; + this.chkCompCLRStore.UseVisualStyleBackColor = true; + // + // chkIndexRowLock + // + this.chkIndexRowLock.AutoSize = true; + this.chkIndexRowLock.Checked = true; + this.chkIndexRowLock.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndexRowLock.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndexRowLock.Location = new System.Drawing.Point(30, 158); + this.chkIndexRowLock.Name = "chkIndexRowLock"; + this.chkIndexRowLock.Size = new System.Drawing.Size(76, 17); + this.chkIndexRowLock.TabIndex = 6; + this.chkIndexRowLock.Text = "Row locks"; + this.chkIndexRowLock.UseVisualStyleBackColor = true; + // + // chkFullText + // + this.chkFullText.AutoSize = true; + this.chkFullText.Checked = true; + this.chkFullText.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkFullText.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkFullText.Location = new System.Drawing.Point(10, 25); + this.chkFullText.Name = "chkFullText"; + this.chkFullText.Size = new System.Drawing.Size(62, 17); + this.chkFullText.TabIndex = 29; + this.chkFullText.Text = "Full text"; + this.chkFullText.UseVisualStyleBackColor = true; + this.chkFullText.CheckedChanged += new System.EventHandler(this.chkFullText_CheckedChanged); + // + // chkCompRules + // + this.chkCompRules.AutoSize = true; + this.chkCompRules.Checked = true; + this.chkCompRules.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompRules.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompRules.Location = new System.Drawing.Point(13, 98); + this.chkCompRules.Name = "chkCompRules"; + this.chkCompRules.Size = new System.Drawing.Size(53, 17); + this.chkCompRules.TabIndex = 22; + this.chkCompRules.Text = "Rules"; + this.chkCompRules.UseVisualStyleBackColor = true; + // + // chkCompRoles + // + this.chkCompRoles.AutoSize = true; + this.chkCompRoles.Checked = true; + this.chkCompRoles.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompRoles.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompRoles.Location = new System.Drawing.Point(10, 82); + this.chkCompRoles.Name = "chkCompRoles"; + this.chkCompRoles.Size = new System.Drawing.Size(53, 17); + this.chkCompRoles.TabIndex = 28; + this.chkCompRoles.Text = "Roles"; + this.chkCompRoles.UseVisualStyleBackColor = true; + // + // chkCompUsers + // + this.chkCompUsers.AutoSize = true; + this.chkCompUsers.Checked = true; + this.chkCompUsers.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompUsers.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompUsers.Location = new System.Drawing.Point(10, 63); + this.chkCompUsers.Name = "chkCompUsers"; + this.chkCompUsers.Size = new System.Drawing.Size(53, 17); + this.chkCompUsers.TabIndex = 23; + this.chkCompUsers.Text = "Users"; + this.chkCompUsers.UseVisualStyleBackColor = true; + // + // chkIndexIncludeColumns + // + this.chkIndexIncludeColumns.AutoSize = true; + this.chkIndexIncludeColumns.Checked = true; + this.chkIndexIncludeColumns.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndexIncludeColumns.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndexIncludeColumns.Location = new System.Drawing.Point(30, 196); + this.chkIndexIncludeColumns.Name = "chkIndexIncludeColumns"; + this.chkIndexIncludeColumns.Size = new System.Drawing.Size(103, 17); + this.chkIndexIncludeColumns.TabIndex = 8; + this.chkIndexIncludeColumns.Text = "Include columns"; + this.chkIndexIncludeColumns.UseVisualStyleBackColor = true; + // + // chkCompTriggersDDL + // + this.chkCompTriggersDDL.AutoSize = true; + this.chkCompTriggersDDL.Checked = true; + this.chkCompTriggersDDL.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompTriggersDDL.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompTriggersDDL.Location = new System.Drawing.Point(13, 6); + this.chkCompTriggersDDL.Name = "chkCompTriggersDDL"; + this.chkCompTriggersDDL.Size = new System.Drawing.Size(85, 17); + this.chkCompTriggersDDL.TabIndex = 19; + this.chkCompTriggersDDL.Text = "DDL triggers"; + this.chkCompTriggersDDL.UseVisualStyleBackColor = true; + // + // chkIndexFillFactor + // + this.chkIndexFillFactor.AutoSize = true; + this.chkIndexFillFactor.Checked = true; + this.chkIndexFillFactor.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndexFillFactor.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndexFillFactor.Location = new System.Drawing.Point(30, 177); + this.chkIndexFillFactor.Name = "chkIndexFillFactor"; + this.chkIndexFillFactor.Size = new System.Drawing.Size(68, 17); + this.chkIndexFillFactor.TabIndex = 7; + this.chkIndexFillFactor.Text = "Fill factor"; + this.chkIndexFillFactor.UseVisualStyleBackColor = true; + // + // chkTablesColumnOrder + // + this.chkTablesColumnOrder.AutoSize = true; + this.chkTablesColumnOrder.Checked = true; + this.chkTablesColumnOrder.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTablesColumnOrder.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTablesColumnOrder.Location = new System.Drawing.Point(30, 44); + this.chkTablesColumnOrder.Name = "chkTablesColumnOrder"; + this.chkTablesColumnOrder.Size = new System.Drawing.Size(88, 17); + this.chkTablesColumnOrder.TabIndex = 3; + this.chkTablesColumnOrder.Text = "Column order"; + this.chkTablesColumnOrder.UseVisualStyleBackColor = true; + // + // chkCompAssemblys + // + this.chkCompAssemblys.AutoSize = true; + this.chkCompAssemblys.Checked = true; + this.chkCompAssemblys.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompAssemblys.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.chkCompAssemblys.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompAssemblys.Location = new System.Drawing.Point(10, 8); + this.chkCompAssemblys.Name = "chkCompAssemblys"; + this.chkCompAssemblys.Size = new System.Drawing.Size(88, 17); + this.chkCompAssemblys.TabIndex = 30; + this.chkCompAssemblys.Text = "Assemblies"; + this.chkCompAssemblys.UseVisualStyleBackColor = true; + this.chkCompAssemblys.CheckedChanged += new System.EventHandler(this.chkCompAssemblys_CheckedChanged); + // + // chkFileGroups + // + this.chkFileGroups.AutoSize = true; + this.chkFileGroups.Checked = true; + this.chkFileGroups.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkFileGroups.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkFileGroups.Location = new System.Drawing.Point(10, 6); + this.chkFileGroups.Name = "chkFileGroups"; + this.chkFileGroups.Size = new System.Drawing.Size(77, 17); + this.chkFileGroups.TabIndex = 25; + this.chkFileGroups.Text = "File groups"; + this.chkFileGroups.UseVisualStyleBackColor = true; + // + // chkTablesColumnIdentity + // + this.chkTablesColumnIdentity.AutoSize = true; + this.chkTablesColumnIdentity.Checked = true; + this.chkTablesColumnIdentity.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTablesColumnIdentity.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTablesColumnIdentity.Location = new System.Drawing.Point(30, 63); + this.chkTablesColumnIdentity.Name = "chkTablesColumnIdentity"; + this.chkTablesColumnIdentity.Size = new System.Drawing.Size(97, 17); + this.chkTablesColumnIdentity.TabIndex = 2; + this.chkTablesColumnIdentity.Text = "Identity options"; + this.chkTablesColumnIdentity.UseVisualStyleBackColor = true; + // + // chkTablesColumnCollation + // + this.chkTablesColumnCollation.AutoSize = true; + this.chkTablesColumnCollation.Checked = true; + this.chkTablesColumnCollation.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTablesColumnCollation.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTablesColumnCollation.Location = new System.Drawing.Point(30, 25); + this.chkTablesColumnCollation.Name = "chkTablesColumnCollation"; + this.chkTablesColumnCollation.Size = new System.Drawing.Size(103, 17); + this.chkTablesColumnCollation.TabIndex = 1; + this.chkTablesColumnCollation.Text = "Column collation"; + this.chkTablesColumnCollation.UseVisualStyleBackColor = true; + // + // chkConstraints + // + this.chkConstraints.AutoSize = true; + this.chkConstraints.Checked = true; + this.chkConstraints.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkConstraints.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.chkConstraints.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkConstraints.Location = new System.Drawing.Point(10, 234); + this.chkConstraints.Name = "chkConstraints"; + this.chkConstraints.Size = new System.Drawing.Size(89, 17); + this.chkConstraints.TabIndex = 10; + this.chkConstraints.Text = "Constraints"; + this.chkConstraints.UseVisualStyleBackColor = true; + this.chkConstraints.CheckedChanged += new System.EventHandler(this.chkConstraints_CheckedChanged); + // + // chkCompSchemas + // + this.chkCompSchemas.AutoSize = true; + this.chkCompSchemas.Checked = true; + this.chkCompSchemas.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompSchemas.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompSchemas.Location = new System.Drawing.Point(10, 101); + this.chkCompSchemas.Name = "chkCompSchemas"; + this.chkCompSchemas.Size = new System.Drawing.Size(70, 17); + this.chkCompSchemas.TabIndex = 24; + this.chkCompSchemas.Text = "Schemas"; + this.chkCompSchemas.UseVisualStyleBackColor = true; + // + // chkCompUDT + // + this.chkCompUDT.AutoSize = true; + this.chkCompUDT.Checked = true; + this.chkCompUDT.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompUDT.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompUDT.Location = new System.Drawing.Point(13, 190); + this.chkCompUDT.Name = "chkCompUDT"; + this.chkCompUDT.Size = new System.Drawing.Size(100, 17); + this.chkCompUDT.TabIndex = 20; + this.chkCompUDT.Text = "User data types"; + this.chkCompUDT.UseVisualStyleBackColor = true; + // + // chkIndex + // + this.chkIndex.AutoSize = true; + this.chkIndex.Checked = true; + this.chkIndex.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkIndex.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.chkIndex.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIndex.Location = new System.Drawing.Point(10, 139); + this.chkIndex.Name = "chkIndex"; + this.chkIndex.Size = new System.Drawing.Size(70, 17); + this.chkIndex.TabIndex = 5; + this.chkIndex.Text = "Indexes"; + this.chkIndex.UseVisualStyleBackColor = true; + this.chkIndex.CheckedChanged += new System.EventHandler(this.chkCompIndices_CheckedChanged); + // + // chkTableOption + // + this.chkTableOption.AutoSize = true; + this.chkTableOption.Checked = true; + this.chkTableOption.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTableOption.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTableOption.Location = new System.Drawing.Point(30, 82); + this.chkTableOption.Name = "chkTableOption"; + this.chkTableOption.Size = new System.Drawing.Size(90, 17); + this.chkTableOption.TabIndex = 4; + this.chkTableOption.Text = "Table options"; + this.chkTableOption.UseVisualStyleBackColor = true; + // + // chkCompXMLSchemas + // + this.chkCompXMLSchemas.AutoSize = true; + this.chkCompXMLSchemas.Checked = true; + this.chkCompXMLSchemas.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompXMLSchemas.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompXMLSchemas.Location = new System.Drawing.Point(13, 236); + this.chkCompXMLSchemas.Name = "chkCompXMLSchemas"; + this.chkCompXMLSchemas.Size = new System.Drawing.Size(93, 17); + this.chkCompXMLSchemas.TabIndex = 21; + this.chkCompXMLSchemas.Text = "XML schemas"; + this.chkCompXMLSchemas.UseVisualStyleBackColor = true; + // + // chkCompFunciones + // + this.chkCompFunciones.AutoSize = true; + this.chkCompFunciones.Checked = true; + this.chkCompFunciones.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompFunciones.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompFunciones.Location = new System.Drawing.Point(13, 29); + this.chkCompFunciones.Name = "chkCompFunciones"; + this.chkCompFunciones.Size = new System.Drawing.Size(72, 17); + this.chkCompFunciones.TabIndex = 15; + this.chkCompFunciones.Text = "Functions"; + this.chkCompFunciones.UseVisualStyleBackColor = true; + // + // chkCompStoredProcedure + // + this.chkCompStoredProcedure.AutoSize = true; + this.chkCompStoredProcedure.Checked = true; + this.chkCompStoredProcedure.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompStoredProcedure.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompStoredProcedure.Location = new System.Drawing.Point(13, 121); + this.chkCompStoredProcedure.Name = "chkCompStoredProcedure"; + this.chkCompStoredProcedure.Size = new System.Drawing.Size(113, 17); + this.chkCompStoredProcedure.TabIndex = 16; + this.chkCompStoredProcedure.Text = "Stored procedures"; + this.chkCompStoredProcedure.UseVisualStyleBackColor = true; + // + // chkTables + // + this.chkTables.AutoSize = true; + this.chkTables.Checked = true; + this.chkTables.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTables.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.chkTables.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTables.Location = new System.Drawing.Point(10, 6); + this.chkTables.Name = "chkTables"; + this.chkTables.Size = new System.Drawing.Size(64, 17); + this.chkTables.TabIndex = 0; + this.chkTables.Text = "Tables"; + this.chkTables.UseVisualStyleBackColor = true; + this.chkTables.CheckedChanged += new System.EventHandler(this.chkCompTablas_CheckedChanged); + // + // chkCompTriggers + // + this.chkCompTriggers.AutoSize = true; + this.chkCompTriggers.Checked = true; + this.chkCompTriggers.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompTriggers.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompTriggers.Location = new System.Drawing.Point(13, 167); + this.chkCompTriggers.Name = "chkCompTriggers"; + this.chkCompTriggers.Size = new System.Drawing.Size(64, 17); + this.chkCompTriggers.TabIndex = 18; + this.chkCompTriggers.Text = "Triggers"; + this.chkCompTriggers.UseVisualStyleBackColor = true; + // + // chkCompVistas + // + this.chkCompVistas.AutoSize = true; + this.chkCompVistas.Checked = true; + this.chkCompVistas.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompVistas.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompVistas.Location = new System.Drawing.Point(13, 213); + this.chkCompVistas.Name = "chkCompVistas"; + this.chkCompVistas.Size = new System.Drawing.Size(54, 17); + this.chkCompVistas.TabIndex = 17; + this.chkCompVistas.Text = "Views"; + this.chkCompVistas.UseVisualStyleBackColor = true; + // + // chkCompExtendedProperties + // + this.chkCompExtendedProperties.AutoSize = true; + this.chkCompExtendedProperties.Checked = true; + this.chkCompExtendedProperties.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkCompExtendedProperties.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkCompExtendedProperties.Location = new System.Drawing.Point(177, 7); + this.chkCompExtendedProperties.Name = "chkCompExtendedProperties"; + this.chkCompExtendedProperties.Size = new System.Drawing.Size(120, 17); + this.chkCompExtendedProperties.TabIndex = 1; + this.chkCompExtendedProperties.Text = "Extended properties"; + this.chkCompExtendedProperties.UseVisualStyleBackColor = true; + // + // txtXML + // + this.txtXML.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtXML.Location = new System.Drawing.Point(16, 257); + this.txtXML.Name = "txtXML"; + this.txtXML.Size = new System.Drawing.Size(388, 20); + this.txtXML.TabIndex = 18; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.ForeColor = System.Drawing.SystemColors.ControlText; + this.label10.Location = new System.Drawing.Point(13, 241); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(29, 13); + this.label10.TabIndex = 17; + this.label10.Text = "XML"; + // + // txtTime + // + this.txtTime.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtTime.Location = new System.Drawing.Point(268, 116); + this.txtTime.Name = "txtTime"; + this.txtTime.Size = new System.Drawing.Size(237, 20); + this.txtTime.TabIndex = 16; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.ForeColor = System.Drawing.SystemColors.ControlText; + this.label9.Location = new System.Drawing.Point(268, 100); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(26, 13); + this.label9.TabIndex = 15; + this.label9.Text = "time"; + // + // txtVariant + // + this.txtVariant.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtVariant.Location = new System.Drawing.Point(16, 209); + this.txtVariant.Name = "txtVariant"; + this.txtVariant.Size = new System.Drawing.Size(388, 20); + this.txtVariant.TabIndex = 14; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.ForeColor = System.Drawing.SystemColors.ControlText; + this.label8.Location = new System.Drawing.Point(13, 193); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(58, 13); + this.label8.TabIndex = 13; + this.label8.Text = "sql_variant"; + // + // txtNText + // + this.txtNText.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtNText.Location = new System.Drawing.Point(268, 68); + this.txtNText.Name = "txtNText"; + this.txtNText.Size = new System.Drawing.Size(237, 20); + this.txtNText.TabIndex = 12; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.ForeColor = System.Drawing.SystemColors.ControlText; + this.label7.Location = new System.Drawing.Point(268, 52); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(184, 13); + this.label7.TabIndex = 11; + this.label7.Text = "nchar, nvarchar, nvarchar(max), ntext"; + // + // txtBlob + // + this.txtBlob.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtBlob.Location = new System.Drawing.Point(16, 164); + this.txtBlob.Name = "txtBlob"; + this.txtBlob.Size = new System.Drawing.Size(388, 20); + this.txtBlob.TabIndex = 10; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.ForeColor = System.Drawing.SystemColors.ControlText; + this.label6.Location = new System.Drawing.Point(13, 148); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(192, 13); + this.label6.TabIndex = 9; + this.label6.Text = "binary, image, varbinary, varbinary(max)"; + // + // txtDate + // + this.txtDate.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtDate.Location = new System.Drawing.Point(16, 116); + this.txtDate.Name = "txtDate"; + this.txtDate.Size = new System.Drawing.Size(237, 20); + this.txtDate.TabIndex = 8; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.ForeColor = System.Drawing.SystemColors.ControlText; + this.label5.Location = new System.Drawing.Point(13, 100); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(240, 13); + this.label5.TabIndex = 7; + this.label5.Text = "datetime, smalldatetime, datetime2, datetimeoffset"; + // + // txtText + // + this.txtText.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtText.Location = new System.Drawing.Point(16, 68); + this.txtText.Name = "txtText"; + this.txtText.Size = new System.Drawing.Size(237, 20); + this.txtText.TabIndex = 6; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.ForeColor = System.Drawing.SystemColors.ControlText; + this.label4.Location = new System.Drawing.Point(13, 52); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(160, 13); + this.label4.TabIndex = 5; + this.label4.Text = "char, varchar, varchar(max), text"; + // + // txtDefaultReal + // + this.txtDefaultReal.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtDefaultReal.Location = new System.Drawing.Point(268, 25); + this.txtDefaultReal.Name = "txtDefaultReal"; + this.txtDefaultReal.Size = new System.Drawing.Size(237, 20); + this.txtDefaultReal.TabIndex = 4; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.ForeColor = System.Drawing.SystemColors.ControlText; + this.label3.Location = new System.Drawing.Point(265, 9); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(232, 13); + this.label3.TabIndex = 3; + this.label3.Text = "float, real, numeric, decimal, money, smallmoney"; + // + // txtDefaultInteger + // + this.txtDefaultInteger.ForeColor = System.Drawing.SystemColors.ControlText; + this.txtDefaultInteger.Location = new System.Drawing.Point(16, 25); + this.txtDefaultInteger.Name = "txtDefaultInteger"; + this.txtDefaultInteger.Size = new System.Drawing.Size(237, 20); + this.txtDefaultInteger.TabIndex = 2; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.ForeColor = System.Drawing.SystemColors.ControlText; + this.label2.Location = new System.Drawing.Point(13, 9); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(160, 13); + this.label2.TabIndex = 1; + this.label2.Text = "integer, smallint, bigint, tinyint, bit"; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage4); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Controls.Add(this.tabPage5); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 0); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(545, 442); + this.tabControl1.TabIndex = 2; + // + // tabPage1 + // + this.tabPage1.BackColor = System.Drawing.Color.White; + this.tabPage1.Controls.Add(this.gradientPanel6); + this.tabPage1.Controls.Add(this.gradientPanel5); + this.tabPage1.Controls.Add(this.gradientPanel4); + this.tabPage1.Controls.Add(this.gradientPanel3); + this.tabPage1.Controls.Add(this.gradientPanel2); + this.tabPage1.Controls.Add(this.gradientPanel1); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Margin = new System.Windows.Forms.Padding(0); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(537, 416); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "Filter by type"; + // + // gradientPanel6 + // + this.gradientPanel6.Controls.Add(this.chkIgnoreNotForReplication); + this.gradientPanel6.Controls.Add(this.chkCompExtendedProperties); + this.gradientPanel6.Location = new System.Drawing.Point(5, 377); + this.gradientPanel6.Name = "gradientPanel6"; + this.gradientPanel6.Size = new System.Drawing.Size(525, 33); + this.gradientPanel6.TabIndex = 7; + // + // chkIgnoreNotForReplication + // + this.chkIgnoreNotForReplication.AutoSize = true; + this.chkIgnoreNotForReplication.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkIgnoreNotForReplication.Location = new System.Drawing.Point(12, 7); + this.chkIgnoreNotForReplication.Name = "chkIgnoreNotForReplication"; + this.chkIgnoreNotForReplication.Size = new System.Drawing.Size(140, 17); + this.chkIgnoreNotForReplication.TabIndex = 0; + this.chkIgnoreNotForReplication.Text = "Ignore not for replication"; + this.chkIgnoreNotForReplication.UseVisualStyleBackColor = true; + // + // gradientPanel5 + // + this.gradientPanel5.Controls.Add(this.IncludeSynonymsCheckBox); + this.gradientPanel5.Controls.Add(this.checkBox5); + this.gradientPanel5.Controls.Add(this.chkCompFunciones); + this.gradientPanel5.Controls.Add(this.checkPartitionFunction); + this.gradientPanel5.Controls.Add(this.chkCompVistas); + this.gradientPanel5.Controls.Add(this.chkCompRules); + this.gradientPanel5.Controls.Add(this.chkCompTriggers); + this.gradientPanel5.Controls.Add(this.chkCompTriggersDDL); + this.gradientPanel5.Controls.Add(this.chkCompStoredProcedure); + this.gradientPanel5.Controls.Add(this.chkCompUDT); + this.gradientPanel5.Controls.Add(this.chkCompXMLSchemas); + this.gradientPanel5.Location = new System.Drawing.Point(359, 33); + this.gradientPanel5.Name = "gradientPanel5"; + this.gradientPanel5.Size = new System.Drawing.Size(171, 338); + this.gradientPanel5.TabIndex = 6; + // + // gradientPanel4 + // + this.gradientPanel4.Controls.Add(this.chkCompCLRStore); + this.gradientPanel4.Controls.Add(this.chkCompAssemblys); + this.gradientPanel4.Controls.Add(this.checkBox4); + this.gradientPanel4.Controls.Add(this.chkCompCLRTrigger); + this.gradientPanel4.Controls.Add(this.chkCompCLRUDT); + this.gradientPanel4.Controls.Add(this.chkCompCLRFunctions); + this.gradientPanel4.Location = new System.Drawing.Point(182, 176); + this.gradientPanel4.Name = "gradientPanel4"; + this.gradientPanel4.Size = new System.Drawing.Size(171, 195); + this.gradientPanel4.TabIndex = 5; + // + // gradientPanel3 + // + this.gradientPanel3.Controls.Add(this.checkBox1); + this.gradientPanel3.Controls.Add(this.chkFullTextPath); + this.gradientPanel3.Controls.Add(this.chkCompUsers); + this.gradientPanel3.Controls.Add(this.chkCompSchemas); + this.gradientPanel3.Controls.Add(this.chkFileGroups); + this.gradientPanel3.Controls.Add(this.chkCompRoles); + this.gradientPanel3.Controls.Add(this.chkFullText); + this.gradientPanel3.Location = new System.Drawing.Point(182, 33); + this.gradientPanel3.Name = "gradientPanel3"; + this.gradientPanel3.Size = new System.Drawing.Size(171, 137); + this.gradientPanel3.TabIndex = 4; + // + // checkBox1 + // + this.checkBox1.AutoSize = true; + this.checkBox1.Checked = true; + this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox1.ForeColor = System.Drawing.SystemColors.ControlText; + this.checkBox1.Location = new System.Drawing.Point(10, 120); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.Size = new System.Drawing.Size(81, 17); + this.checkBox1.TabIndex = 37; + this.checkBox1.Text = "Permissions"; + this.checkBox1.UseVisualStyleBackColor = true; + // + // gradientPanel2 + // + this.gradientPanel2.Controls.Add(this.chkTableChangeTracking); + this.gradientPanel2.Controls.Add(this.chkTableLockEscalation); + this.gradientPanel2.Controls.Add(this.chkTables); + this.gradientPanel2.Controls.Add(this.chkIndexFilter); + this.gradientPanel2.Controls.Add(this.chkTableOption); + this.gradientPanel2.Controls.Add(this.chkConstraintsCheck); + this.gradientPanel2.Controls.Add(this.chkIndex); + this.gradientPanel2.Controls.Add(this.chkConstraintsUK); + this.gradientPanel2.Controls.Add(this.chkConstraints); + this.gradientPanel2.Controls.Add(this.chkConstraintsFK); + this.gradientPanel2.Controls.Add(this.chkTablesColumnCollation); + this.gradientPanel2.Controls.Add(this.chkConstraintsPK); + this.gradientPanel2.Controls.Add(this.chkTablesColumnIdentity); + this.gradientPanel2.Controls.Add(this.chkTablesColumnOrder); + this.gradientPanel2.Controls.Add(this.chkIndexFillFactor); + this.gradientPanel2.Controls.Add(this.chkIndexIncludeColumns); + this.gradientPanel2.Controls.Add(this.chkIndexRowLock); + this.gradientPanel2.Location = new System.Drawing.Point(5, 33); + this.gradientPanel2.Name = "gradientPanel2"; + this.gradientPanel2.Size = new System.Drawing.Size(171, 338); + this.gradientPanel2.TabIndex = 3; + // + // chkTableChangeTracking + // + this.chkTableChangeTracking.AutoSize = true; + this.chkTableChangeTracking.Checked = true; + this.chkTableChangeTracking.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTableChangeTracking.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTableChangeTracking.Location = new System.Drawing.Point(30, 120); + this.chkTableChangeTracking.Name = "chkTableChangeTracking"; + this.chkTableChangeTracking.Size = new System.Drawing.Size(104, 17); + this.chkTableChangeTracking.TabIndex = 16; + this.chkTableChangeTracking.Text = "Change tracking"; + this.chkTableChangeTracking.UseVisualStyleBackColor = true; + // + // chkTableLockEscalation + // + this.chkTableLockEscalation.AutoSize = true; + this.chkTableLockEscalation.Checked = true; + this.chkTableLockEscalation.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkTableLockEscalation.ForeColor = System.Drawing.SystemColors.ControlText; + this.chkTableLockEscalation.Location = new System.Drawing.Point(30, 101); + this.chkTableLockEscalation.Name = "chkTableLockEscalation"; + this.chkTableLockEscalation.Size = new System.Drawing.Size(101, 17); + this.chkTableLockEscalation.TabIndex = 15; + this.chkTableLockEscalation.Text = "Lock escalation"; + this.chkTableLockEscalation.UseVisualStyleBackColor = true; + // + // gradientPanel1 + // + this.gradientPanel1.Controls.Add(this.label11); + this.gradientPanel1.Location = new System.Drawing.Point(5, 6); + this.gradientPanel1.Name = "gradientPanel1"; + this.gradientPanel1.Size = new System.Drawing.Size(525, 21); + this.gradientPanel1.TabIndex = 2; + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label11.Location = new System.Drawing.Point(4, 4); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(113, 13); + this.label11.TabIndex = 3; + this.label11.Text = "Filter items by type"; + // + // tabPage4 + // + this.tabPage4.BackColor = System.Drawing.Color.White; + this.tabPage4.Controls.Add(this.DeleteNameFilterButton); + this.tabPage4.Controls.Add(this.btnAdd); + this.tabPage4.Controls.Add(this.gradientPanel10); + this.tabPage4.Controls.Add(this.btnApply); + this.tabPage4.Controls.Add(this.gradientPanel9); + this.tabPage4.Location = new System.Drawing.Point(4, 22); + this.tabPage4.Name = "tabPage4"; + this.tabPage4.Padding = new System.Windows.Forms.Padding(3); + this.tabPage4.Size = new System.Drawing.Size(537, 416); + this.tabPage4.TabIndex = 3; + this.tabPage4.Text = "Exclude by name"; + // + // DeleteNameFilterButton + // + this.DeleteNameFilterButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.DeleteNameFilterButton.ForeColor = System.Drawing.SystemColors.ControlText; + this.DeleteNameFilterButton.Location = new System.Drawing.Point(464, 387); + this.DeleteNameFilterButton.Name = "DeleteNameFilterButton"; + this.DeleteNameFilterButton.Size = new System.Drawing.Size(58, 23); + this.DeleteNameFilterButton.TabIndex = 6; + this.DeleteNameFilterButton.Text = "Delete"; + this.DeleteNameFilterButton.UseVisualStyleBackColor = true; + this.DeleteNameFilterButton.Click += new System.EventHandler(this.DeleteNameFilterButton_Click); + // + // btnAdd + // + this.btnAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnAdd.ForeColor = System.Drawing.SystemColors.ControlText; + this.btnAdd.Location = new System.Drawing.Point(336, 387); + this.btnAdd.Name = "btnAdd"; + this.btnAdd.Size = new System.Drawing.Size(58, 23); + this.btnAdd.TabIndex = 3; + this.btnAdd.Text = "Add"; + this.btnAdd.UseVisualStyleBackColor = true; + this.btnAdd.Click += new System.EventHandler(this.btnAdd_Click); + // + // gradientPanel10 + // + this.gradientPanel10.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gradientPanel10.Controls.Add(this.lstFilters); + this.gradientPanel10.Location = new System.Drawing.Point(6, 33); + this.gradientPanel10.Name = "gradientPanel10"; + this.gradientPanel10.Size = new System.Drawing.Size(524, 348); + this.gradientPanel10.TabIndex = 5; + // + // lstFilters + // + this.lstFilters.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.lstFilters.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2, + this.columnHeader3, + this.columnHeader4}); + this.lstFilters.FullRowSelect = true; + this.lstFilters.Location = new System.Drawing.Point(7, 8); + this.lstFilters.Name = "lstFilters"; + this.lstFilters.Size = new System.Drawing.Size(509, 333); + this.lstFilters.TabIndex = 0; + this.lstFilters.UseCompatibleStateImageBehavior = false; + this.lstFilters.View = System.Windows.Forms.View.Details; + this.lstFilters.DoubleClick += new System.EventHandler(this.lstFilters_DoubleClick); + // + // columnHeader1 + // + this.columnHeader1.Text = "Exclusion pattern"; + this.columnHeader1.Width = 250; + // + // columnHeader2 + // + this.columnHeader2.Text = "Item type"; + this.columnHeader2.Width = 100; + // + // columnHeader3 + // + this.columnHeader3.Width = 0; + // + // columnHeader4 + // + this.columnHeader4.Text = ""; + // + // btnApply + // + this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnApply.ForeColor = System.Drawing.SystemColors.ControlText; + this.btnApply.Location = new System.Drawing.Point(400, 387); + this.btnApply.Name = "btnApply"; + this.btnApply.Size = new System.Drawing.Size(58, 23); + this.btnApply.TabIndex = 2; + this.btnApply.Text = "Edit"; + this.btnApply.UseVisualStyleBackColor = true; + this.btnApply.Click += new System.EventHandler(this.btnApply_Click); + // + // gradientPanel9 + // + this.gradientPanel9.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gradientPanel9.Controls.Add(this.label1); + this.gradientPanel9.Location = new System.Drawing.Point(5, 6); + this.gradientPanel9.Name = "gradientPanel9"; + this.gradientPanel9.Size = new System.Drawing.Size(525, 21); + this.gradientPanel9.TabIndex = 4; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(4, 4); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(136, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Exclude items by name"; + // + // tabPage2 + // + this.tabPage2.BackColor = System.Drawing.Color.White; + this.tabPage2.Controls.Add(this.gradientPanel8); + this.tabPage2.Controls.Add(this.gradientPanel7); + this.tabPage2.Location = new System.Drawing.Point(4, 22); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(537, 416); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "Defaults"; + // + // gradientPanel8 + // + this.gradientPanel8.Controls.Add(this.txtXML); + this.gradientPanel8.Controls.Add(this.label2); + this.gradientPanel8.Controls.Add(this.label10); + this.gradientPanel8.Controls.Add(this.txtDefaultInteger); + this.gradientPanel8.Controls.Add(this.txtTime); + this.gradientPanel8.Controls.Add(this.label3); + this.gradientPanel8.Controls.Add(this.label9); + this.gradientPanel8.Controls.Add(this.txtDefaultReal); + this.gradientPanel8.Controls.Add(this.txtVariant); + this.gradientPanel8.Controls.Add(this.label4); + this.gradientPanel8.Controls.Add(this.label8); + this.gradientPanel8.Controls.Add(this.txtText); + this.gradientPanel8.Controls.Add(this.txtNText); + this.gradientPanel8.Controls.Add(this.label5); + this.gradientPanel8.Controls.Add(this.label7); + this.gradientPanel8.Controls.Add(this.txtDate); + this.gradientPanel8.Controls.Add(this.txtBlob); + this.gradientPanel8.Controls.Add(this.label6); + this.gradientPanel8.Location = new System.Drawing.Point(5, 33); + this.gradientPanel8.Name = "gradientPanel8"; + this.gradientPanel8.Size = new System.Drawing.Size(525, 377); + this.gradientPanel8.TabIndex = 4; + // + // gradientPanel7 + // + this.gradientPanel7.Controls.Add(this.label12); + this.gradientPanel7.Location = new System.Drawing.Point(5, 6); + this.gradientPanel7.Name = "gradientPanel7"; + this.gradientPanel7.Size = new System.Drawing.Size(525, 21); + this.gradientPanel7.TabIndex = 3; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label12.Location = new System.Drawing.Point(4, 4); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(89, 13); + this.label12.TabIndex = 3; + this.label12.Text = "Default values"; + // + // tabPage3 + // + this.tabPage3.BackColor = System.Drawing.Color.White; + this.tabPage3.Controls.Add(this.groupBox4); + this.tabPage3.Controls.Add(this.gradientPanel16); + this.tabPage3.Location = new System.Drawing.Point(4, 22); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.Size = new System.Drawing.Size(537, 416); + this.tabPage3.TabIndex = 2; + this.tabPage3.Text = "Script"; + // + // groupBox4 + // + this.groupBox4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox4.Controls.Add(this.optScriptSchemaBindingAlter); + this.groupBox4.Controls.Add(this.optScriptSchemaDrop); + this.groupBox4.Location = new System.Drawing.Point(5, 33); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(525, 66); + this.groupBox4.TabIndex = 4; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "When rebuilding a view with schema binding"; + // + // optScriptSchemaBindingAlter + // + this.optScriptSchemaBindingAlter.AutoSize = true; + this.optScriptSchemaBindingAlter.Checked = true; + this.optScriptSchemaBindingAlter.ForeColor = System.Drawing.SystemColors.ControlText; + this.optScriptSchemaBindingAlter.Location = new System.Drawing.Point(18, 42); + this.optScriptSchemaBindingAlter.Name = "optScriptSchemaBindingAlter"; + this.optScriptSchemaBindingAlter.Size = new System.Drawing.Size(120, 17); + this.optScriptSchemaBindingAlter.TabIndex = 1; + this.optScriptSchemaBindingAlter.TabStop = true; + this.optScriptSchemaBindingAlter.Text = "ALTER object twice"; + this.optScriptSchemaBindingAlter.UseVisualStyleBackColor = true; + // + // optScriptSchemaDrop + // + this.optScriptSchemaDrop.AutoSize = true; + this.optScriptSchemaDrop.ForeColor = System.Drawing.SystemColors.ControlText; + this.optScriptSchemaDrop.Location = new System.Drawing.Point(18, 19); + this.optScriptSchemaDrop.Name = "optScriptSchemaDrop"; + this.optScriptSchemaDrop.Size = new System.Drawing.Size(136, 17); + this.optScriptSchemaDrop.TabIndex = 0; + this.optScriptSchemaDrop.TabStop = true; + this.optScriptSchemaDrop.Text = "DROP/CREATE object"; + this.optScriptSchemaDrop.UseVisualStyleBackColor = true; + // + // gradientPanel16 + // + this.gradientPanel16.Controls.Add(this.label15); + this.gradientPanel16.Location = new System.Drawing.Point(5, 6); + this.gradientPanel16.Name = "gradientPanel16"; + this.gradientPanel16.Size = new System.Drawing.Size(525, 21); + this.gradientPanel16.TabIndex = 3; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label15.Location = new System.Drawing.Point(4, 4); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(144, 13); + this.label15.TabIndex = 3; + this.label15.Text = "Advanced script options"; + // + // tabPage5 + // + this.tabPage5.BackColor = System.Drawing.Color.White; + this.tabPage5.Controls.Add(this.gradientPanel15); + this.tabPage5.Controls.Add(this.gradientPanel14); + this.tabPage5.Controls.Add(this.gradientPanel13); + this.tabPage5.Controls.Add(this.gradientPanel12); + this.tabPage5.Controls.Add(this.gradientPanel11); + this.tabPage5.Controls.Add(this.chkReloadDB); + this.tabPage5.Location = new System.Drawing.Point(4, 22); + this.tabPage5.Name = "tabPage5"; + this.tabPage5.Padding = new System.Windows.Forms.Padding(3); + this.tabPage5.Size = new System.Drawing.Size(537, 416); + this.tabPage5.TabIndex = 4; + this.tabPage5.Text = "Comparison"; + // + // gradientPanel15 + // + this.gradientPanel15.Controls.Add(this.chkIgnoreWhiteSpaceInCode); + this.gradientPanel15.Location = new System.Drawing.Point(5, 232); + this.gradientPanel15.Name = "gradientPanel15"; + this.gradientPanel15.Size = new System.Drawing.Size(525, 31); + this.gradientPanel15.TabIndex = 7; + // + // chkIgnoreWhiteSpaceInCode + // + this.chkIgnoreWhiteSpaceInCode.AutoSize = true; + this.chkIgnoreWhiteSpaceInCode.Location = new System.Drawing.Point(7, 7); + this.chkIgnoreWhiteSpaceInCode.Name = "chkIgnoreWhiteSpaceInCode"; + this.chkIgnoreWhiteSpaceInCode.Size = new System.Drawing.Size(327, 17); + this.chkIgnoreWhiteSpaceInCode.TabIndex = 2; + this.chkIgnoreWhiteSpaceInCode.Text = "Ignore white spaces in stored procedures, triggers and functions"; + this.chkIgnoreWhiteSpaceInCode.UseVisualStyleBackColor = true; + // + // gradientPanel14 + // + this.gradientPanel14.Controls.Add(this.label14); + this.gradientPanel14.Location = new System.Drawing.Point(5, 135); + this.gradientPanel14.Name = "gradientPanel14"; + this.gradientPanel14.Size = new System.Drawing.Size(525, 21); + this.gradientPanel14.TabIndex = 6; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label14.Location = new System.Drawing.Point(4, 4); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(247, 13); + this.label14.TabIndex = 3; + this.label14.Text = "Procedures, functions and triggers options"; + // + // gradientPanel13 + // + this.gradientPanel13.Controls.Add(this.rdoCaseSensityInCode); + this.gradientPanel13.Controls.Add(this.rdoCaseInsensityInCode); + this.gradientPanel13.Location = new System.Drawing.Point(5, 162); + this.gradientPanel13.Name = "gradientPanel13"; + this.gradientPanel13.Size = new System.Drawing.Size(525, 64); + this.gradientPanel13.TabIndex = 5; + // + // rdoCaseSensityInCode + // + this.rdoCaseSensityInCode.AutoSize = true; + this.rdoCaseSensityInCode.Location = new System.Drawing.Point(13, 36); + this.rdoCaseSensityInCode.Name = "rdoCaseSensityInCode"; + this.rdoCaseSensityInCode.Size = new System.Drawing.Size(93, 17); + this.rdoCaseSensityInCode.TabIndex = 2; + this.rdoCaseSensityInCode.Text = "Case sensitive"; + this.rdoCaseSensityInCode.UseVisualStyleBackColor = true; + // + // rdoCaseInsensityInCode + // + this.rdoCaseInsensityInCode.AutoSize = true; + this.rdoCaseInsensityInCode.Checked = true; + this.rdoCaseInsensityInCode.Location = new System.Drawing.Point(13, 13); + this.rdoCaseInsensityInCode.Name = "rdoCaseInsensityInCode"; + this.rdoCaseInsensityInCode.Size = new System.Drawing.Size(101, 17); + this.rdoCaseInsensityInCode.TabIndex = 1; + this.rdoCaseInsensityInCode.TabStop = true; + this.rdoCaseInsensityInCode.Text = "Case insensitive"; + this.rdoCaseInsensityInCode.UseVisualStyleBackColor = true; + // + // gradientPanel12 + // + this.gradientPanel12.Controls.Add(this.label13); + this.gradientPanel12.Location = new System.Drawing.Point(5, 6); + this.gradientPanel12.Name = "gradientPanel12"; + this.gradientPanel12.Size = new System.Drawing.Size(525, 21); + this.gradientPanel12.TabIndex = 4; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label13.Location = new System.Drawing.Point(4, 4); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(192, 13); + this.label13.TabIndex = 3; + this.label13.Text = "Collation case sensitivity options"; + // + // gradientPanel11 + // + this.gradientPanel11.Controls.Add(this.rdoCaseSensitive); + this.gradientPanel11.Controls.Add(this.rdoCaseAutomatic); + this.gradientPanel11.Controls.Add(this.rdoCaseInsensitive); + this.gradientPanel11.Location = new System.Drawing.Point(5, 33); + this.gradientPanel11.Name = "gradientPanel11"; + this.gradientPanel11.Size = new System.Drawing.Size(525, 87); + this.gradientPanel11.TabIndex = 3; + // + // rdoCaseSensitive + // + this.rdoCaseSensitive.AutoSize = true; + this.rdoCaseSensitive.Location = new System.Drawing.Point(14, 59); + this.rdoCaseSensitive.Name = "rdoCaseSensitive"; + this.rdoCaseSensitive.Size = new System.Drawing.Size(93, 17); + this.rdoCaseSensitive.TabIndex = 2; + this.rdoCaseSensitive.Text = "Case sensitive"; + this.rdoCaseSensitive.UseVisualStyleBackColor = true; + // + // rdoCaseAutomatic + // + this.rdoCaseAutomatic.AutoSize = true; + this.rdoCaseAutomatic.Checked = true; + this.rdoCaseAutomatic.Location = new System.Drawing.Point(14, 13); + this.rdoCaseAutomatic.Name = "rdoCaseAutomatic"; + this.rdoCaseAutomatic.Size = new System.Drawing.Size(200, 17); + this.rdoCaseAutomatic.TabIndex = 0; + this.rdoCaseAutomatic.TabStop = true; + this.rdoCaseAutomatic.Text = "Automatic (detect database collation)"; + this.rdoCaseAutomatic.UseVisualStyleBackColor = true; + // + // rdoCaseInsensitive + // + this.rdoCaseInsensitive.AutoSize = true; + this.rdoCaseInsensitive.Location = new System.Drawing.Point(14, 36); + this.rdoCaseInsensitive.Name = "rdoCaseInsensitive"; + this.rdoCaseInsensitive.Size = new System.Drawing.Size(101, 17); + this.rdoCaseInsensitive.TabIndex = 1; + this.rdoCaseInsensitive.Text = "Case insensitive"; + this.rdoCaseInsensitive.UseVisualStyleBackColor = true; + // + // chkReloadDB + // + this.chkReloadDB.AutoSize = true; + this.chkReloadDB.Location = new System.Drawing.Point(12, 393); + this.chkReloadDB.Name = "chkReloadDB"; + this.chkReloadDB.Size = new System.Drawing.Size(251, 17); + this.chkReloadDB.TabIndex = 8; + this.chkReloadDB.Text = "Reload database comparison after each update"; + this.chkReloadDB.UseVisualStyleBackColor = false; + // + // IncludeSynonymsCheckBox + // + this.IncludeSynonymsCheckBox.AutoSize = true; + this.IncludeSynonymsCheckBox.Checked = true; + this.IncludeSynonymsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.IncludeSynonymsCheckBox.ForeColor = System.Drawing.SystemColors.ControlText; + this.IncludeSynonymsCheckBox.Location = new System.Drawing.Point(13, 144); + this.IncludeSynonymsCheckBox.Name = "IncludeSynonymsCheckBox"; + this.IncludeSynonymsCheckBox.Size = new System.Drawing.Size(74, 17); + this.IncludeSynonymsCheckBox.TabIndex = 28; + this.IncludeSynonymsCheckBox.Text = "Synonyms"; + this.IncludeSynonymsCheckBox.UseVisualStyleBackColor = true; + // + // SqlOptionsFront + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tabControl1); + this.Name = "SqlOptionsFront"; + this.Size = new System.Drawing.Size(545, 442); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.gradientPanel6.ResumeLayout(false); + this.gradientPanel6.PerformLayout(); + this.gradientPanel5.ResumeLayout(false); + this.gradientPanel5.PerformLayout(); + this.gradientPanel4.ResumeLayout(false); + this.gradientPanel4.PerformLayout(); + this.gradientPanel3.ResumeLayout(false); + this.gradientPanel3.PerformLayout(); + this.gradientPanel2.ResumeLayout(false); + this.gradientPanel2.PerformLayout(); + this.gradientPanel1.ResumeLayout(false); + this.gradientPanel1.PerformLayout(); + this.tabPage4.ResumeLayout(false); + this.gradientPanel10.ResumeLayout(false); + this.gradientPanel9.ResumeLayout(false); + this.gradientPanel9.PerformLayout(); + this.tabPage2.ResumeLayout(false); + this.gradientPanel8.ResumeLayout(false); + this.gradientPanel8.PerformLayout(); + this.gradientPanel7.ResumeLayout(false); + this.gradientPanel7.PerformLayout(); + this.tabPage3.ResumeLayout(false); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); + this.gradientPanel16.ResumeLayout(false); + this.gradientPanel16.PerformLayout(); + this.tabPage5.ResumeLayout(false); + this.tabPage5.PerformLayout(); + this.gradientPanel15.ResumeLayout(false); + this.gradientPanel15.PerformLayout(); + this.gradientPanel14.ResumeLayout(false); + this.gradientPanel14.PerformLayout(); + this.gradientPanel13.ResumeLayout(false); + this.gradientPanel13.PerformLayout(); + this.gradientPanel12.ResumeLayout(false); + this.gradientPanel12.PerformLayout(); + this.gradientPanel11.ResumeLayout(false); + this.gradientPanel11.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private CheckBox chkCompExtendedProperties; + private CheckBox chkConstraints; + private CheckBox chkCompSchemas; + private CheckBox chkCompUDT; + private CheckBox chkIndex; + private CheckBox chkTableOption; + private CheckBox chkCompXMLSchemas; + private CheckBox chkCompFunciones; + private CheckBox chkCompStoredProcedure; + private CheckBox chkTables; + private CheckBox chkCompTriggers; + private CheckBox chkCompVistas; + private Label label2; + private TextBox txtDefaultReal; + private Label label3; + private TextBox txtDefaultInteger; + private TextBox txtText; + private Label label4; + private TextBox txtNText; + private Label label7; + private TextBox txtBlob; + private Label label6; + private TextBox txtDate; + private Label label5; + private TextBox txtVariant; + private Label label8; + private CheckBox chkTablesColumnIdentity; + private CheckBox chkTablesColumnCollation; + private CheckBox chkFileGroups; + private CheckBox chkCompAssemblys; + private TabControl tabControl1; + private TabPage tabPage1; + private TabPage tabPage2; + private CheckBox chkTablesColumnOrder; + private CheckBox chkIndexFillFactor; + private CheckBox chkCompTriggersDDL; + private CheckBox chkIndexIncludeColumns; + private CheckBox chkCompUsers; + private TabPage tabPage3; + private CheckBox chkCompRoles; + private TabPage tabPage4; + private ListView lstFilters; + private ColumnHeader columnHeader1; + private ColumnHeader columnHeader2; + private ColumnHeader columnHeader3; + private ColumnHeader columnHeader4; + private Button btnApply; + private Button btnAdd; + private CheckBox chkIgnoreNotForReplication; + private CheckBox chkCompRules; + private CheckBox chkFullText; + private CheckBox chkIndexRowLock; + private CheckBox chkCompCLRStore; + private CheckBox chkCompCLRTrigger; + private CheckBox chkCompCLRFunctions; + private CheckBox chkCompCLRUDT; + private CheckBox checkBox4; + private CheckBox checkPartitionFunction; + private CheckBox checkBox5; + private TabPage tabPage5; + private RadioButton rdoCaseAutomatic; + private RadioButton rdoCaseSensitive; + private RadioButton rdoCaseInsensitive; + private TextBox txtTime; + private Label label9; + private TextBox txtXML; + private Label label10; + private CheckBox chkConstraintsPK; + private CheckBox chkConstraintsFK; + private CheckBox chkConstraintsUK; + private CheckBox chkConstraintsCheck; + private CheckBox chkIndexFilter; + private CheckBox chkFullTextPath; + private RadioButton rdoCaseSensityInCode; + private RadioButton rdoCaseInsensityInCode; + private CheckBox chkIgnoreWhiteSpaceInCode; + private Panel gradientPanel1; + private Label label11; + private Panel gradientPanel2; + private Panel gradientPanel3; + private Panel gradientPanel4; + private Panel gradientPanel5; + private Panel gradientPanel6; + private Panel gradientPanel8; + private Panel gradientPanel7; + private Label label12; + private Panel gradientPanel9; + private Label label1; + private Panel gradientPanel10; + private CheckBox chkTableLockEscalation; + private CheckBox chkTableChangeTracking; + private CheckBox checkBox1; + private Panel gradientPanel12; + private Label label13; + private Panel gradientPanel11; + private Panel gradientPanel13; + private Panel gradientPanel14; + private Label label14; + private Panel gradientPanel15; + private Panel gradientPanel16; + private Label label15; + private GroupBox groupBox4; + private RadioButton optScriptSchemaBindingAlter; + private RadioButton optScriptSchemaDrop; + private CheckBox chkReloadDB; + private Button DeleteNameFilterButton; + private CheckBox IncludeSynonymsCheckBox; + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/SqlOptionsFront.cs b/OpenDBDiff.SqlServer.Ui/Front/SqlOptionsFront.cs new file mode 100644 index 0000000..95c511b --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/SqlOptionsFront.cs @@ -0,0 +1,279 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Windows.Forms; + +namespace OpenDBDiff.SqlServer.Ui +{ + public partial class SqlOptionsFront : OpenDBDiff.Abstractions.Ui.OptionControl + { + private SqlOption SQLOption; + + public SqlOptionsFront() + { + InitializeComponent(); + HandlerHelper.OnChange += new HandlerHelper.SaveFilterHandler(HandlerHelper_OnChange); + } + + public void HandlerHelper_OnChange() + { + LoadFilters(); + } + + private void LoadFilters() + { + lstFilters.Items.Clear(); + foreach (SqlOptionFilterItem item in SQLOption.Filters.Items) + { + var lview = new ListViewItem(item.FilterPattern); + lview.SubItems.Add(item.ObjectType.ToString()); + lstFilters.Items.Add(lview); + }; + } + + public override void Load(IOption option) + { + this.SQLOption = new SqlOption(option); + txtBlob.Text = SQLOption.Defaults.DefaultBlobValue; + txtDate.Text = SQLOption.Defaults.DefaultDateValue; + txtDefaultInteger.Text = SQLOption.Defaults.DefaultIntegerValue; + txtDefaultReal.Text = SQLOption.Defaults.DefaultRealValue; + txtNText.Text = SQLOption.Defaults.DefaultNTextValue; + txtText.Text = SQLOption.Defaults.DefaultTextValue; + txtVariant.Text = SQLOption.Defaults.DefaultVariantValue; + txtTime.Text = SQLOption.Defaults.DefaultTime; + txtXML.Text = SQLOption.Defaults.DefaultXml; + + chkCompAssemblys.Checked = SQLOption.Ignore.FilterAssemblies; + chkCompCLRFunctions.Checked = SQLOption.Ignore.FilterCLRFunction; + chkCompCLRStore.Checked = SQLOption.Ignore.FilterCLRStoredProcedure; + chkCompCLRTrigger.Checked = SQLOption.Ignore.FilterCLRTrigger; + chkCompCLRUDT.Checked = SQLOption.Ignore.FilterCLRUDT; + + chkConstraints.Checked = SQLOption.Ignore.FilterConstraint; + chkConstraintsPK.Checked = SQLOption.Ignore.FilterConstraintPK; + chkConstraintsFK.Checked = SQLOption.Ignore.FilterConstraintFK; + chkConstraintsUK.Checked = SQLOption.Ignore.FilterConstraintUK; + chkConstraintsCheck.Checked = SQLOption.Ignore.FilterConstraintCheck; + + chkCompExtendedProperties.Checked = SQLOption.Ignore.FilterExtendedProperties; + chkCompFunciones.Checked = SQLOption.Ignore.FilterFunction; + chkIndex.Checked = SQLOption.Ignore.FilterIndex; + chkIndexFillFactor.Checked = SQLOption.Ignore.FilterIndexFillFactor; + chkIndexIncludeColumns.Checked = SQLOption.Ignore.FilterIndexIncludeColumns; + chkIndexFilter.Checked = SQLOption.Ignore.FilterIndexFilter; + chkFullText.Checked = SQLOption.Ignore.FilterFullText; + chkFullTextPath.Checked = SQLOption.Ignore.FilterFullTextPath; + + chkCompSchemas.Checked = SQLOption.Ignore.FilterSchema; + chkCompStoredProcedure.Checked = SQLOption.Ignore.FilterStoredProcedure; + chkTableOption.Checked = SQLOption.Ignore.FilterTableOption; + chkTables.Checked = SQLOption.Ignore.FilterTable; + chkTablesColumnIdentity.Checked = SQLOption.Ignore.FilterColumnIdentity; + chkTablesColumnCollation.Checked = SQLOption.Ignore.FilterColumnCollation; + chkTableLockEscalation.Checked = SQLOption.Ignore.FilterTableLockEscalation; + chkTableChangeTracking.Checked = SQLOption.Ignore.FilterTableChangeTracking; + + chkTablesColumnOrder.Checked = SQLOption.Ignore.FilterColumnOrder; + chkIgnoreNotForReplication.Checked = SQLOption.Ignore.FilterNotForReplication; + + chkCompTriggersDDL.Checked = SQLOption.Ignore.FilterDDLTriggers; + chkCompTriggers.Checked = SQLOption.Ignore.FilterTrigger; + chkCompUDT.Checked = SQLOption.Ignore.FilterUserDataType; + chkCompVistas.Checked = SQLOption.Ignore.FilterView; + chkCompXMLSchemas.Checked = SQLOption.Ignore.FilterXMLSchema; + chkFileGroups.Checked = SQLOption.Ignore.FilterTableFileGroup; + chkCompUsers.Checked = SQLOption.Ignore.FilterUsers; + chkCompRoles.Checked = SQLOption.Ignore.FilterRoles; + chkCompRules.Checked = SQLOption.Ignore.FilterRules; + + IncludeSynonymsCheckBox.Checked = SQLOption.Ignore.FilterSynonyms; + + if (SQLOption.Script.AlterObjectOnSchemaBinding) + optScriptSchemaBindingAlter.Checked = true; + else + optScriptSchemaDrop.Checked = true; + + if (SQLOption.Comparison.CaseSensityType == SqlOptionComparison.CaseSensityOptions.Automatic) + rdoCaseAutomatic.Checked = true; + if (SQLOption.Comparison.CaseSensityType == SqlOptionComparison.CaseSensityOptions.CaseInsensity) + rdoCaseInsensitive.Checked = true; + if (SQLOption.Comparison.CaseSensityType == SqlOptionComparison.CaseSensityOptions.CaseSensity) + rdoCaseSensitive.Checked = true; + + if (SQLOption.Comparison.CaseSensityInCode == SqlOptionComparison.CaseSensityOptions.CaseInsensity) + rdoCaseInsensityInCode.Checked = true; + if (SQLOption.Comparison.CaseSensityInCode == SqlOptionComparison.CaseSensityOptions.CaseSensity) + rdoCaseSensityInCode.Checked = true; + + chkIgnoreWhiteSpaceInCode.Checked = SQLOption.Comparison.IgnoreWhiteSpacesInCode; + + chkReloadDB.Checked = SQLOption.Comparison.ReloadComparisonOnUpdate; + + LoadFilters(); + } + + public override void Save() + { + SQLOption.Defaults.DefaultBlobValue = txtBlob.Text; + SQLOption.Defaults.DefaultDateValue = txtDate.Text; + SQLOption.Defaults.DefaultIntegerValue = txtDefaultInteger.Text; + SQLOption.Defaults.DefaultNTextValue = txtNText.Text; + SQLOption.Defaults.DefaultRealValue = txtDefaultReal.Text; + SQLOption.Defaults.DefaultTextValue = txtText.Text; + SQLOption.Defaults.DefaultVariantValue = txtVariant.Text; + SQLOption.Defaults.DefaultTime = txtTime.Text; + SQLOption.Defaults.DefaultXml = txtXML.Text; + + SQLOption.Ignore.FilterAssemblies = chkCompAssemblys.Checked; + SQLOption.Ignore.FilterCLRFunction = chkCompCLRFunctions.Checked && chkCompAssemblys.Checked; + SQLOption.Ignore.FilterCLRStoredProcedure = chkCompCLRStore.Checked && chkCompAssemblys.Checked; + SQLOption.Ignore.FilterCLRTrigger = chkCompCLRTrigger.Checked && chkCompAssemblys.Checked; + SQLOption.Ignore.FilterCLRUDT = chkCompCLRUDT.Checked && chkCompAssemblys.Checked; + + SQLOption.Ignore.FilterConstraint = chkConstraints.Checked; + SQLOption.Ignore.FilterConstraintPK = chkConstraintsPK.Checked; + SQLOption.Ignore.FilterConstraintFK = chkConstraintsFK.Checked; + SQLOption.Ignore.FilterConstraintUK = chkConstraintsUK.Checked; + SQLOption.Ignore.FilterConstraintCheck = chkConstraintsCheck.Checked; + + SQLOption.Ignore.FilterFunction = chkCompFunciones.Checked; + + SQLOption.Ignore.FilterIndex = chkIndex.Checked; + SQLOption.Ignore.FilterIndexFillFactor = chkIndexFillFactor.Checked && chkIndex.Checked; + SQLOption.Ignore.FilterIndexIncludeColumns = chkIndexIncludeColumns.Checked && chkIndex.Checked; + SQLOption.Ignore.FilterIndexFilter = chkIndexFilter.Checked && chkIndex.Checked; + + SQLOption.Ignore.FilterSchema = chkCompSchemas.Checked; + SQLOption.Ignore.FilterStoredProcedure = chkCompStoredProcedure.Checked; + + SQLOption.Ignore.FilterTable = chkTables.Checked; + SQLOption.Ignore.FilterColumnIdentity = chkTablesColumnIdentity.Checked && chkTables.Checked; + SQLOption.Ignore.FilterColumnCollation = chkTablesColumnCollation.Checked && chkTables.Checked; + SQLOption.Ignore.FilterColumnOrder = chkTablesColumnOrder.Checked && chkTables.Checked; + SQLOption.Ignore.FilterTableOption = chkTableOption.Checked && chkTables.Checked; + SQLOption.Ignore.FilterTableLockEscalation = chkTableLockEscalation.Checked && chkTables.Checked; + SQLOption.Ignore.FilterTableChangeTracking = chkTableChangeTracking.Checked && chkTables.Checked; + + SQLOption.Ignore.FilterTableFileGroup = chkFileGroups.Checked; + SQLOption.Ignore.FilterTrigger = chkCompTriggers.Checked; + SQLOption.Ignore.FilterDDLTriggers = chkCompTriggersDDL.Checked; + SQLOption.Ignore.FilterUserDataType = chkCompUDT.Checked; + SQLOption.Ignore.FilterView = chkCompVistas.Checked; + SQLOption.Ignore.FilterXMLSchema = chkCompXMLSchemas.Checked; + SQLOption.Ignore.FilterExtendedProperties = chkCompExtendedProperties.Checked; + SQLOption.Ignore.FilterUsers = chkCompUsers.Checked; + SQLOption.Ignore.FilterRoles = chkCompRoles.Checked; + SQLOption.Ignore.FilterRules = chkCompRules.Checked; + SQLOption.Ignore.FilterFullText = chkFullText.Checked; + SQLOption.Ignore.FilterFullTextPath = chkFullTextPath.Checked; + SQLOption.Ignore.FilterSynonyms = IncludeSynonymsCheckBox.Checked; + + SQLOption.Ignore.FilterNotForReplication = chkIgnoreNotForReplication.Checked; + SQLOption.Script.AlterObjectOnSchemaBinding = optScriptSchemaBindingAlter.Checked; + + if (rdoCaseAutomatic.Checked) + SQLOption.Comparison.CaseSensityType = SqlOptionComparison.CaseSensityOptions.Automatic; + if (rdoCaseInsensitive.Checked) + SQLOption.Comparison.CaseSensityType = SqlOptionComparison.CaseSensityOptions.CaseInsensity; + if (rdoCaseSensitive.Checked) + SQLOption.Comparison.CaseSensityType = SqlOptionComparison.CaseSensityOptions.CaseSensity; + + if (rdoCaseInsensityInCode.Checked) + SQLOption.Comparison.CaseSensityInCode = SqlOptionComparison.CaseSensityOptions.CaseInsensity; + if (rdoCaseSensityInCode.Checked) + SQLOption.Comparison.CaseSensityInCode = SqlOptionComparison.CaseSensityOptions.CaseSensity; + + SQLOption.Comparison.IgnoreWhiteSpacesInCode = chkIgnoreWhiteSpaceInCode.Checked; + SQLOption.Comparison.ReloadComparisonOnUpdate = chkReloadDB.Checked; + + FireOptionChanged(SQLOption); + } + public Abstractions.Schema.Model.IOption GetOption() + { + return SQLOption; + } + + private void chkCompIndices_CheckedChanged(object sender, EventArgs e) + { + chkIndexFillFactor.Enabled = chkIndex.Checked; + chkIndexIncludeColumns.Enabled = chkIndex.Checked; + chkIndexFilter.Enabled = chkIndex.Checked; + chkIndexRowLock.Enabled = chkIndex.Checked; + } + + private void chkCompTablas_CheckedChanged(object sender, EventArgs e) + { + chkTablesColumnCollation.Enabled = chkTables.Checked; + chkTablesColumnIdentity.Enabled = chkTables.Checked; + chkTablesColumnOrder.Enabled = chkTables.Checked; + chkTableChangeTracking.Enabled = chkTables.Checked; + chkTableLockEscalation.Enabled = chkTables.Checked; + chkTableOption.Enabled = chkTables.Checked; + } + + private void btnApply_Click(object sender, EventArgs e) + { + if (lstFilters.SelectedItems.Count > 0) + { + AddExclusionPatternForm itemForm = new AddExclusionPatternForm(SQLOption, lstFilters.SelectedItems[0].Index); + itemForm.ShowDialog(this); + } + } + + private void btnAdd_Click(object sender, EventArgs e) + { + AddExclusionPatternForm itemForm = new AddExclusionPatternForm(SQLOption); + itemForm.ShowDialog(this); + } + + private void chkConstraints_CheckedChanged(object sender, EventArgs e) + { + chkConstraintsFK.Enabled = chkConstraints.Checked; + chkConstraintsPK.Enabled = chkConstraints.Checked; + chkConstraintsUK.Enabled = chkConstraints.Checked; + chkConstraintsCheck.Enabled = chkConstraints.Checked; + } + + private void chkFullText_CheckedChanged(object sender, EventArgs e) + { + chkFullTextPath.Enabled = chkFullText.Checked; + } + + private void chkCompAssemblys_CheckedChanged(object sender, EventArgs e) + { + chkCompCLRStore.Enabled = chkCompAssemblys.Checked; + chkCompCLRTrigger.Enabled = chkCompAssemblys.Checked; + chkCompCLRFunctions.Enabled = chkCompAssemblys.Checked; + chkCompCLRUDT.Enabled = chkCompAssemblys.Checked; + } + + private void DeleteNameFilterButton_Click(object sender, EventArgs e) + { + if (lstFilters.SelectedItems.Count > 0) + { + foreach (ListViewItem item in lstFilters.Items) + { + if (item.Selected) + { + var type = (ObjectType)Enum.Parse(typeof(ObjectType), item.SubItems[1].Text); + var fi = new SqlOptionFilterItem(type, item.Text); + if (SQLOption.Filters.Items.Contains(fi)) + SQLOption.Filters.Items.Remove(fi); + } + } + LoadFilters(); + } + } + + private void lstFilters_DoubleClick(object sender, EventArgs e) + { + if (lstFilters.SelectedItems.Count > 0) + { + AddExclusionPatternForm itemForm = new AddExclusionPatternForm(SQLOption, lstFilters.SelectedItems[0].Index); + itemForm.ShowDialog(this); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/SqlOptionsFront.resx b/OpenDBDiff.SqlServer.Ui/Front/SqlOptionsFront.resx new file mode 100644 index 0000000..d58980a --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/SqlOptionsFront.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Ui/Front/SqlServerConnectFront.Designer.cs b/OpenDBDiff.SqlServer.Ui/Front/SqlServerConnectFront.Designer.cs new file mode 100644 index 0000000..b20a0dd --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/SqlServerConnectFront.Designer.cs @@ -0,0 +1,237 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.SqlServer.Ui +{ + partial class SqlServerConnectFront + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.txtPassword = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.cboServer = new System.Windows.Forms.ComboBox(); + this.cboAuthentication = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); + this.cboDatabase = new System.Windows.Forms.ComboBox(); + this.label6 = new System.Windows.Forms.Label(); + this.txtUsername = new System.Windows.Forms.TextBox(); + this.btnTest = new System.Windows.Forms.Button(); + this.lblName = new System.Windows.Forms.Label(); + this.gradientPanel1 = new System.Windows.Forms.Panel(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.gradientPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // txtPassword + // + this.txtPassword.Location = new System.Drawing.Point(82, 107); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.PasswordChar = '*'; + this.txtPassword.Size = new System.Drawing.Size(180, 20); + this.txtPassword.TabIndex = 3; + this.txtPassword.TextChanged += new System.EventHandler(this.txtPassword_TextChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(3, 110); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(56, 13); + this.label4.TabIndex = 16; + this.label4.Text = "Password:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(3, 84); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(58, 13); + this.label3.TabIndex = 15; + this.label3.Text = "Username:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(3, 31); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(66, 13); + this.label2.TabIndex = 14; + this.label2.Text = "Server Host:"; + // + // cboServer + // + this.cboServer.FormattingEnabled = true; + this.cboServer.Items.AddRange(new object[] { + "(local)"}); + this.cboServer.Location = new System.Drawing.Point(82, 28); + this.cboServer.Name = "cboServer"; + this.cboServer.Size = new System.Drawing.Size(180, 21); + this.cboServer.TabIndex = 0; + this.cboServer.SelectedIndexChanged += new System.EventHandler(this.cboServer_SelectedIndexChanged); + this.cboServer.DropDown += new System.EventHandler(this.cboServer_DropDown); + this.cboServer.TextChanged += new System.EventHandler(this.cboServer_TextChanged); + // + // cboAuthentication + // + this.cboAuthentication.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cboAuthentication.FormattingEnabled = true; + this.cboAuthentication.Items.AddRange(new object[] { + "Windows Authentication", + "SQL Server Authentication"}); + this.cboAuthentication.Location = new System.Drawing.Point(82, 55); + this.cboAuthentication.Name = "cboAuthentication"; + this.cboAuthentication.Size = new System.Drawing.Size(180, 21); + this.cboAuthentication.TabIndex = 1; + this.cboAuthentication.SelectedIndexChanged += new System.EventHandler(this.cboAuthentication_SelectedIndexChanged); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(3, 58); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(75, 13); + this.label5.TabIndex = 20; + this.label5.Text = "Authentication"; + // + // cboDatabase + // + this.cboDatabase.FormattingEnabled = true; + this.cboDatabase.Location = new System.Drawing.Point(82, 133); + this.cboDatabase.Name = "cboDatabase"; + this.cboDatabase.Size = new System.Drawing.Size(223, 21); + this.cboDatabase.TabIndex = 4; + this.cboDatabase.DropDown += new System.EventHandler(this.cboDatabase_DropDown); + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(3, 136); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(56, 13); + this.label6.TabIndex = 23; + this.label6.Text = "Database:"; + // + // txtUsername + // + this.txtUsername.Location = new System.Drawing.Point(82, 81); + this.txtUsername.Name = "txtUsername"; + this.txtUsername.Size = new System.Drawing.Size(180, 20); + this.txtUsername.TabIndex = 2; + this.txtUsername.TextChanged += new System.EventHandler(this.txtUsername_TextChanged); + // + // btnTest + // + this.btnTest.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnTest.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.btnTest.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnTest.Location = new System.Drawing.Point(327, 126); + this.btnTest.Name = "btnTest"; + this.btnTest.Size = new System.Drawing.Size(54, 28); + this.btnTest.TabIndex = 5; + this.btnTest.Text = "Test"; + this.btnTest.UseVisualStyleBackColor = true; + this.btnTest.Click += new System.EventHandler(this.btnTest_Click); + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblName.Location = new System.Drawing.Point(17, 5); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(105, 13); + this.lblName.TabIndex = 24; + this.lblName.Text = "Source Database"; + // + // gradientPanel1 + // + this.gradientPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gradientPanel1.Controls.Add(this.pictureBox1); + this.gradientPanel1.Controls.Add(this.lblName); + this.gradientPanel1.Location = new System.Drawing.Point(0, 0); + this.gradientPanel1.Name = "gradientPanel1"; + this.gradientPanel1.Size = new System.Drawing.Size(384, 24); + this.gradientPanel1.TabIndex = 26; + // + // pictureBox1 + // + this.pictureBox1.BackColor = System.Drawing.Color.Transparent; + this.pictureBox1.Image = global::OpenDBDiff.SqlServer.Ui.Properties.Resources.database_yellow; + this.pictureBox1.Location = new System.Drawing.Point(2, 3); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(15, 18); + this.pictureBox1.TabIndex = 27; + this.pictureBox1.TabStop = false; + // + // SqlServerConnectFront + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.White; + this.Controls.Add(this.gradientPanel1); + this.Controls.Add(this.cboDatabase); + this.Controls.Add(this.label6); + this.Controls.Add(this.btnTest); + this.Controls.Add(this.cboAuthentication); + this.Controls.Add(this.label5); + this.Controls.Add(this.cboServer); + this.Controls.Add(this.txtPassword); + this.Controls.Add(this.txtUsername); + this.Controls.Add(this.label4); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Name = "SqlServerConnectFront"; + this.Size = new System.Drawing.Size(384, 156); + this.gradientPanel1.ResumeLayout(false); + this.gradientPanel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private TextBox txtPassword; + private TextBox txtUsername; + private Label label4; + private Label label3; + private Label label2; + private ComboBox cboServer; + private ComboBox cboAuthentication; + private Label label5; + private Button btnTest; + private ComboBox cboDatabase; + private Label label6; + private Label lblName; + private Panel gradientPanel1; + private PictureBox pictureBox1; + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/SqlServerConnectFront.cs b/OpenDBDiff.SqlServer.Ui/Front/SqlServerConnectFront.cs new file mode 100644 index 0000000..6d4f8dd --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/SqlServerConnectFront.cs @@ -0,0 +1,339 @@ +using OpenDBDiff.SqlServer.Ui.Util; +using OpenDBDiff.Abstractions.Ui; +using System; +using System.Data.SqlClient; +using System.Windows.Forms; + +namespace OpenDBDiff.SqlServer.Ui +{ + public partial class SqlServerConnectFront : UserControl, IFront + { + private Boolean isDatabaseFilled = false; + private Boolean isServerFilled = false; + + private delegate void clearCombo(); + + private delegate void addCombo(string item); + + public SqlServerConnectFront() + { + InitializeComponent(); + cboAuthentication.SelectedIndex = 1; + } + + private void cboAuthentication_SelectedIndexChanged(object sender, EventArgs e) + { + txtUsername.Enabled = cboAuthentication.SelectedIndex == 1; + txtPassword.Enabled = cboAuthentication.SelectedIndex == 1; + isDatabaseFilled = false; + ClearDatabase(); + } + + public string ErrorConnection { get; private set; } + + public bool UseWindowsAuthentication + { + get + { + return cboAuthentication.SelectedIndex == 0; + } + set + { + cboAuthentication.SelectedIndex = (value ? 0 : 1); + } + } + + public string DatabaseName + { + get { return cboDatabase.Text; } + set { cboDatabase.Text = value; } + } + + public string UserName + { + get { return txtUsername.Text; } + set { txtUsername.Text = value; } + } + + public string Password + { + get { return txtPassword.Text; } + set { txtPassword.Text = value; } + } + + public override string Text + { + get { return lblName.Text; } + set { lblName.Text = value; } + } + + public string ServerName + { + get { return cboServer.Text; } + set { cboServer.Text = value; } + } + + public Boolean TestConnection() + { + try + { + using (SqlConnection connection = new SqlConnection()) + { + connection.ConnectionString = this.ConnectionString; + connection.Open(); + connection.Close(); + return true; + } + } + catch (Exception ex) + { + ErrorConnection = ex.Message; + return false; + } + } + + private string BuildConnectionString(string server, string database) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); + builder.DataSource = server.Trim(); + + // if database is ommitted the connection will be established to the default database for the user + if (!string.IsNullOrEmpty(database)) + builder.InitialCatalog = database.Trim(); + + builder.IntegratedSecurity = true; + return builder.ConnectionString; + } + + private string BuildConnectionString(string server, string database, string username, string password) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(BuildConnectionString(server, database)); + + builder.IntegratedSecurity = false; + builder.UserID = username; + builder.Password = password; + return builder.ConnectionString; + } + + public string ConnectionStringToDefaultDatabase + { + get + { + if (cboAuthentication.SelectedIndex == 1) + return BuildConnectionString(cboServer.Text, null, txtUsername.Text, txtPassword.Text); + else + return BuildConnectionString(cboServer.Text, null); + } + } + + public string ConnectionStringToMasterDatabase + { + get + { + if (cboAuthentication.SelectedIndex == 1) + return BuildConnectionString(cboServer.Text, "master", txtUsername.Text, txtPassword.Text); + else + return BuildConnectionString(cboServer.Text, "master"); + } + } + + public string ConnectionString + { + get + { + if (cboAuthentication.SelectedIndex == 1) + return BuildConnectionString(cboServer.Text, cboDatabase.Text, txtUsername.Text, txtPassword.Text); + else + return BuildConnectionString(cboServer.Text, cboDatabase.Text); + } + set + { + if (!String.IsNullOrWhiteSpace(value)) + { + var builder = new SqlConnectionStringBuilder(value); + + ServerName = builder.DataSource; + UseWindowsAuthentication = builder.IntegratedSecurity; + if (UseWindowsAuthentication) + { + UserName = ""; + Password = ""; + } + else + { + UserName = builder.UserID; + Password = builder.Password; + } + DatabaseName = builder.InitialCatalog; + } + else + { + cboAuthentication.SelectedIndex = 1; + UserName = ""; + Password = ""; + ServerName = "(local)"; + DatabaseName = ""; + } + } + } + + public Control Control + { + get + { + return this; + } + } + + private void btnTest_Click(object sender, EventArgs e) + { + if (TestConnection()) + MessageBox.Show(this, "Test successful!", "Test", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show(this, "Test failed!\r\n" + ErrorConnection, "Test", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + private void AddComboItem(string item) + { + if (!InvokeRequired) + cboDatabase.Items.Add(item); + else + { + addCombo add = new addCombo(AddComboItem); + Invoke(add, new string[] { item }); + } + } + + private void ClearDatabase() + { + if (!InvokeRequired) + cboDatabase.Items.Clear(); + else + { + clearCombo clear = new clearCombo(ClearDatabase); + Invoke(clear); + } + } + + private void FillDatabase() + { + if (!isDatabaseFilled) + { + String connectionString = ConnectionStringToDefaultDatabase; + ClearDatabase(); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + conn.Open(); + using (SqlCommand command = new SqlCommand("SELECT name,database_id FROM sys.databases ORDER BY Name", conn)) + { + using (SqlDataReader reader = command.ExecuteReader()) + { + while (reader.Read()) + { + AddComboItem(reader["Name"].ToString()); + } + isDatabaseFilled = true; + } + } + } + } + } + + private void cboServer_SelectedIndexChanged(object sender, EventArgs e) + { + isDatabaseFilled = false; + } + + private void txtUsername_TextChanged(object sender, EventArgs e) + { + isDatabaseFilled = false; + ClearDatabase(); + } + + private void txtPassword_TextChanged(object sender, EventArgs e) + { + isDatabaseFilled = false; + ClearDatabase(); + } + + private void cboServer_DropDown(object sender, EventArgs e) + { + try + { + if (!isServerFilled) + { + this.Cursor = Cursors.WaitCursor; + SqlServerList.Get().ForEach(item => cboServer.Items.Add(item)); + isServerFilled = true; + } + } + catch (Exception ex) + { + MessageBox.Show(this, ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + Cursor = Cursors.Default; + } + } + + private void cboDatabase_DropDown(object sender, EventArgs e) + { + try + { + this.Cursor = Cursors.WaitCursor; + FillDatabase(); + } + catch (Exception ex) + { + this.Cursor = Cursors.Default; + cboDatabase.Items.Clear(); + MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + this.Cursor = Cursors.Default; + } + } + + private void cboServer_TextChanged(object sender, EventArgs e) + { + isDatabaseFilled = false; + } + + public override string ToString() + { + return string.Format($"Server: {ServerName}, Database: {DatabaseName}"); + } + + public object Clone() + { + var clone = new SqlServerConnectFront + { + ServerName = this.ServerName, + UseWindowsAuthentication = this.UseWindowsAuthentication, + UserName = this.UserName, + Password = this.Password, + DatabaseName = this.DatabaseName + }; + + clone.Location = new System.Drawing.Point(1, 1); + clone.Name = "SourceControl"; + clone.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + + return clone; + } + + public void SetSettingsFrom(IFront other) + { + if (other is SqlServerConnectFront sql) + { + this.ServerName = sql.ServerName; + this.DatabaseName = sql.DatabaseName; + this.UseWindowsAuthentication = sql.UseWindowsAuthentication; + this.UserName = sql.UserName; + this.Password = sql.Password; + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Front/SqlServerConnectFront.resx b/OpenDBDiff.SqlServer.Ui/Front/SqlServerConnectFront.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/SqlServerConnectFront.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Ui/Front/Util/SqlServerList.cs b/OpenDBDiff.SqlServer.Ui/Front/Util/SqlServerList.cs new file mode 100644 index 0000000..da68f7d --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Front/Util/SqlServerList.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Data; +using System.Data.Sql; + +namespace OpenDBDiff.SqlServer.Ui.Util +{ + internal static class SqlServerList + { + public static List Get() + { + SqlDataSourceEnumerator sqlSource = SqlDataSourceEnumerator.Instance; + DataTable dt = sqlSource.GetDataSources(); + + List serverList = new List(); + string serverName = null; + string instanceName = null; + + foreach (DataRow dr in dt.Rows) + { + serverName = dr["ServerName"].ToString(); + instanceName = dr["InstanceName"] != null ? dr["InstanceName"].ToString() : null; + + if (string.IsNullOrEmpty(instanceName)) + serverList.Add(serverName); + else + serverList.Add(string.Format("{0}\\{1}", serverName, instanceName)); + } + + return serverList; + } + } +} diff --git a/OpenDBDiff.SqlServer.Ui/OpenDBDiff.SqlServer.Ui.csproj b/OpenDBDiff.SqlServer.Ui/OpenDBDiff.SqlServer.Ui.csproj new file mode 100644 index 0000000..76fbf7d --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/OpenDBDiff.SqlServer.Ui.csproj @@ -0,0 +1,171 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {EF2F571E-A7AD-40BE-8500-50A039159FC1} + Library + Properties + OpenDBDiff.SqlServer.Ui + OpenDBDiff.SqlServer.Ui + false + + + + + 3.5 + + + v4.5.2 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + -Microsoft.Naming#CA1702;-Microsoft.Naming#CA1700;-Microsoft.Naming#CA1712;-Microsoft.Naming#CA1713;-Microsoft.Naming#CA1714;-Microsoft.Naming#CA1709;-Microsoft.Naming#CA1704;-Microsoft.Naming#CA1708;-Microsoft.Naming#CA1715;-Microsoft.Naming#CA1710;-Microsoft.Naming#CA1720;-Microsoft.Naming#CA1707;-Microsoft.Naming#CA1722;-Microsoft.Naming#CA1711;-Microsoft.Naming#CA1716;-Microsoft.Naming#CA1717;-Microsoft.Naming#CA1725;-Microsoft.Naming#CA1719;-Microsoft.Naming#CA1721;-Microsoft.Naming#CA1701;-Microsoft.Naming#CA1703;-Microsoft.Naming#CA1724;-Microsoft.Naming#CA1726 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + -Microsoft.Naming#CA1702;-Microsoft.Naming#CA1700;-Microsoft.Naming#CA1712;-Microsoft.Naming#CA1713;-Microsoft.Naming#CA1714;-Microsoft.Naming#CA1709;-Microsoft.Naming#CA1704;-Microsoft.Naming#CA1708;-Microsoft.Naming#CA1715;-Microsoft.Naming#CA1710;-Microsoft.Naming#CA1720;-Microsoft.Naming#CA1707;-Microsoft.Naming#CA1722;-Microsoft.Naming#CA1711;-Microsoft.Naming#CA1716;-Microsoft.Naming#CA1717;-Microsoft.Naming#CA1725;-Microsoft.Naming#CA1719;-Microsoft.Naming#CA1721;-Microsoft.Naming#CA1701;-Microsoft.Naming#CA1703;-Microsoft.Naming#CA1724;-Microsoft.Naming#CA1726 + AnyCPU + + + true + + + + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + Form + + + AddExclusionPatternForm.cs + + + + UserControl + + + SqlOptionsFront.cs + + + + UserControl + + + SqlServerConnectFront.cs + + + + + + + True + True + Resources.resx + + + + + {406558a0-1b98-4d0e-b8b6-2013700b065a} + OpenDBDiff.Abstractions.Schema + + + {e82cfc94-de8c-4edd-aa0c-f78abae03768} + OpenDBDiff.Abstractions.Ui + + + {32ac9af6-db93-4354-b69f-6dbc65c70867} + OpenDBDiff.SqlServer.Schema + + + + + .editorconfig + + + + + AddExclusionPatternForm.cs + Designer + + + Designer + SqlOptionsFront.cs + + + SqlServerConnectFront.cs + Designer + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + + + + + + \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Ui/Properties/AssemblyInfo.cs b/OpenDBDiff.SqlServer.Ui/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..488ad94 --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security.Permissions; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.SqlServer.Ui")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.SqlServer.Ui")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("4f1e8d72-25ec-41e6-b56a-0091796271c8")] + +[assembly: CLSCompliant(true)] +[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)] diff --git a/OpenDBDiff.SqlServer.Ui/Properties/Resources.Designer.cs b/OpenDBDiff.SqlServer.Ui/Properties/Resources.Designer.cs new file mode 100644 index 0000000..0c763d2 --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace OpenDBDiff.SqlServer.Ui.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OpenDBDiff.SqlServer.Ui.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap database_yellow { + get { + object obj = ResourceManager.GetObject("database_yellow", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/OpenDBDiff.SqlServer.Ui/Properties/Resources.resx b/OpenDBDiff.SqlServer.Ui/Properties/Resources.resx new file mode 100644 index 0000000..2ea7dea --- /dev/null +++ b/OpenDBDiff.SqlServer.Ui/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\database_yellow.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/OpenDBDiff.SqlServer.Ui/Resources/database_yellow.png b/OpenDBDiff.SqlServer.Ui/Resources/database_yellow.png new file mode 100644 index 0000000..45858a1 Binary files /dev/null and b/OpenDBDiff.SqlServer.Ui/Resources/database_yellow.png differ diff --git a/OpenDBDiff.Tests/Generates/Util/ByteToHexEncoderTests.cs b/OpenDBDiff.Tests/Generates/Util/ByteToHexEncoderTests.cs new file mode 100644 index 0000000..c52c723 --- /dev/null +++ b/OpenDBDiff.Tests/Generates/Util/ByteToHexEncoderTests.cs @@ -0,0 +1,19 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenDBDiff.SqlServer.Schema.Generates.Util; + +namespace OpenDBDiff.Tests.Generates.Utils.Tests +{ + [TestClass] + public class ByteToHexEncoderTests + { + [TestMethod] + public void EncodesBytesIntoHex() + { + byte[] bytes = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 255 }; + + var hex = ByteToHexEncoder.ByteArrayToHex(bytes); + + Assert.AreEqual("0x000102040810204080FF", hex); + } + } +} diff --git a/OpenDBDiff.Tests/Model/ColumnsTests.cs b/OpenDBDiff.Tests/Model/ColumnsTests.cs new file mode 100644 index 0000000..57c5838 --- /dev/null +++ b/OpenDBDiff.Tests/Model/ColumnsTests.cs @@ -0,0 +1,236 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Compare; +using OpenDBDiff.SqlServer.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Options; +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.Tests.Model.Tests +{ + [TestClass()] + public class ColumnsTests + { + [TestMethod()] + public void OriginHasExtraColumn_NothingSelected_ShouldDropExtraColumn() + { + int idStorage = 1; + System.Func getId = new Func(()=>++idStorage); + + Database originDatabase = new Database(); + originDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS", + }; + originDatabase.Options = new SqlOption(); + originDatabase.Id = getId(); + Table originTable = new Table(originDatabase); + originTable.Name = "Example"; + originTable.Id = getId(); + var originColumn1 = new Column(originTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var originColumn2 = new Column(originTable) + { + Name = "Test2", + Type = "varchar(20)", + Id = getId() + }; + var originColumn3 = new Column(originTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + originTable.Columns.Add(originColumn1); + originTable.Columns.Add(originColumn3); + originTable.Columns.Add(originColumn2); + originDatabase.Tables.Add(originTable); + + + Database destinationDatabase = new Database(); + destinationDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + destinationDatabase.Id = getId(); + destinationDatabase.Options = new SqlOption(); + Table destinationTable = new Table(destinationDatabase); + destinationTable.Name = "Example"; + destinationTable.Id = getId(); + var destinationColumn1 = new Column(destinationTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var destinationColumn3 = new Column(destinationTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + destinationTable.Columns.Add(destinationColumn1); + destinationTable.Columns.Add(destinationColumn3); + destinationDatabase.Tables.Add(destinationTable); + + + originTable.OriginalTable = (Table)originTable.Clone((Database)originTable.Parent); + new CompareColumns().GenerateDifferences
(originTable.Columns, destinationTable.Columns); + + SQLScriptList sqlList = originTable.ToSqlDiff(new List()); + string sql = sqlList.ToSQL(); + Assert.AreEqual(originColumn2.ToSqlDrop(), sql); + } + [TestMethod()] + public void OriginHasExtraColumn_NotChangedColumnSelected_ShouldBeEmptyScript() + { + int idStorage = 1; + System.Func getId = new Func(() => ++idStorage); + Database originDatabase = new Database(); + originDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + originDatabase.Id = getId(); + originDatabase.Options = new SqlOption(); + Table originTable = new Table(originDatabase); + originTable.Name = "Example"; + originTable.Id = getId(); + var originColumn1 = new Column(originTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var originColumn2 = new Column(originTable) + { + Name = "Test2", + Type = "varchar(20)", + Id = getId() + }; + var originColumn3 = new Column(originTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + originTable.Columns.Add(originColumn1); + originTable.Columns.Add(originColumn3); + originTable.Columns.Add(originColumn2); + originDatabase.Tables.Add(originTable); + + + Database destinationDatabase = new Database(); + destinationDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + destinationDatabase.Id = getId(); + destinationDatabase.Options = new SqlOption(); + Table destinationTable = new Table(destinationDatabase); + destinationTable.Name = "Example"; + destinationTable.Id = getId(); + var destinationColumn1 = new Column(destinationTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var destinationColumn3 = new Column(destinationTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + destinationTable.Columns.Add(destinationColumn1); + destinationTable.Columns.Add(destinationColumn3); + destinationDatabase.Tables.Add(destinationTable); + + + originTable.OriginalTable = (Table)originTable.Clone((Database)originTable.Parent); + new CompareColumns().GenerateDifferences
(originTable.Columns, destinationTable.Columns); + + SQLScriptList sqlList = originTable.ToSqlDiff(new List() { originColumn3 }); + string sql = sqlList.ToSQL(); + Assert.AreEqual("", sql); + } + [TestMethod()] + public void OriginHasExtraColumn_ExtraColumnSelected_ShouldBeDropColumnScript() + { + int idStorage = 1; + System.Func getId = new Func(() => ++idStorage); + Database originDatabase = new Database(); + originDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + originDatabase.Id = getId(); + originDatabase.Options = new SqlOption(); + Table originTable = new Table(originDatabase); + originTable.Name = "Example"; + originTable.Id = getId(); + var originColumn1 = new Column(originTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var originColumn2 = new Column(originTable) + { + Name = "Test2", + Type = "varchar(20)", + Id = getId() + }; + var originColumn3 = new Column(originTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + originTable.Columns.Add(originColumn1); + originTable.Columns.Add(originColumn3); + originTable.Columns.Add(originColumn2); + originDatabase.Tables.Add(originTable); + + + Database destinationDatabase = new Database(); + destinationDatabase.Info = new DatabaseInfo() + { + Collation = "SQL_Latin1_General_CP1_CI_AS" + }; + destinationDatabase.Id = getId(); + destinationDatabase.Options = new SqlOption(); + Table destinationTable = new Table(destinationDatabase); + destinationTable.Name = "Example"; + destinationTable.Id = getId(); + var destinationColumn1 = new Column(destinationTable) + { + Name = "Test", + Type = "int", + Id = getId() + }; + var destinationColumn3 = new Column(destinationTable) + { + Name = "Test3", + Type = "bigint", + Id = getId() + }; + destinationTable.Columns.Add(destinationColumn1); + destinationTable.Columns.Add(destinationColumn3); + destinationDatabase.Tables.Add(destinationTable); + + + originTable.OriginalTable = (Table)originTable.Clone((Database)originTable.Parent); + new CompareColumns().GenerateDifferences
(originTable.Columns, destinationTable.Columns); + + SQLScriptList sqlList = originTable.ToSqlDiff(new List() { originColumn2 }); + string sql = sqlList.ToSQL(); + Assert.AreEqual(originColumn2.ToSqlDrop(), sql); + } + } +} diff --git a/OpenDBDiff.Tests/Model/FormatCodeTests.cs b/OpenDBDiff.Tests/Model/FormatCodeTests.cs new file mode 100644 index 0000000..ada4ed2 --- /dev/null +++ b/OpenDBDiff.Tests/Model/FormatCodeTests.cs @@ -0,0 +1,129 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.SqlServer.Schema.Model.Util; +using OpenDBDiff.Tests.Utils; +using System; + +namespace OpenDBDiff.Tests.Model.Tests +{ + [TestClass] + public class FormatCodeTests + { + private readonly ResourceFileExtractor extractor; + + public FormatCodeTests() + { + this.extractor = new ResourceFileExtractor(".SqlSnippets.Triggers."); + } + + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void FindAndNormalizeCreate_BrokenThrowsException() + { + var triggerItemMock = new Mock(); + triggerItemMock.Setup(x => x.FullName).Returns("[dbo].[iutrgTriggerName]"); + + FormatCode.FindAndNormalizeCreate(triggerItemMock.Object, extractor.ReadFileFromResource("broken.sql")); + } + + [TestMethod] + public void FindAndNormalizeCreate_NoBracket_ShouldNormalize() + { + var triggerItemMock = new Mock(); + triggerItemMock.Setup(x => x.FullName).Returns("[dbo].[iutrgTriggerName]"); + + var a = FormatCode.FindAndNormalizeCreate(triggerItemMock.Object, extractor.ReadFileFromResource("no-brackets.sql")); + + var normalized = extractor.ReadFileFromResource("normalized.sql"); + Assert.AreEqual(normalized, a.Body); + Assert.AreEqual(0, a.FindPosition); + } + + [TestMethod] + public void FindAndNormalizeCreate_NoOwner_ShouldNormalize() + { + var triggerItemMock = new Mock(); + triggerItemMock.Setup(x => x.FullName).Returns("[dbo].[iutrgTriggerName]"); + + var a = FormatCode.FindAndNormalizeCreate(triggerItemMock.Object, extractor.ReadFileFromResource("no-owner.sql")); + + var normalized = extractor.ReadFileFromResource("normalized.sql"); + Assert.AreEqual(normalized, a.Body); + Assert.AreEqual(0, a.FindPosition); + } + + [TestMethod] + public void FindAndNormalizeCreate_NormalizedSql_ShouldKeepSourceText() + { + var triggerItemMock = new Mock(); + triggerItemMock.Setup(x => x.FullName).Returns("[dbo].[iutrgTriggerName]"); + + var normalized = extractor.ReadFileFromResource("normalized.sql"); + var a = FormatCode.FindAndNormalizeCreate(triggerItemMock.Object, normalized); + + Assert.AreEqual(normalized, a.Body); + Assert.AreEqual(0, a.FindPosition); + } + + [TestMethod] + public void FindAndNormalizeCreate_WithComment_ShouldNormalize() + { + var triggerItemMock = new Mock(); + triggerItemMock.Setup(x => x.FullName).Returns("[dbo].[iutrgTriggerName]"); + + var a = FormatCode.FindAndNormalizeCreate(triggerItemMock.Object, extractor.ReadFileFromResource("with-comments.sql")); + + var normalized = extractor.ReadFileFromResource("normalized.sql"); + Assert.AreEqual(62, a.FindPosition); + Assert.AreEqual(normalized, a.Body.Substring(a.FindPosition)); + } + + [TestMethod] + public void FindCreate_BrokenReturnsNull() + { + var findResult = FormatCode.FindCreate(extractor.ReadFileFromResource("broken.sql")); + Assert.IsNull(findResult); + } + + [TestMethod] + public void FindCreate_NoBracket_ShouldFindTheCreatePositions() + { + var findResult = FormatCode.FindCreate(extractor.ReadFileFromResource("no-brackets.sql")); + + Assert.AreEqual(0, findResult.CreateBeginPosition); + Assert.AreEqual(13, findResult.TypeEndPosition); + Assert.AreEqual(30, findResult.NameEndPosition); + } + + [TestMethod] + public void FindCreate_NoOwner_ShouldFindTheCreatePositions() + { + var findResult = FormatCode.FindCreate(extractor.ReadFileFromResource("no-owner.sql")); + + Assert.AreEqual(0, findResult.CreateBeginPosition); + Assert.AreEqual(13, findResult.TypeEndPosition); + Assert.AreEqual(32, findResult.NameEndPosition); + } + + [TestMethod] + public void FindCreate_Normalized_ShouldFindTheCreatePositions() + { + var findResult = FormatCode.FindCreate(extractor.ReadFileFromResource("normalized.sql")); + + Assert.AreEqual(0, findResult.CreateBeginPosition); + Assert.AreEqual(13, findResult.TypeEndPosition); + Assert.AreEqual(38, findResult.NameEndPosition); + } + + [TestMethod] + public void FindCreate_WithComment_ShouldFindTheCreatePositions() + { + var findResult = FormatCode.FindCreate(extractor.ReadFileFromResource("with-comments.sql")); + + Assert.AreEqual(62, findResult.CreateBeginPosition); + Assert.AreEqual(75, findResult.TypeEndPosition); + Assert.AreEqual(100, findResult.NameEndPosition); + } + } +} diff --git a/OpenDBDiff.Tests/OpenDBDiff.Tests.csproj b/OpenDBDiff.Tests/OpenDBDiff.Tests.csproj new file mode 100644 index 0000000..c616a09 --- /dev/null +++ b/OpenDBDiff.Tests/OpenDBDiff.Tests.csproj @@ -0,0 +1,133 @@ + + + + Debug + AnyCPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F} + Library + Properties + OpenDBDiff.Tests + OpenDBDiff.Tests + v4.5.2 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + + ..\packages\Castle.Core.4.4.1\lib\net45\Castle.Core.dll + + + ..\packages\Moq.4.7.145\lib\net45\Moq.dll + + + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll + + + ..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll + + + + + + + + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + + + + {406558a0-1b98-4d0e-b8b6-2013700b065a} + OpenDBDiff.Abstractions.Schema + + + {32AC9AF6-DB93-4354-B69F-6DBC65C70867} + OpenDBDiff.SqlServer.Schema + + + + + .editorconfig + + + + + + + + + + + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/OpenDBDiff.Tests/Properties/AssemblyInfo.cs b/OpenDBDiff.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9725f81 --- /dev/null +++ b/OpenDBDiff.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff.Tests")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("94f5c91a-6268-41e9-a15e-fa5451bb2b6f")] diff --git a/OpenDBDiff.Tests/SqlSnippets/Triggers/broken.sql b/OpenDBDiff.Tests/SqlSnippets/Triggers/broken.sql new file mode 100644 index 0000000..4227755 --- /dev/null +++ b/OpenDBDiff.Tests/SqlSnippets/Triggers/broken.sql @@ -0,0 +1,7 @@ +EATE TRIGGER iutrgTriggerName ON dbo.TableName +FOR INSERT, UPDATE +AS +UPDATE TableName +SET TableName.SomeColumn = 'something' +FROM inserted,TableName +WHERE inserted.TableNameId = TableName.TableNameId diff --git a/OpenDBDiff.Tests/SqlSnippets/Triggers/no-brackets.sql b/OpenDBDiff.Tests/SqlSnippets/Triggers/no-brackets.sql new file mode 100644 index 0000000..69a57ef --- /dev/null +++ b/OpenDBDiff.Tests/SqlSnippets/Triggers/no-brackets.sql @@ -0,0 +1,7 @@ +CREATE TRIGGER iutrgTriggerName ON dbo.TableName +FOR INSERT, UPDATE +AS +UPDATE TableName +SET TableName.SomeColumn = 'something' +FROM inserted,TableName +WHERE inserted.TableNameId = TableName.TableNameId diff --git a/OpenDBDiff.Tests/SqlSnippets/Triggers/no-owner.sql b/OpenDBDiff.Tests/SqlSnippets/Triggers/no-owner.sql new file mode 100644 index 0000000..c2fd7d4 --- /dev/null +++ b/OpenDBDiff.Tests/SqlSnippets/Triggers/no-owner.sql @@ -0,0 +1,7 @@ +CREATE TRIGGER [iutrgTriggerName] ON dbo.TableName +FOR INSERT, UPDATE +AS +UPDATE TableName +SET TableName.SomeColumn = 'something' +FROM inserted,TableName +WHERE inserted.TableNameId = TableName.TableNameId diff --git a/OpenDBDiff.Tests/SqlSnippets/Triggers/normalized.sql b/OpenDBDiff.Tests/SqlSnippets/Triggers/normalized.sql new file mode 100644 index 0000000..91fdb4a --- /dev/null +++ b/OpenDBDiff.Tests/SqlSnippets/Triggers/normalized.sql @@ -0,0 +1,7 @@ +CREATE TRIGGER [dbo].[iutrgTriggerName] ON dbo.TableName +FOR INSERT, UPDATE +AS +UPDATE TableName +SET TableName.SomeColumn = 'something' +FROM inserted,TableName +WHERE inserted.TableNameId = TableName.TableNameId diff --git a/OpenDBDiff.Tests/SqlSnippets/Triggers/with-comments.sql b/OpenDBDiff.Tests/SqlSnippets/Triggers/with-comments.sql new file mode 100644 index 0000000..c1002b4 --- /dev/null +++ b/OpenDBDiff.Tests/SqlSnippets/Triggers/with-comments.sql @@ -0,0 +1,9 @@ +/* test comment CREATE TRIGGER [test] */ +-- Another comment +CREATE TRIGGER [dbo].[iutrgTriggerName] ON dbo.TableName +FOR INSERT, UPDATE +AS +UPDATE TableName +SET TableName.SomeColumn = 'something' +FROM inserted,TableName +WHERE inserted.TableNameId = TableName.TableNameId diff --git a/OpenDBDiff.Tests/Utils/ResourceFileExtractor.cs b/OpenDBDiff.Tests/Utils/ResourceFileExtractor.cs new file mode 100644 index 0000000..49bb3b0 --- /dev/null +++ b/OpenDBDiff.Tests/Utils/ResourceFileExtractor.cs @@ -0,0 +1,248 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +namespace OpenDBDiff.Tests.Utils +{ + /// + /// Summary description for ResourceFileExtractor. + /// + public sealed class ResourceFileExtractor + { + #region Static + + #region Private fields + + private static readonly IDictionary extractors = new ConcurrentDictionary(); + + #endregion Private fields + + #region Public properties + + /// Instance of resource extractor for executing assembly + public static ResourceFileExtractor Instance + { + get + { + Assembly _assembly = Assembly.GetCallingAssembly(); + string _key = _assembly.GetName().FullName; + if (!extractors.TryGetValue(_key, out ResourceFileExtractor extractor) + && !extractors.TryGetValue(_key, out extractor)) + { + extractor = new ResourceFileExtractor(_assembly, true, null); + extractors.Add(_key, extractor); + } + + return extractor; + } + } + + #endregion Public properties + + #endregion Static + + #region Private fields + + private readonly ResourceFileExtractor m_baseExtractor; + + #endregion Private fields + + #region Constructors + + /// + /// Create instance + /// + /// ResourceFilePath in assembly. Example: .Properties.Scripts. + /// + public ResourceFileExtractor(string resourceFilePath, ResourceFileExtractor baseExtractor) + : this(Assembly.GetCallingAssembly(), baseExtractor) + { + ResourceFilePath = resourceFilePath; + } + + /// + /// Create instance + /// + /// + public ResourceFileExtractor(ResourceFileExtractor baseExtractor) + : this(Assembly.GetCallingAssembly(), baseExtractor) + { + } + + /// + /// Create instance + /// + /// ResourceFilePath in assembly. Example: .Properties.Scripts. + public ResourceFileExtractor(string resourcePath) + : this(Assembly.GetCallingAssembly(), resourcePath) + { + } + + /// + /// Instance constructor + /// + /// + /// + public ResourceFileExtractor(Assembly assembly, string resourcePath) + : this(assembly ?? Assembly.GetCallingAssembly()) + { + ResourceFilePath = resourcePath; + } + + /// + /// Instance constructor + /// + public ResourceFileExtractor() + : this(Assembly.GetCallingAssembly()) + { + } + + /// + /// Instance constructor + /// + /// + public ResourceFileExtractor(Assembly assembly) + : this(assembly ?? Assembly.GetCallingAssembly(), (ResourceFileExtractor)null) + { + } + + /// + /// Instance constructor + /// + /// + /// + public ResourceFileExtractor(Assembly assembly, ResourceFileExtractor baseExtractor) + : this(assembly ?? Assembly.GetCallingAssembly(), false, baseExtractor) + { + } + + /// + /// Instance constructor + /// + /// + /// + /// + /// Argument is null. + private ResourceFileExtractor(Assembly assembly, bool isStatic, ResourceFileExtractor baseExtractor) + { + #region Check + + if (assembly is null) + { + throw new ArgumentNullException("assembly"); + } + + #endregion Check + + Assembly = assembly; + m_baseExtractor = baseExtractor; + AssemblyName = Assembly.GetName().Name; + IsStatic = isStatic; + ResourceFilePath = ".Resources."; + } + + #endregion Constructors + + #region Public properties + + /// Work assembly + public Assembly Assembly { get; } + + /// Work assembly name + public string AssemblyName { get; } + + public bool IsStatic { get; set; } + + /// + /// Path to read resource files. Example: .Resources.Upgrades. + /// + public string ResourceFilePath { get; } + + public IEnumerable GetFileNames(Func predicate = null) + { + predicate = predicate ?? (s => true); + + string _path = AssemblyName + ResourceFilePath; + foreach (string _resourceName in Assembly.GetManifestResourceNames()) + { + if (_resourceName.StartsWith(_path) && predicate(_resourceName)) + { + yield return _resourceName.Replace(_path, string.Empty); + } + } + } + + #endregion Public properties + + #region Public methods + + public string ReadFileFromResource(string fileName) + { + Stream _stream = ReadFileFromResourceToStream(fileName); + string _result; + StreamReader sr = new StreamReader(_stream); + try + { + _result = sr.ReadToEnd(); + } + finally + { + sr.Close(); + } + return _result; + } + + public string ReadFileFromResourceFormat(string fileName, params object[] formatArgs) + { + return string.Format(ReadFileFromResource(fileName), formatArgs); + } + + /// + /// Read file in current assembly by specific file name + /// + /// + /// + /// ApplicationException. + public Stream ReadFileFromResourceToStream(string fileName) + { + string _nameResFile = AssemblyName + ResourceFilePath + fileName; + Stream _stream = Assembly.GetManifestResourceStream(_nameResFile); + + #region Not found + + if (_stream is null) + { + #region Get from base extractor + + if (!(m_baseExtractor is null)) + { + return m_baseExtractor.ReadFileFromResourceToStream(fileName); + } + + #endregion Get from base extractor + + throw new ArgumentException("Can't find resource file " + _nameResFile, nameof(fileName)); + } + + #endregion Not found + + return _stream; + } + + /// + /// Read file in current assembly by specific path + /// + /// Specific path + /// Read file name + /// + public string ReadSpecificFileFromResource(string specificPath, string fileName) + { + ResourceFileExtractor _ext = new ResourceFileExtractor(Assembly, specificPath); + return _ext.ReadFileFromResource(fileName); + } + + #endregion Public methods + } +} diff --git a/OpenDBDiff.Tests/packages.config b/OpenDBDiff.Tests/packages.config new file mode 100644 index 0000000..f6e536c --- /dev/null +++ b/OpenDBDiff.Tests/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/OpenDBDiff.sln b/OpenDBDiff.sln new file mode 100644 index 0000000..eb5db29 --- /dev/null +++ b/OpenDBDiff.sln @@ -0,0 +1,118 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DBEC6CD3-5B8F-427C-8304-9BFD223C8B1D}" + ProjectSection(SolutionItems) = preProject + appveyor.yml = appveyor.yml + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDBDiff", "OpenDBDiff\OpenDBDiff.csproj", "{99A26820-E71D-4E01-ADF2-E6AB25B03FA0}" + ProjectSection(ProjectDependencies) = postProject + {E794AA28-EE68-44BD-827B-1BFD9C106B65} = {E794AA28-EE68-44BD-827B-1BFD9C106B65} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDBDiff.Abstractions.Schema", "OpenDBDiff.Abstractions.Schema\OpenDBDiff.Abstractions.Schema.csproj", "{406558A0-1B98-4D0E-B8B6-2013700B065A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDBDiff.SqlServer.Ui", "OpenDBDiff.SqlServer.Ui\OpenDBDiff.SqlServer.Ui.csproj", "{EF2F571E-A7AD-40BE-8500-50A039159FC1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDBDiff.Abstractions.Ui", "OpenDBDiff.Abstractions.Ui\OpenDBDiff.Abstractions.Ui.csproj", "{E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDBDiff.CLI", "OpenDBDiff.CLI\OpenDBDiff.CLI.csproj", "{E794AA28-EE68-44BD-827B-1BFD9C106B65}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{87023747-4D77-4CCA-A435-4FA32D133639}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDBDiff.SqlServer.Schema", "OpenDBDiff.SqlServer.Schema\OpenDBDiff.SqlServer.Schema.csproj", "{32AC9AF6-DB93-4354-B69F-6DBC65C70867}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenDBDiff.Tests", "OpenDBDiff.Tests\OpenDBDiff.Tests.csproj", "{94F5C91A-6268-41E9-A15E-FA5451BB2B6F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Debug|Win32.ActiveCfg = Debug|Any CPU + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Release|Any CPU.Build.0 = Release|Any CPU + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0}.Release|Win32.ActiveCfg = Release|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Debug|Win32.ActiveCfg = Debug|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Release|Any CPU.Build.0 = Release|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {406558A0-1B98-4D0E-B8B6-2013700B065A}.Release|Win32.ActiveCfg = Release|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Debug|Win32.ActiveCfg = Debug|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Release|Any CPU.Build.0 = Release|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {EF2F571E-A7AD-40BE-8500-50A039159FC1}.Release|Win32.ActiveCfg = Release|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Debug|Win32.ActiveCfg = Debug|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Release|Any CPU.Build.0 = Release|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E82CFC94-DE8C-4EDD-AA0C-F78ABAE03768}.Release|Win32.ActiveCfg = Release|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Debug|Win32.ActiveCfg = Debug|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Release|Any CPU.Build.0 = Release|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E794AA28-EE68-44BD-827B-1BFD9C106B65}.Release|Win32.ActiveCfg = Release|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Debug|Any CPU.Build.0 = Debug|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Debug|Win32.ActiveCfg = Debug|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Debug|Win32.Build.0 = Debug|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Release|Any CPU.ActiveCfg = Release|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Release|Any CPU.Build.0 = Release|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Release|Win32.ActiveCfg = Release|Any CPU + {32AC9AF6-DB93-4354-B69F-6DBC65C70867}.Release|Win32.Build.0 = Release|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Debug|Win32.ActiveCfg = Debug|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Debug|Win32.Build.0 = Debug|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Release|Any CPU.Build.0 = Release|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Release|Win32.ActiveCfg = Release|Any CPU + {94F5C91A-6268-41E9-A15E-FA5451BB2B6F}.Release|Win32.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/OpenDBDiff/App.config b/OpenDBDiff/App.config new file mode 100644 index 0000000..43de787 --- /dev/null +++ b/OpenDBDiff/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/OpenDBDiff/App.ico b/OpenDBDiff/App.ico new file mode 100644 index 0000000..6bd39cc Binary files /dev/null and b/OpenDBDiff/App.ico differ diff --git a/OpenDBDiff/ConnectionsSettings/ConnectionResource.cs b/OpenDBDiff/ConnectionsSettings/ConnectionResource.cs new file mode 100644 index 0000000..8814e92 --- /dev/null +++ b/OpenDBDiff/ConnectionsSettings/ConnectionResource.cs @@ -0,0 +1,13 @@ +namespace OpenDBDiff.ConnectionsSettings +{ + public class ConnectionResource + { + public string ConnectionStringDestination { get; set; } + + public string ConnectionStringSource { get; set; } + + public string Type { get; set; } + + public string Name { get; set; } + } +} diff --git a/OpenDBDiff/Extensions/ExceptionExtensions.cs b/OpenDBDiff/Extensions/ExceptionExtensions.cs new file mode 100644 index 0000000..c32c1ce --- /dev/null +++ b/OpenDBDiff/Extensions/ExceptionExtensions.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace OpenDBDiff.Front.Extensions +{ + public static class ExceptionExtensions + { + public static IEnumerable FlattenHierarchy(this Exception ex) + { + if (ex == null) + { + throw new ArgumentNullException("ex"); + } + + var innerException = ex; + do + { + yield return innerException; + innerException = innerException.InnerException; + } + while (innerException != null); + } + + public static string GetAllMessages(this Exception exception) + { + var messages = exception + .FromHierarchy(ex => ex.InnerException) + .Select(ex => ex.Message); + + return String.Join(Environment.NewLine, messages); + } + } +} diff --git a/OpenDBDiff/Extensions/IEnumerableExtensions.cs b/OpenDBDiff/Extensions/IEnumerableExtensions.cs new file mode 100644 index 0000000..eb6a9a3 --- /dev/null +++ b/OpenDBDiff/Extensions/IEnumerableExtensions.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +namespace OpenDBDiff.Front.Extensions +{ + public static class IEnumerableExtensions + { + // a.k.a., linked list style enumerator + public static IEnumerable FromHierarchy( + this TSource source, + Func nextItem, + Func canContinue) + { + for (var current = source; canContinue(current); current = nextItem(current)) + { + yield return current; + } + } + + public static IEnumerable FromHierarchy( + this TSource source, + Func nextItem) + where TSource : class + { + return FromHierarchy(source, nextItem, s => s != null); + } + } +} diff --git a/OpenDBDiff/Extensions/ScintillaExtensions.cs b/OpenDBDiff/Extensions/ScintillaExtensions.cs new file mode 100644 index 0000000..c6d11ee --- /dev/null +++ b/OpenDBDiff/Extensions/ScintillaExtensions.cs @@ -0,0 +1,69 @@ +using OpenDBDiff.Utils; +using ScintillaNET; +using System; +using System.Drawing; + +namespace OpenDBDiff.Extensions +{ + public static class ScintillaExtensions + { + public static void InitializeScintillaControls(this Scintilla scintilla) + { + // Reset the styles + scintilla.StyleResetDefault(); + scintilla.Styles[Style.Default].BackColor = SystemColors.Window; + scintilla.Styles[Style.Default].Font = GraphicsUtils.PreferredFont(); + scintilla.Styles[Style.Default].SizeF = 9f; + scintilla.StyleClearAll(); + + // Set the SQL Lexer + scintilla.Lexer = Lexer.Sql; + + // Set the Styles + scintilla.Styles[Style.Sql.Identifier].ForeColor = Color.SeaGreen; + scintilla.Styles[Style.LineNumber].ForeColor = Color.FromArgb(255, 128, 128, 128); //Dark Gray + scintilla.Styles[Style.LineNumber].BackColor = Color.FromArgb(255, 228, 228, 228); //Light Gray + scintilla.Styles[Style.Sql.Comment].ForeColor = Color.Green; + scintilla.Styles[Style.Sql.CommentLine].ForeColor = Color.Green; + scintilla.Styles[Style.Sql.CommentLineDoc].ForeColor = Color.Green; + scintilla.Styles[Style.Sql.Number].ForeColor = Color.Maroon; + scintilla.Styles[Style.Sql.Word].ForeColor = Color.Blue; + scintilla.Styles[Style.Sql.Word2].ForeColor = Color.Teal; + scintilla.Styles[Style.Sql.User1].ForeColor = Color.Green; + scintilla.Styles[Style.Sql.User2].ForeColor = Color.Fuchsia; + scintilla.Styles[Style.Sql.User3].ForeColor = Color.DarkGray; + scintilla.Styles[Style.Sql.User4].ForeColor = Color.DarkGoldenrod; + scintilla.Styles[Style.Sql.String].ForeColor = Color.Crimson; + scintilla.Styles[Style.Sql.Character].ForeColor = Color.Red; + scintilla.Styles[Style.Sql.Operator].ForeColor = Color.DarkGoldenrod; + + // Set keyword lists + // Word = 0 + scintilla.SetKeywords(0, @"action add all alter any as asc authorization backup begin break browse bulk by cascade case check checkpoint close clustered coalesce collate column commit committed compute confirm constraint contains containstable continue controlrow convert create cross current current_date current_time current_timestamp current_user cursor database dbcc deallocate declare default delete deny desc disable disk distinct distributed double drop dummy dump else enable end errlvl errorexit escape except exec execute exists exit fetch file fillfactor floppy for foreign forward_only freetext freetexttable from full function go goto grant group having holdlock identity identity_insert identitycol if in index inner insert intersect into is isolation join key kill left level lineno load mirrorexit move national no nocheck nonclustered not nounload null nullif of off offsets on once only open opendatasource openquery openrowset option order outer output over percent perm permanent pipe plan precision prepare primary print privileges proc procedure processexit public raiserror read readtext read_only reconfigure recovery references repeatable replication restore restrict return returns revoke right rollback rowcount rowguidcol rule save schema select serializable session_user set setuser shutdown some statistics stats system_user table tape temp temporary textsize then to top tran transaction trigger truncate tsequal uncommitted unique update updatetext use user values varying view waitfor when where while with work writetext "); + // word2 = 1 + scintilla.SetKeywords(1, @"bigint binary bit char character datetime dec decimal float image int integer money nchar ntext numeric nvarchar real smalldatetime smallint smallmoney sql_variant sysname text timestamp tinyint uniqueidentifier varbinary varchar "); + // user1 = 4 + scintilla.SetKeywords(4, @"deleted inserted sysallocations sysalternates sysaltfiles syscacheobjects syscharsets syscolumns syscomments sysconfigures sysconstraints syscurconfigs syscursorcolumns syscursorrefs syscursors syscursortables sysdatabases sysdepends sysdevices sysfilegroups sysfiles sysfiles1 sysforeignkeys sysfulltextcatalogs sysindexes sysindexkeys syslanguages syslockinfo syslocks syslogins sysmembers sysmessages sysobjects sysoledbusers sysperfinfo syspermissions sysprocesses sysprotects sysreferences sysremote_catalogs sysremote_column_privileges sysremote_columns sysremote_foreign_keys sysremote_indexes sysremote_primary_keys sysremote_provider_types sysremote_schemata sysremote_statistics sysremote_table_privileges sysremote_tables sysremote_views sysremotelogins syssegments sysservers systypes sysusers sysxlogins "); + // user2 = 5 + scintilla.SetKeywords(5, @"abs acos app_name ascii asin atan atn2 avg binary_checksum case cast ceiling char charindex checksum checksum_agg coalesce collationproperty col_length col_name columns_updated columnproperty convert cos cot count count_big current_timestamp current_user cursor_status databaseproperty databasepropertyex datalength dateadd datediff datename datepart day db_id db_name degrees difference exp file_id file_name filegroup_id filegroup_name filegroupproperty fileproperty floor fn_helpcollations fn_listextendedproperty fn_servershareddrives fn_trace_geteventinfo fn_trace_getfilterinfo fn_trace_getinfo fn_trace_gettable fn_virtualfilestats formatmessage fulltextcatalogproperty fulltextserviceproperty getansinull getdate getutcdate grouping has_dbaccess host_id host_name ident_current ident_incr ident_seed index_col indexkey_property indexproperty is_member is_srvrolemember isdate isnull isnumeric left len log log10 lower ltrim max min month nchar newid nullif object_id object_name objectproperty parsename patindex permissions pi power quotename radians rand replace replicate reverse right round rowcount_big rtrim scope_identity serverproperty sessionproperty session_user sign sin soundex space sqare sql_variant_property sqrt stats_date stdev stdevp str stuff substring sum suser_sid suser_sname system_user tan typeproperty unicode upper user_id user_name var varp year ( ) * "); + // user3 = 6 + scintilla.SetKeywords(6, @"sp_activedirectory_obj sp_activedirectory_scp sp_activedirectory_start sp_add_agent_parameter sp_add_agent_profile sp_add_data_file_recover_suspect_db sp_add_log_file_recover_suspect_db sp_add_log_shipping_alert_job sp_add_log_shipping_primary_database sp_add_log_shipping_primary_secondary sp_add_log_shipping_secondary_database sp_add_log_shipping_secondary_primary sp_addalias sp_addapprole sp_addarticle sp_adddatatype sp_adddatatypemapping sp_adddistpublisher sp_adddistributiondb sp_adddistributor sp_adddynamicsnapshot_job sp_addextendedproc sp_addextendedproperty sp_addgroup sp_addlinkedserver sp_addlinkedsrvlogin sp_addlogin sp_addlogreader_agent sp_addmergealternatepublisher sp_addmergearticle sp_addmergefilter sp_addmergelogsettings sp_addmergepartition sp_addmergepublication sp_addmergepullsubscription sp_addmergepullsubscription_agent sp_addmergepushsubscription_agent sp_addmergesubscription sp_addmessage sp_addpublication sp_addpublication_snapshot sp_addpullsubscription sp_addpullsubscription_agent sp_addpushsubscription_agent sp_addqreader_agent sp_addqueued_artinfo sp_addremotelogin sp_addrole sp_addrolemember sp_addscriptexec sp_addserver sp_addsrvrolemember sp_addsubscriber sp_addsubscriber_schedule sp_addsubscription sp_addsynctriggers sp_addsynctriggerscore sp_addtabletocontents sp_addtype sp_addumpdevice sp_adduser sp_adjustpublisheridentityrange sp_altermessage sp_approlepassword sp_article_validation sp_articlecolumn sp_articlefilter sp_articleview sp_assemblies_rowset sp_assemblies_rowset_rmt sp_assemblies_rowset2 sp_assembly_dependencies_rowset sp_assembly_dependencies_rowset_rmt sp_assembly_dependencies_rowset2 sp_attach_db sp_attach_single_file_db sp_attachsubscription sp_autostats sp_bcp_dbcmptlevel sp_bindefault sp_bindrule sp_browsemergesnapshotfolder sp_browsereplcmds sp_browsesnapshotfolder sp_can_tlog_be_applied sp_catalogs sp_catalogs_rowset sp_catalogs_rowset_rmt sp_catalogs_rowset2 sp_certify_removable sp_change_agent_parameter sp_change_agent_profile sp_change_log_shipping_primary_database sp_change_log_shipping_secondary_database sp_change_log_shipping_secondary_primary sp_change_subscription_properties sp_change_users_login sp_changearticle sp_changearticlecolumndatatype sp_changedbowner sp_changedistpublisher sp_changedistributiondb sp_changedistributor_password sp_changedistributor_property sp_changedynamicsnapshot_job sp_changegroup sp_changelogreader_agent sp_changemergearticle sp_changemergefilter sp_changemergelogsettings sp_changemergepublication sp_changemergepullsubscription sp_changemergesubscription sp_changeobjectowner sp_changepublication sp_changepublication_snapshot sp_changeqreader_agent sp_changereplicationserverpasswords sp_changesubscriber sp_changesubscriber_schedule sp_changesubscription sp_changesubscriptiondtsinfo sp_changesubstatus sp_check_constbytable_rowset sp_check_constbytable_rowset2 sp_check_constraints_rowset sp_check_constraints_rowset2 sp_check_dynamic_filters sp_check_for_sync_trigger sp_check_join_filter sp_check_log_shipping_monitor_alert sp_check_publication_access sp_check_removable sp_check_subset_filter sp_check_sync_trigger sp_checkinvalidivarticle sp_checkoraclepackageversion sp_cleanmergelogfiles sp_cleanup_log_shipping_history sp_cleanupdbreplication sp_cleanupwebtask sp_column_privileges sp_column_privileges_ex sp_column_privileges_rowset sp_column_privileges_rowset_rmt sp_column_privileges_rowset2 sp_columns sp_columns_90 sp_columns_90_rowset sp_columns_90_rowset_rmt sp_columns_90_rowset2 sp_columns_ex sp_columns_ex_90 sp_columns_rowset sp_columns_rowset_rmt sp_columns_rowset2 sp_configure sp_constr_col_usage_rowset sp_constr_col_usage_rowset2 sp_convertwebtasks sp_copymergesnapshot sp_copysnapshot sp_copysubscription sp_create_removable sp_createmergepalrole sp_createstats sp_createtranpalrole sp_cursor_list sp_cycle_errorlog sp_databases sp_datatype_info sp_datatype_info_90 sp_db_vardecimal_storage_format sp_dbcmptlevel sp_dbfixedrolepermission sp_dbmmonitoraddmonitoring sp_dbmmonitorchangealert sp_dbmmonitorchangemonitoring sp_dbmmonitordropalert sp_dbmmonitordropmonitoring sp_dbmmonitorhelpalert sp_dbmmonitorhelpmonitoring sp_dbmmonitorresults sp_dbmmonitorupdate sp_dboption sp_dbremove sp_ddopen sp_defaultdb sp_defaultlanguage sp_delete_log_shipping_alert_job sp_delete_log_shipping_primary_database sp_delete_log_shipping_primary_secondary sp_delete_log_shipping_secondary_database sp_delete_log_shipping_secondary_primary sp_deletemergeconflictrow sp_deletepeerrequesthistory sp_deletetracertokenhistory sp_denylogin sp_depends sp_describe_cursor sp_describe_cursor_columns sp_describe_cursor_tables sp_detach_db sp_disableagentoffload sp_distcounters sp_drop_agent_parameter sp_drop_agent_profile sp_dropalias sp_dropanonymousagent sp_dropanonymoussubscription sp_dropapprole sp_droparticle sp_dropdatatypemapping sp_dropdevice sp_dropdistpublisher sp_dropdistributiondb sp_dropdistributor sp_dropdynamicsnapshot_job sp_dropextendedproc sp_dropextendedproperty sp_dropgroup sp_droplinkedsrvlogin sp_droplogin sp_dropmergealternatepublisher sp_dropmergearticle sp_dropmergefilter sp_dropmergelogsettings sp_dropmergepartition sp_dropmergepublication sp_dropmergepullsubscription sp_dropmergesubscription sp_dropmessage sp_droppublication sp_droppublisher sp_droppullsubscription sp_dropremotelogin sp_dropreplsymmetrickey sp_droprole sp_droprolemember sp_dropserver sp_dropsrvrolemember sp_dropsubscriber sp_dropsubscription sp_droptype sp_dropuser sp_dropwebtask sp_dsninfo sp_enable_heterogeneous_subscription sp_enableagentoffload sp_enum_oledb_providers sp_enumcodepages sp_enumcustomresolvers sp_enumdsn sp_enumeratependingschemachanges sp_enumerrorlogs sp_enumfullsubscribers sp_enumoledbdatasources sp_estimated_rowsize_reduction_for_vardecimal sp_expired_subscription_cleanup sp_firstonly_bitmap sp_fkeys sp_foreign_keys_rowset sp_foreign_keys_rowset_rmt sp_foreign_keys_rowset2 sp_foreign_keys_rowset3 sp_foreignkeys sp_fulltext_catalog sp_fulltext_column sp_fulltext_database sp_fulltext_querytimeout sp_fulltext_recycle_crawl_log sp_fulltext_service sp_fulltext_table sp_generate_agent_parameter sp_generatefilters sp_get_distributor sp_get_job_status_mergesubscription_agent sp_get_mergepublishedarticleproperties sp_get_oracle_publisher_metadata sp_getagentparameterlist sp_getapplock sp_getdefaultdatatypemapping sp_getmergedeletetype sp_getpublisherlink sp_getqueuedarticlesynctraninfo sp_getqueuedrows sp_getsqlqueueversion sp_getsubscription_status_hsnapshot sp_getsubscriptiondtspackagename sp_grant_publication_access sp_grantdbaccess sp_grantlogin sp_help sp_help_agent_default sp_help_agent_parameter sp_help_agent_profile sp_help_datatype_mapping sp_help_fulltext_catalog_components sp_help_fulltext_catalogs sp_help_fulltext_catalogs_cursor sp_help_fulltext_columns sp_help_fulltext_columns_cursor sp_help_fulltext_system_components sp_help_fulltext_tables sp_help_fulltext_tables_cursor sp_help_log_shipping_alert_job sp_help_log_shipping_monitor sp_help_log_shipping_monitor_primary sp_help_log_shipping_monitor_secondary sp_help_log_shipping_primary_database sp_help_log_shipping_primary_secondary sp_help_log_shipping_secondary_database sp_help_log_shipping_secondary_primary sp_help_publication_access sp_helpallowmerge_publication sp_helparticle sp_helparticlecolumns sp_helparticledts sp_helpconstraint sp_helpdatatypemap sp_helpdb sp_helpdbfixedrole sp_helpdevice sp_helpdistpublisher sp_helpdistributiondb sp_helpdistributor sp_helpdistributor_properties sp_helpdynamicsnapshot_job sp_helpextendedproc sp_helpfile sp_helpfilegroup sp_helpgroup sp_helpindex sp_helplanguage sp_helplinkedsrvlogin sp_helplogins sp_helplogreader_agent sp_helpmergealternatepublisher sp_helpmergearticle sp_helpmergearticlecolumn sp_helpmergearticleconflicts sp_helpmergeconflictrows sp_helpmergedeleteconflictrows sp_helpmergefilter sp_helpmergelogfiles sp_helpmergelogfileswithdata sp_helpmergelogsettings sp_helpmergepartition sp_helpmergepublication sp_helpmergepullsubscription sp_helpmergesubscription sp_helpntgroup sp_helppeerrequests sp_helppeerresponses sp_helppublication sp_helppublication_snapshot sp_helppublicationsync sp_helppullsubscription sp_helpqreader_agent sp_helpremotelogin sp_helpreplfailovermode sp_helpreplicationdb sp_helpreplicationdboption sp_helpreplicationoption sp_helprole sp_helprolemember sp_helprotect sp_helpserver sp_helpsort sp_helpsrvrole sp_helpsrvrolemember sp_helpstats sp_helpsubscriberinfo sp_helpsubscription sp_helpsubscription_properties sp_helpsubscriptionerrors sp_helptext sp_helptracertokenhistory sp_helptracertokens sp_helptrigger sp_helpuser sp_helpxactsetjob sp_http_generate_wsdl_defaultcomplexorsimple sp_http_generate_wsdl_defaultsimpleorcomplex sp_identitycolumnforreplication sp_ih_lr_getcachedata sp_ihadd_sync_command sp_iharticlecolumn sp_ihget_loopback_detection sp_ihscriptidxfile sp_ihscriptschfile sp_ihvalidaterowfilter sp_ihxactsetjob sp_indexes sp_indexes_90_rowset sp_indexes_90_rowset_rmt sp_indexes_90_rowset2 sp_indexes_rowset sp_indexes_rowset_rmt sp_indexes_rowset2 sp_indexoption sp_invalidate_textptr sp_ivindexhasnullcols sp_lightweightmergemetadataretentioncleanup sp_link_publication sp_linkedservers sp_linkedservers_rowset sp_linkedservers_rowset2 sp_lock sp_logshippinginstallmetadata sp_lookupcustomresolver sp_makewebtask sp_mapdown_bitmap sp_markpendingschemachange sp_marksubscriptionvalidation sp_mergearticlecolumn sp_mergecleanupmetadata sp_mergedummyupdate sp_mergemetadataretentioncleanup sp_mergesubscription_cleanup sp_mergesubscriptionsummary sp_monitor sp_ms_replication_installed sp_msacquireheadofqueuelock sp_msacquireserverresourcefordynamicsnapshot sp_msacquireslotlock sp_msacquiresnapshotdeliverysessionlock sp_msactivate_auto_sub sp_msactivatelogbasedarticleobject sp_msactivateprocedureexecutionarticleobject sp_msadd_anonymous_agent sp_msadd_article sp_msadd_compensating_cmd sp_msadd_distribution_agent sp_msadd_distribution_history sp_msadd_dynamic_snapshot_location sp_msadd_filteringcolumn sp_msadd_log_shipping_error_detail sp_msadd_log_shipping_history_detail sp_msadd_logreader_agent sp_msadd_logreader_history sp_msadd_merge_agent sp_msadd_merge_anonymous_agent sp_msadd_merge_history sp_msadd_merge_history90 sp_msadd_merge_subscription sp_msadd_mergereplcommand sp_msadd_mergesubentry_indistdb sp_msadd_publication sp_msadd_qreader_agent sp_msadd_qreader_history sp_msadd_repl_alert sp_msadd_repl_command sp_msadd_repl_commands27hp sp_msadd_repl_error sp_msadd_replcmds_mcit sp_msadd_replmergealert sp_msadd_snapshot_agent sp_msadd_snapshot_history sp_msadd_subscriber_info sp_msadd_subscriber_schedule sp_msadd_subscription sp_msadd_subscription_3rd sp_msadd_tracer_history sp_msadd_tracer_token sp_msaddanonymousreplica sp_msadddynamicsnapshotjobatdistributor sp_msaddguidcolumn sp_msaddguidindex sp_msaddinitialarticle sp_msaddinitialpublication sp_msaddinitialschemaarticle sp_msaddinitialsubscription sp_msaddlightweightmergearticle sp_msaddmergedynamicsnapshotjob sp_msaddmergetriggers sp_msaddmergetriggers_from_template sp_msaddmergetriggers_internal sp_msaddpeerlsn sp_msaddsubscriptionarticles sp_msadjust_pub_identity sp_msagent_retry_stethoscope sp_msagent_stethoscope sp_msallocate_new_identity_range sp_msalreadyhavegeneration sp_msanonymous_status sp_msarticlecleanup sp_msbrowsesnapshotfolder sp_mscache_agent_parameter sp_mschange_article sp_mschange_distribution_agent_properties sp_mschange_logreader_agent_properties sp_mschange_merge_agent_properties sp_mschange_mergearticle sp_mschange_mergepublication sp_mschange_priority sp_mschange_publication sp_mschange_retention sp_mschange_retention_period_unit sp_mschange_snapshot_agent_properties sp_mschange_subscription_dts_info sp_mschangearticleresolver sp_mschangedynamicsnapshotjobatdistributor sp_mschangedynsnaplocationatdistributor sp_mschangeobjectowner sp_mscheck_agent_instance sp_mscheck_jet_subscriber sp_mscheck_logicalrecord_metadatamatch sp_mscheck_merge_subscription_count sp_mscheck_pub_identity sp_mscheck_pull_access sp_mscheck_snapshot_agent sp_mscheck_subscription sp_mscheck_subscription_expiry sp_mscheck_subscription_partition sp_mscheck_tran_retention sp_mscheckexistsgeneration sp_mscheckexistsrecguid sp_mscheckidentityrange sp_mschecksharedagentforpublication sp_mschecksnapshotstatus sp_mscleanup_agent_entry sp_mscleanup_conflict sp_mscleanup_publication_adinfo sp_mscleanup_subscription_distside_entry sp_mscleanupdynamicsnapshotfolder sp_mscleanupdynsnapshotvws sp_mscleanupforpullreinit sp_mscleanupmergepublisher sp_mscleanupmergepublisher_internal sp_msclear_dynamic_snapshot_location sp_msclearresetpartialsnapshotprogressbit sp_mscomputelastsentgen sp_mscomputemergearticlescreationorder sp_mscomputemergeunresolvedrefs sp_msconflicttableexists sp_mscreate_all_article_repl_views sp_mscreate_article_repl_views sp_mscreate_dist_tables sp_mscreate_logical_record_views sp_mscreate_sub_tables sp_mscreatedisabledmltrigger sp_mscreatedummygeneration sp_mscreateglobalreplica sp_mscreatelightweightinsertproc sp_mscreatelightweightmultipurposeproc sp_mscreatelightweightprocstriggersconstraints sp_mscreatelightweightupdateproc sp_mscreatemergedynamicsnapshot sp_mscreateretry sp_msdbuseraccess sp_msdbuserpriv sp_msdefer_check sp_msdelete_tracer_history sp_msdeletefoldercontents sp_msdeletemetadataactionrequest sp_msdeleteretry sp_msdeletetranconflictrow sp_msdelgenzero sp_msdelrow sp_msdelrowsbatch sp_msdelrowsbatch_downloadonly sp_msdelsubrows sp_msdelsubrowsbatch sp_msdependencies sp_msdetect_nonlogged_shutdown sp_msdetectinvalidpeerconfiguration sp_msdetectinvalidpeersubscription sp_msdist_activate_auto_sub sp_msdist_adjust_identity sp_msdistpublisher_cleanup sp_msdistribution_counters sp_msdistributoravailable sp_msdodatabasesnapshotinitiation sp_msdopartialdatabasesnapshotinitiation sp_msdrop_6x_publication sp_msdrop_6x_replication_agent sp_msdrop_anonymous_entry sp_msdrop_article sp_msdrop_distribution_agent sp_msdrop_distribution_agentid_dbowner_proxy sp_msdrop_dynamic_snapshot_agent sp_msdrop_logreader_agent sp_msdrop_merge_agent sp_msdrop_merge_subscription sp_msdrop_publication sp_msdrop_qreader_history sp_msdrop_snapshot_agent sp_msdrop_snapshot_dirs sp_msdrop_subscriber_info sp_msdrop_subscription sp_msdrop_subscription_3rd sp_msdroparticleconstraints sp_msdroparticletombstones sp_msdropconstraints sp_msdropdynsnapshotvws sp_msdropfkreferencingarticle sp_msdropmergearticle sp_msdropmergedynamicsnapshotjob sp_msdropretry sp_msdroptemptable sp_msdummyupdate sp_msdummyupdate_logicalrecord sp_msdummyupdate90 sp_msdummyupdatelightweight sp_msdynamicsnapshotjobexistsatdistributor sp_msenable_publication_for_het_sub sp_msensure_single_instance sp_msenum_distribution sp_msenum_distribution_s sp_msenum_distribution_sd sp_msenum_logicalrecord_changes sp_msenum_logreader sp_msenum_logreader_s sp_msenum_logreader_sd sp_msenum_merge sp_msenum_merge_agent_properties sp_msenum_merge_s sp_msenum_merge_sd sp_msenum_merge_subscriptions sp_msenum_merge_subscriptions_90_publication sp_msenum_merge_subscriptions_90_publisher sp_msenum_metadataaction_requests sp_msenum_qreader sp_msenum_qreader_s sp_msenum_qreader_sd sp_msenum_replication_agents sp_msenum_replication_job sp_msenum_replqueues sp_msenum_replsqlqueues sp_msenum_snapshot sp_msenum_snapshot_s sp_msenum_snapshot_sd sp_msenum_subscriptions sp_msenumallpublications sp_msenumallsubscriptions sp_msenumarticleslightweight sp_msenumchanges sp_msenumchanges_belongtopartition sp_msenumchanges_notbelongtopartition sp_msenumchangesdirect sp_msenumchangeslightweight sp_msenumcolumns sp_msenumcolumnslightweight sp_msenumdeletes_forpartition sp_msenumdeleteslightweight sp_msenumdeletesmetadata sp_msenumdistributionagentproperties sp_msenumerate_pal sp_msenumgenerations sp_msenumgenerations90 sp_msenumpartialchanges sp_msenumpartialchangesdirect sp_msenumpartialdeletes sp_msenumpubreferences sp_msenumreplicas sp_msenumreplicas90 sp_msenumretries sp_msenumschemachange sp_msenumsubscriptions sp_msenumthirdpartypublicationvendornames sp_msestimatemergesnapshotworkload sp_msestimatesnapshotworkload sp_msevalsubscriberinfo sp_msevaluate_change_membership_for_all_articles_in_pubid sp_msevaluate_change_membership_for_pubid sp_msevaluate_change_membership_for_row sp_msexecwithlsnoutput sp_msfast_delete_trans sp_msfetchadjustidentityrange sp_msfetchidentityrange sp_msfillupmissingcols sp_msfilterclause sp_msfix_6x_tasks sp_msfixlineageversions sp_msfixsubcolumnbitmaps sp_msfixupbeforeimagetables sp_msflush_access_cache sp_msforce_drop_distribution_jobs sp_msforcereenumeration sp_msforeach_worker sp_msforeachdb sp_msforeachtable sp_msgenerateexpandproc sp_msget_agent_names sp_msget_attach_state sp_msget_ddl_after_regular_snapshot sp_msget_dynamic_snapshot_location sp_msget_identity_range_info sp_msget_jobstate sp_msget_last_transaction sp_msget_load_hint sp_msget_log_shipping_new_sessionid sp_msget_logicalrecord_lineage sp_msget_max_used_identity sp_msget_msmerge_rowtrack_colinfo sp_msget_new_xact_seqno sp_msget_oledbinfo sp_msget_partitionid_eval_proc sp_msget_publication_from_taskname sp_msget_publisher_rpc sp_msget_repl_cmds_anonymous sp_msget_repl_commands sp_msget_repl_error sp_msget_session_statistics sp_msget_shared_agent sp_msget_snapshot_history sp_msget_subscriber_partition_id sp_msget_subscription_dts_info sp_msget_subscription_guid sp_msget_synctran_commands sp_msget_type_wrapper sp_msgetagentoffloadinfo sp_msgetalertinfo sp_msgetalternaterecgens sp_msgetarticlereinitvalue sp_msgetchangecount sp_msgetconflictinsertproc sp_msgetconflicttablename sp_msgetcurrentprincipal sp_msgetdatametadatabatch sp_msgetdbversion sp_msgetdynamicsnapshotapplock sp_msgetdynsnapvalidationtoken sp_msgetisvalidwindowsloginfromdistributor sp_msgetlastrecgen sp_msgetlastsentgen sp_msgetlastsentrecgens sp_msgetlastupdatedtime sp_msgetlightweightmetadatabatch sp_msgetmakegenerationapplock sp_msgetmakegenerationapplock_90 sp_msgetmaxbcpgen sp_msgetmaxsnapshottimestamp sp_msgetmergeadminapplock sp_msgetmetadata_changedlogicalrecordmembers sp_msgetmetadatabatch sp_msgetmetadatabatch90 sp_msgetmetadatabatch90new sp_msgetonerow sp_msgetonerowlightweight sp_msgetpeerlsns sp_msgetpeertopeercommands sp_msgetpubinfo sp_msgetreplicainfo sp_msgetreplicastate sp_msgetrowmetadata sp_msgetrowmetadatalightweight sp_msgetserverproperties sp_msgetsetupbelong_cost sp_msgetsubscriberinfo sp_msgetsupportabilitysettings sp_msgettrancftsrcrow sp_msgettranconflictrow sp_msgrantconnectreplication sp_mshaschangeslightweight sp_mshasdbaccess sp_mshelp_article sp_mshelp_distdb sp_mshelp_distribution_agentid sp_mshelp_identity_property sp_mshelp_logreader_agentid sp_mshelp_merge_agentid sp_mshelp_profile sp_mshelp_profilecache sp_mshelp_publication sp_mshelp_repl_agent sp_mshelp_replication_status sp_mshelp_replication_table sp_mshelp_snapshot_agent sp_mshelp_snapshot_agentid sp_mshelp_subscriber_info sp_mshelp_subscription sp_mshelp_subscription_status sp_mshelpcolumns sp_mshelpconflictpublications sp_mshelpcreatebeforetable sp_mshelpdestowner sp_mshelpdynamicsnapshotjobatdistributor sp_mshelpfulltextindex sp_mshelpfulltextscript sp_mshelpindex sp_mshelplogreader_agent sp_mshelpmergearticles sp_mshelpmergeconflictcounts sp_mshelpmergedynamicsnapshotjob sp_mshelpmergeidentity sp_mshelpmergeschemaarticles sp_mshelpobjectpublications sp_mshelpreplicationtriggers sp_mshelpsnapshot_agent sp_mshelpsummarypublication sp_mshelptracertokenhistory sp_mshelptracertokens sp_mshelptranconflictcounts sp_mshelptype sp_mshelpvalidationdate sp_msifexistssubscription sp_msindexspace sp_msinit_publication_access sp_msinit_subscription_agent sp_msinitdynamicsubscriber sp_msinsert_identity sp_msinsertdeleteconflict sp_msinserterrorlineage sp_msinsertgenerationschemachanges sp_msinsertgenhistory sp_msinsertlightweightschemachange sp_msinsertschemachange sp_msinvalidate_snapshot sp_msisnonpkukupdateinconflict sp_msispeertopeeragent sp_msispkupdateinconflict sp_msispublicationqueued sp_msisreplmergeagent sp_msissnapshotitemapplied sp_mskilldb sp_mslock_auto_sub sp_mslock_distribution_agent sp_mslocktable sp_msloginmappings sp_msmakearticleprocs sp_msmakebatchinsertproc sp_msmakebatchupdateproc sp_msmakeconflictinsertproc sp_msmakectsview sp_msmakedeleteproc sp_msmakedynsnapshotvws sp_msmakeexpandproc sp_msmakegeneration sp_msmakeinsertproc sp_msmakemetadataselectproc sp_msmakeselectproc sp_msmakesystableviews sp_msmakeupdateproc sp_msmap_partitionid_to_generations sp_msmarkreinit sp_msmatchkey sp_msmerge_alterschemaonly sp_msmerge_altertrigger sp_msmerge_alterview sp_msmerge_ddldispatcher sp_msmerge_getgencur_public sp_msmerge_is_snapshot_required sp_msmerge_log_identity_range_allocations sp_msmerge_upgrade_subscriber sp_msmergesubscribedb sp_msmergeupdatelastsyncinfo sp_msneedmergemetadataretentioncleanup sp_msnonsqlddl sp_msnonsqlddlforschemaddl sp_msobjectprivs sp_mspeerapplyresponse sp_mspeerdbinfo sp_mspeersendresponse sp_mspeertopeerfwdingexec sp_mspost_auto_proc sp_mspostapplyscript_forsubscriberprocs sp_msprep_exclusive sp_msprepare_mergearticle sp_msprofile_in_use sp_msproxiedmetadata sp_msproxiedmetadatabatch sp_msproxiedmetadatalightweight sp_mspub_adjust_identity sp_mspublication_access sp_mspublicationcleanup sp_mspublicationview sp_msquery_syncstates sp_msquerysubtype sp_msrecordsnapshotdeliveryprogress sp_msreenable_check sp_msrefresh_anonymous sp_msrefresh_publisher_idrange sp_msregenerate_mergetriggersprocs sp_msregisterdynsnapseqno sp_msregistermergesnappubid sp_msregistersubscription sp_msreinit_failed_subscriptions sp_msreinit_hub sp_msreinit_subscription sp_msreinitoverlappingmergepublications sp_msreleasedynamicsnapshotapplock sp_msreleasemakegenerationapplock sp_msreleasemergeadminapplock sp_msreleaseslotlock sp_msreleasesnapshotdeliverysessionlock sp_msremove_mergereplcommand sp_msremoveoffloadparameter sp_msrepl_agentstatussummary sp_msrepl_backup_complete sp_msrepl_backup_start sp_msrepl_check_publisher sp_msrepl_createdatatypemappings sp_msrepl_distributionagentstatussummary sp_msrepl_dropdatatypemappings sp_msrepl_enumarticlecolumninfo sp_msrepl_enumpublications sp_msrepl_enumpublishertables sp_msrepl_enumsubscriptions sp_msrepl_enumtablecolumninfo sp_msrepl_fixpalrole sp_msrepl_getdistributorinfo sp_msrepl_getpkfkrelation sp_msrepl_gettype_mappings sp_msrepl_helparticlermo sp_msrepl_init_backup_lsns sp_msrepl_isdbowner sp_msrepl_islastpubinsharedsubscription sp_msrepl_isuserinanypal sp_msrepl_linkedservers_rowset sp_msrepl_mergeagentstatussummary sp_msrepl_pal_rolecheck sp_msrepl_raiserror sp_msrepl_schema sp_msrepl_setnfr sp_msrepl_snapshot_helparticlecolumns sp_msrepl_snapshot_helppublication sp_msrepl_startup sp_msrepl_startup_internal sp_msrepl_subscription_rowset sp_msrepl_testadminconnection sp_msrepl_testconnection sp_msreplagentjobexists sp_msreplcheck_permission sp_msreplcheck_pull sp_msreplcheck_subscribe sp_msreplcheck_subscribe_withddladmin sp_msreplcheckoffloadserver sp_msreplcopyscriptfile sp_msreplraiserror sp_msreplremoveuncdir sp_msreplupdateschema sp_msrequestreenumeration sp_msrequestreenumeration_lightweight sp_msreset_attach_state sp_msreset_queued_reinit sp_msreset_subscription sp_msreset_subscription_seqno sp_msreset_synctran_bit sp_msreset_transaction sp_msresetsnapshotdeliveryprogress sp_msrestoresavedforeignkeys sp_msretrieve_publication_attributes sp_msscript_article_view sp_msscript_dri sp_msscript_pub_upd_trig sp_msscript_sync_del_proc sp_msscript_sync_del_trig sp_msscript_sync_ins_proc sp_msscript_sync_ins_trig sp_msscript_sync_upd_proc sp_msscript_sync_upd_trig sp_msscriptcustomdelproc sp_msscriptcustominsproc sp_msscriptcustomupdproc sp_msscriptdatabase sp_msscriptdb_worker sp_msscriptforeignkeyrestore sp_msscriptsubscriberprocs sp_msscriptviewproc sp_mssendtosqlqueue sp_msset_dynamic_filter_options sp_msset_logicalrecord_metadata sp_msset_new_identity_range sp_msset_oledb_prop sp_msset_snapshot_xact_seqno sp_msset_sub_guid sp_msset_subscription_properties sp_mssetaccesslist sp_mssetalertinfo sp_mssetartprocs sp_mssetbit sp_mssetconflictscript sp_mssetconflicttable sp_mssetcontext_bypasswholeddleventbit sp_mssetcontext_replagent sp_mssetgentozero sp_mssetlastrecgen sp_mssetlastsentgen sp_mssetreplicainfo sp_mssetreplicaschemaversion sp_mssetreplicastatus sp_mssetrowmetadata sp_mssetserverproperties sp_mssetsubscriberinfo sp_mssettopology sp_mssetup_identity_range sp_mssetup_partition_groups sp_mssetup_use_partition_groups sp_mssetupbelongs sp_mssetupnosyncsubwithlsnatdist sp_mssharedfixeddisk sp_mssqldmo70_version sp_mssqldmo80_version sp_mssqldmo90_version sp_mssqlole_version sp_mssqlole65_version sp_msstartdistribution_agent sp_msstartmerge_agent sp_msstartsnapshot_agent sp_msstopdistribution_agent sp_msstopmerge_agent sp_msstopsnapshot_agent sp_mssub_check_identity sp_mssub_set_identity sp_mssubscription_status sp_mssubscriptionvalidated sp_mstablechecks sp_mstablekeys sp_mstablerefs sp_mstablespace sp_mstestbit sp_mstran_ddlrepl sp_mstran_is_snapshot_required sp_mstrypurgingoldsnapshotdeliveryprogress sp_msuniquename sp_msunmarkifneeded sp_msunmarkreplinfo sp_msunmarkschemaobject sp_msunregistersubscription sp_msupdate_agenttype_default sp_msupdate_singlelogicalrecordmetadata sp_msupdate_subscriber_info sp_msupdate_subscriber_schedule sp_msupdate_subscriber_tracer_history sp_msupdate_subscription sp_msupdate_tracer_history sp_msupdatecachedpeerlsn sp_msupdategenhistory sp_msupdateinitiallightweightsubscription sp_msupdatelastsyncinfo sp_msupdatepeerlsn sp_msupdaterecgen sp_msupdatereplicastate sp_msupdatesysmergearticles sp_msuplineageversion sp_msuploadsupportabilitydata sp_msuselightweightreplication sp_msvalidate_dest_recgen sp_msvalidate_subscription sp_msvalidate_wellpartitioned_articles sp_msvalidatearticle sp_mswritemergeperfcounter sp_objectfilegroup sp_oledb_database sp_oledb_defdb sp_oledb_deflang sp_oledb_language sp_oledb_ro_usrname sp_oledbinfo sp_orbitmap sp_password sp_pkeys sp_posttracertoken sp_primary_keys_rowset sp_primary_keys_rowset_rmt sp_primary_keys_rowset2 sp_primarykeys sp_procedure_params_90_rowset sp_procedure_params_90_rowset2 sp_procedure_params_managed sp_procedure_params_rowset sp_procedure_params_rowset2 sp_procedures_rowset sp_procedures_rowset2 sp_processlogshippingmonitorhistory sp_processlogshippingmonitorprimary sp_processlogshippingmonitorsecondary sp_processlogshippingretentioncleanup sp_processmail sp_procoption sp_prop_oledb_provider sp_provider_types_90_rowset sp_provider_types_rowset sp_publication_validation sp_publicationsummary sp_publishdb sp_publisherproperty sp_readerrorlog sp_readwebtask sp_recompile sp_refresh_heterogeneous_publisher sp_refresh_log_shipping_monitor sp_refreshsqlmodule sp_refreshsubscriptions sp_register_custom_scripting sp_registercustomresolver sp_reinitmergepullsubscription sp_reinitmergesubscription sp_reinitpullsubscription sp_reinitsubscription sp_releaseapplock sp_remoteoption sp_removedbreplication sp_removedistpublisherdbreplication sp_removesrvreplication sp_rename sp_renamedb sp_repladdcolumn sp_replcleanupccsprocs sp_repldeletequeuedtran sp_repldropcolumn sp_replgetparsedddlcmd sp_replica sp_replication_agent_checkup sp_replicationdboption sp_replincrementlsn sp_replmonitorchangepublicationthreshold sp_replmonitorhelpmergesession sp_replmonitorhelpmergesessiondetail sp_replmonitorhelpmergesubscriptionmoreinfo sp_replmonitorhelppublication sp_replmonitorhelppublicationthresholds sp_replmonitorhelppublisher sp_replmonitorhelpsubscription sp_replmonitorrefreshjob sp_replmonitorsubscriptionpendingcmds sp_replpostsyncstatus sp_replqueuemonitor sp_replrestart sp_replsetoriginator sp_replshowcmds sp_replsqlqgetrows sp_replsync sp_requestpeerresponse sp_resetsnapshotdeliveryprogress sp_resetstatus sp_resign_database sp_resolve_logins sp_restoredbreplication sp_restoremergeidentityrange sp_resyncmergesubscription sp_revoke_publication_access sp_revokedbaccess sp_revokelogin sp_runwebtask sp_schemafilter sp_schemata_rowset sp_script_reconciliation_delproc sp_script_reconciliation_insproc sp_script_reconciliation_sinsproc sp_script_reconciliation_vdelproc sp_script_reconciliation_xdelproc sp_script_synctran_commands sp_scriptdelproc sp_scriptdynamicupdproc sp_scriptinsproc sp_scriptmappedupdproc sp_scriptpublicationcustomprocs sp_scriptsinsproc sp_scriptsubconflicttable sp_scriptsupdproc sp_scriptupdproc sp_scriptvdelproc sp_scriptvupdproc sp_scriptxdelproc sp_scriptxupdproc sp_server_info sp_serveroption sp_setapprole sp_setautosapasswordanddisable sp_setdefaultdatatypemapping sp_setnetname sp_setoraclepackageversion sp_setreplfailovermode sp_setsubscriptionxactseqno sp_settriggerorder sp_showcolv sp_showlineage sp_showpendingchanges sp_showrowreplicainfo sp_spaceused sp_special_columns sp_special_columns_90 sp_sproc_columns sp_sproc_columns_90 sp_sqlexec sp_srvrolepermission sp_startmergepullsubscription_agent sp_startmergepushsubscription_agent sp_startpublication_snapshot sp_startpullsubscription_agent sp_startpushsubscription_agent sp_statistics sp_statistics_rowset sp_statistics_rowset2 sp_stopmergepullsubscription_agent sp_stopmergepushsubscription_agent sp_stoppublication_snapshot sp_stoppullsubscription_agent sp_stoppushsubscription_agent sp_stored_procedures sp_subscribe sp_subscription_cleanup sp_subscriptionsummary sp_table_constraints_rowset sp_table_constraints_rowset2 sp_table_privileges sp_table_privileges_ex sp_table_privileges_rowset sp_table_privileges_rowset_rmt sp_table_privileges_rowset2 sp_table_statistics_rowset sp_table_statistics2_rowset sp_table_validation sp_tablecollations sp_tablecollations_90 sp_tableoption sp_tables sp_tables_ex sp_tables_info_90_rowset sp_tables_info_90_rowset_64 sp_tables_info_90_rowset2 sp_tables_info_90_rowset2_64 sp_tables_info_rowset sp_tables_info_rowset_64 sp_tables_info_rowset2 sp_tables_info_rowset2_64 sp_tables_rowset sp_tables_rowset_rmt sp_tables_rowset2 sp_tableswc sp_trace_getdata sp_unbindefault sp_unbindrule sp_unregister_custom_scripting sp_unregistercustomresolver sp_unsetapprole sp_unsubscribe sp_update_agent_profile sp_updateextendedproperty sp_updatestats sp_upgrade_log_shipping sp_user_counter1 sp_user_counter10 sp_user_counter2 sp_user_counter3 sp_user_counter4 sp_user_counter5 sp_user_counter6 sp_user_counter7 sp_user_counter8 sp_user_counter9 sp_usertypes_rowset sp_usertypes_rowset_rmt sp_usertypes_rowset2 sp_validatecache sp_validatelogins sp_validatemergepublication sp_validatemergepullsubscription sp_validatemergesubscription sp_validlang sp_validname sp_verifypublisher sp_views_rowset sp_views_rowset2 sp_vupgrade_mergeobjects sp_vupgrade_mergetables sp_vupgrade_replication sp_vupgrade_replsecurity_metadata sp_who sp_who2 sp_xml_schema_rowset sp_xml_schema_rowset2 xp_grantlogin xp_logininfo xp_repl_convert_encrypt_sysadmin_wrapper xp_revokelogin "); + // user4 = 7 + scintilla.SetKeywords(7, @"between and or union like "); + + scintilla.Text = ""; + scintilla.SetMarginWidth(); + } + + public static void SetMarginWidth(this Scintilla scintilla) + { + var lineCount = scintilla.Lines.Count; + + var fontName = scintilla.Styles[Style.Default].Font; + var fontSize = scintilla.Styles[Style.Default].SizeF; + var lineNumberWidth = GraphicsUtils.GetTextDimensions($"{lineCount.ToString()}XX", fontName, fontSize).Width; + + scintilla.Margins[0].Width = Math.Max(20, (int)lineNumberWidth); + } + } +} diff --git a/OpenDBDiff/Front/DataCompareForm.Designer.cs b/OpenDBDiff/Front/DataCompareForm.Designer.cs new file mode 100644 index 0000000..8a22a2e --- /dev/null +++ b/OpenDBDiff/Front/DataCompareForm.Designer.cs @@ -0,0 +1,283 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + partial class DataCompareForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DataCompareForm)); + this.pnlControl = new System.Windows.Forms.Panel(); + this.lblAdded = new System.Windows.Forms.Label(); + this.lblModified = new System.Windows.Forms.Label(); + this.pnlAdded = new System.Windows.Forms.Panel(); + this.pnlModified = new System.Windows.Forms.Panel(); + this.btnRowToRow = new System.Windows.Forms.Button(); + this.btnMerge = new System.Windows.Forms.Button(); + this.btnUpdateRow = new System.Windows.Forms.Button(); + this.btnCommitChanges = new System.Windows.Forms.Button(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.pnlSource = new System.Windows.Forms.Panel(); + this.lblSrc = new System.Windows.Forms.Label(); + this.srcDgv = new System.Windows.Forms.DataGridView(); + this.pnlDestination = new System.Windows.Forms.Panel(); + this.lblDestination = new System.Windows.Forms.Label(); + this.destDgv = new System.Windows.Forms.DataGridView(); + this.pnlControl.SuspendLayout(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.pnlSource.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.srcDgv)).BeginInit(); + this.pnlDestination.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.destDgv)).BeginInit(); + this.SuspendLayout(); + // + // pnlControl + // + this.pnlControl.BackColor = System.Drawing.Color.White; + this.pnlControl.Controls.Add(this.btnCommitChanges); + this.pnlControl.Controls.Add(this.lblAdded); + this.pnlControl.Controls.Add(this.lblModified); + this.pnlControl.Controls.Add(this.pnlAdded); + this.pnlControl.Controls.Add(this.pnlModified); + this.pnlControl.Controls.Add(this.btnRowToRow); + this.pnlControl.Controls.Add(this.btnMerge); + this.pnlControl.Controls.Add(this.btnUpdateRow); + this.pnlControl.Dock = System.Windows.Forms.DockStyle.Bottom; + this.pnlControl.Location = new System.Drawing.Point(0, 462); + this.pnlControl.Name = "pnlControl"; + this.pnlControl.Size = new System.Drawing.Size(787, 48); + this.pnlControl.TabIndex = 2; + // + // lblAdded + // + this.lblAdded.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.lblAdded.Font = new System.Drawing.Font("Verdana", 9F); + this.lblAdded.Location = new System.Drawing.Point(390, 14); + this.lblAdded.Name = "lblAdded"; + this.lblAdded.Size = new System.Drawing.Size(100, 20); + this.lblAdded.TabIndex = 0; + this.lblAdded.Text = "Added"; + // + // lblModified + // + this.lblModified.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.lblModified.Font = new System.Drawing.Font("Verdana", 9F); + this.lblModified.Location = new System.Drawing.Point(540, 14); + this.lblModified.Name = "lblModified"; + this.lblModified.Size = new System.Drawing.Size(100, 20); + this.lblModified.TabIndex = 1; + this.lblModified.Text = "Modified"; + // + // pnlAdded + // + this.pnlAdded.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.pnlAdded.BackColor = System.Drawing.Color.Green; + this.pnlAdded.Location = new System.Drawing.Point(354, 14); + this.pnlAdded.Name = "pnlAdded"; + this.pnlAdded.Size = new System.Drawing.Size(30, 20); + this.pnlAdded.TabIndex = 2; + // + // pnlModified + // + this.pnlModified.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.pnlModified.BackColor = System.Drawing.Color.Blue; + this.pnlModified.Location = new System.Drawing.Point(504, 14); + this.pnlModified.Name = "pnlModified"; + this.pnlModified.Size = new System.Drawing.Size(30, 20); + this.pnlModified.TabIndex = 3; + // + // btnRowToRow + // + this.btnRowToRow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnRowToRow.BackColor = System.Drawing.Color.LightGray; + this.btnRowToRow.Location = new System.Drawing.Point(10, 6); + this.btnRowToRow.Name = "btnRowToRow"; + this.btnRowToRow.Size = new System.Drawing.Size(120, 30); + this.btnRowToRow.TabIndex = 4; + this.btnRowToRow.Text = "Update row --> row"; + this.btnRowToRow.UseVisualStyleBackColor = false; + this.btnRowToRow.Click += new System.EventHandler(this.btnRowToRow_Click); + // + // btnMerge + // + this.btnMerge.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnMerge.BackColor = System.Drawing.Color.LightGray; + this.btnMerge.Location = new System.Drawing.Point(136, 6); + this.btnMerge.Name = "btnMerge"; + this.btnMerge.Size = new System.Drawing.Size(100, 30); + this.btnMerge.TabIndex = 5; + this.btnMerge.Text = "Merge all -->"; + this.btnMerge.UseVisualStyleBackColor = false; + this.btnMerge.Click += new System.EventHandler(this.btnMerge_Click); + // + // btnUpdateRow + // + this.btnUpdateRow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnUpdateRow.BackColor = System.Drawing.Color.LightGray; + this.btnUpdateRow.Location = new System.Drawing.Point(242, 6); + this.btnUpdateRow.Name = "btnUpdateRow"; + this.btnUpdateRow.Size = new System.Drawing.Size(100, 30); + this.btnUpdateRow.TabIndex = 6; + this.btnUpdateRow.Text = "Update row -->"; + this.btnUpdateRow.UseVisualStyleBackColor = false; + this.btnUpdateRow.Click += new System.EventHandler(this.btnUpdateRow_Click); + // + // btnCommitChanges + // + this.btnCommitChanges.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCommitChanges.BackColor = System.Drawing.Color.LightGray; + this.btnCommitChanges.Enabled = false; + this.btnCommitChanges.Location = new System.Drawing.Point(675, 6); + this.btnCommitChanges.Name = "btnCommitChanges"; + this.btnCommitChanges.Size = new System.Drawing.Size(100, 30); + this.btnCommitChanges.TabIndex = 7; + this.btnCommitChanges.Text = "Commit"; + this.btnCommitChanges.UseVisualStyleBackColor = false; + this.btnCommitChanges.Click += new System.EventHandler(this.btnCommitChanges_Click); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.pnlSource); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.pnlDestination); + this.splitContainer1.Size = new System.Drawing.Size(787, 462); + this.splitContainer1.SplitterDistance = 353; + this.splitContainer1.TabIndex = 3; + // + // pnlSource + // + this.pnlSource.Controls.Add(this.lblSrc); + this.pnlSource.Controls.Add(this.srcDgv); + this.pnlSource.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlSource.Location = new System.Drawing.Point(0, 0); + this.pnlSource.Name = "pnlSource"; + this.pnlSource.Size = new System.Drawing.Size(353, 462); + this.pnlSource.TabIndex = 6; + // + // lblSrc + // + this.lblSrc.Dock = System.Windows.Forms.DockStyle.Top; + this.lblSrc.Font = new System.Drawing.Font("Verdana", 14F, System.Drawing.FontStyle.Bold); + this.lblSrc.Location = new System.Drawing.Point(0, 0); + this.lblSrc.Name = "lblSrc"; + this.lblSrc.Size = new System.Drawing.Size(353, 23); + this.lblSrc.TabIndex = 0; + this.lblSrc.Text = "Source"; + // + // srcDgv + // + this.srcDgv.Dock = System.Windows.Forms.DockStyle.Fill; + this.srcDgv.Location = new System.Drawing.Point(0, 0); + this.srcDgv.Name = "srcDgv"; + this.srcDgv.Size = new System.Drawing.Size(353, 462); + this.srcDgv.TabIndex = 3; + // + // pnlDestination + // + this.pnlDestination.Controls.Add(this.lblDestination); + this.pnlDestination.Controls.Add(this.destDgv); + this.pnlDestination.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlDestination.Location = new System.Drawing.Point(0, 0); + this.pnlDestination.Name = "pnlDestination"; + this.pnlDestination.Size = new System.Drawing.Size(430, 462); + this.pnlDestination.TabIndex = 6; + // + // lblDestination + // + this.lblDestination.Dock = System.Windows.Forms.DockStyle.Top; + this.lblDestination.Font = new System.Drawing.Font("Verdana", 14F, System.Drawing.FontStyle.Bold); + this.lblDestination.Location = new System.Drawing.Point(0, 0); + this.lblDestination.Name = "lblDestination"; + this.lblDestination.Size = new System.Drawing.Size(430, 23); + this.lblDestination.TabIndex = 0; + this.lblDestination.Text = "Destination"; + // + // destDgv + // + this.destDgv.Dock = System.Windows.Forms.DockStyle.Fill; + this.destDgv.Location = new System.Drawing.Point(0, 0); + this.destDgv.Name = "destDgv"; + this.destDgv.Size = new System.Drawing.Size(430, 462); + this.destDgv.TabIndex = 3; + // + // DataCompareForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(787, 510); + this.Controls.Add(this.splitContainer1); + this.Controls.Add(this.pnlControl); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MinimumSize = new System.Drawing.Size(478, 250); + this.Name = "DataCompareForm"; + this.Text = "DataCompare"; + this.pnlControl.ResumeLayout(false); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + this.splitContainer1.ResumeLayout(false); + this.pnlSource.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.srcDgv)).EndInit(); + this.pnlDestination.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.destDgv)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private Button btnRowToRow; + private Button btnMerge; + private Button btnUpdateRow; + private Button btnCommitChanges; + private Label lblAdded; + private Label lblModified; + + private Panel pnlControl; + private Panel pnlAdded; + private Panel pnlModified; + private SplitContainer splitContainer1; + private Panel pnlSource; + private Label lblSrc; + private DataGridView srcDgv; + private Panel pnlDestination; + private Label lblDestination; + private DataGridView destDgv; + } +} diff --git a/OpenDBDiff/Front/DataCompareForm.cs b/OpenDBDiff/Front/DataCompareForm.cs new file mode 100644 index 0000000..d6bf604 --- /dev/null +++ b/OpenDBDiff/Front/DataCompareForm.cs @@ -0,0 +1,130 @@ +using System; +using System.Data; +using System.Drawing; +using System.Windows.Forms; +using OpenDBDiff.Schema.Model; + +namespace OpenDBDiff.Front +{ + public partial class DataCompareForm : Form + { + public DataCompareForm(ISchemaBase Selected, string SrcConnectionString, string DestConnectionString) + { + InitializeComponent(); + this.selected = Selected; + this.srcConnectionString = SrcConnectionString; + this.destConnectionString = DestConnectionString; + + doCompare(); + } + + private void doCompare() + { + DataTable srcTable = Updater.getData(selected, srcConnectionString); + DataTable destTable = Updater.getData(selected, destConnectionString); + + srcDgv.MultiSelect = false; + srcDgv.ReadOnly = true; + srcDgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + srcDgv.RowHeadersVisible = false; + srcDgv.DataSource = srcTable; + srcDgv.Rows[0].Cells[0].Style.ForeColor = Color.Blue; + + destDgv.MultiSelect = false; + destDgv.ReadOnly = true; + destDgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + destDgv.RowHeadersVisible = false; + destDgv.DataSource = destTable; + destDgv.CellFormatting += new DataGridViewCellFormattingEventHandler(destDgv_CellFormatting); + } + + private void destDgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) + { + DataTable table = (DataTable)destDgv.DataSource; + if (e.RowIndex < table.Rows.Count) + { + if (table.Rows[e.RowIndex].RowState == DataRowState.Added) + { + e.CellStyle.ForeColor = Color.Green; + } + else if (table.Rows[e.RowIndex].RowState == DataRowState.Modified) + { + e.CellStyle.ForeColor = Color.Blue; + } + } + } + + private void btnCommitChanges_Click(object sender, EventArgs e) + { + DataTable destination = (DataTable)destDgv.DataSource; + DataTable edits = destination.GetChanges(); + if (Updater.CommitTable(edits, selected.FullName, destConnectionString)) + { + destination.AcceptChanges(); + doCompare(); + btnCommitChanges.Enabled = false; + } + } + + private void btnUpdateRow_Click(object sender, EventArgs e) + { + DataTable source = (DataTable)srcDgv.DataSource; + DataTable destination = (DataTable)destDgv.DataSource; + + object[] sourceItems = source.Rows[srcDgv.CurrentRow.Index].ItemArray; + + for (int i = 0; i < destination.Columns.Count; i++) + { + if (destination.Columns[i].Unique) + { + if (destination.Rows.Find(sourceItems[i]) == null && destination.Columns[i].AutoIncrement) + { + sourceItems[i] = null; + } + } + } + + destination.BeginLoadData(); + destination.LoadDataRow(sourceItems, false); + destination.EndLoadData(); + btnCommitChanges.Enabled = true; + } + + private void btnMerge_Click(object sender, EventArgs e) + { + DataTable source = (DataTable)srcDgv.DataSource; + DataTable destination = (DataTable)destDgv.DataSource; + + destination.Merge(source, true); + foreach (DataRow dr in destination.Rows) + { + if (dr.RowState == DataRowState.Unchanged) + { + dr.SetAdded(); + } + } + btnCommitChanges.Enabled = true; + } + + private void btnRowToRow_Click(object sender, EventArgs e) + { + DataTable source = (DataTable)srcDgv.DataSource; + DataTable destination = (DataTable)destDgv.DataSource; + + DataRow sourceRow = source.Rows[srcDgv.CurrentRow.Index]; + DataRow destinationRow = destination.Rows[destDgv.CurrentRow.Index]; + + for (int i = 0; i < destination.Columns.Count; i++) + { + if (!destination.Columns[i].Unique) + { + destinationRow[i] = sourceRow[i]; + } + } + btnCommitChanges.Enabled = true; + } + private ISchemaBase selected; + private string srcConnectionString; + private string destConnectionString; + } +} diff --git a/OpenDBDiff/Front/DataCompareForm.resx b/OpenDBDiff/Front/DataCompareForm.resx new file mode 100644 index 0000000..e1fd45f --- /dev/null +++ b/OpenDBDiff/Front/DataCompareForm.resx @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAUAEBAQAAEABACSAAAAVgAAACAgAAABACAAwQIAAOgAAABAQAAAAQAgAE8FAACpAwAAgIAAAAEA + IABcCgAA+AgAAAAAAAABACAASxoAAFQTAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EA + AABZSURBVDiNY9TW1magBLBA6f845BkZGBgYdphrYZX3OHmNkYki6xkYGCg2gJHSMKDYBSwMDAwMTs1O + WANpX+0+RigTZyCPBiKRKVHLbwdW+WubPEYDkYGBAQAQKxEnMldECwAAAABJRU5ErkJggolQTkcNChoK + AAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAAAohJREFUWIXtl79rE2Ecxj93vcTYa3o20BrKRaRWFAmI + OBh16yRUBJf7B1pwyywBJ0OgiyB0NNC1t3Qp1qlLuxSRLmdpBNHG61B/pU3O/PKS1yG5GiVCEgNZ8oWD + L7x8nvfhvXve9z1JCMEgSx7o7EMDgAIQjUYB7gL3gUkgAPi9caAGVIEK8A3YBDYsyzoVsheMrng9bW4A + SEIIotFoHLgF7AG7wDvgECg1BfzANDAL3ACuAe8ty0o2J2/L62mz1Bxvy+tpM+kZEEAM2Olw5cJAxrIs + rTmBAGJ62uyItxeMMJDR06bWukRbwAawDewDR0ABEIAKTAGXabyqeWC0RbMGbNkLRte8ZyAPTAAPmk8n + lf+r74n3UuDvEGqtkZa+Z94zoPYgoP6j74r3DDzuQeBZS98zrwDMPZ0r5T/l1w9fHyq5D7lg1amG6rW6 + hmAMkJAoyiPysW/Ul9MuaCfTN6crodlQzlO6t7NXujp2dn3+/IRyPagGz/mUkE+WNIkGL6Do1sVx3q3l + 9pziyavPx5U3J07O4vdH+Hw8Mh5bia90FKP4WjwMZICkx+87pdi+U+oqxkDyjxjG1+L/FUN6iPEwhsMY + KgCbTzaXInciWXVKXVQn1Rl/0K8pZ5SA7JN9EhJ1t+66FbdcdaqF4tfigXPkrGa3s8s8PBVbCkcfZcuF + g8VqITvzs/xdq7vFgKhVfAKBLPtdWRktK4GJgn8schAYv7h69PbFMvTpODYSdlveTOml5nhb3kzp/TmO + jYQtgJiZ0jvijYQdBjJmSu/vcWwk7OE+0DU/3Ae8FABcoXGtvg1conG9DgIS8AP4AnykkZSXwG7rtdxI + 2F3xZkrfPTUwyBr4n9HQwC8Xx0dm0EptCwAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAABAAAAA + QAgGAAAAqmlx3gAABRZJREFUeJztm1FoG3Ucxz9pO7suieu6Wuf8M1E7XGcnOJD1QRSzB4tKtQj3sAd9 + CPZB8F6sMAKDyiDDt5L64kNAURicD8HJMO6hoE/LkGJrGhS2Qdpz3WaXJmvXrFvT+HBZuEtybWyT/Dd7 + Xzi43v/X+/z67V3u/+3/6srn82xnNcluQLYcA2Q3IFuOAbIbkC3HANkNyFbLg53e3t5K4x7gFaAPeBno + BgTwRIXaNHANuAr8AcQK2/XSwng8XlVzul/ZMl+EtTK+Wa4HEyGTAa3AR8DHQI+pdg2YAf4G5oBbwH2M + q6gd2A88BRwA2kzfdxP4GvgSmIX1DdD9St34IqzNbmTAEPBVYWwGOAv8DEwCKduuy9UK9AJvAArGbxFg + DFDtDND9ii1fhLWq+QUTK/JFWFPNtWYDTgJngJ+AYSBRLbAKdQIngU+B8/F4/J0KTVv4IqzVjK/7FQtf + hLUiv8VUdwa4ALxVK7BJ8ximzgKjNjVngAsirNWcL8LaPDCs+5UyvvkpsAYcAT6odQMFvV44d85mfA04 + ovuVuvB1v1KRb74CFjA+RL4BPgO+x7giJoB7m+T2YNyH7wO+wrGMTW2Rr/sVC1+EtU3xdb+yId9sQLNp + v7ewfY7xGJsG/sK4hK8Dt4ElDDebMD512zHudQE8DxzGeGyVym7uYcvX/Urd+C0VCkq1r7Adr6K2Hqor + f9vPBB0DZDcgW2YDdkhgmiWFb/7C3aAG7DhS+GYDvmhQA7/YHJfCNxtwEuO5u1pH+Fng7UoD/bGEFH7p + /Tji7nL3dB7qPO/uct+tBbFtT1tu78G9E50vdA4AJ4A7drX9scTITHal5+LC4vlkdqUm/Osr93O/pZcm + YunFgf5Y4kR/LGHhWyZCvtM+SxxNJ9NR/aI+l7qc8qzeXRXA0xh/jPBi3EtNQB64izHFXACuuZpdyd1i + d0b0CW9Xb9erGHH0HDA2fmrcEkdLNDQ0daXIf9G7K/rukx1zR9vdHk9zc9X81Xw++edSNnPuRsr7663b + Fj5g4RcN8J32WeJoaDBUsziqRtRiHPWd9j0HlMXhwrgljk8vLjO9uFyLFsxx2MIvi8OhwVDN42hoMDQP + DKsRdcM4TIPjeFkcViNqXeKoGlGrisM0OI5XjMNqRLXE0dBgaFNxVI2om4rDNDCOVxWH1YgqNQ5Txzju + xOF6nPRRkmOA7AZky4nDpn0nDjeogYczDo+fGpcah5EUx8tWh499cqw7m8qOtnW0HXd3uXdulZhdyOaW + 55cn82v5kanvpn6EyqvDD/it3gPdj7n3j967M3d8ZTG5Zf6OXftyrR4x6XI1jyzeiJXxSydCQ7GxWDGO + tj/THhV9Yq6ju8PTsrOl6jiaz+WTGT2T0S/q3pvxm+vGUbMOD0QtcXw5NR1NXf1h7s4/E57c/aXq43hT + S7Jtz6FMx7MD3sf3v2bhJ871V47DVIij6WSadDJt6+5/kG0cNf3wFr4WFAljVvvmluFKQC/yDw9E14/D + SF4d1oKi5nwtKOaBYSWgP/yrw0pArwtfCeiPzuqwEtAtfC0oNsVXAvr/Y3VYCehOHK4X3wlDshuQLccA + 074ThxvUgBOHbY5v79VhLSgejjiM8bLxh8B7wNEaQC8DUeBb4BKs/7K0EtDrxteC4lLpYCUDzOrGeE39 + JeAgVcZRjFfWpzGm0b+XnrTa1+WVgL5lvhYUZXyzXM7/DW5zOQbIbkC2HANkNyBbjgGyG5CtfwEXOU0j + eGWigAAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAACAAAAAgAgGAAAAwz5hywAACiNJREFUeJzt + nVtsG1kBhr+4bm512mwvSrudZndpm6oliH3YbqEgAXlyw1LkFYxKXxCyAEHQCF6QsBQJUWQtT5VGRUis + 3PYBUWkesOiuoALJVFoEDd1qJda4bHYD2e30srRqm0sTJ3FqHsZpXGfGHntsx/Y5nzSKMzkzPr/95/jM + mfP7tGWzWSTi4lvvCkjWF2kAwZEGEBxpAMGRBhAcaQDBkQYQHGkAwZEGEBxpAMGRBhAcaQDBkQYQHGkA + wfHb7RwcHPRyzl3AAPBcbtsJ7AZ6c9um3NYJbMAyYRZYBhaBR7ltKrfdAW4BN4H/5LYPgaVKKpdMJitT + 5YAZVgt31VW/EjM81d/WAGXQBxwBXgZeBAaBPdS+ZbkLXAfeAa4CV4CJGj/nGsywuu76zbB6FbiixIyK + 9LfZTQgp0QIcAI4Dw8DncWeiDJarH7Lq8HRu/2OgLXeedlb/Q7YAAaDDlRL4J/Bn4HfA35wKeW0BzLDa + 8PqVmOGov5ByDPAN4NvAl4qcbzy3JYEbwAdYbr0FzABzbiuGJXwTVhPaB/QDLwAHgf3AIZxfnOvAOeDX + WM3oEyo1gBlWm1K/EjOmHMoA7gzwKvAz4JM2x18DLgN/zT2+UezJqsw24FPAZ4AvAl/A+lzN5yHwC+C1 + lR3lGsAMq02vX4kZr+FAKQOcB75Z8Od/AL8B/sA6fO4WYTsQBL4GfLXgb1dz+26XYwAzrJ6niH4lZkzY + dALrykon0AyrJfUrMeN24fHFDPDH3AlXuIT133TZe7VrzgDwQ+B7efvuAgeSyeQDNycww6qtfiVmXC4o + 562mHrG7CjDDqqN+JWY8pd+pt/pdVsUvASeBYzTHmw/W5/D3gZeA93P7dgCvuznYDKtr9Csx41jhm9+o + KDFjXIkZrvQ79WBP5n5msTobH1S7knXiGlZrMIl1Tf6Ky+Oe0q/EjKbUr8SMa8CAGVYncdDv1AIs5z0+ + XP2q1ZX9rHaOMi6PaRn9Zlgtqt/JAIu5n23Ab4EzQE/Va1d7foD1cdCX+/2xy+Oe0m+G1TNmWG06/WZY + Lanf7UjgCHACOI11fXmrGhWsERuxmvAfAZ+u0jlHgBNmWD0NnFNiRsPqN8NqWfrLGQreBvwc+CkQB94E + /kJ9r32dCGAN0LyCNUq3swbP8US/GVYbSr8ZVivWX8m9AD/w9dwGMIY19Pp34F2ssYGKbtSUwR6sQZCX + sAZCPot1o6UeNJR+M6x60u/1ZhBYN0OOYDU5APeAf7M6FPq/3OOH2I+FZ7H6IhuwxsK7sYZAe7H6HbuB + Z7FEfwLYhzUs2ig0tf5qGKCQ7Vg3SYrxGKujtczqC+DL1acWdaonTaV/vV5sH2vHrUWiYfTLGUGCIw0g + ONIAgiMNIDjSAIIjDSA40gCCIw0gOE4G2FjXWtQPt7qE0e9kgLYaV2S9cNviCaPf6QW5UOOKrBdvuCwn + jH4nA7yONSu4lbiLFewoiRIzhNFfrEkcxsoFtAJvY82OcTUlHECJGS2nv3BKOJT+TPwWVjLoX7WoVR14 + CPwEa2LnmlCEE4ODgwwODhIcS7WE/uBY6nBwLHXbLvLnplMUx0q9nsSaAtUMXAd+DDxPXiysEoJjqXhw + LNW0+oNjqaL6y5kPcAG40P+5/uGFmYWRubtzR2c/nu3NPm6Mr5vv3t6d7t7Rnezc3HnWHDN/Ve3zB8dS + F4AL3+nvG97a7h/Z09lx9Pnujt4NbY1xwXAzvZj+aH4heW9x6ewvJ++41u86HTx0amhNOnZxdpFpc5pp + c5qZOzPM3p5dWphZ8JOt7WWUv9OfCfQFfD3P9vh6dvewZc8WurZ25Rd5ko5NjCbKTge7TUc/s9HPgUAX + BzZ1sXdTJ3u7O5e2tvv9bTW+jJxdXs58OLfge/9R2jf+aJ7rs/PcTi/mF3Gdji5pgKFTQ67TsYnRxA1W + vyGjH6sJLvYNGX5WX6wMq9+QMYf1+eX0DRkfDZ0a6sFlOjYxmigrHVxpOvrSkUN10x8cS7nWT5F0tK0B + VtDi2nmKpGP1kD6hxTXH4+uBHtIB0OJayXSsHtJddQRFSkc7GkCLa7bpWD2kXy4o56XSnlkxQD5aXHNM + x+ohveSloEjpaNurAC2urUnH6iH9WOGb36joIX1cD+kVp4MRKB3tKh2sh/SmTMfqIf0aMKDFtUk8pINp + 4XR0y6eDtbgmdDqYEuloV+lgLa6d0eJa06VjtbhWlXQwLZyOLisdrMW108A5PaQ3bDpWi2s1SwfTguno + itLBWlxrqHSsFtfqmg6mhdLRTZ8O1uKa0OlgPKajZTrYO02tX6aDq09T6Zfp4PWhYfTLaeGCIw0gONIA + giMNIDjSAIIjDSA40gCCIw0gODId7K1csyHTwS7LCaNfpoPtEUa/rQH0kC5MOtYBYfQ7Nol6SG+5dKyb + KeF5tJx+bNLRtgZYSccmRhMtkY5NjCYOJ0YTtunYErSEfoqko0t2ihKjiXhiNNG06dj8WFiFtHQ6uuy1 + g/cF9w139HSMdO/oPhroC/S2+Rqjwzx3by49d3cumZ5Onx1/c9wxHeshHArAtr2vDmfS90cWZm8cXZie + 7M1mlx3L1pP2wO50R6A/ubFr+9n7/33DtX5Pawe3B9rZrGxms7KZnp09BHYFljp6Ovy01fYyKpPOZGY/ + nvXN3JrxzdycYerGFPP35/OLeFo72E7/oeOX1ujPLDxg/sF7zD98j/TUBOmpiaVM+r4fsjXVv2FjINPR + 85yvs3e/r6t3gK5nDtK+aVd+kSf6UxeD3tLBlJGOHTo1VLd0bGI0UZV0rB35+g8dv+Raf+pisG76Dx2/ + 5Fp/6mKwvHSwSOnYYqgR8zxF9BtRZUKNmJXWtyoYUQUANWKW1G9EFbl2sNu1g9WIaavfiCqXC8p5q6lH + VgyQjxoxHfUbUUWuHVwKNWKu0W9ElWOFb36jYkSVcSOqyLWDqdLawUZUaUr9RlS5BgyoEXMSUdPBCL52 + sBox5drBeEwHqxHzjBoxm06/GjHl2sFVOucIcEKNmKeBc0ZUaVj9asSUawdT43SwGjEbSr8aMcVNByP4 + 2sFqxJTp4HWmqfXLdHD1aSr9Mh28PjSMfjktXHCkAQRHGkBwpAEERxpAcKQBBEcaQHCkAQRHpoO9lWs2 + ZDrYZTlh9Mt0sD3C6JdrB9tgRBVh9Mu1gx0wokrL6S+cEg5y7eCiGFGlJfQbUeWwXSgEPGYDGxhP2UA7 + 1IjZlPqNqDJVrGDZ6WDgIPAV4MvAURpnAse7wJ+A3wNvORWq1AArqBGz4fUbUcVRfyGVGCCfPqzpUC8D + L2Ll6PdQ+wGme0AKeAcr93YFlzlFrwbIR42YDaPfiCoV5TS9GsCOuqRjWZ27XxbVNADYZgPrqt8uG1gO + RdcOlrQ+8l6A4EgDCI40gOBIAwiONIDgSAMIjjSA4EgDCI40gOBIAwiONIDgSAMIjjSA4EgDCI40gOBI + AwiONIDg/B9DsN1jb+OkIwAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAAEAAAABAAgGAAAAXHKo + ZgAAGhJJREFUeJzt3X9sVfX9x/Fnf9GfloIgird+ccrAgsQfU3RzfmeXbM1Y2FDH0C1bNrLpP3Y6k2Uh + dsk3hGY/so00xmyZbEvMMq1DFn+tEHeVZMuG7ofjWyvMr1il4vwBtIVCSyn3+8f7FEp/cc6958e9/bwe + ySenvdx7zuG+bt/33M/5nM8tymQyiIibipPeARFJjgqAiMNUAEQcpgIg4jAVABGHqQCIOEwFQMRhKgAi + DlMBEHGYCoCIw1QARBymAiDiMBUAEYepAIg4TAVAxGEqACIOUwEQcZgKgIjDVABEHKYCIOIwFQARh6kA + iDhMBUDEYSoAIg5TARBxmAqAiMNUAEQcpgIg4jAVABGHlQa58/Lly6Paj2xUAHOBeuAC7+cLgDpgHjAb + qPZajbesAmYBZUCJtxx1ChgGRoATwBAwABz12ujPh7x2EPjAWx7wWj+QN1+33NnZGfk2etavjXwbU1D+ + QGpLe06PD1QAElAJLASWAkuAS4BFQAoLvg4LNB8cBf4D7Afe8to+4FXgNexFI8Eo/4jlUwGoBq4ArgMW + A9cCDVhlL4SPKjXA5V4b7xjwNvB3oBN4Bfgb0BPb3uU/5Z+AJAtAHXDDmLbSu20mqsJe1IvH3DYMvAGk + gd3ecm/8u5YY5Z8H+cddAJYAq4BbvFYd8/bzSRnwYa+Neg14BngB+CN2WDmTKP8z8iL/OArAUuA24Fbg + moi3NYgdbh0CDmMdN+PbCeCk14bHPLaYM51Ds7BOphqseo8ua7FD0tne72Efmi4G7vVaL/A08HvgKW+/ + C5Hy9y/2/KMqABXAl4A7gE+GtM5TWKj7gDe99h722eod4H3v9yPAcaLrjR19cZyP9TovwDqqLgQuxjqq + Lvd+r8phO3XAl712ANgKPAK8lMM646L8CyT/sAvAxcDdwNexJyVbfcAe4B/Y56RXvfYOVuGTdMJr/di+ + TaYYmIO9EBqAy7AOrmuwHuygz/tC4B6vdQAPYe8K+Ub5m4LJP6wCcB7wXeBbZPe5rht4Hush/Yu3PBLS + viXhFHZ++CCwa8ztJdgL4EZghbe8jmDPWZPXdgKtwI4Q9jdXyv9sBZN/USbj/0hpioFAdwLfx87L+tUL + PAf8GfsP7MUGYLioDrgZuAkL9sqAj98KfBs773yWmAYCKf/chJJ/akv7hPz9yKUAzAZ+Bazx+fCDWIdG + B7Cdwq7wUVqG9ZSvwU6P+XEYuAt4fOyNURaAnvVrlX80ss4/taX98XPec5xsC8AS7DPI4qnvfdoO4DdY + pRoIuH+uuxrrBLoDuMjH/TcBD4z+ElUB6Fm/VvnHI3D+qS3tD5z7bmdkUwAuxUYxzT3H3R8BHgReDLJD + MqkK7IXQzLkPETcD90E0BaBn/VrlH79A+ae2tN/nd8VBz2OWY4MUpgv/d9gwzq+g8MMyCDyMdRx9Axtv + PpV7sY8DoetZv1b5JyNQ/j3r1/rOP2gB+BF2nnMy+4DPAl/ATt9INB7G3gV+Mc19fob1NodN+SfPV/49 + 69f6yj9oAbhnitu3Y1X/mYDrk+z0Ad/EzsBM5f4Itqv880No+YcxlPFZ7PRFbwjrkmB+C3waO0Qcb1VM + +6D8k5Nz/rkWgBFsjLckZwd2yD+en17jXCn/hKW2tOeUf64FoIj43mlkapNdZHM8hu0q//yQdf65FoBi + oB07BJRkPIGNJBsvjis9lX/CetavzSn/MPoASoA/4J17ltgsA/7E1CPxyqa4PWzKPxmh5B/m9cw/wWY1 + WRniOmVy3wFeBj42zX3inpxU+ccntPzDntDgFuCv2NDPFSGvW+CrQBfwA/JrPsdRyj9aoecf1WSLdwL/ + Ah4FPhXRNlyxEDun+yrwa+y68nyn/MMTaf5Rv4t80Wu7gceAbdh/RKZXgY2q+zxwOzYEuxAp/+zEln9c + h5ErvLYJGx++HTt/vYuz52Vz2UXYKbWbgM8A85PdnVAp/3NLJP8kPkde77UW7KKG57B3iOexd4dCnfwy + qPlY2B8BPo51nuXLl1xESfmbvMg/6Y6keuBrY34/gE0JtRv78oR/YpM+DsW/a6Gag82Oey12Df1HgeXY + oZ7LlH/Cki4A4y3EppC+zfv9FDbT66vYJJH7savO3sBmhe0lP14cRdjU0RdhX111GXY13uXY+dpFuD0H + vl/KP2b5VgDGK8amV74QO8U01hD2Ahg/LXQfNv1UL/bFCseYOC/8MGe+CBIswFnjlqPzwo9+wWQVNg3a + XGwet/Oxw7gF2Gy4F2Dzxkt4lH/E8r0ATKcce/IXBHjMiNdOjVmCBV7iLYu9Zam3lPyk/ENQyAUgGyVe + Ezcp/3EK4VtXRSQiKgAiDlMBEHGYCoCIw1QARBymAiDiMBUAEYepAIg4TAVAxGEqACIOUwEQcZgKgIjD + VABEHKYCIOIwFQARh6kAiDhMBUDEYSoAIg5TARBxmArAzKVs3eYrf71IZq64vx5c8ksiXw8u+eOdpHdA + EuUr/6AFQO8qheOZCNap/AuHr/yDFoCfZrEjkowfR7BO5V84fOUftABsALoD74rE7W6gJ4L1Kv/CcHdq + S7uv/IMWgCHsO9oOBt4lictm4OdRrDi1pV3557/NqS3tvvPPphOwG7gR2JvFYyVam4D7otxAakt7N8o/ + X21KbWkPlH+2ZwFeA64Dtmb5eAlXL7AOeCCOjaW2tCv//NILrEttaQ+cf1Em479jd/ny5ZPdvA74IVAf + dOMSiq3A/cCb4/+hs7Mz1A1Nln/Hygbln6ytwP1Nu7qyyj+McQCPAsuww8+jIaxP/NkJNAG3M8kff4yU + fzJ2Ak1Nu7pun+yP36+wBgIdwQ4/lwAbgbdDWq9MtB1YDXzC+zkfKP/4hJp/2CMBDwDfAy4D1gPPh7x+ + V70LPAhcj73rP5Xs7kxJ+UcjsvxLw1rROEPAL712JXAr8Dng6oi2N/MU0UeGp4FngSeAwYT3KAjln6MM + 9BURff5RFYDTGjc2DgMngczAewN8sPcDert76e3uZeTESNSbLyiVcyuZt3QecxbNYc6H5lBSXpLB/phO + pVvSSe9eVpp2dZ3O/78qy7m+roYVtdUsP6+KyhJdijLWgcET7Oo9yu7+AV7uH+D4yKnT+XesbIhkm2Gc + BZigcWNjBfAl4A7gk5Pd5+TgSfr299Hf00///n769vdxcvCk730pdEUlRVTWVTLnQ3OoubCGOR+aQ9X5 + VVA06d0PYL29j6Rb0i/53UZMZwEm3Na0q+uc+deUlLD0vEqWVleytKaSpedVUlNSEur+5rOTmQzvDg3z + cv8Abxwb5OW+Ad4ePDHVxRan8+9Y2XBW/k27uqbchp/8Qy0AjRsbL8aGoX4dWOh7xcDIiRGOfXCM/p5+ + Bt4fGOrb33fi2PvHykaGR8rJTPFnUSCKSoqGy6rKhmpTtUW1C2srqy+oLq5N1VJeW57N6jqAh9It6XN+ + Doy7ADTt6so6/4riYuorZ7GkppL6ivKhK86rPFFfUV5WUVJcXjRVWSwQJzOZ4f6TI0N7jx4vem1gsLL7 + 2GDxvwcG+eDEcDar6wAe6ljZ8BTkSQFo3Nh4HvBd4FtAte8VntGNdRh1An8BOtMt6SNAJfZCWor1MNcD + lwIp7+c6YFYW24vCAHYJ5n6vvQW8DuzBBk4datzYWIzt+43ACm95Hdk9ZzuB1nRLesdUd4irADTt6go9 + /46VDTMu/6ZdXaHnD+SUf84FoHFj453A9wk2EKQXeA74M/Yf2JtuSQftEKgA5gKXAPOB871lnbesxZ7Y + aqDGa1VAmddKObsPJAOMfl4dxjpdBrBz2wNjfj6EjYUf2w5gp776CXjJbOPGxjrgZuAmrIf3yiCPxw4N + v51uSb81/h/iKABAKPl3rGxwMv+mXV2h5I8VnLOEXgDGat7WPBv4FbDG50MOAr/HDmG2Y+eOZaJlwCrs + eb3B52MOA3e1rWl7PLK9YkIBUP7RyDp/4Kz8IysAzdual2DnIhf7uPsO4DdYpRoIvDG3XQ18GetMu8jH + /Te1rWmL7HqAMQVA+ccjcP6MuR4kkgLQvK35UuBv2OHXdB7BBi+8GGgDMpkK7IXQzLkPETe3rWmL5IpA + rwAo//gFyh/vitDQrwVo3tZcDrzA9OH/DrgW+AoKPyyDwMNYx9E3sE6mqdzbvK35roj2Q/knI1D+2McB + X4KOxPgR1ukymX3AZ4EvAP8IuF7x72HsXeAX09znZ83bmlMRbFv5J89X/tjZhnMKWgDumeL27VjVj2Ii + SpmoD/gm1gM/lfsj2K7yzw+h5R/GWMxnsdMXvSGsS4L5LfBpJh8nviqmfVD+yck5/1wLwAh2oYckpG1N + 2w7skG88P73GuVL+ycsp/1wLQBHxvdPI1K6Z5LbjMWxX+eeHrPPPtQAUA+3YIaAkoHlb8xPYSLLxIr/S + E+WfD3LKP4w+gBLgD0Q8G61MsAz4E1OPxCuLaT+UfzJCyT/MC7J/AqSBlSGuUyb3HeBl4GPT3Cfur/FS + /vEJLf+wZ2S4BfgrNvRzRcjrFvgq0AX8gHgO8YNS/tEKPf+opmS5E/gXNmPspyLahisWYud0XwV+DVyR + 6N74o/zDE2n+Ub+LfNFru4HHgG3Yf0SmV4GNqvs8Nu13VjOH5AHln53Y8o/rMHKF1zZh48O3Y+cvd2HX + Xoudt12FXRf+Geya9plC+Z9bIvkn8Tnyeq+1YBc1PIe9QzyPvTucSGCfkjAfC/sjwMexzrN8md0mSsrf + 5EX+SXck1QNfG/P7AWxKqN3AK8A/sZlWhuLftVDNwaa1uha7hv6jwHLsUM9lyj9hSReA8RYCt3kN4BTw + HvbOsAd7x9gHvIF9HVYv+fHiKMKmnLoIWIR9MUYKuBw7X7uI7OZ9c43yj1m+FYDxioELvXbLuH8bwl4A + b2OTMb6PvVj6sOmnerE53I5xZk63AewQc9hro/PQFWGHX2OXFVioo/PKVWHTYM3F5p0bnYNuAXAxcAE2 + D52ER/lHLN8LwHTKsSd/QYDHjHjt1JglWOAl3rLYW5ZS4NNRz3DKPwSFXACyUeI1cZPyH0ffzSTiMBUA + EYepAIg4TAVAxGEqACIOUwEQcZgKgIjDVABEHKYCIOIwFQARh6kAiDhMBUDEYSoAIg5TARBxmAqAiMNU + AEQcpgIg4jAVABGHqQCIOEwFYOZStm7zlb9eJDNX3F8PLvklka8Hl/zxTtI7IInylX/QAqB3lcLxTATr + VP6Fw1f+QQvAT7PYEUnGjyNYp/IvHL7yD1oANgDdgXdF4nZ325q2ngjWq/wLw92Ar/wDFYC2NW1D2He0 + HcxipyQem9vWtP08onUr//y3GfCdf+BOwLY1bd3AjcDeoI+VyG1qW9N2X8Tb6Eb556tNQKD8szoL0Lam + 7TXgOmBrNo+X0PUC69rWtD0Q0/aUf37pBdYBgfMvymT8d+wuX758wm2NGxvXAT8E6oNuXEKxFbg/3ZJ+ + c/w/dHZ2hrqhyfLHXnjKPzlbgfuBrPIPYxzAo8Ay7PDjaAjrE392Ak3plvTtk/3xx0j5J2Mn0ATcziR/ + /H6FNRDoCHb4sQTYCLwd0nplou3AauAT3s/5QPnHJ9T8wx4JeAD4HnAZsB54PuT1u+pd4EHgeqzqP5Xs + 7kxJ+UcjsvxLw1rROEPAL712JXAr8Dng6oi2N/Nk6KOIp4FngSeAwYT3KAjln7OiPshEnn9UBeC0dEt6 + GDgJZKovqGbeknnULaqjblEdJbNKot58QTl+6Dgf7PmAw92HObzvMCNDIxnsj+lU48bGpHcvKw2rO07n + P3TkTY6++yIDB3dz7GAnp04eT3r38sqs6oXULFhJ9bwVVM+7iuLSytP5dz3ZFMk2wzgLMOG2dEu6AvgS + cAfwycnWVVpRyuz62dSmaqmtr2V2/WxKKyKvR3kjM5LheO9xDu87zNH/HOXwvsMcO3hsqtH2B7De3kca + Nza+NPYf0i3pKbcR01mACRpWd5wz/5Hhoxw/vOesNjLsTh9iUXEpZZULqJ5/FRW1l1I97ypm1VwMFE12 + 99P5dz3Z9NJkd5iMn/xDLQDplvTF2DDErwMLfa8YKJlVQtW8KmpTtVTPrx6aXT/7RNX8qrKSspJyiiZ/ + VgpFZiQzPHxseKi/p7+o/0B/5cB7A8X9Pf0M9Q9ls7oO4KHGjY1PQX4VgIbVHVnnf2pkkBNH9nO8dy9D + R/YPHT/86omho/vLTp0cLIdMQedfVFw6XDKrdqiybklRRd3iyorzFhVX1H2Yssp52ayuA3io68mmc/YD + xFYA0i3p84DvAt8Cqn2v8IxurMOoE/gL0Nm4sfEIUIm9kJZiPcz1wKVAyvu5DpiVxfaiMIBdgrnfa28B + rwN7sIEzh9It6WJs328EVnjL68juOdsJtAI7prpDXAWgYXVH6Pl3Pdk04/JvWN0Rev5dTzbllH/OBQC4 + E/g+wQaC9ALPAX/GXsB7Gzc2jgR4PEAFMBe4BJgPnO8t67xlLfbEVgM1XqsCyrxWytl9IBlg9PPqMNbp + MoCd2x4Y8/MhbCz82HYAO/XVT8BLZtMt6TrgZuAmrIf3yiCPxw4Nv4294M4SRwFoWN0RSv5dTzY5mX/D + 6o5Q8u96simr/HMpALOBXwFrfD78IPB77BBmO3buWCZaBqzCntcbfD7mMHAX8PjYG8MuAGOt3dCj/KOR + df7tranHz3nPcbItAEuwc5GLfTxsB/AbrFINBNw/110NfBnrTLvIx/03MWY8eFQFYO2GHuUfj8D5t7em + Al0PkE0BuBT4G3b4NZ1HsMELLwbZIZlUBfZCaObch4ib8a4Ii6IArN3Qo/zjFyj/9taU7ysCg44ELAde + YPrwfwdcC3wFhR+WQeBhrOPoG1gn01TuxT4OhG7thh7ln4xA+a/d0OM7/6AF4EdYp8tk9gGfBb4A/CPg + esW/h7F3gV9Mc5+fYb3NYVP+yfOV/9oNPb7yD1oA7pni9u1Y1Y9iIkqZqA/4JnYGZir3R7Bd5Z8fQss/ + jIuBnsVOX/SGsC4J5rfAp5l8nPiqmPZB+Scn5/xzLQAj2IUekpwd2CH/eH56jXOl/BPW3prKKf9cC0AR + 8b3TyNSumeS2OK60Uf75Iev8cy0AxUA7dggoyXgCG0k2XhxXVin/hK3d0JNT/mH0AZQAfyDgbKSSs2XA + n5h6JF5ZTPuh/JMRSv5hzgj0EyANrAxxnTK57wAvAx+b5j5xf42X8o9PaPmHPSXYLcBfsaGfK0Jet8BX + gS7gB8RziB+U8o9W6PlH9e3AdwL/wmaM/VRE23DFQuyc7qvAr4ErEt0bf5R/eCLNP+p3kS96bTfwGLAN + +4/I9CqwUXWfx6Z9Lk92d7Km/LMTW/5xHUau8NombHz4duz89S7s2mux87arsOvCP4Nd0z5TKP9zSyT/ + JD5HXu+1Fuyihuewd4jnsXeHEwnsUxLmY2F/BPg41nmWL7PbREn5m7zIP+mOpHrga2N+P4BNCbUbeAX4 + JzbTSlaT5+WROdi0Vtdi19B/FFiOHeq5TPknLOkCMN5C4DavAZwC3sPeGfZg7xj7gDewr0PqJT9eHEXY + lFMXAYuwL8ZIAZdj52sXkd28b65R/jHLtwIwXjFwodduGfdvQ9gL4G1sMsb3sRdLHzb9VC82h9sxzszp + NoAdYg57bXQeuiLs8GvssgILdXReuSpsGrS52Lxzo3PQLQAuBi7A5qGT8Cj/iOV7AZhOOfbkLwjwmBGv + nRqzBAu8xFsWe8tSppikXfKC8g9BIReAbJR4Tdyk/MeJaiCQiBQAFQARh6kAiDhMBUDEYSoAIg5TARBx + mAqAiMNUAEQcpgIg4jAVABGHqQCIOEwFQMRhKgAiDlMBEHGYCoCIw1QARBymAiDiMBUAEYepAIg4TAVg + 5lK2bvOVv14kM1fcXw8u+SWRrweX/PFO0jsgifKVf9ACoHeVwvFMBOtU/oXDV/5BC8BPs9gRScaPI1in + 8i8cvvIPWgA2AN2Bd0XidjfQE8F6lX9huLu9NeUr/6AFYAj7jraDgXdJ4rIZ+HkUK25vTSn//Le5vTXl + O/9sOgG7gRuBvVk8VqK1Cbgvyg20t6a6Uf75alN7aypQ/tmeBXgNuA7YmuXjJVy9wDrggTg21t6aUv75 + pRdY196aCpx/LqcBjwC3A3dg39suydgKXAU8FudG21tTR9pbU8o/eVuBq9pbU1nlH8Y4gEeBZdjh59EQ + 1if+7ASasCL8ZoL7ofyTsRNoam9N3d7emso6/7AGAh3BDj+XABuBt0Nar0y0HVgNfML7OR8o//iEmn/Y + IwEPAN8DLgPWA8+HvH5XvQs8CFyPves/lezuTEn5RyOy/EvDWtE4Q8AvvXYlcCvwOeDqiLY3E/Vio7me + BZ4ABpPdnUCUf+5iyT+qAjDW/3rtf7DPiquA/wZuBmpi2H4h+T/gaeAF4I/MjM/Uyt+/2POPowCM9YrX + fgjUATcAK73lDd5trhjGxlT8EdgNpIF/M7PH2yv/M/Ii/7gLwFi9QIfXAKqBpdjnnMXAtUADMJfCv2rx + GPb5+O9AJ/ZH8BLRDNctFMo/D/JPsgCMN4A9QX8fc1slsBB7YSwB6oFLgZT3cx0wK97dnNIAdgnmfq+9 + BbwO7MEGTh1iZr+750r5JyCfCsBkjmNP4utMvLyxAnt3uASYD5zvLeu8ZS32rlKNfdasAaqAMq+Vcvb/ + P4Mdlp30loNYqEe95ejPh7Cx8GPbAezUVz95GHIBU/4RK8pkCmp/RSREhf7ZSkRyoAIg4jAVABGHqQCI + OEwFQMRhKgAiDlMBEHGYCoCIw1QARBymAiDiMBUAEYepAIg4TAVAxGEqACIOUwEQcZgKgIjDVABEHKYC + IOIwFQARh6kAiDhMBUDEYSoAIg5TARBxmAqAiMNUAEQcpgIg4jAVABGHqQCIOEwFQMRhKgAiDlMBEHGY + CoCIw1QARBymAiDiMBUAEYf9P6kddlsUKxPtAAAAAElFTkSuQmCC + + + \ No newline at end of file diff --git a/OpenDBDiff/Front/DatabaseProgressControl.Designer.cs b/OpenDBDiff/Front/DatabaseProgressControl.Designer.cs new file mode 100644 index 0000000..f4c1ad7 --- /dev/null +++ b/OpenDBDiff/Front/DatabaseProgressControl.Designer.cs @@ -0,0 +1,104 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + partial class DatabaseProgressControl + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.lblDatabase = new System.Windows.Forms.Label(); + this.lblMessage = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox1 + // + this.pictureBox1.BackColor = System.Drawing.Color.Transparent; + this.pictureBox1.Image = global::OpenDBDiff.Properties.Resources.database_yellow; + this.pictureBox1.Location = new System.Drawing.Point(3, 3); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(15, 18); + this.pictureBox1.TabIndex = 33; + this.pictureBox1.TabStop = false; + // + // lblDatabase + // + this.lblDatabase.AutoSize = true; + this.lblDatabase.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblDatabase.Location = new System.Drawing.Point(22, 6); + this.lblDatabase.Name = "lblDatabase"; + this.lblDatabase.Size = new System.Drawing.Size(72, 13); + this.lblDatabase.TabIndex = 34; + this.lblDatabase.Text = "Database1:"; + // + // lblMessage + // + this.lblMessage.AutoSize = true; + this.lblMessage.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(192))))); + this.lblMessage.Location = new System.Drawing.Point(22, 23); + this.lblMessage.Name = "lblMessage"; + this.lblMessage.Size = new System.Drawing.Size(0, 13); + this.lblMessage.TabIndex = 35; + // + // progressBar1 + // + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar1.Location = new System.Drawing.Point(25, 40); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(301, 16); + this.progressBar1.TabIndex = 36; + this.progressBar1.Value = 50; + // + // DatabaseProgressControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.WhiteSmoke; + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.lblMessage); + this.Controls.Add(this.lblDatabase); + this.Controls.Add(this.pictureBox1); + this.Name = "DatabaseProgressControl"; + this.Size = new System.Drawing.Size(329, 59); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private PictureBox pictureBox1; + private Label lblDatabase; + private Label lblMessage; + private ProgressBar progressBar1; + } +} diff --git a/OpenDBDiff/Front/DatabaseProgressControl.cs b/OpenDBDiff/Front/DatabaseProgressControl.cs new file mode 100644 index 0000000..dca9756 --- /dev/null +++ b/OpenDBDiff/Front/DatabaseProgressControl.cs @@ -0,0 +1,47 @@ +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + public partial class DatabaseProgressControl : UserControl + { + public DatabaseProgressControl() + { + InitializeComponent(); + } + + public string DatabaseName + { + get { return lblDatabase.Text; } + set { lblDatabase.Text = value; } + } + + public string Message + { + get + { + return lblMessage.Text; + } + set + { + lblMessage.Text = value; + lblMessage.Refresh(); + } + } + + public int Maximum + { + get { return progressBar1.Maximum; } + set { progressBar1.Maximum = value; } + } + + public int Value + { + get { return progressBar1.Value; } + set + { + progressBar1.Value = value; + progressBar1.Refresh(); + } + } + } +} diff --git a/OpenDBDiff/Front/DatabaseProgressControl.resx b/OpenDBDiff/Front/DatabaseProgressControl.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/OpenDBDiff/Front/DatabaseProgressControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenDBDiff/Front/ErrorForm.Designer.cs b/OpenDBDiff/Front/ErrorForm.Designer.cs new file mode 100644 index 0000000..87545ee --- /dev/null +++ b/OpenDBDiff/Front/ErrorForm.Designer.cs @@ -0,0 +1,154 @@ +namespace OpenDBDiff.Front +{ + partial class ErrorForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ErrorForm)); + this.ErrorPanel = new System.Windows.Forms.Panel(); + this.FindIssueButton = new System.Windows.Forms.Button(); + this.CloseButton = new System.Windows.Forms.Button(); + this.CopyButton = new System.Windows.Forms.Button(); + this.ErrorLabel = new System.Windows.Forms.Label(); + this.ErrorInformationTextBox = new System.Windows.Forms.TextBox(); + this.ReportIssueButton = new System.Windows.Forms.Button(); + this.ErrorPanel.SuspendLayout(); + this.SuspendLayout(); + // + // ErrorPanel + // + this.ErrorPanel.Controls.Add(this.ReportIssueButton); + this.ErrorPanel.Controls.Add(this.FindIssueButton); + this.ErrorPanel.Controls.Add(this.CloseButton); + this.ErrorPanel.Controls.Add(this.CopyButton); + this.ErrorPanel.Dock = System.Windows.Forms.DockStyle.Bottom; + this.ErrorPanel.Location = new System.Drawing.Point(0, 299); + this.ErrorPanel.Name = "panel1"; + this.ErrorPanel.Size = new System.Drawing.Size(756, 30); + this.ErrorPanel.TabIndex = 0; + // + // FindIssueButton + // + this.FindIssueButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.FindIssueButton.Location = new System.Drawing.Point(84, 4); + this.FindIssueButton.Name = "btnFindIssue"; + this.FindIssueButton.Size = new System.Drawing.Size(131, 23); + this.FindIssueButton.TabIndex = 2; + this.FindIssueButton.Text = "Search for error on web"; + this.FindIssueButton.UseVisualStyleBackColor = true; + this.FindIssueButton.Click += new System.EventHandler(this.btnFindIssue_Click); + // + // CloseButton + // + this.CloseButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.CloseButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.CloseButton.Location = new System.Drawing.Point(678, 4); + this.CloseButton.Name = "btnClose"; + this.CloseButton.Size = new System.Drawing.Size(75, 23); + this.CloseButton.TabIndex = 1; + this.CloseButton.Text = "Close"; + this.CloseButton.UseVisualStyleBackColor = true; + this.CloseButton.Click += new System.EventHandler(this.btnClose_Click); + // + // CopyButton + // + this.CopyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.CopyButton.Location = new System.Drawing.Point(3, 4); + this.CopyButton.Name = "btnCopy"; + this.CopyButton.Size = new System.Drawing.Size(75, 23); + this.CopyButton.TabIndex = 0; + this.CopyButton.Text = "Copy error"; + this.CopyButton.UseVisualStyleBackColor = true; + this.CopyButton.Click += new System.EventHandler(this.btnCopy_Click); + // + // ErrorLabel + // + this.ErrorLabel.AutoSize = true; + this.ErrorLabel.Location = new System.Drawing.Point(13, 13); + this.ErrorLabel.Name = "lblError"; + this.ErrorLabel.Size = new System.Drawing.Size(254, 13); + this.ErrorLabel.TabIndex = 1; + this.ErrorLabel.Text = "An unexpected error has occured during processing:"; + // + // ErrorInformationTextBox + // + this.ErrorInformationTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ErrorInformationTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ErrorInformationTextBox.Location = new System.Drawing.Point(12, 29); + this.ErrorInformationTextBox.Multiline = true; + this.ErrorInformationTextBox.Name = "txtErrorInformation"; + this.ErrorInformationTextBox.ReadOnly = true; + this.ErrorInformationTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.ErrorInformationTextBox.Size = new System.Drawing.Size(732, 264); + this.ErrorInformationTextBox.TabIndex = 2; + // + // ReportIssueButton + // + this.ReportIssueButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.ReportIssueButton.Location = new System.Drawing.Point(221, 4); + this.ReportIssueButton.Name = "ReportIssueButton"; + this.ReportIssueButton.Size = new System.Drawing.Size(105, 23); + this.ReportIssueButton.TabIndex = 3; + this.ReportIssueButton.Text = "Report issue"; + this.ReportIssueButton.UseVisualStyleBackColor = true; + this.ReportIssueButton.Click += new System.EventHandler(this.ReportIssueButton_Click); + // + // ErrorForm + // + this.AcceptButton = this.CopyButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.CloseButton; + this.ClientSize = new System.Drawing.Size(756, 329); + this.Controls.Add(this.ErrorInformationTextBox); + this.Controls.Add(this.ErrorLabel); + this.Controls.Add(this.ErrorPanel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "ErrorForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Error information"; + this.Load += new System.EventHandler(this.ErrorForm_Load); + this.ErrorPanel.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Panel ErrorPanel; + private System.Windows.Forms.Button FindIssueButton; + private System.Windows.Forms.Button CloseButton; + private System.Windows.Forms.Button CopyButton; + private System.Windows.Forms.Label ErrorLabel; + private System.Windows.Forms.TextBox ErrorInformationTextBox; + private System.Windows.Forms.Button ReportIssueButton; + } +} diff --git a/OpenDBDiff/Front/ErrorForm.cs b/OpenDBDiff/Front/ErrorForm.cs new file mode 100644 index 0000000..952a5e6 --- /dev/null +++ b/OpenDBDiff/Front/ErrorForm.cs @@ -0,0 +1,173 @@ +using OpenDBDiff.Front.Extensions; +using System; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + public partial class ErrorForm : Form + { + private static Regex ExtractBuildPathRegex = new Regex($@"\s+at OpenDBDiff.Front.{nameof(ErrorForm)}.{nameof(GetBuildPath)}\(\) in (.*\\)OpenDBDiff\\Front\\ErrorForm.cs", RegexOptions.Compiled); + private static Regex SystemExceptionsRegex = new Regex(@"\s+at System\.[^\r\n]+\r\n", RegexOptions.Compiled); + private string ErrorInformation; + private Exception Exception; + private string SearchTerm; + + public ErrorForm() + { + InitializeComponent(); + } + + public ErrorForm(Exception ex) : this() + { + Exception = ex; + LoadException(ex); + } + + public void LoadException(Exception ex) + { + var exceptions = ex.FlattenHierarchy(); + var exceptionMessages = exceptions.Select(e => e.Message).ToList(); + var distinctMessages = exceptionMessages + .Distinct() + .OrderByDescending(m => exceptionMessages.IndexOf(m)); + + var exceptionErrorMessage = new StringBuilder(); + exceptionErrorMessage.Append(this.Text); + + foreach (var message in distinctMessages.Skip(1)) + exceptionErrorMessage.Append($"\r\n{message}"); + + var mostInnerException = exceptions.Last(); + + string stackTrace = string.Empty; + if (mostInnerException.StackTrace != null) + { + stackTrace = mostInnerException + .StackTrace; + + var buildPath = GetBuildPath(); + if (!string.IsNullOrEmpty(buildPath)) + stackTrace = stackTrace.Replace(buildPath, string.Empty); + + stackTrace = SystemExceptionsRegex.Replace(stackTrace, string.Empty); + } + + exceptionErrorMessage.Append($"\r\n{mostInnerException.GetType().Name}: {mostInnerException.Message}\r\n{stackTrace}"); + + //var ignoreChunks = new System.Text.RegularExpressions.Regex(@": \[[^\)]*\)|\.\.\.\)|\'[^\']*\'|\([^\)]*\)|\" + '"' + @"[^\" + '"' + @"]*\" + '"' + @"|Source|Destination"); + + int queryMaxLength = 280; //Bug in Github for searching issues? Q max length is 280 + var queryString = new StringBuilder(); + string orOperator = " OR "; + foreach (var message in distinctMessages) + { + var roomLeft = queryMaxLength - queryString.Length; + if (roomLeft > (orOperator.Length + 2 + message.Length)) + { + if (queryString.Length > 0) + { + queryString.Append(orOperator); + } + queryString.Append("\""); + queryString.Append(message); + queryString.Append("\""); + } + } + string searchHash = GenerateHash(queryString.ToString()); + + exceptionErrorMessage.AppendFormat("\r\n\r\n{0}", searchHash); + + ErrorInformation = string.Join("\r\n", + "1. To report an error search first in the Github issues to see if it's already been reported.", + "2a. If there is no issue, click 'New issue' and paste the error details", + " into the body of the issue. To copy the error press \"Copy error\"", + " (At least email the details to opendbdiff@gmail.com)", + "", + "2b. If the issue exists, but your situation is different please leave a comment with the details.", + "", + "• If possible, please attach a SQL script creating the two databases with", + " the minimum necessary to reproduce the problem.", + "" + ).Trim() + "\r\n\r\n" + exceptionErrorMessage.ToString(); + SearchTerm = queryString.ToString(); + + this.ErrorInformationTextBox.Text = ErrorInformation; + } + + private static string GenerateHash(string queryString) + { + var searchableErrorBytes = Encoding.UTF8.GetBytes(queryString); + searchableErrorBytes = new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(searchableErrorBytes); + var searchHash = BitConverter.ToString(searchableErrorBytes).Replace("-", String.Empty); + return searchHash; + } + + private static string GetBuildPath() + { + try + { + throw new Exception("dummy"); + } + catch (Exception ex) + { + var match = ExtractBuildPathRegex.Match(ex.StackTrace); + if (match.Success) + return match.Groups[1].Value; + else + return string.Empty; + } + } + + private void btnClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void btnCopy_Click(object sender, EventArgs e) + { + try + { + Clipboard.SetText(ErrorInformation); + } + catch (Exception ex) + { + MessageBox.Show(this, "Error while trying to copy the error to the clipboard: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void btnFindIssue_Click(object sender, EventArgs e) + { + try + { + System.Diagnostics.Process.Start("https://github.com/OpenDBDiff/OpenDBDiff/issues?q=is%3Aissue+" + Uri.EscapeDataString(SearchTerm)); + } + catch (Exception ex) + { + MessageBox.Show(this, "Error while trying to search the error in the Github issues: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void ErrorForm_Load(object sender, EventArgs e) + { + this.ErrorInformationTextBox.Text = ErrorInformation; + } + + private void ReportIssueButton_Click(object sender, EventArgs e) + { + if (MessageBox.Show(this, "Have you searched Github to determine whether this error has already been reported?", "Searched Github", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes) + { + try + { + System.Diagnostics.Process.Start("https://github.com/OpenDBDiff/OpenDBDiff/issues/new"); + } + catch (Exception ex) + { + MessageBox.Show(this, "Error while trying to create a new Github issue: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + } +} diff --git a/OpenDBDiff/Front/ErrorForm.resx b/OpenDBDiff/Front/ErrorForm.resx new file mode 100644 index 0000000..e1fd45f --- /dev/null +++ b/OpenDBDiff/Front/ErrorForm.resx @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/Front/ListProjectsForm.Designer.cs b/OpenDBDiff/Front/ListProjectsForm.Designer.cs new file mode 100644 index 0000000..46dfeb5 --- /dev/null +++ b/OpenDBDiff/Front/ListProjectsForm.Designer.cs @@ -0,0 +1,182 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + sealed partial class ListProjectsForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem(new string[] { + "ListViewItem", + "ListViewSubItem1", + "ListViewSubItem2"}, 0); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ListProjectsForm)); + this.ProjectsListView = new System.Windows.Forms.ListView(); + this.ProjectNameColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.SourceConnectionStringColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.DestinationConnectionStringColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.IconsImageList = new System.Windows.Forms.ImageList(this.components); + this.ActionsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.OpenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.RenameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.ActionsContextMenuStrip.SuspendLayout(); + this.statusStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // ProjectsListView + // + this.ProjectsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.ProjectNameColumnHeader, + this.SourceConnectionStringColumnHeader, + this.DestinationConnectionStringColumnHeader}); + this.ProjectsListView.Dock = System.Windows.Forms.DockStyle.Fill; + this.ProjectsListView.FullRowSelect = true; + this.ProjectsListView.GridLines = true; + this.ProjectsListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.ProjectsListView.Items.AddRange(new System.Windows.Forms.ListViewItem[] { + listViewItem1}); + this.ProjectsListView.LabelWrap = false; + this.ProjectsListView.Location = new System.Drawing.Point(0, 0); + this.ProjectsListView.MultiSelect = false; + this.ProjectsListView.Name = "ProjectsListView"; + this.ProjectsListView.Size = new System.Drawing.Size(860, 304); + this.ProjectsListView.SmallImageList = this.IconsImageList; + this.ProjectsListView.TabIndex = 5; + this.ProjectsListView.UseCompatibleStateImageBehavior = false; + this.ProjectsListView.View = System.Windows.Forms.View.Details; + this.ProjectsListView.AfterLabelEdit += new System.Windows.Forms.LabelEditEventHandler(this.ProjectsListView_AfterLabelEdit); + this.ProjectsListView.SelectedIndexChanged += new System.EventHandler(this.ProjectsListView_SelectedIndexChanged); + this.ProjectsListView.DoubleClick += new System.EventHandler(this.ProjectsListView_DoubleClick); + // + // ProjectNameColumnHeader + // + this.ProjectNameColumnHeader.Text = "Icon"; + this.ProjectNameColumnHeader.Width = 100; + // + // SourceConnectionStringColumnHeader + // + this.SourceConnectionStringColumnHeader.Text = "Connection"; + this.SourceConnectionStringColumnHeader.Width = 150; + // + // DestinationConnectionStringColumnHeader + // + this.DestinationConnectionStringColumnHeader.Width = 150; + // + // IconsImageList + // + this.IconsImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("IconsImageList.ImageStream"))); + this.IconsImageList.TransparentColor = System.Drawing.Color.Transparent; + this.IconsImageList.Images.SetKeyName(0, "database_yellow.png"); + // + // ActionsContextMenuStrip + // + this.ActionsContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.OpenToolStripMenuItem, + this.RenameToolStripMenuItem, + this.DeleteToolStripMenuItem}); + this.ActionsContextMenuStrip.Name = "ActionsContextMenuStrip"; + this.ActionsContextMenuStrip.Size = new System.Drawing.Size(118, 70); + // + // OpenToolStripMenuItem + // + this.OpenToolStripMenuItem.Name = "OpenToolStripMenuItem"; + this.OpenToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.OpenToolStripMenuItem.Text = "&Open"; + this.OpenToolStripMenuItem.Click += new System.EventHandler(this.mnuItemOpen_Click); + // + // RenameToolStripMenuItem + // + this.RenameToolStripMenuItem.Name = "RenameToolStripMenuItem"; + this.RenameToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.RenameToolStripMenuItem.Text = "&Rename"; + this.RenameToolStripMenuItem.Click += new System.EventHandler(this.mnuItemRename_Click); + // + // DeleteToolStripMenuItem + // + this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem"; + this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.DeleteToolStripMenuItem.Text = "&Delete"; + this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.mnuItemDelete_Click); + // + // statusStrip1 + // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1}); + this.statusStrip1.Location = new System.Drawing.Point(0, 282); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(860, 22); + this.statusStrip1.TabIndex = 6; + this.statusStrip1.Text = "statusStrip1"; + // + // toolStripStatusLabel1 + // + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(214, 17); + this.toolStripStatusLabel1.Text = "Right-click on project for more actions."; + // + // ListProjectsForm + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.ClientSize = new System.Drawing.Size(860, 304); + this.ContextMenuStrip = this.ActionsContextMenuStrip; + this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.ProjectsListView); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.KeyPreview = true; + this.MinimizeBox = false; + this.Name = "ListProjectsForm"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "OpenDBDiff projects"; + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ListProjectsForm_KeyDown); + this.ActionsContextMenuStrip.ResumeLayout(false); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private ListView ProjectsListView; + private ColumnHeader ProjectNameColumnHeader; + private ColumnHeader SourceConnectionStringColumnHeader; + private ImageList IconsImageList; + private ContextMenuStrip ActionsContextMenuStrip; + private ToolStripMenuItem OpenToolStripMenuItem; + private ToolStripMenuItem RenameToolStripMenuItem; + private ToolStripMenuItem DeleteToolStripMenuItem; + private ColumnHeader DestinationConnectionStringColumnHeader; + private StatusStrip statusStrip1; + private ToolStripStatusLabel toolStripStatusLabel1; + } +} diff --git a/OpenDBDiff/Front/ListProjectsForm.cs b/OpenDBDiff/Front/ListProjectsForm.cs new file mode 100644 index 0000000..9684d3f --- /dev/null +++ b/OpenDBDiff/Front/ListProjectsForm.cs @@ -0,0 +1,151 @@ +using OpenDBDiff.Settings; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + public delegate void ListProjectHandler(Project itemSelected); + + public sealed partial class ListProjectsForm : Form + { + public event ListProjectHandler OnSelect; + + public event ListProjectHandler OnDelete; + + public event ListProjectHandler OnRename; + + private IList Projects { get; } + + public ListProjectsForm(IList projects) + { + InitializeComponent(); + + Projects = projects; + + ProjectsListView.Items.Clear(); + + if (Projects.Any()) + { + foreach (var p in Projects) + ProjectsListView.Items.Add(new ListViewItem(items: new string[] { p.ProjectName, p.ConnectionStringSource, p.ConnectionStringDestination }, imageIndex: 0)); + + ProjectsListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); + } + else + { + ProjectsListView.Items.Add(new ListViewItem + { + Text = "There are no saved projects." + }); + } + + ProjectsListView.LabelEdit = true; + } + + private void OpenProject() + { + try + { + if (ProjectsListView.SelectedItems.Count != 0) + { + var item = new Project + { + Id = Projects[ProjectsListView.SelectedItems[0].Index].Id, + ConnectionStringDestination = Projects[ProjectsListView.SelectedItems[0].Index].ConnectionStringDestination, + ConnectionStringSource = Projects[ProjectsListView.SelectedItems[0].Index].ConnectionStringSource, + ProjectName = Projects[ProjectsListView.SelectedItems[0].Index].ProjectName, + Options = Projects[ProjectsListView.SelectedItems[0].Index].Options, + Type = Projects[ProjectsListView.SelectedItems[0].Index].Type, + }; + OnSelect?.Invoke(item); + } + } + catch (Exception ex) + { + MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void DeleteProject() + { + try + { + if (ProjectsListView.SelectedItems.Count != 0) + { + if (MessageBox.Show(this, + "Are you sure you want delete this project?", + "Confirm project deletion", MessageBoxButtons.YesNo, + MessageBoxIcon.Question) == DialogResult.Yes) + { + OnDelete?.Invoke(Projects[ProjectsListView.SelectedItems[0].Index]); + Projects.Remove(Projects[ProjectsListView.SelectedItems[0].Index]); + ProjectsListView.Items.Remove(ProjectsListView.SelectedItems[0]); + } + } + } + catch (Exception ex) + { + MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void mnuItemRename_Click(object sender, EventArgs e) + { + if (ProjectsListView.SelectedItems.Count != 0) + { + ProjectsListView.SelectedItems[0].BeginEdit(); + } + } + + private void ProjectsListView_AfterLabelEdit(object sender, LabelEditEventArgs e) + { + if (string.IsNullOrWhiteSpace(e.Label)) + { + e.CancelEdit = true; + return; + } + + if (ProjectsListView.SelectedItems.Count != 0) + { + Projects[ProjectsListView.SelectedItems[0].Index].ProjectName = e.Label.Trim(); + OnRename?.Invoke(Projects[ProjectsListView.SelectedItems[0].Index]); + } + } + + private void mnuItemOpen_Click(object sender, EventArgs e) + { + OpenProject(); + Dispose(); + } + + private void mnuItemDelete_Click(object sender, EventArgs e) + { + DeleteProject(); + } + + private void ProjectsListView_SelectedIndexChanged(object sender, EventArgs e) + { + OpenProject(); + } + + private void ProjectsListView_DoubleClick(object sender, EventArgs e) + { + Dispose(); + } + + private void ListProjectsForm_KeyDown(object sender, KeyEventArgs e) + { + if (e != null) + { + if (e.KeyCode == Keys.Escape) + Dispose(); + if (e.KeyCode == Keys.Enter) + Dispose(); + if (e.KeyCode == Keys.Delete) + DeleteProject(); + } + } + } +} diff --git a/OpenDBDiff/Front/ListProjectsForm.resx b/OpenDBDiff/Front/ListProjectsForm.resx new file mode 100644 index 0000000..06ac379 --- /dev/null +++ b/OpenDBDiff/Front/ListProjectsForm.resx @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA2 + CAAAAk1TRnQBSQFMAwEBAAEkAQABJAEAARABAAEQAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA + AUADAAEQAwABAQEAAQgGAAEEGAABgAIAAYADAAKAAQABgAMAAYABAAGAAQACgAIAA8ABAAHAAdwBwAEA + AfABygGmAQABMwUAATMBAAEzAQABMwEAAjMCAAMWAQADHAEAAyIBAAMpAQADVQEAA00BAANCAQADOQEA + AYABfAH/AQACUAH/AQABkwEAAdYBAAH/AewBzAEAAcYB1gHvAQAB1gLnAQABkAGpAa0CAAH/ATMDAAFm + AwABmQMAAcwCAAEzAwACMwIAATMBZgIAATMBmQIAATMBzAIAATMB/wIAAWYDAAFmATMCAAJmAgABZgGZ + AgABZgHMAgABZgH/AgABmQMAAZkBMwIAAZkBZgIAApkCAAGZAcwCAAGZAf8CAAHMAwABzAEzAgABzAFm + AgABzAGZAgACzAIAAcwB/wIAAf8BZgIAAf8BmQIAAf8BzAEAATMB/wIAAf8BAAEzAQABMwEAAWYBAAEz + AQABmQEAATMBAAHMAQABMwEAAf8BAAH/ATMCAAMzAQACMwFmAQACMwGZAQACMwHMAQACMwH/AQABMwFm + AgABMwFmATMBAAEzAmYBAAEzAWYBmQEAATMBZgHMAQABMwFmAf8BAAEzAZkCAAEzAZkBMwEAATMBmQFm + AQABMwKZAQABMwGZAcwBAAEzAZkB/wEAATMBzAIAATMBzAEzAQABMwHMAWYBAAEzAcwBmQEAATMCzAEA + ATMBzAH/AQABMwH/ATMBAAEzAf8BZgEAATMB/wGZAQABMwH/AcwBAAEzAv8BAAFmAwABZgEAATMBAAFm + AQABZgEAAWYBAAGZAQABZgEAAcwBAAFmAQAB/wEAAWYBMwIAAWYCMwEAAWYBMwFmAQABZgEzAZkBAAFm + ATMBzAEAAWYBMwH/AQACZgIAAmYBMwEAA2YBAAJmAZkBAAJmAcwBAAFmAZkCAAFmAZkBMwEAAWYBmQFm + AQABZgKZAQABZgGZAcwBAAFmAZkB/wEAAWYBzAIAAWYBzAEzAQABZgHMAZkBAAFmAswBAAFmAcwB/wEA + AWYB/wIAAWYB/wEzAQABZgH/AZkBAAFmAf8BzAEAAcwBAAH/AQAB/wEAAcwBAAKZAgABmQEzAZkBAAGZ + AQABmQEAAZkBAAHMAQABmQMAAZkCMwEAAZkBAAFmAQABmQEzAcwBAAGZAQAB/wEAAZkBZgIAAZkBZgEz + AQABmQEzAWYBAAGZAWYBmQEAAZkBZgHMAQABmQEzAf8BAAKZATMBAAKZAWYBAAOZAQACmQHMAQACmQH/ + AQABmQHMAgABmQHMATMBAAFmAcwBZgEAAZkBzAGZAQABmQLMAQABmQHMAf8BAAGZAf8CAAGZAf8BMwEA + AZkBzAFmAQABmQH/AZkBAAGZAf8BzAEAAZkC/wEAAcwDAAGZAQABMwEAAcwBAAFmAQABzAEAAZkBAAHM + AQABzAEAAZkBMwIAAcwCMwEAAcwBMwFmAQABzAEzAZkBAAHMATMBzAEAAcwBMwH/AQABzAFmAgABzAFm + ATMBAAGZAmYBAAHMAWYBmQEAAcwBZgHMAQABmQFmAf8BAAHMAZkCAAHMAZkBMwEAAcwBmQFmAQABzAKZ + AQABzAGZAcwBAAHMAZkB/wEAAswCAALMATMBAALMAWYBAALMAZkBAAPMAQACzAH/AQABzAH/AgABzAH/ + ATMBAAGZAf8BZgEAAcwB/wGZAQABzAH/AcwBAAHMAv8BAAHMAQABMwEAAf8BAAFmAQAB/wEAAZkBAAHM + ATMCAAH/AjMBAAH/ATMBZgEAAf8BMwGZAQAB/wEzAcwBAAH/ATMB/wEAAf8BZgIAAf8BZgEzAQABzAJm + AQAB/wFmAZkBAAH/AWYBzAEAAcwBZgH/AQAB/wGZAgAB/wGZATMBAAH/AZkBZgEAAf8CmQEAAf8BmQHM + AQAB/wGZAf8BAAH/AcwCAAH/AcwBMwEAAf8BzAFmAQAB/wHMAZkBAAH/AswBAAH/AcwB/wEAAv8BMwEA + AcwB/wFmAQAC/wGZAQAC/wHMAQACZgH/AQABZgH/AWYBAAFmAv8BAAH/AmYBAAH/AWYB/wEAAv8BZgEA + ASEBAAGlAQADXwEAA3cBAAOGAQADlgEAA8sBAAOyAQAD1wEAA90BAAPjAQAD6gEAA/EBAAP4AQAB8AH7 + Af8BAAGkAqABAAOAAwAB/wIAAf8DAAL/AQAB/wMAAf8BAAH/AQAC/wIAA/8DAAH/AfQI8wH0Af8zAAH/ + AfEBmQhSAZkB8QH/MgABGgFSAnoBmgWgAnoBUgEaMgABUgR6AZoDoAGaA3oBUjIAAVIEegKaAaACmgN6 + AVIyAAFSBXoCoAGaBHoBUjIAAVIBegGgCMMBoAF6AVIyAAGZAcMBmgF6BnkBegGaAcMBmTIAAZkBUgFZ + AnoBmgOgAZoCegFSAZkyAAFSBHoBmgOgAZoDegFSMgABUgV6AqABmgR6AVIyAAFSAXoBmgjDAZoBegFS + MgABUgHDAqAGmgKgAcMBUjIAAVIMegFSMgABGwFSCnoBUgEbMwAB9AGZCFIBmQH0MgABQgFNAT4HAAE+ + AwABKAMAAUADAAEQAwABAQEAAQEFAAGAFwAD/wEAAcABAwYAAYABAQYAAYABAQYAAYABAQYAAYABAQYA + AYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYA + AcABAwYACw== + + + + 149, 17 + + + 340, 17 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/Front/OptionForm.Designer.cs b/OpenDBDiff/Front/OptionForm.Designer.cs new file mode 100644 index 0000000..8bd23ba --- /dev/null +++ b/OpenDBDiff/Front/OptionForm.Designer.cs @@ -0,0 +1,88 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + partial class OptionForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(OptionForm)); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnApply = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(433, 450); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 5; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // btnApply + // + this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnApply.Location = new System.Drawing.Point(514, 450); + this.btnApply.Name = "btnApply"; + this.btnApply.Size = new System.Drawing.Size(75, 23); + this.btnApply.TabIndex = 4; + this.btnApply.Text = "Apply"; + this.btnApply.UseVisualStyleBackColor = true; + this.btnApply.Click += new System.EventHandler(this.btnApply_Click); + // + // OptionForm + // + this.AcceptButton = this.btnApply; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(592, 477); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnApply); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "OptionForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Comparison options"; + this.ResumeLayout(false); + + } + + #endregion + + private OptionControl sqlOptionsFront1; + private Button btnCancel; + private Button btnApply; + + } +} diff --git a/OpenDBDiff/Front/OptionForm.cs b/OpenDBDiff/Front/OptionForm.cs new file mode 100644 index 0000000..1f96cc3 --- /dev/null +++ b/OpenDBDiff/Front/OptionForm.cs @@ -0,0 +1,53 @@ +using System; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + public partial class OptionForm : Form + { + private IProjectHandler projectSelectorHandler; + private Schema.Model.IOption SqlFilter; + + public event OptionControl.OptionEventHandler OptionSaved; + + public OptionForm(IProjectHandler projectSelectorHandler, Schema.Model.IOption filter) + { + this.projectSelectorHandler = projectSelectorHandler; + sqlOptionsFront1 = projectSelectorHandler.CreateOptionControl(); + sqlOptionsFront1.OptionSaved += SqlOptionsFront1_OptionSaved; + SqlFilter = filter; + sqlOptionsFront1.Load(filter); + + InitializeComponent(); + + this.SuspendLayout(); + + this.sqlOptionsFront1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.sqlOptionsFront1.Location = new System.Drawing.Point(3, 3); + this.sqlOptionsFront1.Name = "sqlOptionsFront1"; + this.sqlOptionsFront1.Size = new System.Drawing.Size(586, 440); + this.sqlOptionsFront1.TabIndex = 0; + this.Controls.Add(this.sqlOptionsFront1); + + this.ResumeLayout(); + } + + private void SqlOptionsFront1_OptionSaved(Schema.Model.IOption option) + { + OptionSaved?.Invoke(option); + } + + private void btnApply_Click(object sender, EventArgs e) + { + sqlOptionsFront1.Save(); + this.Close(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/OpenDBDiff/Front/OptionForm.resx b/OpenDBDiff/Front/OptionForm.resx new file mode 100644 index 0000000..4bf5cc5 --- /dev/null +++ b/OpenDBDiff/Front/OptionForm.resx @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/Front/PrincipalForm.Designer.cs b/OpenDBDiff/Front/PrincipalForm.Designer.cs new file mode 100644 index 0000000..b3ed843 --- /dev/null +++ b/OpenDBDiff/Front/PrincipalForm.Designer.cs @@ -0,0 +1,728 @@ +using System.ComponentModel; +using System.Windows.Forms; +using ScintillaNET; + +namespace OpenDBDiff.Front +{ + partial class PrincipalForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PrincipalForm)); + this.lblMessage = new System.Windows.Forms.Label(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.tabControl2 = new System.Windows.Forms.TabControl(); + this.tabPage4 = new System.Windows.Forms.TabPage(); + this.txtNewObject = new ScintillaNET.Scintilla(); + this.tabPage5 = new System.Windows.Forms.TabPage(); + this.txtOldObject = new ScintillaNET.Scintilla(); + this.tabPage6 = new System.Windows.Forms.TabPage(); + this.txtDiff = new ScintillaNET.Scintilla(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.panel5 = new System.Windows.Forms.Panel(); + this.panel4 = new System.Windows.Forms.Panel(); + this.panel3 = new System.Windows.Forms.Panel(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.schemaTreeView1 = new OpenDBDiff.Front.SchemaTreeView(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.panel1 = new System.Windows.Forms.Panel(); + this.txtSyncScript = new ScintillaNET.Scintilla(); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.btnOptions = new System.Windows.Forms.Button(); + this.btnCopy = new System.Windows.Forms.Button(); + this.btnUpdate = new System.Windows.Forms.Button(); + this.btnUpdateAll = new System.Windows.Forms.Button(); + this.btnSaveAs = new System.Windows.Forms.Button(); + this.btnCompare = new System.Windows.Forms.Button(); + this.PanelGlobal = new System.Windows.Forms.Panel(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.LeftDatabasePanel = new System.Windows.Forms.Panel(); + this.RightDatabasePanel = new System.Windows.Forms.Panel(); + this.btnNewProject = new System.Windows.Forms.Button(); + this.btnSaveProject = new System.Windows.Forms.Button(); + this.btnProject = new System.Windows.Forms.Button(); + this.btnCompareTableData = new System.Windows.Forms.Button(); + this.toolMenu = new System.Windows.Forms.ToolStrip(); + this.toolOpenProject = new System.Windows.Forms.ToolStripButton(); + this.toolNewProject = new System.Windows.Forms.ToolStripButton(); + this.toolSaveProject = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.toolLblProjectType = new System.Windows.Forms.ToolStripLabel(); + this.toolProjectTypes = new System.Windows.Forms.ToolStripComboBox(); + this.PanelActions = new System.Windows.Forms.FlowLayoutPanel(); + this.tabControl1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.tabControl2.SuspendLayout(); + this.tabPage4.SuspendLayout(); + this.tabPage5.SuspendLayout(); + this.tabPage6.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.tabPage3.SuspendLayout(); + this.PanelGlobal.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.toolMenu.SuspendLayout(); + this.PanelActions.SuspendLayout(); + this.SuspendLayout(); + // + // lblMessage + // + this.lblMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.lblMessage.AutoSize = true; + this.lblMessage.Location = new System.Drawing.Point(6, 528); + this.lblMessage.Name = "lblMessage"; + this.lblMessage.Size = new System.Drawing.Size(0, 13); + this.lblMessage.TabIndex = 4; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 175); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(842, 483); + this.tabControl1.TabIndex = 3; + this.tabControl1.SelectedIndexChanged += new System.EventHandler(this.tabControl1_SelectedIndexChanged); + // + // tabPage2 + // + this.tabPage2.Controls.Add(this.tabControl2); + this.tabPage2.Controls.Add(this.groupBox2); + this.tabPage2.Controls.Add(this.groupBox1); + this.tabPage2.Location = new System.Drawing.Point(4, 22); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(834, 457); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "Schema"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // tabControl2 + // + this.tabControl2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabControl2.Controls.Add(this.tabPage4); + this.tabControl2.Controls.Add(this.tabPage5); + this.tabControl2.Controls.Add(this.tabPage6); + this.tabControl2.Location = new System.Drawing.Point(350, 50); + this.tabControl2.Name = "tabControl2"; + this.tabControl2.SelectedIndex = 0; + this.tabControl2.Size = new System.Drawing.Size(477, 402); + this.tabControl2.TabIndex = 3; + // + // tabPage4 + // + this.tabPage4.Controls.Add(this.txtNewObject); + this.tabPage4.Location = new System.Drawing.Point(4, 22); + this.tabPage4.Name = "tabPage4"; + this.tabPage4.Padding = new System.Windows.Forms.Padding(3); + this.tabPage4.Size = new System.Drawing.Size(469, 376); + this.tabPage4.TabIndex = 0; + this.tabPage4.Text = "New object"; + this.tabPage4.UseVisualStyleBackColor = true; + // + // txtNewObject + // + this.txtNewObject.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtNewObject.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtNewObject.Location = new System.Drawing.Point(3, 3); + this.txtNewObject.Name = "txtNewObject"; + this.txtNewObject.Size = new System.Drawing.Size(463, 370); + this.txtNewObject.TabIndex = 0; + // + // tabPage5 + // + this.tabPage5.Controls.Add(this.txtOldObject); + this.tabPage5.Location = new System.Drawing.Point(4, 22); + this.tabPage5.Name = "tabPage5"; + this.tabPage5.Padding = new System.Windows.Forms.Padding(3); + this.tabPage5.Size = new System.Drawing.Size(469, 376); + this.tabPage5.TabIndex = 1; + this.tabPage5.Text = "Old object"; + this.tabPage5.UseVisualStyleBackColor = true; + // + // txtOldObject + // + this.txtOldObject.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtOldObject.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtOldObject.Location = new System.Drawing.Point(3, 3); + this.txtOldObject.Name = "txtOldObject"; + this.txtOldObject.Size = new System.Drawing.Size(463, 370); + this.txtOldObject.TabIndex = 0; + // + // tabPage6 + // + this.tabPage6.Controls.Add(this.txtDiff); + this.tabPage6.Location = new System.Drawing.Point(4, 22); + this.tabPage6.Name = "tabPage6"; + this.tabPage6.Size = new System.Drawing.Size(469, 376); + this.tabPage6.TabIndex = 2; + this.tabPage6.Text = "Diff"; + this.tabPage6.UseVisualStyleBackColor = true; + // + // txtDiff + // + this.txtDiff.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtDiff.Location = new System.Drawing.Point(0, 0); + this.txtDiff.Name = "txtDiff"; + this.txtDiff.Size = new System.Drawing.Size(469, 376); + this.txtDiff.TabIndex = 0; + // + // groupBox2 + // + this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox2.Controls.Add(this.label3); + this.groupBox2.Controls.Add(this.label2); + this.groupBox2.Controls.Add(this.label1); + this.groupBox2.Controls.Add(this.panel5); + this.groupBox2.Controls.Add(this.panel4); + this.groupBox2.Controls.Add(this.panel3); + this.groupBox2.Location = new System.Drawing.Point(350, 5); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(478, 40); + this.groupBox2.TabIndex = 2; + this.groupBox2.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(345, 16); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(62, 13); + this.label3.TabIndex = 5; + this.label3.Text = "Drop object"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(195, 16); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(77, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Alter old object"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(45, 16); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(93, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Create new object"; + // + // panel5 + // + this.panel5.BackColor = System.Drawing.Color.Red; + this.panel5.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel5.Location = new System.Drawing.Point(310, 12); + this.panel5.Name = "panel5"; + this.panel5.Size = new System.Drawing.Size(32, 20); + this.panel5.TabIndex = 2; + // + // panel4 + // + this.panel4.BackColor = System.Drawing.Color.Blue; + this.panel4.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel4.Location = new System.Drawing.Point(160, 12); + this.panel4.Name = "panel4"; + this.panel4.Size = new System.Drawing.Size(32, 20); + this.panel4.TabIndex = 1; + // + // panel3 + // + this.panel3.BackColor = System.Drawing.Color.Lime; + this.panel3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel3.Location = new System.Drawing.Point(10, 12); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(32, 20); + this.panel3.TabIndex = 0; + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.groupBox1.Controls.Add(this.schemaTreeView1); + this.groupBox1.Location = new System.Drawing.Point(6, 4); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(335, 445); + this.groupBox1.TabIndex = 1; + this.groupBox1.TabStop = false; + // + // schemaTreeView1 + // + this.schemaTreeView1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.schemaTreeView1.LeftDatabase = null; + this.schemaTreeView1.Location = new System.Drawing.Point(7, 10); + this.schemaTreeView1.Name = "schemaTreeView1"; + this.schemaTreeView1.RightDatabase = null; + this.schemaTreeView1.ShowChangedItems = true; + this.schemaTreeView1.ShowMissingItems = true; + this.schemaTreeView1.ShowNewItems = true; + this.schemaTreeView1.ShowUnchangedItems = true; + this.schemaTreeView1.Size = new System.Drawing.Size(322, 429); + this.schemaTreeView1.TabIndex = 0; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.panel1); + this.tabPage1.Controls.Add(this.lblMessage); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(834, 457); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "Synchronized script"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.panel1.Controls.Add(this.txtSyncScript); + this.panel1.Location = new System.Drawing.Point(9, 6); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(819, 461); + this.panel1.TabIndex = 6; + // + // txtSyncScript + // + this.txtSyncScript.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtSyncScript.Location = new System.Drawing.Point(0, 0); + this.txtSyncScript.Name = "txtSyncScript"; + this.txtSyncScript.ReadOnly = true; + this.txtSyncScript.Size = new System.Drawing.Size(815, 457); + this.txtSyncScript.TabIndex = 0; + // + // tabPage3 + // + this.tabPage3.Controls.Add(this.textBox1); + this.tabPage3.Location = new System.Drawing.Point(4, 22); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.Padding = new System.Windows.Forms.Padding(3); + this.tabPage3.Size = new System.Drawing.Size(834, 457); + this.tabPage3.TabIndex = 2; + this.tabPage3.Text = "Action report"; + this.tabPage3.UseVisualStyleBackColor = true; + // + // textBox1 + // + this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox1.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textBox1.Location = new System.Drawing.Point(9, 6); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textBox1.Size = new System.Drawing.Size(819, 461); + this.textBox1.TabIndex = 0; + // + // saveFileDialog1 + // + this.saveFileDialog1.DefaultExt = "sql"; + this.saveFileDialog1.Filter = "SQL File|*.sql"; + // + // btnOptions + // + this.btnOptions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnOptions.Image = global::OpenDBDiff.Properties.Resources.setting_tools; + this.btnOptions.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnOptions.Location = new System.Drawing.Point(3, 64); + this.btnOptions.Name = "btnOptions"; + this.btnOptions.Size = new System.Drawing.Size(95, 55); + this.btnOptions.TabIndex = 5; + this.btnOptions.Text = "Options"; + this.btnOptions.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnOptions.UseVisualStyleBackColor = true; + this.btnOptions.Click += new System.EventHandler(this.btnOptions_Click); + // + // btnCopy + // + this.btnCopy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCopy.Enabled = false; + this.btnCopy.Image = global::OpenDBDiff.Properties.Resources.clipboard_invoice; + this.btnCopy.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnCopy.Location = new System.Drawing.Point(3, 186); + this.btnCopy.Name = "btnCopy"; + this.btnCopy.Size = new System.Drawing.Size(95, 55); + this.btnCopy.TabIndex = 7; + this.btnCopy.Text = "Copy script"; + this.btnCopy.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnCopy.UseVisualStyleBackColor = true; + this.btnCopy.Click += new System.EventHandler(this.btnCopy_Click); + // + // btnUpdate + // + this.btnUpdate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnUpdate.Enabled = false; + this.btnUpdate.Image = global::OpenDBDiff.Properties.Resources.refresh_all; + this.btnUpdate.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnUpdate.Location = new System.Drawing.Point(3, 247); + this.btnUpdate.Name = "btnUpdate"; + this.btnUpdate.Size = new System.Drawing.Size(95, 55); + this.btnUpdate.TabIndex = 8; + this.btnUpdate.Text = "Update selected"; + this.btnUpdate.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnUpdate.UseVisualStyleBackColor = true; + this.btnUpdate.Click += new System.EventHandler(this.btnUpdate_Click); + // + // btnUpdateAll + // + this.btnUpdateAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnUpdateAll.Enabled = false; + this.btnUpdateAll.Image = global::OpenDBDiff.Properties.Resources.database_refresh; + this.btnUpdateAll.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnUpdateAll.Location = new System.Drawing.Point(3, 396); + this.btnUpdateAll.Margin = new System.Windows.Forms.Padding(3, 30, 3, 3); + this.btnUpdateAll.Name = "btnUpdateAll"; + this.btnUpdateAll.Size = new System.Drawing.Size(95, 55); + this.btnUpdateAll.TabIndex = 10; + this.btnUpdateAll.Text = "Update all"; + this.btnUpdateAll.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnUpdateAll.UseVisualStyleBackColor = true; + this.btnUpdateAll.Click += new System.EventHandler(this.btnUpdateAll_Click); + // + // btnSaveAs + // + this.btnSaveAs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnSaveAs.Enabled = false; + this.btnSaveAs.Image = global::OpenDBDiff.Properties.Resources.save_as; + this.btnSaveAs.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnSaveAs.Location = new System.Drawing.Point(3, 125); + this.btnSaveAs.Name = "btnSaveAs"; + this.btnSaveAs.Size = new System.Drawing.Size(95, 55); + this.btnSaveAs.TabIndex = 6; + this.btnSaveAs.Text = "Save as"; + this.btnSaveAs.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnSaveAs.UseVisualStyleBackColor = true; + this.btnSaveAs.Click += new System.EventHandler(this.btnSaveAs_Click); + // + // btnCompare + // + this.btnCompare.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCompare.Image = global::OpenDBDiff.Properties.Resources.compare; + this.btnCompare.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnCompare.Location = new System.Drawing.Point(3, 3); + this.btnCompare.Name = "btnCompare"; + this.btnCompare.Size = new System.Drawing.Size(95, 55); + this.btnCompare.TabIndex = 4; + this.btnCompare.Text = "Compare"; + this.btnCompare.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnCompare.UseVisualStyleBackColor = true; + this.btnCompare.Click += new System.EventHandler(this.btnCompare_Click); + // + // PanelGlobal + // + this.PanelGlobal.BackColor = System.Drawing.Color.White; + this.PanelGlobal.Controls.Add(this.tableLayoutPanel1); + this.PanelGlobal.Controls.Add(this.btnNewProject); + this.PanelGlobal.Controls.Add(this.btnSaveProject); + this.PanelGlobal.Controls.Add(this.btnProject); + this.PanelGlobal.Dock = System.Windows.Forms.DockStyle.Top; + this.PanelGlobal.Location = new System.Drawing.Point(0, 0); + this.PanelGlobal.Name = "PanelGlobal"; + this.PanelGlobal.Size = new System.Drawing.Size(940, 175); + this.PanelGlobal.TabIndex = 10; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableLayoutPanel1.AutoSize = true; + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.LeftDatabasePanel, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.RightDatabasePanel, 1, 0); + this.tableLayoutPanel1.Location = new System.Drawing.Point(126, 3); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 1; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 172F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(814, 172); + this.tableLayoutPanel1.TabIndex = 0; + // + // LeftDatabasePanel + // + this.LeftDatabasePanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.LeftDatabasePanel.Location = new System.Drawing.Point(3, 3); + this.LeftDatabasePanel.Name = "LeftDatabasePanel"; + this.LeftDatabasePanel.Size = new System.Drawing.Size(401, 166); + this.LeftDatabasePanel.TabIndex = 10; + // + // RightDatabasePanel + // + this.RightDatabasePanel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.RightDatabasePanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.RightDatabasePanel.Location = new System.Drawing.Point(410, 3); + this.RightDatabasePanel.Name = "RightDatabasePanel"; + this.RightDatabasePanel.Size = new System.Drawing.Size(401, 166); + this.RightDatabasePanel.TabIndex = 11; + // + // btnNewProject + // + this.btnNewProject.BackColor = System.Drawing.SystemColors.ButtonFace; + this.btnNewProject.Image = global::OpenDBDiff.Properties.Resources.new_window; + this.btnNewProject.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnNewProject.Location = new System.Drawing.Point(7, 60); + this.btnNewProject.Name = "btnNewProject"; + this.btnNewProject.Size = new System.Drawing.Size(113, 33); + this.btnNewProject.TabIndex = 15; + this.btnNewProject.Text = "New project"; + this.btnNewProject.UseVisualStyleBackColor = false; + this.btnNewProject.Click += new System.EventHandler(this.btnNewProject_Click); + // + // btnSaveProject + // + this.btnSaveProject.BackColor = System.Drawing.SystemColors.ButtonFace; + this.btnSaveProject.Image = global::OpenDBDiff.Properties.Resources.diskette; + this.btnSaveProject.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnSaveProject.Location = new System.Drawing.Point(7, 99); + this.btnSaveProject.Name = "btnSaveProject"; + this.btnSaveProject.Size = new System.Drawing.Size(113, 33); + this.btnSaveProject.TabIndex = 13; + this.btnSaveProject.Text = "Save project"; + this.btnSaveProject.UseVisualStyleBackColor = false; + this.btnSaveProject.Click += new System.EventHandler(this.btnSaveProject_Click); + // + // btnProject + // + this.btnProject.BackColor = System.Drawing.SystemColors.ButtonFace; + this.btnProject.Image = global::OpenDBDiff.Properties.Resources.folder; + this.btnProject.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnProject.Location = new System.Drawing.Point(7, 21); + this.btnProject.Name = "btnProject"; + this.btnProject.Size = new System.Drawing.Size(113, 33); + this.btnProject.TabIndex = 12; + this.btnProject.Text = "Open project"; + this.btnProject.UseVisualStyleBackColor = false; + this.btnProject.Click += new System.EventHandler(this.btnProject_Click); + // + // btnCompareTableData + // + this.btnCompareTableData.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCompareTableData.Enabled = false; + this.btnCompareTableData.Image = global::OpenDBDiff.Properties.Resources.table_analysis; + this.btnCompareTableData.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnCompareTableData.Location = new System.Drawing.Point(3, 308); + this.btnCompareTableData.Name = "btnCompareTableData"; + this.btnCompareTableData.Size = new System.Drawing.Size(95, 55); + this.btnCompareTableData.TabIndex = 9; + this.btnCompareTableData.Text = "Compare data"; + this.btnCompareTableData.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnCompareTableData.UseVisualStyleBackColor = true; + this.btnCompareTableData.Click += new System.EventHandler(this.btnCompareTableData_Click); + // + // toolMenu + // + this.toolMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolOpenProject, + this.toolNewProject, + this.toolSaveProject, + this.toolStripSeparator1, + this.toolLblProjectType, + this.toolProjectTypes}); + this.toolMenu.Location = new System.Drawing.Point(0, 0); + this.toolMenu.Name = "toolMenu"; + this.toolMenu.Size = new System.Drawing.Size(940, 25); + this.toolMenu.TabIndex = 16; + this.toolMenu.Visible = false; + // + // toolOpenProject + // + this.toolOpenProject.Image = global::OpenDBDiff.Properties.Resources.folder; + this.toolOpenProject.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolOpenProject.Name = "toolOpenProject"; + this.toolOpenProject.Size = new System.Drawing.Size(96, 22); + this.toolOpenProject.Text = "&Open Project"; + // + // toolNewProject + // + this.toolNewProject.Image = global::OpenDBDiff.Properties.Resources.new_window; + this.toolNewProject.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolNewProject.Name = "toolNewProject"; + this.toolNewProject.Size = new System.Drawing.Size(91, 22); + this.toolNewProject.Text = "&New Project"; + // + // toolSaveProject + // + this.toolSaveProject.Image = global::OpenDBDiff.Properties.Resources.diskette; + this.toolSaveProject.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolSaveProject.Name = "toolSaveProject"; + this.toolSaveProject.Size = new System.Drawing.Size(91, 22); + this.toolSaveProject.Text = "&Save Project"; + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); + this.toolStripSeparator1.Visible = false; + // + // toolLblProjectType + // + this.toolLblProjectType.Name = "toolLblProjectType"; + this.toolLblProjectType.Size = new System.Drawing.Size(76, 22); + this.toolLblProjectType.Text = "Project Type:"; + // + // toolProjectTypes + // + this.toolProjectTypes.AutoSize = false; + this.toolProjectTypes.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.toolProjectTypes.Items.AddRange(new object[] { + "SQL Sever 2005", + "MySQL 5.0 or Higher", + "Sybase 12.5"}); + this.toolProjectTypes.Name = "toolProjectTypes"; + this.toolProjectTypes.Size = new System.Drawing.Size(200, 23); + this.toolProjectTypes.SelectedIndexChanged += new System.EventHandler(this.toolProjectTypes_SelectedIndexChanged); + // + // PanelActions + // + this.PanelActions.Controls.Add(this.btnCompare); + this.PanelActions.Controls.Add(this.btnOptions); + this.PanelActions.Controls.Add(this.btnSaveAs); + this.PanelActions.Controls.Add(this.btnCopy); + this.PanelActions.Controls.Add(this.btnUpdate); + this.PanelActions.Controls.Add(this.btnCompareTableData); + this.PanelActions.Controls.Add(this.btnUpdateAll); + this.PanelActions.Dock = System.Windows.Forms.DockStyle.Right; + this.PanelActions.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.PanelActions.Location = new System.Drawing.Point(842, 175); + this.PanelActions.Name = "PanelActions"; + this.PanelActions.Size = new System.Drawing.Size(98, 483); + this.PanelActions.TabIndex = 17; + // + // PrincipalForm + // + this.AcceptButton = this.btnCompare; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(940, 658); + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.PanelActions); + this.Controls.Add(this.PanelGlobal); + this.Controls.Add(this.toolMenu); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "PrincipalForm"; + this.Text = "OpenDBDiff"; + this.WindowState = System.Windows.Forms.FormWindowState.Maximized; + this.Load += new System.EventHandler(this.PrincipalForm_Load); + this.tabControl1.ResumeLayout(false); + this.tabPage2.ResumeLayout(false); + this.tabControl2.ResumeLayout(false); + this.tabPage4.ResumeLayout(false); + this.tabPage5.ResumeLayout(false); + this.tabPage6.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.tabPage3.ResumeLayout(false); + this.tabPage3.PerformLayout(); + this.PanelGlobal.ResumeLayout(false); + this.PanelGlobal.PerformLayout(); + this.tableLayoutPanel1.ResumeLayout(false); + this.toolMenu.ResumeLayout(false); + this.toolMenu.PerformLayout(); + this.PanelActions.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label lblMessage; + private TabControl tabControl1; + private TabPage tabPage1; + private Button btnCompare; + private Button btnSaveAs; + private SaveFileDialog saveFileDialog1; + private Button btnCopy; + private Button btnUpdate; + private Button btnUpdateAll; + private Button btnOptions; + private TabPage tabPage2; + private SchemaTreeView schemaTreeView1; + private GroupBox groupBox1; + private TabPage tabPage3; + private TextBox textBox1; + private Panel panel1; + private Scintilla txtSyncScript; + private Panel PanelGlobal; + private Panel LeftDatabasePanel; + private Panel RightDatabasePanel; + private GroupBox groupBox2; + private Panel panel3; + private Panel panel4; + private Panel panel5; + private Label label1; + private Label label3; + private Label label2; + private TabControl tabControl2; + private TabPage tabPage4; + private TabPage tabPage5; + private Scintilla txtNewObject; + private Scintilla txtOldObject; + private Button btnSaveProject; + private Button btnProject; + private Button btnNewProject; + private Button btnCompareTableData; + private TabPage tabPage6; + private Scintilla txtDiff; + private ToolStrip toolMenu; + private ToolStripButton toolOpenProject; + private ToolStripButton toolNewProject; + private ToolStripButton toolSaveProject; + private ToolStripComboBox toolProjectTypes; + private FlowLayoutPanel PanelActions; + private ToolStripLabel toolLblProjectType; + private TableLayoutPanel tableLayoutPanel1; + private ToolStripSeparator toolStripSeparator1; + } +} diff --git a/OpenDBDiff/Front/PrincipalForm.cs b/OpenDBDiff/Front/PrincipalForm.cs new file mode 100644 index 0000000..b4f8eab --- /dev/null +++ b/OpenDBDiff/Front/PrincipalForm.cs @@ -0,0 +1,679 @@ +using DiffPlex; +using DiffPlex.DiffBuilder; +using DiffPlex.DiffBuilder.Model; +using Essy.Tools.InputBox; +using OpenDBDiff.Extensions; +using OpenDBDiff.Schema; +using OpenDBDiff.Schema.Misc; +using OpenDBDiff.Schema.Model; +using OpenDBDiff.Settings; +using ScintillaNET; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + public partial class PrincipalForm : Form + { + private Project ActiveProject; + private IFront LeftDatabaseSelector; + private IFront RightDatabaseSelector; + private IOption Options; + private List _selectedSchemas = new List(); + + private List ProjectHandlers = new List(); + private OpenDBDiff.Front.IProjectHandler ProjectSelectorHandler; + + public PrincipalForm() + { + InitializeComponent(); + + this.Text = string.Concat(nameof(OpenDBDiff), " v", Assembly.GetExecutingAssembly().GetName().Version.ToString()); + } + + private void StartComparison() + { + ProgressForm progress = null; + string errorLocation = null; + try + { + if ((!String.IsNullOrEmpty(ProjectSelectorHandler.GetSourceDatabaseName()) && + (!String.IsNullOrEmpty(ProjectSelectorHandler.GetDestinationDatabaseName())))) + { + Options = Options ?? this.ProjectSelectorHandler.GetDefaultProjectOptions(); + var leftGenerator = this.ProjectSelectorHandler.SetSourceGenerator(LeftDatabaseSelector.ConnectionString, Options); + var rightGenerator = this.ProjectSelectorHandler.SetDestinationGenerator(RightDatabaseSelector.ConnectionString, Options); + IDatabaseComparer databaseComparer = this.ProjectSelectorHandler.GetDatabaseComparer(); + + var leftPair = new KeyValuePair(LeftDatabaseSelector.ToString(), leftGenerator); + var rightPair = new KeyValuePair(RightDatabaseSelector.ToString(), rightGenerator); + + // The progress form will execute the comparer to generate action scripts to migrate the right to the left + // Hence, inside the ProgressForm and deeper, right is the origin and left is the destination + progress = new ProgressForm(rightPair, leftPair, databaseComparer); + progress.ShowDialog(this); + if (progress.Error != null) + { + throw new SchemaException(progress.Error.Message, progress.Error); + } + + txtSyncScript.LexerLanguage = this.ProjectSelectorHandler.GetScriptLanguage(); + txtSyncScript.ReadOnly = false; + errorLocation = "Generating Synchronized Script"; + txtSyncScript.Text = progress.Destination.ToSqlDiff(this._selectedSchemas).ToSQL(); + txtSyncScript.ReadOnly = true; + txtSyncScript.SetMarginWidth(); + + // Notice again that left is destination, because we generated scripts to migrate the right database to the left. + schemaTreeView1.LeftDatabase = progress.Destination; + schemaTreeView1.RightDatabase = progress.Origin; + + schemaTreeView1.OnSelectItem += new SchemaTreeView.SchemaHandler(schemaTreeView1_OnSelectItem); + schemaTreeView1_OnSelectItem(schemaTreeView1.SelectedNode); + textBox1.Text = progress.Origin.ActionMessage.Message; + + btnCopy.Enabled = true; + btnSaveAs.Enabled = true; + btnUpdateAll.Enabled = true; + } + else + MessageBox.Show(Owner, "Please select a valid connection string", "ERROR", MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + catch (Exception ex) + { + if (errorLocation == null && progress != null) + { + errorLocation = String.Format("{0} (while {1})", progress.ErrorLocation, progress.ErrorMostRecentProgress ?? "initializing"); + } + + throw new SchemaException("Error " + (errorLocation ?? " Comparing Databases"), ex); + } + } + + private void schemaTreeView1_OnSelectItem(string nodeFullName) + { + try + { + txtNewObject.ReadOnly = false; + txtOldObject.ReadOnly = false; + txtDiff.ReadOnly = false; + + txtNewObject.ClearAll(); + txtOldObject.ClearAll(); + txtDiff.ClearAll(); + + if (string.IsNullOrEmpty(nodeFullName)) + return; + + IDatabase database = (IDatabase)schemaTreeView1.LeftDatabase; + + ObjectStatus? status; + + status = database.Find(nodeFullName)?.Status; + if (status.HasValue && status.Value != ObjectStatus.Drop) + { + txtNewObject.Text = database.Find(nodeFullName).ToSql(); + txtNewObject.SetMarginWidth(); + if (database.Find(nodeFullName).Status == ObjectStatus.Original) + { + btnUpdate.Enabled = false; + } + else + { + btnUpdate.Enabled = true; + } + if (database.Find(nodeFullName).ObjectType == ObjectType.Table) + { + btnCompareTableData.Enabled = true; + } + else + { + btnCompareTableData.Enabled = false; + } + } + + database = (IDatabase)schemaTreeView1.RightDatabase; + status = database.Find(nodeFullName)?.Status; + if (status.HasValue && status.Value != ObjectStatus.Create) + { + txtOldObject.Text = database.Find(nodeFullName).ToSql(); + txtOldObject.SetMarginWidth(); + } + txtNewObject.ReadOnly = true; + txtOldObject.ReadOnly = true; + + var diff = (new SideBySideDiffBuilder(new Differ())).BuildDiffModel(txtOldObject.Text, txtNewObject.Text); + + var sb = new StringBuilder(); + DiffPiece newLine, oldLine; + var markers = new Marker[] { txtDiff.Markers[0], txtDiff.Markers[1], txtDiff.Markers[2], txtDiff.Markers[3] }; + foreach (var marker in markers) marker.Symbol = MarkerSymbol.Background; + markers[0].SetBackColor(Color.LightGreen); // Imaginary (?) + markers[1].SetBackColor(Color.LightCyan); // Modified + markers[2].SetBackColor(Color.LightSalmon); // Deleted + markers[3].SetBackColor(Color.PeachPuff); // Modified + + var indexes = new List[] { new List(), new List(), new List(), new List() }; + var index = 0; + for (var i = 0; i < Math.Max(diff.NewText.Lines.Count, diff.OldText.Lines.Count); i++) + { + newLine = i < diff.NewText.Lines.Count ? diff.NewText.Lines[i] : null; + oldLine = i < diff.OldText.Lines.Count ? diff.OldText.Lines[i] : null; + if (oldLine.Type == ChangeType.Inserted) + { + sb.AppendLine(" " + oldLine.Text); + } + else if (oldLine.Type == ChangeType.Deleted) + { + sb.AppendLine("- " + oldLine.Text); + indexes[2].Add(index); + } + else if (oldLine.Type == ChangeType.Modified) + { + sb.AppendLine("* " + newLine.Text); + indexes[1].Add(index++); + sb.AppendLine("* " + oldLine.Text); + indexes[3].Add(index); + } + else if (oldLine.Type == ChangeType.Imaginary) + { + sb.AppendLine("+ " + newLine.Text); + indexes[0].Add(index); + } + else if (oldLine.Type == ChangeType.Unchanged) + { + sb.AppendLine(" " + oldLine.Text); + } + index++; + } + txtDiff.Text = sb.ToString(); + txtDiff.SetMarginWidth(); + for (var i = 0; i < 4; i++) + { + foreach (var ind in indexes[i]) + { + txtDiff.Lines[ind].MarkerAdd(i); + } + } + } + finally + { + txtNewObject.ReadOnly = true; + txtOldObject.ReadOnly = true; + txtDiff.ReadOnly = true; + } + } + + private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) + { + // Refresh script when tab is shown + if (tabControl1.SelectedIndex != 1) + { + return; + } + + var db = schemaTreeView1.LeftDatabase as IDatabase; + if (db != null) + { + this._selectedSchemas = this.schemaTreeView1.GetCheckedSchemas(); + this.txtSyncScript.ReadOnly = false; + this.txtSyncScript.Text = db.ToSqlDiff(this._selectedSchemas).ToSQL(); + this.txtSyncScript.ReadOnly = true; + txtSyncScript.SetMarginWidth(); + } + } + + private void btnCompareTableData_Click(object sender, EventArgs e) + { + TreeView tree = (TreeView)schemaTreeView1.Controls.Find("treeView1", true)[0]; + ISchemaBase selected = (ISchemaBase)tree.SelectedNode.Tag; + DataCompareForm dataCompare = new DataCompareForm(selected, LeftDatabaseSelector.ConnectionString, RightDatabaseSelector.ConnectionString); + dataCompare.ShowDialog(); + } + + private void btnCompare_Click(object sender, EventArgs e) + { + string errorLocation = "Processing Compare"; + try + { + Cursor = Cursors.WaitCursor; + _selectedSchemas = schemaTreeView1.GetCheckedSchemas(); + StartComparison(); + schemaTreeView1.SetCheckedSchemas(_selectedSchemas); + errorLocation = "Saving Connections"; + Project.SaveLastConfiguration(LeftDatabaseSelector.ConnectionString, RightDatabaseSelector.ConnectionString); + } + catch (Exception ex) + { + Cursor = Cursors.Default; + HandleException(errorLocation, ex); + } + finally + { + Cursor = Cursors.Default; + } + } + + private void HandleException(string errorLocation, Exception ex) + { + var errorDialog = new ErrorForm(ex); + errorDialog.ShowDialog(this); + } + + private void UnloadProjectHandler() + { + if (ProjectSelectorHandler != null) + { + LeftDatabasePanel.Controls.Remove((Control)LeftDatabaseSelector); + RightDatabasePanel.Controls.Remove((Control)RightDatabaseSelector); + ProjectSelectorHandler.Unload(); + ProjectSelectorHandler = null; + } + } + + private void LoadProjectHandler(IProjectHandler projectHandler) + { + UnloadProjectHandler(); + ProjectSelectorHandler = projectHandler; + LeftDatabaseSelector = ProjectSelectorHandler.CreateSourceSelector(); + RightDatabaseSelector = ProjectSelectorHandler.CreateDestinationSelector(); + LeftDatabasePanel.Controls.Add(LeftDatabaseSelector.Control); + RightDatabasePanel.Controls.Add(RightDatabaseSelector.Control); + } + + private void LoadProjectHandler() where T : IProjectHandler, new() + { + var handler = new T(); + LoadProjectHandler(handler); + } + + private void optSybase_CheckedChanged(object sender, EventArgs e) + { + /*if (optSybase.Checked) + { + this.mySqlConnectFront2 = new OpenDBDiff.Schema.Sybase.Front.AseConnectFront(); + this.mySqlConnectFront1 = new OpenDBDiff.Schema.Sybase.Front.AseConnectFront(); + this.mySqlConnectFront1.Location = new System.Drawing.Point(5, 19); + this.mySqlConnectFront1.Name = "mySqlConnectFront1"; + this.mySqlConnectFront1.Size = new System.Drawing.Size(410, 214); + this.mySqlConnectFront1.TabIndex = 10; + this.mySqlConnectFront2.Location = new System.Drawing.Point(5, 19); + this.mySqlConnectFront2.Name = "mySqlConnectFront2"; + this.mySqlConnectFront2.Size = new System.Drawing.Size(410, 214); + this.mySqlConnectFront2.TabIndex = 10; + this.mySqlConnectFront1.Visible = true; + this.mySqlConnectFront2.Visible = true; + this.groupBox3.Controls.Add((System.Windows.Forms.Control)this.mySqlConnectFront2); + this.groupBox2.Controls.Add((System.Windows.Forms.Control)this.mySqlConnectFront1); + } + else + { + this.groupBox2.Controls.Remove((System.Windows.Forms.Control)this.mySqlConnectFront1); + this.groupBox3.Controls.Remove((System.Windows.Forms.Control)this.mySqlConnectFront2); + }*/ + } + + private void btnSaveAs_Click(object sender, EventArgs e) + { + try + { + if (!string.IsNullOrEmpty(saveFileDialog1.FileName) && !string.IsNullOrEmpty(Path.GetDirectoryName(saveFileDialog1.FileName))) + { + saveFileDialog1.InitialDirectory = Path.GetDirectoryName(saveFileDialog1.FileName); + saveFileDialog1.FileName = Path.GetFileName(saveFileDialog1.FileName); + } + saveFileDialog1.ShowDialog(this); + if (!String.IsNullOrEmpty(saveFileDialog1.FileName)) + { + var db = schemaTreeView1.LeftDatabase as IDatabase; + if (db != null) + { + using (StreamWriter writer = new StreamWriter(saveFileDialog1.FileName, false)) + { + this._selectedSchemas = this.schemaTreeView1.GetCheckedSchemas(); + writer.Write(db.ToSqlDiff(this._selectedSchemas).ToSQL()); + writer.Close(); + } + } + } + } + catch (Exception ex) + { + HandleException("Save Script As", ex); + } + } + + private void btnCopy_Click(object sender, EventArgs e) + { + try + { + System.Windows.Forms.Clipboard.SetText(txtSyncScript.Text); + } + catch (Exception ex) + { + MessageBox.Show("An error ocurred while trying to copying the text to the clipboard"); + Trace.WriteLine("ERROR: +" + ex.Message); + } + } + + private void btnUpdate_Click(object sender, EventArgs e) + { + TreeView tree = (TreeView)schemaTreeView1.Controls.Find("treeView1", true)[0]; + TreeNode dbArm = tree.Nodes[0]; + var sb = new StringBuilder(); + + foreach (TreeNode node in dbArm.Nodes) + { + if (node.Nodes.Count != 0) + { + foreach (TreeNode subnode in node.Nodes) + { + if (subnode.Checked) + { + //ISchemaBase selected = (ISchemaBase)tree.SelectedNode.Tag; + ISchemaBase selected = (ISchemaBase)subnode.Tag; + + IDatabase database = (IDatabase)schemaTreeView1.LeftDatabase; + + if (database.Find(selected.FullName) != null) + { + switch (selected.ObjectType) + { + case ObjectType.Table: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.AlterWhitespace: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for table '{selected.Name}'"); break; + } + } + break; + + case ObjectType.StoredProcedure: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.AlterWhitespace: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for stored procedure '{selected.Name}'"); break; + } + } + break; + + case ObjectType.Function: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.AlterWhitespace: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter | ObjectStatus.AlterBody: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for function '{selected.Name}'"); break; + } + } + break; + + case ObjectType.View: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.AlterWhitespace: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter | ObjectStatus.AlterBody: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for view '{selected.Name}'"); break; + } + } + break; + + default: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.addNew(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for '{selected.Name}'"); break; + } + } + break; + } + } + } + } + } + } + + if (sb.Length == 0) + MessageBox.Show(this, "All successful.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show(this, sb.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + + if (Options.Comparison.ReloadComparisonOnUpdate) + { + StartComparison(); + } + + btnUpdate.Enabled = false; + } + + private void btnUpdateAll_Click(object sender, EventArgs e) + { + if (MessageBox.Show("Are you sure you want to update all?", "Confirm update", MessageBoxButtons.OKCancel) == DialogResult.OK) + { + TreeView tree = (TreeView)schemaTreeView1.Controls.Find("treeView1", true)[0]; + TreeNode database = tree.Nodes[0]; + var sb = new StringBuilder(); + foreach (TreeNode tn in database.Nodes) + { + foreach (TreeNode inner in tn.Nodes) + { + if (inner.Tag != null) + { + ISchemaBase item = (ISchemaBase)inner.Tag; + switch (item.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(item, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(item, RightDatabaseSelector.ConnectionString)); break; + } + } + } + } + + if (sb.Length == 0) + MessageBox.Show(this, "Update successful.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show(this, sb.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + + StartComparison(); + } + } + + private void btnOptions_Click(object sender, EventArgs e) + { + Options = Options ?? ProjectSelectorHandler.GetDefaultProjectOptions(); + OptionForm form = new OptionForm(this.ProjectSelectorHandler, Options); + form.OptionSaved += new OptionControl.OptionEventHandler((option) => Options = option); + form.ShowDialog(this); + } + + private void LoadProjectHandlers() + { + ProjectHandlers.Clear(); + toolProjectTypes.Items.Clear(); + + ProjectHandlers.Add(new OpenDBDiff.Schema.SQLServer.Generates.Front.SQLServerProjectHandler()); + } + + private void PrincipalForm_Load(object sender, EventArgs e) + { + LoadProjectHandlers(); + foreach (var projectHandler in ProjectHandlers) + { + toolProjectTypes.Items.Add(projectHandler); + } + + if (toolProjectTypes.SelectedItem == null && toolProjectTypes.Items.Count > 0) + { + toolProjectTypes.SelectedIndex = 0; + } + + var LastConfiguration = Project.GetLastConfiguration(); + if (LastConfiguration != null) + { + if (LeftDatabaseSelector != null) + LeftDatabaseSelector.ConnectionString = LastConfiguration.ConnectionStringSource; + if (RightDatabaseSelector != null) + RightDatabaseSelector.ConnectionString = LastConfiguration.ConnectionStringDestination; + } + + txtNewObject.LexerLanguage = "mssql"; + txtNewObject.ReadOnly = false; + txtOldObject.LexerLanguage = "mssql"; + txtOldObject.ReadOnly = false; + txtDiff.LexerLanguage = "mssql"; + txtDiff.ReadOnly = false; + txtDiff.Margins[0].Width = 20; + + Scintilla[] scintillaControls = new Scintilla[] { txtNewObject, txtOldObject, txtDiff, txtSyncScript }; + foreach (var scintilla in scintillaControls) + { + scintilla.InitializeScintillaControls(); + } + txtSyncScript.Text = ""; + txtSyncScript.SetMarginWidth(); + } + + private void btnSaveProject_Click(object sender, EventArgs e) + { + try + { + if (ActiveProject == null) + { + ActiveProject = new Project + { + ConnectionStringSource = ProjectSelectorHandler.GetSourceConnectionString(), + ConnectionStringDestination = ProjectSelectorHandler.GetDestinationConnectionString(), + ProjectName = String.Format( + "[{0}].[{1}] - [{2}].[{3}]", + ProjectSelectorHandler.GetSourceServerName(), + ProjectSelectorHandler.GetSourceDatabaseName(), + ProjectSelectorHandler.GetDestinationServerName(), + ProjectSelectorHandler.GetDestinationDatabaseName() + ), + Options = Options ?? ProjectSelectorHandler.GetDefaultProjectOptions(), + Type = Project.ProjectType.SQLServer + }; + + string newProjectName = ActiveProject.ProjectName.Trim(); + do + { + newProjectName = InputBox.ShowInputBox("Enter the project name.", newProjectName, false).Trim(); + } + while (string.IsNullOrWhiteSpace(newProjectName)); + ActiveProject.ProjectName = newProjectName; + } + ActiveProject.Id = Project.Save(ActiveProject); + } + catch (Exception ex) + { + HandleException("Saving Project", ex); + } + } + + private void btnProject_Click(object sender, EventArgs e) + { + try + { + var projects = Project.GetAll(); + if (projects.Any()) + { + var form = new ListProjectsForm(projects); + form.OnSelect += new ListProjectHandler(form_OnSelect); + form.OnDelete += new ListProjectHandler(form_OnDelete); + form.OnRename += new ListProjectHandler(form_OnRename); + form.ShowDialog(this); + } + else + MessageBox.Show(this, "There are currently no saved projects.", "Projects", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + HandleException("Opening Project", ex); + } + } + + private void form_OnRename(Project itemSelected) + { + try + { + Project.Save(itemSelected); + } + catch (Exception ex) + { + HandleException("Renaming Project", ex); + } + } + + private void form_OnDelete(Project itemSelected) + { + try + { + Project.Delete(itemSelected.Id); + if ((ActiveProject?.Id ?? int.MinValue) == itemSelected.Id) + { + ActiveProject = null; + LeftDatabaseSelector.ConnectionString = ""; + RightDatabaseSelector.ConnectionString = ""; + } + } + catch (Exception ex) + { + HandleException("Deleting Project", ex); + } + } + + private void form_OnSelect(Project itemSelected) + { + try + { + if (itemSelected != null) + { + ActiveProject = itemSelected; + LeftDatabaseSelector.ConnectionString = itemSelected.ConnectionStringSource; + RightDatabaseSelector.ConnectionString = itemSelected.ConnectionStringDestination; + } + } + catch (Exception ex) + { + HandleException("Selecting Project", ex); + } + } + + private void btnNewProject_Click(object sender, EventArgs e) + { + LeftDatabaseSelector.ConnectionString = ""; + RightDatabaseSelector.ConnectionString = ""; + ActiveProject = null; + } + + private void toolProjectTypes_SelectedIndexChanged(object sender, EventArgs e) + { + UnloadProjectHandler(); + if (toolProjectTypes.SelectedItem != null) + { + var handler = toolProjectTypes.SelectedItem as IProjectHandler; + LoadProjectHandler(handler); + } + } + } +} diff --git a/OpenDBDiff/Front/PrincipalForm.resx b/OpenDBDiff/Front/PrincipalForm.resx new file mode 100644 index 0000000..c5c2aef --- /dev/null +++ b/OpenDBDiff/Front/PrincipalForm.resx @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, -2 + + + 153, -2 + + + 36 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/Front/ProgressForm.Designer.cs b/OpenDBDiff/Front/ProgressForm.Designer.cs new file mode 100644 index 0000000..5982a91 --- /dev/null +++ b/OpenDBDiff/Front/ProgressForm.Designer.cs @@ -0,0 +1,132 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + partial class ProgressForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProgressForm)); + this.gradientPanel1 = new System.Windows.Forms.Panel(); + this.lblName = new System.Windows.Forms.Label(); + this.panel1 = new System.Windows.Forms.Panel(); + this.originProgressControl = new OpenDBDiff.Front.DatabaseProgressControl(); + this.destinationProgressControl = new OpenDBDiff.Front.DatabaseProgressControl(); + this.gradientPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // gradientPanel1 + // + this.gradientPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gradientPanel1.Controls.Add(this.lblName); + this.gradientPanel1.Location = new System.Drawing.Point(0, 0); + this.gradientPanel1.Name = "gradientPanel1"; + this.gradientPanel1.Size = new System.Drawing.Size(499, 58); + this.gradientPanel1.TabIndex = 27; + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Font = new System.Drawing.Font("Arial", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblName.Location = new System.Drawing.Point(12, 16); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(200, 24); + this.lblName.TabIndex = 24; + this.lblName.Text = "Compare Progress"; + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.Controls.Add(this.destinationProgressControl); + this.panel1.Controls.Add(this.originProgressControl); + this.panel1.Location = new System.Drawing.Point(0, 57); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(499, 173); + this.panel1.TabIndex = 30; + // + // originProgressControl + // + this.originProgressControl.BackColor = System.Drawing.Color.WhiteSmoke; + this.originProgressControl.DatabaseName = "Source:"; + this.originProgressControl.Location = new System.Drawing.Point(12, 92); + this.originProgressControl.Maximum = 100; + this.originProgressControl.Message = ""; + this.originProgressControl.Name = "sourceProgressControl"; + this.originProgressControl.Size = new System.Drawing.Size(472, 64); + this.originProgressControl.TabIndex = 35; + this.originProgressControl.Value = 0; + // + // destinationProgressControl + // + this.destinationProgressControl.BackColor = System.Drawing.Color.WhiteSmoke; + this.destinationProgressControl.DatabaseName = "Destination:"; + this.destinationProgressControl.Location = new System.Drawing.Point(12, 15); + this.destinationProgressControl.Maximum = 100; + this.destinationProgressControl.Message = ""; + this.destinationProgressControl.Name = "destinationProgressControl"; + this.destinationProgressControl.Size = new System.Drawing.Size(472, 64); + this.destinationProgressControl.TabIndex = 34; + this.destinationProgressControl.Value = 0; + // + // ProgressForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Control; + this.ClientSize = new System.Drawing.Size(496, 230); + this.Controls.Add(this.panel1); + this.Controls.Add(this.gradientPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProgressForm"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Running"; + this.Activated += new System.EventHandler(this.ProgressForm_Activated); + this.gradientPanel1.ResumeLayout(false); + this.gradientPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private Panel gradientPanel1; + private Label lblName; + private Panel panel1; + private DatabaseProgressControl destinationProgressControl; + private DatabaseProgressControl originProgressControl; + } +} diff --git a/OpenDBDiff/Front/ProgressForm.cs b/OpenDBDiff/Front/ProgressForm.cs new file mode 100644 index 0000000..0929cd2 --- /dev/null +++ b/OpenDBDiff/Front/ProgressForm.cs @@ -0,0 +1,124 @@ +using OpenDBDiff.Schema.Events; +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + public partial class ProgressForm : Form + { + private IGenerator OriginGenerator; + private IGenerator DestinationGenerator; + private bool IsProcessing = false; + private Schema.Model.IDatabase originClone = null; + private readonly IDatabaseComparer Comparer; + + // TODO: thread-safe error reporting + + public ProgressForm(KeyValuePair originDatabase, KeyValuePair destinationDatabase, IDatabaseComparer comparer) + { + InitializeComponent(); + + Origin = null; + Destination = null; + originProgressControl.Maximum = originDatabase.Value.GetMaxValue(); + originProgressControl.DatabaseName = originDatabase.Key; + this.OriginGenerator = originDatabase.Value; + + destinationProgressControl.Maximum = destinationDatabase.Value.GetMaxValue(); + destinationProgressControl.DatabaseName = destinationDatabase.Key; + this.DestinationGenerator = destinationDatabase.Value; + + this.Comparer = comparer; + } + + public Schema.Model.IDatabase Origin { get; private set; } + + public Schema.Model.IDatabase Destination { get; private set; } + + public string ErrorLocation { get; private set; } + + public string ErrorMostRecentProgress { get; private set; } + + public Exception Error { get; private set; } + + private void btnOK_Click(object sender, EventArgs e) + { + this.Cursor = Cursors.WaitCursor; + this.Close(); + this.Cursor = Cursors.Default; + } + + private void ProgressForm_Activated(object sender, EventArgs e) + { + var handler = new ProgressEventHandler.ProgressHandler(genData2_OnProgress); + try + { + if (!IsProcessing) + { + this.Refresh(); + IsProcessing = false; + OriginGenerator.OnProgress += new ProgressEventHandler.ProgressHandler(genData1_OnProgress); + DestinationGenerator.OnProgress += handler; + + this.ErrorLocation = "Loading " + destinationProgressControl.DatabaseName; + Origin = OriginGenerator.Process(); + originProgressControl.Message = "Complete"; + originProgressControl.Value = OriginGenerator.GetMaxValue(); + + this.ErrorLocation = "Loading " + originProgressControl.DatabaseName; + Destination = DestinationGenerator.Process(); + + originClone = (Schema.Model.IDatabase)Origin.Clone(null); + + this.ErrorLocation = "Comparing Databases"; + Destination = Comparer.Compare(Origin, Destination); + Origin = originClone; + + destinationProgressControl.Message = "Complete"; + destinationProgressControl.Value = DestinationGenerator.GetMaxValue(); + } + } + catch (Exception err) + { + this.Error = err; + } + finally + { + OriginGenerator.OnProgress -= handler; + DestinationGenerator.OnProgress -= handler; + this.Close(); + } + } + + private void genData2_OnProgress(ProgressEventArgs e) + { + if (e.Progress > -1 && destinationProgressControl.Value != e.Progress) + { + destinationProgressControl.Value = e.Progress; + } + + if (String.Compare(destinationProgressControl.Message, e.Message) != 0) + { + destinationProgressControl.Message = e.Message; + } + + this.ErrorMostRecentProgress = e.Message; + } + + private void genData1_OnProgress(ProgressEventArgs e) + { + if (e.Progress > -1 && originProgressControl.Value != e.Progress) + { + originProgressControl.Value = e.Progress; + } + + if (String.Compare(originProgressControl.Message, e.Message) != 0) + { + originProgressControl.Message = e.Message; + } + + this.ErrorMostRecentProgress = e.Message; + } + } +} diff --git a/OpenDBDiff/Front/ProgressForm.resx b/OpenDBDiff/Front/ProgressForm.resx new file mode 100644 index 0000000..4bf5cc5 --- /dev/null +++ b/OpenDBDiff/Front/ProgressForm.resx @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/Front/SchemaTreeView.Designer.cs b/OpenDBDiff/Front/SchemaTreeView.Designer.cs new file mode 100644 index 0000000..967c1f7 --- /dev/null +++ b/OpenDBDiff/Front/SchemaTreeView.Designer.cs @@ -0,0 +1,158 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + partial class SchemaTreeView + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SchemaTreeView)); + this.treeView1 = new System.Windows.Forms.TreeView(); + this.imageList1 = new System.Windows.Forms.ImageList(this.components); + this.chkOld = new System.Windows.Forms.CheckBox(); + this.chkNew = new System.Windows.Forms.CheckBox(); + this.chkDifferent = new System.Windows.Forms.CheckBox(); + this.chkShowUnchangedItems = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // treeView1 + // + this.treeView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.treeView1.CheckBoxes = true; + this.treeView1.ImageIndex = 0; + this.treeView1.ImageList = this.imageList1; + this.treeView1.Location = new System.Drawing.Point(0, 50); + this.treeView1.Name = "treeView1"; + this.treeView1.SelectedImageIndex = 0; + this.treeView1.Size = new System.Drawing.Size(262, 150); + this.treeView1.TabIndex = 0; + this.treeView1.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterCheck); + this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect); + // + // imageList1 + // + this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); + this.imageList1.TransparentColor = System.Drawing.Color.Transparent; + this.imageList1.Images.SetKeyName(0, "Folder"); + this.imageList1.Images.SetKeyName(1, "Table"); + this.imageList1.Images.SetKeyName(2, "Procedure"); + this.imageList1.Images.SetKeyName(3, "User"); + this.imageList1.Images.SetKeyName(4, "Column"); + this.imageList1.Images.SetKeyName(5, "Index"); + this.imageList1.Images.SetKeyName(6, "Rol"); + this.imageList1.Images.SetKeyName(7, "Schema"); + this.imageList1.Images.SetKeyName(8, "View"); + this.imageList1.Images.SetKeyName(9, "Function"); + this.imageList1.Images.SetKeyName(10, "XMLSchema"); + this.imageList1.Images.SetKeyName(11, "Database"); + this.imageList1.Images.SetKeyName(12, "UDT"); + this.imageList1.Images.SetKeyName(13, "Assembly"); + this.imageList1.Images.SetKeyName(14, "PartitionFunction"); + this.imageList1.Images.SetKeyName(15, "PartitionScheme"); + // + // chkOld + // + this.chkOld.AutoSize = true; + this.chkOld.Checked = true; + this.chkOld.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkOld.Location = new System.Drawing.Point(141, 27); + this.chkOld.Name = "chkOld"; + this.chkOld.Size = new System.Drawing.Size(117, 17); + this.chkOld.TabIndex = 1; + this.chkOld.Text = "Show missing items"; + this.chkOld.UseVisualStyleBackColor = true; + this.chkOld.CheckedChanged += new System.EventHandler(this.FilterCheckbox_CheckedChanged); + // + // chkNew + // + this.chkNew.AutoSize = true; + this.chkNew.Checked = true; + this.chkNew.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkNew.Location = new System.Drawing.Point(4, 27); + this.chkNew.Name = "chkNew"; + this.chkNew.Size = new System.Drawing.Size(103, 17); + this.chkNew.TabIndex = 2; + this.chkNew.Text = "Show new items"; + this.chkNew.UseVisualStyleBackColor = true; + this.chkNew.CheckedChanged += new System.EventHandler(this.FilterCheckbox_CheckedChanged); + // + // chkDifferent + // + this.chkDifferent.AutoSize = true; + this.chkDifferent.Checked = true; + this.chkDifferent.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkDifferent.Location = new System.Drawing.Point(141, 4); + this.chkDifferent.Name = "chkDifferent"; + this.chkDifferent.Size = new System.Drawing.Size(125, 17); + this.chkDifferent.TabIndex = 3; + this.chkDifferent.Text = "Show changed items"; + this.chkDifferent.UseVisualStyleBackColor = true; + this.chkDifferent.CheckedChanged += new System.EventHandler(this.FilterCheckbox_CheckedChanged); + // + // chkShowUnchangedItems + // + this.chkShowUnchangedItems.AutoSize = true; + this.chkShowUnchangedItems.Checked = true; + this.chkShowUnchangedItems.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkShowUnchangedItems.Location = new System.Drawing.Point(3, 4); + this.chkShowUnchangedItems.Name = "chkShowUnchangedItems"; + this.chkShowUnchangedItems.Size = new System.Drawing.Size(137, 17); + this.chkShowUnchangedItems.TabIndex = 4; + this.chkShowUnchangedItems.Text = "Show unchanged items"; + this.chkShowUnchangedItems.UseVisualStyleBackColor = true; + this.chkShowUnchangedItems.CheckedChanged += new System.EventHandler(this.FilterCheckbox_CheckedChanged); + // + // SchemaTreeView + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.chkShowUnchangedItems); + this.Controls.Add(this.chkDifferent); + this.Controls.Add(this.chkNew); + this.Controls.Add(this.chkOld); + this.Controls.Add(this.treeView1); + this.Name = "SchemaTreeView"; + this.Size = new System.Drawing.Size(266, 203); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private TreeView treeView1; + private CheckBox chkOld; + private CheckBox chkNew; + private CheckBox chkDifferent; + private ImageList imageList1; + private CheckBox chkShowUnchangedItems; + } +} diff --git a/OpenDBDiff/Front/SchemaTreeView.cs b/OpenDBDiff/Front/SchemaTreeView.cs new file mode 100644 index 0000000..3a26980 --- /dev/null +++ b/OpenDBDiff/Front/SchemaTreeView.cs @@ -0,0 +1,303 @@ +using OpenDBDiff.Schema; +using OpenDBDiff.Schema.Attributes; +using OpenDBDiff.Schema.Model; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace OpenDBDiff.Front +{ + public partial class SchemaTreeView : UserControl + { + private ISchemaBase databaseSource; + + public delegate void SchemaHandler(string ObjectFullName); + + public event SchemaHandler OnSelectItem; + + private bool busy = false; + + public SchemaTreeView() + { + InitializeComponent(); + } + + public ISchemaBase RightDatabase { get; set; } + + public ISchemaBase LeftDatabase + { + get { return databaseSource; } + set + { + databaseSource = value; + if (value != null) + { + RebuildSchemaTree(); + } + } + } + + public List GetCheckedSchemas() + { + List schemas = new List(); + if (treeView1.CheckBoxes) + { + GetCheckedNodesToList(schemas, treeView1.Nodes); + } + return schemas; + } + + public void SetCheckedSchemas(List schemas) + { + SetCheckedNodesFromList(schemas, treeView1.Nodes); + } + + private void GetCheckedNodesToList(List schemas, TreeNodeCollection nodes) + { + foreach (TreeNode node in nodes) + { + if (node.Tag != null) + { + if (node.Checked) + { + schemas.Add(node.Tag as ISchemaBase); + } + } + GetCheckedNodesToList(schemas, node.Nodes); + } + } + + private void SetCheckedNodesFromList(List schemas, TreeNodeCollection nodes) + { + foreach (TreeNode node in nodes) + { + if (node.Tag != null) + { + node.Checked = schemas.FirstOrDefault(sch => sch.Id == (node.Tag as ISchemaBase).Id) != null; + } + SetCheckedNodesFromList(schemas, node.Nodes); + } + } + + private void ReadProperties(Type item, TreeNodeCollection nodes, ISchemaBase schema) + { + PropertyInfo[] pi = item.GetProperties(); + nodes.Clear(); + foreach (PropertyInfo p in pi) + { + object[] attrs = p.GetCustomAttributes(typeof(SchemaNodeAttribute), true); + if (attrs.Length > 0) + { + SchemaNodeAttribute show = (SchemaNodeAttribute)attrs[0]; + TreeNode node = nodes.Add(p.Name, show.Name); + node.ImageKey = "Folder"; + ReadPropertyDetail(node, p, schema, show); + } + } + } + + private void ReadPropertyDetail(TreeNode node, PropertyInfo p, ISchemaBase schema, SchemaNodeAttribute attr) + { + Color NodeColor = Color.Black; + IList items = (IList)p.GetValue(schema, null); + node.Text = node.Text + " (" + items.Count + ")"; + node.Nodes.Clear(); + foreach (ISchemaBase item in items) + { + if (CanNodeAdd(item)) + { + TreeNode subnode = node.Nodes.Add(item.Id.ToString(), (attr.IsFullName ? item.FullName : item.Name)); + if (item.Status == ObjectStatus.Drop) + { + subnode.ForeColor = Color.Red; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.Red ? Color.Red : Color.Plum); + } + if (item.Status == ObjectStatus.Create) + { + subnode.ForeColor = Color.Green; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.Green ? Color.Green : Color.Plum); + } + if ((item.HasState(ObjectStatus.Alter)) || (item.HasState(ObjectStatus.Disabled))) + { + subnode.ForeColor = Color.Blue; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.Blue ? Color.Blue : Color.Plum); + } + if (item.HasState(ObjectStatus.AlterWhitespace)) + { + subnode.ForeColor = Color.DarkGoldenrod; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.DarkGoldenrod ? Color.DarkGoldenrod : Color.Plum); + } + if (item.HasState(ObjectStatus.Rebuild)) + { + subnode.ForeColor = Color.Purple; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.Purple ? Color.Purple : Color.Plum); + } + subnode.Tag = item; + subnode.ImageKey = attr.Image; + subnode.SelectedImageKey = attr.Image; + } + } + + node.ForeColor = NodeColor; + } + + private void RebuildSchemaTree() + { + string currentlySelectedNode = treeView1.SelectedNode != null ? treeView1.SelectedNode.Name : null; + string currentTopNode = treeView1.TopNode != null ? treeView1.TopNode.Name : null; + + this.busy = true; + treeView1.BeginUpdate(); + treeView1.Nodes.Clear(); + TreeNode databaseNode = treeView1.Nodes.Add("root", databaseSource.Name); + ReadProperties(databaseSource.GetType(), databaseNode.Nodes, databaseSource); + treeView1.Sort(); + databaseNode.ImageKey = "Database"; + databaseNode.Expand(); + + if (currentlySelectedNode != null) + { + var nodes = treeView1.Nodes.Find(currentlySelectedNode, true); + if (nodes.Any()) treeView1.SelectedNode = nodes.First(); + } + + if (currentTopNode != null) + { + var nodes = treeView1.Nodes.Find(currentTopNode, true); + if (nodes.Any()) treeView1.TopNode = nodes.First(); + } + + treeView1.EndUpdate(); + this.busy = false; + treeView1.Focus(); + } + + private Boolean CanNodeAdd(ISchemaBase item) + { + ObjectStatus checkedStatus = ObjectStatus.Original; + // OriginalStatus == 0, so have to treat differently + if (item.Status == ObjectStatus.Original && ShowUnchangedItems) return true; + + if (item.HasState(ObjectStatus.Drop) && ShowMissingItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Drop; + + if (item.HasState(ObjectStatus.Create) && ShowNewItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Create; + + if (item.HasState(ObjectStatus.Alter) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Alter; + + if (item.HasState(ObjectStatus.AlterWhitespace) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.AlterWhitespace; + + if (item.HasState(ObjectStatus.AlterBody) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.AlterBody; + + if (item.HasState(ObjectStatus.Rebuild) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Rebuild; + + if (item.HasState(ObjectStatus.RebuildDependencies) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.RebuildDependencies; + + if (item.HasState(ObjectStatus.ChangeOwner) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.ChangeOwner; + + if (item.HasState(ObjectStatus.DropOlder) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.DropOlder; + + if (item.HasState(ObjectStatus.Bind) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Bind; + + if (item.HasState(ObjectStatus.PermissionSet) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.PermissionSet; + + if (item.HasState(ObjectStatus.Disabled) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Disabled; + + if (item.HasState(ObjectStatus.Update) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Update; + + // At the end, we should have check all possible statuses. + ObjectStatus expectedTotalStatus = ObjectStatus.Original; + Enum.GetValues(typeof(ObjectStatus)).Cast().ToList().ForEach((s) => expectedTotalStatus = expectedTotalStatus | s); + + if (expectedTotalStatus != checkedStatus) + throw new Exception(string.Format("The OjbectStatusType '{0:G}' wasn't implemented in the CanNodeAdd() method. Developer, please ensure that all values in the Enum are checked.", (ObjectStatus)(expectedTotalStatus - checkedStatus))); + + return false; + } + + public Boolean ShowNewItems + { + get { return chkNew.Checked; } + set { chkNew.Checked = value; } + } + + public Boolean ShowMissingItems + { + get { return chkOld.Checked; } + set { chkOld.Checked = value; } + } + + public Boolean ShowChangedItems + { + get { return chkDifferent.Checked; } + set { chkDifferent.Checked = value; } + } + + public Boolean ShowUnchangedItems + { + get { return chkShowUnchangedItems.Checked; } + set { chkShowUnchangedItems.Checked = value; } + } + + private void FilterCheckbox_CheckedChanged(object sender, EventArgs e) + { + if (databaseSource == null) return; + + RebuildSchemaTree(); + } + + private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) + { + if (busy) return; + + ISchemaBase item = ((ISchemaBase)e.Node.Tag); + if (item != null) + { + if (item.ObjectType == ObjectType.Table + || item.ObjectType == ObjectType.View) + ReadProperties(item.GetType(), e.Node.Nodes, item); + if (OnSelectItem != null) OnSelectItem(item.FullName); + } + } + + private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) + { + if (e.Node.Tag == null) + { + foreach (TreeNode node in e.Node.Nodes) + { + node.Checked = e.Node.Checked; + } + } + } + + public string SelectedNode + { + get + { + if (treeView1.SelectedNode == null) return null; + + var item = treeView1.SelectedNode.Tag as ISchemaBase; + if (item == null) return null; + + return item.FullName; + } + } + } +} diff --git a/OpenDBDiff/Front/SchemaTreeView.resx b/OpenDBDiff/Front/SchemaTreeView.resx new file mode 100644 index 0000000..3cf89d0 --- /dev/null +++ b/OpenDBDiff/Front/SchemaTreeView.resx @@ -0,0 +1,481 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK + UgAAAk1TRnQBSQFMAgEBEAEAARQBAAEUAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABUAMAAQEBAAEgBgABUP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgABqgGTAYEB/wFU + AToBKAH/AVQBOAEqAf8BUgE6ASgB/wFSAToBKAH/AVEBOwEnAf8BUwE7ASkB/wFSAToBKAH/AVIBOgEo + Af8BVAE6ASgB/wFUAToBKAH/AVEBOgEpAf8BUgE6ASgB/0AAAU0BlgG0Af8BJwGkAdgB/wEUAY8ByQH/ + AQoBgwHAAf8BCAF9AbcB/wEKAVABdwH/AcUBfQE9Af8B2gGWAVUB/wHcAZIBUAH/AeMBnwFfAf8B3QGY + AVgB/wHdAZUBUwH/Ad0BkAFPAf8B3QGOAUoB/wHeAYwBRwH/AcIBaQEjAf8ByQLBAe8ByQLBAe8ByQLB + Ae8ByQLBAe8ByQLBAe8ByQLBAe8ByQLBAe8ByQLBAe8ByQLBAe8ByQLBAe8BUAF+AZEB7wE5AYYBqAHv + ASwBdAGfAe8BJAFvAZcB7wEkAWYBkgHvASQBSgFlAe8MAAGlAZMBggL/Af4C/wGtAZIBgQH/AaoBkgGC + Af8BqgGSAYIB/wGqAZEBhAH/Aa0BkAGDAf8BqgGSAYIB/wGqAZIBggH/AawBkgGBAf8BrgGSAYEB/wGs + AZIBgQH/AVEBOgEoAf9AAAFhAbABzAH/AT4B0gL/ASIBuAH2Af8BDgGsAfYB/wEDAaQB8gH/ARABcwGn + Af8B3wGmAWYB/wGFAYIBbwH/AZMBgQFtAf8B+QHMAYwB/wH3AckBigH/AfoBxwGEAv8BxwGBAf8B8AGx + AW0C/wG+AXYB/wHUAYEBOSH/AToBlwFTBf8BXQGtAckB/wE5AcwB+gH/AR4BswHwAf8BDAGnAe8B/wEC + AZ8B6wH/AQ0BbQGhAf8MAAGsAZIBgQH/Af0P/wP5Af8B+QHwAecB/wH5AfAB5wH/AfkB8AHnAf8B+QHw + AecB/wH5AfAB5wH/AaoBkgGCAf8BUQE6ASkB/0AAAYEBvQHNAf8BcwHjAfwB/wFPAcgB7wH/ATABuAHr + Af8BFwGqAeoB/wEUAXcBqAH/AdgBnwFlAf8B4gHaAawB/wGOAXYBWQH/AaEBiQFyAf8B5wGzAXwB/wFm + AVIBNgH/AXEBWgE6Af8BrQF8AUoB/wH+AbsBcgH/AdIBgQE9Gf8BSAGeAV8B/wFIAZ4BXwH/AR4BiAE6 + Af8BSAGeAV8B/wF4AbsBzQH/AWcB4AH9Af8BRQHFAfAB/wEoAbYB7QH/AREBqQHsAf8BEQF0AagB/wwA + AaYBkQGBA/8B/gH/Af0B/gr/AfgB9gH0Af8B+AH2AfQB/wH4AesB6AH/AfgB6wHoAf8B+AHrAegB/wH5 + AfAB5wH/AasBkQGBAf8BUwE7ASkB/0AAAY0BxAHLAf8BmAHsAfEB/wF9AdgB6gH/AV0BzwHxAf8BPwHD + AfMB/wElAYsBuwH/AdUBoAFnA/8BxQH/AbQBkAFmAf8BhgFxAVgC/wHrAakB/wF3AWEBRAH/AQgBDQEX + Af8BzgGnAXgC/wHHAYAB/wHRAYIBPxX/AVYBpgFrAf8BxwHhAc4B/wHHAeEBzgH/AR4BiAE6Af8BxwHh + Ac4B/wGKAcIBzAH/AY8B6gH0Af8BcAHUAesB/wFQAckB8AH/ATMBvQHxAf8BHwGGAbYB/wwAAawBkQGE + B/8B/g3/AfgB9gH0Af8B+AH2AfQB/wH4AfYB9AH/AfgB6wHoAf8B+QHwAecB/wGsAZIBggH/AVIBOwEn + Af8UAAHaAdMBzQH/AaMBjQGBAf8BgQFkAVgB/wGBAWgBVgH/AYABZQFTAf8BfAFfAU4B/wFzAV4BTAH/ + AW0BWAFDAf8BbAFTAUMB/wFgAUoBOQH/AZoBgwF9Af8BgwGsAbYB/wGDAcIBzgH/AWoBrwHHAf8BdgGv + AcEB/wFgAbcB0AH/AV0BoAG+Af8B1QGkAWoC/wH+AcoB/wGeAYMBZgH/AW4BUQEyAf8B8wHjAZ8B/wG4 + AaABdwH/AU8BNwEeAf8B4wGYAVQB/wHzAbQBdAH/AdEBhwFFAf8B9wHkAdsB/wHUAccBwQH/AdQBxwHB + Af8B1AHHAcEB/wHUAccBwQH/AY4BoQGEAf8B1AHHAcEF/wG5AdoBwgX/AYYBtAG9Af8BigHPAdkB/wFu + AbwB0gH/AWwBuQHQAf8BVAG7AdsB/wFKAZkBvQH/DAABqwGWAYUB/wH+Af8B/QH/Af0P/wH9A/8B+AH2 + AfQB/wH4AfYB9AH/AfgB6wHoAf8B+QHwAecB/wGqAZIBggH/AVIBOgEoAf8UAAGmAY8BgQX/AdABxgG3 + Af8ByQG3AbAB/wHBAasBogH/AbgBogGTAf8BtQGYAYoB/wGtAY0BgQH/AaQBhwF7Af8BnQGDAXMB/wFZ + AUMBMgH/AZIBuwHEAf8BhAHRAeEB/wFQAbcB3AH/AYMBpwG0Cf8B1gGnAW4C/wH7AckB/wGjAZYBgQH/ + AT8BOQEzAf8BvQGmAYIB/wHDAbMBiwH/AdkBuQGBAf8B5wG0AXcB/wHcAbkBhwH/AdQBigFKAf8B8wHY + AcsB/wHCAbQBrQH/AXYBbAFnAf8BuQGqAaMB/wHiAc4BxQH/AYwBgAF4Af8BwAGtAaUN/wGMAbUBvwH/ + AYQBywHaAf8BWAG0AdQB/wF9AaoBuQH/AcMB5AHtAf8BwgHbAecB/wHzAdgBywH/AcABrQGlAf8BwAGt + AaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/ + AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AfkB8AHnAf8BqgGSAYIB/wFSAToBKAX/AWMBSgE7Af8BYgFJ + AToB/wgAAa0BlgGFBf8B+wHqAeIB/wH3AeIB1wH/AfQB2wHSAf8B9AHUAcgB/wHtAc0BvAH/AfAByAG1 + Af8B7AG/AaoB/wGgAYYBeAH/AVsBRwE3Cf8BIAGIATwN/wHVAagBbgP/AdoB/wH4Ae4BtQH/AVsBSAE5 + Af8BrwGYAW4C/wH1AbQC/wHnAaYC/wHdAaAC/wHfAZ4B/wHVAYwBTgH/AfMB2AHLAf8BgQF3AXQB/wGs + AaEBnAH/AXgBcAFrAf8B9wHjAdkB/wF2AWwBZwH/AcABrQGlDf8BzwHhAeUB/wHJAesB8gH/AbIB4AHw + Af8ByQHZAd4J/wHzAdgBywH/AccBxAHDAf8BTgFNAUwB/wG5AbQBsQH/AfsB8gHuAf8BcQFsAWoB/wH6 + Ae0B5gH/AcMBuAGyAf8BTQFIAUUB/wG1AagBoQH/AfYB4gHYAf8BbwFlAWEB/wHAAa0BpQH/AfkB8AHn + Af8BqgGSAYIB/wFSATsBJwH/AbkBpAGYAf8B/gH9AfgB/wGXAYUBdgH/AZ0BiQF6Af8BmgGFAXoB/wGz + AZ0BjwH/Af0D/wH8Ae4B6gH/AfcB5wHdAf8B9gHfAdUB/wHzAdcBzgH/AfEB0gHDAf8B8AHKAbkB/wHw + AcUBsgH/AasBjAGBAf8BYwFLAToJ/wEgAYgBPA3/AdcBqwF1A/8B4wP/AcUB/wG0AZgBeAH/AXoBbwFh + Af8B+gHpAbIC/wHtAbMC/wHkAagC/wHoAasB/wHXAZIBUwH/AfMB2AHLAf8BgwF8AXkB/wGjAZkBlAH/ + AXoBcgFuAf8B9wHkAdsB/wGbAZABigH/AcABrQGlJf8B8wHYAcsB/wNOAf8B/gH5AfcB/wFOAU0BSwH/ + AfwB9AHwAf8BgwKBAf8B+gHvAekB/wFNAUkBRwH/AfgB6AHhAf8BTQFIAUUB/wH3AeMB2gH/AYEBdwFx + Af8BwAGtAaUB/wH5AfAB5wH/AawBkgGCAf8BUgE6ASgF/wHOAcABtAH/AWMBSwE6Af8IAAG4AaIBkQX/ + Af4C8gH/AfkB6wHjAf8B+QHjAdsB/wHzAdwB0wH/AfEB1wHGAf8B8QHSAb8B/wHwAcgBtQH/AbEBkgGH + Af8BZwFTAUIB/wHzAdgBywH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHN + AZYBXwH/AfAB4AG0Af8B7wHeAacB/wHyAc4BmAH/AesBugGEAf8B7wHOAZQB/wHvAcsBkgH/Ae8BygGN + Af8B8AHMAY0B/wHNAYQBRwH/AfMB2AHLAf8BuwGyAa8B/wGYAZABjAH/AbUBqgGkAf8BrAGfAZkB/wG2 + AakBowH/AcABrQGlJf8B8wHYAcsB/wHDAcEBwAH/AVEBUAFPAf8BrgGqAagB/wH8AfYB8gH/AckBwAG7 + Af8B+gHwAesB/wG7AbIBrwH/AU8BSwFIAf8BqgGfAZoB/wH3AeUB3AH/AbcBqwGlAf8BwAGtAaUF/wGq + AZIBggH/AVIBOgEoAf8UAAG7AakBlwH/Af4B/QL/Af0B+QH0Af8B/AHxAewB/wH7AeoB4gH/AfcB4AHX + Af8B9gHbAc4B/wHuAdQBxgH/AewBzAG7Af8BuAGcAY8B/wFvAVsBSgH/AfMB2AHLAf8BwwG4AbIB/wFM + AUcBRAH/AbUBqAGhAf8B9gHiAdgB/wFuAWQBYAH/AcABrQGlJf8B8wHYAcsB/wGmAZ8BmwH/AfkB7AHn + Af8BlgGNAYkB/wGMAYMBfQH/AY0BggF9Af8BwAGtAaUN/wG8AdgB4wH/Aa4B3QHwAf8BpwHVAesB/wGj + AdEB5wH/AaIBzgHkAf8BowG9AcwB/wHzAdgBywH/Ab0BuQG4Af8B/gH7AfoB/wHGAcQBwwH/AU4BTQFM + Af8BuQG0AbEB/wH8AfIB7gH/AbsBsgGuAf8B+QHsAeYB/wHDAbcBsQH/AU0BSAFFAf8BtQGnAaEB/wHA + Aa0BpQX/AaoBkgGCAf8BUgE6ASgB/xQAAcEBqwGaBf8B/AH/Af0C/wH+Bv8B/QH/Af4C/wL+Av8B/gT/ + Af4B/wG6AaIBmQH/AXoBYQFVAf8B8wHYAcsB/wFMAUgBRgH/AfgB6AHhAf8BTAFHAUQB/wH3AeMB2gH/ + AYEBdgFwAf8BwAGtAaUN/wFNAZYBtAH/AScBpAHYAf8BFAGPAckB/wEKAYMBwAH/AQgBfQG3Af8BCgFQ + AXcB/wHzAdgBywH/AXoBdwF1Af8B+gHuAekB/wFrAWYBYwH/AcIBtgGwAf8BaAFgAV0B/wHAAa0BpQ3/ + AVEBngG8Af8BLAGyAeQB/wEWAZwB1wH/AQkBkAHRAf8BBAGJAckB/wEKAVkBhQH/AfMB2AHLAf8DjAH/ + Af4B/QH8Af8BTwFOAU0B/wH9AfgB9wH/AU4BTAFLAf8B/AHzAe8B/wGCAYEBgAH/AfoB7QHoAf8BTQFJ + AUcB/wH4AekB4QH/AU0BRwFFAf8BwAGtAaUB/wGsAZIBgQH/AaoBkgGCAf8BUwE8ASgB/xQAAeMB3QHa + Af8BwgGrAZ8B/wHAAakBnAH/AbgBogGTAf8BswGdAY8B/wGtAZgBiQH/AakBkwGFAf8BowGOAYEB/wGg + AYkBgQH/AYwBdAFjAf8BwgG1AawB/wHzAdgBywH/AbsBsgGvAf8BTgFKAUcB/wGqAZ8BmgH/AfcB5QHc + Af8BtwGrAaUB/wHAAa0BpQ3/AWEBsAHMAf8BPgHSAv8BIgG4AfYB/wEOAawB9gH/AQMBpAHyAf8BEAFz + AacB/wHzAdgBywH/AY4BhQGBAf8B+AHqAeIB/wHFAbgBsQH/AXQBagFmAf8BvAGtAaYB/wHAAa0BpQ3/ + AWcBswHMAf8BSQHWAf4B/wErAbwB9AH/ARUBrwHzAf8BBgGmAfAB/wEPAXIBpwH/AfMB2AHLAf8DbwH/ + Av4B/QH/AbkCtwH/AU8BTgFNAf8BrgGqAagB/wH8AfUB8QH/AW4BawFqAf8B+gHwAeoB/wG2Aa0BqAH/ + AU0BSQFHAf8BqgGfAZoB/wHAAa0BpQH/AVIBOwEpAf8BVAE8ASkB/wFTAToBKgH/QAAB8wHYAcsB/wG7 + AbIBrgH/AfkB7AHmAf8BwwG3AbEB/wFMAUcBRAH/AbUBpwGhAf8BwAGtAaUN/wGBAb0BzQH/AXMB4wH8 + Af8BTwHIAe8B/wEwAbgB6wH/ARcBqgHqAf8BFAF3AagB/wH1Ad8B1QH/AfUB3wHVAf8B9QHfAdUB/wH1 + Ad8B1QH/AfUB3wHVAf8BywHJAbAB/wHMAbwBtgX/AdUB6QHaBf8BggG+Ac0B/wF4AeUB+gH/AVYBywHu + Af8BNgG8AewB/wEdAa8B7AH/ARUBeQGsAf8B8wHYAcsB/wHzAdgBywH/AfMB2AHLAf8B8wHYAcsB/wHz + AdgBywH/AfMB2AHLAf8B8wHYAcsB/wHzAdgBywH/AfMB2AHLAf8B8wHYAcsB/wHzAdgBywH/AfMB2AHL + Af8BwAGtAaUB/wHNAbkBrgH/AVIBOwEqAf8B2wHNAcEB/0AAAfMB2AHLAf8BggGBAX0B/wH6Ae0B6AH/ + AUwBSAFGAf8B+AHpAeEB/wFMAUYBRAH/AcABrQGlBf8BIAGIATwF/wGNAcQBywH/AZgB7AHxAf8BfQHY + AeoB/wFdAc8B8QH/AT8BwwHzAf8BJQGLAbsV/wE6AZcBUwH/AeMB8AHnAf8B4wHwAecB/wEeAYgBOgH/ + AeMB8AHnAf8BjAHBAcgB/wGVAecB7QH/AXkB0wHmAf8BXgHLAesB/wFBAcIB7wH/ASoBjgG7Af8MAAHN + AbcBpQL/Af4O/wP+Df8BswGbAYoB/wFTATwBKQH/Ad8BzQHCAf9EAAHzAdgBywH/AW0BagFpAf8B+gHw + AeoB/wG2Aa0BqAH/AUwBSAFGAf8BqgGfAZoB/wHAAa0BpQH/ASABiAE8Af8BIAGIATwB/wEgAYgBPAH/ + AYMBrAG2Af8BgwHCAc4B/wFqAa8BxwH/AXYBrwHBAf8BYAG3AdAB/wFdAaABvhn/ASwBjwFGAf8BLAGP + AUYB/wEeAYgBOgH/ASwBjwFGAf8BhAGtAbcB/wGDAcMBzwH/AWYBsAHIAf8BdQGvAcAB/wFoAbwB0wH/ + AWUBpgHCAf8MAAHQAbgBoAH/Ac0BtwGlAf8B1AG4AaMB/wHSAbcBpAH/AdIBtwGkAf8B0gG3AaQB/wHQ + AbUBowH/Ac0BsQGjAf8BxwGsAZoB/wHBAaQBmQH/AdoBzgHCAf9IAAHzAdgBywH/AfMB2AHLAf8B8wHY + AcsB/wHzAdgBywH/AfMB2AHLAf8B8wHYAcsB/wHAAa0BpQX/ASABiAE8Bf8BkgG7AcQB/wGEAdEB4QH/ + AVABtwHcAf8BgwGnAbQp/wEeAYgBOgX/AZIBuwHEAf8BhAHRAeEB/wFOAbcB3AH/AYMBpwG0Cf9MAAHz + AdgBywH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AcABrQGl + Af8BwAGtAaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/UAABhgG0AccB/wFwAZoBrgH/ + AV0BhAGbAf8BUQF3AY4B/wFJAW4BhgH/AUQBdgGSAf8BSAGBAaIB/wFnAZsBugH/EAABbwFVAUEB/wFv + AVUBQQH/AW8BVQFBAf8BbwFVAUEB/wFvAVUBQQH/AW8BVQFBAf8BbwFVAUEB/wFvAVUBQQH/AW8BVQFB + Af8BbwFVAUEB/wFvAVUBQQH/IAAB8wHYAcsB/wHHAcQBwwH/AVEBUAFPAf8BuQG0AbEB/wH7AfIB7gH/ + AXQBbwFtAf8B+gHtAeYB/wHDAbgBsgH/AVABSwFIAf8BtQGoAaEB/wH2AeIB2AH/AXIBaAFkAf8BwAGt + AaUB/wgAAegBgQFJAf8B4AF1ATwB/wHSAWoBNQH/Ab4BYAEvAf8BqgFXASsB/wGXAU4BKAX/AegBgQFJ + Af8B4AF1ATwB/wHRAWsBNAH/Ab4BYAEvAf8BqgFWASsB/wGWAU4BJwH/EAABVwGPAasB/wFfAaMBvwH/ + AXsBwAHUAf8BlQHZAeYB/wGDAd8B9AH/AVMBxgHsAf8BJwGqAd0B/wEZAZIBxwH/ASUBgQGsAf8BOAFx + AZAB/wwAAW8BVQFBJf8BbwFVAUEB/yAAAfMB2AHLAf8DUQH/Af4B+QH3Af8BUQFQAU4B/wH8AfQB8AH/ + AYMCgQH/AfoB7wHpAf8BUAFMAUoB/wH4AegB4QH/AVABSwFIAf8B9wHjAdoB/wGBAXoBdAH/AcABrQGl + Af8IAAHqAYwBYgH/Ad4B0gHKAf8B3gHSAcoB/wHeAdIBygH/Ad4B0gHKAf8BrwFYASsF/wHqAYwBYQH/ + Ad4B0gHKAf8B3gHSAcoB/wHeAdIBygH/Ad4B0gHKAf8BrwFZASsB/wwAAV0BhAGbAf8BRwG9AecB/wFq + AdMB8QH/AYwB4wH0Af8BogHrAfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHi + Af8BDAGWAdIB/wFAAWEBfQH/CAABbwFVAUEF/wFvAVUBQQH/AdgByAG9Af8B2AHIAb0B/wHYAcgBvQH/ + AdgByAG9Af8B2AHIAb0B/wFvAVUBQQH/AdgByAG9Af8BbwFVAUEB/wGnAZQBhgH/AacBlAGGAf8BpwGU + AYYB/wGqAZcBiQH/EAAB8wHYAcsB/wHDAcEBwAH/AVQBUwFSAf8BrgGqAagB/wH8AfYB8gH/AckBwAG7 + Af8B+gHwAesB/wG7AbIBrwH/AVIBTgFLAf8BqgGfAZoB/wH3AeUB3AH/AbcBqwGlAf8BwAGtAaUB/wgA + AeoBnQF6Af8B/QH6AfkB/wH7AfEB7QH/AfcB5gHdAf8B3gHSAcoB/wHIAWYBMgX/AeoBnQF7Af8B/QH6 + AfgB/wH6AfEB7AH/AfcB5QHdAf8B3gHSAcoB/wHIAWYBMQH/DAABXQGEAZsB/wFGAcQB8AH/AW4B1QH0 + Af8BjAHjAfQB/wGiAesB9gH/AYMB3wH0Af8BVAHLAfAB/wEhAbUB7QH/AQUBqAHpAf8BBAGiAeIB/wEG + AZwB2wH/AUABYQF9Af8IAAFvAVUBQQX/AdwBzAHBAf8BbwFVAUEB/wHxAe8B7gH/AfEB7wHuAf8B8gHn + Ad8B/wFvAVUBQQH/AfEB4gHYAf8B8gHfAdIB/wFvAVUBQQH/AfMB3AHOAf8B8gHbAcsB/wHhAc0BvwH/ + AaoBlwGJAf8QAAHzAdgBywH/Ab0BuQG4Af8B/gH7AfoB/wHGAcQBwwH/AVEBUAFPAf8BuQG0AbEB/wH8 + AfIB7gH/AbsBsgGuAf8B+QHsAeYB/wHDAbcBsQH/AVABSwFIAf8BtQGnAaEB/wHAAa0BpQH/CAAB6QGo + AYgF/wH9AfgB9gH/AfoB7gHoAf8B3gHSAcoB/wHdAXIBOgX/AekBqQGIBf8B/QH4AfUB/wH6Ae4B6AH/ + Ad4B0gHKAf8B3AFyAToB/wwAAWcBjwGlAf8BRgHEAe8B/wFuAdUB9AH/AYwB4wH0Af8BogHrAfYB/wGD + Ad8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGcAdsB/wFJAW4BhgH/CAABbwFV + AUEF/wHhAdABxQH/Af0B/gH9Af8B7AHeAdYB/wHpAdkB0QH/AewB3gHWAf8B/QH1Ae4B/wHsAd4B1gH/ + AewB3gHWAf8BbwFVAUEB/wHjAbYBtQH/Af0B6QHbAf8B4QHNAb8B/wGqAZcBiQH/EAAB8wHYAcsB/wOM + Af8B/gH9AfwB/wFSAVEBUAH/Af0B+AH3Af8BUQFPAU4B/wH8AfMB7wH/AYICgQH/AfoB7QHoAf8BUAFM + AUoB/wH4AekB4QH/AVABSgFIAf8BwAGtAaUB/wgAAeoBqgGLAf8B6gGqAYsB/wHqAaIBgQH/AeoBlgFw + Af8B6gGJAVwB/wHoAYEBSgX/AeoBqgGLAf8B6gGqAYsB/wHqAaIBgQH/AeoBlgFxAf8B6gGJAVwB/wHp + AYEBSQH/DAABZwGPAaUB/wFGAcQB8AH/AW4B1QH0Af8BjAHjAfQB/wGiAesB9gH/AYMB3wH0Af8BVAHL + AfAB/wEhAbUB7QH/AQUBqAHpAf8BBAGiAeIB/wEGAZwB2wH/AUkBbgGGAf8IAAFvAVUBQQX/AdgByAG9 + Af8B/QH+Af0B/wH9Af4B/QH/Af0B/gH9Af8B/QH+Af0B/wH9AfUB7gH/Af0B9QHuAf8B/gHxAegB/wFv + AVUBQQH/Af0B7gHhAf8B/QHpAdsB/wHiAc8BwgH/AaoBlwGJAf8QAAHzAdgBywH/A3IB/wL+Af0B/wG5 + ArcB/wFSAVEBUAH/Aa4BqgGoAf8B/AH1AfEB/wFxAW4BbQH/AfoB8AHqAf8BtgGtAagB/wFQAUwBSgH/ + AaoBnwGaAf8BwAGtAaUB/xQAAW8BXgFQFf8BdQFiAVQB/xgAAWcBjwGlAf8BRgHEAfAB/wFuAdUB9AH/ + AYwB4wH0Af8BogHrAfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGc + AdsB/wFJAW4BhgH/CAABbwFVAUEF/wHkAdQByQH/Af0B/gH9Af8B7AHeAdYB/wHsAd4B1gH/AewB3gHW + Af8B/QH8AfkB/wHsAd4B1gH/AewB3gHWAf8BbwFVAUEB/wHjAbYBtQH/Af0B7gHhAf8B4gHRAcYB/wGq + AZcBiQH/BAABxQGBAUEB/wHaAZYBWQH/AdwBkgFUAf8B4wGfAWMB/wHdAZgBXAH/Ad0BlQFXAf8B3QGQ + AVMB/wHdAY4BTgH/Ad4BjAFLAf8BwgFtAScB/wHzAdgBywH/AfMB2AHLAf8B8wHYAcsB/wHzAdgBywH/ + AfMB2AHLAf8BwAGtAaUB/xQAAXwBagFcFf8BegFnAVkB/xgAAWsBlQGrAf8BRgHEAfAB/wFuAdUB9AH/ + AYwB4wH0Af8BogHrAfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGc + AdsB/wFJAW4BhgH/CAABbwFVAUEF/wHkAdQByQH/AW8BVQFBAf8B/QH+Af0B/wH9Af4B/QH/Af0B/gH9 + Af8BbwFVAUEB/wH9AfUB7gH/Af4B8QHoAf8BbwFVAUEB/wH9Ae4B4QH/AfIB5wHfAf8B4gHRAcYB/wGq + AZcBiQH/BAAB3wGmAWoB/wGFAYIBcwH/AZMBgQFxAf8B+QHMAYwB/wH3AckBigH/AfoBxwGEAv8BxwGB + Af8B8AGxAXEC/wG+AXoB/wHUAYEBPQH/LAABqgGVAYYB/wGpAZQBhAH/AakBkwGEAf8BqQGUAYQB/wGp + AZMBhAH/AakBlAGFAf8BpwGRAYIB/xgAAWsBlQGrAf8BRgHEAfAB/wFuAdUB9AH/AYwB4wH0Af8BogHr + AfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGcAdsB/wFRAXcBjgH/ + CAABbwFVAUEF/wFvAVUBQQH/Af0B/gH9Af8B7AHfAdgB/wHsAd4B1gH/AewB3wHYAf8B/QH+Af0B/wFv + AVUBQQH/AewB3gHWAf8BbwFVAUEB/wHjAbYBtQH/Af0B9QHuAf8B4gHYAdEB/wGqAZcBiQH/BAAB2AGf + AWkB/wHiAdoBrAH/AY4BegFdAf8BoQGJAXYB/wHnAbMBgQH/AWoBVgE6Af8BdQFeAT4B/wGtAYEBTgH/ + Af4BuwF2Af8B0gGBAUEB/wwAAVQBlQFLAf8oAAFxAV4BTwH/JAABcAGaAa4B/wFGAcQB8AH/AW4B1QH0 + Af8BjAHjAfQB/wGiAesB9gH/AYMB3wH0Af8BVAHLAfAB/wEhAbUB7QH/AQUBqAHpAf8BBAGiAeIB/wEG + AZwB2wH/AVEBdwGOAf8IAAFvAVUBQQX/AeQB1AHJAf8B/QH+Af0B/wH9Af4B/QH/Af0B/gH9Af8B/QH+ + Af0B/wH9Af4B/QH/Af0B/gH9Af8B/QH8AfkB/wFvAVUBQQH/Af4B+QH1Af8B/QH1Ae4B/wHhAc0BvwH/ + AaoBlwGJAf8EAAHVAaABawP/AcUB/wG0AZABagH/AYYBdQFcAv8B6wGpAf8BewFlAUgB/wEMAREBGwH/ + Ac4BpwF8Av8BxwGBAf8B0QGCAUMB/wgAAVQBlQFLAf8BVAGVAUsB/wFUAZUBSwH/JAABbwFcAU4B/yQA + AXABmwGwAf8BRgHEAfAB/wFuAdUB9AH/AYwB4wH0Af8BogHrAfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1 + Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGcAdsB/wFRAXcBjgH/CAABbwFVAUEB/wFvAVUBQQH/AW8BVQFB + Af8BbwFVAUEB/wFvAVUBQQH/AW8BVQFBAf8BbwFVAUEB/wFvAVUBQQH/AW8BVQFBAf8BbwFVAUEB/wFv + AVUBQQH/Af0B9QHuAf8B/QH1Ae4B/wHhAc0BvwH/AaoBlwGJAf8EAAHVAaQBbgL/Af4BygH/AZ4BgwFq + Af8BcgFVATYB/wHzAeMBnwH/AbgBoAF7Af8BUwE7ASIB/wHjAZgBWAH/AfMBtAF4Af8B0QGHAUkB/wwA + AVQBlQFLAf8cAAHqAZUBcAH/AeoBiAFbAf8B6AGBAUgB/wHeAXQBOgH/Ac8BaQEzAf8BugFeAS4B/wGl + AVQBKgH/GAABdAGfAbIB/wFGAcQB8AH/AW4B1QH0Af8BjAHjAfQB/wGiAesB9gH/AYMB3wH0Af8BVAHL + AfAB/wEhAbUB7QH/AQUBqAHpAf8BBAGiAeIB/wEGAZwB2wH/AVgBgQGVAf8QAAHkAdQBySn/Af0B9QHu + Af8BqgGXAYkB/wQAAdYBpwFyAv8B+wHJAf8BowGWAYEB/wFDAT0BNwH/Ab0BpgGCAf8BwwGzAYsB/wHZ + AbkBgQH/AecBtAF7Af8B3AG5AYcB/wHUAYoBTgH/DAABVAGVAUsB/xwAAeoBogGBAf8B3gHSAcoB/wHe + AdIBygH/Ad4B0gHKAf8B3gHSAcoB/wHeAdIBygH/AbsBXwEuAf8YAAF3AaMBuAH/AW4B1QH0Af8BmgHo + AfcB/wG1AfMB+gH/AcUB+QH9Af8BxQH5Af0B/wHCAfUB+gH/Aa8B8AH7Af8BjAHjAfQB/wFuAdUB9AH/ + AUEBuAHlAf8BWAGBAZUB/xAAAfoBzAG1Af8B+gHLAbQB/wH6AcoBswH/AfoBxgGrAf8B+wHAAaMB/wH6 + AboBmQH/AfsBtAGQAf8B+wGtAYcB/wH8AakBgQH/AfwBqQGBAf8B+wGoAYEB/wH8AakBgQH/Ae0BoQGB + Af8EAAHVAagBcgP/AdoB/wH4Ae4BtQH/AV8BTAE9Af8BrwGYAXIC/wH1AbQC/wHnAaYC/wHdAaAC/wHf + AZ4B/wHVAYwBUgH/DAABVAGVAUsB/xwAAeoBqgGLAf8B/gH8AfsB/wH7AfQB8AH/AfkB6QHjAf8B9QHf + AdQB/wHeAdIBygH/Ac8BaQEzAf8YAAF3AaMBuAH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9 + Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BWAGBAZUB/xAA + AfoBzAG1Av8B3AHJAv8B2gHFAv8B1wHBAv8B1AG+Av8B0AG5Av8BzQG0Av8BygGvAv8BxgGpAv8BxgGp + Av8BwgGkAv8BwQGhAf8B8QGnAYMB/wQAAdcBqwF5A/8B4wP/AcUB/wG0AZgBfAH/AYABcwFlAf8B+gHp + AbIC/wHtAbMC/wHkAagC/wHoAasB/wHXAZIBVwH/AVQBlQFLAf8BVAGVAUsB/wFUAZUBSwH/IAAB6gGq + AYsF/wH9AfkB9wH/AfoB8AHrAf8B9wHmAd0B/wHeAdIBygH/Ad4BdAE7Af8cAAGMAb0BzAH/AZ0BzwHb + Af8BrQHfAegB/wG5AewB8wH/AcIB9QH6Af8BwgH1AfoB/wG5AewB8wH/AakB2gHjAf8BlAHEAdEB/wGA + AagBuAH/FAAB+gHMAbUB/wH6AcsBtAH/AfoBywG0Af8B+gHKAbMB/wH6AcYBrgH/AfsBwwGnAf8B+wG+ + AZ8B/wH6AbgBmAH/AfwBqQGBAf8B+wG0AZAB/wH7AbABiAH/AfwBrAGDAf8B+gGpAYEB/wQAAc0BlgFj + Af8B8AHgAbQB/wHvAd4BpwH/AfIBzgGYAf8B6wG6AYQB/wHvAc4BlAH/Ae8BywGSAf8B7wHKAY0B/wHw + AcwBjQH/Ac0BhAFLAf8sAAHqAaoBiwH/AeoBqgGLAf8B6gGqAYsB/wHqAaIBgQH/AeoBlgFvAf8B6gGH + AVsB/wHoAYEBRwH/IAABpQHMAdgB/wGMAb0BzAH/AXwBpwG6Af8BcAGbAbAB/wFwAZoBrgH/AXQBnwGy + Af8BggGrAb0B/wGbAb8BzAH/2AABtwGiAZMB/wFrAVEBPQH/AWsBUQE9Af8BawFRAT0B/wFrAVEBPQH/ + AWsBUQE9Af8BawFRAT0B/wFrAVEBPQH/AWsBUQE9Af8BawFRAT0B/wFrAVEBPQH/AWsBUQE9Af8QAAG3 + AaIBkwH/AW0BUwE/Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/ + Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/Af8BbQFTAT8B/1wAAbwBZgEmAf8B3AGBAUYB/wHcAXsBQQH/ + AdwBeQE9Af8B3AF1ATsB/wHcAXMBNwH/AeEBbgEyAf8B2AFzATcB/wHWAXMBNwH/AdgBcwE3Af8B2AFz + ATkB/wgAAbcBogGTAf8B/AH+Av8BoAHgAekB/wGbAdoB5AH/AZgB1AHgAf8BlAHPAdwB/wGQAcoB2AH/ + AYwBxAHTAf8BiAG/Ac4B/wGEAboBygH/AYEBtgHHAf8BawFRAT0B/xAAAbcBogGTAv8B+gH3Af8B6QHh + Ad0B/wHpAd0B2AH/AekB2QHRAf8B6QHVAcsB/wHpAdEBxQH/AekBzgG/Af8B6QHJAbkB/wHpAcYBtAH/ + AekBxAGwAf8BbQFTAT8B/xQAAecBgQFQAf8ByAFtATkB/wGYAVQBLgH/BAAB5wGBAVAB/wHIAW0BOQH/ + AZgBVAEuAf8EAAHnAYEBUQH/AcgBbgE6Af8BmQFVAS8B/xgAAT8BqQHgAf8B6wGzAYYC/wHjAb4C/wHF + AZ4C/wG0AYcC/wGlAX0C/wGPAWEC/wGNAWwC/wGNAWQC/wGNAWEC/wGNAWIC/wGPAWYB/wgAAbcBogGT + Af8B/AH+Av8B0QH2AfoB/wHNAfUB+QH/AckB9QH5Af8BxAHzAfgB/wHBAfMB9wH/Ab0B8gH3Af8BuQHy + AfYB/wG2AfEB9gH/AYQBuAHJAf8BawFRAT0B/xAAAbcBogGTAv8C/QL/AfcB8wL/AfcB8wH/AYUBgQGA + Af8BhQGBAYAB/wGFAYEBgAH/AYUBgQGAAv8B9wHzAv8B3gHNAf8B6QHGAbUB/wFtAVMBPwH/FAAB6QGc + AYEB/wH4AeIB1AH/AcgBbAE6Af8EAAHpAZwBgQH/AfgB4gHUAf8ByAFsAToB/wQAAekBnQGBAf8B+AHi + AdQB/wHIAW0BOwH/DAABCQGnAegB/wEJAacB6AH/AQkBpwHoAf8BPwGpAeAB/wHrAbMBhgL/AekBxwL/ + AdEBqQL/AcIBmAL/AbEBgQL/AaIBgQL/Ae8B6wL/AY8BagL/AYkBWQL/AYsBXwL/AY0BYgH/CAABtwGi + AZMC/wG7AZkB/wHoAZABbQH/Ad8BgQFOAf8BxgFlATAB/wHMAeoB6QH/AeoBjwFpAf8B5gGEAVoB/wHf + AYEBTwH/AcoBaAE0Af8BhgG8AcwB/wFrAVEBPQH/EAABtwGiAZMG/wH+Af0C/wH3AfMC/wH4AfQC/wH0 + Ae8C/wHwAegC/wHrAeEC/wH3AfMC/wHiAdQB/wHpAcsBvAH/AW0BUwE/Af8UAAHqAaoBiwH/AegBnAGB + Af8BmAFUAS4B/wQAAeoBqgGLAf8B6AGcAYEB/wGYAVQBLgH/BAAB6gGqAYsB/wHoAZ0BgQH/AZkBVQEv + Af8IAAEJAacB6AH/Aa4B7QL/AUkB2AL/AUkB2AL/AesBswGGAf8B6wGGAVUC/wHvAc8C/wHeAbgC/wHS + AakC/wG4AZYK/wGHAWgC/wGBAVUC/wGEAVkC/wGPAWIB/wgAAbcBogGTAf8B/gHGAakB/wP+Af8B3QHc + AdkB/wHXAYwBawH/AdAB7QHuAf8B6gGaAXoB/wP+Af8B3QHcAdkB/wHYAYEBUAH/AYkBwAHPAf8BawFR + AT0B/xAAAbcBogGTBv8B9wHzAv8B9wHzAf8BhQGBAYAB/wGFAYEBgAH/AYUBgQGAAf8BhQGBAYAC/wH3 + AfMC/wH3AfMB/wHpAc8BwwH/AW0BUwE/Af8YAAHqAaoBiwH/DAAB5gGBAUgB/wwAAZQBUgEuAf8MAAEJ + AacB6AH/AboB8AH+Af8BrgHuAf4B/wFJAdgC/wFJAdgC/wHhAYEBTgL/AeUBxQL/AesBywL/Ae0BywH/ + AdYCswH/AYsBjgG1Af8BagFmAYIC/wGYAXEC/wGRAWEC/wGEAVkB/wHtAXEBMgH/CAABugGlAZYB/wH+ + AdABuAH/AewBqwGMAf8B6gGWAXQB/wHkAYEBUQH/AdUB7gHtAf8B6gGqAYsB/wHqAaIBgQH/AeoBiAFe + Af8B2AGBAVAB/wGMAcQB0wH/AWsBUQE9Af8QAAG6AaUBlgr/AfcB8wL/Av4C/wH9AfoC/wH5AfYC/wH1 + AfAC/wH3AfMC/wHtAeQB/wHpAdQBygH/AW0BUwE/Af8YAAHqAaoBiwH/DAAB5gGBAUgB/wwAAZQBUgEu + Af8MAAEJAacB6AH/AcYB8gL/AbsB8AH+Af8BrgHuAf4B/wGhAesB/gH/AdoBpQGBAf8B9gGHAVIC/wG2 + AYQB/wH8AYkBdQH/AdIBwAHRAf8BdAGgAdAB/wE3AVYBgAH/AekBdwFqAv8BlgGBAf8B+AFuASgB/wHn + AboBjQH/CAABvgGpAZoB/wH8Af4C/wHhAfgB/AH/AWUBTAE4Af8B2AH3AfsB/wHVAfcB+gH/AdEB9gH5 + Af8BZQFMATgB/wHKAfUB+QH/AccB9AH5Af8BjwHJAdYB/wFrAVEBPQH/EAABvgGpAZoG/wH3AfMC/wH3 + AfMB/wGFAYEBgAH/AYUBgQGAAf8BhQGBAYAB/wGFAYEBgAL/AfcB8wL/AfIB7AH/AekB2QHSAf8BbQFT + AT8B/xgAAeoBqgGLAf8MAAHmAYEBSgH/DAABlQFTAS0B/wwAAQkBpwHoAf8B0gH1Af4B/wHGAfIB/gH/ + AboB8AH+Af8BSQHYAv8B8QHrAv8BtgGpAc0B/wHWAaABgQH/ARsCCAH/AV4BZQGBAf8BbwGYAc4B/wFq + AY8BvgH/AScBXAGBAf8BVQFyAZAB/wH2AdIBswH/DAABwwGuAZ4B/wH8Af4C/wHlAfkB/AH/AZcBhwGB + Af8BlwGHAYEB/wGXAYcBgQH/AZcBhwGBAf8BlwGHAYEB/wHOAfYB+QH/AcoB9QH5Af8BkgHMAdoB/wFr + AVEBPQH/EAABwwGuAZ4K/wH3AfMO/wL9Av8B9wHzAv8B9wHzAf8B6QHfAdkB/wFtAVMBPwH/GAAB6gGq + AYsB/wHqAaoBiwH/AeYBjQFpAf8B5gGDAVkB/wHmAYEBSgH/AeABegFAAf8BtAFiATYB/wGmAVsBMQH/ + AZUBUwEtAf8MAAG7AfAB/gH/AQkBpwHoAf8B0gH0Af4B/wHGAfIB/gH/AdIBwAHRAf8BdAGgAdAB/wE3 + AVYBgAH/AbMD/wEZASEBUwH/AU8BgQGoAf8BhwGxAdcB/wGFAbQB1wH/AW8BogHWAf8BegGaAckB/xAA + AcgBsgGjAf8B/AH+Av8B6QH7AfwB/wHiAfUB9gH/AdkC6wH/AYABVQE7Af8BzwLjAf8B0AHuAfAB/wHS + AfcB+gH/Ac8B9gH5Af8BlQHQAdwB/wFrAVEBPQH/EAAByAGyAaMG/wH3AfMC/wH3AfMB/wGFAYEBgAH/ + AYUBgQGAAf8BhQGBAYAB/wGFAYEBgAL/AfcB8wL/AfcB8wH/AekB4wHfAf8BbQFTAT8B/ygAAeYBgQFO + Af8kAAEJAacB6AH/ARsCCAH/AaIBngHFAf8BbwGYAc4B/wFqAY8BvgH/ASoBYgGaAf8BeQGEAbkB/wFe + AZYBywH/AYIBvAHXAf8BgQG3AdcB/wF9AbQB1gH/AXABlAHIAf8QAAHIAbIBowH/AfwB/gL/Ae0B/AH+ + Af8B6gGPAWkB/wHqAYEBVAH/AeUBfQFEAf8B5QF9AUQB/wHIAWgBNAH/AdYB9wH7Af8B0gH3AfoB/wGY + AdUB4AH/AWsBUQE9Af8QAAHMAbYBpyL/Av4C/wH7AfoB/wFtAVMBPwH/KAAB5wGBAVAB/ygAARkBIQFT + Af8BTwGBAagB/wGHAbEB1wH/AYUBtAHXAf8BbwGiAdYB/wEMARQBOwH/AUYBZgGKAf8BbAGUAcUB/wF6 + AagB1gH/AUoBdAGfAf8BYQGBAacB/xAAAcwBtgGnAf8B/AH+Av8B8AH7Af4B/wHqAZoBegH/A/4B/wP+ + Af8B3QHcAdkB/wHhAXoBQAH/AdoB+AH7Af8BngHeAecB/wGbAdkB4wH/AWwBUgE+Af8QAAHqAaoBiwH/ + AeoBqgGLAf8B6AGmAYYB/wHmAaEBgQH/AeMBmgGBAf8B4QGTAXcB/wHdAYwBbQH/AdoBgwFjAf8B1wGB + AVkB/wHTAYEBTwH/AdEBeAFHAf8BzwFzAUAB/yQAAecBgQFQAf8ByAFtATkB/wGYAVQBLgH/JAABeQGE + AbkB/wFeAZYBywH/AYIBvAHXAf8BgQG3AdcB/wF9AbQB1gH/AwgB/wIIASMB/wEkATcBYwH/AUQBZgGG + Af8BCAEOAUoB/wFTAUEBYgH/EAAB0QG7AasB/wH8Af4C/wH0Af0B/gH/AeoBqgGLAf8B6gGiAYEB/wHq + AZYBdAH/AeoBiAFeAf8B6AGBAUwB/wG3AaIBkwH/AWwBUgE+Af8BbAFSAT4B/wFsAVIBPgH/EAAB6gGq + AYsC/wHCAaIC/wHCAaIB/wH9Ab4BnAH/AfwBuAGTAf8B+gGvAYkB/wH4AacBgQH/AfYBoAGAAf8B9AGa + AXUB/wHzAZUBbwH/AfMBlQFvAf8BzgFzAUAB/yQAAekBnAGBAf8B+AHiAdQB/wHIAWwBOgH/JAABDAEU + ATsB/wFGAWYBigH/AWwBlAHFAf8BegGoAdYB/wFKAXQBnwH/ASoBJQE5Af8DCAH/AwgB/wMIAf8DCAH/ + AdgBywHgAf8QAAHVAb8BrwH/AfwB/gL/AfgB/QH+Af8B9QH8Af4B/wHyAfwB/gH/Ae0B+wH9Af8B6gH7 + AfwB/wHnAfoB/AH/AbkBpAGVAf8B1AHFAboB/wFsAVIBPgH/AeIB1gHOAf8QAAHqAaoBiwH/AeoBqgGL + Af8B6AGmAYYB/wHmAaABgQH/AeMBmgGBAf8B4AGTAXcB/wHdAYwBbQH/AdoBhAFjAf8B1wGBAVkB/wHU + AYABTwH/AdABeAFHAf8BzwFzAUEB/yQAAeoBqgGLAf8B6AGcAYEB/wGYAVQBLgH/JAADCAH/AggBIwH/ + ASQBNwFjAf8BRAFmAYYB/wEJARIBPgH/AVMBQQFiAf8DCAH/AwgB/wMIAf8BxwG6Ac0B/xQAAdgBwgGy + Af8B/AH+Av8B/AH+Av8B/AH+Av8B/AH+Av8B/AH+Av8B/AH+Av8B/AH+Av8BwAGrAZwB/wFsAVIBPgH/ + AeIB1gHOAf+YAAEqASUBOQH/AwgB/wMIAf8DCAH/AwgB/wHYAcsB4AH/JAAB2AHCAbIB/wHYAcIBsgH/ + AdgBwgGyAf8B2AHCAbIB/wHYAcIBsgH/AdgBwgGyAf8B1AG+Aa4B/wHPAbkBqQH/AckBswGkAf8B4gHW + Ac4B/6AAAwgB/wMIAf8DCAH/AccBugHNAf//AC0AAf8B3gG4Af8BvAFoASgB/wHcAYEBSAH/AdwBfQFD + Af8B3AF7AT8B/wHcAXcBPQH/AdwBdQE5Af8B4QFwATQB/wHYAXUBOQH/AdYBdQE5Af8B2AF1ATkB/wHY + AXUBOwH/AcMBcAEyAf/MAAH/AaUBgQH/AesBswGGAv8B4wG+Av8BxQGeAv8BtAGHAv8BpQGBAv8BjwFj + Av8BjQFuAv8BjQFmAv8BjQFjAv8BjQFkAv8BjwFoAf8B2gF1ATkB/wQAAYABhAGPAf8BdQGBAYUB/wFp + AXYBgQH/AVoBZgFvAf8BSwFVAV0B/wE6AUMBSgH/ASwBMwE5Af8BHwElASoB/wEXARwBIQH/ARcBHAEh + Af8BFwEcASEB/wEXARwBIQH/ARcBHAEhAf8BFwEcASEB/wEXARwBIQH/SAABzQFsATMB/wHIAWQBOgH/ + AbQBYAEyAf8BrwFkASwB/wGgAVMBOQH/AZABUwEtAf8BmAFTASgB/wGFAUsBLgH/AYQBSgEnAf8BgQFF + ASwB/wGBAU0BMAH/AZEBRgEmAf8UAAH/AaUBgQH/AesBswGGAv8B6QHHAv8B0QGpAv8BwgGYAv8BsQGB + Av8BogGBAv8B7wHrAv8BjwFsAv8BiQFbAv8BiwFhAv8BjQFkAf8B2AF1ATkB/wQAAYEBhwGSAf8BogHf + AfAB/wF5Ac0B6gH/AVIBuAHiAf8BQAGuAdsB/wE2AakB2QH/AS8BoQHSAf8BKgGYAccB/wEpAY4BvAH/ + AScBgwGuAf8BIgGBAasB/wEeAYEBqQH/ASQBgQGfAf8BKAF7AZYB/wEfASUBKgH/CAABtwGiAZMB/wFq + AVABPAH/AW0BUwE/Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/ + Af8BbQFTAT8B/wFtAVMBPwH/AXIBWAFEAf8QAAHQAW8BNgL/Ae4B8QH/AfkB9wHvAf8C7QHnAf8B9gHk + AdkC/wHjAcwB/wHtAd0BzQH/AfYB3gHMAf8B8gHaAcIB/wHvAdABwQH/AesByAG0Af8BiQFGASsB/xQA + AesBswGGAf8B6wGGAVcC/wHvAc8C/wHeAbgC/wHSAakC/wG4AZYK/wGHAWoC/wGBAVcC/wGEAVsC/wGP + AWQB/wHWAXIBNgH/BAABgQGKAZUB/wGqAegB9gH/AZUB5QH8Af8BhAHfAfsB/wGAAdYB+gH/AXMB0AH3 + Af8BZgHGAfQB/wFZAb4B8AH/AUoBtAHsAf8BPgGqAegB/wE0AaQB5gH/ASkBmgHfAf8BHwGQAdcB/wEk + AYEBnwH/ASkBMAE2Af8IAAG9AagBmQH/AfwB/gH8Af8B5wHmAeQB/wHnAeIB3AH/AeYB3AHUAf8B5QHW + AcsB/wHkAc8BwQH/AeMBygG4Af8B4wHFAbEB/wHiAcIBrAH/AccBqgGYAf8BcgFYAUQB/xAAAdYBdQE8 + Av8B+QH0Af8BqAFbAUEB/wGoAVsBQQH/AagBWwFBAf8BqAFbAUEB/wGoAVsBQQH/AagBWwFBAf8BqAFb + AUEB/wH7Ac8BtwH/AesBzwGwAf8BjQFQAS4B/wgAAeEB7gH0Af8BggGsAb8B/wFtAZABogL/Ad4BuAH/ + AeEBgQFQAv8B5QHFAv8B6wHLAv8B7QHLAf8B1gKzAf8CogHWAf8BgQF3AZoC/wGYAXMC/wGRAWMC/wGE + AVsB/wHtAXMBNAH/AesBswGGAf8EAAGBAY4BmAH/AbAB6gH2Af8BnwHpAfsB/wGSAeQB/AH/AYEB3QH7 + Af8BgAHWAfoB/wFxAc4B9wH/AWYBxgH0Af8BVgG8AfAB/wFKAbQB7AH/AT4BqgHoAf8BMwGjAeYB/wEm + AZYB3AH/AR4BgQGpAf8BNgE9AUQB/wgAAcYBsAGhAf8B/AH+AfwB/wHYAcQBuQH/AdYBwAG1Af8B0wG8 + Aa8B/wH6Ae8B5gH/Ac8BswGlAf8BzAGvAZ8B/wHKAasBmwH/AfYB2wHIAf8BxwGqAZgB/wFyAVgBRAH/ + EAAB2wF6AUEB/wH9AfoB9gH/AfcB9QH0Af8B/QHyAe4B/wHzAewB4wH/AfUB6wHaAf8B8QHmAdIB/wHw + AeAB2QH/AfkB2wHQAf8B7QHRAcYB/wHuAc4BuwH/AYoBRwEsAf8IAAFxAZcBrQH/AVsBsAHRAf8BhAHV + AegB/wGhAesB9gH/AdoBpQGBAf8B9gGHAVQC/wG2AYQB/wH8AYkBdwH/AdIBwAHRAf8BdgGgAdAB/wE5 + AVgBgQH/AekBeQFsAv8BlgGBAf8B+AFwASoB/wHnAboBjQH/CAABgQGRAZwB/wG2Ae0B+AH/AaoB7AH7 + Af8BmwHoAfsB/wGPAeMB/AH/AYEB3QH7Af8BegHVAfkB/wFxAc4B9wH/AWQBxQH0Af8BVgG8AfAB/wFG + AbIB7AH/ATsBqQHoAf8BLQGeAeIB/wEZAYIBtAH/AUQBTAFUAf8IAAHMAbYBpwH/AfwB/gH8Af8B/AH+ + AfwB/wH8Af4B/AH/AfsB+gH3Af8B+wH1Ae8B/wH6Ae8B5gH/AfkB6AHcAf8B9wHhAdEB/wH2AdsByAH/ + AcgBrgGcAf8BcgFYAUQB/xAAAd8BgAFFAv8B/QH1Af8BqAFbAUEB/wGoAVsBQQH/Af4B7wHsAf8BqAFb + AUEB/wGoAVsBQQH/AfAB5AHSAf8B9AHcAdYB/wHyAdIBzAH/AfAB0gG/Af8BgwFJASwB/wgAAV0BjwGq + Af8BVwHXAv8BkAHqAfoB/wGhAesB9gH/AXsB2QH0Av8B3gG4Af8B1gGgAYEB/wEdAgoB/wFgAWcBgQH/ + AXEBmAHOAf8BbAGPAb4B/wEpAV4BgQH/AVcBdAGQAf8B9gHSAbMB/wwAAYMBlQGfAf8BvgHwAfkB/wGr + AfAB9wH/AaUB7AH7Af8BmAHnAfsB/wGJAeEB/AH/AYEB3QH7Af8BegHVAfkB/wFuAc0B9wH/AWEBxAHz + Af8BVAG7AfAB/wFGAbIB7AH/ATUBpAHjAf8BFQGKAb8B/wFSAVwBZQH/CAABzAG2AacB/wH8Af4B/AH/ + AdsBygHAAf8B2gHIAb0B/wHYAcQBuQH/AfsB+gH3Af8B0wG8Aa8B/wHRAbgBqgH/Ac8BswGlAf8B9wHh + AdEB/wHIAbIBogH/AXIBWAFEAf8QAAHkAYEBSgH/AfkB/gH8Av8B/gH5Af8B9QL3Af8B/QHuAesB/wH2 + AeoB5gH/AfcB6AHlAf8B/AHiAdwB/wHqAeMBzwH/AfQB1gHFAf8B+wHYAb4B/wGKAUwBKgH/CAABXgGR + Aa4B/wFWAdIB+gH/AY0B5AH2Af8BoQHrAfYB/wF6AdcB8wH/AS4BuQHvAf8BCwGnAegB/wEZASQBSQH/ + AVEBgQGoAf8BhwGxAdcB/wGFAbQB1wH/AXEBogHWAf8BfAGaAckB/xAAAYYBmQGjAf8BvgHwAfkB/wG2 + Ae0B+AH/AbAB7gH6Af8BpAHrAfoB/wGVAeYB+wH/AYkB4QH8Af8BgQHcAfwB/wF6AdUB+QH/AW4BzQH3 + Af8BYQHEAfMB/wFSAbkB7wH/AT4BqQHnAf8BFQGPAccB/wFgAWwBdAH/CAABzAG2AacB/wH8Af4B/AH/ + AfwB/gH8Af8B/AH+AfwB/wH8Af4B/AH/AfwB/gH8Af8B+wH6AfcB/wH7AfUB7wH/AfoB7wHmAf8B+QHo + AdwB/wHJAbcBqgH/AXIBWAFEAf8QAAHtAYIBUwH/AfsB/QP/AfwB+QH/AfwB/wH2Af8B+wH4AeoB/wHz + AfcB6wL/AecB4wH/AfUB7wHkAf8B/gHmAdoB/wHrAd4BzgH/Ae8B4QHFAf8BiAFPAS4B/wgAAWEBlQGw + Af8BWAHSAfoB/wGNAeQB9AH/AaEB6wH2Af8BegHXAfIB/wEuAbkB7gH/AQsBpwHoAf8BewGEAbkB/wFg + AZYBywH/AYIBvAHXAf8BgQG3AdcB/wGBAbQB1gH/AXIBlAHIAf8QAAGJAZwBpgH/Ab4B8AH5Af8BtgHt + AfgB/wG2Ae0B+AH/AasB8AH3Af8BogHsAfoB/wGVAeYB+wH/AYkB4QH8Af8BgQHcAfwB/wF4AdMB+gH/ + AWwBzAH3Af8BXgHDAfMB/wFSAbkB7wH/ASIBmQHPAf8BbAF5AYEB/wgAAcwBtgGnAf8B/AH+AfwB/wHb + AcoBwAH/AdsBygHAAf8B2wHKAcAB/wH8Af4B/AH/AdgBxAG5Af8B1gHAAbUB/wHTAbwBrwH/AfoB7wHm + Af8BygG8AbMB/wFyAVgBRAH/EAAB8QGGAV0D/wH5Af8BqAFbAUEB/wGoAVsBQQL/AfIB7gH/AfAB8gH6 + Af8B9gHxAfAC/wHvAd0B/wH2AesB3QH/AfsB2wHVAf8B+AHaAc8B/wGiAVoBKgH/CAABYwGZAbUB/wFZ + AdEB+wH/AY4B5AH1Af8BoQHrAfYB/wF6AdcB8gH/AS4BuQHuAf8BCwGnAegB/wEOARYBPQH/AUgBaAGK + Af8BbgGUAcUB/wF8AagB1gH/AUwBdgGfAf8BYwGBAacB/xAAAYsBoAGoAf8BvgHwAfkB/wG+AfAB+QH/ + Ab4B8AH5Af8BvgHwAfkB/wG0AfIB+AH/AaoB7AH7Af8BoAHpAfsB/wGVAeUB/AH/AYoB3wH8Af8BgQHY + AfsB/wF9AdIB+AH/AXEBygH0Af8BZgHAAfEB/wFsAXkBgQH/CAABzAG2AacB/wH8Af4B/AH/AfwB/gH8 + Af8B/AH+AfwB/wH8Af4B/AH/AfwB/gH8Af8B/AH+AfwB/wH7AfoB9wH/AfsB9QHvAf8B+gHvAeYB/wH5 + AegB3AH/AXIBWAFEAf8QAAHuAZMBagH/AfMD/wH5Af8B9wP/AfUC/wH7AfUC/wL2Af8B+ALwAf8B9AHv + AewB/wH1AeoB5gL/AeMB3AH/AfwB2wHSAf8BnwFcATUB/wgAAWYBmwG3Af8BWQHQAfkB/wGNAeMB9QH/ + AaEB6wH2Af8BfAHZAfIB/wEuAbkB7gH/AQsBpwHoAf8DCgH/AgoBJQH/ASYBOQFlAf8BRgFoAYYB/wIo + AWMB/wFVAUMBZAH/EAABjQGhAaoB/wGNAaEBqgH/AY0BoQGqAf8BjQGhAaoB/wGNAaEBqgH/AYsBnwGo + Af8BiQGcAaYB/wGJAZsBpgH/AYcBmgGkAf8BhgGZAaMB/wGEAZYBoAH/AYQBlgGgAf8BgwGVAaAB/wGD + AZUBoAH/AYABhAGPAf8IAAHrAawBjQH/AeoBqgGMAf8B6gGpAYkB/wHpAaIBgQH/AegBmQF7Af8B5gGP + AW0B/wHlAYUBXwH/AeMBgQFRAf8B4wGAAUYB/wHiAXwBQgH/AeMBfQFDAf8BzgFyAUAB/xAAAecBlAFx + Af8B7wGLAWUB/wHwAYoBaQH/AeUBgQFcAf8B4QGBAUIB/wHjAYEBQQH/AdgBfQE/Af8BzwF1AT4B/wHY + AW8BPAH/Ab4BZgEwAf8BqQFgATMB/wG4AWIBLAH/CAABaAGeAboB/wFXAdAB+QH/AY0B4wH0Af8BoQHr + AfYB/wF5AdcB8gH/ASkBtwHuAf8BCwGnAegB/wEsAScBOwH/AwoB/wMKAf8DCgH/AwoB/wHYAcsB4AH/ + EAABjwGkAawB/wGyAeQB7AH/AbYB7QH4Af8BtgHtAfgB/wGpAewB9gH/AZIB4QHzAf8BjQGhAaoB/wHV + AdwB4AH/JAAB6wGsAY0C/wHDAaIB/wH+Ab8BnQH/AfwBuwGYAf8B+wG2AZIB/wH6AbABiwH/AfkBqwGD + Af8B+AGmAYEB/wH1AaABgQH/AfUBmgF3Af8B9QGXAXIB/wHUAXoBSAH/EAAB5AGXAYEB/wH9Ab4BqgL/ + AbsBpwL/AbgBoQL/AbYBkQH/Af0BrgGFAv8BrwGHAv8BqwGEAv8BpQGBAv8BowF7Af8B/QGZAXkB/wG4 + AV8BMwH/CAABaQGiAbwB/wFRAc4B9wH/AYsB4wH0Af8BoQHrAfYB/wF4AdYB8gH/ASkBtwHuAf8BCwGn + AegB/wENAZwB2gH/AwoB/wMKAf8DCgH/AccBugHNAf8UAAHaAd4B4QH/AY8BpAGsAf8BjwGkAawB/wGP + AaQBrAH/AY8BpAGsAf8BjwGkAawB/wHVAdwB4AH/KAAB6wGsAY0B/wHqAaoBiwH/AeoBqgGLAf8B6gGo + AYkB/wHpAaIBgQH/AegBnAGBAf8B5wGUAXUB/wHmAYwBagH/AeUBhQFeAf8B5AGBAVMB/wHjAYEBSgH/ + AeMBgQFJAf8QAAHVAZ8BiAH/Ae4BnQF6Af8B4gGVAW4B/wHhAZQBZgH/AeYBhgFaAf8B6AGBAVIB/wHo + AYEBTAH/AeIBgQFBAf8B3wF1ATwB/wHRAW4BMAH/Ac0BbAE5Af8BuQFnATwB/wgAAXUBqQHAAf8BYAHU + AfoB/wGcAewB+gH/AasB7wH6Af8BpgHtAfgB/wGUAecB+AH/AXsB2QH2Af8BRgG9AekB/wFNAYEBlwH/ + 3AABgQGzAcUB/wGbAd4B6wH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BxQH5Af0B/wGg + Ad8B6gH/AXABkQGiAf/cAAHSAekB7wH/AZUBwwHTAf8BgQGrAboB/wF6AaMBswH/AXYBnQGvAf8BdQGb + Aa4B/wF5AaIBtAH/AYgBsgHCAf8BxAHcAeQB/xwAAUIBTQE+BwABPgMAASgDAAFAAwABUAMAAQEBAAEB + BQABgAECFgAD/4EAAeABAAL/BAAB4AEAAv8EAAHgAQAC/wQAAeABAAL/BAAB4AEAAfgFAAHgAQAB+AcA + ARgPAAEYBwAB+AcAAfgHAAH4BwAC/wYAAv8EAAHgAQEC/wQAAeABAwL/BAAC/wHgAQAC/wHwAQ8BAAEf + AeABAAHAAQEB4AEHAQABHwHgAQABwAEBAcABAwEAAQEB4AEAAcABAQHAAQMBAAEBAeABAAHAAQEBwAED + AQABAQHgAQABwAEBAcABAwEAAQEB4AEAAfgBDwHAAQMBAAEBAgAB+AEPAcABAwEAAQEBAAE/AfgBDwHA + AQMBAAEBAQABOwH/AX8BwAEDAQABAQEAATEB/wF/AcABAwEAAQEBAAE7AfgBDwHAAQMBwAEBAQABOwH4 + AQ8BwAEDAcABAQEAATsB+AEPAcABAwHAAQEBAAEHAfgBDwHgAQcBwAEBAQABPwH4AQ8B8AEPBv8BwAED + AcABAwL/AfgBAAHAAQMBwAEDAeIBIwHwAQABwAEDAcABAwHiASMBgAEAAcABAwHAAQMB4gEjAgABwAED + AcABAwH3AXcCAAHAAQMBwAEDAfcBdwIAAcABAwHAAQMB9wF3AQABAQHAAQMBwAEDAfABBwEAAQMBwAED + AcABAwH/AX8BwAEDAcABAwHAAQMB/wF/AeABAwHAAQMBwAEDAf4BPwHgAQMBwAEDAcABAwH+AT8B4AED + AcABAwHAAQMB/gE/AeABBwHAAQcE/wHgAX8BwAEPBP8B8An/AeABAAb/AeABAAGAAQAC/wHAAQMB4AEA + AYABAAHAAQMBwAEDAeABAAGAAQABwAEDAcABAwIAAYABAAHAAQMBwAEDAQABAQGAAQABwAEDAcABAwEA + AQMBgAEAAcABAwHAAQMBAAEHAYABAAHAAQMBwAEDAQABBwGAAQABwAEDAcABAwEAAQcBgAEAAcABAwHA + AQMBAAEHAYABAAHAAQMBwAEDAQABBwGAAX8BwAEDAcABAwEAAQ8BgAH/AcABAwHAAQMBAAF/Bv8BAAF/ + Bv8BAAF/Cw== + + + \ No newline at end of file diff --git a/OpenDBDiff/OpenDBDiff.csproj b/OpenDBDiff/OpenDBDiff.csproj new file mode 100644 index 0000000..92c2eb5 --- /dev/null +++ b/OpenDBDiff/OpenDBDiff.csproj @@ -0,0 +1,261 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {99A26820-E71D-4E01-ADF2-E6AB25B03FA0} + WinExe + Properties + OpenDBDiff + OpenDBDiff + false + + + 3.5 + + + false + v4.5.2 + App.ico + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 0.8.5.%2a + false + true + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + false + + + true + + + + ..\packages\DiffPlex.1.6.3\lib\net40\DiffPlex.dll + + + ..\packages\Essy.Tools.InputBox.1.0.0\lib\net20\InputBox.dll + True + + + ..\packages\LiteDB.5.0.9\lib\net45\LiteDB.dll + + + ..\packages\jacobslusser.ScintillaNET.3.6.3\lib\net40\ScintillaNET.dll + True + + + + + + + + + + + + + + + + + + + Form + + + DataCompareForm.cs + + + Form + + + ErrorForm.cs + + + Form + + + MainForm.cs + + + + UserControl + + + DatabaseProgressControl.cs + + + Form + + + ListProjectsForm.cs + + + Form + + + OptionForm.cs + + + Form + + + ProgressForm.cs + + + UserControl + + + SchemaTreeView.cs + + + + + DatabaseProgressControl.cs + + + DataCompareForm.cs + + + ErrorForm.cs + + + MainForm.cs + + + OptionForm.cs + Designer + + + ProgressForm.cs + + + SchemaTreeView.cs + Designer + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + .editorconfig + + + + True + True + Resources.resx + + + + + + + + + {406558a0-1b98-4d0e-b8b6-2013700b065a} + OpenDBDiff.Abstractions.Schema + + + {e82cfc94-de8c-4edd-aa0c-f78abae03768} + OpenDBDiff.Abstractions.Ui + + + {ef2f571e-a7ad-40be-8500-50a039159fc1} + OpenDBDiff.SqlServer.Ui + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + + + + + + + + + + + + + ListProjectsForm.cs + + + + + + + + + \ No newline at end of file diff --git a/OpenDBDiff/Program.cs b/OpenDBDiff/Program.cs new file mode 100644 index 0000000..f2ae296 --- /dev/null +++ b/OpenDBDiff/Program.cs @@ -0,0 +1,20 @@ +using OpenDBDiff.UI; +using System; +using System.Windows.Forms; + +namespace OpenDBDiff +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainForm()); + } + } +} diff --git a/OpenDBDiff/Properties/AssemblyInfo.cs b/OpenDBDiff/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..fecfc4c --- /dev/null +++ b/OpenDBDiff/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("05d564b6-a409-42dc-adf7-a5764a124cdf")] diff --git a/OpenDBDiff/Properties/AssemblyVersionInfo.cs b/OpenDBDiff/Properties/AssemblyVersionInfo.cs new file mode 100644 index 0000000..5303259 --- /dev/null +++ b/OpenDBDiff/Properties/AssemblyVersionInfo.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("0.13.0.0")] +[assembly: AssemblyFileVersion("0.13.0.0")] diff --git a/OpenDBDiff/Properties/Resources.Designer.cs b/OpenDBDiff/Properties/Resources.Designer.cs new file mode 100644 index 0000000..5a5eb3d --- /dev/null +++ b/OpenDBDiff/Properties/Resources.Designer.cs @@ -0,0 +1,193 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace OpenDBDiff.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OpenDBDiff.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap arrow_ew { + get { + object obj = ResourceManager.GetObject("arrow_ew", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap clipboard_invoice { + get { + object obj = ResourceManager.GetObject("clipboard_invoice", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap compare { + get { + object obj = ResourceManager.GetObject("compare", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap database_refresh { + get { + object obj = ResourceManager.GetObject("database_refresh", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap database_yellow { + get { + object obj = ResourceManager.GetObject("database_yellow", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap diskette { + get { + object obj = ResourceManager.GetObject("diskette", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap folder { + get { + object obj = ResourceManager.GetObject("folder", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap new_window { + get { + object obj = ResourceManager.GetObject("new_window", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap refresh_all { + get { + object obj = ResourceManager.GetObject("refresh_all", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap save_as { + get { + object obj = ResourceManager.GetObject("save_as", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap setting_tools { + get { + object obj = ResourceManager.GetObject("setting_tools", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap table_analysis { + get { + object obj = ResourceManager.GetObject("table_analysis", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap table_edit { + get { + object obj = ResourceManager.GetObject("table_edit", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/OpenDBDiff/Properties/Resources.resx b/OpenDBDiff/Properties/Resources.resx new file mode 100644 index 0000000..fd3fba2 --- /dev/null +++ b/OpenDBDiff/Properties/Resources.resx @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\compare.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\clipboard_invoice.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\database_refresh.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\database_yellow.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\refresh_all.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\save_as.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\setting_tools.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\table_analysis.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\table_edit.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\diskette.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\new_window.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\arrow_ew.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/OpenDBDiff/Resources/arrow_ew.png b/OpenDBDiff/Resources/arrow_ew.png new file mode 100644 index 0000000..db2b449 Binary files /dev/null and b/OpenDBDiff/Resources/arrow_ew.png differ diff --git a/OpenDBDiff/Resources/clipboard_invoice.png b/OpenDBDiff/Resources/clipboard_invoice.png new file mode 100644 index 0000000..8e0f6b5 Binary files /dev/null and b/OpenDBDiff/Resources/clipboard_invoice.png differ diff --git a/OpenDBDiff/Resources/compare.png b/OpenDBDiff/Resources/compare.png new file mode 100644 index 0000000..82b8088 Binary files /dev/null and b/OpenDBDiff/Resources/compare.png differ diff --git a/OpenDBDiff/Resources/database_refresh.png b/OpenDBDiff/Resources/database_refresh.png new file mode 100644 index 0000000..bb0751e Binary files /dev/null and b/OpenDBDiff/Resources/database_refresh.png differ diff --git a/OpenDBDiff/Resources/database_yellow.png b/OpenDBDiff/Resources/database_yellow.png new file mode 100644 index 0000000..45858a1 Binary files /dev/null and b/OpenDBDiff/Resources/database_yellow.png differ diff --git a/OpenDBDiff/Resources/diskette.png b/OpenDBDiff/Resources/diskette.png new file mode 100644 index 0000000..d0d400e Binary files /dev/null and b/OpenDBDiff/Resources/diskette.png differ diff --git a/OpenDBDiff/Resources/folder.png b/OpenDBDiff/Resources/folder.png new file mode 100644 index 0000000..f1ed9ab Binary files /dev/null and b/OpenDBDiff/Resources/folder.png differ diff --git a/OpenDBDiff/Resources/new_window.png b/OpenDBDiff/Resources/new_window.png new file mode 100644 index 0000000..8da3ac4 Binary files /dev/null and b/OpenDBDiff/Resources/new_window.png differ diff --git a/OpenDBDiff/Resources/refresh_all.png b/OpenDBDiff/Resources/refresh_all.png new file mode 100644 index 0000000..0f4d261 Binary files /dev/null and b/OpenDBDiff/Resources/refresh_all.png differ diff --git a/OpenDBDiff/Resources/save_as.png b/OpenDBDiff/Resources/save_as.png new file mode 100644 index 0000000..915e280 Binary files /dev/null and b/OpenDBDiff/Resources/save_as.png differ diff --git a/OpenDBDiff/Resources/setting_tools.png b/OpenDBDiff/Resources/setting_tools.png new file mode 100644 index 0000000..2a1e727 Binary files /dev/null and b/OpenDBDiff/Resources/setting_tools.png differ diff --git a/OpenDBDiff/Resources/table_analysis.png b/OpenDBDiff/Resources/table_analysis.png new file mode 100644 index 0000000..af1086c Binary files /dev/null and b/OpenDBDiff/Resources/table_analysis.png differ diff --git a/OpenDBDiff/Resources/table_edit.png b/OpenDBDiff/Resources/table_edit.png new file mode 100644 index 0000000..7a34105 Binary files /dev/null and b/OpenDBDiff/Resources/table_edit.png differ diff --git a/OpenDBDiff/Settings/Project.cs b/OpenDBDiff/Settings/Project.cs new file mode 100644 index 0000000..40eaf44 --- /dev/null +++ b/OpenDBDiff/Settings/Project.cs @@ -0,0 +1,117 @@ +using LiteDB; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Windows.Forms; + +namespace OpenDBDiff.Settings +{ + public class Project + { + private const string settingsFile = "settings.liteDb"; + private static bool showErrors; + + public enum ProjectType + { + SQLServer = 1 + } + + public string ConnectionStringDestination { get; set; } + + public string ConnectionStringSource { get; set; } + + public Guid Id { get; set; } + + public bool IsLastConfiguration { get; set; } + [BsonIgnore] public IOption Options { get; set; } + + public string ProjectName { get; set; } + + public DateTime SavedDateTime { get; private set; } + + public ProjectType Type { get; set; } + + private static string SettingsFilePath + { + get + { + var userLocalAppDataDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), nameof(OpenDBDiff)); + if (!Directory.Exists(userLocalAppDataDirectory)) Directory.CreateDirectory(userLocalAppDataDirectory); + + return Path.Combine(userLocalAppDataDirectory, settingsFile); + } + } + + public static int Delete(Guid id) + { + using (var db = GetDatabase()) + { + var projects = db.GetCollection("projects"); + return projects.DeleteMany(p => p.Id == id); + } + } + + public static IEnumerable GetAll() + { + using (var db = GetDatabase()) + { + return db.GetCollection("projects").FindAll().ToArray(); + } + } + + public static Project GetLastConfiguration() + { + using (var db = GetDatabase()) + { + var projects = db.GetCollection("projects"); + return projects.Query() + .Where(p => p.IsLastConfiguration) + .OrderBy(p => p.ProjectName) + .FirstOrDefault(); + } + } + + public static void SaveLastConfiguration(String connectionStringSource, String connectionStringDestination) + { + var last = GetLastConfiguration() ?? new Project + { + Id = Guid.NewGuid(), + ProjectName = "LastConfiguration", + Type = ProjectType.SQLServer, + IsLastConfiguration = true + }; + last.ConnectionStringSource = connectionStringSource; + last.ConnectionStringDestination = connectionStringDestination; + Upsert(last); + } + + public static bool Upsert(Project item) + { + try + { + using (var db = GetDatabase()) + { + var projects = db.GetCollection("projects"); + item.SavedDateTime = DateTime.Now; + return projects.Upsert(item); + } + } + catch (Exception ex) + { + if (showErrors) + showErrors = MessageBox.Show($"{ex.Message}\n\nDo you want to see further errors?\n\n{ex.ToString()}", "Project error", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.Yes; + + return false; + } + } + + protected virtual string GetSerializedOptions() + { + return Options.Serialize(); + } + + private static LiteDatabase GetDatabase() => new LiteDatabase(SettingsFilePath); + } +} diff --git a/OpenDBDiff/UI/DataCompareForm.Designer.cs b/OpenDBDiff/UI/DataCompareForm.Designer.cs new file mode 100644 index 0000000..3aa4fea --- /dev/null +++ b/OpenDBDiff/UI/DataCompareForm.Designer.cs @@ -0,0 +1,353 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + partial class DataCompareForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DataCompareForm)); + this.pnlControl = new System.Windows.Forms.Panel(); + this.button1 = new System.Windows.Forms.Button(); + this.btnCommitChanges = new System.Windows.Forms.Button(); + this.lblAdded = new System.Windows.Forms.Label(); + this.lblModified = new System.Windows.Forms.Label(); + this.pnlAdded = new System.Windows.Forms.Panel(); + this.pnlModified = new System.Windows.Forms.Panel(); + this.btnRowToRow = new System.Windows.Forms.Button(); + this.btnMerge = new System.Windows.Forms.Button(); + this.btnUpdateRow = new System.Windows.Forms.Button(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.pnlSource = new System.Windows.Forms.Panel(); + this.lblSrc = new System.Windows.Forms.Label(); + this.srcDgv = new System.Windows.Forms.DataGridView(); + this.pnlDestination = new System.Windows.Forms.Panel(); + this.lblDestination = new System.Windows.Forms.Label(); + this.destDgv = new System.Windows.Forms.DataGridView(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.GrpScript = new System.Windows.Forms.GroupBox(); + this.label1 = new System.Windows.Forms.Label(); + this.panel1 = new System.Windows.Forms.Panel(); + this.pnlControl.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.pnlSource.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.srcDgv)).BeginInit(); + this.pnlDestination.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.destDgv)).BeginInit(); + this.GrpScript.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // pnlControl + // + this.pnlControl.BackColor = System.Drawing.Color.White; + this.pnlControl.Controls.Add(this.btnCommitChanges); + this.pnlControl.Controls.Add(this.lblAdded); + this.pnlControl.Controls.Add(this.lblModified); + this.pnlControl.Controls.Add(this.pnlAdded); + this.pnlControl.Controls.Add(this.pnlModified); + this.pnlControl.Controls.Add(this.btnRowToRow); + this.pnlControl.Controls.Add(this.btnMerge); + this.pnlControl.Controls.Add(this.btnUpdateRow); + this.pnlControl.Dock = System.Windows.Forms.DockStyle.Bottom; + this.pnlControl.Location = new System.Drawing.Point(0, 590); + this.pnlControl.Name = "pnlControl"; + this.pnlControl.Size = new System.Drawing.Size(1352, 48); + this.pnlControl.TabIndex = 2; + // + // button1 + // + this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.button1.BackColor = System.Drawing.Color.LightGray; + this.button1.Location = new System.Drawing.Point(10, 27); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(110, 30); + this.button1.TabIndex = 8; + this.button1.Text = "Script new Records"; + this.button1.UseVisualStyleBackColor = false; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // btnCommitChanges + // + this.btnCommitChanges.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCommitChanges.BackColor = System.Drawing.Color.LightGray; + this.btnCommitChanges.Enabled = false; + this.btnCommitChanges.Location = new System.Drawing.Point(840, 4); + this.btnCommitChanges.Name = "btnCommitChanges"; + this.btnCommitChanges.Size = new System.Drawing.Size(66, 30); + this.btnCommitChanges.TabIndex = 7; + this.btnCommitChanges.Text = "Commit"; + this.btnCommitChanges.UseVisualStyleBackColor = false; + this.btnCommitChanges.Click += new System.EventHandler(this.btnCommitChanges_Click); + // + // lblAdded + // + this.lblAdded.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.lblAdded.Font = new System.Drawing.Font("Verdana", 9F); + this.lblAdded.Location = new System.Drawing.Point(390, 14); + this.lblAdded.Name = "lblAdded"; + this.lblAdded.Size = new System.Drawing.Size(100, 20); + this.lblAdded.TabIndex = 0; + this.lblAdded.Text = "Added"; + // + // lblModified + // + this.lblModified.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.lblModified.Font = new System.Drawing.Font("Verdana", 9F); + this.lblModified.Location = new System.Drawing.Point(521, 14); + this.lblModified.Name = "lblModified"; + this.lblModified.Size = new System.Drawing.Size(100, 20); + this.lblModified.TabIndex = 1; + this.lblModified.Text = "Modified"; + // + // pnlAdded + // + this.pnlAdded.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.pnlAdded.BackColor = System.Drawing.Color.Green; + this.pnlAdded.Location = new System.Drawing.Point(354, 14); + this.pnlAdded.Name = "pnlAdded"; + this.pnlAdded.Size = new System.Drawing.Size(30, 20); + this.pnlAdded.TabIndex = 2; + // + // pnlModified + // + this.pnlModified.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.pnlModified.BackColor = System.Drawing.Color.Blue; + this.pnlModified.Location = new System.Drawing.Point(485, 14); + this.pnlModified.Name = "pnlModified"; + this.pnlModified.Size = new System.Drawing.Size(30, 20); + this.pnlModified.TabIndex = 3; + // + // btnRowToRow + // + this.btnRowToRow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnRowToRow.BackColor = System.Drawing.Color.LightGray; + this.btnRowToRow.Location = new System.Drawing.Point(10, 6); + this.btnRowToRow.Name = "btnRowToRow"; + this.btnRowToRow.Size = new System.Drawing.Size(120, 30); + this.btnRowToRow.TabIndex = 4; + this.btnRowToRow.Text = "Update row --> row"; + this.btnRowToRow.UseVisualStyleBackColor = false; + this.btnRowToRow.Click += new System.EventHandler(this.btnRowToRow_Click); + // + // btnMerge + // + this.btnMerge.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnMerge.BackColor = System.Drawing.Color.LightGray; + this.btnMerge.Location = new System.Drawing.Point(136, 6); + this.btnMerge.Name = "btnMerge"; + this.btnMerge.Size = new System.Drawing.Size(100, 30); + this.btnMerge.TabIndex = 5; + this.btnMerge.Text = "Merge all -->"; + this.btnMerge.UseVisualStyleBackColor = false; + this.btnMerge.Click += new System.EventHandler(this.btnMerge_Click); + // + // btnUpdateRow + // + this.btnUpdateRow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.btnUpdateRow.BackColor = System.Drawing.Color.LightGray; + this.btnUpdateRow.Location = new System.Drawing.Point(242, 6); + this.btnUpdateRow.Name = "btnUpdateRow"; + this.btnUpdateRow.Size = new System.Drawing.Size(100, 30); + this.btnUpdateRow.TabIndex = 6; + this.btnUpdateRow.Text = "Update row -->"; + this.btnUpdateRow.UseVisualStyleBackColor = false; + this.btnUpdateRow.Click += new System.EventHandler(this.btnUpdateRow_Click); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Left; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.pnlSource); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.pnlDestination); + this.splitContainer1.Size = new System.Drawing.Size(775, 590); + this.splitContainer1.SplitterDistance = 347; + this.splitContainer1.TabIndex = 3; + // + // pnlSource + // + this.pnlSource.Controls.Add(this.lblSrc); + this.pnlSource.Controls.Add(this.srcDgv); + this.pnlSource.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlSource.Location = new System.Drawing.Point(0, 0); + this.pnlSource.Name = "pnlSource"; + this.pnlSource.Size = new System.Drawing.Size(347, 590); + this.pnlSource.TabIndex = 6; + // + // lblSrc + // + this.lblSrc.Dock = System.Windows.Forms.DockStyle.Top; + this.lblSrc.Font = new System.Drawing.Font("Verdana", 14F, System.Drawing.FontStyle.Bold); + this.lblSrc.Location = new System.Drawing.Point(0, 0); + this.lblSrc.Name = "lblSrc"; + this.lblSrc.Size = new System.Drawing.Size(347, 23); + this.lblSrc.TabIndex = 0; + this.lblSrc.Text = "Source"; + // + // srcDgv + // + this.srcDgv.Dock = System.Windows.Forms.DockStyle.Fill; + this.srcDgv.Location = new System.Drawing.Point(0, 0); + this.srcDgv.Name = "srcDgv"; + this.srcDgv.Size = new System.Drawing.Size(347, 590); + this.srcDgv.TabIndex = 3; + // + // pnlDestination + // + this.pnlDestination.Controls.Add(this.lblDestination); + this.pnlDestination.Controls.Add(this.destDgv); + this.pnlDestination.Dock = System.Windows.Forms.DockStyle.Fill; + this.pnlDestination.Location = new System.Drawing.Point(0, 0); + this.pnlDestination.Name = "pnlDestination"; + this.pnlDestination.Size = new System.Drawing.Size(424, 590); + this.pnlDestination.TabIndex = 6; + // + // lblDestination + // + this.lblDestination.Dock = System.Windows.Forms.DockStyle.Top; + this.lblDestination.Font = new System.Drawing.Font("Verdana", 14F, System.Drawing.FontStyle.Bold); + this.lblDestination.Location = new System.Drawing.Point(0, 0); + this.lblDestination.Name = "lblDestination"; + this.lblDestination.Size = new System.Drawing.Size(424, 23); + this.lblDestination.TabIndex = 0; + this.lblDestination.Text = "Destination"; + // + // destDgv + // + this.destDgv.Dock = System.Windows.Forms.DockStyle.Fill; + this.destDgv.Location = new System.Drawing.Point(0, 0); + this.destDgv.Name = "destDgv"; + this.destDgv.Size = new System.Drawing.Size(424, 590); + this.destDgv.TabIndex = 3; + // + // textBox1 + // + this.textBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBox1.Location = new System.Drawing.Point(135, 16); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(439, 571); + this.textBox1.TabIndex = 4; + // + // GrpScript + // + this.GrpScript.Controls.Add(this.textBox1); + this.GrpScript.Controls.Add(this.label1); + this.GrpScript.Controls.Add(this.panel1); + this.GrpScript.Dock = System.Windows.Forms.DockStyle.Fill; + this.GrpScript.Location = new System.Drawing.Point(775, 0); + this.GrpScript.Name = "GrpScript"; + this.GrpScript.Size = new System.Drawing.Size(577, 590); + this.GrpScript.TabIndex = 5; + this.GrpScript.TabStop = false; + // + // label1 + // + this.label1.Font = new System.Drawing.Font("Verdana", 14F, System.Drawing.FontStyle.Bold); + this.label1.Location = new System.Drawing.Point(1, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(424, 23); + this.label1.TabIndex = 5; + this.label1.Text = "Script"; + // + // panel1 + // + this.panel1.Controls.Add(this.button1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Left; + this.panel1.Location = new System.Drawing.Point(3, 16); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(132, 571); + this.panel1.TabIndex = 9; + // + // DataCompareForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1352, 638); + this.Controls.Add(this.GrpScript); + this.Controls.Add(this.splitContainer1); + this.Controls.Add(this.pnlControl); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MinimumSize = new System.Drawing.Size(478, 250); + this.Name = "DataCompareForm"; + this.Text = "DataCompare"; + this.Load += new System.EventHandler(this.DataCompareForm_Load); + this.pnlControl.ResumeLayout(false); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.pnlSource.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.srcDgv)).EndInit(); + this.pnlDestination.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.destDgv)).EndInit(); + this.GrpScript.ResumeLayout(false); + this.GrpScript.PerformLayout(); + this.panel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private Button btnRowToRow; + private Button btnMerge; + private Button btnUpdateRow; + private Button btnCommitChanges; + private Label lblAdded; + private Label lblModified; + + private Panel pnlControl; + private Panel pnlAdded; + private Panel pnlModified; + private SplitContainer splitContainer1; + private Panel pnlSource; + private Label lblSrc; + private DataGridView srcDgv; + private Panel pnlDestination; + private Label lblDestination; + private DataGridView destDgv; + private Button button1; + private TextBox textBox1; + private GroupBox GrpScript; + private Label label1; + private Panel panel1; + } +} diff --git a/OpenDBDiff/UI/DataCompareForm.cs b/OpenDBDiff/UI/DataCompareForm.cs new file mode 100644 index 0000000..711a778 --- /dev/null +++ b/OpenDBDiff/UI/DataCompareForm.cs @@ -0,0 +1,253 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Data; +using System.Drawing; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + public partial class DataCompareForm : Form + { + public DataCompareForm(ISchemaBase Selected, string SrcConnectionString, string DestConnectionString) + { + InitializeComponent(); + this.selected = Selected; + this.srcConnectionString = SrcConnectionString; + this.destConnectionString = DestConnectionString; + + doCompare(); + } + + private void doCompare() + { + DataTable srcTable = Updater.getData(selected, srcConnectionString); + DataTable destTable = Updater.getData(selected, destConnectionString); + + srcDgv.MultiSelect = false; + srcDgv.ReadOnly = true; + srcDgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + srcDgv.RowHeadersVisible = false; + srcDgv.DataSource = srcTable; + srcDgv.Rows[0].Cells[0].Style.ForeColor = Color.Blue; + + destDgv.MultiSelect = false; + destDgv.ReadOnly = true; + destDgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + destDgv.RowHeadersVisible = false; + destDgv.DataSource = destTable; + destDgv.CellFormatting += new DataGridViewCellFormattingEventHandler(destDgv_CellFormatting); + } + + private void destDgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) + { + DataTable table = (DataTable)destDgv.DataSource; + if (e.RowIndex < table.Rows.Count) + { + if (table.Rows[e.RowIndex].RowState == DataRowState.Added) + { + e.CellStyle.ForeColor = Color.Green; + } + else if (table.Rows[e.RowIndex].RowState == DataRowState.Modified) + { + e.CellStyle.ForeColor = Color.Blue; + } + } + } + + private void btnCommitChanges_Click(object sender, EventArgs e) + { + DataTable destination = (DataTable)destDgv.DataSource; + DataTable edits = destination.GetChanges(); + if (Updater.CommitTable(edits, selected.FullName, destConnectionString)) + { + destination.AcceptChanges(); + doCompare(); + btnCommitChanges.Enabled = false; + } + } + + private void btnUpdateRow_Click(object sender, EventArgs e) + { + DataTable source = (DataTable)srcDgv.DataSource; + DataTable destination = (DataTable)destDgv.DataSource; + + object[] sourceItems = source.Rows[srcDgv.CurrentRow.Index].ItemArray; + + for (int i = 0; i < destination.Columns.Count; i++) + { + if (destination.Columns[i].Unique) + { + if (destination.Rows.Find(sourceItems[i]) == null && destination.Columns[i].AutoIncrement) + { + sourceItems[i] = null; + } + } + } + + destination.BeginLoadData(); + destination.LoadDataRow(sourceItems, false); + destination.EndLoadData(); + btnCommitChanges.Enabled = true; + } + + private void btnMerge_Click(object sender, EventArgs e) + { + DataTable source = (DataTable)srcDgv.DataSource; + DataTable destination = (DataTable)destDgv.DataSource; + + destination.Merge(source, true); + foreach (DataRow dr in destination.Rows) + { + if (dr.RowState == DataRowState.Unchanged) + { + dr.SetAdded(); + } + } + btnCommitChanges.Enabled = true; + } + + private void btnRowToRow_Click(object sender, EventArgs e) + { + DataTable source = (DataTable)srcDgv.DataSource; + DataTable destination = (DataTable)destDgv.DataSource; + + DataRow sourceRow = source.Rows[srcDgv.CurrentRow.Index]; + DataRow destinationRow = destination.Rows[destDgv.CurrentRow.Index]; + + for (int i = 0; i < destination.Columns.Count; i++) + { + if (!destination.Columns[i].Unique) + { + destinationRow[i] = sourceRow[i]; + } + } + btnCommitChanges.Enabled = true; + } + private ISchemaBase selected; + private string srcConnectionString; + private string destConnectionString; + + private void DataCompareForm_Load(object sender, EventArgs e) + { + + } + + private void button1_Click(object sender, EventArgs e) + { + DataTable srcTable = Updater.getData(selected, srcConnectionString); + DataTable destTable = Updater.getData(selected, destConnectionString); + bool found = false; + textBox1.Text = ""; + bool AutoInc = false; + + foreach (DataColumn c in srcTable.Columns) + { + if (c.AutoIncrement == true) + AutoInc = true; + } + if (AutoInc == true) + { + textBox1.AppendText("SET IDENTITY_INSERT [dbo].[" + srcTable.TableName + "] ON"); + textBox1.AppendText(Environment.NewLine); + textBox1.AppendText("Go"); + textBox1.AppendText(Environment.NewLine); + } + + foreach (DataRow r in srcTable.Rows) + { + + found = false; + foreach (DataRow rr in destTable.Rows) + { + string s1 =""; + string s2 =""; + s1 = r.ItemArray[0].ToString(); + s2 = rr[0].ToString(); + + if (s1 == s2) + { + found = true; + } + } + if (found == false) + { + + + string s; + s = ""; + + + s = "insert [dbo].[" + srcTable.TableName + "] ("; + foreach (DataColumn c in srcTable.Columns) + { + s = s + "["+ c.ColumnName + "], "; + } + s = s + ") values ("; + + + foreach (DataColumn c in srcTable.Columns) + { + s = s + ""; + + if (r[c.ColumnName].ToString() == "") + { + s = s + "N'', "; + } + else + { + if (c.DataType.Name == "Int32") + s = s + r[c.ColumnName].ToString() + ", "; + if (c.DataType.Name == "Int64") + s = s + r[c.ColumnName].ToString() + ", "; + if (c.DataType.Name == "String") + { + string ts; + ts = r[c.ColumnName].ToString(); + ts = ts.Replace("'", "''"); + s = s + "N'" + ts + "', "; + } + + + + if (c.DataType.Name == "Boolean") + { + if (r[c.ColumnName].ToString() == "True") + { + s = s + "1, "; + } + else + { + s = s + "0, "; + } + if (r[c.ColumnName].ToString() == "False") ; + } + + if (c.DataType.Name == "DateTime") + { + DateTime d = (DateTime)r[c.ColumnName]; + s = s + "cast(N'" + d.ToString("s") + "' as Datetime), "; + + } + } + } + + s = s + ") "; + s = s.Replace(",)", ")"); + s = s.Replace(", )", ")"); + textBox1.AppendText(s); + textBox1.AppendText(Environment.NewLine); + textBox1.AppendText("Go"); + textBox1.AppendText(Environment.NewLine); + + } + } + if (AutoInc == true) + { + textBox1.AppendText("SET IDENTITY_INSERT [dbo].[" + srcTable.TableName + "] OFF"); + textBox1.AppendText(Environment.NewLine); + textBox1.AppendText("Go"); + textBox1.AppendText(Environment.NewLine); + } + } + } +} diff --git a/OpenDBDiff/UI/DataCompareForm.resx b/OpenDBDiff/UI/DataCompareForm.resx new file mode 100644 index 0000000..e1fd45f --- /dev/null +++ b/OpenDBDiff/UI/DataCompareForm.resx @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/UI/DatabaseProgressControl.Designer.cs b/OpenDBDiff/UI/DatabaseProgressControl.Designer.cs new file mode 100644 index 0000000..3394788 --- /dev/null +++ b/OpenDBDiff/UI/DatabaseProgressControl.Designer.cs @@ -0,0 +1,104 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + partial class DatabaseProgressControl + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.lblDatabase = new System.Windows.Forms.Label(); + this.lblMessage = new System.Windows.Forms.Label(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // pictureBox1 + // + this.pictureBox1.BackColor = System.Drawing.Color.Transparent; + this.pictureBox1.Image = global::OpenDBDiff.Properties.Resources.database_yellow; + this.pictureBox1.Location = new System.Drawing.Point(3, 3); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(15, 18); + this.pictureBox1.TabIndex = 33; + this.pictureBox1.TabStop = false; + // + // lblDatabase + // + this.lblDatabase.AutoSize = true; + this.lblDatabase.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblDatabase.Location = new System.Drawing.Point(22, 6); + this.lblDatabase.Name = "lblDatabase"; + this.lblDatabase.Size = new System.Drawing.Size(72, 13); + this.lblDatabase.TabIndex = 34; + this.lblDatabase.Text = "Database1:"; + // + // lblMessage + // + this.lblMessage.AutoSize = true; + this.lblMessage.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(192))))); + this.lblMessage.Location = new System.Drawing.Point(22, 23); + this.lblMessage.Name = "lblMessage"; + this.lblMessage.Size = new System.Drawing.Size(0, 13); + this.lblMessage.TabIndex = 35; + // + // progressBar1 + // + this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar1.Location = new System.Drawing.Point(25, 40); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(301, 16); + this.progressBar1.TabIndex = 36; + this.progressBar1.Value = 50; + // + // DatabaseProgressControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.WhiteSmoke; + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.lblMessage); + this.Controls.Add(this.lblDatabase); + this.Controls.Add(this.pictureBox1); + this.Name = "DatabaseProgressControl"; + this.Size = new System.Drawing.Size(329, 59); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private PictureBox pictureBox1; + private Label lblDatabase; + private Label lblMessage; + private ProgressBar progressBar1; + } +} diff --git a/OpenDBDiff/UI/DatabaseProgressControl.cs b/OpenDBDiff/UI/DatabaseProgressControl.cs new file mode 100644 index 0000000..ed12bb4 --- /dev/null +++ b/OpenDBDiff/UI/DatabaseProgressControl.cs @@ -0,0 +1,47 @@ +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + public partial class DatabaseProgressControl : UserControl + { + public DatabaseProgressControl() + { + InitializeComponent(); + } + + public string DatabaseName + { + get { return lblDatabase.Text; } + set { lblDatabase.Text = value; } + } + + public string Message + { + get + { + return lblMessage.Text; + } + set + { + lblMessage.Text = value; + lblMessage.Refresh(); + } + } + + public int Maximum + { + get { return progressBar1.Maximum; } + set { progressBar1.Maximum = value; } + } + + public int Value + { + get { return progressBar1.Value; } + set + { + progressBar1.Value = value; + progressBar1.Refresh(); + } + } + } +} diff --git a/OpenDBDiff/UI/DatabaseProgressControl.resx b/OpenDBDiff/UI/DatabaseProgressControl.resx new file mode 100644 index 0000000..19dc0dd --- /dev/null +++ b/OpenDBDiff/UI/DatabaseProgressControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OpenDBDiff/UI/ErrorForm.Designer.cs b/OpenDBDiff/UI/ErrorForm.Designer.cs new file mode 100644 index 0000000..14c259f --- /dev/null +++ b/OpenDBDiff/UI/ErrorForm.Designer.cs @@ -0,0 +1,154 @@ +namespace OpenDBDiff.UI +{ + partial class ErrorForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ErrorForm)); + this.ErrorPanel = new System.Windows.Forms.Panel(); + this.FindIssueButton = new System.Windows.Forms.Button(); + this.CloseButton = new System.Windows.Forms.Button(); + this.CopyButton = new System.Windows.Forms.Button(); + this.ErrorLabel = new System.Windows.Forms.Label(); + this.ErrorInformationTextBox = new System.Windows.Forms.TextBox(); + this.ReportIssueButton = new System.Windows.Forms.Button(); + this.ErrorPanel.SuspendLayout(); + this.SuspendLayout(); + // + // ErrorPanel + // + this.ErrorPanel.Controls.Add(this.ReportIssueButton); + this.ErrorPanel.Controls.Add(this.FindIssueButton); + this.ErrorPanel.Controls.Add(this.CloseButton); + this.ErrorPanel.Controls.Add(this.CopyButton); + this.ErrorPanel.Dock = System.Windows.Forms.DockStyle.Bottom; + this.ErrorPanel.Location = new System.Drawing.Point(0, 299); + this.ErrorPanel.Name = "panel1"; + this.ErrorPanel.Size = new System.Drawing.Size(756, 30); + this.ErrorPanel.TabIndex = 0; + // + // FindIssueButton + // + this.FindIssueButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.FindIssueButton.Location = new System.Drawing.Point(84, 4); + this.FindIssueButton.Name = "btnFindIssue"; + this.FindIssueButton.Size = new System.Drawing.Size(131, 23); + this.FindIssueButton.TabIndex = 2; + this.FindIssueButton.Text = "Search for error on web"; + this.FindIssueButton.UseVisualStyleBackColor = true; + this.FindIssueButton.Click += new System.EventHandler(this.btnFindIssue_Click); + // + // CloseButton + // + this.CloseButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.CloseButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.CloseButton.Location = new System.Drawing.Point(678, 4); + this.CloseButton.Name = "btnClose"; + this.CloseButton.Size = new System.Drawing.Size(75, 23); + this.CloseButton.TabIndex = 1; + this.CloseButton.Text = "Close"; + this.CloseButton.UseVisualStyleBackColor = true; + this.CloseButton.Click += new System.EventHandler(this.btnClose_Click); + // + // CopyButton + // + this.CopyButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.CopyButton.Location = new System.Drawing.Point(3, 4); + this.CopyButton.Name = "btnCopy"; + this.CopyButton.Size = new System.Drawing.Size(75, 23); + this.CopyButton.TabIndex = 0; + this.CopyButton.Text = "Copy error"; + this.CopyButton.UseVisualStyleBackColor = true; + this.CopyButton.Click += new System.EventHandler(this.btnCopy_Click); + // + // ErrorLabel + // + this.ErrorLabel.AutoSize = true; + this.ErrorLabel.Location = new System.Drawing.Point(13, 13); + this.ErrorLabel.Name = "lblError"; + this.ErrorLabel.Size = new System.Drawing.Size(254, 13); + this.ErrorLabel.TabIndex = 1; + this.ErrorLabel.Text = "An unexpected error has occured during processing:"; + // + // ErrorInformationTextBox + // + this.ErrorInformationTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ErrorInformationTextBox.Font = new System.Drawing.Font("Consolas", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.ErrorInformationTextBox.Location = new System.Drawing.Point(12, 29); + this.ErrorInformationTextBox.Multiline = true; + this.ErrorInformationTextBox.Name = "txtErrorInformation"; + this.ErrorInformationTextBox.ReadOnly = true; + this.ErrorInformationTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.ErrorInformationTextBox.Size = new System.Drawing.Size(732, 264); + this.ErrorInformationTextBox.TabIndex = 2; + // + // ReportIssueButton + // + this.ReportIssueButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.ReportIssueButton.Location = new System.Drawing.Point(221, 4); + this.ReportIssueButton.Name = "ReportIssueButton"; + this.ReportIssueButton.Size = new System.Drawing.Size(105, 23); + this.ReportIssueButton.TabIndex = 3; + this.ReportIssueButton.Text = "Report issue"; + this.ReportIssueButton.UseVisualStyleBackColor = true; + this.ReportIssueButton.Click += new System.EventHandler(this.ReportIssueButton_Click); + // + // ErrorForm + // + this.AcceptButton = this.CopyButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.CloseButton; + this.ClientSize = new System.Drawing.Size(756, 329); + this.Controls.Add(this.ErrorInformationTextBox); + this.Controls.Add(this.ErrorLabel); + this.Controls.Add(this.ErrorPanel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "ErrorForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Error information"; + this.Load += new System.EventHandler(this.ErrorForm_Load); + this.ErrorPanel.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Panel ErrorPanel; + private System.Windows.Forms.Button FindIssueButton; + private System.Windows.Forms.Button CloseButton; + private System.Windows.Forms.Button CopyButton; + private System.Windows.Forms.Label ErrorLabel; + private System.Windows.Forms.TextBox ErrorInformationTextBox; + private System.Windows.Forms.Button ReportIssueButton; + } +} diff --git a/OpenDBDiff/UI/ErrorForm.cs b/OpenDBDiff/UI/ErrorForm.cs new file mode 100644 index 0000000..3455123 --- /dev/null +++ b/OpenDBDiff/UI/ErrorForm.cs @@ -0,0 +1,173 @@ +using OpenDBDiff.Front.Extensions; +using System; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + public partial class ErrorForm : Form + { + private static Regex ExtractBuildPathRegex = new Regex($@"\s+at OpenDBDiff.Front.{nameof(ErrorForm)}.{nameof(GetBuildPath)}\(\) in (.*\\)OpenDBDiff\\Front\\ErrorForm.cs", RegexOptions.Compiled); + private static Regex SystemExceptionsRegex = new Regex(@"\s+at System\.[^\r\n]+\r\n", RegexOptions.Compiled); + private string ErrorInformation; + private Exception Exception; + private string SearchTerm; + + public ErrorForm() + { + InitializeComponent(); + } + + public ErrorForm(Exception ex) : this() + { + Exception = ex; + LoadException(ex); + } + + public void LoadException(Exception ex) + { + var exceptions = ex.FlattenHierarchy(); + var exceptionMessages = exceptions.Select(e => e.Message).ToList(); + var distinctMessages = exceptionMessages + .Distinct() + .OrderByDescending(m => exceptionMessages.IndexOf(m)); + + var exceptionErrorMessage = new StringBuilder(); + exceptionErrorMessage.Append(this.Text); + + foreach (var message in distinctMessages.Skip(1)) + exceptionErrorMessage.Append($"\r\n{message}"); + + var mostInnerException = exceptions.Last(); + + string stackTrace = string.Empty; + if (mostInnerException.StackTrace != null) + { + stackTrace = mostInnerException + .StackTrace; + + var buildPath = GetBuildPath(); + if (!string.IsNullOrEmpty(buildPath)) + stackTrace = stackTrace.Replace(buildPath, string.Empty); + + stackTrace = SystemExceptionsRegex.Replace(stackTrace, string.Empty); + } + + exceptionErrorMessage.Append($"\r\n{mostInnerException.GetType().Name}: {mostInnerException.Message}\r\n{stackTrace}"); + + //var ignoreChunks = new System.Text.RegularExpressions.Regex(@": \[[^\)]*\)|\.\.\.\)|\'[^\']*\'|\([^\)]*\)|\" + '"' + @"[^\" + '"' + @"]*\" + '"' + @"|Source|Destination"); + + int queryMaxLength = 280; //Bug in Github for searching issues? Q max length is 280 + var queryString = new StringBuilder(); + string orOperator = " OR "; + foreach (var message in distinctMessages) + { + var roomLeft = queryMaxLength - queryString.Length; + if (roomLeft > (orOperator.Length + 2 + message.Length)) + { + if (queryString.Length > 0) + { + queryString.Append(orOperator); + } + queryString.Append("\""); + queryString.Append(message); + queryString.Append("\""); + } + } + string searchHash = GenerateHash(queryString.ToString()); + + exceptionErrorMessage.AppendFormat("\r\n\r\n{0}", searchHash); + + ErrorInformation = string.Join("\r\n", + "1. To report an error search first in the Github issues to see if it's already been reported.", + "2a. If there is no issue, click 'New issue' and paste the error details", + " into the body of the issue. To copy the error press \"Copy error\"", + " (At least email the details to opendbdiff@gmail.com)", + "", + "2b. If the issue exists, but your situation is different please leave a comment with the details.", + "", + "• If possible, please attach a SQL script creating the two databases with", + " the minimum necessary to reproduce the problem.", + "" + ).Trim() + "\r\n\r\n" + exceptionErrorMessage.ToString(); + SearchTerm = queryString.ToString(); + + this.ErrorInformationTextBox.Text = ErrorInformation; + } + + private static string GenerateHash(string queryString) + { + var searchableErrorBytes = Encoding.UTF8.GetBytes(queryString); + searchableErrorBytes = new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(searchableErrorBytes); + var searchHash = BitConverter.ToString(searchableErrorBytes).Replace("-", String.Empty); + return searchHash; + } + + private static string GetBuildPath() + { + try + { + throw new Exception("dummy"); + } + catch (Exception ex) + { + var match = ExtractBuildPathRegex.Match(ex.StackTrace); + if (match.Success) + return match.Groups[1].Value; + else + return string.Empty; + } + } + + private void btnClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void btnCopy_Click(object sender, EventArgs e) + { + try + { + Clipboard.SetText(ErrorInformation); + } + catch (Exception ex) + { + MessageBox.Show(this, "Error while trying to copy the error to the clipboard: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void btnFindIssue_Click(object sender, EventArgs e) + { + try + { + System.Diagnostics.Process.Start("https://github.com/OpenDBDiff/OpenDBDiff/issues?q=is%3Aissue+" + Uri.EscapeDataString(SearchTerm)); + } + catch (Exception ex) + { + MessageBox.Show(this, "Error while trying to search the error in the Github issues: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void ErrorForm_Load(object sender, EventArgs e) + { + this.ErrorInformationTextBox.Text = ErrorInformation; + } + + private void ReportIssueButton_Click(object sender, EventArgs e) + { + if (MessageBox.Show(this, "Have you searched Github to determine whether this error has already been reported?", "Searched Github", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes) + { + try + { + System.Diagnostics.Process.Start("https://github.com/OpenDBDiff/OpenDBDiff/issues/new"); + } + catch (Exception ex) + { + MessageBox.Show(this, "Error while trying to create a new Github issue: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + } +} diff --git a/OpenDBDiff/UI/ErrorForm.resx b/OpenDBDiff/UI/ErrorForm.resx new file mode 100644 index 0000000..e1fd45f --- /dev/null +++ b/OpenDBDiff/UI/ErrorForm.resx @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/UI/ListProjectsForm.Designer.cs b/OpenDBDiff/UI/ListProjectsForm.Designer.cs new file mode 100644 index 0000000..3e6010a --- /dev/null +++ b/OpenDBDiff/UI/ListProjectsForm.Designer.cs @@ -0,0 +1,182 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + sealed partial class ListProjectsForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem(new string[] { + "ListViewItem", + "ListViewSubItem1", + "ListViewSubItem2"}, 0); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ListProjectsForm)); + this.ProjectsListView = new System.Windows.Forms.ListView(); + this.ProjectNameColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.SourceConnectionStringColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.DestinationConnectionStringColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.IconsImageList = new System.Windows.Forms.ImageList(this.components); + this.ActionsContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); + this.OpenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.RenameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.DeleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.ActionsContextMenuStrip.SuspendLayout(); + this.statusStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // ProjectsListView + // + this.ProjectsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.ProjectNameColumnHeader, + this.SourceConnectionStringColumnHeader, + this.DestinationConnectionStringColumnHeader}); + this.ProjectsListView.Dock = System.Windows.Forms.DockStyle.Fill; + this.ProjectsListView.FullRowSelect = true; + this.ProjectsListView.GridLines = true; + this.ProjectsListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.ProjectsListView.Items.AddRange(new System.Windows.Forms.ListViewItem[] { + listViewItem1}); + this.ProjectsListView.LabelWrap = false; + this.ProjectsListView.Location = new System.Drawing.Point(0, 0); + this.ProjectsListView.MultiSelect = false; + this.ProjectsListView.Name = "ProjectsListView"; + this.ProjectsListView.Size = new System.Drawing.Size(860, 304); + this.ProjectsListView.SmallImageList = this.IconsImageList; + this.ProjectsListView.TabIndex = 5; + this.ProjectsListView.UseCompatibleStateImageBehavior = false; + this.ProjectsListView.View = System.Windows.Forms.View.Details; + this.ProjectsListView.AfterLabelEdit += new System.Windows.Forms.LabelEditEventHandler(this.ProjectsListView_AfterLabelEdit); + this.ProjectsListView.SelectedIndexChanged += new System.EventHandler(this.ProjectsListView_SelectedIndexChanged); + this.ProjectsListView.DoubleClick += new System.EventHandler(this.ProjectsListView_DoubleClick); + // + // ProjectNameColumnHeader + // + this.ProjectNameColumnHeader.Text = "Icon"; + this.ProjectNameColumnHeader.Width = 100; + // + // SourceConnectionStringColumnHeader + // + this.SourceConnectionStringColumnHeader.Text = "Connection"; + this.SourceConnectionStringColumnHeader.Width = 150; + // + // DestinationConnectionStringColumnHeader + // + this.DestinationConnectionStringColumnHeader.Width = 150; + // + // IconsImageList + // + this.IconsImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("IconsImageList.ImageStream"))); + this.IconsImageList.TransparentColor = System.Drawing.Color.Transparent; + this.IconsImageList.Images.SetKeyName(0, "database_yellow.png"); + // + // ActionsContextMenuStrip + // + this.ActionsContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.OpenToolStripMenuItem, + this.RenameToolStripMenuItem, + this.DeleteToolStripMenuItem}); + this.ActionsContextMenuStrip.Name = "ActionsContextMenuStrip"; + this.ActionsContextMenuStrip.Size = new System.Drawing.Size(118, 70); + // + // OpenToolStripMenuItem + // + this.OpenToolStripMenuItem.Name = "OpenToolStripMenuItem"; + this.OpenToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.OpenToolStripMenuItem.Text = "&Open"; + this.OpenToolStripMenuItem.Click += new System.EventHandler(this.mnuItemOpen_Click); + // + // RenameToolStripMenuItem + // + this.RenameToolStripMenuItem.Name = "RenameToolStripMenuItem"; + this.RenameToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.RenameToolStripMenuItem.Text = "&Rename"; + this.RenameToolStripMenuItem.Click += new System.EventHandler(this.mnuItemRename_Click); + // + // DeleteToolStripMenuItem + // + this.DeleteToolStripMenuItem.Name = "DeleteToolStripMenuItem"; + this.DeleteToolStripMenuItem.Size = new System.Drawing.Size(117, 22); + this.DeleteToolStripMenuItem.Text = "&Delete"; + this.DeleteToolStripMenuItem.Click += new System.EventHandler(this.mnuItemDelete_Click); + // + // statusStrip1 + // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1}); + this.statusStrip1.Location = new System.Drawing.Point(0, 282); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(860, 22); + this.statusStrip1.TabIndex = 6; + this.statusStrip1.Text = "statusStrip1"; + // + // toolStripStatusLabel1 + // + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(214, 17); + this.toolStripStatusLabel1.Text = "Right-click on project for more actions."; + // + // ListProjectsForm + // + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; + this.ClientSize = new System.Drawing.Size(860, 304); + this.ContextMenuStrip = this.ActionsContextMenuStrip; + this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.ProjectsListView); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.KeyPreview = true; + this.MinimizeBox = false; + this.Name = "ListProjectsForm"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "OpenDBDiff projects"; + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ListProjectsForm_KeyDown); + this.ActionsContextMenuStrip.ResumeLayout(false); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private ListView ProjectsListView; + private ColumnHeader ProjectNameColumnHeader; + private ColumnHeader SourceConnectionStringColumnHeader; + private ImageList IconsImageList; + private ContextMenuStrip ActionsContextMenuStrip; + private ToolStripMenuItem OpenToolStripMenuItem; + private ToolStripMenuItem RenameToolStripMenuItem; + private ToolStripMenuItem DeleteToolStripMenuItem; + private ColumnHeader DestinationConnectionStringColumnHeader; + private StatusStrip statusStrip1; + private ToolStripStatusLabel toolStripStatusLabel1; + } +} diff --git a/OpenDBDiff/UI/ListProjectsForm.cs b/OpenDBDiff/UI/ListProjectsForm.cs new file mode 100644 index 0000000..122d367 --- /dev/null +++ b/OpenDBDiff/UI/ListProjectsForm.cs @@ -0,0 +1,151 @@ +using OpenDBDiff.Settings; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + public delegate void ListProjectHandler(Project itemSelected); + + public sealed partial class ListProjectsForm : Form + { + public event ListProjectHandler OnSelect; + + public event ListProjectHandler OnDelete; + + public event ListProjectHandler OnRename; + + private IList Projects { get; } + + public ListProjectsForm(IEnumerable projects) + { + InitializeComponent(); + + Projects = projects.ToList(); + + ProjectsListView.Items.Clear(); + + if (Projects.Any()) + { + foreach (var p in Projects) + ProjectsListView.Items.Add(new ListViewItem(items: new string[] { p.ProjectName, p.ConnectionStringSource, p.ConnectionStringDestination }, imageIndex: 0)); + + ProjectsListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent); + } + else + { + ProjectsListView.Items.Add(new ListViewItem + { + Text = "There are no saved projects." + }); + } + + ProjectsListView.LabelEdit = true; + } + + private void OpenProject() + { + try + { + if (ProjectsListView.SelectedItems.Count != 0) + { + var item = new Project + { + Id = Projects[ProjectsListView.SelectedItems[0].Index].Id, + ConnectionStringDestination = Projects[ProjectsListView.SelectedItems[0].Index].ConnectionStringDestination, + ConnectionStringSource = Projects[ProjectsListView.SelectedItems[0].Index].ConnectionStringSource, + ProjectName = Projects[ProjectsListView.SelectedItems[0].Index].ProjectName, + Options = Projects[ProjectsListView.SelectedItems[0].Index].Options, + Type = Projects[ProjectsListView.SelectedItems[0].Index].Type, + }; + OnSelect?.Invoke(item); + } + } + catch (Exception ex) + { + MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void DeleteProject() + { + try + { + if (ProjectsListView.SelectedItems.Count != 0) + { + if (MessageBox.Show(this, + "Are you sure you want delete this project?", + "Confirm project deletion", MessageBoxButtons.YesNo, + MessageBoxIcon.Question) == DialogResult.Yes) + { + OnDelete?.Invoke(Projects[ProjectsListView.SelectedItems[0].Index]); + Projects.Remove(Projects[ProjectsListView.SelectedItems[0].Index]); + ProjectsListView.Items.Remove(ProjectsListView.SelectedItems[0]); + } + } + } + catch (Exception ex) + { + MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void mnuItemRename_Click(object sender, EventArgs e) + { + if (ProjectsListView.SelectedItems.Count != 0) + { + ProjectsListView.SelectedItems[0].BeginEdit(); + } + } + + private void ProjectsListView_AfterLabelEdit(object sender, LabelEditEventArgs e) + { + if (string.IsNullOrWhiteSpace(e.Label)) + { + e.CancelEdit = true; + return; + } + + if (ProjectsListView.SelectedItems.Count != 0) + { + Projects[ProjectsListView.SelectedItems[0].Index].ProjectName = e.Label.Trim(); + OnRename?.Invoke(Projects[ProjectsListView.SelectedItems[0].Index]); + } + } + + private void mnuItemOpen_Click(object sender, EventArgs e) + { + OpenProject(); + Dispose(); + } + + private void mnuItemDelete_Click(object sender, EventArgs e) + { + DeleteProject(); + } + + private void ProjectsListView_SelectedIndexChanged(object sender, EventArgs e) + { + OpenProject(); + } + + private void ProjectsListView_DoubleClick(object sender, EventArgs e) + { + Dispose(); + } + + private void ListProjectsForm_KeyDown(object sender, KeyEventArgs e) + { + if (e != null) + { + if (e.KeyCode == Keys.Escape) + Dispose(); + if (e.KeyCode == Keys.Enter) + Dispose(); + if (e.KeyCode == Keys.Delete) + DeleteProject(); + } + } + } +} diff --git a/OpenDBDiff/UI/ListProjectsForm.resx b/OpenDBDiff/UI/ListProjectsForm.resx new file mode 100644 index 0000000..06ac379 --- /dev/null +++ b/OpenDBDiff/UI/ListProjectsForm.resx @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAA2 + CAAAAk1TRnQBSQFMAwEBAAEkAQABJAEAARABAAEQAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA + AUADAAEQAwABAQEAAQgGAAEEGAABgAIAAYADAAKAAQABgAMAAYABAAGAAQACgAIAA8ABAAHAAdwBwAEA + AfABygGmAQABMwUAATMBAAEzAQABMwEAAjMCAAMWAQADHAEAAyIBAAMpAQADVQEAA00BAANCAQADOQEA + AYABfAH/AQACUAH/AQABkwEAAdYBAAH/AewBzAEAAcYB1gHvAQAB1gLnAQABkAGpAa0CAAH/ATMDAAFm + AwABmQMAAcwCAAEzAwACMwIAATMBZgIAATMBmQIAATMBzAIAATMB/wIAAWYDAAFmATMCAAJmAgABZgGZ + AgABZgHMAgABZgH/AgABmQMAAZkBMwIAAZkBZgIAApkCAAGZAcwCAAGZAf8CAAHMAwABzAEzAgABzAFm + AgABzAGZAgACzAIAAcwB/wIAAf8BZgIAAf8BmQIAAf8BzAEAATMB/wIAAf8BAAEzAQABMwEAAWYBAAEz + AQABmQEAATMBAAHMAQABMwEAAf8BAAH/ATMCAAMzAQACMwFmAQACMwGZAQACMwHMAQACMwH/AQABMwFm + AgABMwFmATMBAAEzAmYBAAEzAWYBmQEAATMBZgHMAQABMwFmAf8BAAEzAZkCAAEzAZkBMwEAATMBmQFm + AQABMwKZAQABMwGZAcwBAAEzAZkB/wEAATMBzAIAATMBzAEzAQABMwHMAWYBAAEzAcwBmQEAATMCzAEA + ATMBzAH/AQABMwH/ATMBAAEzAf8BZgEAATMB/wGZAQABMwH/AcwBAAEzAv8BAAFmAwABZgEAATMBAAFm + AQABZgEAAWYBAAGZAQABZgEAAcwBAAFmAQAB/wEAAWYBMwIAAWYCMwEAAWYBMwFmAQABZgEzAZkBAAFm + ATMBzAEAAWYBMwH/AQACZgIAAmYBMwEAA2YBAAJmAZkBAAJmAcwBAAFmAZkCAAFmAZkBMwEAAWYBmQFm + AQABZgKZAQABZgGZAcwBAAFmAZkB/wEAAWYBzAIAAWYBzAEzAQABZgHMAZkBAAFmAswBAAFmAcwB/wEA + AWYB/wIAAWYB/wEzAQABZgH/AZkBAAFmAf8BzAEAAcwBAAH/AQAB/wEAAcwBAAKZAgABmQEzAZkBAAGZ + AQABmQEAAZkBAAHMAQABmQMAAZkCMwEAAZkBAAFmAQABmQEzAcwBAAGZAQAB/wEAAZkBZgIAAZkBZgEz + AQABmQEzAWYBAAGZAWYBmQEAAZkBZgHMAQABmQEzAf8BAAKZATMBAAKZAWYBAAOZAQACmQHMAQACmQH/ + AQABmQHMAgABmQHMATMBAAFmAcwBZgEAAZkBzAGZAQABmQLMAQABmQHMAf8BAAGZAf8CAAGZAf8BMwEA + AZkBzAFmAQABmQH/AZkBAAGZAf8BzAEAAZkC/wEAAcwDAAGZAQABMwEAAcwBAAFmAQABzAEAAZkBAAHM + AQABzAEAAZkBMwIAAcwCMwEAAcwBMwFmAQABzAEzAZkBAAHMATMBzAEAAcwBMwH/AQABzAFmAgABzAFm + ATMBAAGZAmYBAAHMAWYBmQEAAcwBZgHMAQABmQFmAf8BAAHMAZkCAAHMAZkBMwEAAcwBmQFmAQABzAKZ + AQABzAGZAcwBAAHMAZkB/wEAAswCAALMATMBAALMAWYBAALMAZkBAAPMAQACzAH/AQABzAH/AgABzAH/ + ATMBAAGZAf8BZgEAAcwB/wGZAQABzAH/AcwBAAHMAv8BAAHMAQABMwEAAf8BAAFmAQAB/wEAAZkBAAHM + ATMCAAH/AjMBAAH/ATMBZgEAAf8BMwGZAQAB/wEzAcwBAAH/ATMB/wEAAf8BZgIAAf8BZgEzAQABzAJm + AQAB/wFmAZkBAAH/AWYBzAEAAcwBZgH/AQAB/wGZAgAB/wGZATMBAAH/AZkBZgEAAf8CmQEAAf8BmQHM + AQAB/wGZAf8BAAH/AcwCAAH/AcwBMwEAAf8BzAFmAQAB/wHMAZkBAAH/AswBAAH/AcwB/wEAAv8BMwEA + AcwB/wFmAQAC/wGZAQAC/wHMAQACZgH/AQABZgH/AWYBAAFmAv8BAAH/AmYBAAH/AWYB/wEAAv8BZgEA + ASEBAAGlAQADXwEAA3cBAAOGAQADlgEAA8sBAAOyAQAD1wEAA90BAAPjAQAD6gEAA/EBAAP4AQAB8AH7 + Af8BAAGkAqABAAOAAwAB/wIAAf8DAAL/AQAB/wMAAf8BAAH/AQAC/wIAA/8DAAH/AfQI8wH0Af8zAAH/ + AfEBmQhSAZkB8QH/MgABGgFSAnoBmgWgAnoBUgEaMgABUgR6AZoDoAGaA3oBUjIAAVIEegKaAaACmgN6 + AVIyAAFSBXoCoAGaBHoBUjIAAVIBegGgCMMBoAF6AVIyAAGZAcMBmgF6BnkBegGaAcMBmTIAAZkBUgFZ + AnoBmgOgAZoCegFSAZkyAAFSBHoBmgOgAZoDegFSMgABUgV6AqABmgR6AVIyAAFSAXoBmgjDAZoBegFS + MgABUgHDAqAGmgKgAcMBUjIAAVIMegFSMgABGwFSCnoBUgEbMwAB9AGZCFIBmQH0MgABQgFNAT4HAAE+ + AwABKAMAAUADAAEQAwABAQEAAQEFAAGAFwAD/wEAAcABAwYAAYABAQYAAYABAQYAAYABAQYAAYABAQYA + AYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYAAYABAQYA + AcABAwYACw== + + + + 149, 17 + + + 340, 17 + + + + + AAABAAUAEBAQAAEABACSAAAAVgAAACAgAAABACAAwQIAAOgAAABAQAAAAQAgAE8FAACpAwAAgIAAAAEA + IABcCgAA+AgAAAAAAAABACAASxoAAFQTAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EA + AABZSURBVDiNY9TW1magBLBA6f845BkZGBgYdphrYZX3OHmNkYki6xkYGCg2gJHSMKDYBSwMDAwMTs1O + WANpX+0+RigTZyCPBiKRKVHLbwdW+WubPEYDkYGBAQAQKxEnMldECwAAAABJRU5ErkJggolQTkcNChoK + AAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAAAohJREFUWIXtl79rE2Ecxj93vcTYa3o20BrKRaRWFAmI + OBh16yRUBJf7B1pwyywBJ0OgiyB0NNC1t3Qp1qlLuxSRLmdpBNHG61B/pU3O/PKS1yG5GiVCEgNZ8oWD + L7x8nvfhvXve9z1JCMEgSx7o7EMDgAIQjUYB7gL3gUkgAPi9caAGVIEK8A3YBDYsyzoVsheMrng9bW4A + SEIIotFoHLgF7AG7wDvgECg1BfzANDAL3ACuAe8ty0o2J2/L62mz1Bxvy+tpM+kZEEAM2Olw5cJAxrIs + rTmBAGJ62uyItxeMMJDR06bWukRbwAawDewDR0ABEIAKTAGXabyqeWC0RbMGbNkLRte8ZyAPTAAPmk8n + lf+r74n3UuDvEGqtkZa+Z94zoPYgoP6j74r3DDzuQeBZS98zrwDMPZ0r5T/l1w9fHyq5D7lg1amG6rW6 + hmAMkJAoyiPysW/Ul9MuaCfTN6crodlQzlO6t7NXujp2dn3+/IRyPagGz/mUkE+WNIkGL6Do1sVx3q3l + 9pziyavPx5U3J07O4vdH+Hw8Mh5bia90FKP4WjwMZICkx+87pdi+U+oqxkDyjxjG1+L/FUN6iPEwhsMY + KgCbTzaXInciWXVKXVQn1Rl/0K8pZ5SA7JN9EhJ1t+66FbdcdaqF4tfigXPkrGa3s8s8PBVbCkcfZcuF + g8VqITvzs/xdq7vFgKhVfAKBLPtdWRktK4GJgn8schAYv7h69PbFMvTpODYSdlveTOml5nhb3kzp/TmO + jYQtgJiZ0jvijYQdBjJmSu/vcWwk7OE+0DU/3Ae8FABcoXGtvg1conG9DgIS8AP4AnykkZSXwG7rtdxI + 2F3xZkrfPTUwyBr4n9HQwC8Xx0dm0EptCwAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAABAAAAA + QAgGAAAAqmlx3gAABRZJREFUeJztm1FoG3Ucxz9pO7suieu6Wuf8M1E7XGcnOJD1QRSzB4tKtQj3sAd9 + CPZB8F6sMAKDyiDDt5L64kNAURicD8HJMO6hoE/LkGJrGhS2Qdpz3WaXJmvXrFvT+HBZuEtybWyT/Dd7 + Xzi43v/X+/z67V3u/+3/6srn82xnNcluQLYcA2Q3IFuOAbIbkC3HANkNyFbLg53e3t5K4x7gFaAPeBno + BgTwRIXaNHANuAr8AcQK2/XSwng8XlVzul/ZMl+EtTK+Wa4HEyGTAa3AR8DHQI+pdg2YAf4G5oBbwH2M + q6gd2A88BRwA2kzfdxP4GvgSmIX1DdD9St34IqzNbmTAEPBVYWwGOAv8DEwCKduuy9UK9AJvAArGbxFg + DFDtDND9ii1fhLWq+QUTK/JFWFPNtWYDTgJngJ+AYSBRLbAKdQIngU+B8/F4/J0KTVv4IqzVjK/7FQtf + hLUiv8VUdwa4ALxVK7BJ8ximzgKjNjVngAsirNWcL8LaPDCs+5UyvvkpsAYcAT6odQMFvV44d85mfA04 + ovuVuvB1v1KRb74CFjA+RL4BPgO+x7giJoB7m+T2YNyH7wO+wrGMTW2Rr/sVC1+EtU3xdb+yId9sQLNp + v7ewfY7xGJsG/sK4hK8Dt4ElDDebMD512zHudQE8DxzGeGyVym7uYcvX/Urd+C0VCkq1r7Adr6K2Hqor + f9vPBB0DZDcgW2YDdkhgmiWFb/7C3aAG7DhS+GYDvmhQA7/YHJfCNxtwEuO5u1pH+Fng7UoD/bGEFH7p + /Tji7nL3dB7qPO/uct+tBbFtT1tu78G9E50vdA4AJ4A7drX9scTITHal5+LC4vlkdqUm/Osr93O/pZcm + YunFgf5Y4kR/LGHhWyZCvtM+SxxNJ9NR/aI+l7qc8qzeXRXA0xh/jPBi3EtNQB64izHFXACuuZpdyd1i + d0b0CW9Xb9erGHH0HDA2fmrcEkdLNDQ0daXIf9G7K/rukx1zR9vdHk9zc9X81Xw++edSNnPuRsr7663b + Fj5g4RcN8J32WeJoaDBUsziqRtRiHPWd9j0HlMXhwrgljk8vLjO9uFyLFsxx2MIvi8OhwVDN42hoMDQP + DKsRdcM4TIPjeFkcViNqXeKoGlGrisM0OI5XjMNqRLXE0dBgaFNxVI2om4rDNDCOVxWH1YgqNQ5Txzju + xOF6nPRRkmOA7AZky4nDpn0nDjeogYczDo+fGpcah5EUx8tWh499cqw7m8qOtnW0HXd3uXdulZhdyOaW + 55cn82v5kanvpn6EyqvDD/it3gPdj7n3j967M3d8ZTG5Zf6OXftyrR4x6XI1jyzeiJXxSydCQ7GxWDGO + tj/THhV9Yq6ju8PTsrOl6jiaz+WTGT2T0S/q3pvxm+vGUbMOD0QtcXw5NR1NXf1h7s4/E57c/aXq43hT + S7Jtz6FMx7MD3sf3v2bhJ871V47DVIij6WSadDJt6+5/kG0cNf3wFr4WFAljVvvmluFKQC/yDw9E14/D + SF4d1oKi5nwtKOaBYSWgP/yrw0pArwtfCeiPzuqwEtAtfC0oNsVXAvr/Y3VYCehOHK4X3wlDshuQLccA + 074ThxvUgBOHbY5v79VhLSgejjiM8bLxh8B7wNEaQC8DUeBb4BKs/7K0EtDrxteC4lLpYCUDzOrGeE39 + JeAgVcZRjFfWpzGm0b+XnrTa1+WVgL5lvhYUZXyzXM7/DW5zOQbIbkC2HANkNyBbjgGyG5CtfwEXOU0j + eGWigAAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAACAAAAAgAgGAAAAwz5hywAACiNJREFUeJzt + nVtsG1kBhr+4bm512mwvSrudZndpm6oliH3YbqEgAXlyw1LkFYxKXxCyAEHQCF6QsBQJUWQtT5VGRUis + 3PYBUWkesOiuoALJVFoEDd1qJda4bHYD2e30srRqm0sTJ3FqHsZpXGfGHntsx/Y5nzSKMzkzPr/95/jM + mfP7tGWzWSTi4lvvCkjWF2kAwZEGEBxpAMGRBhAcaQDBkQYQHGkAwZEGEBxpAMGRBhAcaQDBkQYQHGkA + wfHb7RwcHPRyzl3AAPBcbtsJ7AZ6c9um3NYJbMAyYRZYBhaBR7ltKrfdAW4BN4H/5LYPgaVKKpdMJitT + 5YAZVgt31VW/EjM81d/WAGXQBxwBXgZeBAaBPdS+ZbkLXAfeAa4CV4CJGj/nGsywuu76zbB6FbiixIyK + 9LfZTQgp0QIcAI4Dw8DncWeiDJarH7Lq8HRu/2OgLXeedlb/Q7YAAaDDlRL4J/Bn4HfA35wKeW0BzLDa + 8PqVmOGov5ByDPAN4NvAl4qcbzy3JYEbwAdYbr0FzABzbiuGJXwTVhPaB/QDLwAHgf3AIZxfnOvAOeDX + WM3oEyo1gBlWm1K/EjOmHMoA7gzwKvAz4JM2x18DLgN/zT2+UezJqsw24FPAZ4AvAl/A+lzN5yHwC+C1 + lR3lGsAMq02vX4kZr+FAKQOcB75Z8Od/AL8B/sA6fO4WYTsQBL4GfLXgb1dz+26XYwAzrJ6niH4lZkzY + dALrykon0AyrJfUrMeN24fHFDPDH3AlXuIT133TZe7VrzgDwQ+B7efvuAgeSyeQDNycww6qtfiVmXC4o + 562mHrG7CjDDqqN+JWY8pd+pt/pdVsUvASeBYzTHmw/W5/D3gZeA93P7dgCvuznYDKtr9Csx41jhm9+o + KDFjXIkZrvQ79WBP5n5msTobH1S7knXiGlZrMIl1Tf6Ky+Oe0q/EjKbUr8SMa8CAGVYncdDv1AIs5z0+ + XP2q1ZX9rHaOMi6PaRn9Zlgtqt/JAIu5n23Ab4EzQE/Va1d7foD1cdCX+/2xy+Oe0m+G1TNmWG06/WZY + Lanf7UjgCHACOI11fXmrGhWsERuxmvAfAZ+u0jlHgBNmWD0NnFNiRsPqN8NqWfrLGQreBvwc+CkQB94E + /kJ9r32dCGAN0LyCNUq3swbP8US/GVYbSr8ZVivWX8m9AD/w9dwGMIY19Pp34F2ssYGKbtSUwR6sQZCX + sAZCPot1o6UeNJR+M6x60u/1ZhBYN0OOYDU5APeAf7M6FPq/3OOH2I+FZ7H6IhuwxsK7sYZAe7H6HbuB + Z7FEfwLYhzUs2ig0tf5qGKCQ7Vg3SYrxGKujtczqC+DL1acWdaonTaV/vV5sH2vHrUWiYfTLGUGCIw0g + ONIAgiMNIDjSAIIjDSA40gCCIw0gOE4G2FjXWtQPt7qE0e9kgLYaV2S9cNviCaPf6QW5UOOKrBdvuCwn + jH4nA7yONSu4lbiLFewoiRIzhNFfrEkcxsoFtAJvY82OcTUlHECJGS2nv3BKOJT+TPwWVjLoX7WoVR14 + CPwEa2LnmlCEE4ODgwwODhIcS7WE/uBY6nBwLHXbLvLnplMUx0q9nsSaAtUMXAd+DDxPXiysEoJjqXhw + LNW0+oNjqaL6y5kPcAG40P+5/uGFmYWRubtzR2c/nu3NPm6Mr5vv3t6d7t7Rnezc3HnWHDN/Ve3zB8dS + F4AL3+nvG97a7h/Z09lx9Pnujt4NbY1xwXAzvZj+aH4heW9x6ewvJ++41u86HTx0amhNOnZxdpFpc5pp + c5qZOzPM3p5dWphZ8JOt7WWUv9OfCfQFfD3P9vh6dvewZc8WurZ25Rd5ko5NjCbKTge7TUc/s9HPgUAX + BzZ1sXdTJ3u7O5e2tvv9bTW+jJxdXs58OLfge/9R2jf+aJ7rs/PcTi/mF3Gdji5pgKFTQ67TsYnRxA1W + vyGjH6sJLvYNGX5WX6wMq9+QMYf1+eX0DRkfDZ0a6sFlOjYxmigrHVxpOvrSkUN10x8cS7nWT5F0tK0B + VtDi2nmKpGP1kD6hxTXH4+uBHtIB0OJayXSsHtJddQRFSkc7GkCLa7bpWD2kXy4o56XSnlkxQD5aXHNM + x+ohveSloEjpaNurAC2urUnH6iH9WOGb36joIX1cD+kVp4MRKB3tKh2sh/SmTMfqIf0aMKDFtUk8pINp + 4XR0y6eDtbgmdDqYEuloV+lgLa6d0eJa06VjtbhWlXQwLZyOLisdrMW108A5PaQ3bDpWi2s1SwfTguno + itLBWlxrqHSsFtfqmg6mhdLRTZ8O1uKa0OlgPKajZTrYO02tX6aDq09T6Zfp4PWhYfTLaeGCIw0gONIA + giMNIDjSAIIjDSA40gCCIw0gODId7K1csyHTwS7LCaNfpoPtEUa/rQH0kC5MOtYBYfQ7Nol6SG+5dKyb + KeF5tJx+bNLRtgZYSccmRhMtkY5NjCYOJ0YTtunYErSEfoqko0t2ihKjiXhiNNG06dj8WFiFtHQ6uuy1 + g/cF9w139HSMdO/oPhroC/S2+Rqjwzx3by49d3cumZ5Onx1/c9wxHeshHArAtr2vDmfS90cWZm8cXZie + 7M1mlx3L1pP2wO50R6A/ubFr+9n7/33DtX5Pawe3B9rZrGxms7KZnp09BHYFljp6Ovy01fYyKpPOZGY/ + nvXN3JrxzdycYerGFPP35/OLeFo72E7/oeOX1ujPLDxg/sF7zD98j/TUBOmpiaVM+r4fsjXVv2FjINPR + 85yvs3e/r6t3gK5nDtK+aVd+kSf6UxeD3tLBlJGOHTo1VLd0bGI0UZV0rB35+g8dv+Raf+pisG76Dx2/ + 5Fp/6mKwvHSwSOnYYqgR8zxF9BtRZUKNmJXWtyoYUQUANWKW1G9EFbl2sNu1g9WIaavfiCqXC8p5q6lH + VgyQjxoxHfUbUUWuHVwKNWKu0W9ElWOFb36jYkSVcSOqyLWDqdLawUZUaUr9RlS5BgyoEXMSUdPBCL52 + sBox5drBeEwHqxHzjBoxm06/GjHl2sFVOucIcEKNmKeBc0ZUaVj9asSUawdT43SwGjEbSr8aMcVNByP4 + 2sFqxJTp4HWmqfXLdHD1aSr9Mh28PjSMfjktXHCkAQRHGkBwpAEERxpAcKQBBEcaQHCkAQRHpoO9lWs2 + ZDrYZTlh9Mt0sD3C6JdrB9tgRBVh9Mu1gx0wokrL6S+cEg5y7eCiGFGlJfQbUeWwXSgEPGYDGxhP2UA7 + 1IjZlPqNqDJVrGDZ6WDgIPAV4MvAURpnAse7wJ+A3wNvORWq1AArqBGz4fUbUcVRfyGVGCCfPqzpUC8D + L2Ll6PdQ+wGme0AKeAcr93YFlzlFrwbIR42YDaPfiCoV5TS9GsCOuqRjWZ27XxbVNADYZgPrqt8uG1gO + RdcOlrQ+8l6A4EgDCI40gOBIAwiONIDgSAMIjjSA4EgDCI40gOBIAwiONIDgSAMIjjSA4EgDCI40gOBI + AwiONIDg/B9DsN1jb+OkIwAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAAEAAAABAAgGAAAAXHKo + ZgAAGhJJREFUeJzt3X9sVfX9x/Fnf9GfloIgird+ccrAgsQfU3RzfmeXbM1Y2FDH0C1bNrLpP3Y6k2Uh + dsk3hGY/so00xmyZbEvMMq1DFn+tEHeVZMuG7ofjWyvMr1il4vwBtIVCSyn3+8f7FEp/cc6958e9/bwe + ySenvdx7zuG+bt/33M/5nM8tymQyiIibipPeARFJjgqAiMNUAEQcpgIg4jAVABGHqQCIOEwFQMRhKgAi + DlMBEHGYCoCIw1QARBymAiDiMBUAEYepAIg4TAVAxGEqACIOUwEQcZgKgIjDVABEHKYCIOIwFQARh6kA + iDhMBUDEYSoAIg5TARBxmAqAiMNUAEQcpgIg4jAVABGHlQa58/Lly6Paj2xUAHOBeuAC7+cLgDpgHjAb + qPZajbesAmYBZUCJtxx1ChgGRoATwBAwABz12ujPh7x2EPjAWx7wWj+QN1+33NnZGfk2etavjXwbU1D+ + QGpLe06PD1QAElAJLASWAkuAS4BFQAoLvg4LNB8cBf4D7Afe8to+4FXgNexFI8Eo/4jlUwGoBq4ArgMW + A9cCDVhlL4SPKjXA5V4b7xjwNvB3oBN4Bfgb0BPb3uU/5Z+AJAtAHXDDmLbSu20mqsJe1IvH3DYMvAGk + gd3ecm/8u5YY5Z8H+cddAJYAq4BbvFYd8/bzSRnwYa+Neg14BngB+CN2WDmTKP8z8iL/OArAUuA24Fbg + moi3NYgdbh0CDmMdN+PbCeCk14bHPLaYM51Ds7BOphqseo8ua7FD0tne72Efmi4G7vVaL/A08HvgKW+/ + C5Hy9y/2/KMqABXAl4A7gE+GtM5TWKj7gDe99h722eod4H3v9yPAcaLrjR19cZyP9TovwDqqLgQuxjqq + Lvd+r8phO3XAl712ANgKPAK8lMM646L8CyT/sAvAxcDdwNexJyVbfcAe4B/Y56RXvfYOVuGTdMJr/di+ + TaYYmIO9EBqAy7AOrmuwHuygz/tC4B6vdQAPYe8K+Ub5m4LJP6wCcB7wXeBbZPe5rht4Hush/Yu3PBLS + viXhFHZ++CCwa8ztJdgL4EZghbe8jmDPWZPXdgKtwI4Q9jdXyv9sBZN/USbj/0hpioFAdwLfx87L+tUL + PAf8GfsP7MUGYLioDrgZuAkL9sqAj98KfBs773yWmAYCKf/chJJ/akv7hPz9yKUAzAZ+Bazx+fCDWIdG + B7Cdwq7wUVqG9ZSvwU6P+XEYuAt4fOyNURaAnvVrlX80ss4/taX98XPec5xsC8AS7DPI4qnvfdoO4DdY + pRoIuH+uuxrrBLoDuMjH/TcBD4z+ElUB6Fm/VvnHI3D+qS3tD5z7bmdkUwAuxUYxzT3H3R8BHgReDLJD + MqkK7IXQzLkPETcD90E0BaBn/VrlH79A+ae2tN/nd8VBz2OWY4MUpgv/d9gwzq+g8MMyCDyMdRx9Axtv + PpV7sY8DoetZv1b5JyNQ/j3r1/rOP2gB+BF2nnMy+4DPAl/ATt9INB7G3gV+Mc19fob1NodN+SfPV/49 + 69f6yj9oAbhnitu3Y1X/mYDrk+z0Ad/EzsBM5f4Itqv880No+YcxlPFZ7PRFbwjrkmB+C3waO0Qcb1VM + +6D8k5Nz/rkWgBFsjLckZwd2yD+en17jXCn/hKW2tOeUf64FoIj43mlkapNdZHM8hu0q//yQdf65FoBi + oB07BJRkPIGNJBsvjis9lX/CetavzSn/MPoASoA/4J17ltgsA/7E1CPxyqa4PWzKPxmh5B/m9cw/wWY1 + WRniOmVy3wFeBj42zX3inpxU+ccntPzDntDgFuCv2NDPFSGvW+CrQBfwA/JrPsdRyj9aoecf1WSLdwL/ + Ah4FPhXRNlyxEDun+yrwa+y68nyn/MMTaf5Rv4t80Wu7gceAbdh/RKZXgY2q+zxwOzYEuxAp/+zEln9c + h5ErvLYJGx++HTt/vYuz52Vz2UXYKbWbgM8A85PdnVAp/3NLJP8kPkde77UW7KKG57B3iOexd4dCnfwy + qPlY2B8BPo51nuXLl1xESfmbvMg/6Y6keuBrY34/gE0JtRv78oR/YpM+DsW/a6Gag82Oey12Df1HgeXY + oZ7LlH/Cki4A4y3EppC+zfv9FDbT66vYJJH7savO3sBmhe0lP14cRdjU0RdhX111GXY13uXY+dpFuD0H + vl/KP2b5VgDGK8amV74QO8U01hD2Ahg/LXQfNv1UL/bFCseYOC/8MGe+CBIswFnjlqPzwo9+wWQVNg3a + XGwet/Oxw7gF2Gy4F2Dzxkt4lH/E8r0ATKcce/IXBHjMiNdOjVmCBV7iLYu9Zam3lPyk/ENQyAUgGyVe + Ezcp/3EK4VtXRSQiKgAiDlMBEHGYCoCIw1QARBymAiDiMBUAEYepAIg4TAVAxGEqACIOUwEQcZgKgIjD + VABEHKYCIOIwFQARh6kAiDhMBUDEYSoAIg5TARBxmArAzKVs3eYrf71IZq64vx5c8ksiXw8u+eOdpHdA + EuUr/6AFQO8qheOZCNap/AuHr/yDFoCfZrEjkowfR7BO5V84fOUftABsALoD74rE7W6gJ4L1Kv/CcHdq + S7uv/IMWgCHsO9oOBt4lictm4OdRrDi1pV3557/NqS3tvvPPphOwG7gR2JvFYyVam4D7otxAakt7N8o/ + X21KbWkPlH+2ZwFeA64Dtmb5eAlXL7AOeCCOjaW2tCv//NILrEttaQ+cf1Em479jd/ny5ZPdvA74IVAf + dOMSiq3A/cCb4/+hs7Mz1A1Nln/Hygbln6ytwP1Nu7qyyj+McQCPAsuww8+jIaxP/NkJNAG3M8kff4yU + fzJ2Ak1Nu7pun+yP36+wBgIdwQ4/lwAbgbdDWq9MtB1YDXzC+zkfKP/4hJp/2CMBDwDfAy4D1gPPh7x+ + V70LPAhcj73rP5Xs7kxJ+UcjsvxLw1rROEPAL712JXAr8Dng6oi2N/MU0UeGp4FngSeAwYT3KAjln6MM + 9BURff5RFYDTGjc2DgMngczAewN8sPcDert76e3uZeTESNSbLyiVcyuZt3QecxbNYc6H5lBSXpLB/phO + pVvSSe9eVpp2dZ3O/78qy7m+roYVtdUsP6+KyhJdijLWgcET7Oo9yu7+AV7uH+D4yKnT+XesbIhkm2Gc + BZigcWNjBfAl4A7gk5Pd5+TgSfr299Hf00///n769vdxcvCk730pdEUlRVTWVTLnQ3OoubCGOR+aQ9X5 + VVA06d0PYL29j6Rb0i/53UZMZwEm3Na0q+uc+deUlLD0vEqWVleytKaSpedVUlNSEur+5rOTmQzvDg3z + cv8Abxwb5OW+Ad4ePDHVxRan8+9Y2XBW/k27uqbchp/8Qy0AjRsbL8aGoX4dWOh7xcDIiRGOfXCM/p5+ + Bt4fGOrb33fi2PvHykaGR8rJTPFnUSCKSoqGy6rKhmpTtUW1C2srqy+oLq5N1VJeW57N6jqAh9It6XN+ + Doy7ADTt6so6/4riYuorZ7GkppL6ivKhK86rPFFfUV5WUVJcXjRVWSwQJzOZ4f6TI0N7jx4vem1gsLL7 + 2GDxvwcG+eDEcDar6wAe6ljZ8BTkSQFo3Nh4HvBd4FtAte8VntGNdRh1An8BOtMt6SNAJfZCWor1MNcD + lwIp7+c6YFYW24vCAHYJ5n6vvQW8DuzBBk4datzYWIzt+43ACm95Hdk9ZzuB1nRLesdUd4irADTt6go9 + /46VDTMu/6ZdXaHnD+SUf84FoHFj453A9wk2EKQXeA74M/Yf2JtuSQftEKgA5gKXAPOB871lnbesxZ7Y + aqDGa1VAmddKObsPJAOMfl4dxjpdBrBz2wNjfj6EjYUf2w5gp776CXjJbOPGxjrgZuAmrIf3yiCPxw4N + v51uSb81/h/iKABAKPl3rGxwMv+mXV2h5I8VnLOEXgDGat7WPBv4FbDG50MOAr/HDmG2Y+eOZaJlwCrs + eb3B52MOA3e1rWl7PLK9YkIBUP7RyDp/4Kz8IysAzdual2DnIhf7uPsO4DdYpRoIvDG3XQ18GetMu8jH + /Te1rWmL7HqAMQVA+ccjcP6MuR4kkgLQvK35UuBv2OHXdB7BBi+8GGgDMpkK7IXQzLkPETe3rWmL5IpA + rwAo//gFyh/vitDQrwVo3tZcDrzA9OH/DrgW+AoKPyyDwMNYx9E3sE6mqdzbvK35roj2Q/knI1D+2McB + X4KOxPgR1ukymX3AZ4EvAP8IuF7x72HsXeAX09znZ83bmlMRbFv5J89X/tjZhnMKWgDumeL27VjVj2Ii + SpmoD/gm1gM/lfsj2K7yzw+h5R/GWMxnsdMXvSGsS4L5LfBpJh8nviqmfVD+yck5/1wLwAh2oYckpG1N + 2w7skG88P73GuVL+ycsp/1wLQBHxvdPI1K6Z5LbjMWxX+eeHrPPPtQAUA+3YIaAkoHlb8xPYSLLxIr/S + E+WfD3LKP4w+gBLgD0Q8G61MsAz4E1OPxCuLaT+UfzJCyT/MC7J/AqSBlSGuUyb3HeBl4GPT3Cfur/FS + /vEJLf+wZ2S4BfgrNvRzRcjrFvgq0AX8gHgO8YNS/tEKPf+opmS5E/gXNmPspyLahisWYud0XwV+DVyR + 6N74o/zDE2n+Ub+LfNFru4HHgG3Yf0SmV4GNqvs8Nu13VjOH5AHln53Y8o/rMHKF1zZh48O3Y+cvd2HX + Xoudt12FXRf+Geya9plC+Z9bIvkn8Tnyeq+1YBc1PIe9QzyPvTucSGCfkjAfC/sjwMexzrN8md0mSsrf + 5EX+SXck1QNfG/P7AWxKqN3AK8A/sZlWhuLftVDNwaa1uha7hv6jwHLsUM9lyj9hSReA8RYCt3kN4BTw + HvbOsAd7x9gHvIF9HVYv+fHiKMKmnLoIWIR9MUYKuBw7X7uI7OZ9c43yj1m+FYDxioELvXbLuH8bwl4A + b2OTMb6PvVj6sOmnerE53I5xZk63AewQc9hro/PQFWGHX2OXFVioo/PKVWHTYM3F5p0bnYNuAXAxcAE2 + D52ER/lHLN8LwHTKsSd/QYDHjHjt1JglWOAl3rLYW5ZS4NNRz3DKPwSFXACyUeI1cZPyH0ffzSTiMBUA + EYepAIg4TAVAxGEqACIOUwEQcZgKgIjDVABEHKYCIOIwFQARh6kAiDhMBUDEYSoAIg5TARBxmAqAiMNU + AEQcpgIg4jAVABGHqQCIOEwFYOZStm7zlb9eJDNX3F8PLvklka8Hl/zxTtI7IInylX/QAqB3lcLxTATr + VP6Fw1f+QQvAT7PYEUnGjyNYp/IvHL7yD1oANgDdgXdF4nZ325q2ngjWq/wLw92Ar/wDFYC2NW1D2He0 + HcxipyQem9vWtP08onUr//y3GfCdf+BOwLY1bd3AjcDeoI+VyG1qW9N2X8Tb6Eb556tNQKD8szoL0Lam + 7TXgOmBrNo+X0PUC69rWtD0Q0/aUf37pBdYBgfMvymT8d+wuX758wm2NGxvXAT8E6oNuXEKxFbg/3ZJ+ + c/w/dHZ2hrqhyfLHXnjKPzlbgfuBrPIPYxzAo8Ay7PDjaAjrE392Ak3plvTtk/3xx0j5J2Mn0ATcziR/ + /H6FNRDoCHb4sQTYCLwd0nplou3AauAT3s/5QPnHJ9T8wx4JeAD4HnAZsB54PuT1u+pd4EHgeqzqP5Xs + 7kxJ+UcjsvxLw1rROEPAL712JXAr8Dng6oi2N/Nk6KOIp4FngSeAwYT3KAjln7OiPshEnn9UBeC0dEt6 + GDgJZKovqGbeknnULaqjblEdJbNKot58QTl+6Dgf7PmAw92HObzvMCNDIxnsj+lU48bGpHcvKw2rO07n + P3TkTY6++yIDB3dz7GAnp04eT3r38sqs6oXULFhJ9bwVVM+7iuLSytP5dz3ZFMk2wzgLMOG2dEu6AvgS + cAfwycnWVVpRyuz62dSmaqmtr2V2/WxKKyKvR3kjM5LheO9xDu87zNH/HOXwvsMcO3hsqtH2B7De3kca + Nza+NPYf0i3pKbcR01mACRpWd5wz/5Hhoxw/vOesNjLsTh9iUXEpZZULqJ5/FRW1l1I97ypm1VwMFE12 + 99P5dz3Z9NJkd5iMn/xDLQDplvTF2DDErwMLfa8YKJlVQtW8KmpTtVTPrx6aXT/7RNX8qrKSspJyiiZ/ + VgpFZiQzPHxseKi/p7+o/0B/5cB7A8X9Pf0M9Q9ls7oO4KHGjY1PQX4VgIbVHVnnf2pkkBNH9nO8dy9D + R/YPHT/86omho/vLTp0cLIdMQedfVFw6XDKrdqiybklRRd3iyorzFhVX1H2Yssp52ayuA3io68mmc/YD + xFYA0i3p84DvAt8Cqn2v8IxurMOoE/gL0Nm4sfEIUIm9kJZiPcz1wKVAyvu5DpiVxfaiMIBdgrnfa28B + rwN7sIEzh9It6WJs328EVnjL68juOdsJtAI7prpDXAWgYXVH6Pl3Pdk04/JvWN0Rev5dTzbllH/OBQC4 + E/g+wQaC9ALPAX/GXsB7Gzc2jgR4PEAFMBe4BJgPnO8t67xlLfbEVgM1XqsCyrxWytl9IBlg9PPqMNbp + MoCd2x4Y8/MhbCz82HYAO/XVT8BLZtMt6TrgZuAmrIf3yiCPxw4Nv4294M4SRwFoWN0RSv5dTzY5mX/D + 6o5Q8u96simr/HMpALOBXwFrfD78IPB77BBmO3buWCZaBqzCntcbfD7mMHAX8PjYG8MuAGOt3dCj/KOR + df7tranHz3nPcbItAEuwc5GLfTxsB/AbrFINBNw/110NfBnrTLvIx/03MWY8eFQFYO2GHuUfj8D5t7em + Al0PkE0BuBT4G3b4NZ1HsMELLwbZIZlUBfZCaObch4ib8a4Ii6IArN3Qo/zjFyj/9taU7ysCg44ELAde + YPrwfwdcC3wFhR+WQeBhrOPoG1gn01TuxT4OhG7thh7ln4xA+a/d0OM7/6AF4EdYp8tk9gGfBb4A/CPg + esW/h7F3gV9Mc5+fYb3NYVP+yfOV/9oNPb7yD1oA7pni9u1Y1Y9iIkqZqA/4JnYGZir3R7Bd5Z8fQss/ + jIuBnsVOX/SGsC4J5rfAp5l8nPiqmPZB+Scn5/xzLQAj2IUekpwd2CH/eH56jXOl/BPW3prKKf9cC0AR + 8b3TyNSumeS2OK60Uf75Iev8cy0AxUA7dggoyXgCG0k2XhxXVin/hK3d0JNT/mH0AZQAfyDgbKSSs2XA + n5h6JF5ZTPuh/JMRSv5hzgj0EyANrAxxnTK57wAvAx+b5j5xf42X8o9PaPmHPSXYLcBfsaGfK0Jet8BX + gS7gB8RziB+U8o9W6PlH9e3AdwL/wmaM/VRE23DFQuyc7qvAr4ErEt0bf5R/eCLNP+p3kS96bTfwGLAN + +4/I9CqwUXWfx6Z9Lk92d7Km/LMTW/5xHUau8NombHz4duz89S7s2mux87arsOvCP4Nd0z5TKP9zSyT/ + JD5HXu+1Fuyihuewd4jnsXeHEwnsUxLmY2F/BPg41nmWL7PbREn5m7zIP+mOpHrga2N+P4BNCbUbeAX4 + JzbTSlaT5+WROdi0Vtdi19B/FFiOHeq5TPknLOkCMN5C4DavAZwC3sPeGfZg7xj7gDewr0PqJT9eHEXY + lFMXAYuwL8ZIAZdj52sXkd28b65R/jHLtwIwXjFwodduGfdvQ9gL4G1sMsb3sRdLHzb9VC82h9sxzszp + NoAdYg57bXQeuiLs8GvssgILdXReuSpsGrS52Lxzo3PQLQAuBi7A5qGT8Cj/iOV7AZhOOfbkLwjwmBGv + nRqzBAu8xFsWe8tSppikXfKC8g9BIReAbJR4Tdyk/MeJaiCQiBQAFQARh6kAiDhMBUDEYSoAIg5TARBx + mAqAiMNUAEQcpgIg4jAVABGHqQCIOEwFQMRhKgAiDlMBEHGYCoCIw1QARBymAiDiMBUAEYepAIg4TAVg + 5lK2bvOVv14kM1fcXw8u+SWRrweX/PFO0jsgifKVf9ACoHeVwvFMBOtU/oXDV/5BC8BPs9gRScaPI1in + 8i8cvvIPWgA2AN2Bd0XidjfQE8F6lX9huLu9NeUr/6AFYAj7jraDgXdJ4rIZ+HkUK25vTSn//Le5vTXl + O/9sOgG7gRuBvVk8VqK1Cbgvyg20t6a6Uf75alN7aypQ/tmeBXgNuA7YmuXjJVy9wDrggTg21t6aUv75 + pRdY196aCpx/LqcBjwC3A3dg39suydgKXAU8FudG21tTR9pbU8o/eVuBq9pbU1nlH8Y4gEeBZdjh59EQ + 1if+7ASasCL8ZoL7ofyTsRNoam9N3d7emso6/7AGAh3BDj+XABuBt0Nar0y0HVgNfML7OR8o//iEmn/Y + IwEPAN8DLgPWA8+HvH5XvQs8CFyPves/lezuTEn5RyOy/EvDWtE4Q8AvvXYlcCvwOeDqiLY3E/Vio7me + BZ4ABpPdnUCUf+5iyT+qAjDW/3rtf7DPiquA/wZuBmpi2H4h+T/gaeAF4I/MjM/Uyt+/2POPowCM9YrX + fgjUATcAK73lDd5trhjGxlT8EdgNpIF/M7PH2yv/M/Ii/7gLwFi9QIfXAKqBpdjnnMXAtUADMJfCv2rx + GPb5+O9AJ/ZH8BLRDNctFMo/D/JPsgCMN4A9QX8fc1slsBB7YSwB6oFLgZT3cx0wK97dnNIAdgnmfq+9 + BbwO7MEGTh1iZr+750r5JyCfCsBkjmNP4utMvLyxAnt3uASYD5zvLeu8ZS32rlKNfdasAaqAMq+Vcvb/ + P4Mdlp30loNYqEe95ejPh7Cx8GPbAezUVz95GHIBU/4RK8pkCmp/RSREhf7ZSkRyoAIg4jAVABGHqQCI + OEwFQMRhKgAiDlMBEHGYCoCIw1QARBymAiDiMBUAEYepAIg4TAVAxGEqACIOUwEQcZgKgIjDVABEHKYC + IOIwFQARh6kAiDhMBUDEYSoAIg5TARBxmAqAiMNUAEQcpgIg4jAVABGHqQCIOEwFQMRhKgAiDlMBEHGY + CoCIw1QARBymAiDiMBUAEYf9P6kddlsUKxPtAAAAAElFTkSuQmCC + + + \ No newline at end of file diff --git a/OpenDBDiff/UI/MainForm.Designer.cs b/OpenDBDiff/UI/MainForm.Designer.cs new file mode 100644 index 0000000..8efa0d4 --- /dev/null +++ b/OpenDBDiff/UI/MainForm.Designer.cs @@ -0,0 +1,745 @@ +using System.ComponentModel; +using System.Windows.Forms; +using ScintillaNET; + +namespace OpenDBDiff.UI +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + this.lblMessage = new System.Windows.Forms.Label(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.tabControl2 = new System.Windows.Forms.TabControl(); + this.tabPage4 = new System.Windows.Forms.TabPage(); + this.txtNewObject = new ScintillaNET.Scintilla(); + this.tabPage5 = new System.Windows.Forms.TabPage(); + this.txtOldObject = new ScintillaNET.Scintilla(); + this.tabPage6 = new System.Windows.Forms.TabPage(); + this.txtDiff = new ScintillaNET.Scintilla(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.panel5 = new System.Windows.Forms.Panel(); + this.panel4 = new System.Windows.Forms.Panel(); + this.panel3 = new System.Windows.Forms.Panel(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.panel1 = new System.Windows.Forms.Panel(); + this.txtSyncScript = new ScintillaNET.Scintilla(); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.PanelGlobal = new System.Windows.Forms.Panel(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.LeftDatabasePanel = new System.Windows.Forms.Panel(); + this.RightDatabasePanel = new System.Windows.Forms.Panel(); + this.toolMenu = new System.Windows.Forms.ToolStrip(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.toolLblProjectType = new System.Windows.Forms.ToolStripLabel(); + this.toolProjectTypes = new System.Windows.Forms.ToolStripComboBox(); + this.PanelActions = new System.Windows.Forms.FlowLayoutPanel(); + this.SwapButton = new System.Windows.Forms.Button(); + this.btnCompare = new System.Windows.Forms.Button(); + this.btnOptions = new System.Windows.Forms.Button(); + this.btnSaveAs = new System.Windows.Forms.Button(); + this.btnCopy = new System.Windows.Forms.Button(); + this.btnUpdate = new System.Windows.Forms.Button(); + this.btnCompareTableData = new System.Windows.Forms.Button(); + this.btnUpdateAll = new System.Windows.Forms.Button(); + this.btnNewProject = new System.Windows.Forms.Button(); + this.btnSaveProject = new System.Windows.Forms.Button(); + this.btnProject = new System.Windows.Forms.Button(); + this.toolOpenProject = new System.Windows.Forms.ToolStripButton(); + this.toolNewProject = new System.Windows.Forms.ToolStripButton(); + this.toolSaveProject = new System.Windows.Forms.ToolStripButton(); + this.schemaTreeView1 = new OpenDBDiff.UI.SchemaTreeView(); + this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); + this.tabControl1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.tabControl2.SuspendLayout(); + this.tabPage4.SuspendLayout(); + this.tabPage5.SuspendLayout(); + this.tabPage6.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.tabPage3.SuspendLayout(); + this.PanelGlobal.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.toolMenu.SuspendLayout(); + this.PanelActions.SuspendLayout(); + this.SuspendLayout(); + // + // lblMessage + // + this.lblMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.lblMessage.AutoSize = true; + this.lblMessage.Location = new System.Drawing.Point(6, 528); + this.lblMessage.Name = "lblMessage"; + this.lblMessage.Size = new System.Drawing.Size(0, 13); + this.lblMessage.TabIndex = 4; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 175); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(842, 483); + this.tabControl1.TabIndex = 3; + this.tabControl1.SelectedIndexChanged += new System.EventHandler(this.tabControl1_SelectedIndexChanged); + // + // tabPage2 + // + this.tabPage2.Controls.Add(this.tabControl2); + this.tabPage2.Controls.Add(this.groupBox2); + this.tabPage2.Controls.Add(this.groupBox1); + this.tabPage2.Location = new System.Drawing.Point(4, 22); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(834, 457); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "Schema"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // tabControl2 + // + this.tabControl2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabControl2.Controls.Add(this.tabPage4); + this.tabControl2.Controls.Add(this.tabPage5); + this.tabControl2.Controls.Add(this.tabPage6); + this.tabControl2.Location = new System.Drawing.Point(350, 50); + this.tabControl2.Name = "tabControl2"; + this.tabControl2.SelectedIndex = 0; + this.tabControl2.Size = new System.Drawing.Size(477, 402); + this.tabControl2.TabIndex = 3; + // + // tabPage4 + // + this.tabPage4.Controls.Add(this.txtNewObject); + this.tabPage4.Location = new System.Drawing.Point(4, 22); + this.tabPage4.Name = "tabPage4"; + this.tabPage4.Padding = new System.Windows.Forms.Padding(3); + this.tabPage4.Size = new System.Drawing.Size(469, 376); + this.tabPage4.TabIndex = 0; + this.tabPage4.Text = "New object"; + this.tabPage4.UseVisualStyleBackColor = true; + // + // txtNewObject + // + this.txtNewObject.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtNewObject.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtNewObject.Location = new System.Drawing.Point(3, 3); + this.txtNewObject.Name = "txtNewObject"; + this.txtNewObject.Size = new System.Drawing.Size(463, 370); + this.txtNewObject.TabIndex = 0; + // + // tabPage5 + // + this.tabPage5.Controls.Add(this.txtOldObject); + this.tabPage5.Location = new System.Drawing.Point(4, 22); + this.tabPage5.Name = "tabPage5"; + this.tabPage5.Padding = new System.Windows.Forms.Padding(3); + this.tabPage5.Size = new System.Drawing.Size(469, 376); + this.tabPage5.TabIndex = 1; + this.tabPage5.Text = "Old object"; + this.tabPage5.UseVisualStyleBackColor = true; + // + // txtOldObject + // + this.txtOldObject.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtOldObject.Font = new System.Drawing.Font("Courier New", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtOldObject.Location = new System.Drawing.Point(3, 3); + this.txtOldObject.Name = "txtOldObject"; + this.txtOldObject.Size = new System.Drawing.Size(463, 370); + this.txtOldObject.TabIndex = 0; + // + // tabPage6 + // + this.tabPage6.Controls.Add(this.txtDiff); + this.tabPage6.Location = new System.Drawing.Point(4, 22); + this.tabPage6.Name = "tabPage6"; + this.tabPage6.Size = new System.Drawing.Size(469, 376); + this.tabPage6.TabIndex = 2; + this.tabPage6.Text = "Diff"; + this.tabPage6.UseVisualStyleBackColor = true; + // + // txtDiff + // + this.txtDiff.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtDiff.Location = new System.Drawing.Point(0, 0); + this.txtDiff.Name = "txtDiff"; + this.txtDiff.Size = new System.Drawing.Size(469, 376); + this.txtDiff.TabIndex = 0; + // + // groupBox2 + // + this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox2.Controls.Add(this.label3); + this.groupBox2.Controls.Add(this.label2); + this.groupBox2.Controls.Add(this.label1); + this.groupBox2.Controls.Add(this.panel5); + this.groupBox2.Controls.Add(this.panel4); + this.groupBox2.Controls.Add(this.panel3); + this.groupBox2.Location = new System.Drawing.Point(350, 5); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(478, 40); + this.groupBox2.TabIndex = 2; + this.groupBox2.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(345, 16); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(62, 13); + this.label3.TabIndex = 5; + this.label3.Text = "Drop object"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(195, 16); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(77, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Alter old object"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(45, 16); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(93, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Create new object"; + // + // panel5 + // + this.panel5.BackColor = System.Drawing.Color.Red; + this.panel5.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel5.Location = new System.Drawing.Point(310, 12); + this.panel5.Name = "panel5"; + this.panel5.Size = new System.Drawing.Size(32, 20); + this.panel5.TabIndex = 2; + // + // panel4 + // + this.panel4.BackColor = System.Drawing.Color.Blue; + this.panel4.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel4.Location = new System.Drawing.Point(160, 12); + this.panel4.Name = "panel4"; + this.panel4.Size = new System.Drawing.Size(32, 20); + this.panel4.TabIndex = 1; + // + // panel3 + // + this.panel3.BackColor = System.Drawing.Color.Lime; + this.panel3.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panel3.Location = new System.Drawing.Point(10, 12); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(32, 20); + this.panel3.TabIndex = 0; + // + // groupBox1 + // + this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.groupBox1.Controls.Add(this.schemaTreeView1); + this.groupBox1.Location = new System.Drawing.Point(6, 4); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(335, 445); + this.groupBox1.TabIndex = 1; + this.groupBox1.TabStop = false; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.panel1); + this.tabPage1.Controls.Add(this.lblMessage); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(834, 457); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "Synchronized script"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D; + this.panel1.Controls.Add(this.txtSyncScript); + this.panel1.Location = new System.Drawing.Point(9, 6); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(819, 461); + this.panel1.TabIndex = 6; + // + // txtSyncScript + // + this.txtSyncScript.Dock = System.Windows.Forms.DockStyle.Fill; + this.txtSyncScript.Location = new System.Drawing.Point(0, 0); + this.txtSyncScript.Name = "txtSyncScript"; + this.txtSyncScript.ReadOnly = true; + this.txtSyncScript.Size = new System.Drawing.Size(815, 457); + this.txtSyncScript.TabIndex = 0; + // + // tabPage3 + // + this.tabPage3.Controls.Add(this.textBox1); + this.tabPage3.Location = new System.Drawing.Point(4, 22); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.Padding = new System.Windows.Forms.Padding(3); + this.tabPage3.Size = new System.Drawing.Size(834, 457); + this.tabPage3.TabIndex = 2; + this.tabPage3.Text = "Action report"; + this.tabPage3.UseVisualStyleBackColor = true; + // + // textBox1 + // + this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox1.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textBox1.Location = new System.Drawing.Point(9, 6); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textBox1.Size = new System.Drawing.Size(819, 461); + this.textBox1.TabIndex = 0; + // + // saveFileDialog1 + // + this.saveFileDialog1.DefaultExt = "sql"; + this.saveFileDialog1.Filter = "SQL File|*.sql"; + // + // PanelGlobal + // + this.PanelGlobal.BackColor = System.Drawing.Color.White; + this.PanelGlobal.Controls.Add(this.tableLayoutPanel1); + this.PanelGlobal.Controls.Add(this.btnNewProject); + this.PanelGlobal.Controls.Add(this.btnSaveProject); + this.PanelGlobal.Controls.Add(this.btnProject); + this.PanelGlobal.Dock = System.Windows.Forms.DockStyle.Top; + this.PanelGlobal.Location = new System.Drawing.Point(0, 0); + this.PanelGlobal.Name = "PanelGlobal"; + this.PanelGlobal.Size = new System.Drawing.Size(940, 175); + this.PanelGlobal.TabIndex = 10; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableLayoutPanel1.AutoSize = true; + this.tableLayoutPanel1.ColumnCount = 3; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.LeftDatabasePanel, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.RightDatabasePanel, 2, 0); + this.tableLayoutPanel1.Controls.Add(this.SwapButton, 1, 0); + this.tableLayoutPanel1.Location = new System.Drawing.Point(126, 3); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 1; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(854, 172); + this.tableLayoutPanel1.TabIndex = 0; + // + // LeftDatabasePanel + // + this.LeftDatabasePanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.LeftDatabasePanel.Location = new System.Drawing.Point(3, 3); + this.LeftDatabasePanel.Name = "LeftDatabasePanel"; + this.LeftDatabasePanel.Size = new System.Drawing.Size(401, 166); + this.LeftDatabasePanel.TabIndex = 10; + // + // RightDatabasePanel + // + this.RightDatabasePanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.RightDatabasePanel.Location = new System.Drawing.Point(450, 3); + this.RightDatabasePanel.Name = "RightDatabasePanel"; + this.RightDatabasePanel.Size = new System.Drawing.Size(401, 166); + this.RightDatabasePanel.TabIndex = 11; + // + // toolMenu + // + this.toolMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolOpenProject, + this.toolNewProject, + this.toolSaveProject, + this.toolStripSeparator1, + this.toolLblProjectType, + this.toolProjectTypes}); + this.toolMenu.Location = new System.Drawing.Point(0, 0); + this.toolMenu.Name = "toolMenu"; + this.toolMenu.Size = new System.Drawing.Size(940, 25); + this.toolMenu.TabIndex = 16; + this.toolMenu.Visible = false; + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); + this.toolStripSeparator1.Visible = false; + // + // toolLblProjectType + // + this.toolLblProjectType.Name = "toolLblProjectType"; + this.toolLblProjectType.Size = new System.Drawing.Size(74, 22); + this.toolLblProjectType.Text = "Project Type:"; + // + // toolProjectTypes + // + this.toolProjectTypes.AutoSize = false; + this.toolProjectTypes.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.toolProjectTypes.Items.AddRange(new object[] { + "SQL Sever 2005", + "MySQL 5.0 or Higher", + "Sybase 12.5"}); + this.toolProjectTypes.Name = "toolProjectTypes"; + this.toolProjectTypes.Size = new System.Drawing.Size(200, 23); + this.toolProjectTypes.SelectedIndexChanged += new System.EventHandler(this.toolProjectTypes_SelectedIndexChanged); + // + // PanelActions + // + this.PanelActions.Controls.Add(this.btnCompare); + this.PanelActions.Controls.Add(this.btnOptions); + this.PanelActions.Controls.Add(this.btnSaveAs); + this.PanelActions.Controls.Add(this.btnCopy); + this.PanelActions.Controls.Add(this.btnUpdate); + this.PanelActions.Controls.Add(this.btnCompareTableData); + this.PanelActions.Controls.Add(this.btnUpdateAll); + this.PanelActions.Dock = System.Windows.Forms.DockStyle.Right; + this.PanelActions.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.PanelActions.Location = new System.Drawing.Point(842, 175); + this.PanelActions.Name = "PanelActions"; + this.PanelActions.Size = new System.Drawing.Size(98, 483); + this.PanelActions.TabIndex = 17; + // + // SwapButton + // + this.SwapButton.Dock = System.Windows.Forms.DockStyle.Fill; + this.SwapButton.Image = global::OpenDBDiff.Properties.Resources.arrow_ew; + this.SwapButton.Location = new System.Drawing.Point(410, 3); + this.SwapButton.Name = "SwapButton"; + this.SwapButton.Size = new System.Drawing.Size(34, 166); + this.SwapButton.TabIndex = 12; + this.toolTip1.SetToolTip(this.SwapButton, "Swap source and destination"); + this.SwapButton.UseVisualStyleBackColor = true; + this.SwapButton.Click += new System.EventHandler(this.SwapButton_Click); + // + // btnCompare + // + this.btnCompare.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCompare.Image = global::OpenDBDiff.Properties.Resources.compare; + this.btnCompare.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnCompare.Location = new System.Drawing.Point(3, 3); + this.btnCompare.Name = "btnCompare"; + this.btnCompare.Size = new System.Drawing.Size(95, 55); + this.btnCompare.TabIndex = 4; + this.btnCompare.Text = "Compare"; + this.btnCompare.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnCompare.UseVisualStyleBackColor = true; + this.btnCompare.Click += new System.EventHandler(this.btnCompare_Click); + // + // btnOptions + // + this.btnOptions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnOptions.Image = global::OpenDBDiff.Properties.Resources.setting_tools; + this.btnOptions.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnOptions.Location = new System.Drawing.Point(3, 64); + this.btnOptions.Name = "btnOptions"; + this.btnOptions.Size = new System.Drawing.Size(95, 55); + this.btnOptions.TabIndex = 5; + this.btnOptions.Text = "Options"; + this.btnOptions.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnOptions.UseVisualStyleBackColor = true; + this.btnOptions.Click += new System.EventHandler(this.btnOptions_Click); + // + // btnSaveAs + // + this.btnSaveAs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnSaveAs.Enabled = false; + this.btnSaveAs.Image = global::OpenDBDiff.Properties.Resources.save_as; + this.btnSaveAs.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnSaveAs.Location = new System.Drawing.Point(3, 125); + this.btnSaveAs.Name = "btnSaveAs"; + this.btnSaveAs.Size = new System.Drawing.Size(95, 55); + this.btnSaveAs.TabIndex = 6; + this.btnSaveAs.Text = "Save as"; + this.btnSaveAs.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnSaveAs.UseVisualStyleBackColor = true; + this.btnSaveAs.Click += new System.EventHandler(this.btnSaveAs_Click); + // + // btnCopy + // + this.btnCopy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCopy.Enabled = false; + this.btnCopy.Image = global::OpenDBDiff.Properties.Resources.clipboard_invoice; + this.btnCopy.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnCopy.Location = new System.Drawing.Point(3, 186); + this.btnCopy.Name = "btnCopy"; + this.btnCopy.Size = new System.Drawing.Size(95, 55); + this.btnCopy.TabIndex = 7; + this.btnCopy.Text = "Copy script"; + this.btnCopy.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnCopy.UseVisualStyleBackColor = true; + this.btnCopy.Click += new System.EventHandler(this.btnCopy_Click); + // + // btnUpdate + // + this.btnUpdate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnUpdate.Enabled = false; + this.btnUpdate.Image = global::OpenDBDiff.Properties.Resources.refresh_all; + this.btnUpdate.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnUpdate.Location = new System.Drawing.Point(3, 247); + this.btnUpdate.Name = "btnUpdate"; + this.btnUpdate.Size = new System.Drawing.Size(95, 55); + this.btnUpdate.TabIndex = 8; + this.btnUpdate.Text = "Update selected"; + this.btnUpdate.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnUpdate.UseVisualStyleBackColor = true; + this.btnUpdate.Click += new System.EventHandler(this.btnUpdate_Click); + // + // btnCompareTableData + // + this.btnCompareTableData.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnCompareTableData.Enabled = false; + this.btnCompareTableData.Image = global::OpenDBDiff.Properties.Resources.table_analysis; + this.btnCompareTableData.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnCompareTableData.Location = new System.Drawing.Point(3, 308); + this.btnCompareTableData.Name = "btnCompareTableData"; + this.btnCompareTableData.Size = new System.Drawing.Size(95, 55); + this.btnCompareTableData.TabIndex = 9; + this.btnCompareTableData.Text = "Compare data"; + this.btnCompareTableData.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnCompareTableData.UseVisualStyleBackColor = true; + this.btnCompareTableData.Click += new System.EventHandler(this.btnCompareTableData_Click); + // + // btnUpdateAll + // + this.btnUpdateAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btnUpdateAll.Enabled = false; + this.btnUpdateAll.Image = global::OpenDBDiff.Properties.Resources.database_refresh; + this.btnUpdateAll.ImageAlign = System.Drawing.ContentAlignment.TopCenter; + this.btnUpdateAll.Location = new System.Drawing.Point(3, 396); + this.btnUpdateAll.Margin = new System.Windows.Forms.Padding(3, 30, 3, 3); + this.btnUpdateAll.Name = "btnUpdateAll"; + this.btnUpdateAll.Size = new System.Drawing.Size(95, 55); + this.btnUpdateAll.TabIndex = 10; + this.btnUpdateAll.Text = "Update all"; + this.btnUpdateAll.TextAlign = System.Drawing.ContentAlignment.BottomCenter; + this.btnUpdateAll.UseVisualStyleBackColor = true; + this.btnUpdateAll.Click += new System.EventHandler(this.btnUpdateAll_Click); + // + // btnNewProject + // + this.btnNewProject.BackColor = System.Drawing.SystemColors.ButtonFace; + this.btnNewProject.Image = global::OpenDBDiff.Properties.Resources.new_window; + this.btnNewProject.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnNewProject.Location = new System.Drawing.Point(7, 60); + this.btnNewProject.Name = "btnNewProject"; + this.btnNewProject.Size = new System.Drawing.Size(113, 33); + this.btnNewProject.TabIndex = 15; + this.btnNewProject.Text = "New project"; + this.btnNewProject.UseVisualStyleBackColor = false; + this.btnNewProject.Click += new System.EventHandler(this.btnNewProject_Click); + // + // btnSaveProject + // + this.btnSaveProject.BackColor = System.Drawing.SystemColors.ButtonFace; + this.btnSaveProject.Image = global::OpenDBDiff.Properties.Resources.diskette; + this.btnSaveProject.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnSaveProject.Location = new System.Drawing.Point(7, 99); + this.btnSaveProject.Name = "btnSaveProject"; + this.btnSaveProject.Size = new System.Drawing.Size(113, 33); + this.btnSaveProject.TabIndex = 13; + this.btnSaveProject.Text = "Save project"; + this.btnSaveProject.UseVisualStyleBackColor = false; + this.btnSaveProject.Click += new System.EventHandler(this.btnSaveProject_Click); + // + // btnProject + // + this.btnProject.BackColor = System.Drawing.SystemColors.ButtonFace; + this.btnProject.Image = global::OpenDBDiff.Properties.Resources.folder; + this.btnProject.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft; + this.btnProject.Location = new System.Drawing.Point(7, 21); + this.btnProject.Name = "btnProject"; + this.btnProject.Size = new System.Drawing.Size(113, 33); + this.btnProject.TabIndex = 12; + this.btnProject.Text = "Open project"; + this.btnProject.UseVisualStyleBackColor = false; + this.btnProject.Click += new System.EventHandler(this.btnProject_Click); + // + // toolOpenProject + // + this.toolOpenProject.Image = global::OpenDBDiff.Properties.Resources.folder; + this.toolOpenProject.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolOpenProject.Name = "toolOpenProject"; + this.toolOpenProject.Size = new System.Drawing.Size(96, 22); + this.toolOpenProject.Text = "&Open Project"; + // + // toolNewProject + // + this.toolNewProject.Image = global::OpenDBDiff.Properties.Resources.new_window; + this.toolNewProject.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolNewProject.Name = "toolNewProject"; + this.toolNewProject.Size = new System.Drawing.Size(91, 22); + this.toolNewProject.Text = "&New Project"; + // + // toolSaveProject + // + this.toolSaveProject.Image = global::OpenDBDiff.Properties.Resources.diskette; + this.toolSaveProject.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolSaveProject.Name = "toolSaveProject"; + this.toolSaveProject.Size = new System.Drawing.Size(91, 22); + this.toolSaveProject.Text = "&Save Project"; + // + // schemaTreeView1 + // + this.schemaTreeView1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.schemaTreeView1.LeftDatabase = null; + this.schemaTreeView1.Location = new System.Drawing.Point(7, 10); + this.schemaTreeView1.Name = "schemaTreeView1"; + this.schemaTreeView1.RightDatabase = null; + this.schemaTreeView1.ShowChangedItems = true; + this.schemaTreeView1.ShowMissingItems = true; + this.schemaTreeView1.ShowNewItems = true; + this.schemaTreeView1.ShowUnchangedItems = true; + this.schemaTreeView1.Size = new System.Drawing.Size(322, 429); + this.schemaTreeView1.TabIndex = 0; + // + // MainForm + // + this.AcceptButton = this.btnCompare; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(940, 658); + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.PanelActions); + this.Controls.Add(this.PanelGlobal); + this.Controls.Add(this.toolMenu); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "MainForm"; + this.Text = "OpenDBDiff"; + this.WindowState = System.Windows.Forms.FormWindowState.Maximized; + this.Load += new System.EventHandler(this.MainForm_Load); + this.tabControl1.ResumeLayout(false); + this.tabPage2.ResumeLayout(false); + this.tabControl2.ResumeLayout(false); + this.tabPage4.ResumeLayout(false); + this.tabPage5.ResumeLayout(false); + this.tabPage6.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.tabPage3.ResumeLayout(false); + this.tabPage3.PerformLayout(); + this.PanelGlobal.ResumeLayout(false); + this.PanelGlobal.PerformLayout(); + this.tableLayoutPanel1.ResumeLayout(false); + this.toolMenu.ResumeLayout(false); + this.toolMenu.PerformLayout(); + this.PanelActions.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label lblMessage; + private TabControl tabControl1; + private TabPage tabPage1; + private Button btnCompare; + private Button btnSaveAs; + private SaveFileDialog saveFileDialog1; + private Button btnCopy; + private Button btnUpdate; + private Button btnUpdateAll; + private Button btnOptions; + private TabPage tabPage2; + private SchemaTreeView schemaTreeView1; + private GroupBox groupBox1; + private TabPage tabPage3; + private TextBox textBox1; + private Panel panel1; + private Scintilla txtSyncScript; + private Panel PanelGlobal; + private Panel LeftDatabasePanel; + private Panel RightDatabasePanel; + private GroupBox groupBox2; + private Panel panel3; + private Panel panel4; + private Panel panel5; + private Label label1; + private Label label3; + private Label label2; + private TabControl tabControl2; + private TabPage tabPage4; + private TabPage tabPage5; + private Scintilla txtNewObject; + private Scintilla txtOldObject; + private Button btnSaveProject; + private Button btnProject; + private Button btnNewProject; + private Button btnCompareTableData; + private TabPage tabPage6; + private Scintilla txtDiff; + private ToolStrip toolMenu; + private ToolStripButton toolOpenProject; + private ToolStripButton toolNewProject; + private ToolStripButton toolSaveProject; + private ToolStripComboBox toolProjectTypes; + private FlowLayoutPanel PanelActions; + private ToolStripLabel toolLblProjectType; + private TableLayoutPanel tableLayoutPanel1; + private ToolStripSeparator toolStripSeparator1; + private Button SwapButton; + private ToolTip toolTip1; + } +} diff --git a/OpenDBDiff/UI/MainForm.cs b/OpenDBDiff/UI/MainForm.cs new file mode 100644 index 0000000..ab28c96 --- /dev/null +++ b/OpenDBDiff/UI/MainForm.cs @@ -0,0 +1,686 @@ +using DiffPlex; +using DiffPlex.DiffBuilder; +using DiffPlex.DiffBuilder.Model; +using Essy.Tools.InputBox; +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Misc; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.Abstractions.Ui; +using OpenDBDiff.Extensions; +using OpenDBDiff.Settings; +using ScintillaNET; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + public partial class MainForm : Form + { + private Project ActiveProject; + private IFront LeftDatabaseSelector; + private IFront RightDatabaseSelector; + private IOption Options; + private List _selectedSchemas = new List(); + + private List ProjectHandlers = new List(); + private IProjectHandler ProjectSelectorHandler; + + public MainForm() + { + InitializeComponent(); + + this.Text = string.Concat(nameof(OpenDBDiff), " v", Assembly.GetExecutingAssembly().GetName().Version.ToString()); + } + + private void StartComparison() + { + ProgressForm progress = null; + string errorLocation = null; + try + { + if ((!String.IsNullOrEmpty(ProjectSelectorHandler.GetSourceDatabaseName()) && + (!String.IsNullOrEmpty(ProjectSelectorHandler.GetDestinationDatabaseName())))) + { + Options = Options ?? this.ProjectSelectorHandler.GetDefaultProjectOptions(); + var leftGenerator = this.ProjectSelectorHandler.SetSourceGenerator(LeftDatabaseSelector.ConnectionString, Options); + var rightGenerator = this.ProjectSelectorHandler.SetDestinationGenerator(RightDatabaseSelector.ConnectionString, Options); + IDatabaseComparer databaseComparer = this.ProjectSelectorHandler.GetDatabaseComparer(); + + var leftPair = new KeyValuePair(LeftDatabaseSelector.ToString(), leftGenerator); + var rightPair = new KeyValuePair(RightDatabaseSelector.ToString(), rightGenerator); + + // The progress form will execute the comparer to generate action scripts to migrate the right to the left + // Hence, inside the ProgressForm and deeper, right is the origin and left is the destination + progress = new ProgressForm(rightPair, leftPair, databaseComparer); + progress.ShowDialog(this); + if (progress.Error != null) + { + throw new SchemaException(progress.Error.Message, progress.Error); + } + + txtSyncScript.LexerLanguage = this.ProjectSelectorHandler.GetScriptLanguage(); + txtSyncScript.ReadOnly = false; + errorLocation = "Generating Synchronized Script"; + txtSyncScript.Text = progress.Destination.ToSqlDiff(this._selectedSchemas).ToSQL(); + txtSyncScript.ReadOnly = true; + txtSyncScript.SetMarginWidth(); + + // Notice again that left is destination, because we generated scripts to migrate the right database to the left. + schemaTreeView1.LeftDatabase = progress.Destination; + schemaTreeView1.RightDatabase = progress.Origin; + + schemaTreeView1.OnSelectItem += new SchemaTreeView.SchemaHandler(schemaTreeView1_OnSelectItem); + schemaTreeView1_OnSelectItem(schemaTreeView1.SelectedNode); + textBox1.Text = progress.Origin.ActionMessage.Message; + + btnCopy.Enabled = true; + btnSaveAs.Enabled = true; + btnUpdateAll.Enabled = true; + } + else + MessageBox.Show(Owner, "Please select a valid connection string", "ERROR", MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + catch (Exception ex) + { + if (errorLocation == null && progress != null) + { + errorLocation = String.Format("{0} (while {1})", progress.ErrorLocation, progress.ErrorMostRecentProgress ?? "initializing"); + } + + throw new SchemaException("Error " + (errorLocation ?? " Comparing Databases"), ex); + } + } + + private void schemaTreeView1_OnSelectItem(string nodeFullName) + { + try + { + txtNewObject.ReadOnly = false; + txtOldObject.ReadOnly = false; + txtDiff.ReadOnly = false; + + txtNewObject.ClearAll(); + txtOldObject.ClearAll(); + txtDiff.ClearAll(); + + if (string.IsNullOrEmpty(nodeFullName)) + return; + + IDatabase database = (IDatabase)schemaTreeView1.LeftDatabase; + + ObjectStatus? status; + + status = database.Find(nodeFullName)?.Status; + if (status.HasValue && status.Value != ObjectStatus.Drop) + { + txtNewObject.Text = database.Find(nodeFullName).ToSql(); + txtNewObject.SetMarginWidth(); + if (database.Find(nodeFullName).Status == ObjectStatus.Original) + { + btnUpdate.Enabled = false; + } + else + { + btnUpdate.Enabled = true; + } + if (database.Find(nodeFullName).ObjectType == ObjectType.Table) + { + btnCompareTableData.Enabled = true; + } + else + { + btnCompareTableData.Enabled = false; + } + } + + database = (IDatabase)schemaTreeView1.RightDatabase; + status = database.Find(nodeFullName)?.Status; + if (status.HasValue && status.Value != ObjectStatus.Create) + { + txtOldObject.Text = database.Find(nodeFullName).ToSql(); + txtOldObject.SetMarginWidth(); + } + txtNewObject.ReadOnly = true; + txtOldObject.ReadOnly = true; + + var diff = (new SideBySideDiffBuilder(new Differ())).BuildDiffModel(txtOldObject.Text, txtNewObject.Text); + + var sb = new StringBuilder(); + DiffPiece newLine, oldLine; + var markers = new Marker[] { txtDiff.Markers[0], txtDiff.Markers[1], txtDiff.Markers[2], txtDiff.Markers[3] }; + foreach (var marker in markers) marker.Symbol = MarkerSymbol.Background; + markers[0].SetBackColor(Color.LightGreen); // Imaginary (?) + markers[1].SetBackColor(Color.LightCyan); // Modified + markers[2].SetBackColor(Color.LightSalmon); // Deleted + markers[3].SetBackColor(Color.PeachPuff); // Modified + + var indexes = new List[] { new List(), new List(), new List(), new List() }; + var index = 0; + for (var i = 0; i < Math.Max(diff.NewText.Lines.Count, diff.OldText.Lines.Count); i++) + { + newLine = i < diff.NewText.Lines.Count ? diff.NewText.Lines[i] : null; + oldLine = i < diff.OldText.Lines.Count ? diff.OldText.Lines[i] : null; + if (oldLine.Type == ChangeType.Inserted) + { + sb.AppendLine(" " + oldLine.Text); + } + else if (oldLine.Type == ChangeType.Deleted) + { + sb.AppendLine("- " + oldLine.Text); + indexes[2].Add(index); + } + else if (oldLine.Type == ChangeType.Modified) + { + sb.AppendLine("* " + newLine.Text); + indexes[1].Add(index++); + sb.AppendLine("* " + oldLine.Text); + indexes[3].Add(index); + } + else if (oldLine.Type == ChangeType.Imaginary) + { + sb.AppendLine("+ " + newLine.Text); + indexes[0].Add(index); + } + else if (oldLine.Type == ChangeType.Unchanged) + { + sb.AppendLine(" " + oldLine.Text); + } + index++; + } + txtDiff.Text = sb.ToString(); + txtDiff.SetMarginWidth(); + for (var i = 0; i < 4; i++) + { + foreach (var ind in indexes[i]) + { + txtDiff.Lines[ind].MarkerAdd(i); + } + } + } + finally + { + txtNewObject.ReadOnly = true; + txtOldObject.ReadOnly = true; + txtDiff.ReadOnly = true; + } + } + + private void tabControl1_SelectedIndexChanged(object sender, EventArgs e) + { + // Refresh script when tab is shown + if (tabControl1.SelectedIndex != 1) + { + return; + } + + var db = schemaTreeView1.LeftDatabase as IDatabase; + if (db != null) + { + this._selectedSchemas = this.schemaTreeView1.GetCheckedSchemas(); + this.txtSyncScript.ReadOnly = false; + this.txtSyncScript.Text = db.ToSqlDiff(this._selectedSchemas).ToSQL(); + this.txtSyncScript.ReadOnly = true; + txtSyncScript.SetMarginWidth(); + } + } + + private void btnCompareTableData_Click(object sender, EventArgs e) + { + TreeView tree = (TreeView)schemaTreeView1.Controls.Find("treeView1", true)[0]; + ISchemaBase selected = (ISchemaBase)tree.SelectedNode.Tag; + DataCompareForm dataCompare = new DataCompareForm(selected, LeftDatabaseSelector.ConnectionString, RightDatabaseSelector.ConnectionString); + dataCompare.ShowDialog(); + } + + private void btnCompare_Click(object sender, EventArgs e) + { + string errorLocation = "Processing Compare"; + try + { + Cursor = Cursors.WaitCursor; + _selectedSchemas = schemaTreeView1.GetCheckedSchemas(); + StartComparison(); + schemaTreeView1.SetCheckedSchemas(_selectedSchemas); + errorLocation = "Saving Connections"; + Project.SaveLastConfiguration(LeftDatabaseSelector.ConnectionString, RightDatabaseSelector.ConnectionString); + } + catch (Exception ex) + { + Cursor = Cursors.Default; + HandleException(errorLocation, ex); + } + finally + { + Cursor = Cursors.Default; + } + } + + private void HandleException(string errorLocation, Exception ex) + { + var errorDialog = new ErrorForm(ex); + errorDialog.ShowDialog(this); + } + + private void UnloadProjectHandler() + { + if (ProjectSelectorHandler != null) + { + LeftDatabasePanel.Controls.Remove((Control)LeftDatabaseSelector); + RightDatabasePanel.Controls.Remove((Control)RightDatabaseSelector); + ProjectSelectorHandler.Unload(); + ProjectSelectorHandler = null; + } + } + + private void LoadProjectHandler(IProjectHandler projectHandler) + { + UnloadProjectHandler(); + ProjectSelectorHandler = projectHandler; + LeftDatabaseSelector = ProjectSelectorHandler.CreateSourceSelector(); + RightDatabaseSelector = ProjectSelectorHandler.CreateDestinationSelector(); + LeftDatabasePanel.Controls.Add(LeftDatabaseSelector.Control); + RightDatabasePanel.Controls.Add(RightDatabaseSelector.Control); + } + + private void LoadProjectHandler() where T : IProjectHandler, new() + { + var handler = new T(); + LoadProjectHandler(handler); + } + + private void optSybase_CheckedChanged(object sender, EventArgs e) + { + /*if (optSybase.Checked) + { + this.mySqlConnectFront2 = new OpenDBDiff.Schema.Sybase.Front.AseConnectFront(); + this.mySqlConnectFront1 = new OpenDBDiff.Schema.Sybase.Front.AseConnectFront(); + this.mySqlConnectFront1.Location = new System.Drawing.Point(5, 19); + this.mySqlConnectFront1.Name = "mySqlConnectFront1"; + this.mySqlConnectFront1.Size = new System.Drawing.Size(410, 214); + this.mySqlConnectFront1.TabIndex = 10; + this.mySqlConnectFront2.Location = new System.Drawing.Point(5, 19); + this.mySqlConnectFront2.Name = "mySqlConnectFront2"; + this.mySqlConnectFront2.Size = new System.Drawing.Size(410, 214); + this.mySqlConnectFront2.TabIndex = 10; + this.mySqlConnectFront1.Visible = true; + this.mySqlConnectFront2.Visible = true; + this.groupBox3.Controls.Add((System.Windows.Forms.Control)this.mySqlConnectFront2); + this.groupBox2.Controls.Add((System.Windows.Forms.Control)this.mySqlConnectFront1); + } + else + { + this.groupBox2.Controls.Remove((System.Windows.Forms.Control)this.mySqlConnectFront1); + this.groupBox3.Controls.Remove((System.Windows.Forms.Control)this.mySqlConnectFront2); + }*/ + } + + private void btnSaveAs_Click(object sender, EventArgs e) + { + try + { + if (!string.IsNullOrEmpty(saveFileDialog1.FileName) && !string.IsNullOrEmpty(Path.GetDirectoryName(saveFileDialog1.FileName))) + { + saveFileDialog1.InitialDirectory = Path.GetDirectoryName(saveFileDialog1.FileName); + saveFileDialog1.FileName = Path.GetFileName(saveFileDialog1.FileName); + } + saveFileDialog1.ShowDialog(this); + if (!String.IsNullOrEmpty(saveFileDialog1.FileName)) + { + var db = schemaTreeView1.LeftDatabase as IDatabase; + if (db != null) + { + using (StreamWriter writer = new StreamWriter(saveFileDialog1.FileName, false)) + { + this._selectedSchemas = this.schemaTreeView1.GetCheckedSchemas(); + writer.Write(db.ToSqlDiff(this._selectedSchemas).ToSQL()); + writer.Close(); + } + } + } + } + catch (Exception ex) + { + HandleException("Save Script As", ex); + } + } + + private void btnCopy_Click(object sender, EventArgs e) + { + try + { + System.Windows.Forms.Clipboard.SetText(txtSyncScript.Text); + } + catch (Exception ex) + { + MessageBox.Show("An error ocurred while trying to copying the text to the clipboard"); + Trace.WriteLine("ERROR: +" + ex.Message); + } + } + + private void btnUpdate_Click(object sender, EventArgs e) + { + TreeView tree = (TreeView)schemaTreeView1.Controls.Find("treeView1", true)[0]; + TreeNode dbArm = tree.Nodes[0]; + var sb = new StringBuilder(); + + foreach (TreeNode node in dbArm.Nodes) + { + if (node.Nodes.Count != 0) + { + foreach (TreeNode subnode in node.Nodes) + { + if (subnode.Checked) + { + //ISchemaBase selected = (ISchemaBase)tree.SelectedNode.Tag; + ISchemaBase selected = (ISchemaBase)subnode.Tag; + + IDatabase database = (IDatabase)schemaTreeView1.LeftDatabase; + + if (database.Find(selected.FullName) != null) + { + switch (selected.ObjectType) + { + case ObjectType.Table: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.AlterWhitespace: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for table '{selected.Name}'"); break; + } + } + break; + + case ObjectType.StoredProcedure: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.AlterWhitespace: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for stored procedure '{selected.Name}'"); break; + } + } + break; + + case ObjectType.Function: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.AlterWhitespace: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter | ObjectStatus.AlterBody: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for function '{selected.Name}'"); break; + } + } + break; + + case ObjectType.View: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.AlterWhitespace: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter | ObjectStatus.AlterBody: sb.Append(Updater.alter(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for view '{selected.Name}'"); break; + } + } + break; + + default: + { + switch (selected.Status) + { + case ObjectStatus.Create: sb.Append(Updater.addNew(selected, RightDatabaseSelector.ConnectionString)); break; + default: sb.AppendLine($"Nothing could be found to do for '{selected.Name}'"); break; + } + } + break; + } + } + } + } + } + } + + if (sb.Length == 0) + MessageBox.Show(this, "All successful.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show(this, sb.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + + if (Options.Comparison.ReloadComparisonOnUpdate) + { + StartComparison(); + } + + btnUpdate.Enabled = false; + } + + private void btnUpdateAll_Click(object sender, EventArgs e) + { + if (MessageBox.Show("Are you sure you want to update all?", "Confirm update", MessageBoxButtons.OKCancel) == DialogResult.OK) + { + TreeView tree = (TreeView)schemaTreeView1.Controls.Find("treeView1", true)[0]; + TreeNode database = tree.Nodes[0]; + var sb = new StringBuilder(); + foreach (TreeNode tn in database.Nodes) + { + foreach (TreeNode inner in tn.Nodes) + { + if (inner.Tag != null) + { + ISchemaBase item = (ISchemaBase)inner.Tag; + switch (item.Status) + { + case ObjectStatus.Create: sb.Append(Updater.createNew(item, RightDatabaseSelector.ConnectionString)); break; + case ObjectStatus.Alter: sb.Append(Updater.alter(item, RightDatabaseSelector.ConnectionString)); break; + } + } + } + } + + if (sb.Length == 0) + MessageBox.Show(this, "Update successful.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + else + MessageBox.Show(this, sb.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + + StartComparison(); + } + } + + private void btnOptions_Click(object sender, EventArgs e) + { + Options = Options ?? ProjectSelectorHandler.GetDefaultProjectOptions(); + OptionForm form = new OptionForm(this.ProjectSelectorHandler, Options); + form.OptionSaved += new OptionControl.OptionEventHandler((option) => Options = option); + form.ShowDialog(this); + } + + private void LoadProjectHandlers() + { + ProjectHandlers.Clear(); + toolProjectTypes.Items.Clear(); + + ProjectHandlers.Add(new SqlServer.Ui.SQLServerProjectHandler()); + } + + private void MainForm_Load(object sender, EventArgs e) + { + LoadProjectHandlers(); + foreach (var projectHandler in ProjectHandlers) + { + toolProjectTypes.Items.Add(projectHandler); + } + + if (toolProjectTypes.SelectedItem == null && toolProjectTypes.Items.Count > 0) + { + toolProjectTypes.SelectedIndex = 0; + } + + var LastConfiguration = Project.GetLastConfiguration(); + if (LastConfiguration != null) + { + if (LeftDatabaseSelector != null) + LeftDatabaseSelector.ConnectionString = LastConfiguration.ConnectionStringSource; + if (RightDatabaseSelector != null) + RightDatabaseSelector.ConnectionString = LastConfiguration.ConnectionStringDestination; + } + + txtNewObject.LexerLanguage = "mssql"; + txtNewObject.ReadOnly = false; + txtOldObject.LexerLanguage = "mssql"; + txtOldObject.ReadOnly = false; + txtDiff.LexerLanguage = "mssql"; + txtDiff.ReadOnly = false; + txtDiff.Margins[0].Width = 20; + + Scintilla[] scintillaControls = new Scintilla[] { txtNewObject, txtOldObject, txtDiff, txtSyncScript }; + foreach (var scintilla in scintillaControls) + { + scintilla.InitializeScintillaControls(); + } + txtSyncScript.Text = ""; + txtSyncScript.SetMarginWidth(); + } + + private void btnSaveProject_Click(object sender, EventArgs e) + { + try + { + if (ActiveProject == null) + { + ActiveProject = new Project + { + ConnectionStringSource = ProjectSelectorHandler.GetSourceConnectionString(), + ConnectionStringDestination = ProjectSelectorHandler.GetDestinationConnectionString(), + ProjectName = String.Format( + "[{0}].[{1}] - [{2}].[{3}]", + ProjectSelectorHandler.GetSourceServerName(), + ProjectSelectorHandler.GetSourceDatabaseName(), + ProjectSelectorHandler.GetDestinationServerName(), + ProjectSelectorHandler.GetDestinationDatabaseName() + ), + Options = Options ?? ProjectSelectorHandler.GetDefaultProjectOptions(), + Type = Project.ProjectType.SQLServer + }; + + var newProjectName = InputBox.ShowInputBox("Enter the project name.", ActiveProject.ProjectName.Trim(), false)?.Trim(); + + if (string.IsNullOrWhiteSpace(newProjectName)) + return; + + ActiveProject.ProjectName = newProjectName; + } + Project.Upsert(ActiveProject); + } + catch (Exception ex) + { + HandleException("Saving Project", ex); + } + } + + private void btnProject_Click(object sender, EventArgs e) + { + try + { + var projects = Project.GetAll(); + if (projects.Any()) + { + var form = new ListProjectsForm(projects); + form.OnSelect += new ListProjectHandler(form_OnSelect); + form.OnDelete += new ListProjectHandler(form_OnDelete); + form.OnRename += new ListProjectHandler(form_OnRename); + form.ShowDialog(this); + } + else + MessageBox.Show(this, "There are currently no saved projects.", "Projects", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + catch (Exception ex) + { + HandleException("Opening Project", ex); + } + } + + private void form_OnRename(Project itemSelected) + { + try + { + Project.Upsert(itemSelected); + } + catch (Exception ex) + { + HandleException("Renaming Project", ex); + } + } + + private void form_OnDelete(Project itemSelected) + { + try + { + Project.Delete(itemSelected.Id); + if ((ActiveProject?.Id).HasValue && ActiveProject.Id == itemSelected.Id) + { + ActiveProject = null; + LeftDatabaseSelector.ConnectionString = ""; + RightDatabaseSelector.ConnectionString = ""; + } + } + catch (Exception ex) + { + HandleException("Deleting Project", ex); + } + } + + private void form_OnSelect(Project itemSelected) + { + try + { + if (itemSelected != null) + { + ActiveProject = itemSelected; + LeftDatabaseSelector.ConnectionString = itemSelected.ConnectionStringSource; + RightDatabaseSelector.ConnectionString = itemSelected.ConnectionStringDestination; + } + } + catch (Exception ex) + { + HandleException("Selecting Project", ex); + } + } + + private void btnNewProject_Click(object sender, EventArgs e) + { + LeftDatabaseSelector.ConnectionString = ""; + RightDatabaseSelector.ConnectionString = ""; + ActiveProject = null; + } + + private void toolProjectTypes_SelectedIndexChanged(object sender, EventArgs e) + { + UnloadProjectHandler(); + if (toolProjectTypes.SelectedItem != null) + { + var handler = toolProjectTypes.SelectedItem as IProjectHandler; + LoadProjectHandler(handler); + } + } + + private void SwapButton_Click(object sender, EventArgs e) + { + var temp = RightDatabaseSelector.Clone() as IFront; + RightDatabaseSelector.SetSettingsFrom(LeftDatabaseSelector); + LeftDatabaseSelector.SetSettingsFrom(temp); + } + } +} diff --git a/OpenDBDiff/UI/MainForm.resx b/OpenDBDiff/UI/MainForm.resx new file mode 100644 index 0000000..4895a61 --- /dev/null +++ b/OpenDBDiff/UI/MainForm.resx @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, -2 + + + 258, -2 + + + 153, -2 + + + 36 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/UI/OptionForm.Designer.cs b/OpenDBDiff/UI/OptionForm.Designer.cs new file mode 100644 index 0000000..763d9b4 --- /dev/null +++ b/OpenDBDiff/UI/OptionForm.Designer.cs @@ -0,0 +1,89 @@ +using OpenDBDiff.Abstractions.Ui; +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + partial class OptionForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(OptionForm)); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnApply = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(433, 450); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 5; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); + // + // btnApply + // + this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.btnApply.Location = new System.Drawing.Point(514, 450); + this.btnApply.Name = "btnApply"; + this.btnApply.Size = new System.Drawing.Size(75, 23); + this.btnApply.TabIndex = 4; + this.btnApply.Text = "Apply"; + this.btnApply.UseVisualStyleBackColor = true; + this.btnApply.Click += new System.EventHandler(this.btnApply_Click); + // + // OptionForm + // + this.AcceptButton = this.btnApply; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(592, 477); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnApply); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "OptionForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Comparison options"; + this.ResumeLayout(false); + + } + + #endregion + + private OptionControl sqlOptionsFront1; + private Button btnCancel; + private Button btnApply; + + } +} diff --git a/OpenDBDiff/UI/OptionForm.cs b/OpenDBDiff/UI/OptionForm.cs new file mode 100644 index 0000000..9ae71fb --- /dev/null +++ b/OpenDBDiff/UI/OptionForm.cs @@ -0,0 +1,55 @@ +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.Abstractions.Ui; +using System; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + public partial class OptionForm : Form + { + private IProjectHandler projectSelectorHandler; + private IOption SqlFilter; + + public event OptionControl.OptionEventHandler OptionSaved; + + public OptionForm(IProjectHandler projectSelectorHandler, IOption filter) + { + this.projectSelectorHandler = projectSelectorHandler; + sqlOptionsFront1 = projectSelectorHandler.CreateOptionControl(); + sqlOptionsFront1.OptionSaved += SqlOptionsFront1_OptionSaved; + SqlFilter = filter; + sqlOptionsFront1.Load(filter); + + InitializeComponent(); + + this.SuspendLayout(); + + this.sqlOptionsFront1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.sqlOptionsFront1.Location = new System.Drawing.Point(3, 3); + this.sqlOptionsFront1.Name = "sqlOptionsFront1"; + this.sqlOptionsFront1.Size = new System.Drawing.Size(586, 440); + this.sqlOptionsFront1.TabIndex = 0; + this.Controls.Add(this.sqlOptionsFront1); + + this.ResumeLayout(); + } + + private void SqlOptionsFront1_OptionSaved(IOption option) + { + OptionSaved?.Invoke(option); + } + + private void btnApply_Click(object sender, EventArgs e) + { + sqlOptionsFront1.Save(); + this.Close(); + } + + private void btnCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/OpenDBDiff/UI/OptionForm.resx b/OpenDBDiff/UI/OptionForm.resx new file mode 100644 index 0000000..4bf5cc5 --- /dev/null +++ b/OpenDBDiff/UI/OptionForm.resx @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/UI/ProgressForm.Designer.cs b/OpenDBDiff/UI/ProgressForm.Designer.cs new file mode 100644 index 0000000..9b40a23 --- /dev/null +++ b/OpenDBDiff/UI/ProgressForm.Designer.cs @@ -0,0 +1,132 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + partial class ProgressForm + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProgressForm)); + this.gradientPanel1 = new System.Windows.Forms.Panel(); + this.lblName = new System.Windows.Forms.Label(); + this.panel1 = new System.Windows.Forms.Panel(); + this.originProgressControl = new OpenDBDiff.UI.DatabaseProgressControl(); + this.destinationProgressControl = new OpenDBDiff.UI.DatabaseProgressControl(); + this.gradientPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // gradientPanel1 + // + this.gradientPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.gradientPanel1.Controls.Add(this.lblName); + this.gradientPanel1.Location = new System.Drawing.Point(0, 0); + this.gradientPanel1.Name = "gradientPanel1"; + this.gradientPanel1.Size = new System.Drawing.Size(499, 58); + this.gradientPanel1.TabIndex = 27; + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Font = new System.Drawing.Font("Arial", 15.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblName.Location = new System.Drawing.Point(12, 16); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(200, 24); + this.lblName.TabIndex = 24; + this.lblName.Text = "Compare Progress"; + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.Controls.Add(this.destinationProgressControl); + this.panel1.Controls.Add(this.originProgressControl); + this.panel1.Location = new System.Drawing.Point(0, 57); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(499, 173); + this.panel1.TabIndex = 30; + // + // originProgressControl + // + this.originProgressControl.BackColor = System.Drawing.Color.WhiteSmoke; + this.originProgressControl.DatabaseName = "Source:"; + this.originProgressControl.Location = new System.Drawing.Point(12, 92); + this.originProgressControl.Maximum = 100; + this.originProgressControl.Message = ""; + this.originProgressControl.Name = "sourceProgressControl"; + this.originProgressControl.Size = new System.Drawing.Size(472, 64); + this.originProgressControl.TabIndex = 35; + this.originProgressControl.Value = 0; + // + // destinationProgressControl + // + this.destinationProgressControl.BackColor = System.Drawing.Color.WhiteSmoke; + this.destinationProgressControl.DatabaseName = "Destination:"; + this.destinationProgressControl.Location = new System.Drawing.Point(12, 15); + this.destinationProgressControl.Maximum = 100; + this.destinationProgressControl.Message = ""; + this.destinationProgressControl.Name = "destinationProgressControl"; + this.destinationProgressControl.Size = new System.Drawing.Size(472, 64); + this.destinationProgressControl.TabIndex = 34; + this.destinationProgressControl.Value = 0; + // + // ProgressForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Control; + this.ClientSize = new System.Drawing.Size(496, 230); + this.Controls.Add(this.panel1); + this.Controls.Add(this.gradientPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProgressForm"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Running"; + this.Activated += new System.EventHandler(this.ProgressForm_Activated); + this.gradientPanel1.ResumeLayout(false); + this.gradientPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private Panel gradientPanel1; + private Label lblName; + private Panel panel1; + private DatabaseProgressControl destinationProgressControl; + private DatabaseProgressControl originProgressControl; + } +} diff --git a/OpenDBDiff/UI/ProgressForm.cs b/OpenDBDiff/UI/ProgressForm.cs new file mode 100644 index 0000000..6d51f8f --- /dev/null +++ b/OpenDBDiff/UI/ProgressForm.cs @@ -0,0 +1,126 @@ +using OpenDBDiff.Abstractions.Schema.Events; +using OpenDBDiff.Abstractions.Schema.Model; +using OpenDBDiff.Abstractions.Ui; +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + public partial class ProgressForm : Form + { + private IGenerator OriginGenerator; + private IGenerator DestinationGenerator; + private bool IsProcessing = false; + private IDatabase originClone = null; + private readonly IDatabaseComparer Comparer; + + // TODO: thread-safe error reporting + + public ProgressForm(KeyValuePair originDatabase, KeyValuePair destinationDatabase, IDatabaseComparer comparer) + { + InitializeComponent(); + + Origin = null; + Destination = null; + originProgressControl.Maximum = originDatabase.Value.GetMaxValue(); + originProgressControl.DatabaseName = originDatabase.Key; + this.OriginGenerator = originDatabase.Value; + + destinationProgressControl.Maximum = destinationDatabase.Value.GetMaxValue(); + destinationProgressControl.DatabaseName = destinationDatabase.Key; + this.DestinationGenerator = destinationDatabase.Value; + + this.Comparer = comparer; + } + + public Abstractions.Schema.Model.IDatabase Origin { get; private set; } + + public Abstractions.Schema.Model.IDatabase Destination { get; private set; } + + public string ErrorLocation { get; private set; } + + public string ErrorMostRecentProgress { get; private set; } + + public Exception Error { get; private set; } + + private void btnOK_Click(object sender, EventArgs e) + { + this.Cursor = Cursors.WaitCursor; + this.Close(); + this.Cursor = Cursors.Default; + } + + private void ProgressForm_Activated(object sender, EventArgs e) + { + var handler = new ProgressEventHandler.ProgressHandler(genData2_OnProgress); + try + { + if (!IsProcessing) + { + this.Refresh(); + IsProcessing = false; + OriginGenerator.OnProgress += new ProgressEventHandler.ProgressHandler(genData1_OnProgress); + DestinationGenerator.OnProgress += handler; + + this.ErrorLocation = "Loading " + destinationProgressControl.DatabaseName; + Origin = OriginGenerator.Process(); + originProgressControl.Message = "Complete"; + originProgressControl.Value = OriginGenerator.GetMaxValue(); + + this.ErrorLocation = "Loading " + originProgressControl.DatabaseName; + Destination = DestinationGenerator.Process(); + + originClone = (IDatabase)Origin.Clone(null); + + this.ErrorLocation = "Comparing Databases"; + Destination = Comparer.Compare(Origin, Destination); + Origin = originClone; + + destinationProgressControl.Message = "Complete"; + destinationProgressControl.Value = DestinationGenerator.GetMaxValue(); + } + } + catch (Exception err) + { + this.Error = err; + } + finally + { + OriginGenerator.OnProgress -= handler; + DestinationGenerator.OnProgress -= handler; + this.Close(); + } + } + + private void genData2_OnProgress(ProgressEventArgs e) + { + if (e.Progress > -1 && destinationProgressControl.Value != e.Progress) + { + destinationProgressControl.Value = e.Progress; + } + + if (String.Compare(destinationProgressControl.Message, e.Message) != 0) + { + destinationProgressControl.Message = e.Message; + } + + this.ErrorMostRecentProgress = e.Message; + } + + private void genData1_OnProgress(ProgressEventArgs e) + { + if (e.Progress > -1 && originProgressControl.Value != e.Progress) + { + originProgressControl.Value = e.Progress; + } + + if (String.Compare(originProgressControl.Message, e.Message) != 0) + { + originProgressControl.Message = e.Message; + } + + this.ErrorMostRecentProgress = e.Message; + } + } +} diff --git a/OpenDBDiff/UI/ProgressForm.resx b/OpenDBDiff/UI/ProgressForm.resx new file mode 100644 index 0000000..4bf5cc5 --- /dev/null +++ b/OpenDBDiff/UI/ProgressForm.resx @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + + + \ No newline at end of file diff --git a/OpenDBDiff/UI/SchemaTreeView.Designer.cs b/OpenDBDiff/UI/SchemaTreeView.Designer.cs new file mode 100644 index 0000000..607e408 --- /dev/null +++ b/OpenDBDiff/UI/SchemaTreeView.Designer.cs @@ -0,0 +1,158 @@ +using System.ComponentModel; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + partial class SchemaTreeView + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SchemaTreeView)); + this.treeView1 = new System.Windows.Forms.TreeView(); + this.imageList1 = new System.Windows.Forms.ImageList(this.components); + this.chkOld = new System.Windows.Forms.CheckBox(); + this.chkNew = new System.Windows.Forms.CheckBox(); + this.chkDifferent = new System.Windows.Forms.CheckBox(); + this.chkShowUnchangedItems = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // treeView1 + // + this.treeView1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.treeView1.CheckBoxes = true; + this.treeView1.ImageIndex = 0; + this.treeView1.ImageList = this.imageList1; + this.treeView1.Location = new System.Drawing.Point(0, 50); + this.treeView1.Name = "treeView1"; + this.treeView1.SelectedImageIndex = 0; + this.treeView1.Size = new System.Drawing.Size(262, 150); + this.treeView1.TabIndex = 0; + this.treeView1.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterCheck); + this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect); + // + // imageList1 + // + this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); + this.imageList1.TransparentColor = System.Drawing.Color.Transparent; + this.imageList1.Images.SetKeyName(0, "Folder"); + this.imageList1.Images.SetKeyName(1, "Table"); + this.imageList1.Images.SetKeyName(2, "Procedure"); + this.imageList1.Images.SetKeyName(3, "User"); + this.imageList1.Images.SetKeyName(4, "Column"); + this.imageList1.Images.SetKeyName(5, "Index"); + this.imageList1.Images.SetKeyName(6, "Rol"); + this.imageList1.Images.SetKeyName(7, "Schema"); + this.imageList1.Images.SetKeyName(8, "View"); + this.imageList1.Images.SetKeyName(9, "Function"); + this.imageList1.Images.SetKeyName(10, "XMLSchema"); + this.imageList1.Images.SetKeyName(11, "Database"); + this.imageList1.Images.SetKeyName(12, "UDT"); + this.imageList1.Images.SetKeyName(13, "Assembly"); + this.imageList1.Images.SetKeyName(14, "PartitionFunction"); + this.imageList1.Images.SetKeyName(15, "PartitionScheme"); + // + // chkOld + // + this.chkOld.AutoSize = true; + this.chkOld.Checked = true; + this.chkOld.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkOld.Location = new System.Drawing.Point(141, 27); + this.chkOld.Name = "chkOld"; + this.chkOld.Size = new System.Drawing.Size(117, 17); + this.chkOld.TabIndex = 1; + this.chkOld.Text = "Show missing items"; + this.chkOld.UseVisualStyleBackColor = true; + this.chkOld.CheckedChanged += new System.EventHandler(this.FilterCheckbox_CheckedChanged); + // + // chkNew + // + this.chkNew.AutoSize = true; + this.chkNew.Checked = true; + this.chkNew.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkNew.Location = new System.Drawing.Point(4, 27); + this.chkNew.Name = "chkNew"; + this.chkNew.Size = new System.Drawing.Size(103, 17); + this.chkNew.TabIndex = 2; + this.chkNew.Text = "Show new items"; + this.chkNew.UseVisualStyleBackColor = true; + this.chkNew.CheckedChanged += new System.EventHandler(this.FilterCheckbox_CheckedChanged); + // + // chkDifferent + // + this.chkDifferent.AutoSize = true; + this.chkDifferent.Checked = true; + this.chkDifferent.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkDifferent.Location = new System.Drawing.Point(141, 4); + this.chkDifferent.Name = "chkDifferent"; + this.chkDifferent.Size = new System.Drawing.Size(125, 17); + this.chkDifferent.TabIndex = 3; + this.chkDifferent.Text = "Show changed items"; + this.chkDifferent.UseVisualStyleBackColor = true; + this.chkDifferent.CheckedChanged += new System.EventHandler(this.FilterCheckbox_CheckedChanged); + // + // chkShowUnchangedItems + // + this.chkShowUnchangedItems.AutoSize = true; + this.chkShowUnchangedItems.Checked = true; + this.chkShowUnchangedItems.CheckState = System.Windows.Forms.CheckState.Checked; + this.chkShowUnchangedItems.Location = new System.Drawing.Point(3, 4); + this.chkShowUnchangedItems.Name = "chkShowUnchangedItems"; + this.chkShowUnchangedItems.Size = new System.Drawing.Size(137, 17); + this.chkShowUnchangedItems.TabIndex = 4; + this.chkShowUnchangedItems.Text = "Show unchanged items"; + this.chkShowUnchangedItems.UseVisualStyleBackColor = true; + this.chkShowUnchangedItems.CheckedChanged += new System.EventHandler(this.FilterCheckbox_CheckedChanged); + // + // SchemaTreeView + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.chkShowUnchangedItems); + this.Controls.Add(this.chkDifferent); + this.Controls.Add(this.chkNew); + this.Controls.Add(this.chkOld); + this.Controls.Add(this.treeView1); + this.Name = "SchemaTreeView"; + this.Size = new System.Drawing.Size(266, 203); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private TreeView treeView1; + private CheckBox chkOld; + private CheckBox chkNew; + private CheckBox chkDifferent; + private ImageList imageList1; + private CheckBox chkShowUnchangedItems; + } +} diff --git a/OpenDBDiff/UI/SchemaTreeView.cs b/OpenDBDiff/UI/SchemaTreeView.cs new file mode 100644 index 0000000..afd1bd3 --- /dev/null +++ b/OpenDBDiff/UI/SchemaTreeView.cs @@ -0,0 +1,303 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Attributes; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace OpenDBDiff.UI +{ + public partial class SchemaTreeView : UserControl + { + private ISchemaBase databaseSource; + + public delegate void SchemaHandler(string ObjectFullName); + + public event SchemaHandler OnSelectItem; + + private bool busy = false; + + public SchemaTreeView() + { + InitializeComponent(); + } + + public ISchemaBase RightDatabase { get; set; } + + public ISchemaBase LeftDatabase + { + get { return databaseSource; } + set + { + databaseSource = value; + if (value != null) + { + RebuildSchemaTree(); + } + } + } + + public List GetCheckedSchemas() + { + List schemas = new List(); + if (treeView1.CheckBoxes) + { + GetCheckedNodesToList(schemas, treeView1.Nodes); + } + return schemas; + } + + public void SetCheckedSchemas(List schemas) + { + SetCheckedNodesFromList(schemas, treeView1.Nodes); + } + + private void GetCheckedNodesToList(List schemas, TreeNodeCollection nodes) + { + foreach (TreeNode node in nodes) + { + if (node.Tag != null) + { + if (node.Checked) + { + schemas.Add(node.Tag as ISchemaBase); + } + } + GetCheckedNodesToList(schemas, node.Nodes); + } + } + + private void SetCheckedNodesFromList(List schemas, TreeNodeCollection nodes) + { + foreach (TreeNode node in nodes) + { + if (node.Tag != null) + { + node.Checked = schemas.FirstOrDefault(sch => sch.Id == (node.Tag as ISchemaBase).Id) != null; + } + SetCheckedNodesFromList(schemas, node.Nodes); + } + } + + private void ReadProperties(Type item, TreeNodeCollection nodes, ISchemaBase schema) + { + PropertyInfo[] pi = item.GetProperties(); + nodes.Clear(); + foreach (PropertyInfo p in pi) + { + object[] attrs = p.GetCustomAttributes(typeof(SchemaNodeAttribute), true); + if (attrs.Length > 0) + { + SchemaNodeAttribute show = (SchemaNodeAttribute)attrs[0]; + TreeNode node = nodes.Add(p.Name, show.Name); + node.ImageKey = "Folder"; + ReadPropertyDetail(node, p, schema, show); + } + } + } + + private void ReadPropertyDetail(TreeNode node, PropertyInfo p, ISchemaBase schema, SchemaNodeAttribute attr) + { + Color NodeColor = Color.Black; + IList items = (IList)p.GetValue(schema, null); + node.Text = node.Text + " (" + items.Count + ")"; + node.Nodes.Clear(); + foreach (ISchemaBase item in items) + { + if (CanNodeAdd(item)) + { + TreeNode subnode = node.Nodes.Add(item.Id.ToString(), (attr.IsFullName ? item.FullName : item.Name)); + if (item.Status == ObjectStatus.Drop) + { + subnode.ForeColor = Color.Red; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.Red ? Color.Red : Color.Plum); + } + if (item.Status == ObjectStatus.Create) + { + subnode.ForeColor = Color.Green; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.Green ? Color.Green : Color.Plum); + } + if ((item.HasState(ObjectStatus.Alter)) || (item.HasState(ObjectStatus.Disabled))) + { + subnode.ForeColor = Color.Blue; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.Blue ? Color.Blue : Color.Plum); + } + if (item.HasState(ObjectStatus.AlterWhitespace)) + { + subnode.ForeColor = Color.DarkGoldenrod; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.DarkGoldenrod ? Color.DarkGoldenrod : Color.Plum); + } + if (item.HasState(ObjectStatus.Rebuild)) + { + subnode.ForeColor = Color.Purple; + NodeColor = (NodeColor == Color.Black || NodeColor == Color.Purple ? Color.Purple : Color.Plum); + } + subnode.Tag = item; + subnode.ImageKey = attr.Image; + subnode.SelectedImageKey = attr.Image; + } + } + + node.ForeColor = NodeColor; + } + + private void RebuildSchemaTree() + { + string currentlySelectedNode = treeView1.SelectedNode != null ? treeView1.SelectedNode.Name : null; + string currentTopNode = treeView1.TopNode != null ? treeView1.TopNode.Name : null; + + this.busy = true; + treeView1.BeginUpdate(); + treeView1.Nodes.Clear(); + TreeNode databaseNode = treeView1.Nodes.Add("root", databaseSource.Name); + ReadProperties(databaseSource.GetType(), databaseNode.Nodes, databaseSource); + treeView1.Sort(); + databaseNode.ImageKey = "Database"; + databaseNode.Expand(); + + if (currentlySelectedNode != null) + { + var nodes = treeView1.Nodes.Find(currentlySelectedNode, true); + if (nodes.Any()) treeView1.SelectedNode = nodes.First(); + } + + if (currentTopNode != null) + { + var nodes = treeView1.Nodes.Find(currentTopNode, true); + if (nodes.Any()) treeView1.TopNode = nodes.First(); + } + + treeView1.EndUpdate(); + this.busy = false; + treeView1.Focus(); + } + + private Boolean CanNodeAdd(ISchemaBase item) + { + ObjectStatus checkedStatus = ObjectStatus.Original; + // OriginalStatus == 0, so have to treat differently + if (item.Status == ObjectStatus.Original && ShowUnchangedItems) return true; + + if (item.HasState(ObjectStatus.Drop) && ShowMissingItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Drop; + + if (item.HasState(ObjectStatus.Create) && ShowNewItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Create; + + if (item.HasState(ObjectStatus.Alter) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Alter; + + if (item.HasState(ObjectStatus.AlterWhitespace) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.AlterWhitespace; + + if (item.HasState(ObjectStatus.AlterBody) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.AlterBody; + + if (item.HasState(ObjectStatus.Rebuild) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Rebuild; + + if (item.HasState(ObjectStatus.RebuildDependencies) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.RebuildDependencies; + + if (item.HasState(ObjectStatus.ChangeOwner) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.ChangeOwner; + + if (item.HasState(ObjectStatus.DropOlder) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.DropOlder; + + if (item.HasState(ObjectStatus.Bind) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Bind; + + if (item.HasState(ObjectStatus.PermissionSet) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.PermissionSet; + + if (item.HasState(ObjectStatus.Disabled) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Disabled; + + if (item.HasState(ObjectStatus.Update) && ShowChangedItems) return true; + checkedStatus = checkedStatus | ObjectStatus.Update; + + // At the end, we should have check all possible statuses. + ObjectStatus expectedTotalStatus = ObjectStatus.Original; + Enum.GetValues(typeof(ObjectStatus)).Cast().ToList().ForEach((s) => expectedTotalStatus = expectedTotalStatus | s); + + if (expectedTotalStatus != checkedStatus) + throw new Exception(string.Format("The OjbectStatusType '{0:G}' wasn't implemented in the CanNodeAdd() method. Developer, please ensure that all values in the Enum are checked.", (ObjectStatus)(expectedTotalStatus - checkedStatus))); + + return false; + } + + public Boolean ShowNewItems + { + get { return chkNew.Checked; } + set { chkNew.Checked = value; } + } + + public Boolean ShowMissingItems + { + get { return chkOld.Checked; } + set { chkOld.Checked = value; } + } + + public Boolean ShowChangedItems + { + get { return chkDifferent.Checked; } + set { chkDifferent.Checked = value; } + } + + public Boolean ShowUnchangedItems + { + get { return chkShowUnchangedItems.Checked; } + set { chkShowUnchangedItems.Checked = value; } + } + + private void FilterCheckbox_CheckedChanged(object sender, EventArgs e) + { + if (databaseSource == null) return; + + RebuildSchemaTree(); + } + + private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) + { + if (busy) return; + + ISchemaBase item = ((ISchemaBase)e.Node.Tag); + if (item != null) + { + if (item.ObjectType == ObjectType.Table + || item.ObjectType == ObjectType.View) + ReadProperties(item.GetType(), e.Node.Nodes, item); + if (OnSelectItem != null) OnSelectItem(item.FullName); + } + } + + private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) + { + if (e.Node.Tag == null) + { + foreach (TreeNode node in e.Node.Nodes) + { + node.Checked = e.Node.Checked; + } + } + } + + public string SelectedNode + { + get + { + if (treeView1.SelectedNode == null) return null; + + var item = treeView1.SelectedNode.Tag as ISchemaBase; + if (item == null) return null; + + return item.FullName; + } + } + } +} diff --git a/OpenDBDiff/UI/SchemaTreeView.resx b/OpenDBDiff/UI/SchemaTreeView.resx new file mode 100644 index 0000000..3cf89d0 --- /dev/null +++ b/OpenDBDiff/UI/SchemaTreeView.resx @@ -0,0 +1,481 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAK + UgAAAk1TRnQBSQFMAgEBEAEAARQBAAEUAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABUAMAAQEBAAEgBgABUP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8ALgABqgGTAYEB/wFU + AToBKAH/AVQBOAEqAf8BUgE6ASgB/wFSAToBKAH/AVEBOwEnAf8BUwE7ASkB/wFSAToBKAH/AVIBOgEo + Af8BVAE6ASgB/wFUAToBKAH/AVEBOgEpAf8BUgE6ASgB/0AAAU0BlgG0Af8BJwGkAdgB/wEUAY8ByQH/ + AQoBgwHAAf8BCAF9AbcB/wEKAVABdwH/AcUBfQE9Af8B2gGWAVUB/wHcAZIBUAH/AeMBnwFfAf8B3QGY + AVgB/wHdAZUBUwH/Ad0BkAFPAf8B3QGOAUoB/wHeAYwBRwH/AcIBaQEjAf8ByQLBAe8ByQLBAe8ByQLB + Ae8ByQLBAe8ByQLBAe8ByQLBAe8ByQLBAe8ByQLBAe8ByQLBAe8ByQLBAe8BUAF+AZEB7wE5AYYBqAHv + ASwBdAGfAe8BJAFvAZcB7wEkAWYBkgHvASQBSgFlAe8MAAGlAZMBggL/Af4C/wGtAZIBgQH/AaoBkgGC + Af8BqgGSAYIB/wGqAZEBhAH/Aa0BkAGDAf8BqgGSAYIB/wGqAZIBggH/AawBkgGBAf8BrgGSAYEB/wGs + AZIBgQH/AVEBOgEoAf9AAAFhAbABzAH/AT4B0gL/ASIBuAH2Af8BDgGsAfYB/wEDAaQB8gH/ARABcwGn + Af8B3wGmAWYB/wGFAYIBbwH/AZMBgQFtAf8B+QHMAYwB/wH3AckBigH/AfoBxwGEAv8BxwGBAf8B8AGx + AW0C/wG+AXYB/wHUAYEBOSH/AToBlwFTBf8BXQGtAckB/wE5AcwB+gH/AR4BswHwAf8BDAGnAe8B/wEC + AZ8B6wH/AQ0BbQGhAf8MAAGsAZIBgQH/Af0P/wP5Af8B+QHwAecB/wH5AfAB5wH/AfkB8AHnAf8B+QHw + AecB/wH5AfAB5wH/AaoBkgGCAf8BUQE6ASkB/0AAAYEBvQHNAf8BcwHjAfwB/wFPAcgB7wH/ATABuAHr + Af8BFwGqAeoB/wEUAXcBqAH/AdgBnwFlAf8B4gHaAawB/wGOAXYBWQH/AaEBiQFyAf8B5wGzAXwB/wFm + AVIBNgH/AXEBWgE6Af8BrQF8AUoB/wH+AbsBcgH/AdIBgQE9Gf8BSAGeAV8B/wFIAZ4BXwH/AR4BiAE6 + Af8BSAGeAV8B/wF4AbsBzQH/AWcB4AH9Af8BRQHFAfAB/wEoAbYB7QH/AREBqQHsAf8BEQF0AagB/wwA + AaYBkQGBA/8B/gH/Af0B/gr/AfgB9gH0Af8B+AH2AfQB/wH4AesB6AH/AfgB6wHoAf8B+AHrAegB/wH5 + AfAB5wH/AasBkQGBAf8BUwE7ASkB/0AAAY0BxAHLAf8BmAHsAfEB/wF9AdgB6gH/AV0BzwHxAf8BPwHD + AfMB/wElAYsBuwH/AdUBoAFnA/8BxQH/AbQBkAFmAf8BhgFxAVgC/wHrAakB/wF3AWEBRAH/AQgBDQEX + Af8BzgGnAXgC/wHHAYAB/wHRAYIBPxX/AVYBpgFrAf8BxwHhAc4B/wHHAeEBzgH/AR4BiAE6Af8BxwHh + Ac4B/wGKAcIBzAH/AY8B6gH0Af8BcAHUAesB/wFQAckB8AH/ATMBvQHxAf8BHwGGAbYB/wwAAawBkQGE + B/8B/g3/AfgB9gH0Af8B+AH2AfQB/wH4AfYB9AH/AfgB6wHoAf8B+QHwAecB/wGsAZIBggH/AVIBOwEn + Af8UAAHaAdMBzQH/AaMBjQGBAf8BgQFkAVgB/wGBAWgBVgH/AYABZQFTAf8BfAFfAU4B/wFzAV4BTAH/ + AW0BWAFDAf8BbAFTAUMB/wFgAUoBOQH/AZoBgwF9Af8BgwGsAbYB/wGDAcIBzgH/AWoBrwHHAf8BdgGv + AcEB/wFgAbcB0AH/AV0BoAG+Af8B1QGkAWoC/wH+AcoB/wGeAYMBZgH/AW4BUQEyAf8B8wHjAZ8B/wG4 + AaABdwH/AU8BNwEeAf8B4wGYAVQB/wHzAbQBdAH/AdEBhwFFAf8B9wHkAdsB/wHUAccBwQH/AdQBxwHB + Af8B1AHHAcEB/wHUAccBwQH/AY4BoQGEAf8B1AHHAcEF/wG5AdoBwgX/AYYBtAG9Af8BigHPAdkB/wFu + AbwB0gH/AWwBuQHQAf8BVAG7AdsB/wFKAZkBvQH/DAABqwGWAYUB/wH+Af8B/QH/Af0P/wH9A/8B+AH2 + AfQB/wH4AfYB9AH/AfgB6wHoAf8B+QHwAecB/wGqAZIBggH/AVIBOgEoAf8UAAGmAY8BgQX/AdABxgG3 + Af8ByQG3AbAB/wHBAasBogH/AbgBogGTAf8BtQGYAYoB/wGtAY0BgQH/AaQBhwF7Af8BnQGDAXMB/wFZ + AUMBMgH/AZIBuwHEAf8BhAHRAeEB/wFQAbcB3AH/AYMBpwG0Cf8B1gGnAW4C/wH7AckB/wGjAZYBgQH/ + AT8BOQEzAf8BvQGmAYIB/wHDAbMBiwH/AdkBuQGBAf8B5wG0AXcB/wHcAbkBhwH/AdQBigFKAf8B8wHY + AcsB/wHCAbQBrQH/AXYBbAFnAf8BuQGqAaMB/wHiAc4BxQH/AYwBgAF4Af8BwAGtAaUN/wGMAbUBvwH/ + AYQBywHaAf8BWAG0AdQB/wF9AaoBuQH/AcMB5AHtAf8BwgHbAecB/wHzAdgBywH/AcABrQGlAf8BwAGt + AaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/ + AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AfkB8AHnAf8BqgGSAYIB/wFSAToBKAX/AWMBSgE7Af8BYgFJ + AToB/wgAAa0BlgGFBf8B+wHqAeIB/wH3AeIB1wH/AfQB2wHSAf8B9AHUAcgB/wHtAc0BvAH/AfAByAG1 + Af8B7AG/AaoB/wGgAYYBeAH/AVsBRwE3Cf8BIAGIATwN/wHVAagBbgP/AdoB/wH4Ae4BtQH/AVsBSAE5 + Af8BrwGYAW4C/wH1AbQC/wHnAaYC/wHdAaAC/wHfAZ4B/wHVAYwBTgH/AfMB2AHLAf8BgQF3AXQB/wGs + AaEBnAH/AXgBcAFrAf8B9wHjAdkB/wF2AWwBZwH/AcABrQGlDf8BzwHhAeUB/wHJAesB8gH/AbIB4AHw + Af8ByQHZAd4J/wHzAdgBywH/AccBxAHDAf8BTgFNAUwB/wG5AbQBsQH/AfsB8gHuAf8BcQFsAWoB/wH6 + Ae0B5gH/AcMBuAGyAf8BTQFIAUUB/wG1AagBoQH/AfYB4gHYAf8BbwFlAWEB/wHAAa0BpQH/AfkB8AHn + Af8BqgGSAYIB/wFSATsBJwH/AbkBpAGYAf8B/gH9AfgB/wGXAYUBdgH/AZ0BiQF6Af8BmgGFAXoB/wGz + AZ0BjwH/Af0D/wH8Ae4B6gH/AfcB5wHdAf8B9gHfAdUB/wHzAdcBzgH/AfEB0gHDAf8B8AHKAbkB/wHw + AcUBsgH/AasBjAGBAf8BYwFLAToJ/wEgAYgBPA3/AdcBqwF1A/8B4wP/AcUB/wG0AZgBeAH/AXoBbwFh + Af8B+gHpAbIC/wHtAbMC/wHkAagC/wHoAasB/wHXAZIBUwH/AfMB2AHLAf8BgwF8AXkB/wGjAZkBlAH/ + AXoBcgFuAf8B9wHkAdsB/wGbAZABigH/AcABrQGlJf8B8wHYAcsB/wNOAf8B/gH5AfcB/wFOAU0BSwH/ + AfwB9AHwAf8BgwKBAf8B+gHvAekB/wFNAUkBRwH/AfgB6AHhAf8BTQFIAUUB/wH3AeMB2gH/AYEBdwFx + Af8BwAGtAaUB/wH5AfAB5wH/AawBkgGCAf8BUgE6ASgF/wHOAcABtAH/AWMBSwE6Af8IAAG4AaIBkQX/ + Af4C8gH/AfkB6wHjAf8B+QHjAdsB/wHzAdwB0wH/AfEB1wHGAf8B8QHSAb8B/wHwAcgBtQH/AbEBkgGH + Af8BZwFTAUIB/wHzAdgBywH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHN + AZYBXwH/AfAB4AG0Af8B7wHeAacB/wHyAc4BmAH/AesBugGEAf8B7wHOAZQB/wHvAcsBkgH/Ae8BygGN + Af8B8AHMAY0B/wHNAYQBRwH/AfMB2AHLAf8BuwGyAa8B/wGYAZABjAH/AbUBqgGkAf8BrAGfAZkB/wG2 + AakBowH/AcABrQGlJf8B8wHYAcsB/wHDAcEBwAH/AVEBUAFPAf8BrgGqAagB/wH8AfYB8gH/AckBwAG7 + Af8B+gHwAesB/wG7AbIBrwH/AU8BSwFIAf8BqgGfAZoB/wH3AeUB3AH/AbcBqwGlAf8BwAGtAaUF/wGq + AZIBggH/AVIBOgEoAf8UAAG7AakBlwH/Af4B/QL/Af0B+QH0Af8B/AHxAewB/wH7AeoB4gH/AfcB4AHX + Af8B9gHbAc4B/wHuAdQBxgH/AewBzAG7Af8BuAGcAY8B/wFvAVsBSgH/AfMB2AHLAf8BwwG4AbIB/wFM + AUcBRAH/AbUBqAGhAf8B9gHiAdgB/wFuAWQBYAH/AcABrQGlJf8B8wHYAcsB/wGmAZ8BmwH/AfkB7AHn + Af8BlgGNAYkB/wGMAYMBfQH/AY0BggF9Af8BwAGtAaUN/wG8AdgB4wH/Aa4B3QHwAf8BpwHVAesB/wGj + AdEB5wH/AaIBzgHkAf8BowG9AcwB/wHzAdgBywH/Ab0BuQG4Af8B/gH7AfoB/wHGAcQBwwH/AU4BTQFM + Af8BuQG0AbEB/wH8AfIB7gH/AbsBsgGuAf8B+QHsAeYB/wHDAbcBsQH/AU0BSAFFAf8BtQGnAaEB/wHA + Aa0BpQX/AaoBkgGCAf8BUgE6ASgB/xQAAcEBqwGaBf8B/AH/Af0C/wH+Bv8B/QH/Af4C/wL+Av8B/gT/ + Af4B/wG6AaIBmQH/AXoBYQFVAf8B8wHYAcsB/wFMAUgBRgH/AfgB6AHhAf8BTAFHAUQB/wH3AeMB2gH/ + AYEBdgFwAf8BwAGtAaUN/wFNAZYBtAH/AScBpAHYAf8BFAGPAckB/wEKAYMBwAH/AQgBfQG3Af8BCgFQ + AXcB/wHzAdgBywH/AXoBdwF1Af8B+gHuAekB/wFrAWYBYwH/AcIBtgGwAf8BaAFgAV0B/wHAAa0BpQ3/ + AVEBngG8Af8BLAGyAeQB/wEWAZwB1wH/AQkBkAHRAf8BBAGJAckB/wEKAVkBhQH/AfMB2AHLAf8DjAH/ + Af4B/QH8Af8BTwFOAU0B/wH9AfgB9wH/AU4BTAFLAf8B/AHzAe8B/wGCAYEBgAH/AfoB7QHoAf8BTQFJ + AUcB/wH4AekB4QH/AU0BRwFFAf8BwAGtAaUB/wGsAZIBgQH/AaoBkgGCAf8BUwE8ASgB/xQAAeMB3QHa + Af8BwgGrAZ8B/wHAAakBnAH/AbgBogGTAf8BswGdAY8B/wGtAZgBiQH/AakBkwGFAf8BowGOAYEB/wGg + AYkBgQH/AYwBdAFjAf8BwgG1AawB/wHzAdgBywH/AbsBsgGvAf8BTgFKAUcB/wGqAZ8BmgH/AfcB5QHc + Af8BtwGrAaUB/wHAAa0BpQ3/AWEBsAHMAf8BPgHSAv8BIgG4AfYB/wEOAawB9gH/AQMBpAHyAf8BEAFz + AacB/wHzAdgBywH/AY4BhQGBAf8B+AHqAeIB/wHFAbgBsQH/AXQBagFmAf8BvAGtAaYB/wHAAa0BpQ3/ + AWcBswHMAf8BSQHWAf4B/wErAbwB9AH/ARUBrwHzAf8BBgGmAfAB/wEPAXIBpwH/AfMB2AHLAf8DbwH/ + Av4B/QH/AbkCtwH/AU8BTgFNAf8BrgGqAagB/wH8AfUB8QH/AW4BawFqAf8B+gHwAeoB/wG2Aa0BqAH/ + AU0BSQFHAf8BqgGfAZoB/wHAAa0BpQH/AVIBOwEpAf8BVAE8ASkB/wFTAToBKgH/QAAB8wHYAcsB/wG7 + AbIBrgH/AfkB7AHmAf8BwwG3AbEB/wFMAUcBRAH/AbUBpwGhAf8BwAGtAaUN/wGBAb0BzQH/AXMB4wH8 + Af8BTwHIAe8B/wEwAbgB6wH/ARcBqgHqAf8BFAF3AagB/wH1Ad8B1QH/AfUB3wHVAf8B9QHfAdUB/wH1 + Ad8B1QH/AfUB3wHVAf8BywHJAbAB/wHMAbwBtgX/AdUB6QHaBf8BggG+Ac0B/wF4AeUB+gH/AVYBywHu + Af8BNgG8AewB/wEdAa8B7AH/ARUBeQGsAf8B8wHYAcsB/wHzAdgBywH/AfMB2AHLAf8B8wHYAcsB/wHz + AdgBywH/AfMB2AHLAf8B8wHYAcsB/wHzAdgBywH/AfMB2AHLAf8B8wHYAcsB/wHzAdgBywH/AfMB2AHL + Af8BwAGtAaUB/wHNAbkBrgH/AVIBOwEqAf8B2wHNAcEB/0AAAfMB2AHLAf8BggGBAX0B/wH6Ae0B6AH/ + AUwBSAFGAf8B+AHpAeEB/wFMAUYBRAH/AcABrQGlBf8BIAGIATwF/wGNAcQBywH/AZgB7AHxAf8BfQHY + AeoB/wFdAc8B8QH/AT8BwwHzAf8BJQGLAbsV/wE6AZcBUwH/AeMB8AHnAf8B4wHwAecB/wEeAYgBOgH/ + AeMB8AHnAf8BjAHBAcgB/wGVAecB7QH/AXkB0wHmAf8BXgHLAesB/wFBAcIB7wH/ASoBjgG7Af8MAAHN + AbcBpQL/Af4O/wP+Df8BswGbAYoB/wFTATwBKQH/Ad8BzQHCAf9EAAHzAdgBywH/AW0BagFpAf8B+gHw + AeoB/wG2Aa0BqAH/AUwBSAFGAf8BqgGfAZoB/wHAAa0BpQH/ASABiAE8Af8BIAGIATwB/wEgAYgBPAH/ + AYMBrAG2Af8BgwHCAc4B/wFqAa8BxwH/AXYBrwHBAf8BYAG3AdAB/wFdAaABvhn/ASwBjwFGAf8BLAGP + AUYB/wEeAYgBOgH/ASwBjwFGAf8BhAGtAbcB/wGDAcMBzwH/AWYBsAHIAf8BdQGvAcAB/wFoAbwB0wH/ + AWUBpgHCAf8MAAHQAbgBoAH/Ac0BtwGlAf8B1AG4AaMB/wHSAbcBpAH/AdIBtwGkAf8B0gG3AaQB/wHQ + AbUBowH/Ac0BsQGjAf8BxwGsAZoB/wHBAaQBmQH/AdoBzgHCAf9IAAHzAdgBywH/AfMB2AHLAf8B8wHY + AcsB/wHzAdgBywH/AfMB2AHLAf8B8wHYAcsB/wHAAa0BpQX/ASABiAE8Bf8BkgG7AcQB/wGEAdEB4QH/ + AVABtwHcAf8BgwGnAbQp/wEeAYgBOgX/AZIBuwHEAf8BhAHRAeEB/wFOAbcB3AH/AYMBpwG0Cf9MAAHz + AdgBywH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/AcABrQGl + Af8BwAGtAaUB/wHAAa0BpQH/AcABrQGlAf8BwAGtAaUB/wHAAa0BpQH/UAABhgG0AccB/wFwAZoBrgH/ + AV0BhAGbAf8BUQF3AY4B/wFJAW4BhgH/AUQBdgGSAf8BSAGBAaIB/wFnAZsBugH/EAABbwFVAUEB/wFv + AVUBQQH/AW8BVQFBAf8BbwFVAUEB/wFvAVUBQQH/AW8BVQFBAf8BbwFVAUEB/wFvAVUBQQH/AW8BVQFB + Af8BbwFVAUEB/wFvAVUBQQH/IAAB8wHYAcsB/wHHAcQBwwH/AVEBUAFPAf8BuQG0AbEB/wH7AfIB7gH/ + AXQBbwFtAf8B+gHtAeYB/wHDAbgBsgH/AVABSwFIAf8BtQGoAaEB/wH2AeIB2AH/AXIBaAFkAf8BwAGt + AaUB/wgAAegBgQFJAf8B4AF1ATwB/wHSAWoBNQH/Ab4BYAEvAf8BqgFXASsB/wGXAU4BKAX/AegBgQFJ + Af8B4AF1ATwB/wHRAWsBNAH/Ab4BYAEvAf8BqgFWASsB/wGWAU4BJwH/EAABVwGPAasB/wFfAaMBvwH/ + AXsBwAHUAf8BlQHZAeYB/wGDAd8B9AH/AVMBxgHsAf8BJwGqAd0B/wEZAZIBxwH/ASUBgQGsAf8BOAFx + AZAB/wwAAW8BVQFBJf8BbwFVAUEB/yAAAfMB2AHLAf8DUQH/Af4B+QH3Af8BUQFQAU4B/wH8AfQB8AH/ + AYMCgQH/AfoB7wHpAf8BUAFMAUoB/wH4AegB4QH/AVABSwFIAf8B9wHjAdoB/wGBAXoBdAH/AcABrQGl + Af8IAAHqAYwBYgH/Ad4B0gHKAf8B3gHSAcoB/wHeAdIBygH/Ad4B0gHKAf8BrwFYASsF/wHqAYwBYQH/ + Ad4B0gHKAf8B3gHSAcoB/wHeAdIBygH/Ad4B0gHKAf8BrwFZASsB/wwAAV0BhAGbAf8BRwG9AecB/wFq + AdMB8QH/AYwB4wH0Af8BogHrAfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHi + Af8BDAGWAdIB/wFAAWEBfQH/CAABbwFVAUEF/wFvAVUBQQH/AdgByAG9Af8B2AHIAb0B/wHYAcgBvQH/ + AdgByAG9Af8B2AHIAb0B/wFvAVUBQQH/AdgByAG9Af8BbwFVAUEB/wGnAZQBhgH/AacBlAGGAf8BpwGU + AYYB/wGqAZcBiQH/EAAB8wHYAcsB/wHDAcEBwAH/AVQBUwFSAf8BrgGqAagB/wH8AfYB8gH/AckBwAG7 + Af8B+gHwAesB/wG7AbIBrwH/AVIBTgFLAf8BqgGfAZoB/wH3AeUB3AH/AbcBqwGlAf8BwAGtAaUB/wgA + AeoBnQF6Af8B/QH6AfkB/wH7AfEB7QH/AfcB5gHdAf8B3gHSAcoB/wHIAWYBMgX/AeoBnQF7Af8B/QH6 + AfgB/wH6AfEB7AH/AfcB5QHdAf8B3gHSAcoB/wHIAWYBMQH/DAABXQGEAZsB/wFGAcQB8AH/AW4B1QH0 + Af8BjAHjAfQB/wGiAesB9gH/AYMB3wH0Af8BVAHLAfAB/wEhAbUB7QH/AQUBqAHpAf8BBAGiAeIB/wEG + AZwB2wH/AUABYQF9Af8IAAFvAVUBQQX/AdwBzAHBAf8BbwFVAUEB/wHxAe8B7gH/AfEB7wHuAf8B8gHn + Ad8B/wFvAVUBQQH/AfEB4gHYAf8B8gHfAdIB/wFvAVUBQQH/AfMB3AHOAf8B8gHbAcsB/wHhAc0BvwH/ + AaoBlwGJAf8QAAHzAdgBywH/Ab0BuQG4Af8B/gH7AfoB/wHGAcQBwwH/AVEBUAFPAf8BuQG0AbEB/wH8 + AfIB7gH/AbsBsgGuAf8B+QHsAeYB/wHDAbcBsQH/AVABSwFIAf8BtQGnAaEB/wHAAa0BpQH/CAAB6QGo + AYgF/wH9AfgB9gH/AfoB7gHoAf8B3gHSAcoB/wHdAXIBOgX/AekBqQGIBf8B/QH4AfUB/wH6Ae4B6AH/ + Ad4B0gHKAf8B3AFyAToB/wwAAWcBjwGlAf8BRgHEAe8B/wFuAdUB9AH/AYwB4wH0Af8BogHrAfYB/wGD + Ad8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGcAdsB/wFJAW4BhgH/CAABbwFV + AUEF/wHhAdABxQH/Af0B/gH9Af8B7AHeAdYB/wHpAdkB0QH/AewB3gHWAf8B/QH1Ae4B/wHsAd4B1gH/ + AewB3gHWAf8BbwFVAUEB/wHjAbYBtQH/Af0B6QHbAf8B4QHNAb8B/wGqAZcBiQH/EAAB8wHYAcsB/wOM + Af8B/gH9AfwB/wFSAVEBUAH/Af0B+AH3Af8BUQFPAU4B/wH8AfMB7wH/AYICgQH/AfoB7QHoAf8BUAFM + AUoB/wH4AekB4QH/AVABSgFIAf8BwAGtAaUB/wgAAeoBqgGLAf8B6gGqAYsB/wHqAaIBgQH/AeoBlgFw + Af8B6gGJAVwB/wHoAYEBSgX/AeoBqgGLAf8B6gGqAYsB/wHqAaIBgQH/AeoBlgFxAf8B6gGJAVwB/wHp + AYEBSQH/DAABZwGPAaUB/wFGAcQB8AH/AW4B1QH0Af8BjAHjAfQB/wGiAesB9gH/AYMB3wH0Af8BVAHL + AfAB/wEhAbUB7QH/AQUBqAHpAf8BBAGiAeIB/wEGAZwB2wH/AUkBbgGGAf8IAAFvAVUBQQX/AdgByAG9 + Af8B/QH+Af0B/wH9Af4B/QH/Af0B/gH9Af8B/QH+Af0B/wH9AfUB7gH/Af0B9QHuAf8B/gHxAegB/wFv + AVUBQQH/Af0B7gHhAf8B/QHpAdsB/wHiAc8BwgH/AaoBlwGJAf8QAAHzAdgBywH/A3IB/wL+Af0B/wG5 + ArcB/wFSAVEBUAH/Aa4BqgGoAf8B/AH1AfEB/wFxAW4BbQH/AfoB8AHqAf8BtgGtAagB/wFQAUwBSgH/ + AaoBnwGaAf8BwAGtAaUB/xQAAW8BXgFQFf8BdQFiAVQB/xgAAWcBjwGlAf8BRgHEAfAB/wFuAdUB9AH/ + AYwB4wH0Af8BogHrAfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGc + AdsB/wFJAW4BhgH/CAABbwFVAUEF/wHkAdQByQH/Af0B/gH9Af8B7AHeAdYB/wHsAd4B1gH/AewB3gHW + Af8B/QH8AfkB/wHsAd4B1gH/AewB3gHWAf8BbwFVAUEB/wHjAbYBtQH/Af0B7gHhAf8B4gHRAcYB/wGq + AZcBiQH/BAABxQGBAUEB/wHaAZYBWQH/AdwBkgFUAf8B4wGfAWMB/wHdAZgBXAH/Ad0BlQFXAf8B3QGQ + AVMB/wHdAY4BTgH/Ad4BjAFLAf8BwgFtAScB/wHzAdgBywH/AfMB2AHLAf8B8wHYAcsB/wHzAdgBywH/ + AfMB2AHLAf8BwAGtAaUB/xQAAXwBagFcFf8BegFnAVkB/xgAAWsBlQGrAf8BRgHEAfAB/wFuAdUB9AH/ + AYwB4wH0Af8BogHrAfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGc + AdsB/wFJAW4BhgH/CAABbwFVAUEF/wHkAdQByQH/AW8BVQFBAf8B/QH+Af0B/wH9Af4B/QH/Af0B/gH9 + Af8BbwFVAUEB/wH9AfUB7gH/Af4B8QHoAf8BbwFVAUEB/wH9Ae4B4QH/AfIB5wHfAf8B4gHRAcYB/wGq + AZcBiQH/BAAB3wGmAWoB/wGFAYIBcwH/AZMBgQFxAf8B+QHMAYwB/wH3AckBigH/AfoBxwGEAv8BxwGB + Af8B8AGxAXEC/wG+AXoB/wHUAYEBPQH/LAABqgGVAYYB/wGpAZQBhAH/AakBkwGEAf8BqQGUAYQB/wGp + AZMBhAH/AakBlAGFAf8BpwGRAYIB/xgAAWsBlQGrAf8BRgHEAfAB/wFuAdUB9AH/AYwB4wH0Af8BogHr + AfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGcAdsB/wFRAXcBjgH/ + CAABbwFVAUEF/wFvAVUBQQH/Af0B/gH9Af8B7AHfAdgB/wHsAd4B1gH/AewB3wHYAf8B/QH+Af0B/wFv + AVUBQQH/AewB3gHWAf8BbwFVAUEB/wHjAbYBtQH/Af0B9QHuAf8B4gHYAdEB/wGqAZcBiQH/BAAB2AGf + AWkB/wHiAdoBrAH/AY4BegFdAf8BoQGJAXYB/wHnAbMBgQH/AWoBVgE6Af8BdQFeAT4B/wGtAYEBTgH/ + Af4BuwF2Af8B0gGBAUEB/wwAAVQBlQFLAf8oAAFxAV4BTwH/JAABcAGaAa4B/wFGAcQB8AH/AW4B1QH0 + Af8BjAHjAfQB/wGiAesB9gH/AYMB3wH0Af8BVAHLAfAB/wEhAbUB7QH/AQUBqAHpAf8BBAGiAeIB/wEG + AZwB2wH/AVEBdwGOAf8IAAFvAVUBQQX/AeQB1AHJAf8B/QH+Af0B/wH9Af4B/QH/Af0B/gH9Af8B/QH+ + Af0B/wH9Af4B/QH/Af0B/gH9Af8B/QH8AfkB/wFvAVUBQQH/Af4B+QH1Af8B/QH1Ae4B/wHhAc0BvwH/ + AaoBlwGJAf8EAAHVAaABawP/AcUB/wG0AZABagH/AYYBdQFcAv8B6wGpAf8BewFlAUgB/wEMAREBGwH/ + Ac4BpwF8Av8BxwGBAf8B0QGCAUMB/wgAAVQBlQFLAf8BVAGVAUsB/wFUAZUBSwH/JAABbwFcAU4B/yQA + AXABmwGwAf8BRgHEAfAB/wFuAdUB9AH/AYwB4wH0Af8BogHrAfYB/wGDAd8B9AH/AVQBywHwAf8BIQG1 + Ae0B/wEFAagB6QH/AQQBogHiAf8BBgGcAdsB/wFRAXcBjgH/CAABbwFVAUEB/wFvAVUBQQH/AW8BVQFB + Af8BbwFVAUEB/wFvAVUBQQH/AW8BVQFBAf8BbwFVAUEB/wFvAVUBQQH/AW8BVQFBAf8BbwFVAUEB/wFv + AVUBQQH/Af0B9QHuAf8B/QH1Ae4B/wHhAc0BvwH/AaoBlwGJAf8EAAHVAaQBbgL/Af4BygH/AZ4BgwFq + Af8BcgFVATYB/wHzAeMBnwH/AbgBoAF7Af8BUwE7ASIB/wHjAZgBWAH/AfMBtAF4Af8B0QGHAUkB/wwA + AVQBlQFLAf8cAAHqAZUBcAH/AeoBiAFbAf8B6AGBAUgB/wHeAXQBOgH/Ac8BaQEzAf8BugFeAS4B/wGl + AVQBKgH/GAABdAGfAbIB/wFGAcQB8AH/AW4B1QH0Af8BjAHjAfQB/wGiAesB9gH/AYMB3wH0Af8BVAHL + AfAB/wEhAbUB7QH/AQUBqAHpAf8BBAGiAeIB/wEGAZwB2wH/AVgBgQGVAf8QAAHkAdQBySn/Af0B9QHu + Af8BqgGXAYkB/wQAAdYBpwFyAv8B+wHJAf8BowGWAYEB/wFDAT0BNwH/Ab0BpgGCAf8BwwGzAYsB/wHZ + AbkBgQH/AecBtAF7Af8B3AG5AYcB/wHUAYoBTgH/DAABVAGVAUsB/xwAAeoBogGBAf8B3gHSAcoB/wHe + AdIBygH/Ad4B0gHKAf8B3gHSAcoB/wHeAdIBygH/AbsBXwEuAf8YAAF3AaMBuAH/AW4B1QH0Af8BmgHo + AfcB/wG1AfMB+gH/AcUB+QH9Af8BxQH5Af0B/wHCAfUB+gH/Aa8B8AH7Af8BjAHjAfQB/wFuAdUB9AH/ + AUEBuAHlAf8BWAGBAZUB/xAAAfoBzAG1Af8B+gHLAbQB/wH6AcoBswH/AfoBxgGrAf8B+wHAAaMB/wH6 + AboBmQH/AfsBtAGQAf8B+wGtAYcB/wH8AakBgQH/AfwBqQGBAf8B+wGoAYEB/wH8AakBgQH/Ae0BoQGB + Af8EAAHVAagBcgP/AdoB/wH4Ae4BtQH/AV8BTAE9Af8BrwGYAXIC/wH1AbQC/wHnAaYC/wHdAaAC/wHf + AZ4B/wHVAYwBUgH/DAABVAGVAUsB/xwAAeoBqgGLAf8B/gH8AfsB/wH7AfQB8AH/AfkB6QHjAf8B9QHf + AdQB/wHeAdIBygH/Ac8BaQEzAf8YAAF3AaMBuAH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9 + Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BWAGBAZUB/xAA + AfoBzAG1Av8B3AHJAv8B2gHFAv8B1wHBAv8B1AG+Av8B0AG5Av8BzQG0Av8BygGvAv8BxgGpAv8BxgGp + Av8BwgGkAv8BwQGhAf8B8QGnAYMB/wQAAdcBqwF5A/8B4wP/AcUB/wG0AZgBfAH/AYABcwFlAf8B+gHp + AbIC/wHtAbMC/wHkAagC/wHoAasB/wHXAZIBVwH/AVQBlQFLAf8BVAGVAUsB/wFUAZUBSwH/IAAB6gGq + AYsF/wH9AfkB9wH/AfoB8AHrAf8B9wHmAd0B/wHeAdIBygH/Ad4BdAE7Af8cAAGMAb0BzAH/AZ0BzwHb + Af8BrQHfAegB/wG5AewB8wH/AcIB9QH6Af8BwgH1AfoB/wG5AewB8wH/AakB2gHjAf8BlAHEAdEB/wGA + AagBuAH/FAAB+gHMAbUB/wH6AcsBtAH/AfoBywG0Af8B+gHKAbMB/wH6AcYBrgH/AfsBwwGnAf8B+wG+ + AZ8B/wH6AbgBmAH/AfwBqQGBAf8B+wG0AZAB/wH7AbABiAH/AfwBrAGDAf8B+gGpAYEB/wQAAc0BlgFj + Af8B8AHgAbQB/wHvAd4BpwH/AfIBzgGYAf8B6wG6AYQB/wHvAc4BlAH/Ae8BywGSAf8B7wHKAY0B/wHw + AcwBjQH/Ac0BhAFLAf8sAAHqAaoBiwH/AeoBqgGLAf8B6gGqAYsB/wHqAaIBgQH/AeoBlgFvAf8B6gGH + AVsB/wHoAYEBRwH/IAABpQHMAdgB/wGMAb0BzAH/AXwBpwG6Af8BcAGbAbAB/wFwAZoBrgH/AXQBnwGy + Af8BggGrAb0B/wGbAb8BzAH/2AABtwGiAZMB/wFrAVEBPQH/AWsBUQE9Af8BawFRAT0B/wFrAVEBPQH/ + AWsBUQE9Af8BawFRAT0B/wFrAVEBPQH/AWsBUQE9Af8BawFRAT0B/wFrAVEBPQH/AWsBUQE9Af8QAAG3 + AaIBkwH/AW0BUwE/Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/ + Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/Af8BbQFTAT8B/1wAAbwBZgEmAf8B3AGBAUYB/wHcAXsBQQH/ + AdwBeQE9Af8B3AF1ATsB/wHcAXMBNwH/AeEBbgEyAf8B2AFzATcB/wHWAXMBNwH/AdgBcwE3Af8B2AFz + ATkB/wgAAbcBogGTAf8B/AH+Av8BoAHgAekB/wGbAdoB5AH/AZgB1AHgAf8BlAHPAdwB/wGQAcoB2AH/ + AYwBxAHTAf8BiAG/Ac4B/wGEAboBygH/AYEBtgHHAf8BawFRAT0B/xAAAbcBogGTAv8B+gH3Af8B6QHh + Ad0B/wHpAd0B2AH/AekB2QHRAf8B6QHVAcsB/wHpAdEBxQH/AekBzgG/Af8B6QHJAbkB/wHpAcYBtAH/ + AekBxAGwAf8BbQFTAT8B/xQAAecBgQFQAf8ByAFtATkB/wGYAVQBLgH/BAAB5wGBAVAB/wHIAW0BOQH/ + AZgBVAEuAf8EAAHnAYEBUQH/AcgBbgE6Af8BmQFVAS8B/xgAAT8BqQHgAf8B6wGzAYYC/wHjAb4C/wHF + AZ4C/wG0AYcC/wGlAX0C/wGPAWEC/wGNAWwC/wGNAWQC/wGNAWEC/wGNAWIC/wGPAWYB/wgAAbcBogGT + Af8B/AH+Av8B0QH2AfoB/wHNAfUB+QH/AckB9QH5Af8BxAHzAfgB/wHBAfMB9wH/Ab0B8gH3Af8BuQHy + AfYB/wG2AfEB9gH/AYQBuAHJAf8BawFRAT0B/xAAAbcBogGTAv8C/QL/AfcB8wL/AfcB8wH/AYUBgQGA + Af8BhQGBAYAB/wGFAYEBgAH/AYUBgQGAAv8B9wHzAv8B3gHNAf8B6QHGAbUB/wFtAVMBPwH/FAAB6QGc + AYEB/wH4AeIB1AH/AcgBbAE6Af8EAAHpAZwBgQH/AfgB4gHUAf8ByAFsAToB/wQAAekBnQGBAf8B+AHi + AdQB/wHIAW0BOwH/DAABCQGnAegB/wEJAacB6AH/AQkBpwHoAf8BPwGpAeAB/wHrAbMBhgL/AekBxwL/ + AdEBqQL/AcIBmAL/AbEBgQL/AaIBgQL/Ae8B6wL/AY8BagL/AYkBWQL/AYsBXwL/AY0BYgH/CAABtwGi + AZMC/wG7AZkB/wHoAZABbQH/Ad8BgQFOAf8BxgFlATAB/wHMAeoB6QH/AeoBjwFpAf8B5gGEAVoB/wHf + AYEBTwH/AcoBaAE0Af8BhgG8AcwB/wFrAVEBPQH/EAABtwGiAZMG/wH+Af0C/wH3AfMC/wH4AfQC/wH0 + Ae8C/wHwAegC/wHrAeEC/wH3AfMC/wHiAdQB/wHpAcsBvAH/AW0BUwE/Af8UAAHqAaoBiwH/AegBnAGB + Af8BmAFUAS4B/wQAAeoBqgGLAf8B6AGcAYEB/wGYAVQBLgH/BAAB6gGqAYsB/wHoAZ0BgQH/AZkBVQEv + Af8IAAEJAacB6AH/Aa4B7QL/AUkB2AL/AUkB2AL/AesBswGGAf8B6wGGAVUC/wHvAc8C/wHeAbgC/wHS + AakC/wG4AZYK/wGHAWgC/wGBAVUC/wGEAVkC/wGPAWIB/wgAAbcBogGTAf8B/gHGAakB/wP+Af8B3QHc + AdkB/wHXAYwBawH/AdAB7QHuAf8B6gGaAXoB/wP+Af8B3QHcAdkB/wHYAYEBUAH/AYkBwAHPAf8BawFR + AT0B/xAAAbcBogGTBv8B9wHzAv8B9wHzAf8BhQGBAYAB/wGFAYEBgAH/AYUBgQGAAf8BhQGBAYAC/wH3 + AfMC/wH3AfMB/wHpAc8BwwH/AW0BUwE/Af8YAAHqAaoBiwH/DAAB5gGBAUgB/wwAAZQBUgEuAf8MAAEJ + AacB6AH/AboB8AH+Af8BrgHuAf4B/wFJAdgC/wFJAdgC/wHhAYEBTgL/AeUBxQL/AesBywL/Ae0BywH/ + AdYCswH/AYsBjgG1Af8BagFmAYIC/wGYAXEC/wGRAWEC/wGEAVkB/wHtAXEBMgH/CAABugGlAZYB/wH+ + AdABuAH/AewBqwGMAf8B6gGWAXQB/wHkAYEBUQH/AdUB7gHtAf8B6gGqAYsB/wHqAaIBgQH/AeoBiAFe + Af8B2AGBAVAB/wGMAcQB0wH/AWsBUQE9Af8QAAG6AaUBlgr/AfcB8wL/Av4C/wH9AfoC/wH5AfYC/wH1 + AfAC/wH3AfMC/wHtAeQB/wHpAdQBygH/AW0BUwE/Af8YAAHqAaoBiwH/DAAB5gGBAUgB/wwAAZQBUgEu + Af8MAAEJAacB6AH/AcYB8gL/AbsB8AH+Af8BrgHuAf4B/wGhAesB/gH/AdoBpQGBAf8B9gGHAVIC/wG2 + AYQB/wH8AYkBdQH/AdIBwAHRAf8BdAGgAdAB/wE3AVYBgAH/AekBdwFqAv8BlgGBAf8B+AFuASgB/wHn + AboBjQH/CAABvgGpAZoB/wH8Af4C/wHhAfgB/AH/AWUBTAE4Af8B2AH3AfsB/wHVAfcB+gH/AdEB9gH5 + Af8BZQFMATgB/wHKAfUB+QH/AccB9AH5Af8BjwHJAdYB/wFrAVEBPQH/EAABvgGpAZoG/wH3AfMC/wH3 + AfMB/wGFAYEBgAH/AYUBgQGAAf8BhQGBAYAB/wGFAYEBgAL/AfcB8wL/AfIB7AH/AekB2QHSAf8BbQFT + AT8B/xgAAeoBqgGLAf8MAAHmAYEBSgH/DAABlQFTAS0B/wwAAQkBpwHoAf8B0gH1Af4B/wHGAfIB/gH/ + AboB8AH+Af8BSQHYAv8B8QHrAv8BtgGpAc0B/wHWAaABgQH/ARsCCAH/AV4BZQGBAf8BbwGYAc4B/wFq + AY8BvgH/AScBXAGBAf8BVQFyAZAB/wH2AdIBswH/DAABwwGuAZ4B/wH8Af4C/wHlAfkB/AH/AZcBhwGB + Af8BlwGHAYEB/wGXAYcBgQH/AZcBhwGBAf8BlwGHAYEB/wHOAfYB+QH/AcoB9QH5Af8BkgHMAdoB/wFr + AVEBPQH/EAABwwGuAZ4K/wH3AfMO/wL9Av8B9wHzAv8B9wHzAf8B6QHfAdkB/wFtAVMBPwH/GAAB6gGq + AYsB/wHqAaoBiwH/AeYBjQFpAf8B5gGDAVkB/wHmAYEBSgH/AeABegFAAf8BtAFiATYB/wGmAVsBMQH/ + AZUBUwEtAf8MAAG7AfAB/gH/AQkBpwHoAf8B0gH0Af4B/wHGAfIB/gH/AdIBwAHRAf8BdAGgAdAB/wE3 + AVYBgAH/AbMD/wEZASEBUwH/AU8BgQGoAf8BhwGxAdcB/wGFAbQB1wH/AW8BogHWAf8BegGaAckB/xAA + AcgBsgGjAf8B/AH+Av8B6QH7AfwB/wHiAfUB9gH/AdkC6wH/AYABVQE7Af8BzwLjAf8B0AHuAfAB/wHS + AfcB+gH/Ac8B9gH5Af8BlQHQAdwB/wFrAVEBPQH/EAAByAGyAaMG/wH3AfMC/wH3AfMB/wGFAYEBgAH/ + AYUBgQGAAf8BhQGBAYAB/wGFAYEBgAL/AfcB8wL/AfcB8wH/AekB4wHfAf8BbQFTAT8B/ygAAeYBgQFO + Af8kAAEJAacB6AH/ARsCCAH/AaIBngHFAf8BbwGYAc4B/wFqAY8BvgH/ASoBYgGaAf8BeQGEAbkB/wFe + AZYBywH/AYIBvAHXAf8BgQG3AdcB/wF9AbQB1gH/AXABlAHIAf8QAAHIAbIBowH/AfwB/gL/Ae0B/AH+ + Af8B6gGPAWkB/wHqAYEBVAH/AeUBfQFEAf8B5QF9AUQB/wHIAWgBNAH/AdYB9wH7Af8B0gH3AfoB/wGY + AdUB4AH/AWsBUQE9Af8QAAHMAbYBpyL/Av4C/wH7AfoB/wFtAVMBPwH/KAAB5wGBAVAB/ygAARkBIQFT + Af8BTwGBAagB/wGHAbEB1wH/AYUBtAHXAf8BbwGiAdYB/wEMARQBOwH/AUYBZgGKAf8BbAGUAcUB/wF6 + AagB1gH/AUoBdAGfAf8BYQGBAacB/xAAAcwBtgGnAf8B/AH+Av8B8AH7Af4B/wHqAZoBegH/A/4B/wP+ + Af8B3QHcAdkB/wHhAXoBQAH/AdoB+AH7Af8BngHeAecB/wGbAdkB4wH/AWwBUgE+Af8QAAHqAaoBiwH/ + AeoBqgGLAf8B6AGmAYYB/wHmAaEBgQH/AeMBmgGBAf8B4QGTAXcB/wHdAYwBbQH/AdoBgwFjAf8B1wGB + AVkB/wHTAYEBTwH/AdEBeAFHAf8BzwFzAUAB/yQAAecBgQFQAf8ByAFtATkB/wGYAVQBLgH/JAABeQGE + AbkB/wFeAZYBywH/AYIBvAHXAf8BgQG3AdcB/wF9AbQB1gH/AwgB/wIIASMB/wEkATcBYwH/AUQBZgGG + Af8BCAEOAUoB/wFTAUEBYgH/EAAB0QG7AasB/wH8Af4C/wH0Af0B/gH/AeoBqgGLAf8B6gGiAYEB/wHq + AZYBdAH/AeoBiAFeAf8B6AGBAUwB/wG3AaIBkwH/AWwBUgE+Af8BbAFSAT4B/wFsAVIBPgH/EAAB6gGq + AYsC/wHCAaIC/wHCAaIB/wH9Ab4BnAH/AfwBuAGTAf8B+gGvAYkB/wH4AacBgQH/AfYBoAGAAf8B9AGa + AXUB/wHzAZUBbwH/AfMBlQFvAf8BzgFzAUAB/yQAAekBnAGBAf8B+AHiAdQB/wHIAWwBOgH/JAABDAEU + ATsB/wFGAWYBigH/AWwBlAHFAf8BegGoAdYB/wFKAXQBnwH/ASoBJQE5Af8DCAH/AwgB/wMIAf8DCAH/ + AdgBywHgAf8QAAHVAb8BrwH/AfwB/gL/AfgB/QH+Af8B9QH8Af4B/wHyAfwB/gH/Ae0B+wH9Af8B6gH7 + AfwB/wHnAfoB/AH/AbkBpAGVAf8B1AHFAboB/wFsAVIBPgH/AeIB1gHOAf8QAAHqAaoBiwH/AeoBqgGL + Af8B6AGmAYYB/wHmAaABgQH/AeMBmgGBAf8B4AGTAXcB/wHdAYwBbQH/AdoBhAFjAf8B1wGBAVkB/wHU + AYABTwH/AdABeAFHAf8BzwFzAUEB/yQAAeoBqgGLAf8B6AGcAYEB/wGYAVQBLgH/JAADCAH/AggBIwH/ + ASQBNwFjAf8BRAFmAYYB/wEJARIBPgH/AVMBQQFiAf8DCAH/AwgB/wMIAf8BxwG6Ac0B/xQAAdgBwgGy + Af8B/AH+Av8B/AH+Av8B/AH+Av8B/AH+Av8B/AH+Av8B/AH+Av8B/AH+Av8BwAGrAZwB/wFsAVIBPgH/ + AeIB1gHOAf+YAAEqASUBOQH/AwgB/wMIAf8DCAH/AwgB/wHYAcsB4AH/JAAB2AHCAbIB/wHYAcIBsgH/ + AdgBwgGyAf8B2AHCAbIB/wHYAcIBsgH/AdgBwgGyAf8B1AG+Aa4B/wHPAbkBqQH/AckBswGkAf8B4gHW + Ac4B/6AAAwgB/wMIAf8DCAH/AccBugHNAf//AC0AAf8B3gG4Af8BvAFoASgB/wHcAYEBSAH/AdwBfQFD + Af8B3AF7AT8B/wHcAXcBPQH/AdwBdQE5Af8B4QFwATQB/wHYAXUBOQH/AdYBdQE5Af8B2AF1ATkB/wHY + AXUBOwH/AcMBcAEyAf/MAAH/AaUBgQH/AesBswGGAv8B4wG+Av8BxQGeAv8BtAGHAv8BpQGBAv8BjwFj + Av8BjQFuAv8BjQFmAv8BjQFjAv8BjQFkAv8BjwFoAf8B2gF1ATkB/wQAAYABhAGPAf8BdQGBAYUB/wFp + AXYBgQH/AVoBZgFvAf8BSwFVAV0B/wE6AUMBSgH/ASwBMwE5Af8BHwElASoB/wEXARwBIQH/ARcBHAEh + Af8BFwEcASEB/wEXARwBIQH/ARcBHAEhAf8BFwEcASEB/wEXARwBIQH/SAABzQFsATMB/wHIAWQBOgH/ + AbQBYAEyAf8BrwFkASwB/wGgAVMBOQH/AZABUwEtAf8BmAFTASgB/wGFAUsBLgH/AYQBSgEnAf8BgQFF + ASwB/wGBAU0BMAH/AZEBRgEmAf8UAAH/AaUBgQH/AesBswGGAv8B6QHHAv8B0QGpAv8BwgGYAv8BsQGB + Av8BogGBAv8B7wHrAv8BjwFsAv8BiQFbAv8BiwFhAv8BjQFkAf8B2AF1ATkB/wQAAYEBhwGSAf8BogHf + AfAB/wF5Ac0B6gH/AVIBuAHiAf8BQAGuAdsB/wE2AakB2QH/AS8BoQHSAf8BKgGYAccB/wEpAY4BvAH/ + AScBgwGuAf8BIgGBAasB/wEeAYEBqQH/ASQBgQGfAf8BKAF7AZYB/wEfASUBKgH/CAABtwGiAZMB/wFq + AVABPAH/AW0BUwE/Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/Af8BbQFTAT8B/wFtAVMBPwH/AW0BUwE/ + Af8BbQFTAT8B/wFtAVMBPwH/AXIBWAFEAf8QAAHQAW8BNgL/Ae4B8QH/AfkB9wHvAf8C7QHnAf8B9gHk + AdkC/wHjAcwB/wHtAd0BzQH/AfYB3gHMAf8B8gHaAcIB/wHvAdABwQH/AesByAG0Af8BiQFGASsB/xQA + AesBswGGAf8B6wGGAVcC/wHvAc8C/wHeAbgC/wHSAakC/wG4AZYK/wGHAWoC/wGBAVcC/wGEAVsC/wGP + AWQB/wHWAXIBNgH/BAABgQGKAZUB/wGqAegB9gH/AZUB5QH8Af8BhAHfAfsB/wGAAdYB+gH/AXMB0AH3 + Af8BZgHGAfQB/wFZAb4B8AH/AUoBtAHsAf8BPgGqAegB/wE0AaQB5gH/ASkBmgHfAf8BHwGQAdcB/wEk + AYEBnwH/ASkBMAE2Af8IAAG9AagBmQH/AfwB/gH8Af8B5wHmAeQB/wHnAeIB3AH/AeYB3AHUAf8B5QHW + AcsB/wHkAc8BwQH/AeMBygG4Af8B4wHFAbEB/wHiAcIBrAH/AccBqgGYAf8BcgFYAUQB/xAAAdYBdQE8 + Av8B+QH0Af8BqAFbAUEB/wGoAVsBQQH/AagBWwFBAf8BqAFbAUEB/wGoAVsBQQH/AagBWwFBAf8BqAFb + AUEB/wH7Ac8BtwH/AesBzwGwAf8BjQFQAS4B/wgAAeEB7gH0Af8BggGsAb8B/wFtAZABogL/Ad4BuAH/ + AeEBgQFQAv8B5QHFAv8B6wHLAv8B7QHLAf8B1gKzAf8CogHWAf8BgQF3AZoC/wGYAXMC/wGRAWMC/wGE + AVsB/wHtAXMBNAH/AesBswGGAf8EAAGBAY4BmAH/AbAB6gH2Af8BnwHpAfsB/wGSAeQB/AH/AYEB3QH7 + Af8BgAHWAfoB/wFxAc4B9wH/AWYBxgH0Af8BVgG8AfAB/wFKAbQB7AH/AT4BqgHoAf8BMwGjAeYB/wEm + AZYB3AH/AR4BgQGpAf8BNgE9AUQB/wgAAcYBsAGhAf8B/AH+AfwB/wHYAcQBuQH/AdYBwAG1Af8B0wG8 + Aa8B/wH6Ae8B5gH/Ac8BswGlAf8BzAGvAZ8B/wHKAasBmwH/AfYB2wHIAf8BxwGqAZgB/wFyAVgBRAH/ + EAAB2wF6AUEB/wH9AfoB9gH/AfcB9QH0Af8B/QHyAe4B/wHzAewB4wH/AfUB6wHaAf8B8QHmAdIB/wHw + AeAB2QH/AfkB2wHQAf8B7QHRAcYB/wHuAc4BuwH/AYoBRwEsAf8IAAFxAZcBrQH/AVsBsAHRAf8BhAHV + AegB/wGhAesB9gH/AdoBpQGBAf8B9gGHAVQC/wG2AYQB/wH8AYkBdwH/AdIBwAHRAf8BdgGgAdAB/wE5 + AVgBgQH/AekBeQFsAv8BlgGBAf8B+AFwASoB/wHnAboBjQH/CAABgQGRAZwB/wG2Ae0B+AH/AaoB7AH7 + Af8BmwHoAfsB/wGPAeMB/AH/AYEB3QH7Af8BegHVAfkB/wFxAc4B9wH/AWQBxQH0Af8BVgG8AfAB/wFG + AbIB7AH/ATsBqQHoAf8BLQGeAeIB/wEZAYIBtAH/AUQBTAFUAf8IAAHMAbYBpwH/AfwB/gH8Af8B/AH+ + AfwB/wH8Af4B/AH/AfsB+gH3Af8B+wH1Ae8B/wH6Ae8B5gH/AfkB6AHcAf8B9wHhAdEB/wH2AdsByAH/ + AcgBrgGcAf8BcgFYAUQB/xAAAd8BgAFFAv8B/QH1Af8BqAFbAUEB/wGoAVsBQQH/Af4B7wHsAf8BqAFb + AUEB/wGoAVsBQQH/AfAB5AHSAf8B9AHcAdYB/wHyAdIBzAH/AfAB0gG/Af8BgwFJASwB/wgAAV0BjwGq + Af8BVwHXAv8BkAHqAfoB/wGhAesB9gH/AXsB2QH0Av8B3gG4Af8B1gGgAYEB/wEdAgoB/wFgAWcBgQH/ + AXEBmAHOAf8BbAGPAb4B/wEpAV4BgQH/AVcBdAGQAf8B9gHSAbMB/wwAAYMBlQGfAf8BvgHwAfkB/wGr + AfAB9wH/AaUB7AH7Af8BmAHnAfsB/wGJAeEB/AH/AYEB3QH7Af8BegHVAfkB/wFuAc0B9wH/AWEBxAHz + Af8BVAG7AfAB/wFGAbIB7AH/ATUBpAHjAf8BFQGKAb8B/wFSAVwBZQH/CAABzAG2AacB/wH8Af4B/AH/ + AdsBygHAAf8B2gHIAb0B/wHYAcQBuQH/AfsB+gH3Af8B0wG8Aa8B/wHRAbgBqgH/Ac8BswGlAf8B9wHh + AdEB/wHIAbIBogH/AXIBWAFEAf8QAAHkAYEBSgH/AfkB/gH8Av8B/gH5Af8B9QL3Af8B/QHuAesB/wH2 + AeoB5gH/AfcB6AHlAf8B/AHiAdwB/wHqAeMBzwH/AfQB1gHFAf8B+wHYAb4B/wGKAUwBKgH/CAABXgGR + Aa4B/wFWAdIB+gH/AY0B5AH2Af8BoQHrAfYB/wF6AdcB8wH/AS4BuQHvAf8BCwGnAegB/wEZASQBSQH/ + AVEBgQGoAf8BhwGxAdcB/wGFAbQB1wH/AXEBogHWAf8BfAGaAckB/xAAAYYBmQGjAf8BvgHwAfkB/wG2 + Ae0B+AH/AbAB7gH6Af8BpAHrAfoB/wGVAeYB+wH/AYkB4QH8Af8BgQHcAfwB/wF6AdUB+QH/AW4BzQH3 + Af8BYQHEAfMB/wFSAbkB7wH/AT4BqQHnAf8BFQGPAccB/wFgAWwBdAH/CAABzAG2AacB/wH8Af4B/AH/ + AfwB/gH8Af8B/AH+AfwB/wH8Af4B/AH/AfwB/gH8Af8B+wH6AfcB/wH7AfUB7wH/AfoB7wHmAf8B+QHo + AdwB/wHJAbcBqgH/AXIBWAFEAf8QAAHtAYIBUwH/AfsB/QP/AfwB+QH/AfwB/wH2Af8B+wH4AeoB/wHz + AfcB6wL/AecB4wH/AfUB7wHkAf8B/gHmAdoB/wHrAd4BzgH/Ae8B4QHFAf8BiAFPAS4B/wgAAWEBlQGw + Af8BWAHSAfoB/wGNAeQB9AH/AaEB6wH2Af8BegHXAfIB/wEuAbkB7gH/AQsBpwHoAf8BewGEAbkB/wFg + AZYBywH/AYIBvAHXAf8BgQG3AdcB/wGBAbQB1gH/AXIBlAHIAf8QAAGJAZwBpgH/Ab4B8AH5Af8BtgHt + AfgB/wG2Ae0B+AH/AasB8AH3Af8BogHsAfoB/wGVAeYB+wH/AYkB4QH8Af8BgQHcAfwB/wF4AdMB+gH/ + AWwBzAH3Af8BXgHDAfMB/wFSAbkB7wH/ASIBmQHPAf8BbAF5AYEB/wgAAcwBtgGnAf8B/AH+AfwB/wHb + AcoBwAH/AdsBygHAAf8B2wHKAcAB/wH8Af4B/AH/AdgBxAG5Af8B1gHAAbUB/wHTAbwBrwH/AfoB7wHm + Af8BygG8AbMB/wFyAVgBRAH/EAAB8QGGAV0D/wH5Af8BqAFbAUEB/wGoAVsBQQL/AfIB7gH/AfAB8gH6 + Af8B9gHxAfAC/wHvAd0B/wH2AesB3QH/AfsB2wHVAf8B+AHaAc8B/wGiAVoBKgH/CAABYwGZAbUB/wFZ + AdEB+wH/AY4B5AH1Af8BoQHrAfYB/wF6AdcB8gH/AS4BuQHuAf8BCwGnAegB/wEOARYBPQH/AUgBaAGK + Af8BbgGUAcUB/wF8AagB1gH/AUwBdgGfAf8BYwGBAacB/xAAAYsBoAGoAf8BvgHwAfkB/wG+AfAB+QH/ + Ab4B8AH5Af8BvgHwAfkB/wG0AfIB+AH/AaoB7AH7Af8BoAHpAfsB/wGVAeUB/AH/AYoB3wH8Af8BgQHY + AfsB/wF9AdIB+AH/AXEBygH0Af8BZgHAAfEB/wFsAXkBgQH/CAABzAG2AacB/wH8Af4B/AH/AfwB/gH8 + Af8B/AH+AfwB/wH8Af4B/AH/AfwB/gH8Af8B/AH+AfwB/wH7AfoB9wH/AfsB9QHvAf8B+gHvAeYB/wH5 + AegB3AH/AXIBWAFEAf8QAAHuAZMBagH/AfMD/wH5Af8B9wP/AfUC/wH7AfUC/wL2Af8B+ALwAf8B9AHv + AewB/wH1AeoB5gL/AeMB3AH/AfwB2wHSAf8BnwFcATUB/wgAAWYBmwG3Af8BWQHQAfkB/wGNAeMB9QH/ + AaEB6wH2Af8BfAHZAfIB/wEuAbkB7gH/AQsBpwHoAf8DCgH/AgoBJQH/ASYBOQFlAf8BRgFoAYYB/wIo + AWMB/wFVAUMBZAH/EAABjQGhAaoB/wGNAaEBqgH/AY0BoQGqAf8BjQGhAaoB/wGNAaEBqgH/AYsBnwGo + Af8BiQGcAaYB/wGJAZsBpgH/AYcBmgGkAf8BhgGZAaMB/wGEAZYBoAH/AYQBlgGgAf8BgwGVAaAB/wGD + AZUBoAH/AYABhAGPAf8IAAHrAawBjQH/AeoBqgGMAf8B6gGpAYkB/wHpAaIBgQH/AegBmQF7Af8B5gGP + AW0B/wHlAYUBXwH/AeMBgQFRAf8B4wGAAUYB/wHiAXwBQgH/AeMBfQFDAf8BzgFyAUAB/xAAAecBlAFx + Af8B7wGLAWUB/wHwAYoBaQH/AeUBgQFcAf8B4QGBAUIB/wHjAYEBQQH/AdgBfQE/Af8BzwF1AT4B/wHY + AW8BPAH/Ab4BZgEwAf8BqQFgATMB/wG4AWIBLAH/CAABaAGeAboB/wFXAdAB+QH/AY0B4wH0Af8BoQHr + AfYB/wF5AdcB8gH/ASkBtwHuAf8BCwGnAegB/wEsAScBOwH/AwoB/wMKAf8DCgH/AwoB/wHYAcsB4AH/ + EAABjwGkAawB/wGyAeQB7AH/AbYB7QH4Af8BtgHtAfgB/wGpAewB9gH/AZIB4QHzAf8BjQGhAaoB/wHV + AdwB4AH/JAAB6wGsAY0C/wHDAaIB/wH+Ab8BnQH/AfwBuwGYAf8B+wG2AZIB/wH6AbABiwH/AfkBqwGD + Af8B+AGmAYEB/wH1AaABgQH/AfUBmgF3Af8B9QGXAXIB/wHUAXoBSAH/EAAB5AGXAYEB/wH9Ab4BqgL/ + AbsBpwL/AbgBoQL/AbYBkQH/Af0BrgGFAv8BrwGHAv8BqwGEAv8BpQGBAv8BowF7Af8B/QGZAXkB/wG4 + AV8BMwH/CAABaQGiAbwB/wFRAc4B9wH/AYsB4wH0Af8BoQHrAfYB/wF4AdYB8gH/ASkBtwHuAf8BCwGn + AegB/wENAZwB2gH/AwoB/wMKAf8DCgH/AccBugHNAf8UAAHaAd4B4QH/AY8BpAGsAf8BjwGkAawB/wGP + AaQBrAH/AY8BpAGsAf8BjwGkAawB/wHVAdwB4AH/KAAB6wGsAY0B/wHqAaoBiwH/AeoBqgGLAf8B6gGo + AYkB/wHpAaIBgQH/AegBnAGBAf8B5wGUAXUB/wHmAYwBagH/AeUBhQFeAf8B5AGBAVMB/wHjAYEBSgH/ + AeMBgQFJAf8QAAHVAZ8BiAH/Ae4BnQF6Af8B4gGVAW4B/wHhAZQBZgH/AeYBhgFaAf8B6AGBAVIB/wHo + AYEBTAH/AeIBgQFBAf8B3wF1ATwB/wHRAW4BMAH/Ac0BbAE5Af8BuQFnATwB/wgAAXUBqQHAAf8BYAHU + AfoB/wGcAewB+gH/AasB7wH6Af8BpgHtAfgB/wGUAecB+AH/AXsB2QH2Af8BRgG9AekB/wFNAYEBlwH/ + 3AABgQGzAcUB/wGbAd4B6wH/AcUB+QH9Af8BxQH5Af0B/wHFAfkB/QH/AcUB+QH9Af8BxQH5Af0B/wGg + Ad8B6gH/AXABkQGiAf/cAAHSAekB7wH/AZUBwwHTAf8BgQGrAboB/wF6AaMBswH/AXYBnQGvAf8BdQGb + Aa4B/wF5AaIBtAH/AYgBsgHCAf8BxAHcAeQB/xwAAUIBTQE+BwABPgMAASgDAAFAAwABUAMAAQEBAAEB + BQABgAECFgAD/4EAAeABAAL/BAAB4AEAAv8EAAHgAQAC/wQAAeABAAL/BAAB4AEAAfgFAAHgAQAB+AcA + ARgPAAEYBwAB+AcAAfgHAAH4BwAC/wYAAv8EAAHgAQEC/wQAAeABAwL/BAAC/wHgAQAC/wHwAQ8BAAEf + AeABAAHAAQEB4AEHAQABHwHgAQABwAEBAcABAwEAAQEB4AEAAcABAQHAAQMBAAEBAeABAAHAAQEBwAED + AQABAQHgAQABwAEBAcABAwEAAQEB4AEAAfgBDwHAAQMBAAEBAgAB+AEPAcABAwEAAQEBAAE/AfgBDwHA + AQMBAAEBAQABOwH/AX8BwAEDAQABAQEAATEB/wF/AcABAwEAAQEBAAE7AfgBDwHAAQMBwAEBAQABOwH4 + AQ8BwAEDAcABAQEAATsB+AEPAcABAwHAAQEBAAEHAfgBDwHgAQcBwAEBAQABPwH4AQ8B8AEPBv8BwAED + AcABAwL/AfgBAAHAAQMBwAEDAeIBIwHwAQABwAEDAcABAwHiASMBgAEAAcABAwHAAQMB4gEjAgABwAED + AcABAwH3AXcCAAHAAQMBwAEDAfcBdwIAAcABAwHAAQMB9wF3AQABAQHAAQMBwAEDAfABBwEAAQMBwAED + AcABAwH/AX8BwAEDAcABAwHAAQMB/wF/AeABAwHAAQMBwAEDAf4BPwHgAQMBwAEDAcABAwH+AT8B4AED + AcABAwHAAQMB/gE/AeABBwHAAQcE/wHgAX8BwAEPBP8B8An/AeABAAb/AeABAAGAAQAC/wHAAQMB4AEA + AYABAAHAAQMBwAEDAeABAAGAAQABwAEDAcABAwIAAYABAAHAAQMBwAEDAQABAQGAAQABwAEDAcABAwEA + AQMBgAEAAcABAwHAAQMBAAEHAYABAAHAAQMBwAEDAQABBwGAAQABwAEDAcABAwEAAQcBgAEAAcABAwHA + AQMBAAEHAYABAAHAAQMBwAEDAQABBwGAAX8BwAEDAcABAwEAAQ8BgAH/AcABAwHAAQMBAAF/Bv8BAAF/ + Bv8BAAF/Cw== + + + \ No newline at end of file diff --git a/OpenDBDiff/Updater.cs b/OpenDBDiff/Updater.cs new file mode 100644 index 0000000..ce52190 --- /dev/null +++ b/OpenDBDiff/Updater.cs @@ -0,0 +1,183 @@ +using OpenDBDiff.Abstractions.Schema; +using OpenDBDiff.Abstractions.Schema.Model; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Text; +using System.Windows.Forms; + +namespace OpenDBDiff +{ + /// + /// Handles the SQL update queries + /// + static class Updater + { + public static string createNew(ISchemaBase target, string connectionString) + { + string script = target.ToSql(); + script = script.Replace("GO", ""); + //script = script.Replace("\r", ""); + //script = script.Replace("\t", ""); + //script = script.Replace("\n", ""); + string result = string.Empty; + using (SqlConnection connection = new SqlConnection(connectionString)) + { + SqlCommand command = new SqlCommand(script, connection); + + try + { + connection.Open(); + command.ExecuteNonQuery(); + connection.Close(); + } + catch (Exception e) + { + result = e.Message + "\n"; + } + } + return result; + } + + public static string addNew(ISchemaBase target, string connectionString) + { + string result = string.Empty; + string script = target.ToSqlAdd(); + script = script.Replace("GO", ""); + //script = script.Replace("\r", ""); + //script = script.Replace("\t", ""); + //script = script.Replace("\n", ""); + + using (SqlConnection connection = new SqlConnection(connectionString)) + { + SqlCommand command = new SqlCommand(script, connection); + + try + { + connection.Open(); + command.ExecuteNonQuery(); + connection.Close(); + } + catch (Exception e) + { + result = e.Message + "\n"; + } + } + return result; + } + + public static DataTable getData(ISchemaBase selected, string connectionString) + { + DataTable data = new DataTable(); + try + { + using (SqlConnection connection = new SqlConnection(connectionString)) + { + SqlCommand command = new SqlCommand(); + command.Connection = connection; + command.CommandText = "SELECT * FROM " + selected.FullName; + + connection.Open(); + SqlDataReader reader = command.ExecuteReader(CommandBehavior.KeyInfo); + data.Load(reader); + //data.Load(command.ExecuteReader()); + + connection.Close(); + } + } + catch (Exception e) + { + MessageBox.Show(e.Message); + } + return data; + } + + public static string alter(ISchemaBase target, string connectionString) + { + var db = target.RootParent as IDatabase; + using (SqlConnection connection = new SqlConnection(connectionString)) + { + if (db != null && DialogResult.Yes != MessageBox.Show(String.Format("Alter {0} {1} in {2}..{3}?\n(WARNING: No automatic backup is made!)", + target.ObjectType, + target.Name, + connection.DataSource, + connection.Database), "ALTER Destination?", MessageBoxButtons.YesNo, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button2)) + { + return "Cancelled."; + } + + var sb = new StringBuilder(); + SQLScriptList SqlDiff = target.ToSqlDiff(new List()); + string[] splitOn = { "GO" }; + string[] tempList = SqlDiff.ToSQL().Split(splitOn, StringSplitOptions.RemoveEmptyEntries); + List scripts = new List(tempList); + + foreach (string sql in scripts) + { + string script = sql; + //script = script.Replace("\r", ""); + //script = script.Replace("\t", ""); + //script = script.Replace("\n", " "); + if (target.ObjectType == ObjectType.StoredProcedure) + { + script = sql.Replace("CREATE PROCEDURE", "ALTER PROCEDURE"); + } + SqlCommand command = new SqlCommand(script, connection); + try + { + connection.Open(); + command.ExecuteNonQuery(); + connection.Close(); + } + catch (Exception e) + { + sb.AppendLine($"{target.Name}: {e.Message}"); + connection.Close(); + } + } + return sb.ToString(); + } + } + + public static string rebuild(ISchemaBase target, string connectionString) + { + SQLScriptList SqlDiff = target.ToSqlDiff(new List()); + string[] splitOn = { "GO" }; + string[] tempList = SqlDiff.ToSQL().Split(splitOn, StringSplitOptions.RemoveEmptyEntries); + List scripts = new List(tempList); + string result = string.Empty; + string script = scripts[0]; + if (target.ObjectType == ObjectType.Table) + { + script = script.Replace("CREATE TABLE", "ALTER TABLE"); + } + MessageBox.Show(script); + return result; + } + + public static bool CommitTable(DataTable table, string tableFullName, string ConnectionString) + { + using (SqlConnection connection = new SqlConnection(ConnectionString)) + { + SqlCommand command = new SqlCommand("SELECT * FROM " + tableFullName, connection); + SqlDataAdapter da = new SqlDataAdapter(command); + try + { + using (SqlCommandBuilder builder = new SqlCommandBuilder(da)) + { + connection.Open(); + da.Update(table); + connection.Close(); + return true; + } + } + catch (Exception e) + { + MessageBox.Show(e.Message); + return false; + } + } + } + } +} diff --git a/OpenDBDiff/Utils/GraphicsUtils.cs b/OpenDBDiff/Utils/GraphicsUtils.cs new file mode 100644 index 0000000..ed74bb2 --- /dev/null +++ b/OpenDBDiff/Utils/GraphicsUtils.cs @@ -0,0 +1,47 @@ +using System; +using System.Drawing; +using System.Drawing.Text; +using System.Linq; + +namespace OpenDBDiff.Utils +{ + internal static class GraphicsUtils + { + private static readonly Lazy bitmap = new Lazy(() => new Bitmap(1, 1)); + private static readonly Lazy graphics = new Lazy(() => Graphics.FromImage(bitmap.Value)); + + private static readonly Lazy preferredFont = new Lazy(() => + { + var fontNames = new string[] { "Consolas", "Courier New", "Courier" }; + var fontsCollection = new InstalledFontCollection(); + var installedNames = fontsCollection.Families.Select(ff => ff.Name); + return fontNames.FirstOrDefault(fn => installedNames.Contains(fn)) ?? "Courier"; + }); + + public static SizeF GetTextDimensions(string text, Font font) + { + return GetTextDimensions(text, font, StringFormat.GenericTypographic); + } + + public static SizeF GetTextDimensions(string text, Font font, StringFormat stringFormat) + { + return graphics.Value.MeasureString(text, font, int.MaxValue, stringFormat); + } + + public static SizeF GetTextDimensions(string text, string fontName, float fontSize) + { + return GetTextDimensions(text, fontName, fontSize, StringFormat.GenericTypographic); + } + + public static SizeF GetTextDimensions(string text, string fontName, float fontSize, StringFormat stringFormat) + { + var font = new Font(fontName, fontSize); + return graphics.Value.MeasureString(text, font, int.MaxValue, stringFormat); + } + + public static string PreferredFont() + { + return preferredFont.Value; + } + } +} diff --git a/OpenDBDiff/XmlConfig/ConfigProvider.cs b/OpenDBDiff/XmlConfig/ConfigProvider.cs new file mode 100644 index 0000000..19ae2a3 --- /dev/null +++ b/OpenDBDiff/XmlConfig/ConfigProvider.cs @@ -0,0 +1,11 @@ +namespace OpenDBDiff.XmlConfig +{ + public class ConfigProvider + { + public string Library { get; set; } + + public string Key { get; set; } + + public string Description { get; set; } + } +} diff --git a/OpenDBDiff/XmlConfig/ConfigProviders.cs b/OpenDBDiff/XmlConfig/ConfigProviders.cs new file mode 100644 index 0000000..b89c58a --- /dev/null +++ b/OpenDBDiff/XmlConfig/ConfigProviders.cs @@ -0,0 +1,31 @@ +using System.Collections; +using System.Xml; + +namespace OpenDBDiff.XmlConfig +{ + public class ConfigProviders + { + private static Hashtable providers = null; + + public static ConfigProvider GetProvider(string key) + { + XmlNodeList nodes; + if (providers == null) + { + XmlDocument xmldom = new XmlDocument(); + xmldom.Load("OpenDBDiffConfig.xml"); + nodes = xmldom.SelectNodes("OpenDBDiff/Providers/Provider"); + providers = new Hashtable(); + for (int index = 0; index < nodes.Count; index++) + { + ConfigProvider provider = new ConfigProvider(); + provider.Description = nodes[index].Attributes.GetNamedItem("description").Value; + provider.Key = nodes[index].Attributes.GetNamedItem("key").Value; + provider.Library = nodes[index].Attributes.GetNamedItem("library").Value; + providers.Add(key, provider); + } + } + return (ConfigProvider)providers[key]; + } + } +} diff --git a/OpenDBDiff/packages.config b/OpenDBDiff/packages.config new file mode 100644 index 0000000..2364b61 --- /dev/null +++ b/OpenDBDiff/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/OpenDBDiffCmd/App.config b/OpenDBDiffCmd/App.config new file mode 100644 index 0000000..d39d31b --- /dev/null +++ b/OpenDBDiffCmd/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/OpenDBDiffCmd/CommandlineOptions.cs b/OpenDBDiffCmd/CommandlineOptions.cs new file mode 100644 index 0000000..38b94e8 --- /dev/null +++ b/OpenDBDiffCmd/CommandlineOptions.cs @@ -0,0 +1,26 @@ +using CommandLine; +using CommandLine.Text; + +namespace OpenDBDiff.OCDB +{ + public class CommandlineOptions + { + [Option('b', "before", Required = true, HelpText = "Connection string of database before changes are applied.")] + public string Before { get; set; } + + [Option('a', "after", Required = true, HelpText = "Connection string of database after changes are applied.")] + public string After { get; set; } + + [Option('o', "outputfile", Required = false, HelpText = "Output file of action script. If omitted, script is written to the console.")] + public string OutputFile { get; set; } + + [ParserState] + public IParserState LastParserState { get; set; } + + [HelpOption] + public string GetUsage() + { + return HelpText.AutoBuild(this, (HelpText current) => HelpText.DefaultParsingErrorsHandler(this, current)); + } + } +} diff --git a/OpenDBDiffCmd/OpenDBDiff.OCDB.csproj b/OpenDBDiffCmd/OpenDBDiff.OCDB.csproj new file mode 100644 index 0000000..463dca3 --- /dev/null +++ b/OpenDBDiffCmd/OpenDBDiff.OCDB.csproj @@ -0,0 +1,90 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E794AA28-EE68-44BD-827B-1BFD9C106B65} + Exe + Properties + OpenDBDiff.OCDB + OCDB + v4.5.2 + 512 + + + + + 3.5 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + + ..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll + True + + + + + + + + + + + + Properties\AssemblyVersionInfo.cs + + + + + + + + {32ac9af6-db93-4354-b69f-6dbc65c70867} + DBDiff.Schema.SQLServer.Generates + + + {EF2F571E-A7AD-40BE-8500-50A039159FC1} + DBDiff.Schema.SQLServer + + + {406558A0-1B98-4D0E-B8B6-2013700B065A} + DBDiff.Schema + + + + + .editorconfig + + + + + + + \ No newline at end of file diff --git a/OpenDBDiffCmd/Program.cs b/OpenDBDiffCmd/Program.cs new file mode 100644 index 0000000..9020c3f --- /dev/null +++ b/OpenDBDiffCmd/Program.cs @@ -0,0 +1,116 @@ +using OpenDBDiff.Schema.SQLServer.Generates.Generates; +using OpenDBDiff.Schema.SQLServer.Generates.Model; +using OpenDBDiff.Schema.SQLServer.Generates.Options; +using System; +using System.Data.SqlClient; +using System.Diagnostics; +using System.IO; + +namespace OpenDBDiff.OCDB +{ + public class Program + { + private static SqlOption SqlFilter = new SqlOption(); + + protected Program() { } + + private static int Main(string[] args) + { + bool completedSuccessfully = false; + + var options = new CommandlineOptions(); + if (CommandLine.Parser.Default.ParseArguments(args, options)) + { + try + { + completedSuccessfully = Work(options); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } + + if (Debugger.IsAttached) + { + Console.WriteLine("Press any key to continue..."); + Console.ReadKey(false); + } + + return completedSuccessfully ? 0 : 1; + } + + private static Boolean TestConnection(string connectionString1) + { + using (SqlConnection connection = new SqlConnection()) + { + connection.ConnectionString = connectionString1; + connection.Open(); + connection.Close(); + return true; + } + } + + private static bool Work(CommandlineOptions options) + { + try + { + Database origin; + Database destination; + if (TestConnection(options.Before) + && TestConnection(options.After)) + { + Generate sql = new Generate(); + sql.ConnectionString = options.Before; + Console.WriteLine("Reading first database..."); + sql.Options = SqlFilter; + origin = sql.Process(); + + sql.ConnectionString = options.After; + Console.WriteLine("Reading second database..."); + destination = sql.Process(); + Console.WriteLine("Comparing databases schemas..."); + origin = Generate.Compare(origin, destination); + // temporary work-around: run twice just like GUI + origin.ToSqlDiff(new System.Collections.Generic.List()); + + Console.WriteLine("Generating SQL file..."); + var script = origin.ToSqlDiff(new System.Collections.Generic.List()).ToSQL(); + if (!string.IsNullOrWhiteSpace(options.OutputFile)) + { + Console.WriteLine("Writing action script to {0}", options.OutputFile); + SaveFile(options.OutputFile, script); + } + else + { + Console.WriteLine(); + Console.WriteLine(script); + Console.WriteLine(); + } + return true; + } + } + catch (Exception ex) + { + string newIssueUri = System.Configuration.ConfigurationManager.AppSettings["OpenDBDiff.NewIssueUri"]; + if (string.IsNullOrEmpty(newIssueUri)) + newIssueUri = "https://github.com/OpenDBDiff/OpenDBDiff/issues/new"; + + Console.WriteLine($"{ex.Message}\r\n{ex.StackTrace}\r\n\r\nPlease report this issue at {newIssueUri}."); + Console.WriteLine(); + } + + return false; + } + + private static void SaveFile(string filenmame, string sql) + { + if (!String.IsNullOrEmpty(filenmame)) + { + StreamWriter writer = new StreamWriter(filenmame, false); + writer.Write(sql); + writer.Close(); + } + } + } +} diff --git a/OpenDBDiffCmd/Properties/AssemblyInfo.cs b/OpenDBDiffCmd/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2d2224b --- /dev/null +++ b/OpenDBDiffCmd/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenDBDiff Console")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("OpenDBDiff Console")] +[assembly: AssemblyCopyright("OpenDBDiff")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("30c9b799-3cd9-4c83-9141-dc7782005ec1")] diff --git a/OpenDBDiffCmd/packages.config b/OpenDBDiffCmd/packages.config new file mode 100644 index 0000000..e1a8737 --- /dev/null +++ b/OpenDBDiffCmd/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3d138e3 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# OpenDBDiff +A database comparison tool for Microsoft SQL Server 2005+ that reports schema differences and creates a synchronization script. + +[![Build status](https://ci.appveyor.com/api/projects/status/rdng91bfx3ao8ts6?svg=true)](https://ci.appveyor.com/project/OpenDBDiff/OpenDBDiff/branch/develop/artifacts) + +[💾 Download latest release](https://github.com/OpenDBDiff/OpenDBDiff/releases/latest) + +[💾 Download develop CI build](https://ci.appveyor.com/project/OpenDBDiff/OpenDBDiff/branch/develop/artifacts) + +Open DBDiff can synchronize +* Tables (including Table Options like vardecimal, text in row, etc.) +* Columns (including Computed Columns, XML options, Identities, etc.) +* Constraints +* Indexes (and XML Indexes) +* XML Schemas +* Table Types +* User Data Types (UDT) +* CLR Objects (Assemblies, CLR-UDT, CLR-Store Procedure, CLR-Triggers) +* Triggers (including DDL Triggers) +* Synonyms +* Schemas +* File groups +* Views +* Functions +* Store Procedures +* Partition Functions/Schemes +* Users +* Roles + +![image](https://cloud.githubusercontent.com/assets/145854/24702579/9e657426-19ff-11e7-9722-9d2f4a54d2ed.png) +![image](https://cloud.githubusercontent.com/assets/145854/24702592/abc1b094-19ff-11e7-9e1b-d4ed581105a3.png) + +Icons provided from http://www.fatcow.com/free-icons under under a Creative Commons Attribution 3.0 License. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..924af02 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,27 @@ +version: 0.13.0.{build} +image: Visual Studio 2019 + +# enable patching of AssemblyInfo.* files +assembly_info: + patch: true + file: OpenDBDiff\Properties\AssemblyVersionInfo.cs + assembly_version: "{version}" + assembly_file_version: "{version}" + assembly_informational_version: "{version}" + +before_build: +- cmd: nuget restore OpenDBDiff.sln + +configuration: +- Release + +build: + parallel: true # enable MSBuild parallel builds + project: OpenDBDiff.sln + verbosity: minimal + +artifacts: +- path: OpenDBDiff\bin\Release + name: OpenDBDiff.CI +- path: OpenDBDiff.CLI\bin\Release + name: OpenDBDiff.CLI.CI diff --git a/resources/icons/application.ico b/resources/icons/application.ico new file mode 100644 index 0000000..6bd39cc Binary files /dev/null and b/resources/icons/application.ico differ diff --git a/resources/icons/application.xcf b/resources/icons/application.xcf new file mode 100644 index 0000000..7e85ffa Binary files /dev/null and b/resources/icons/application.xcf differ diff --git a/resources/icons/psd/OpenDBDiff.psd b/resources/icons/psd/OpenDBDiff.psd new file mode 100644 index 0000000..f49dc78 Binary files /dev/null and b/resources/icons/psd/OpenDBDiff.psd differ diff --git a/resources/icons/psd/OpenDBDiff_128.psd b/resources/icons/psd/OpenDBDiff_128.psd new file mode 100644 index 0000000..1def011 Binary files /dev/null and b/resources/icons/psd/OpenDBDiff_128.psd differ diff --git a/resources/icons/psd/OpenDBDiff_16.psd b/resources/icons/psd/OpenDBDiff_16.psd new file mode 100644 index 0000000..8a28a67 Binary files /dev/null and b/resources/icons/psd/OpenDBDiff_16.psd differ diff --git a/resources/icons/psd/OpenDBDiff_256.psd b/resources/icons/psd/OpenDBDiff_256.psd new file mode 100644 index 0000000..47bea20 Binary files /dev/null and b/resources/icons/psd/OpenDBDiff_256.psd differ diff --git a/resources/icons/psd/OpenDBDiff_32.psd b/resources/icons/psd/OpenDBDiff_32.psd new file mode 100644 index 0000000..6029e53 Binary files /dev/null and b/resources/icons/psd/OpenDBDiff_32.psd differ diff --git a/resources/icons/psd/OpenDBDiff_64.psd b/resources/icons/psd/OpenDBDiff_64.psd new file mode 100644 index 0000000..592bee5 Binary files /dev/null and b/resources/icons/psd/OpenDBDiff_64.psd differ diff --git a/resources/icons/psd/readme.txt b/resources/icons/psd/readme.txt new file mode 100644 index 0000000..01ee2bb --- /dev/null +++ b/resources/icons/psd/readme.txt @@ -0,0 +1 @@ +Application icon designed by Ervin Nagy ( http://github.com/beerwin ) \ No newline at end of file