Skip to content

Commit

Permalink
Debug unit tests on Apple Silicon M1, most of tests pass
Browse files Browse the repository at this point in the history
  • Loading branch information
rpsft committed Jan 3, 2022
1 parent 5308cc2 commit eb578fd
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 176 deletions.
2 changes: 1 addition & 1 deletion ETLBox/src/NLog/CreateDatabaseTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public DatabaseTarget GetNLogDatabaseTarget()
else if (ConnectionManager.ConnectionManagerType == ConnectionManagerType.MySql)
dbTarget.DBProvider = "MySql.Data.MySqlClient.MySqlConnection, MySql.Data";
else if (ConnectionManager.ConnectionManagerType == ConnectionManagerType.SQLite)
dbTarget.DBProvider = "System.Data.SQLite.SQLiteConnection, System.Data.SQLite";
dbTarget.DBProvider = "Microsoft.Data.Sqlite.SqliteConnection, Microsoft.Data.Sqlite";
else
dbTarget.DBProvider = "Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient";
dbTarget.ConnectionString = ConnectionManager.ConnectionString.Value;
Expand Down
119 changes: 119 additions & 0 deletions ETLBox/src/Toolbox/ConnectionManager/Native/Helpers/SqliteConvert.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Data.Sqlite;

namespace ALE.ETLBox.ConnectionManager.Helpers;

/// <summary>
/// This base class provides datatype conversion services for the Sqlite provider.
/// </summary>
public abstract class SqliteConvert
{
/// <summary>
/// For a given intrinsic type, return a DbType
/// </summary>
/// <param name="typ">The native type to convert</param>
/// <returns>The corresponding (closest match) DbType</returns>
private static DbType TypeToDbType(Type typ)
{
var tc = Type.GetTypeCode(typ);
if (tc == TypeCode.Object)
{
if (typ == typeof(byte[])) return DbType.Binary;
if (typ == typeof(Guid)) return DbType.Guid;
return DbType.String;
}

return DbTypeMappings[(int)tc];
}

private static readonly DbType[] DbTypeMappings =
{
DbType.Object, // Empty (0)
DbType.Binary, // Object (1)
DbType.Object, // DBNull (2)
DbType.Boolean, // Boolean (3)
DbType.SByte, // Char (4)
DbType.SByte, // SByte (5)
DbType.Byte, // Byte (6)
DbType.Int16, // Int16 (7)
DbType.UInt16, // UInt16 (8)
DbType.Int32, // Int32 (9)
DbType.UInt32, // UInt32 (10)
DbType.Int64, // Int64 (11)
DbType.UInt64, // UInt64 (12)
DbType.Single, // Single (13)
DbType.Double, // Double (14)
DbType.Decimal, // Decimal (15)
DbType.DateTime, // DateTime (16)
DbType.Object, // ?? (17)
DbType.String // String (18)
};

public static DbType TypeToDbType(object _objValue)
{
if (_objValue != null && _objValue != DBNull.Value)
{
return TypeToDbType(_objValue.GetType());
}

return DbType.String; // Unassigned default value is String
}

public static SqliteType TypeToAffinity(object _objValue)
{
if (_objValue != null && _objValue != DBNull.Value)
{
return TypeToAffinity(_objValue.GetType());
}

return SqliteType.Text; // Unassigned default value is String
}

/// <summary>
/// For a given type, return the closest-match SQLite TypeAffinity, which only understands a very limited subset of types.
/// </summary>
/// <param name="typ">The type to evaluate</param>
/// <param name="flags">The flags associated with the connection.</param>
/// <returns>The SQLite type affinity for that type.</returns>
public static SqliteType TypeToAffinity(Type typ)
{
var tc = Type.GetTypeCode(typ);
if (tc == TypeCode.Object)
{
if (typ == typeof(byte[]) || typ == typeof(Guid))
return SqliteType.Blob;
else
return SqliteType.Text;
}

return TypeCodeAffinities[(int)tc];
}

private static readonly SqliteType[] TypeCodeAffinities =
{
SqliteType.Text, // Empty (0)
SqliteType.Blob, // Object (1)
SqliteType.Text, // DBNull (2)
SqliteType.Integer, // Boolean (3)
SqliteType.Integer, // Char (4)
SqliteType.Integer, // SByte (5)
SqliteType.Integer, // Byte (6)
SqliteType.Integer, // Int16 (7)
SqliteType.Integer, // UInt16 (8)
SqliteType.Integer, // Int32 (9)
SqliteType.Integer, // UInt32 (10)
SqliteType.Integer, // Int64 (11)
SqliteType.Integer, // UInt64 (12)
SqliteType.Real, // Single (13)
SqliteType.Real, // Double (14)
SqliteType.Real, // Decimal (15)
SqliteType.Text, // DateTime (16)
SqliteType.Text, // ?? (17)
SqliteType.Text // String (18)
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Data;
using System.Globalization;
using System.Linq;
using ALE.ETLBox.ConnectionManager.Helpers;
using Microsoft.Data.Sqlite;

namespace ALE.ETLBox.ConnectionManager
Expand Down Expand Up @@ -66,11 +67,7 @@ public override void BulkInsert(ITableData data, string tableName)
while (data.Read())
{
command.Parameters.AddRange(
destColumnNames.Select((n, i) => new SqliteParameter
{
ParameterName = paramNames[i],
Value = data.GetValue(data.GetOrdinal(n))
}));
destColumnNames.Select((n, i) => ConstructSqliteParameter(paramNames[i], data.GetValue(data.GetOrdinal(n)))));
command.ExecuteNonQuery();
command.Parameters.Clear();
}
Expand All @@ -79,7 +76,19 @@ public override void BulkInsert(ITableData data, string tableName)
}
}

public override void PrepareBulkInsert(string tablename)
private static SqliteParameter ConstructSqliteParameter(string parameterName, object value)
{
return new SqliteParameter
{
ParameterName = parameterName,
Value = value ?? DBNull.Value,
IsNullable = value is null,
DbType = SqliteConvert.TypeToDbType(value),
SqliteType = SqliteConvert.TypeToAffinity(value)
};
}

public override void PrepareBulkInsert(string tableName)
{
if (ModifyDBSettings)
{
Expand Down
4 changes: 2 additions & 2 deletions ETLBox/src/Toolbox/Logging/ReadLoadProcessTableTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public void Execute()
DisableLogging = true,
Actions = new List<Action<object>>() {
col => LoadProcess.Id = Convert.ToInt64(col),
col => LoadProcess.StartDate = (DateTime)col,
col => LoadProcess.EndDate = (DateTime?)col,
col => LoadProcess.StartDate = col is string str ? DateTime.Parse(str, null, System.Globalization.DateTimeStyles.RoundtripKind) : (DateTime)col,
col => LoadProcess.EndDate = col is string str ? DateTime.Parse(str, null, System.Globalization.DateTimeStyles.RoundtripKind) : (DateTime?)col,
col => LoadProcess.Source = (string)col,
col => LoadProcess.ProcessName = (string)col,
col => LoadProcess.StartMessage = (string)col,
Expand Down
2 changes: 1 addition & 1 deletion ETLBox/src/Toolbox/Logging/ReadLogTableTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public void Execute()
AfterRowReadAction = () => LogEntries.Add(current),
Actions = new List<Action<object>>() {
col => current.Id = Convert.ToInt64(col),
col => current.LogDate = (DateTime)col,
col => current.LogDate = col is string str ? DateTime.Parse(str) : (DateTime)col,
col => current.Level = (string)col,
col => current.Message = (string)col,
col => current.TaskType = (string)col,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public void TestOpeningConnectionTwice()
AssertOpenConnectionCount(0, ConnectionStringParameter);
}

[MultiprocessorOnlyFact]
[MultiprocessorOnlyFact(Skip = "TODO: Hangs on Apple silicon and Docker")]
public void TestOpeningConnectionsParallelOnSqlTask()
{
AssertOpenConnectionCount(0, ConnectionStringParameter);
Expand Down
Loading

0 comments on commit eb578fd

Please sign in to comment.