This commit is contained in:
2025-09-06 08:27:22 -05:00
2 changed files with 69 additions and 61 deletions

View File

@@ -55,7 +55,7 @@ namespace DbToolsTester.Forms {
return null; return null;
} }
private void ToolbarItemClicked(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { private async void ToolbarItemClicked(object sender, DevExpress.XtraBars.ItemClickEventArgs e) {
if (e.Item.Equals(bbiDelta)) { if (e.Item.Equals(bbiDelta)) {
SQLiteConnection db1 = new SQLiteConnection("Data Source=" + Database1File + ";Version=3;"); SQLiteConnection db1 = new SQLiteConnection("Data Source=" + Database1File + ";Version=3;");
SQLiteConnection db2 = new SQLiteConnection("Data Source=" + Database2File + ";Version=3;"); SQLiteConnection db2 = new SQLiteConnection("Data Source=" + Database2File + ";Version=3;");
@@ -85,7 +85,7 @@ namespace DbToolsTester.Forms {
if (frm.ShowDialog(this) == DialogResult.OK) { if (frm.ShowDialog(this) == DialogResult.OK) {
using (var cn = new SQLiteConnection("Data Source=" + (frm.SelectedDatabase == Path.GetFileName(Database1File) ? Database1File : Database2File) + ";Version=3;")) { using (var cn = new SQLiteConnection("Data Source=" + (frm.SelectedDatabase == Path.GetFileName(Database1File) ? Database1File : Database2File) + ";Version=3;")) {
SqlBuilder builder = new SqlBuilder(); SqlBuilder builder = new SqlBuilder();
string sql = builder.GetTableCreateSql(cn, frm.SelectedTable); string sql = await builder.GetTableCreateSqlAsync(cn, frm.SelectedTable);
if (!string.IsNullOrEmpty(sql)) { if (!string.IsNullOrEmpty(sql)) {
deltaSql.Text = sql; deltaSql.Text = sql;
} else { } else {

View File

@@ -4,6 +4,7 @@ using System.Data;
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace DbTools { namespace DbTools {
public class SqlBuilder { public class SqlBuilder {
@@ -52,7 +53,7 @@ namespace DbTools {
/// optionally its data. Returns an empty string if the table's schema cannot be determined.</returns> /// optionally its data. Returns an empty string if the table's schema cannot be determined.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="cn"/> is <see langword="null"/> or if <paramref name="tableName"/> is <see /// <exception cref="ArgumentNullException">Thrown if <paramref name="cn"/> is <see langword="null"/> or if <paramref name="tableName"/> is <see
/// langword="null"/> or empty.</exception> /// langword="null"/> or empty.</exception>
public string GetTableCreateSql(IDbConnection cn, string tableName, string selectStatement = null) { public async Task<string> GetTableCreateSqlAsync(IDbConnection cn, string tableName, string selectStatement = null) {
if (cn == null) { if (cn == null) {
throw new ArgumentNullException("cn"); throw new ArgumentNullException("cn");
} }
@@ -86,14 +87,14 @@ namespace DbTools {
sb.AppendLine("\t" + columns.Trim()); sb.AppendLine("\t" + columns.Trim());
sb.AppendLine(sql.Substring(startIndex + length) + ";"); sb.AppendLine(sql.Substring(startIndex + length) + ";");
string indexes = GetIndexCreateSql(cn, tableName); string indexes = await GetIndexCreateSqlAsync(cn, tableName);
if (!string.IsNullOrEmpty(indexes)) { if (!string.IsNullOrEmpty(indexes)) {
sb.AppendLine(); sb.AppendLine();
sb.AppendLine("-- INDEXES --"); sb.AppendLine("-- INDEXES --");
sb.AppendLine(indexes); sb.AppendLine(indexes);
} }
string triggers = GetTriggerCreateSql(cn, tableName); string triggers = await GetTriggerCreateSqlAsync(cn, tableName);
if (!string.IsNullOrEmpty(triggers)) { if (!string.IsNullOrEmpty(triggers)) {
sb.AppendLine(); sb.AppendLine();
sb.AppendLine("-- TRIGGERS --"); sb.AppendLine("-- TRIGGERS --");
@@ -101,7 +102,7 @@ namespace DbTools {
} }
if (!string.IsNullOrEmpty(selectStatement)) { if (!string.IsNullOrEmpty(selectStatement)) {
string data = GetTableDataSql(cn, tableName, selectStatement); string data = await GetTableDataSqlAsync(cn, tableName, selectStatement);
if (!string.IsNullOrEmpty(data)) { if (!string.IsNullOrEmpty(data)) {
sb.AppendLine(); sb.AppendLine();
sb.AppendLine("-- DATA --"); sb.AppendLine("-- DATA --");
@@ -125,7 +126,7 @@ namespace DbTools {
/// <returns>A string containing the SQL statements for creating all indexes on the specified table, separated by /// <returns>A string containing the SQL statements for creating all indexes on the specified table, separated by
/// newlines. Returns an empty string if no indexes are found.</returns> /// newlines. Returns an empty string if no indexes are found.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="cn"/> is null or if <paramref name="tableName"/> is null or empty.</exception> /// <exception cref="ArgumentNullException">Thrown if <paramref name="cn"/> is null or if <paramref name="tableName"/> is null or empty.</exception>
public string GetIndexCreateSql(IDbConnection cn, string tableName) { public async Task<string> GetIndexCreateSqlAsync(IDbConnection cn, string tableName) {
if (cn == null) { if (cn == null) {
throw new ArgumentNullException("cn"); throw new ArgumentNullException("cn");
} }
@@ -135,16 +136,19 @@ namespace DbTools {
if (cn.State != ConnectionState.Open) { if (cn.State != ConnectionState.Open) {
cn.Open(); cn.Open();
} }
using (IDbCommand cmd = cn.CreateCommand()) { StringBuilder sb = new StringBuilder();
cmd.CommandText = $"SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name='{tableName}' AND sql NOT NULL;";
StringBuilder sb = new StringBuilder(); await Task.Run(() => {
using (IDataReader reader = cmd.ExecuteReader()) { using (IDbCommand cmd = cn.CreateCommand()) {
while (reader.Read()) { cmd.CommandText = $"SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name='{tableName}' AND sql NOT NULL;";
sb.AppendLine(reader.GetString(0) + ";"); using (IDataReader reader = cmd.ExecuteReader()) {
while (reader.Read()) {
sb.AppendLine(reader.GetString(0) + ";");
}
} }
} }
return sb.ToString(); });
} return sb.ToString();
} }
/// <summary> /// <summary>
@@ -159,7 +163,7 @@ namespace DbTools {
/// <returns>A string containing the SQL definitions of all triggers for the specified table, separated by semicolons. /// <returns>A string containing the SQL definitions of all triggers for the specified table, separated by semicolons.
/// Returns an empty string if no triggers are found.</returns> /// Returns an empty string if no triggers are found.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="cn"/> is null or if <paramref name="tableName"/> is null or empty.</exception> /// <exception cref="ArgumentNullException">Thrown if <paramref name="cn"/> is null or if <paramref name="tableName"/> is null or empty.</exception>
public string GetTriggerCreateSql(IDbConnection cn, string tableName) { public async Task<string> GetTriggerCreateSqlAsync(IDbConnection cn, string tableName) {
if (cn == null) { if (cn == null) {
throw new ArgumentNullException("cn"); throw new ArgumentNullException("cn");
} }
@@ -169,16 +173,18 @@ namespace DbTools {
if (cn.State != ConnectionState.Open) { if (cn.State != ConnectionState.Open) {
cn.Open(); cn.Open();
} }
using (IDbCommand cmd = cn.CreateCommand()) { StringBuilder sb = new StringBuilder();
cmd.CommandText = $"SELECT sql FROM sqlite_master WHERE type='trigger' AND tbl_name='{tableName}' AND sql NOT NULL;"; await Task.Run(() => {
StringBuilder sb = new StringBuilder(); using (IDbCommand cmd = cn.CreateCommand()) {
using (IDataReader reader = cmd.ExecuteReader()) { cmd.CommandText = $"SELECT sql FROM sqlite_master WHERE type='trigger' AND tbl_name='{tableName}' AND sql NOT NULL;";
while (reader.Read()) { using (IDataReader reader = cmd.ExecuteReader()) {
sb.AppendLine(reader.GetString(0) + ";"); while (reader.Read()) {
sb.AppendLine(reader.GetString(0) + ";");
}
} }
} }
return sb.ToString(); });
} return sb.ToString();
} }
/// <summary> /// <summary>
@@ -196,7 +202,7 @@ namespace DbTools {
/// <returns>A string containing the generated SQL script. The script includes INSERT statements for the data retrieved /// <returns>A string containing the generated SQL script. The script includes INSERT statements for the data retrieved
/// by the <paramref name="selectStatement"/>.</returns> /// by the <paramref name="selectStatement"/>.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="cn"/> is null or <paramref name="tableName"/> is null or empty.</exception> /// <exception cref="ArgumentNullException">Thrown if <paramref name="cn"/> is null or <paramref name="tableName"/> is null or empty.</exception>
public string GetTableDataSql(IDbConnection cn, string tableName, string selectStatement) { public async Task<string> GetTableDataSqlAsync(IDbConnection cn, string tableName, string selectStatement) {
if (cn == null) { if (cn == null) {
throw new ArgumentNullException("cn"); throw new ArgumentNullException("cn");
} }
@@ -208,48 +214,50 @@ namespace DbTools {
cn.Open(); cn.Open();
} }
StringBuilder sb = new StringBuilder();
selectStatement = selectStatement.Replace("$table", tableName); selectStatement = selectStatement.Replace("$table", tableName);
using (IDbCommand cmd = cn.CreateCommand()) { await Task.Run(() => {
cmd.CommandText = selectStatement; using (IDbCommand cmd = cn.CreateCommand()) {
using (IDataReader reader = cmd.ExecuteReader()) { cmd.CommandText = selectStatement;
StringBuilder sb = new StringBuilder(); using (IDataReader reader = cmd.ExecuteReader()) {
int rowCount = 0; int rowCount = 0;
while (reader.Read()) { while (reader.Read()) {
List<string> values = new List<string>(); List<string> values = new List<string>();
for (int i = 0; i < reader.FieldCount; i++) { for (int i = 0; i < reader.FieldCount; i++) {
object value = DBNull.Value; object value = DBNull.Value;
try { try {
value = reader.GetValue(i); value = reader.GetValue(i);
} catch { } } catch { }
if (value == DBNull.Value) { if (value == DBNull.Value) {
values.Add("NULL"); values.Add("NULL");
} else if (value is string || value is DateTime) { } else if (value is string || value is DateTime) {
values.Add("'" + value.ToString().Replace("'", "''") + "'"); values.Add("'" + value.ToString().Replace("'", "''") + "'");
} else if (value is bool) { } else if (value is bool) {
values.Add((bool)value ? "1" : "0"); values.Add((bool)value ? "1" : "0");
} else { } else {
values.Add(value.ToString()); values.Add(value.ToString());
}
} }
}
if (rowCount % 100 == 0) { if (rowCount % 100 == 0) {
if (rowCount != 0) if (rowCount != 0)
sb.AppendLine(";"); sb.AppendLine(";");
sb.Append($"INSERT INTO {tableName} ({string.Join(", ", GetColumnNames(reader))}) VALUES"); sb.Append($"INSERT INTO {tableName} ({string.Join(", ", GetColumnNames(reader))}) VALUES");
sb.AppendLine(); sb.AppendLine();
sb.Append($" ({string.Join(", ", values)})"); sb.Append($" ({string.Join(", ", values)})");
} else { } else {
sb.AppendLine(","); sb.AppendLine(",");
sb.Append($" ({string.Join(", ", values)})"); sb.Append($" ({string.Join(", ", values)})");
}
rowCount++;
} }
rowCount++; if (rowCount > 0)
sb.AppendLine(";");
} }
if (rowCount > 0)
sb.AppendLine(";");
return sb.ToString();
} }
} });
return sb.ToString();
} }
/// <summary> /// <summary>