Skip to content

Commit

Permalink
Merge pull request #1059 from inforithmics/FastColumnArgumentException
Browse files Browse the repository at this point in the history
Fix for issue "1.8.0-beta - System.ArgumentException: method arguments are incompatible" and Unit Tests
  • Loading branch information
praeclarum committed Sep 2, 2021
2 parents 4479f31 + e1d4ce7 commit 56c06a4
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 13 deletions.
36 changes: 23 additions & 13 deletions src/SQLite.cs
Expand Up @@ -3004,20 +3004,30 @@ public IEnumerable<T> ExecuteDeferredQuery<T> (TableMapping map)
var stmt = Prepare ();
try {
var cols = new TableMapping.Column[SQLite3.ColumnCount (stmt)];
var fastColumnSetters = new Action<T, Sqlite3Statement, int>[SQLite3.ColumnCount (stmt)];
var fastColumnSetters = new Action<object, Sqlite3Statement, int>[SQLite3.ColumnCount (stmt)];

if (map.Method == TableMapping.MapMethod.ByPosition)
{
Array.Copy(map.Columns, cols, Math.Min(cols.Length, map.Columns.Length));
}
else if (map.Method == TableMapping.MapMethod.ByName)
{
for (int i = 0; i < cols.Length; i++)
{
else if (map.Method == TableMapping.MapMethod.ByName) {
MethodInfo getSetter = null;
if (typeof(T) != map.MappedType) {
getSetter = typeof(FastColumnSetter)
.GetMethod (nameof(FastColumnSetter.GetFastSetter),
BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod (map.MappedType);
}

for (int i = 0; i < cols.Length; i++) {
var name = SQLite3.ColumnName16 (stmt, i);
cols[i] = map.FindColumn (name);
if (cols[i] != null)
fastColumnSetters[i] = FastColumnSetter.GetFastSetter<T> (_conn, cols[i]);
if (getSetter != null) {
fastColumnSetters[i] = (Action<object, Sqlite3Statement, int>)getSetter.Invoke(null, new object[]{ _conn, cols[i]});
}
else {
fastColumnSetters[i] = FastColumnSetter.GetFastSetter<T>(_conn, cols[i]);
}
}
}

Expand All @@ -3028,7 +3038,7 @@ public IEnumerable<T> ExecuteDeferredQuery<T> (TableMapping map)
continue;

if (fastColumnSetters[i] != null) {
fastColumnSetters[i].Invoke ((T)obj, stmt, i);
fastColumnSetters[i].Invoke (obj, stmt, i);
}
else {
var colType = SQLite3.ColumnType (stmt, i);
Expand Down Expand Up @@ -3369,9 +3379,9 @@ internal class FastColumnSetter
///
/// If no fast setter is available for the requested column (enums in particular cause headache), then this function returns null.
/// </returns>
internal static Action<T, Sqlite3Statement, int> GetFastSetter<T> (SQLiteConnection conn, TableMapping.Column column)
internal static Action<object, Sqlite3Statement, int> GetFastSetter<T> (SQLiteConnection conn, TableMapping.Column column)
{
Action<T, Sqlite3Statement, int> fastSetter = null;
Action<object, Sqlite3Statement, int> fastSetter = null;

Type clrType = column.PropertyInfo.PropertyType;

Expand Down Expand Up @@ -3528,7 +3538,7 @@ internal class FastColumnSetter
/// <param name="column">The column mapping that identifies the target member of the destination object</param>
/// <param name="getColumnValue">A lambda that can be used to retrieve the column value at query-time</param>
/// <returns>A strongly-typed delegate</returns>
private static Action<ObjectType, Sqlite3Statement, int> CreateNullableTypedSetterDelegate<ObjectType, ColumnMemberType> (TableMapping.Column column, Func<Sqlite3Statement, int, ColumnMemberType> getColumnValue) where ColumnMemberType : struct
private static Action<object, Sqlite3Statement, int> CreateNullableTypedSetterDelegate<ObjectType, ColumnMemberType> (TableMapping.Column column, Func<Sqlite3Statement, int, ColumnMemberType> getColumnValue) where ColumnMemberType : struct
{
var clrTypeInfo = column.PropertyInfo.PropertyType.GetTypeInfo();
bool isNullable = false;
Expand All @@ -3545,7 +3555,7 @@ internal class FastColumnSetter
return (o, stmt, i) => {
var colType = SQLite3.ColumnType (stmt, i);
if (colType != SQLite3.ColType.Null)
setProperty.Invoke (o, getColumnValue.Invoke (stmt, i));
setProperty.Invoke ((ObjectType)o, getColumnValue.Invoke (stmt, i));
};
}

Expand All @@ -3560,7 +3570,7 @@ internal class FastColumnSetter
/// <param name="column">The column mapping that identifies the target member of the destination object</param>
/// <param name="getColumnValue">A lambda that can be used to retrieve the column value at query-time</param>
/// <returns>A strongly-typed delegate</returns>
private static Action<ObjectType, Sqlite3Statement, int> CreateTypedSetterDelegate<ObjectType, ColumnMemberType> (TableMapping.Column column, Func<Sqlite3Statement, int, ColumnMemberType> getColumnValue)
private static Action<object, Sqlite3Statement, int> CreateTypedSetterDelegate<ObjectType, ColumnMemberType> (TableMapping.Column column, Func<Sqlite3Statement, int, ColumnMemberType> getColumnValue)
{
var setProperty = (Action<ObjectType, ColumnMemberType>)Delegate.CreateDelegate (
typeof (Action<ObjectType, ColumnMemberType>), null,
Expand All @@ -3569,7 +3579,7 @@ internal class FastColumnSetter
return (o, stmt, i) => {
var colType = SQLite3.ColumnType (stmt, i);
if (colType != SQLite3.ColType.Null)
setProperty.Invoke (o, getColumnValue.Invoke (stmt, i));
setProperty.Invoke ((ObjectType)o, getColumnValue.Invoke (stmt, i));
};
}
}
Expand Down
55 changes: 55 additions & 0 deletions tests/SQLite.Tests/DbCommandTest.cs
@@ -0,0 +1,55 @@
using System.Linq;
using System.Text;
using SQLite;
using System.Threading.Tasks;
using System.IO;

#if NETFX_CORE
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using SetUp = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestInitializeAttribute;
using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute;
using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute;
#else
using NUnit.Framework;
#endif

namespace SQLite.Tests
{
[TestFixture]
public class DbCommandTest
{
[Test]
public void QueryCommand()
{
var db = new SQLiteConnection (Path.GetTempFileName(), true);
db.CreateTable<Product>();
var b = new Product();
db.Insert(b);

var test = db.CreateCommand("select * from Product")
.ExecuteDeferredQuery<Product>(new TableMapping(typeof(Product))).ToList();


Assert.AreEqual (test.Count, 1);
}

#region Issue #1048

[Test]
public void QueryCommandCastToObject()
{
var db = new SQLiteConnection (Path.GetTempFileName(), true);
db.CreateTable<Product>();
var b = new Product();
db.Insert(b);

var test = db.CreateCommand("select * from Product")
.ExecuteDeferredQuery<object>(new TableMapping(typeof(Product))).ToList();


Assert.AreEqual (test.Count, 1);
}

#endregion
}
}

0 comments on commit 56c06a4

Please sign in to comment.