diff --git a/SQL Format/FormSQLFormat.cs b/SQL Format/FormSQLFormat.cs
index 4b9b686..6c9cb1f 100644
--- a/SQL Format/FormSQLFormat.cs
+++ b/SQL Format/FormSQLFormat.cs
@@ -25,13 +25,17 @@ public FormSQLFormat()
AddItemByClass(new SQLTranslatorUpdate());
AddItemByClass(new SQLTranslatorMerge());
AddItemByClass(new SQLTranslatorCopy());
+ AddItemByClass(new SQLTranslatorCopySingle());
AddItemByClass(new SQLTranslatorInsert());
AddItemByClass(new SQLTranslatorSame());
AddItemByClass(new SQLTranslatorXmlSelect());
- AddItemByClass(new TabTranslatorJson());
+ //AddItemByClass(new TabTranslatorJson());
+#if DEBUG
+ AddItemByClass(new SQLTranslatorMyScript());
+#endif
}
- void AddItemByClass(SQLTranslator t)
+ void AddItemByClass(SQLTranslator t)
{
int idx = TabCtrl.TabPages.Count;
TabCtrl.TabPages.Add(t.GetCaption());
diff --git a/SQL Format/Helpers/SqlBuilder.cs b/SQL Format/Helpers/SqlBuilder.cs
index 0afa764..5d548d3 100644
--- a/SQL Format/Helpers/SqlBuilder.cs
+++ b/SQL Format/Helpers/SqlBuilder.cs
@@ -91,7 +91,7 @@ public SqlBuilder AppendIf(string lineCondition)
public SqlBuilder AppendCatchTypicalRollback()
{
AppendBegin(BEGIN_CATCH);
- AppendLine($"if @@trancount > 0 rollback;");
+ AppendLine($"if @@trancount > 0 begin print('rollback'); rollback; end");
AppendLine($";throw;");
AppendEnd(BEGIN_END);
return this;
diff --git a/SQL Format/Helpers/SqlDomBuilder.cs b/SQL Format/Helpers/SqlDomBuilder.cs
index 598dba5..f15367e 100644
--- a/SQL Format/Helpers/SqlDomBuilder.cs
+++ b/SQL Format/Helpers/SqlDomBuilder.cs
@@ -45,6 +45,31 @@ public void ProduceFullTableRenameScript(TSqlScript script, string suffix, bool
objType = OBJECT;
_sqlBuilder.AppendSpRename(objName, newName, objType, "constraint").NL();
}
+
+ foreach (var colDef in createTableStatement.Definition.ColumnDefinitions)
+ {
+ foreach (var constraint in colDef.Constraints)
+ {
+ if (constraint.ConstraintIdentifier == null) continue;
+ var conName = TSQLHelper.Identifier2Value(constraint.ConstraintIdentifier);
+ objName = !reverse ? $"{schemaName}.{conName}" : $"{schemaName}.{conName + suffix}";
+ newName = reverse ? conName : conName + suffix;
+ objType = OBJECT;
+ _sqlBuilder.AppendSpRename(objName, newName, objType, "constraint").NL();
+ }
+
+ {
+ var constraint = colDef.DefaultConstraint;
+ if (constraint == null || constraint.ConstraintIdentifier == null) continue;
+ var conName = TSQLHelper.Identifier2Value(constraint.ConstraintIdentifier);
+ objName = !reverse ? $"{schemaName}.{conName}" : $"{schemaName}.{conName + suffix}";
+ newName = reverse ? conName : conName + suffix;
+ objType = OBJECT;
+ _sqlBuilder.AppendSpRename(objName, newName, objType, "constraint").NL();
+ }
+
+ }
+
}
if (statement is CreateIndexStatement createIndexStatement)
{
@@ -382,5 +407,93 @@ public void ProduceCopytableVerify(CreateTableStatement createTableStatement, st
Print($"Success comparing {sourceTableNameFull} with {destTableNameFull}");
_sqlBuilder.Unindent();
}
+
+ public void ProduceCopyTableSingle(CreateTableStatement createTableStatement, string varSuffix, string targetTableNameFull = null)
+ {
+ string sourceTableNameFull = TSQLHelper.Identifiers2Value(createTableStatement.SchemaObjectName.Identifiers);
+ string destTableNameFull = targetTableNameFull != null ? targetTableNameFull : TSQLHelper.Identifiers2Value(createTableStatement.SchemaObjectName.Identifiers);
+
+ UniqueConstraintDefinition clusteredKey = createTableStatement.Definition.TableConstraints.Where(c => c is UniqueConstraintDefinition uni && uni.Clustered == true).SingleOrDefault() as UniqueConstraintDefinition;
+ if (clusteredKey is null)
+ {
+ _sqlBuilder.AppendLine("Error: No clustered index!");
+ return;
+ }
+ ColInfo keyColumn = new ColInfo();
+ {
+ var colName = TSQLHelper.Identifiers2Value(clusteredKey.Columns[0].Column.MultiPartIdentifier.Identifiers);
+ ColumnDefinition column = createTableStatement.Definition.ColumnDefinitions.Where(c => TSQLHelper.Identifier2Value(c.ColumnIdentifier).ToLowerInvariant() == colName.ToLowerInvariant()).Single();
+ keyColumn.Index = 0;
+ keyColumn.ColumnName = colName;
+ keyColumn.ColumnDefinition = column;
+ keyColumn.ColumnTypeStr = TSQLHelper.Column2TypeStr(column);
+ keyColumn.VarNameLastValue = $"@Key{varSuffix}";
+ }
+
+ string AffectedIterationName = $"@AffectedIteration{varSuffix}";
+ _sqlBuilder.AppendLine($"declare {AffectedIterationName} int;");
+
+ string numName = $"@i{varSuffix}";
+ _sqlBuilder.AppendLine($"declare {numName} int = 0;");
+
+ string totalCountName = $"@TotalCount{varSuffix}";
+ _sqlBuilder.AppendLine($"declare {totalCountName} int = (select count(*) from {sourceTableNameFull} with (nolock));").NL();
+
+
+ // last column via table
+ string keysTableName = $"#keys{varSuffix}";
+ _sqlBuilder.AppendLine($"drop table if exists {keysTableName};")
+ .AppendLine($"create table {keysTableName}(")
+ .Indent()
+ .AppendLine($"{keyColumn.ColumnName} {keyColumn.ColumnTypeStr} not null primary key clustered")
+ .Unindent()
+ .AppendLine(");").NL();
+
+
+ _sqlBuilder.AppendLine($"declare {keyColumn.VarNameLastValue} {keyColumn.ColumnTypeStr};");
+
+ _sqlBuilder.NL();
+ _sqlBuilder.AppendLine($"insert into {keysTableName}({keyColumn.ColumnName})");
+ _sqlBuilder.AppendLine($"select distinct t.{keyColumn.ColumnName}");
+ _sqlBuilder.AppendLine($"from {sourceTableNameFull} t with (nolock);").NL();
+
+ string loopCountName = $"@LoopCount{varSuffix}";
+ _sqlBuilder.AppendLine($"declare {loopCountName} int = @@rowcount;");
+
+ Print($"concat('Total count:', {totalCountName}, ', loop count: ', {loopCountName}, ' in {sourceTableNameFull}.')", false);
+ _sqlBuilder.NL();
+
+ _sqlBuilder.AppendLine($"while 1=1").AppendBegin();
+ {
+ _sqlBuilder.AppendLine($"set {numName} += 1;").NL();
+
+ _sqlBuilder.AppendLine($"set {keyColumn.VarNameLastValue} = (").Indent()
+ .AppendLine($"select top (1) t.{keyColumn.ColumnName}")
+ .AppendLine($"from {keysTableName} t")
+ .AppendLine($"where {keyColumn.VarNameLastValue} is null or t.{keyColumn.ColumnName} > {keyColumn.VarNameLastValue}")
+ .AppendLine($"order by 1 asc")
+ .Unindent().AppendLine(");").NL();
+
+ _sqlBuilder.AppendLine($"if {keyColumn.VarNameLastValue} is null").AppendBegin().AppendLine("break;").AppendEnd().NL();
+
+
+ Print($"concat('Processing ', {numName},' / ', {loopCountName}, ', {keyColumn.ColumnName}: ', {keyColumn.VarNameLastValue}, ' ...')", false);
+
+ _sqlBuilder.AppendLine($"insert into {destTableNameFull}(")
+ .Indent()
+ .AppendLines(createTableStatement.Definition.ColumnDefinitions.Select(c => TSQLHelper.Identifier2Value(c.ColumnIdentifier)), ",")
+ .Unindent()
+ .AppendLine(")")
+ .AppendLine($"select ")
+ .Indent()
+ .AppendLines(createTableStatement.Definition.ColumnDefinitions.Select(c => $"t.{TSQLHelper.Identifier2Value(c.ColumnIdentifier)}"), ",")
+ .Unindent()
+ .AppendLine($"from {sourceTableNameFull} t")
+ .AppendLine($"where t.{keyColumn.ColumnName} = {keyColumn.VarNameLastValue};").NL();
+
+ }
+ _sqlBuilder.AppendEnd($"end");
+ }
+
}
}
diff --git a/SQL Format/SQLFormat.csproj b/SQL Format/SQLFormat.csproj
index 89bf507..74cb1af 100644
--- a/SQL Format/SQLFormat.csproj
+++ b/SQL Format/SQLFormat.csproj
@@ -118,6 +118,8 @@
+
+
diff --git a/SQL Format/SQLTranslatorCopySingle.cs b/SQL Format/SQLTranslatorCopySingle.cs
new file mode 100644
index 0000000..2ba6035
--- /dev/null
+++ b/SQL Format/SQLTranslatorCopySingle.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Microsoft.SqlServer.TransactSql.ScriptDom;
+using SQL_Format.Helpers;
+
+namespace SQL_Format
+{
+ public class SQLTranslatorCopySingle : SQLTranslator
+ {
+ public override string GetCaption()
+ {
+ return "Copy Table Sinlge";
+ }
+
+ public override void SetupOptionsContent(Control Parent, EventHandler changedHandler)
+ {
+ this.AddOptionTextBox("Var Suffix", "varSuffix", "11245U1", Parent, changedHandler);
+ this.AddOptionCheckBox("Use Transaction", "useTransaction", true, Parent, changedHandler);
+ this.AddOptionCheckBox("Rollback", "useRollback", true, Parent, changedHandler);
+ }
+
+ public override string TranslateExt2(CreateTableStatement createTableStatement, object options, string content, TSqlScript sqlScript)
+ {
+ string varSuffix = this.GetOptionString("varSuffix", options) ?? "";
+ bool useTransaction = this.GetOptionBoolDef("useTransaction", options, false);
+ bool useRollback = this.GetOptionBoolDef("useRollback", options, false);
+
+ SqlBuilder result = new SqlBuilder();
+ SqlDomBuilder sqlDomBuilder = new SqlDomBuilder(sqlScript, result);
+
+
+ string tableSuffix = "_new";
+ result.TableNameFull = TSQLHelper.Identifiers2Value(createTableStatement.SchemaObjectName.Identifiers);
+ result.TableName = TSQLHelper.Identifiers2ValueLast(createTableStatement.SchemaObjectName.Identifiers);
+ string tableNameNew = result.TableName + tableSuffix;
+ string tableNameFullNew = result.TableNameFull + tableSuffix;
+ {
+ result.AppendBegin(SqlBuilder.BEGIN_TRY);
+ {
+ if (useTransaction) result.AppendLine($"begin tran;").NL();
+
+ string messageVarName = $"@msg{varSuffix}";
+ result.AppendLine($"declare {messageVarName} nvarchar(2024);").NL();
+ sqlDomBuilder.VarMsgName = messageVarName;
+ sqlDomBuilder.Print($"Running Script{varSuffix}.{result.TableNameFull}...").NL();
+
+ result.AppendIf($"object_id('{tableNameFullNew}') is null").AppendBegin();
+ {
+ result.AppendLine("-- create new table");
+ sqlDomBuilder.ProduceFullTableRenameContent(sqlScript, tableSuffix, content);
+
+ result.AppendEnd();
+ }
+
+ sqlDomBuilder.ProduceCopyTableSingle(createTableStatement, varSuffix, targetTableNameFull: tableNameFullNew);
+
+ result.AppendBegin();
+ {
+ result.AppendLine("-- rename source table to _old");
+ sqlDomBuilder.ProduceFullTableRenameScript(sqlScript, "_old");
+ result.AppendEnd();
+ }
+
+ result.AppendBegin();
+ {
+ result.AppendLine("-- rename new table to current");
+ sqlDomBuilder.ProduceFullTableRenameScript(sqlScript, tableSuffix, reverse: true);
+
+ result.AppendEnd();
+ }
+
+ sqlDomBuilder.ProduceCopytableVerify(createTableStatement, varSuffix, targetTableNameFull: result.TableNameFull + "_old");
+
+ result.NL();
+ sqlDomBuilder.Print("Dropping table {result.TableNameFull}_old...");
+ result.AppendLine($"drop table if exists {result.TableNameFull}_old;").NL();
+
+ if (useTransaction)
+ {
+ if (useRollback)
+ result.AppendLine($"rollback;").NL();
+ else
+ {
+ result.AppendLine($"commit;").NL();
+ sqlDomBuilder.Print("Committed.");
+ }
+ }
+
+ result.AppendEnd(SqlBuilder.END_TRY, false);
+ }
+ result.AppendCatchTypicalRollback();
+ }
+ return result.ToString();
+ }
+ }
+}
diff --git a/SQL Format/SQLTranslatorMyScript.cs b/SQL Format/SQLTranslatorMyScript.cs
new file mode 100644
index 0000000..1c94261
--- /dev/null
+++ b/SQL Format/SQLTranslatorMyScript.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Microsoft.SqlServer.TransactSql.ScriptDom;
+using SQL_Format.Helpers;
+
+namespace SQL_Format
+{
+ public class SQLTranslatorMyScript: SQLTranslator
+ {
+ public override string GetCaption()
+ {
+ return "My Script";
+ }
+
+ public override void SetupOptionsContent(Control Parent, EventHandler changedHandler)
+ {
+ }
+
+ public override string TranslateExt2(CreateTableStatement createTableStatement, object options, string content, TSqlScript sqlScript)
+ {
+ SqlBuilder result = new SqlBuilder();
+ SqlDomBuilder sqlDomBuilder = new SqlDomBuilder(sqlScript, result);
+ result.TableNameFull = TSQLHelper.Identifiers2Value(createTableStatement.SchemaObjectName.Identifiers);
+ result.TableName = TSQLHelper.Identifiers2ValueLast(createTableStatement.SchemaObjectName.Identifiers);
+
+ int[] precs = new int[] { 18, 26, 20};
+
+ result.AppendLine($"----------------- {result.TableNameFull} -----------------");
+ result.AppendLine($"raiserror('Altering {result.TableNameFull}...', 10, 1) with nowait;");
+
+ int addedCount = 0;
+ foreach (var c in createTableStatement.Definition.ColumnDefinitions)
+ {
+ string colType = TSQLHelper.Column2TypeStr(c).ToUpperInvariant();
+ if (colType.StartsWith("DECIMAL"))
+ {
+ int prec = TSQLHelper.ColumnDecimalPrecision(c);
+ if (precs.Contains(prec))
+ {
+ addedCount++;
+ bool isNullable = TSQLHelper.ColumnIsNullable(c);
+ string null_ = isNullable ? " NULL" : " NOT NULL";
+ string colName = TSQLHelper.Identifier2Value(c.ColumnIdentifier);
+ string subalterColumn = $"column {colName} {colType}{null_}";
+ result.AppendIf($"not exists(select * from INFORMATION_SCHEMA.COLUMNS c where c.TABLE_NAME = '{result.TableName}' and c.COLUMN_NAME = '{colName}' and c.NUMERIC_PRECISION = {prec})").AppendBegin();
+ {
+ string alterColumn = $"alter {subalterColumn}";
+ result.AppendLine($"raiserror('{alterColumn}...', 10, 1) with nowait;");
+ if (isNullable)
+ result.AppendLine($"update {result.TableNameFull} set {colName} = try_cast({colName} as {colType});");
+ result.AppendLine($"alter table {result.TableNameFull}").Indent();
+ result.AppendLine($"{alterColumn};").Unindent();
+ result.AppendEnd(addSpaceafterwards: false);
+ }
+ result.AppendLine("else").Indent();
+ {
+ result.AppendLine($"raiserror('already {subalterColumn}.', 10, 1) with nowait;");
+ result.Unindent();
+ }
+
+ result.AppendLine("GO");
+ }
+ }
+ }
+ result.AppendLine($"----------------------------------");
+ return result.ToString();
+ }
+ }
+}
diff --git a/SQL Format/SQLTranslatorXmlSelect.cs b/SQL Format/SQLTranslatorXmlSelect.cs
index bae62c1..7ba7604 100644
--- a/SQL Format/SQLTranslatorXmlSelect.cs
+++ b/SQL Format/SQLTranslatorXmlSelect.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
+using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -99,9 +100,18 @@ public override void SetupOptionsContent(Control Parent, EventHandler changedHan
checkBox.AutoSize = true;
Parent.Controls.Add(checkBox);
}
- }
- public override string TranslateExt(CreateTableStatement createTableStatement, object options)
+ {
+ CheckBox checkBox = new CheckBox();
+ checkBox.Text = "json";
+ checkBox.Name = "option_json";
+ checkBox.CheckedChanged += changedHandler;
+ checkBox.AutoSize = true;
+ Parent.Controls.Add(checkBox);
+ }
+ }
+
+ public override string TranslateExt(CreateTableStatement createTableStatement, object options)
{
TableDefinition tableDefinition = createTableStatement.Definition;
string optionSource0 = null;
@@ -143,7 +153,9 @@ public override string TranslateExt(CreateTableStatement createTableStatement, o
}
}
- bool option_insert = GetOptionBoolDef("option_insert", options, false);
+ bool option_json = GetOptionBoolDef("option_json", options, false);
+
+ bool option_insert = GetOptionBoolDef("option_insert", options, false);
bool option_identity_insert = GetOptionBoolDef("option_identity_insert", options, false);
bool option_tab_path = GetOptionBoolDef("option_tab_path", options, false);
bool option_output = GetOptionBoolDef("option_output", options, false);
@@ -183,6 +195,7 @@ public override string TranslateExt(CreateTableStatement createTableStatement, o
result.Append($"select{Environment.NewLine}");
+ List jsonWith = new List();
// rows
{
sep = null;
@@ -196,20 +209,38 @@ public override string TranslateExt(CreateTableStatement createTableStatement, o
if (option_ccolumns) {
attName = $"c{iter}";
}
- if (optionsSafe)
+ if (!option_json)
{
- result.Append($"\t{sep}{ident} = case when {optionRowAlias0}.value('@{attName}', 'nvarchar(max)') = \'NULL\' then null else {optionRowAlias0}.value('@{attName}', '{typ}') end{Environment.NewLine}");
+ if (optionsSafe)
+ {
+ result.Append($"\t{sep}{ident} = case when {optionRowAlias0}.value('@{attName}', 'nvarchar(max)') = \'NULL\' then null else {optionRowAlias0}.value('@{attName}', '{typ}') end{Environment.NewLine}");
+ }
+ else
+ {
+ result.Append($"\t{sep}{ident} = {optionRowAlias0}.value('@{attName}', '{typ}'){Environment.NewLine}");
+ }
}
else
{
- result.Append($"\t{sep}{ident} = {optionRowAlias0}.value('@{attName}', '{typ}'){Environment.NewLine}");
- }
+ result.Append($"\t{sep}{ident} = {optionRowAlias0}.{attName}{Environment.NewLine}");
+ jsonWith.Add($"{sep}{attName} {typ} '$.{attName}'");
+ }
if (String.IsNullOrEmpty(sep)) sep = ", ";
}
}
- string path = "/root[1]/data[1]/row";
- if (option_tab_path) path = $"/root[1]/{tableName0}/row";
- result.Append($"from @{optionSource0}.nodes('{path}') as t({optionRowAlias0}){Environment.NewLine}");
+ if (!option_json)
+ {
+ string path = "/root[1]/data[1]/row";
+ if (option_tab_path) path = $"/root[1]/{tableName0}/row";
+ result.Append($"from @{optionSource0}.nodes('{path}') as t({optionRowAlias0}){Environment.NewLine}");
+ }
+ else
+ {
+ result.Append($"from openjson(@json) with ({Environment.NewLine}");
+ foreach (var ss in jsonWith)
+ result.Append($"\t{ss}{Environment.NewLine}");
+ result.Append($") {optionRowAlias0}{Environment.NewLine}");
+ }
if (option_identity_insert)
{
diff --git a/SQL Format/TSQLHelper.cs b/SQL Format/TSQLHelper.cs
index 6fe1ba7..360b0a5 100644
--- a/SQL Format/TSQLHelper.cs
+++ b/SQL Format/TSQLHelper.cs
@@ -41,11 +41,12 @@ public static string Column2TypeStr(ColumnDefinition columnDefinition)
if (columnDefinition.DataType == null) return null;
string result = columnDefinition.DataType.Name.Identifiers[0].Value.ToLowerInvariant();
//+ Name {Microsoft.SqlServer.TransactSql.ScriptDom.SchemaObjectName} Microsoft.SqlServer.TransactSql.ScriptDom.SchemaObjectName
- if (columnDefinition.DataType is ParameterizedDataTypeReference)
+ if (columnDefinition.DataType is ParameterizedDataTypeReference p)
{
- if (((ParameterizedDataTypeReference)columnDefinition.DataType).Parameters.Count > 0)
+ if (p.Parameters.Count > 0)
{
- result = $"{result}({((ParameterizedDataTypeReference)columnDefinition.DataType).Parameters[0].Value})";
+ var pars = string.Join(", ", p.Parameters.Select(s => s.Value));
+ result += $"({pars})";
}
}
@@ -76,7 +77,24 @@ public static bool ColumnIsIdentity(ColumnDefinition columnDefinition)
return false;
}
- public static bool ColumnIsPrimaryKey(ColumnDefinition columnDefinition, TableDefinition definition, bool AllowUnique = false)
+ public static bool ColumnIsNullable(ColumnDefinition columnDefinition)
+ {
+ return columnDefinition.Constraints.Where(c => c is NullableConstraintDefinition nu && nu.Nullable == true).Any();
+ }
+
+ public static int ColumnDecimalPrecision(ColumnDefinition columnDefinition)
+ {
+ if (columnDefinition.DataType is ParameterizedDataTypeReference p)
+ {
+ if (p.Parameters.Count > 0)
+ {
+ return int.Parse(p.Parameters[0].Value);
+ }
+ }
+ return 0;
+ }
+
+ public static bool ColumnIsPrimaryKey(ColumnDefinition columnDefinition, TableDefinition definition, bool AllowUnique = false)
{
if ((columnDefinition.Index != null) && (columnDefinition.Index.IndexType != null) && (columnDefinition.Index.IndexType.IndexTypeKind == IndexTypeKind.Clustered))
{