Add project files.

This commit is contained in:
Andy Howard
2021-05-05 15:36:28 +01:00
parent 949836d24c
commit a4cf706eb3
353 changed files with 60029 additions and 0 deletions
@@ -0,0 +1,408 @@
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
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.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Sarand.Net.Standard.Dbas.Proc
{
//=======================================================================
public class SaDbProcess_CompareDatabaseSchemas : SacsProcess
{
//-------------------------------------------------------------------
// Configuration.
public new class Config : SacsProcess.Config
{
public Config (SacsDatabase sourceDatabase, SacsDatabase targetDatabase)
{
SourceDatabase = sourceDatabase;
TargetDatabase = targetDatabase;
}
public SacsDatabase SourceDatabase { get; }
public SacsDatabase TargetDatabase { get; }
public bool HideIdenticalObjects { get; set; }
public bool IgnoreNullable { get; set; }
public bool IgnorePosition { get; set; }
public bool IgnoreSimilarCharTypes { get; set; }
public bool IgnoreSimilarNumericTypes { get; set; }
}
//-------------------------------------------------------------------
// Definitions.
public interface IProcessNotifier : ISacsProcessNotifier
{
void OnSchemaComparisonItemAdded (SaDbProcess_CompareDatabaseSchemas proc);
}
public class SchemaComparisonItem
{
internal SchemaComparisonItem (String tableName, String columnName, int columnPosition, String indexName, String comment)
{
Id = ++SeedId;
TableName = tableName;
ColumnName = columnName;
ColumnPosition = columnPosition;
IndexName = indexName;
Comment = comment;
}
public static int SeedId { get; private set; }
public int Id { get; }
public String TableName { get; }
public String ColumnName { get; }
public int ColumnPosition { get; }
public String IndexName { get; }
public String Comment { get; }
}
//-------------------------------------------------------------------
// Data members.
private Config config;
private IProcessNotifier processNotifier = null;
private readonly List<SchemaComparisonItem> schemaComparisonItems = new List<SchemaComparisonItem>();
//-------------------------------------------------------------------
// Construction.
public SaDbProcess_CompareDatabaseSchemas (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 Schema Comparison";
public new IProcessNotifier ProcessNotifier
{
get { return processNotifier; }
set
{
processNotifier = value;
base.ProcessNotifier = value;
}
}
//-------------------------------------------------------------------
// S c h e m a D i f f e r e n c e s
//-------------------------------------------------------------------
public List<SchemaComparisonItem> GetSchemaComparisonItems (int minId = 0)
{
return new List<SchemaComparisonItem>(schemaComparisonItems.FindAll(item => item.Id >= minId));
}
//-------------------------------------------------------------------
// P r o c e s s i n g
//-------------------------------------------------------------------
protected override bool Run ()
{
schemaComparisonItems.Clear();
if (config.SourceDatabase == null) return SetProcessError("Source database must be supplied.");
CompareTables();
return OK;
}
//-------------------------------------------------------------------
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;)
{
String sourceTableName = (sourceTableIdx < sourceTables.Count ? sourceTables[sourceTableIdx] : "");
String targetTableName = (targetTableIdx < targetTables.Count ? targetTables[targetTableIdx] : "");
if (StringUtil.IsEmpty(targetTableName) || targetTableName.CompareTo(sourceTableName) > 0)
{
// Target table missing.
AddSchemaComparisonItem(sourceTableName, "", 0, "", "Table is missing");
sourceTableIdx++;
continue;
}
if (StringUtil.IsEmpty(sourceTableName) || sourceTableName.CompareTo(targetTableName) > 0)
{
// Source table missing.
AddSchemaComparisonItem(targetTableName, "", 0, "", "Table is not required");
targetTableIdx++;
continue;
}
SetProgressInfo("Processing table: " + sourceTableName);
// Table is present in both databases.
if (!config.HideIdenticalObjects) AddSchemaComparisonItem(sourceTableName, "", 0, "", "Table OK");
#if DEBUG_X
if (sourceTableName.EqualsCI("address"))
Debugger.Break();
#endif
// Retrieve table definition from each database.
DbDfnTable sourceTableDfn = config.SourceDatabase.GetTableDfn (sourceTableName);
DbDfnTable targetTableDfn = config.TargetDatabase.GetTableDfn (targetTableName);
// Compare the columns and indices.
CompareTableColumns(sourceTableDfn, targetTableDfn);
CompareTableIndices(sourceTableDfn, targetTableDfn);
// Move to next table in BOTH lists.
sourceTableIdx++;
targetTableIdx++;
}
}
//-------------------------------------------------------------------
private bool CompareTableColumns (DbDfnTable sourceTableDfn, DbDfnTable targetTableDfn)
{
String tableName = sourceTableDfn.Name;
#if DEBUG_X
if (tableName.EqualsCI("company"))
Debugger.Break();
#endif
// Columns:
List<DbDfnColumn> sourceColumns = sourceTableDfn.Columns;
List<DbDfnColumn> targetColumns = targetTableDfn.Columns;
List<String> sourceColumnNames = sourceColumns.GetNames();
List<String> targetColumnNames = targetColumns.GetNames();
sourceColumnNames.Sort();
targetColumnNames.Sort();
for (int sourceColumnIdx = 0, targetColumnIdx = 0; sourceColumnIdx < sourceColumns.Count && targetColumnIdx < targetColumns.Count;)
{
// Retrieve the Column names:
int iPosition = 0;
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);
if (sourceColumn != null) iPosition = sourceColumn.Pos;
DbDfnColumn targetColumn = targetColumns.GetColumnByName(targetColumnName);
// Compare Columns.
if (StringUtil.IsEmpty(targetColumnName) || targetColumnName.CompareTo(sourceColumnName) > 0)
{
// Column is only present in SOURCE list:
AddSchemaComparisonItem(tableName, sourceColumnName, iPosition, "", "Column is missing");
// Move to next Column in SOURCE list:
sourceColumnIdx++;
continue;
}
else if (StringUtil.IsEmpty(sourceColumnName) || sourceColumnName.CompareTo(targetColumnName) > 0)
{
// Column is only present in TARGET list:
AddSchemaComparisonItem(tableName, targetColumnName, iPosition, "", "Column is not required");
// Move to next Column in TARGET list:
targetColumnIdx++;
continue;
}
else
{
// Column is present in both databases.
List<String> lDifferences = new List<string>();
// Verify column attributes:
if (!config.IgnorePosition)
if (sourceColumn.Pos != targetColumn.Pos) lDifferences.Add("pos");
if (!sourceColumn.Name.EqualsCI(targetColumn.Name)) lDifferences.Add("name");
if (ColumnNativeDataTypesDiffer(sourceColumn, targetColumn)) lDifferences.Add((String)"native type (" + sourceColumn.DataTypeNameNative + ":" + targetColumn.DataTypeNameNative + ")");
else if (ColumnDataTypesDiffer(sourceColumn, targetColumn)) lDifferences.Add("data type (" + sourceColumn.DataTypeName + ":" + targetColumn.DataTypeName + ")");
if (ColumnSizesDiffer(sourceColumn, targetColumn)) lDifferences.Add((String)"size (" + sourceColumn.Size + ":" + targetColumn.Size + ")");
if (ColumnDecimalsDiffer(sourceColumn, targetColumn)) lDifferences.Add("decimals (" + sourceColumn.DecimalDigits + "," + targetColumn.DecimalDigits + ")");
if (!config.IgnoreNullable)
{
if (sourceColumn.Nullable != targetColumn.Nullable) lDifferences.Add("nullable");
if (sourceColumn.IsNullable != targetColumn.IsNullable) lDifferences.Add("is nullable");
}
// Display results:
if (!config.HideIdenticalObjects || !lDifferences.IsEmpty())
AddSchemaComparisonItem(tableName, sourceColumnName, iPosition, "", (lDifferences.IsEmpty() ? "Column OK" : "Different: " + lDifferences.Concat(", ")));
// Move to next Column in BOTH lists:
sourceColumnIdx++;
targetColumnIdx++;
}
}
return OK;
}
private static long iLargeSizeThreshold = 4000;
private bool ColumnSizesDiffer (DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
{
if (sourceColumn.Size == targetColumn.Size) return false;
// If both columns are large, treat then as equal:
if (sourceColumn.Size >= iLargeSizeThreshold && targetColumn.Size >= iLargeSizeThreshold) return false;
// If one column is large (eg. varchar max) and the other zero (eg. Access Large Text):
if (sourceColumn.Size >= iLargeSizeThreshold && targetColumn.Size == 0) return false;
if (sourceColumn.Size == 0 && targetColumn.Size >= iLargeSizeThreshold) return false;
// Check for specific data types:
String sourceDataType = sourceColumn.DataTypeNameNative;
String targetDataType = targetColumn.DataTypeNameNative;
// Ignore length check for numeric types.
if (config.IgnoreSimilarNumericTypes)
{
// Floating point types.
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",",");
if (dateTimeTypes.ContainsCI(sourceDataType) && dateTimeTypes.ContainsCI(targetDataType)) return false;
return true;
}
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",",");
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",",");
if (dateTimeTypes.ContainsCI(sourceDataType) && dateTimeTypes.ContainsCI(targetDataType)) return false;
return true;
}
private bool ColumnDataTypesDiffer (DbDfnColumn sourceColumn, DbDfnColumn targetColumn)
{
if (sourceColumn.DataType == targetColumn.DataType) return false;
// Check for specific data type matches:
String sourceDataType = sourceColumn.DataTypeName;
String targetDataType = targetColumn.DataTypeName;
if (config.IgnoreSimilarCharTypes)
{
}
if (config.IgnoreSimilarNumericTypes)
{
// Similar numeric type.
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)
{
if (sourceColumn.DataTypeNative == targetColumn.DataTypeNative) return false;
// Check for specific data type matches:
String sourceDataType = sourceColumn.DataTypeNameNative;
String targetDataType = targetColumn.DataTypeNameNative;
if (config.IgnoreSimilarCharTypes)
{
// Similar Char types.
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",",");
if (numericTypes.ContainsCI(sourceDataType) && numericTypes.ContainsCI(targetDataType)) return false;
}
return true;
}
//-------------------------------------------------------------------
private bool CompareTableIndices (DbDfnTable sourceTableDfn, DbDfnTable targetTableDfn)
{
String sTable = sourceTableDfn.Name;
// Indices:
List<DbDfnIndex> sourceIndices = sourceTableDfn.Indices;
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; )
{
// Retrieve the Index names.
String sourceIndexName = sourceIndexIdx < sourceIndexNames.Count ? sourceIndexNames[sourceIndexIdx] : "";
String targetIndexName = targetIndexIdx < targetIndexNames.Count ? targetIndexNames[targetIndexIdx] : "";
// Compare Indices.
if (StringUtil.IsEmpty(targetIndexName) || targetIndexName.CompareTo(sourceIndexName) > 0)
{
// Index is only present in SOURCE list.
AddSchemaComparisonItem(sTable, "", 0, sourceIndexName, "Index is missing");
// Move to next Index in SOURCE list.
sourceIndexIdx++;
}
else if (StringUtil.IsEmpty(sourceIndexName) || sourceIndexName.CompareTo(targetIndexName) > 0)
{
// Index is only present in TARGET list.
AddSchemaComparisonItem(sTable, "", 0, targetIndexName, "Index is not required");
// Move to next Index in TARGET list.
targetIndexIdx++;
}
else
{
// Index is present in both databases.
// Retrieve Index definition from each database.
DbDfnIndex sourceIndex = sourceIndices.GetIndexByName(sourceIndexName);
DbDfnIndex targetIndex = targetIndices.GetIndexByName(targetIndexName);
List<String> indexDifferences = new List<string>();
// Verify Index attributes.
if (!sourceIndex.Name.EqualsCI(targetIndex.Name)) indexDifferences.Add("name");
if (sourceIndex.Primary != targetIndex.Primary) indexDifferences.Add("primary");
if (sourceIndex.Unique != targetIndex.Unique) indexDifferences.Add("unique");
if (sourceIndex.Nullable != targetIndex.Nullable) indexDifferences.Add("nullable");
// Display results.
if (!config.HideIdenticalObjects || indexDifferences.Count > 0)
AddSchemaComparisonItem(sTable, "", 0, sourceIndexName, (indexDifferences.IsEmpty() ? "Index OK" : "Different: " + indexDifferences.Concat(",")));
// Compare index column lists:
List<DbDfnIndexColumn> sourceIndexColumns = sourceIndex.Columns;
List<DbDfnIndexColumn> targetIndexColumns = targetIndex.Columns;
for (int sourceColumnIdx = 0; sourceColumnIdx < sourceIndexColumns.Count; sourceColumnIdx++)
{
String columnName = sourceIndexColumns[sourceColumnIdx].Name;
int columnPos = sourceColumnIdx + 1;
if (!targetIndexColumns.Exists(item => item.Name.EqualsCI(columnName)))
AddSchemaComparisonItem(sTable, columnName, columnPos, sourceIndexName, "Index column is missing");
else if (sourceColumnIdx != targetIndexColumns.GetPosForName(columnName) - 1)
AddSchemaComparisonItem(sTable, columnName, columnPos, sourceIndexName, "Index column in different position");
}
for (int targetColumnIdx = 0; targetColumnIdx < targetIndexColumns.Count; targetColumnIdx++)
{
String columnName = targetIndexColumns[targetColumnIdx].Name;
int columnPos = targetColumnIdx + 1;
if (!sourceIndexColumns.Exists(item => item.Name.EqualsCI(columnName)))
AddSchemaComparisonItem(sTable, columnName, columnPos, targetIndexName, "Index column is not required");
}
// Move to next Index in BOTH lists.
sourceIndexIdx++;
targetIndexIdx++;
}
}
return OK;
}
//-------------------------------------------------------------------
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);
}
//-------------------------------------------------------------------
}
//=======================================================================
public static class SchemaComparisonItemList
{
/// <summary>Identify the maximum Id value in the list.</summary>
public static int GetMaxId (this IEnumerable<SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem> values)
{
int maxId = 0;
foreach (SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem schemaComparisonItem in values)
maxId = Math.Max(maxId, schemaComparisonItem.Id);
return maxId;
}
}
//=======================================================================
}
@@ -0,0 +1,438 @@
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;
namespace Sarand.Net.Standard.Dbas.Proc
{
//=======================================================================
public class SaDbProcess_ConvertDbDefinition : SacsProcess
{
//-------------------------------------------------------------------
// Configuration.
public enum SourceDefinitionType
{
Unknown = 0,
CppCode
}
public enum TargetDefinitionType
{
Unknown = 0,
CsCode
}
public new class Config : SacsProcess.Config
{
public Config ()
{
}
public SourceDefinitionType SourceDefinitionType { get; set; }
public String SourceDefinitionFilePath { get; set; }
public TargetDefinitionType TargetDefinitionType { get; set; }
public String TargetDefinitionFilePath { get; set; }
}
//-------------------------------------------------------------------
// Definitions.
public interface IProcessNotifier : ISacsProcessNotifier
{
}
private class Statistics
{
}
//-------------------------------------------------------------------
// Data members.
private Config config;
private IProcessNotifier processNotifier;
private readonly List<DbDfnTable> tableDfns = new List<DbDfnTable>();
private Statistics stats;
//-------------------------------------------------------------------
// Construction.
public SaDbProcess_ConvertDbDefinition (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 new IProcessNotifier ProcessNotifier
{
get { return processNotifier; }
set
{
processNotifier = value;
base.ProcessNotifier = value;
}
}
/// <summary>Processing statistics.</summary>
public override List<StringPair> ProcessingStatistics
{
get
{
List<StringPair> processStats = new List<StringPair>();
if (stats != null)
{
//if (tableDfns.Count > 0)
processStats.Add("Tables found", tableDfns.Count.ToString());
processStats.Add("Columns found", tableDfns.GetColumnCount().ToString());
}
return processStats;
}
}
//-------------------------------------------------------------------
// P r o c e s s i n g
//-------------------------------------------------------------------
protected override bool Run ()
{
// Initialise process.
tableDfns.Clear();
stats = new Statistics();
// Validate configuration.
if (!ValidateConfiguration()) return false;
ConvertCppDatabaseDefinition();
return OK;
}
protected bool ValidateConfiguration ()
{
// Source file.
if (config.SourceDefinitionType <= 0)
return SetProcessError("Source definition type must be specified.");
if (StringUtil.IsEmpty(config.SourceDefinitionFilePath))
return SetProcessError("Source definition file must be specified.");
if (!FileUtil.IsFile(config.SourceDefinitionFilePath))
return SetProcessError("Source definition file not found.");
// Target file.
if (config.TargetDefinitionType <= 0)
return SetProcessError("Target definition type must be specified.");
if (StringUtil.IsEmpty(config.TargetDefinitionFilePath))
return SetProcessError("Target definition file must be specified.");
if (!DirectoryUtil.DirectoryExists(DirectoryUtil.GetDirectoryName(config.TargetDefinitionFilePath)))
return SetProcessError("Target folder not found.");
if (config.SourceDefinitionFilePath.EqualsCI(config.TargetDefinitionFilePath))
return SetProcessError("Target file must not be the same as the source file.");
return OK;
}
//-------------------------------------------------------------------
private bool ConvertCppDatabaseDefinition ()
{
if (!OK) return false;
// Read source database definition.
ExtractDatabaseDefinition();
return OK;
}
//-------------------------------------------------------------------
// E x t r a c t S o u r c e D e f i n i t i o n
//-------------------------------------------------------------------
private class TableData
{
public String TableName { get; set; } = "";
public int TableIdx { get; set; } = -1;
}
private class ColumnData
{
public String TableName { get; set; } = "";
public String ColumnName { get; set; } = "";
public int DataType { get; set; } = -1;
public int ColumnLength { get; set; } = -1;
public int TableIdx { get; set; } = -1;
public int ColumnIdx { get; set; } = -1;
}
private class SourceDefinition_Params
{
protected SourceDefinition_Params () { }
public int LineNumber { get; set; } = -1;
public int TableIdx { get; set; } = -1;
public int ColumnIdx { get; set; } = -1;
}
private class SourceDefinition_Params_CppCode : SourceDefinition_Params
{
public bool TablesEnumFound { get; set; }
public bool InTablesEnum { get; set; }
public bool ColumnsEnumFound { get; set; }
public bool InColumnsEnum { get; set; }
public bool ColumnsDfnsFound { get; set; }
public bool InColumnsDfns { get; set; }
public Dictionary<String, TableData> TableMap { get; } = new Dictionary<String, TableData>();
public Dictionary<StringPair, ColumnData> ColumnMap { get; } = new Dictionary<StringPair, ColumnData>();
}
//-------------------------------------------------------------------
private bool ExtractDatabaseDefinition ()
{
if (!OK) return false;
// Source definition parameters.
SourceDefinition_Params sourceDfnParams = null;
SourceDefinition_Params_CppCode sourceDfnParams_CppCode = null;
if (config.SourceDefinitionType == SourceDefinitionType.CppCode)
{
sourceDfnParams_CppCode = new SourceDefinition_Params_CppCode();
sourceDfnParams = sourceDfnParams_CppCode;
}
try
{
// Extract source database definition.
using (StreamReader file = new StreamReader(config.SourceDefinitionFilePath))
{
while (OK)
{
String line = file.ReadLine();
if (line == null) break;
sourceDfnParams.LineNumber++;
SetProgressInfo("Extracting source database definition.");
line = line.Trim(new char[] { ' ', '\t', '\r', '\n' });
if (config.SourceDefinitionType == SourceDefinitionType.CppCode)
{
ExtractDatabaseDefinitionLine_CppCode(sourceDfnParams_CppCode, line);
}
}
file.Close();
}
// Generate target database definition.
String dbDfnClassname = "SaDbDfn";
using (System.IO.StreamWriter file = new System.IO.StreamWriter(config.TargetDefinitionFilePath))
{
file.WriteLine("using Sarand.Net.Standard.Base.Core;");
file.WriteLine("using Sarand.Net.Standard.Base.Dbas;");
file.WriteLine("using System;");
file.WriteLine("using System.Collections.Generic;");
file.WriteLine("using System.Linq;");
file.WriteLine("");
file.WriteLine("//---------------------------------------------------------------------------");
file.WriteLine("// Code generated by Sarand Database Utilities " + DateTime.Now.Format("ddd d-MMM-yyyy HH:mm:ss"));
file.WriteLine("//---------------------------------------------------------------------------");
file.WriteLine("namespace sarand.database.definition");
file.WriteLine("{");
file.WriteLine("\tpublic class " + dbDfnClassname);
file.WriteLine("\t{");
file.WriteLine("\t\t//-------------------------------------------------------------------");
DatabaseDefinitionGenerator.GenerateDatabaseDefinitionTablesEnum(tableDfns, file);
DatabaseDefinitionGenerator.GenerateDatabaseDefinitionColumnsEnum(tableDfns, file);
DatabaseDefinitionGenerator.GenerateDatabaseDefinitionClass(tableDfns, dbDfnClassname, file);
file.WriteLine("\t}");
file.WriteLine("}");
file.Close();
}
}
catch (Exception exc) { SaLogger.Warn(ExceptionUtil.GetLogMessage(exc)); SetProcessError(ExceptionUtil.GetErrorStateMessage(exc)); }
return OK;
}
//-------------------------------------------------------------------
// C + + C o d e S o u r c e
//-------------------------------------------------------------------
private readonly Dictionary<int,String> cppColumnDataTypes = new Dictionary<int, string>()
{
{ 1, "VarChar" },
{ -7, "Bit" },
{ -6, "TinyInt" },
{ 5, "SmallInt" },
{ -16, "Int" },
{ -25, "BigInt" },
{ 7, "Single" },
{ 8, "Double" },
{ 93, "DateTime" }
};
private bool ExtractDatabaseDefinitionLine_CppCode (SourceDefinition_Params_CppCode sourceDfnParams, String line)
{
if (!OK) return false;
// C++ Code definition.
//---------------------------------------------------------------
// Table enums.
if (line.EqualsCI("enum eSaDbTable"))
{
// Table enum start.
if (sourceDfnParams.TablesEnumFound)
return SetProcessError("Found multiple table enums at line " + sourceDfnParams.LineNumber + ": " + line + ".");
sourceDfnParams.TablesEnumFound = true;
sourceDfnParams.InTablesEnum = true;
return OK;
}
if (sourceDfnParams.InTablesEnum)
{
// In Tables enum.
if (line.Equals("};") || line.EqualsCI("// Database column identifiers:"))
sourceDfnParams.InTablesEnum = false;
else if (!line.ContainsCI("eSaDbTblUnknown"))
{
if (!line.ContainsCI("eSaDbTbl"))
return SetProcessError("Invalid table definition on line " + sourceDfnParams.LineNumber + ": " + line + ".");
// Extract table name.
String tableName = line.ReplaceAll("eSaDbTbl","").ReplaceAll(",","");
if (StringUtil.IsEmpty(tableName))
return SetProcessError("Blank table name on line " + sourceDfnParams.LineNumber + ": " + line + ".");
if (tableDfns.Exists(item => item.Name.EqualsCI(tableName)))
return SetProcessError("Duplicate table name on line " + sourceDfnParams.LineNumber + ": " + line + ".");
// Add this table to the list.
sourceDfnParams.TableIdx++;
//SaLogger.Debug("Table #" + sourceDfnParams.TableIdx + ": " + tableName);
sourceDfnParams.TableMap.Add(tableName, new TableData() { TableName = tableName, TableIdx = sourceDfnParams.TableIdx });
tableDfns.Add(new DbDfnTable("", tableName, ""));
}
return OK;
}
//---------------------------------------------------------------
// Column enums.
if (line.EqualsCI("enum eSaDbColumn"))
{
// Column enum start.
if (sourceDfnParams.ColumnsEnumFound)
return SetProcessError("Found multiple columns enums at line " + sourceDfnParams.LineNumber + ": " + line + ".");
sourceDfnParams.ColumnsEnumFound = true;
sourceDfnParams.InColumnsEnum = true;
return OK;
}
if (sourceDfnParams.InColumnsEnum)
{
// In Columns enum.
if (line.Equals("};") || line.StartsWithCI("//----"))
sourceDfnParams.InColumnsEnum = false;
else if (!line.ContainsCI("eSaDbColUnknown"))
{
if (!line.ContainsCI("eSaDbCol"))
return SetProcessError("Invalid column definition on line " + sourceDfnParams.LineNumber + ": " + line + ".");
// Column definitions:
// eSaDbColUnknown = -1,
// #define eSaDbColVendorType_ListID (eSaDbColumn)4101
// #define eSaDbColSaCode_Notes (eSaDbColumn)101
// Extract Table/Column name pair - value starts 'eSaDbCol'.
int colDfnStartIdx = line.IndexOf("eSaDbCol");
String tableColumnName = line.Substring(colDfnStartIdx + "eSaDbCol".Length);
// Table/Column names end with space, equals or comma.
int colDfnEndIdx = tableColumnName.IndexOf(' ');
if (colDfnEndIdx > 0)
tableColumnName = tableColumnName.Left(colDfnEndIdx + 1);
colDfnEndIdx = tableColumnName.IndexOf('=');
if (colDfnEndIdx > 0)
tableColumnName = tableColumnName.Left(colDfnEndIdx + 1);
colDfnEndIdx = tableColumnName.IndexOf(',');
if (colDfnEndIdx > 0)
tableColumnName = tableColumnName.Left(colDfnEndIdx + 1);
//SaLogger.Debug("Table/Column name: " + tableColumnName);
// Split table and column names on Underscore.
String[] tableColumnNameParts = tableColumnName.Split('_');
if (tableColumnNameParts.Length != 2)
return SetProcessError("Invalid column definition on line (missing underscore?) " + sourceDfnParams.LineNumber + ": " + line + ".");
sourceDfnParams.ColumnIdx++;
String tableName = tableColumnNameParts[0];
String columnName = tableColumnNameParts[1];
//SaLogger.Debug("Column #" + sourceDfnParams.ColumnIdx + ": " + tableName + "." + columnName);
sourceDfnParams.ColumnMap.Add(new StringPair(tableName, columnName), new ColumnData() { TableName = tableName, ColumnName = columnName, ColumnIdx = sourceDfnParams.ColumnIdx });
}
return OK;
}
//---------------------------------------------------------------
// Column definitions.
if (line.StartsWithCI("SaDbColumnDefinition dfnColumn []"))
{
// Column definitions start.
if (sourceDfnParams.ColumnsDfnsFound)
return SetProcessError("Found multiple column definitions at line " + sourceDfnParams.LineNumber + ": " + line + ".");
sourceDfnParams.ColumnsDfnsFound = true;
sourceDfnParams.InColumnsDfns = true;
sourceDfnParams.ColumnIdx = -1;
return OK;
}
if (sourceDfnParams.InColumnsDfns)
{
if (line.Equals("{")) return OK;
if (line.Equals("};"))
{
sourceDfnParams.InColumnsDfns = false;
return OK;
}
// Column definition:
// { TableIdx,"ColumnName",DataType,Length }, ... [multiple per line]
// Column data types:
// eString = 1 SQL_C_CHAR
// eBool = -7 SQL_C_BIT
// eByte = -6 SQL_C_TINYINT
// eShortInt = 5 SQL_C_SHORT
// eLongInt = -16 SQL_C_SLONG
// eBigInt = -25 SQL_C_SBIGINT
// eReal = 7 SQL_C_FLOAT
// eDouble = 8 SQL_C_DOUBLE
// eTime = 93 SQL_C_TYPE_TIMESTAMP
foreach (String columnDfnDataRaw in line.Split(new String[] { "}," }, StringSplitOptions.RemoveEmptyEntries))
{
String columnDfnData = columnDfnDataRaw.ReplaceAll("{","").TrimAll();
//SaLogger.Debug("Column dfn: " + columnDfnData);
String[] columnDfnParts = columnDfnData.Split(',');
if (columnDfnParts.Length != 4) return SetProcessError("Invalid column definition (expecting 4 parts) at line " + sourceDfnParams.LineNumber + ": " + line + ".");
String tableIdxRaw = columnDfnParts[0].TrimAll();
int tableIdx = StringUtil.ToInt(tableIdxRaw);
String columnName = columnDfnParts[1].TrimAll().ReplaceAll("\"","");
String dataTypeRaw = columnDfnParts[2].TrimAll();
int dataType = StringUtil.ToInt(dataTypeRaw);
String columnLengthRaw = columnDfnParts[3].TrimAll();
int columnLength = StringUtil.ToInt(columnLengthRaw);
if (!tableIdxRaw.IsNumeric()) return SetProcessError("Invalid table index in column definition (" + tableIdxRaw + ") at line " + sourceDfnParams.LineNumber + ": " + line + ".");
if (StringUtil.IsEmpty(columnName)) return SetProcessError("Blank name in column definition at line " + sourceDfnParams.LineNumber + ": " + line + ".");
if (!dataTypeRaw.IsNumeric(true) || !cppColumnDataTypes.ContainsKey(dataType)) return SetProcessError("Invalid data type in column definition (" + dataTypeRaw + ") at line " + sourceDfnParams.LineNumber + ": " + line + ".");
if (!columnLengthRaw.IsNumeric()) return SetProcessError("Invalid column length in column definition (" + columnLengthRaw + ") at line " + sourceDfnParams.LineNumber + ": " + line + ".");
// Table definition.
String tableName = sourceDfnParams.TableMap.Values.ToList().Find(item => item.TableIdx == tableIdx)?.TableName ?? "";
if (StringUtil.IsEmpty(tableName)) return SetProcessError("Unable to identify table name for Table idx " + tableIdx + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
DbDfnTable tableDfn = tableDfns.GetTableByName(tableName);
if (tableDfn == null) return SetProcessError("Unable to retrieve table definition for Table name " + tableName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
// Column data.
sourceDfnParams.ColumnIdx++;
ColumnData columnData = sourceDfnParams.ColumnMap.Values.ToList().Find(item => item.TableName.EqualsCI(tableName) && item.ColumnIdx == sourceDfnParams.ColumnIdx);
if (columnData == null) return SetProcessError("Unable to column data for table " + tableName + " and column " + columnName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
if (columnData.ColumnName.EqualsCI(columnName)) return SetProcessError("Inconsistent column name for table " + tableName + " and column " + columnName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
// Column definition.
DbDfnColumn columnDfn = new DbDfnColumn()
{
Table = tableName,
Name = columnName,
DataType = EnumUtil.ParseEnum(cppColumnDataTypes.GetValue(dataType,""),DbColumnDataType.Unknown),
Size = columnLength
};
if (columnDfn.DataType < 0) return SetProcessError("Invalid data type for table " + tableName + " and column " + columnName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
tableDfn.AddColumn(columnDfn);
}
return OK;
}
//---------------------------------------------------------------
return OK;
}
//-------------------------------------------------------------------
}
//=======================================================================
}