Skip to content

Commit

Permalink
Merge remote-tracking branch 'keith-hall/master'
Browse files Browse the repository at this point in the history
Conflicts:
	readme.md
  • Loading branch information
sethreno committed Jun 23, 2015
2 parents 3355bd7 + 131829f commit 74d9b31
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 39 deletions.
20 changes: 20 additions & 0 deletions console/Compare.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.IO;
using ManyConsole;
using model;
using NDesk.Options;
Expand All @@ -7,6 +8,8 @@ namespace console {
internal class Compare : ConsoleCommand {
private string _source;
private string _target;
private string _outDiff;
private bool _overwrite;

public Compare() {
IsCommand("Compare", "Compare two databases.");
Expand All @@ -20,6 +23,14 @@ public Compare() {
"t|target=",
"Connection string to a database to compare.",
o => _target = o);
HasOption(
"outFile=",
"Create a sql diff file in the specified path.",
o => _outDiff = o);
HasOption(
"o|overwrite=",
"Overwrite existing target without prompt.",
o => _overwrite = o != null);
}

public override int Run(string[] remainingArguments) {
Expand All @@ -32,6 +43,15 @@ public override int Run(string[] remainingArguments) {
DatabaseDiff diff = sourceDb.Compare(targetDb);
if (diff.IsDiff) {
Console.WriteLine("Databases are different.");
if (!string.IsNullOrEmpty(_outDiff)) {
if (!_overwrite && File.Exists(_outDiff)) {
if (!ConsoleQuestion.AskYN(string.Format("{0} already exists - do you want to replace it", _outDiff))) {
return 1;
}
}
File.WriteAllText(_outDiff, diff.Script());
Console.WriteLine("Script to make the databases identical has been created at {0}", Path.GetFullPath(_outDiff));
}
return 1;
}
Console.WriteLine("Databases are identical.");
Expand Down
5 changes: 5 additions & 0 deletions console/ConsoleQuestion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,10 @@ public static bool AskYN(string question) {
Console.WriteLine();
return key.Key == ConsoleKey.Y;
}

public static void WaitForKeyPress() {
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
}
}
8 changes: 7 additions & 1 deletion console/Create.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using model;

Expand All @@ -11,7 +11,9 @@ public Create()
public override int Run(string[] remainingArguments) {
Database db = CreateDatabase();
if (!Directory.Exists(db.Dir)) {
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Snapshot dir {0} does not exist.", db.Dir);
Console.ForegroundColor = ConsoleColor.White;
return 1;
}

Expand All @@ -30,13 +32,17 @@ public override int Run(string[] remainingArguments) {
} catch (BatchSqlFileException ex) {
Console.WriteLine();
Console.WriteLine(@"Create completed with the following errors:");
Console.ForegroundColor = ConsoleColor.Red;
foreach (SqlFileException e in ex.Exceptions) {
Console.WriteLine(@"{0} (Line {1}): {2}", e.FileName.Replace("/", "\\"), e.LineNumber, e.Message);
}
Console.ForegroundColor = ConsoleColor.White;
return -1;
} catch (SqlFileException ex) {
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(@"An unexpected SQL error occurred while executing scripts, and the process wasn't completed.
{0} (Line {1}): {2}", ex.FileName.Replace("/", "\\"), ex.LineNumber, ex.Message);
Console.ForegroundColor = ConsoleColor.White;
return -1;
}

Expand Down
5 changes: 5 additions & 0 deletions console/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using ManyConsole;

namespace console {
Expand All @@ -11,6 +12,10 @@ private static int Main(string[] args) {
} catch (Exception ex) {
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
#if DEBUG
if (Debugger.IsAttached)
ConsoleQuestion.WaitForKeyPress();
#endif
return -1;
}
}
Expand Down
10 changes: 8 additions & 2 deletions console/Script.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
using System.Linq;
using model;

namespace console {
namespace console
{
public class Script : DbCommand {
public Script()
: base(
Expand All @@ -17,10 +18,15 @@ public Script()
"dataTablesPattern=",
"A regular expression pattern that matches tables to export data from.",
o => DataTablesPattern = o);
HasOption(
"tableHint=",
"Table hint to use when exporting data.",
o => TableHint = o);
}

protected string DataTables { get; set; }
protected string DataTablesPattern { get; set; }
protected string TableHint { get; set; }

public override int Run(string[] args) {
Database db = CreateDatabase();
Expand All @@ -41,7 +47,7 @@ public override int Run(string[] args) {
return 1;
}

db.ScriptToDir();
db.ScriptToDir(TableHint);

Console.WriteLine("Snapshot successfully created at " + db.Dir);
return 0;
Expand Down
65 changes: 38 additions & 27 deletions model/Database.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
Expand Down Expand Up @@ -433,7 +433,7 @@ inner join sys.columns c1
inner join sys.columns c2
on fkc.referenced_column_id = c2.column_id
and fkc.referenced_object_id = c2.object_id
order by fk.name
order by fk.name, fkc.constraint_column_id
";
using (SqlDataReader dr = cm.ExecuteReader()) {
while (dr.Read()) {
Expand Down Expand Up @@ -466,26 +466,37 @@ from sys.sql_modules m
left join sys.tables t on tr.parent_id = t.object_id";
using (SqlDataReader dr = cm.ExecuteReader()) {
while (dr.Read()) {
var r = new Routine((string) dr["schemaName"], (string) dr["routineName"]);
r.Text = (string) dr["definition"];
r.AnsiNull = (bool) dr["uses_ansi_nulls"];
r.QuotedId = (bool) dr["uses_quoted_identifier"];
Routines.Add(r);

switch ((string) dr["type_desc"]) {
case "SQL_STORED_PROCEDURE":
r.RoutineType = Routine.RoutineKind.Procedure;
break;
case "SQL_TRIGGER":
r.RoutineType = Routine.RoutineKind.Trigger;
break;
case "SQL_SCALAR_FUNCTION":
case "SQL_INLINE_TABLE_VALUED_FUNCTION":
r.RoutineType = Routine.RoutineKind.Function;
break;
case "VIEW":
r.RoutineType = Routine.RoutineKind.View;
break;
if (dr["definition"] is DBNull) {
Console.ForegroundColor = ConsoleColor.Magenta;
Console.WriteLine("Warning: Unable to get definition for {0} {1}.{2}", (string)dr["type_desc"], (string)dr["schemaName"], (string)dr["routineName"]);
Console.ForegroundColor = ConsoleColor.White;
} else {
if (!((string)dr["definition"]).Contains((string)dr["routineName"])) {
Console.ForegroundColor = ConsoleColor.Magenta;
Console.WriteLine("Warning: {0} {1}.{2} has been renamed since it's definition.", (string)dr["type_desc"], (string)dr["schemaName"], (string)dr["routineName"]);
Console.ForegroundColor = ConsoleColor.White;
}
var r = new Routine((string)dr["schemaName"], (string)dr["routineName"]);
r.Text = (string)dr["definition"];
r.AnsiNull = (bool)dr["uses_ansi_nulls"];
r.QuotedId = (bool)dr["uses_quoted_identifier"];
Routines.Add(r);

switch ((string)dr["type_desc"]) {
case "SQL_STORED_PROCEDURE":
r.RoutineType = Routine.RoutineKind.Procedure;
break;
case "SQL_TRIGGER":
r.RoutineType = Routine.RoutineKind.Trigger;
break;
case "SQL_SCALAR_FUNCTION":
case "SQL_INLINE_TABLE_VALUED_FUNCTION":
r.RoutineType = Routine.RoutineKind.Function;
break;
case "VIEW":
r.RoutineType = Routine.RoutineKind.View;
break;
}
}
}
}
Expand Down Expand Up @@ -557,7 +568,7 @@ where sp.name not like '##%##'
using (SqlDataReader dr = cm.ExecuteReader()) {
while (dr.Read()) {
u = Users.SingleOrDefault(user => user.Name == (string) dr["name"]);
if (u != null)
if (u != null && !(dr["password_hash"] is DBNull))
u.PasswordHash = (byte[]) dr["password_hash"];
}
}
Expand Down Expand Up @@ -745,7 +756,7 @@ public string ScriptCreate() {

#region Script

public void ScriptToDir() {
public void ScriptToDir(string tableHint = null) {
if (Directory.Exists(Dir)) {
// delete the existing script files
foreach (
Expand Down Expand Up @@ -818,7 +829,7 @@ string f in
}


ExportData();
ExportData(tableHint);
}

private static string MakeFileName(Routine r) {
Expand All @@ -840,14 +851,14 @@ private static string MakeFileName(string schema, string name) {
return schema.ToLower() == "dbo" ? name : string.Format("{0}.{1}", schema, name);
}

public void ExportData() {
public void ExportData(string tableHint = null) {
string dataDir = Dir + "/data";
if (!Directory.Exists(dataDir)) {
Directory.CreateDirectory(dataDir);
}
foreach (Table t in DataTables) {
StreamWriter sw = File.CreateText(dataDir + "/" + MakeFileName(t) + ".tsv");
t.ExportData(Connection, sw);
t.ExportData(Connection, sw, tableHint);
sw.Flush();
sw.Close();
}
Expand Down
4 changes: 3 additions & 1 deletion model/Table.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,16 @@ public string ScriptDrop() {
}


public void ExportData(string conn, TextWriter data) {
public void ExportData(string conn, TextWriter data, string tableHint = null) {
var sql = new StringBuilder();
sql.Append("select ");
foreach (Column c in Columns.Items) {
sql.AppendFormat("[{0}],", c.Name);
}
sql.Remove(sql.Length - 1, 1);
sql.AppendFormat(" from [{0}].[{1}]", Owner, Name);
if (!string.IsNullOrEmpty(tableHint))
sql.AppendFormat(" WITH ({0})", tableHint);
using (var cn = new SqlConnection(conn)) {
cn.Open();
using (SqlCommand cm = cn.CreateCommand()) {
Expand Down
29 changes: 21 additions & 8 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,46 @@
Schema Zen - Script and create SQL Server objects quickly
--------------------------------------------------------

[![Join the chat at https://gitter.im/sethreno/schemazen](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/sethreno/schemazen?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

Schema Zen has two main commands:
Schema Zen has three main commands:

**script**
## script

schemazen.exe script --server localhost --database db --scriptDir c:\somedir
SchemaZen.exe script --server localhost --database db --scriptDir c:\somedir

This will generate sql scripts for all objects in the database in the
following directory structure:
```
c:\somedir\
assemblies
data
foreign_keys
functions
procedures
tables
triggers
users
views
xmlschemacollections
data
props.sql
schemas.sql
```
**create**
See ```SchemaZen.exe help script``` for more information, including how to specify which tables to export data from (none by default).
## create

schemazen.exe create --server localhost --database db --scriptDir c:\somedir
SchemaZen.exe create --server localhost --database db --scriptDir c:\somedir

This will create a database named db from the sql scripts in c:\somedir.
> Note that you can put additional scripts in a folder called ```after_data```, and it will run these between importing the data and adding the foreign key constraints, allowing you to "fix" any necessary records first. (You will need to create this directory first, and the **script** command will *not* affect it. The scripts will be run in alphabetical order, so you may want to prefix them with numbers if you want to enforce a certain order. i.e. ```00001 - first script.sql```, ```00002 - second script.sql```)
## compare

SchemaZen.exe compare --source "Data Source=localhost;Initial Catalog=Database1;Integrated Security=True" --target "Data Source=localhost;Initial Catalog=Database2;Integrated Security=True" --outFile c:\somedir\diff.sql

This will compare the databases named Database1 and Database2 on localhost and create a sql script called c:\somedir\diff.sql that can be run on Database2 to make it's schema identical to Database1.

---
## download SchemaZen
The latest release can be downloaded [here](https://github.com/sethreno/schemazen/releases)

[![Join the chat at https://gitter.im/sethreno/schemazen](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/sethreno/schemazen?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

0 comments on commit 74d9b31

Please sign in to comment.