Commit a18dc63c authored by Sébastien Ros's avatar Sébastien Ros Committed by Marc Gravell

Use InvariantCulture in FlexibleConvert (#1363)

In Sqlite, DateTime is stored as String, and custom serializers ultimately use Convert.ChangeType to do the conversion. The generated code however doesn't set the Invariant culture, and the conversion can fail if the current culture doesn't match the standard DateTime serialization format from Sqlite.
parent 247e498f
......@@ -2,6 +2,7 @@
using System;
using System.Data.Common;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
......@@ -123,6 +124,46 @@ private void Isse467_SqliteParameterNaming(bool prefix)
var i = Convert.ToInt32(cmd.ExecuteScalar());
Assert.Equal(42, i);
}
}
}
[FactSqlite]
public void DateTimeIsParsedWithInvariantCulture()
{
connection.Execute("CREATE TABLE [PersonWithDob] ([Id] integer primary key autoincrement, [DoB] DATETIME not null )");
var localMorning = DateTime.Parse("2019-07-31 01:00:00");
var culture = Thread.CurrentThread.CurrentCulture;
try
{
connection.Execute("INSERT INTO [PersonWithDob] ([DoB]) VALUES (@DoB)", new PersonWithDob { DoB = localMorning });
// Before we read the column, use Farsi this is a way to ensure the
// InvariantCulture is used as otherwise it would fail because Farsi
// is not able to parse a DateTime that is formatted with Invariant
var farsi = System.Globalization.CultureInfo.GetCultureInfo("fa-IR");
Thread.CurrentThread.CurrentCulture = farsi;
Thread.CurrentThread.CurrentUICulture = farsi;
var person = connection.QueryFirst<PersonWithDob>("SELECT * FROM [PersonWithDob]");
Assert.Equal(localMorning, person.DoB);
}
finally
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
connection.Execute("DROP TABLE [PersonWithDob]");
}
}
private class PersonWithDob
{
public int Id { get; set; }
public DateTime DoB { get; set; }
}
}
}
......@@ -3563,7 +3563,8 @@ private static void FlexibleConvertBoxedFromHeadOfStack(ILGenerator il, Type fro
{
il.Emit(OpCodes.Ldtoken, via ?? to); // stack is now [target][target][value][member-type-token]
il.EmitCall(OpCodes.Call, typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)), null); // stack is now [target][target][value][member-type]
il.EmitCall(OpCodes.Call, typeof(Convert).GetMethod(nameof(Convert.ChangeType), new Type[] { typeof(object), typeof(Type) }), null); // stack is now [target][target][boxed-member-type-value]
il.EmitCall(OpCodes.Call, InvariantCulture, null); // stack is now [target][target][value][member-type][culture]
il.EmitCall(OpCodes.Call, typeof(Convert).GetMethod(nameof(Convert.ChangeType), new Type[] { typeof(object), typeof(Type), typeof(IFormatProvider) }), null); // stack is now [target][target][boxed-member-type-value]
il.Emit(OpCodes.Unbox_Any, to); // stack is now [target][target][typed-value]
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment