initial
This commit is contained in:
12
Class1.cs
12
Class1.cs
@@ -1,12 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace DbMigrate
|
|
||||||
{
|
|
||||||
public class Class1
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
<ProjectGuid>a4a58207-cf8c-46fd-9749-3d4d8816e11a</ProjectGuid>
|
<ProjectGuid>{A4A58207-CF8C-46FD-9749-3D4D8816E11A}</ProjectGuid>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>DbMigrate</RootNamespace>
|
<RootNamespace>DbMigrate</RootNamespace>
|
||||||
@@ -31,24 +31,20 @@
|
|||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System"/>
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Core"/>
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Xml.Linq"/>
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
<Reference Include="System.Data.DataSetExtensions"/>
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="Microsoft.CSharp"/>
|
<Reference Include="System.Xml" />
|
||||||
|
|
||||||
<Reference Include="System.Data"/>
|
|
||||||
|
|
||||||
<Reference Include="System.Net.Http"/>
|
|
||||||
|
|
||||||
<Reference Include="System.Xml"/>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Class1.cs" />
|
<Compile Include="Extensions.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="SqlDatabase.cs" />
|
||||||
|
<Compile Include="SqlTable.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
76
Extensions.cs
Normal file
76
Extensions.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace DbMigrate {
|
||||||
|
internal static class Extensions {
|
||||||
|
public static string[] GetCommonColumns(this SqlTable table, SqlTable table2) {
|
||||||
|
return table.GetColumnNames().Where(f => table2.HasColumn(f)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ParseSql(this SqlTable table, string sql, string tableName = null) {
|
||||||
|
if (tableName != null) {
|
||||||
|
table.TableName = tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool inTable = false;
|
||||||
|
bool inColumns = false;
|
||||||
|
|
||||||
|
Match m = null;
|
||||||
|
foreach (string line in Regex.Split(sql, "\\r\\n")) {
|
||||||
|
if (string.IsNullOrEmpty(line) || line.StartsWith("--")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = Regex.Match(line, "^CREATE TABLE( IF NOT EXISTS)? (\\S+) ");
|
||||||
|
if (m.Success) {
|
||||||
|
if (string.IsNullOrEmpty(tableName) && string.IsNullOrEmpty(table.TableName)) {
|
||||||
|
// Set table name from the above regex match
|
||||||
|
table.TableName = m.Groups[2].Value.Trim();
|
||||||
|
}
|
||||||
|
if (!inTable && (table.TableName == null || m.Groups[2].Value.Trim() == table.TableName)) {
|
||||||
|
table.CreateTableSql += line + Environment.NewLine;
|
||||||
|
inTable = true;
|
||||||
|
inColumns = true;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (inTable) {
|
||||||
|
// We are done with this table
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m = Regex.Match(line, "^CREATE INDEX( IF NOT EXISTS)? (\\S+) ");
|
||||||
|
if (m.Success && inTable) {
|
||||||
|
table.Indexes.Add(m.Groups[2].Value.Trim(), line.Trim());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = Regex.Match(line, "^CREATE TRIGGER( IF NOT EXISTS)? (\\S+) ");
|
||||||
|
if (m.Success && inTable) {
|
||||||
|
table.Triggers.Add(m.Groups[2].Value.Trim(), line.Trim());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inColumns) {
|
||||||
|
if (line.Trim().StartsWith(")")) {
|
||||||
|
inColumns = false;
|
||||||
|
} else {
|
||||||
|
m = Regex.Match(line.Trim(), "^(\\S+).*");
|
||||||
|
if (m.Success) {
|
||||||
|
string columnLine = line.Trim();
|
||||||
|
if (columnLine.EndsWith(",")) {
|
||||||
|
columnLine = columnLine.Substring(0, columnLine.Length - 1);
|
||||||
|
}
|
||||||
|
table.Columns.Add(m.Groups[1].Value.Trim(), columnLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table.CreateTableSql += line + Environment.NewLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
120
SqlDatabase.cs
Normal file
120
SqlDatabase.cs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.OleDb;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DbMigrate {
|
||||||
|
public class SqlDatabase {
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
public string SqlScript { get; set; }
|
||||||
|
public List<SqlTable> Tables { get; set; } = new List<SqlTable>();
|
||||||
|
|
||||||
|
|
||||||
|
public SqlDatabase() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Connect(string connectionString) {
|
||||||
|
ConnectionString = connectionString;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadSql(string sql) {
|
||||||
|
SqlScript = sql;
|
||||||
|
Tables = ParseTablesFromSql(sql).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadSqlFromFile(string fileName) {
|
||||||
|
if (!File.Exists(fileName)) {
|
||||||
|
throw new FileNotFoundException("SQL file '" + fileName + "' was not found and could not be loaded.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string sql = File.ReadAllText(fileName);
|
||||||
|
LoadSql(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<SqlTable> ParseTablesFromSql(string sql) {
|
||||||
|
SqlTable table = null;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (string line in Regex.Split(sql, "\\r\\n")) {
|
||||||
|
if (string.IsNullOrEmpty(line) || line.StartsWith("--")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.ToUpper().StartsWith("CREATE TABLE ")) {
|
||||||
|
if (table != null) {
|
||||||
|
table.ParseSql(sb.ToString());
|
||||||
|
yield return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a new table
|
||||||
|
table = new SqlTable();
|
||||||
|
sb = new StringBuilder();
|
||||||
|
sb.AppendLine(line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sb.AppendLine(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
table.ParseSql(sb.ToString());
|
||||||
|
yield return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> BuildSql(string dbConnectionString, bool includeIfNotExist = false) {
|
||||||
|
using (OleDbConnection cn = new OleDbConnection(dbConnectionString)) {
|
||||||
|
string sql = "";
|
||||||
|
|
||||||
|
//List<string> TableSql = new List<string>();
|
||||||
|
IEnumerable<SqliteTableDefinition> TableDefs = await cn.QueryAsync<SqliteTableDefinition>("select * from sqlite_master");
|
||||||
|
|
||||||
|
foreach (SqliteTableDefinition table in TableDefs.Where(f => f.type == "table").OrderBy(f => f.tbl_name)) {
|
||||||
|
if (table.tbl_name == "sqlite_sequence") { continue; }
|
||||||
|
Match m = Regex.Match(table.sql, "CREATE TABLE \\S+ \\((.*)\\)", RegexOptions.Singleline);
|
||||||
|
if (!m.Success) {
|
||||||
|
Trace.TraceWarning("Unable to match regex on table " + table.name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int startIndex = m.Groups[1].Index;
|
||||||
|
int length = m.Groups[1].Length;
|
||||||
|
string columns = Regex.Replace(m.Groups[1].Value, "\\s{2,}", " ");
|
||||||
|
columns = Regex.Replace(columns.Replace(", ", ",").Replace(",\n", ","), ",(?!\\d+\\))", ",\r\n\t");
|
||||||
|
|
||||||
|
sql += "-- BEGIN TABLE " + table.tbl_name + " --\r\n";
|
||||||
|
sql += table.sql.Substring(0, startIndex) + "\r\n\t" +
|
||||||
|
columns.Trim() + "\r\n" +
|
||||||
|
table.sql.Substring(startIndex + length) + ";\r\n";
|
||||||
|
|
||||||
|
|
||||||
|
List<SqliteTableDefinition> indexes = TableDefs.Where(f => f.type == "index" && f.tbl_name == table.tbl_name && !string.IsNullOrEmpty(f.sql)).ToList();
|
||||||
|
if (indexes.Count > 0) {
|
||||||
|
sql += "\r\n-- INDEXES --\r\n";
|
||||||
|
foreach (var index in indexes) {
|
||||||
|
if (string.IsNullOrEmpty(index.sql)) { continue; }
|
||||||
|
sql += index.sql + ";\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SqliteTableDefinition> triggers = TableDefs.Where(f => f.type == "trigger" && f.tbl_name == table.tbl_name && !string.IsNullOrEmpty(f.sql)).ToList();
|
||||||
|
if (triggers.Count > 0) {
|
||||||
|
sql += "\r\n-- TRIGGERS --\r\n";
|
||||||
|
foreach (var trigger in triggers) {
|
||||||
|
if (string.IsNullOrEmpty(trigger.sql)) { continue; }
|
||||||
|
sql += trigger.sql + ";\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sql += "-- END TABLE " + table.tbl_name + " --\r\n\r\n";
|
||||||
|
//TableSql.Add(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
SqlTable.cs
Normal file
79
SqlTable.cs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DbMigrate {
|
||||||
|
public class SqlTable {
|
||||||
|
public string TableName { get; set; }
|
||||||
|
public string CreateTableSql { get; set; }
|
||||||
|
public string OriginalSql { get; set; }
|
||||||
|
public Dictionary<string, string> Columns { get; set; }
|
||||||
|
public Dictionary<string, string> Indexes { get; set; }
|
||||||
|
public Dictionary<string, string> Triggers { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public SqlTable() {
|
||||||
|
Columns = new Dictionary<string, string>();
|
||||||
|
Indexes = new Dictionary<string, string>();
|
||||||
|
Triggers = new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SqlTable(string sql) {
|
||||||
|
OriginalSql = sql;
|
||||||
|
this.ParseSql(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FullSql() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
//sb.AppendLine("-- Create Table " + TableName);
|
||||||
|
sb.AppendLine(CreateTableSql);
|
||||||
|
|
||||||
|
if (Indexes.Count > 0) {
|
||||||
|
sb.AppendLine("\r\n-- Create Indexes");
|
||||||
|
foreach (string index in Indexes.Keys) {
|
||||||
|
sb.AppendLine(Indexes[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Triggers.Count > 0) {
|
||||||
|
sb.AppendLine("\r\n-- Create Triggers");
|
||||||
|
foreach (string trigger in Triggers.Keys) {
|
||||||
|
sb.AppendLine(Triggers[trigger]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine();
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] GetColumnNames() {
|
||||||
|
return Columns.Keys.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] GetColumns() {
|
||||||
|
return Columns.Values.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasColumn(string columnName) {
|
||||||
|
return Columns.ContainsKey(columnName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] GetTriggerNames() {
|
||||||
|
return Triggers.Keys.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] GetTriggers() {
|
||||||
|
return Triggers.Values.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] GetIndexNames() {
|
||||||
|
return Indexes.Keys.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] GetIndexes() {
|
||||||
|
return Indexes.Values.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user