Commit 3c6cbebe authored by mgravell's avatar mgravell

Merge branch 'master' into lib-updates

# Conflicts:
#	Dapper/SqlMapper.cs
parents 0f3911b5 4eeb632f
...@@ -81,6 +81,22 @@ public void PseudoPositionalParameters_ReusedParameter() ...@@ -81,6 +81,22 @@ public void PseudoPositionalParameters_ReusedParameter()
} }
} }
[Fact]
public void Issue569_SO38527197_PseudoPositionalParameters_In_And_Other_Condition()
{
const string sql = @"select s1.value as id, s2.value as score
from string_split('1,2,3,4,5',',') s1, string_split('1,2,3,4,5',',') s2
where s1.value in ?ids? and s2.value = ?score?";
using (var connection = GetOleDbConnection())
{
const int score = 2;
int[] ids = { 1, 2, 5, 7 };
var list = connection.Query<int>(sql, new { ids, score }).AsList();
list.Sort();
Assert.Equal("1,2,5", string.Join(",", list));
}
}
[Fact] [Fact]
public void Issue569_SO38527197_PseudoPositionalParameters_In() public void Issue569_SO38527197_PseudoPositionalParameters_In()
{ {
......
using System;
using System.Threading.Tasks;
namespace Dapper
{
internal static class Extensions
{
/// <summary>
/// Creates a <see cref="Task{TResult}"/> with a less specific generic parameter that perfectly mirrors the
/// state of the specified <paramref name="task"/>.
/// </summary>
internal static Task<TTo> CastResult<TFrom, TTo>(this Task<TFrom> task)
where TFrom : TTo
{
if (task is null) throw new ArgumentNullException(nameof(task));
if (task.Status == TaskStatus.RanToCompletion)
return Task.FromResult((TTo)task.Result);
var source = new TaskCompletionSource<TTo>();
task.ContinueWith(OnTaskCompleted<TFrom, TTo>, state: source, TaskContinuationOptions.ExecuteSynchronously);
return source.Task;
}
private static void OnTaskCompleted<TFrom, TTo>(Task<TFrom> completedTask, object state)
where TFrom : TTo
{
var source = (TaskCompletionSource<TTo>)state;
switch (completedTask.Status)
{
case TaskStatus.RanToCompletion:
source.SetResult(completedTask.Result);
break;
case TaskStatus.Canceled:
source.SetCanceled();
break;
case TaskStatus.Faulted:
source.SetException(completedTask.Exception.InnerExceptions);
break;
}
}
}
}
...@@ -1101,6 +1101,18 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn, ...@@ -1101,6 +1101,18 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
/// </code> /// </code>
/// </example> /// </example>
public static Task<IDataReader> ExecuteReaderAsync(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) => public static Task<IDataReader> ExecuteReaderAsync(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) =>
ExecuteWrappedReaderImplAsync(cnn, new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered), CommandBehavior.Default).CastResult<DbDataReader, IDataReader>();
/// <summary>
/// Execute parameterized SQL and return a <see cref="DbDataReader"/>.
/// </summary>
/// <param name="cnn">The connection to execute on.</param>
/// <param name="sql">The SQL to execute.</param>
/// <param name="param">The parameters to use for this command.</param>
/// <param name="transaction">The transaction to use for this command.</param>
/// <param name="commandTimeout">Number of seconds before command execution timeout.</param>
/// <param name="commandType">Is it a stored proc or a batch?</param>
public static Task<DbDataReader> ExecuteReaderAsync(this DbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) =>
ExecuteWrappedReaderImplAsync(cnn, new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered), CommandBehavior.Default); ExecuteWrappedReaderImplAsync(cnn, new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered), CommandBehavior.Default);
/// <summary> /// <summary>
...@@ -1114,6 +1126,14 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn, ...@@ -1114,6 +1126,14 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
/// or <see cref="T:DataSet"/>. /// or <see cref="T:DataSet"/>.
/// </remarks> /// </remarks>
public static Task<IDataReader> ExecuteReaderAsync(this IDbConnection cnn, CommandDefinition command) => public static Task<IDataReader> ExecuteReaderAsync(this IDbConnection cnn, CommandDefinition command) =>
ExecuteWrappedReaderImplAsync(cnn, command, CommandBehavior.Default).CastResult<DbDataReader, IDataReader>();
/// <summary>
/// Execute parameterized SQL and return a <see cref="DbDataReader"/>.
/// </summary>
/// <param name="cnn">The connection to execute on.</param>
/// <param name="command">The command to execute.</param>
public static Task<DbDataReader> ExecuteReaderAsync(this DbConnection cnn, CommandDefinition command) =>
ExecuteWrappedReaderImplAsync(cnn, command, CommandBehavior.Default); ExecuteWrappedReaderImplAsync(cnn, command, CommandBehavior.Default);
/// <summary> /// <summary>
...@@ -1128,9 +1148,18 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn, ...@@ -1128,9 +1148,18 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
/// or <see cref="T:DataSet"/>. /// or <see cref="T:DataSet"/>.
/// </remarks> /// </remarks>
public static Task<IDataReader> ExecuteReaderAsync(this IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior) => public static Task<IDataReader> ExecuteReaderAsync(this IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior) =>
ExecuteWrappedReaderImplAsync(cnn, command, commandBehavior).CastResult<DbDataReader, IDataReader>();
/// <summary>
/// Execute parameterized SQL and return a <see cref="DbDataReader"/>.
/// </summary>
/// <param name="cnn">The connection to execute on.</param>
/// <param name="command">The command to execute.</param>
/// <param name="commandBehavior">The <see cref="CommandBehavior"/> flags for this reader.</param>
public static Task<DbDataReader> ExecuteReaderAsync(this DbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior) =>
ExecuteWrappedReaderImplAsync(cnn, command, commandBehavior); ExecuteWrappedReaderImplAsync(cnn, command, commandBehavior);
private static async Task<IDataReader> ExecuteWrappedReaderImplAsync(IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior) private static async Task<DbDataReader> ExecuteWrappedReaderImplAsync(IDbConnection cnn, CommandDefinition command, CommandBehavior commandBehavior)
{ {
Action<IDbCommand, object> paramReader = GetParameterReader(cnn, ref command); Action<IDbCommand, object> paramReader = GetParameterReader(cnn, ref command);
......
...@@ -2091,11 +2091,11 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj ...@@ -2091,11 +2091,11 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
else else
{ {
var sb = GetStringBuilder().Append('(').Append(variableName); var sb = GetStringBuilder().Append('(').Append(variableName);
if (!byPosition) sb.Append(1); if (!byPosition) sb.Append(1); else sb.Append(namePrefix).Append(1).Append(variableName);
for (int i = 2; i <= count; i++) for (int i = 2; i <= count; i++)
{ {
sb.Append(',').Append(variableName); sb.Append(',').Append(variableName);
if (!byPosition) sb.Append(i); if (!byPosition) sb.Append(i); else sb.Append(namePrefix).Append(i).Append(variableName);
} }
return sb.Append(')').__ToStringRecycle(); return sb.Append(')').__ToStringRecycle();
} }
...@@ -2379,19 +2379,21 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2379,19 +2379,21 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
var il = dm.GetILGenerator(); var il = dm.GetILGenerator();
bool isStruct = type.IsValueType; bool isStruct = type.IsValueType;
bool haveInt32Arg1 = false; var sizeLocal = (LocalBuilder)null;
il.Emit(OpCodes.Ldarg_1); // stack is now [untyped-param] il.Emit(OpCodes.Ldarg_1); // stack is now [untyped-param]
LocalBuilder typedParameterLocal;
if (isStruct) if (isStruct)
{ {
il.DeclareLocal(type.MakeByRefType()); // note: ref-local typedParameterLocal = il.DeclareLocal(type.MakeByRefType()); // note: ref-local
il.Emit(OpCodes.Unbox, type); // stack is now [typed-param] il.Emit(OpCodes.Unbox, type); // stack is now [typed-param]
} }
else else
{ {
il.DeclareLocal(type); // 0 typedParameterLocal = il.DeclareLocal(type);
il.Emit(OpCodes.Castclass, type); // stack is now [typed-param] il.Emit(OpCodes.Castclass, type); // stack is now [typed-param]
} }
il.Emit(OpCodes.Stloc_0);// stack is now empty il.Emit(OpCodes.Stloc, typedParameterLocal); // stack is now empty
il.Emit(OpCodes.Ldarg_0); // stack is now [command] il.Emit(OpCodes.Ldarg_0); // stack is now [command]
il.EmitCall(OpCodes.Callvirt, typeof(IDbCommand).GetProperty(nameof(IDbCommand.Parameters)).GetGetMethod(), null); // stack is now [parameters] il.EmitCall(OpCodes.Callvirt, typeof(IDbCommand).GetProperty(nameof(IDbCommand.Parameters)).GetGetMethod(), null); // stack is now [parameters]
...@@ -2470,7 +2472,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2470,7 +2472,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
{ {
if (typeof(ICustomQueryParameter).IsAssignableFrom(prop.PropertyType)) if (typeof(ICustomQueryParameter).IsAssignableFrom(prop.PropertyType))
{ {
il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [typed-param] il.Emit(OpCodes.Ldloc, typedParameterLocal); // stack is now [parameters] [typed-param]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [custom] il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [custom]
il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [custom] [command] il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [custom] [command]
il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [custom] [command] [name] il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [custom] [command] [name]
...@@ -2485,7 +2487,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2485,7 +2487,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
// this actually represents special handling for list types; // this actually represents special handling for list types;
il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [command] il.Emit(OpCodes.Ldarg_0); // stack is now [parameters] [command]
il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [command] [name] il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [command] [name]
il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [command] [name] [typed-param] il.Emit(OpCodes.Ldloc, typedParameterLocal); // stack is now [parameters] [command] [name] [typed-param]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [command] [name] [typed-value] il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [command] [name] [typed-value]
if (prop.PropertyType.IsValueType) if (prop.PropertyType.IsValueType)
{ {
...@@ -2519,7 +2521,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2519,7 +2521,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
if (dbType == DbType.Object && prop.PropertyType == typeof(object)) // includes dynamic if (dbType == DbType.Object && prop.PropertyType == typeof(object)) // includes dynamic
{ {
// look it up from the param value // look it up from the param value
il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [[parameters]] [parameter] [parameter] [typed-param] il.Emit(OpCodes.Ldloc, typedParameterLocal); // stack is now [parameters] [[parameters]] [parameter] [parameter] [typed-param]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [object-value] il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [object-value]
il.Emit(OpCodes.Call, typeof(SqlMapper).GetMethod(nameof(SqlMapper.GetDbType), BindingFlags.Static | BindingFlags.Public)); // stack is now [parameters] [[parameters]] [parameter] [parameter] [db-type] il.Emit(OpCodes.Call, typeof(SqlMapper).GetMethod(nameof(SqlMapper.GetDbType), BindingFlags.Static | BindingFlags.Public)); // stack is now [parameters] [[parameters]] [parameter] [parameter] [db-type]
} }
...@@ -2536,7 +2538,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2536,7 +2538,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
il.EmitCall(OpCodes.Callvirt, typeof(IDataParameter).GetProperty(nameof(IDataParameter.Direction)).GetSetMethod(), null);// stack is now [parameters] [[parameters]] [parameter] il.EmitCall(OpCodes.Callvirt, typeof(IDataParameter).GetProperty(nameof(IDataParameter.Direction)).GetSetMethod(), null);// stack is now [parameters] [[parameters]] [parameter]
il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter] il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter]
il.Emit(OpCodes.Ldloc_0); // stack is now [parameters] [[parameters]] [parameter] [parameter] [typed-param] il.Emit(OpCodes.Ldloc, typedParameterLocal); // stack is now [parameters] [[parameters]] [parameter] [parameter] [typed-param]
il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [typed-value] il.Emit(callOpCode, prop.GetGetMethod()); // stack is [parameters] [[parameters]] [parameter] [parameter] [typed-value]
bool checkForNull; bool checkForNull;
if (prop.PropertyType.IsValueType) if (prop.PropertyType.IsValueType)
...@@ -2588,10 +2590,9 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2588,10 +2590,9 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
} }
if (checkForNull) if (checkForNull)
{ {
if ((dbType == DbType.String || dbType == DbType.AnsiString) && !haveInt32Arg1) if ((dbType == DbType.String || dbType == DbType.AnsiString) && sizeLocal == null)
{ {
il.DeclareLocal(typeof(int)); sizeLocal = il.DeclareLocal(typeof(int));
haveInt32Arg1 = true;
} }
// relative stack: [boxed value] // relative stack: [boxed value]
il.Emit(OpCodes.Dup);// relative stack: [boxed value] [boxed value] il.Emit(OpCodes.Dup);// relative stack: [boxed value] [boxed value]
...@@ -2604,7 +2605,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2604,7 +2605,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
if (dbType == DbType.String || dbType == DbType.AnsiString) if (dbType == DbType.String || dbType == DbType.AnsiString)
{ {
EmitInt32(il, 0); EmitInt32(il, 0);
il.Emit(OpCodes.Stloc_1); il.Emit(OpCodes.Stloc, sizeLocal);
} }
if (allDone != null) il.Emit(OpCodes.Br_S, allDone.Value); if (allDone != null) il.Emit(OpCodes.Br_S, allDone.Value);
il.MarkLabel(notNull); il.MarkLabel(notNull);
...@@ -2621,7 +2622,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2621,7 +2622,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
il.MarkLabel(isLong); il.MarkLabel(isLong);
EmitInt32(il, -1); // [string] [-1] EmitInt32(il, -1); // [string] [-1]
il.MarkLabel(lenDone); il.MarkLabel(lenDone);
il.Emit(OpCodes.Stloc_1); // [string] il.Emit(OpCodes.Stloc, sizeLocal); // [string]
} }
if (prop.PropertyType.FullName == LinqBinary) if (prop.PropertyType.FullName == LinqBinary)
{ {
...@@ -2646,11 +2647,11 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2646,11 +2647,11 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
{ {
var endOfSize = il.DefineLabel(); var endOfSize = il.DefineLabel();
// don't set if 0 // don't set if 0
il.Emit(OpCodes.Ldloc_1); // [parameters] [[parameters]] [parameter] [size] il.Emit(OpCodes.Ldloc, sizeLocal); // [parameters] [[parameters]] [parameter] [size]
il.Emit(OpCodes.Brfalse_S, endOfSize); // [parameters] [[parameters]] [parameter] il.Emit(OpCodes.Brfalse_S, endOfSize); // [parameters] [[parameters]] [parameter]
il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter] il.Emit(OpCodes.Dup);// stack is now [parameters] [[parameters]] [parameter] [parameter]
il.Emit(OpCodes.Ldloc_1); // stack is now [parameters] [[parameters]] [parameter] [parameter] [size] il.Emit(OpCodes.Ldloc, sizeLocal); // stack is now [parameters] [[parameters]] [parameter] [parameter] [size]
il.EmitCall(OpCodes.Callvirt, typeof(IDbDataParameter).GetProperty(nameof(IDbDataParameter.Size)).GetSetMethod(), null); // stack is now [parameters] [[parameters]] [parameter] il.EmitCall(OpCodes.Callvirt, typeof(IDbDataParameter).GetProperty(nameof(IDbDataParameter.Size)).GetSetMethod(), null); // stack is now [parameters] [[parameters]] [parameter]
il.MarkLabel(endOfSize); il.MarkLabel(endOfSize);
...@@ -2703,7 +2704,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql) ...@@ -2703,7 +2704,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
if (prop != null) if (prop != null)
{ {
il.Emit(OpCodes.Ldstr, literal.Token); il.Emit(OpCodes.Ldstr, literal.Token);
il.Emit(OpCodes.Ldloc_0); // command, sql, typed parameter il.Emit(OpCodes.Ldloc, typedParameterLocal); // command, sql, typed parameter
il.EmitCall(callOpCode, prop.GetGetMethod(), null); // command, sql, typed value il.EmitCall(callOpCode, prop.GetGetMethod(), null); // command, sql, typed value
Type propType = prop.PropertyType; Type propType = prop.PropertyType;
var typeCode = Type.GetTypeCode(propType); var typeCode = Type.GetTypeCode(propType);
...@@ -3034,9 +3035,9 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo ...@@ -3034,9 +3035,9 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo
} }
if (initAndLoad) if (initAndLoad)
{ {
il.Emit(OpCodes.Ldloca, (short)found.LocalIndex); il.Emit(OpCodes.Ldloca, found);
il.Emit(OpCodes.Initobj, type); il.Emit(OpCodes.Initobj, type);
il.Emit(OpCodes.Ldloca, (short)found.LocalIndex); il.Emit(OpCodes.Ldloca, found);
il.Emit(OpCodes.Ldobj, type); il.Emit(OpCodes.Ldobj, type);
} }
return found; return found;
...@@ -3123,7 +3124,7 @@ private static void GenerateValueTupleDeserializer(Type valueTupleType, IDataRea ...@@ -3123,7 +3124,7 @@ private static void GenerateValueTupleDeserializer(Type valueTupleType, IDataRea
} }
} }
var enumDeclareLocal = -1; var stringEnumLocal = (LocalBuilder)null;
for (var i = 0; i < languageTupleElementTypes.Count; i++) for (var i = 0; i < languageTupleElementTypes.Count; i++)
{ {
...@@ -3134,7 +3135,7 @@ private static void GenerateValueTupleDeserializer(Type valueTupleType, IDataRea ...@@ -3134,7 +3135,7 @@ private static void GenerateValueTupleDeserializer(Type valueTupleType, IDataRea
LoadReaderValueOrBranchToDBNullLabel( LoadReaderValueOrBranchToDBNullLabel(
il, il,
startBound + i, startBound + i,
ref enumDeclareLocal, ref stringEnumLocal,
valueCopyLocal: null, valueCopyLocal: null,
reader.GetFieldType(startBound + i), reader.GetFieldType(startBound + i),
targetType, targetType,
...@@ -3167,9 +3168,9 @@ private static void GenerateValueTupleDeserializer(Type valueTupleType, IDataRea ...@@ -3167,9 +3168,9 @@ private static void GenerateValueTupleDeserializer(Type valueTupleType, IDataRea
private static void GenerateDeserializerFromMap(Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing, ILGenerator il) private static void GenerateDeserializerFromMap(Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing, ILGenerator il)
{ {
var currentIndexDiagnosticLocal = il.DeclareLocal(typeof(int)); var currentIndexDiagnosticLocal = il.DeclareLocal(typeof(int));
il.DeclareLocal(type); var returnValueLocal = il.DeclareLocal(type);
il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc_0); il.Emit(OpCodes.Stloc, currentIndexDiagnosticLocal);
var names = Enumerable.Range(startBound, length).Select(i => reader.GetName(i)).ToArray(); var names = Enumerable.Range(startBound, length).Select(i => reader.GetName(i)).ToArray();
...@@ -3182,7 +3183,7 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i ...@@ -3182,7 +3183,7 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
Dictionary<Type, LocalBuilder> structLocals = null; Dictionary<Type, LocalBuilder> structLocals = null;
if (type.IsValueType) if (type.IsValueType)
{ {
il.Emit(OpCodes.Ldloca_S, (byte)1); il.Emit(OpCodes.Ldloca, returnValueLocal);
il.Emit(OpCodes.Initobj, type); il.Emit(OpCodes.Initobj, type);
} }
else else
...@@ -3210,12 +3211,11 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i ...@@ -3210,12 +3211,11 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
} }
il.Emit(OpCodes.Newobj, explicitConstr); il.Emit(OpCodes.Newobj, explicitConstr);
il.Emit(OpCodes.Stloc_1); il.Emit(OpCodes.Stloc, returnValueLocal);
supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type); supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type);
if (supportInitialize) if (supportInitialize)
{ {
il.Emit(OpCodes.Ldloc_1); il.Emit(OpCodes.Ldloc, returnValueLocal);
il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.BeginInit)), null); il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.BeginInit)), null);
} }
} }
...@@ -3231,11 +3231,11 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i ...@@ -3231,11 +3231,11 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
if (ctor.GetParameters().Length == 0) if (ctor.GetParameters().Length == 0)
{ {
il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_1); il.Emit(OpCodes.Stloc, returnValueLocal);
supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type); supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type);
if (supportInitialize) if (supportInitialize)
{ {
il.Emit(OpCodes.Ldloc_1); il.Emit(OpCodes.Ldloc, returnValueLocal);
il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.BeginInit)), null); il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.BeginInit)), null);
} }
} }
...@@ -3249,11 +3249,11 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i ...@@ -3249,11 +3249,11 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
il.BeginExceptionBlock(); il.BeginExceptionBlock();
if (type.IsValueType) if (type.IsValueType)
{ {
il.Emit(OpCodes.Ldloca_S, (byte)1);// [target] il.Emit(OpCodes.Ldloca, returnValueLocal); // [target]
} }
else if (specializedConstructor == null) else if (specializedConstructor == null)
{ {
il.Emit(OpCodes.Ldloc_1);// [target] il.Emit(OpCodes.Ldloc, returnValueLocal); // [target]
} }
var members = (specializedConstructor != null var members = (specializedConstructor != null
...@@ -3264,7 +3264,8 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i ...@@ -3264,7 +3264,8 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
bool first = true; bool first = true;
var allDone = il.DefineLabel(); var allDone = il.DefineLabel();
int enumDeclareLocal = -1, valueCopyLocal = il.DeclareLocal(typeof(object)).LocalIndex; var stringEnumLocal = (LocalBuilder)null;
var valueCopyDiagnosticLocal = il.DeclareLocal(typeof(object));
bool applyNullSetting = Settings.ApplyNullValues; bool applyNullSetting = Settings.ApplyNullValues;
foreach (var item in members) foreach (var item in members)
{ {
...@@ -3279,7 +3280,7 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i ...@@ -3279,7 +3280,7 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
EmitInt32(il, index); EmitInt32(il, index);
il.Emit(OpCodes.Stloc, currentIndexDiagnosticLocal); il.Emit(OpCodes.Stloc, currentIndexDiagnosticLocal);
LoadReaderValueOrBranchToDBNullLabel(il, index, ref enumDeclareLocal, valueCopyLocal, reader.GetFieldType(index), memberType, out var isDbNullLabel); LoadReaderValueOrBranchToDBNullLabel(il, index, ref stringEnumLocal, valueCopyDiagnosticLocal, reader.GetFieldType(index), memberType, out var isDbNullLabel);
if (specializedConstructor == null) if (specializedConstructor == null)
{ {
...@@ -3336,7 +3337,7 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i ...@@ -3336,7 +3337,7 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
{ {
il.Emit(OpCodes.Pop); il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldnull); // stack is now [null] il.Emit(OpCodes.Ldnull); // stack is now [null]
il.Emit(OpCodes.Stloc_1); il.Emit(OpCodes.Stloc, returnValueLocal);
il.Emit(OpCodes.Br, allDone); il.Emit(OpCodes.Br, allDone);
} }
...@@ -3355,10 +3356,10 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i ...@@ -3355,10 +3356,10 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
{ {
il.Emit(OpCodes.Newobj, specializedConstructor); il.Emit(OpCodes.Newobj, specializedConstructor);
} }
il.Emit(OpCodes.Stloc_1); // stack is empty il.Emit(OpCodes.Stloc, returnValueLocal); // stack is empty
if (supportInitialize) if (supportInitialize)
{ {
il.Emit(OpCodes.Ldloc_1); il.Emit(OpCodes.Ldloc, returnValueLocal);
il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.EndInit)), null); il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.EndInit)), null);
} }
} }
...@@ -3366,11 +3367,10 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i ...@@ -3366,11 +3367,10 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
il.BeginCatchBlock(typeof(Exception)); // stack is Exception il.BeginCatchBlock(typeof(Exception)); // stack is Exception
il.Emit(OpCodes.Ldloc, currentIndexDiagnosticLocal); // stack is Exception, index il.Emit(OpCodes.Ldloc, currentIndexDiagnosticLocal); // stack is Exception, index
il.Emit(OpCodes.Ldarg_0); // stack is Exception, index, reader il.Emit(OpCodes.Ldarg_0); // stack is Exception, index, reader
LoadLocal(il, valueCopyLocal); // stack is Exception, index, reader, value il.Emit(OpCodes.Ldloc, valueCopyDiagnosticLocal); // stack is Exception, index, reader, value
il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod(nameof(SqlMapper.ThrowDataException)), null); il.EmitCall(OpCodes.Call, typeof(SqlMapper).GetMethod(nameof(SqlMapper.ThrowDataException)), null);
il.EndExceptionBlock(); il.EndExceptionBlock();
il.Emit(OpCodes.Ldloc_1); // stack is [rval]
if (type.IsValueType) if (type.IsValueType)
{ {
il.Emit(OpCodes.Box, type); il.Emit(OpCodes.Box, type);
...@@ -3382,10 +3382,10 @@ private static void LoadDefaultValue(ILGenerator il, Type type) ...@@ -3382,10 +3382,10 @@ private static void LoadDefaultValue(ILGenerator il, Type type)
{ {
if (type.IsValueType) if (type.IsValueType)
{ {
int localIndex = il.DeclareLocal(type).LocalIndex; var local = il.DeclareLocal(type);
LoadLocalAddress(il, localIndex); il.Emit(OpCodes.Ldloca, local);
il.Emit(OpCodes.Initobj, type); il.Emit(OpCodes.Initobj, type);
LoadLocal(il, localIndex); il.Emit(OpCodes.Ldloc, local);
} }
else else
{ {
...@@ -3393,7 +3393,7 @@ private static void LoadDefaultValue(ILGenerator il, Type type) ...@@ -3393,7 +3393,7 @@ private static void LoadDefaultValue(ILGenerator il, Type type)
} }
} }
private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int index, ref int enumDeclareLocal, int? valueCopyLocal, Type colType, Type memberType, out Label isDbNullLabel) private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int index, ref LocalBuilder stringEnumLocal, LocalBuilder valueCopyLocal, Type colType, Type memberType, out Label isDbNullLabel)
{ {
isDbNullLabel = il.DefineLabel(); isDbNullLabel = il.DefineLabel();
il.Emit(OpCodes.Ldarg_0); // stack is now [...][reader] il.Emit(OpCodes.Ldarg_0); // stack is now [...][reader]
...@@ -3403,7 +3403,7 @@ private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int ind ...@@ -3403,7 +3403,7 @@ private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int ind
if (valueCopyLocal != null) if (valueCopyLocal != null)
{ {
il.Emit(OpCodes.Dup); // stack is now [...][value-as-object][value-as-object] il.Emit(OpCodes.Dup); // stack is now [...][value-as-object][value-as-object]
StoreLocal(il, valueCopyLocal.Value); // stack is now [...][value-as-object] il.Emit(OpCodes.Stloc, valueCopyLocal); // stack is now [...][value-as-object]
} }
if (memberType == typeof(char) || memberType == typeof(char?)) if (memberType == typeof(char) || memberType == typeof(char?))
...@@ -3427,15 +3427,15 @@ private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int ind ...@@ -3427,15 +3427,15 @@ private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int ind
Type numericType = Enum.GetUnderlyingType(unboxType); Type numericType = Enum.GetUnderlyingType(unboxType);
if (colType == typeof(string)) if (colType == typeof(string))
{ {
if (enumDeclareLocal == -1) if (stringEnumLocal == null)
{ {
enumDeclareLocal = il.DeclareLocal(typeof(string)).LocalIndex; stringEnumLocal = il.DeclareLocal(typeof(string));
} }
il.Emit(OpCodes.Castclass, typeof(string)); // stack is now [...][string] il.Emit(OpCodes.Castclass, typeof(string)); // stack is now [...][string]
StoreLocal(il, enumDeclareLocal); // stack is now [...] il.Emit(OpCodes.Stloc, stringEnumLocal); // stack is now [...]
il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [...][enum-type-token] il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [...][enum-type-token]
il.EmitCall(OpCodes.Call, typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)), null);// stack is now [...][enum-type] il.EmitCall(OpCodes.Call, typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)), null);// stack is now [...][enum-type]
LoadLocal(il, enumDeclareLocal); // stack is now [...][enum-type][string] il.Emit(OpCodes.Ldloc, stringEnumLocal); // stack is now [...][enum-type][string]
il.Emit(OpCodes.Ldc_I4_1); // stack is now [...][enum-type][string][true] il.Emit(OpCodes.Ldc_I4_1); // stack is now [...][enum-type][string][true]
il.EmitCall(OpCodes.Call, enumParse, null); // stack is now [...][enum-as-object] il.EmitCall(OpCodes.Call, enumParse, null); // stack is now [...][enum-as-object]
il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [...][typed-value] il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [...][typed-value]
...@@ -3589,64 +3589,6 @@ private static MethodInfo ResolveOperator(MethodInfo[] methods, Type from, Type ...@@ -3589,64 +3589,6 @@ private static MethodInfo ResolveOperator(MethodInfo[] methods, Type from, Type
return null; return null;
} }
private static void LoadLocal(ILGenerator il, int index)
{
if (index < 0 || index >= short.MaxValue) throw new ArgumentNullException(nameof(index));
switch (index)
{
case 0: il.Emit(OpCodes.Ldloc_0); break;
case 1: il.Emit(OpCodes.Ldloc_1); break;
case 2: il.Emit(OpCodes.Ldloc_2); break;
case 3: il.Emit(OpCodes.Ldloc_3); break;
default:
if (index <= 255)
{
il.Emit(OpCodes.Ldloc_S, (byte)index);
}
else
{
il.Emit(OpCodes.Ldloc, (short)index);
}
break;
}
}
private static void StoreLocal(ILGenerator il, int index)
{
if (index < 0 || index >= short.MaxValue) throw new ArgumentNullException(nameof(index));
switch (index)
{
case 0: il.Emit(OpCodes.Stloc_0); break;
case 1: il.Emit(OpCodes.Stloc_1); break;
case 2: il.Emit(OpCodes.Stloc_2); break;
case 3: il.Emit(OpCodes.Stloc_3); break;
default:
if (index <= 255)
{
il.Emit(OpCodes.Stloc_S, (byte)index);
}
else
{
il.Emit(OpCodes.Stloc, (short)index);
}
break;
}
}
private static void LoadLocalAddress(ILGenerator il, int index)
{
if (index < 0 || index >= short.MaxValue) throw new ArgumentNullException(nameof(index));
if (index <= 255)
{
il.Emit(OpCodes.Ldloca_S, (byte)index);
}
else
{
il.Emit(OpCodes.Ldloca, (short)index);
}
}
/// <summary> /// <summary>
/// Throws a data exception, only used internally /// Throws a data exception, only used internally
/// </summary> /// </summary>
......
...@@ -93,6 +93,14 @@ public static IDataReader Create(IDbCommand cmd, IDataReader reader) ...@@ -93,6 +93,14 @@ public static IDataReader Create(IDbCommand cmd, IDataReader reader)
cmd.Dispose(); cmd.Dispose();
return null; // GIGO return null; // GIGO
} }
public static DbDataReader Create(IDbCommand cmd, DbDataReader reader)
{
if (cmd == null) return reader; // no need to wrap if no command
if (reader != null) return new DbWrappedReader(cmd, reader);
cmd.Dispose();
return null; // GIGO
}
} }
internal sealed class DbWrappedReader : DbDataReader, IWrappedDataReader internal sealed class DbWrappedReader : DbDataReader, IWrappedDataReader
{ {
......
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