Saxonite - various

This commit is contained in:
2021-06-04 14:04:03 +01:00
parent 19be985731
commit 8d3aa5ec03
31 changed files with 390 additions and 170 deletions
@@ -19,13 +19,19 @@ namespace Sarand.Net.Standard.Dbas.Proc
// Configuration.
public new class Config : SacsProcess.Config
{
public Config (SacsDatabase sourceDatabase, SacsDatabase targetDatabase)
public Config(ISacsDatabase sourceDatabase, ISacsDatabase targetDatabase)
{
SourceDatabase = sourceDatabase;
TargetDatabase = targetDatabase;
}
public SacsDatabase SourceDatabase { get; }
public SacsDatabase TargetDatabase { get; }
public Config(List<DbDfnTable> sourceTables, ISacsDatabase targetDatabase)
{
SourceTables = sourceTables;
TargetDatabase = targetDatabase;
}
public ISacsDatabase SourceDatabase { get; }
public List<DbDfnTable> SourceTables { get; }
public ISacsDatabase TargetDatabase { get; }
public bool HideIdenticalObjects { get; set; }
public bool IgnoreNullable { get; set; }
public bool IgnorePosition { get; set; }
@@ -37,11 +43,11 @@ namespace Sarand.Net.Standard.Dbas.Proc
// Definitions.
public interface IProcessNotifier : ISacsProcessNotifier
{
void OnSchemaComparisonItemAdded (SaDbProcess_CompareDatabaseSchemas proc);
void OnSchemaComparisonItemAdded(SaDbProcess_CompareDatabaseSchemas proc);
}
public class SchemaComparisonItem
{
internal SchemaComparisonItem (String tableName, String columnName, int columnPosition, String indexName, String comment)
internal SchemaComparisonItem(String tableName, String columnName, int columnPosition, String indexName, String comment)
{
Id = ++SeedId;
TableName = tableName;
@@ -67,11 +73,11 @@ namespace Sarand.Net.Standard.Dbas.Proc
//-------------------------------------------------------------------
// Construction.
public SaDbProcess_CompareDatabaseSchemas (Config config) : base(config)
public SaDbProcess_CompareDatabaseSchemas(Config config) : base(config)
{
this.config = config;
}
protected override void Dispose (bool disposing)
protected override void Dispose(bool disposing)
{
if (disposing)
{
@@ -95,7 +101,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
//-------------------------------------------------------------------
// S c h e m a D i f f e r e n c e s
//-------------------------------------------------------------------
public List<SchemaComparisonItem> GetSchemaComparisonItems (int minId = 0)
public List<SchemaComparisonItem> GetSchemaComparisonItems(int minId = 0)
{
return new List<SchemaComparisonItem>(schemaComparisonItems.FindAll(item => item.Id >= minId));
}
@@ -103,21 +109,23 @@ namespace Sarand.Net.Standard.Dbas.Proc
//-------------------------------------------------------------------
// P r o c e s s i n g
//-------------------------------------------------------------------
protected override bool Run ()
protected override bool Run()
{
schemaComparisonItems.Clear();
if (config.SourceDatabase == null) return SetProcessError("Source database must be supplied.");
if (config.SourceDatabase == null && config.SourceTables == null) return SetProcessError("Source database must be supplied.");
CompareTables();
return OK;
}
//-------------------------------------------------------------------
private void CompareTables ()
private void CompareTables()
{
List<String> sourceTables = config.SourceDatabase.GetTableNames().OrderBy(item => item).ToList();
List<String> targetTables = config.TargetDatabase.GetTableNames().OrderBy(item => item).ToList();
for (int sourceTableIdx = 0, targetTableIdx = 0; sourceTableIdx <= sourceTables.Count && targetTableIdx <= targetTables.Count;)
// Database schemas.
List<String> sourceTables = (config.SourceDatabase?.GetTableNames(true) ?? config.SourceTables.Select(item => item.Name)).OrderBy(item => item).ToList();
List<String> targetTables = config.TargetDatabase.GetTableNames(true).OrderBy(item => item).ToList();
for (int sourceTableIdx = 0, targetTableIdx = 0; sourceTableIdx < sourceTables.Count || targetTableIdx < targetTables.Count;)
{
String sourceTableName = (sourceTableIdx < sourceTables.Count ? sourceTables[sourceTableIdx] : "");
String targetTableName = (targetTableIdx < targetTables.Count ? targetTables[targetTableIdx] : "");
@@ -143,8 +151,8 @@ namespace Sarand.Net.Standard.Dbas.Proc
Debugger.Break();
#endif
// Retrieve table definition from each database.
DbDfnTable sourceTableDfn = config.SourceDatabase.GetTableDfn (sourceTableName);
DbDfnTable targetTableDfn = config.TargetDatabase.GetTableDfn (targetTableName);
DbDfnTable sourceTableDfn = config.SourceDatabase?.GetTableDfn(sourceTableName, true) ?? config.SourceTables.GetTableByName(sourceTableName);
DbDfnTable targetTableDfn = config.TargetDatabase.GetTableDfn(targetTableName, true);
// Compare the columns and indices.
CompareTableColumns(sourceTableDfn, targetTableDfn);
CompareTableIndices(sourceTableDfn, targetTableDfn);
@@ -155,7 +163,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
}
//-------------------------------------------------------------------
private bool CompareTableColumns (DbDfnTable sourceTableDfn, DbDfnTable targetTableDfn)
private bool CompareTableColumns(DbDfnTable sourceTableDfn, DbDfnTable targetTableDfn)
{
String tableName = sourceTableDfn.Name;
#if DEBUG_X
@@ -177,7 +185,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
String sourceColumnName = sourceColumnIdx < sourceColumnNames.Count() ? sourceColumnNames[sourceColumnIdx] : "";
String targetColumnName = targetColumnIdx < targetColumnNames.Count() ? targetColumnNames[targetColumnIdx] : "";
// Retrieve Column definition from each database.
DbDfnColumn sourceColumn = sourceColumns.GetColumnByName (sourceColumnName);
DbDfnColumn sourceColumn = sourceColumns.GetColumnByName(sourceColumnName);
if (sourceColumn != null) iPosition = sourceColumn.Pos;
DbDfnColumn targetColumn = targetColumns.GetColumnByName(targetColumnName);
// Compare Columns.
@@ -225,7 +233,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
return OK;
}
private static long iLargeSizeThreshold = 4000;
private bool ColumnSizesDiffer (DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
private bool ColumnSizesDiffer(DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
{
if (sourceColumn.Size == targetColumn.Size) return false;
// If both columns are large, treat then as equal:
@@ -240,33 +248,33 @@ namespace Sarand.Net.Standard.Dbas.Proc
if (config.IgnoreSimilarNumericTypes)
{
// Floating point types.
List<String> numericTypes = StringListUtil.Split("Real,Float,Double,Decimal,Numeric",",");
List<String> numericTypes = StringListUtil.Split("Real,Float,Double,Decimal,Numeric", ",");
if (numericTypes.ContainsCI(sourceDataType) && numericTypes.ContainsCI(targetDataType)) return false;
}
// DateTimes:
List<String> dateTimeTypes = StringListUtil.Split("DateTime",",");
List<String> dateTimeTypes = StringListUtil.Split("DateTime", ",");
if (dateTimeTypes.ContainsCI(sourceDataType) && dateTimeTypes.ContainsCI(targetDataType)) return false;
return true;
}
private bool ColumnDecimalsDiffer (DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
private bool ColumnDecimalsDiffer(DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
{
if (sourceColumn.DecimalDigits == targetColumn.DecimalDigits) return false;
// Check for specific data types:
String sourceDataType = sourceColumn.DataTypeNameNative;
String targetDataType = targetColumn.DataTypeNameNative;
// Numeric types - float/double columns report decimals as 0.
List<String> floatTypes = StringListUtil.Split("Real,Float,Double",",");
List<String> decimalTypes = StringListUtil.Split("Decimal,Numeric",",");
List<String> floatTypes = StringListUtil.Split("Real,Float,Double", ",");
List<String> decimalTypes = StringListUtil.Split("Decimal,Numeric", ",");
if (sourceColumn.DecimalDigits == 0 && floatTypes.ContainsCI(sourceDataType) && targetColumn.DecimalDigits > 0 && decimalTypes.ContainsCI(targetDataType)) return false;
if (sourceColumn.DecimalDigits > 0 && decimalTypes.ContainsCI(sourceDataType) && targetColumn.DecimalDigits == 0 && floatTypes.ContainsCI(targetDataType)) return false;
// DateTimes:
List<String> dateTimeTypes = StringListUtil.Split("DateTime",",");
List<String> dateTimeTypes = StringListUtil.Split("DateTime", ",");
if (dateTimeTypes.ContainsCI(sourceDataType) && dateTimeTypes.ContainsCI(targetDataType)) return false;
return true;
}
private bool ColumnDataTypesDiffer (DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
private bool ColumnDataTypesDiffer(DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
{
if (sourceColumn.DataType == targetColumn.DataType) return false;
@@ -279,13 +287,13 @@ namespace Sarand.Net.Standard.Dbas.Proc
if (config.IgnoreSimilarNumericTypes)
{
// Similar numeric type.
List<String> numericTypes = StringListUtil.Split("Real,Float,Double,Decimal,Numeric",",");
List<String> numericTypes = StringListUtil.Split("Real,Float,Double,Decimal,Numeric", ",");
if (numericTypes.ContainsCI(sourceDataType) && numericTypes.ContainsCI(targetDataType)) return false;
}
return true;
}
private bool ColumnNativeDataTypesDiffer (DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
private bool ColumnNativeDataTypesDiffer(DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
{
if (sourceColumn.DataTypeNative == targetColumn.DataTypeNative) return false;
@@ -295,20 +303,20 @@ namespace Sarand.Net.Standard.Dbas.Proc
if (config.IgnoreSimilarCharTypes)
{
// Similar Char types.
List<String> varCharTypes = StringListUtil.Split("VarChar,LongVarChar,LongChar,NVarChar,VarWChar",",");
List<String> varCharTypes = StringListUtil.Split("VarChar,LongVarChar,LongChar,NVarChar,VarWChar", ",");
if (varCharTypes.ContainsCI(sourceDataType) && varCharTypes.ContainsCI(targetDataType)) return false;
}
if (config.IgnoreSimilarNumericTypes)
{
// Similar numeric types.
List<String> numericTypes = StringListUtil.Split("Real,Float,Double,Numeric,Decimal",",");
List<String> numericTypes = StringListUtil.Split("Real,Float,Double,Numeric,Decimal", ",");
if (numericTypes.ContainsCI(sourceDataType) && numericTypes.ContainsCI(targetDataType)) return false;
}
return true;
}
//-------------------------------------------------------------------
private bool CompareTableIndices (DbDfnTable sourceTableDfn, DbDfnTable targetTableDfn)
private bool CompareTableIndices(DbDfnTable sourceTableDfn, DbDfnTable targetTableDfn)
{
String sTable = sourceTableDfn.Name;
@@ -317,7 +325,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
List<DbDfnIndex> targetIndices = targetTableDfn.Indices;
List<String> sourceIndexNames = sourceIndices.GetNames().OrderBy(item => item).ToList();
List<String> targetIndexNames = targetIndices.GetNames().OrderBy(item => item).ToList();
for (int sourceIndexIdx = 0, targetIndexIdx = 0; OK && sourceIndexIdx < sourceIndexNames.Count && targetIndexIdx < targetIndexNames.Count; )
for (int sourceIndexIdx = 0, targetIndexIdx = 0; OK && sourceIndexIdx < sourceIndexNames.Count && targetIndexIdx < targetIndexNames.Count;)
{
// Retrieve the Index names.
String sourceIndexName = sourceIndexIdx < sourceIndexNames.Count ? sourceIndexNames[sourceIndexIdx] : "";
@@ -382,7 +390,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
}
//-------------------------------------------------------------------
private void AddSchemaComparisonItem (String tableName, String columnName, int position, String indexName, String comment)
private void AddSchemaComparisonItem(String tableName, String columnName, int position, String indexName, String comment)
{
schemaComparisonItems.Add(new SchemaComparisonItem(tableName, columnName, position, indexName, comment));
if (ProcessNotifier != null) ProcessNotifier.OnSchemaComparisonItemAdded(this);
@@ -395,7 +403,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
public static class SchemaComparisonItemList
{
/// <summary>Identify the maximum Id value in the list.</summary>
public static int GetMaxId (this IEnumerable<SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem> values)
public static int GetMaxId(this IEnumerable<SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem> values)
{
int maxId = 0;
foreach (SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem schemaComparisonItem in values)
@@ -0,0 +1,183 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.IO;
using Sarand.Net.Standard.Base.Procs;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Dbas.Base;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Sarand.Net.Standard.Dbas.Proc
{
//=======================================================================
public class SaDbProcess_ConvertDbSchema : SacsProcess
{
//-------------------------------------------------------------------
// Configuration.
public new class Config : SacsProcess.Config
{
public Config()
{
}
}
//-------------------------------------------------------------------
// Data members.
private Config config;
//-------------------------------------------------------------------
// Construction.
public SaDbProcess_ConvertDbSchema(Config config) : base(config)
{
this.config = config;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
}
base.Dispose(disposing);
}
//-------------------------------------------------------------------
// Properties.
public override string ProcessDescription { get; } = "Database Definition Convertor";
public String XmlSchemaRootElementName { get; } = "DbDfnDatabase";
// Processing.
protected override bool Run()
{
throw new NotSupportedException(ProcessDescription + " - 'Run' not supported. Use a specific conversion method.");
}
//-------------------------------------------------------------------
// X M L T o T a b l e s
//-------------------------------------------------------------------
public List<DbDfnTable> ConvertXmlToTables(String xmlSchemaData)
{
ClearProcessError();
String fn = GetType().Name + ".ConvertXmlToTables";
Dictionary<String, DbDfnTable> tables = new Dictionary<String, DbDfnTable>(StringComparer.OrdinalIgnoreCase);
try
{
// Load XML data.
XDocument xmlSchema = XDocument.Parse(xmlSchemaData);
// Root element.
XElement rootElement = xmlSchema.Root;
if (rootElement == null)
throw new NotSupportedException("XML schema missing root node");
String rootElementName = rootElement.GetLocalName();
if (!rootElementName.EqualsCI(XmlSchemaRootElementName))
throw new NotSupportedException("XML schema has invalid root node. Expected: " + XmlSchemaRootElementName + ". Found: " + rootElementName);
// 'Tables' element.
XElement tablesElement = rootElement.GetFirstChildElement("Tables");
if (tablesElement == null)
throw new NotSupportedException("XML schema missing tables node");
// Iterate tables.
foreach (XElement tableElement in tablesElement.GetChildElements("DbDfnTable"))
{
DbDfnTable tableDfn = new DbDfnTable()
{
Schema = tableElement.GetChildText("Schema"),
Name = tableElement.GetChildText("Name"),
Remarks = tableElement.GetChildText("Remarks")
};
if (tableDfn.Name.IsEmpty())
throw new NotSupportedException("XML schema contains blank table name.");
if (tables.ContainsKey(tableDfn.QualifiedName))
throw new NotSupportedException("XML schema contains duplicate table: " + tableDfn.QualifiedName);
tables[tableDfn.QualifiedName] = tableDfn;
// Columns.
XElement columnsElement = tableElement.GetFirstChildElement("Columns");
if (tablesElement == null)
throw new NotSupportedException("XML schema table missing columns node: " + tableDfn.QualifiedName);
// Iterate columns.
foreach (XElement columnElement in columnsElement.GetChildElements("DbDfnColumn"))
{
DbDfnColumn columnDfn = new DbDfnColumn()
{
Schema = tableDfn.Schema,
Table = tableDfn.Name,
Pos = StringUtil.ToShort(columnElement.GetChildText("Pos")),
Name = columnElement.GetChildText("Name"),
DataType = EnumUtil.ParseEnum(columnElement.GetChildText("DataType"), DbColumnDataType.Unknown),
DataTypeName = columnElement.GetChildText("DataTypeName"),
DataTypeNative = StringUtil.ToShort(columnElement.GetChildText("DataTypeNative")),
DataTypeNameNative = columnElement.GetChildText("DataTypeNameNative"),
IsIdentity = StringUtil.ToBool(columnElement.GetChildText("IsIdentity")),
Size = StringUtil.ToLong(columnElement.GetChildText("Size")),
BufferLen = StringUtil.ToLong(columnElement.GetChildText("BufferLen")),
DecimalDigits = StringUtil.ToShort(columnElement.GetChildText("DecimalDigits")),
Nullable = EnumUtil.ParseEnum(columnElement.GetChildText("Nullable"), DbColumnNullable.Unknown),
IsNullable = StringUtil.ToBool(columnElement.GetChildText("IsNullable")),
Remarks = columnElement.GetChildText("Remarks")
};
tableDfn.AddColumn(columnDfn);
}
// Indices.
XElement IndicesElement = tableElement.GetFirstChildElement("Indices");
if (IndicesElement == null)
throw new NotSupportedException("XML schema table missing indices node: " + tableDfn.QualifiedName);
// Iterate indices.
foreach (XElement indexElement in IndicesElement.GetChildElements("DbDfnIndex"))
{
DbDfnIndex indexDfn = new DbDfnIndex()
{
Schema = tableDfn.Schema,
Table = tableDfn.Name,
Name = indexElement.GetChildText("Name"),
IndexType = StringUtil.ToInt(indexElement.GetChildText("IndexType")),
Unique = StringUtil.ToBool(indexElement.GetChildText("Unique")),
Primary = StringUtil.ToBool(indexElement.GetChildText("Primary")),
Clustered = StringUtil.ToBool(indexElement.GetChildText("Clustered")),
Nullable = StringUtil.ToBool(indexElement.GetChildText("Nullable")),
Pages = StringUtil.ToInt(indexElement.GetChildText("Pages")),
UniqueValues = StringUtil.ToInt(indexElement.GetChildText("UniqueValues")),
HasColumns = StringUtil.ToBool(indexElement.GetChildText("HasColumns")),
};
// Index columns.
XElement IndexColumnsElement = indexElement.GetFirstChildElement("Columns");
foreach (XElement indexColumnElement in IndexColumnsElement?.GetChildElements("DbDfnIndexColumn") ?? Enumerable.Empty<XElement>())
{
DbDfnIndexColumn indexColumn = new DbDfnIndexColumn()
{
Seq = StringUtil.ToShort(indexColumnElement.GetChildText("Seq")),
Name = indexColumnElement.GetChildText("Name"),
Ascend = StringUtil.ToBool(indexColumnElement.GetChildText("Ascend")),
};
indexDfn.AddColumn(indexColumn);
}
tableDfn.AddIndex(indexDfn);
}
}
}
catch (Exception exc)
{
SetProcessError(exc.GetErrorStateMessage());
SaLogger.Warn(fn + " " + ExceptionUtil.GetLogMessage(exc));
}
return tables.Values.ToList();
}
//-------------------------------------------------------------------
}
//=======================================================================
}