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()
}
}
[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]
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,
/// </code>
/// </example>
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);
/// <summary>
......@@ -1114,6 +1126,14 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
/// or <see cref="T:DataSet"/>.
/// </remarks>
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);
/// <summary>
......@@ -1128,9 +1148,18 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
/// or <see cref="T:DataSet"/>.
/// </remarks>
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);
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);
......
......@@ -2091,11 +2091,11 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
else
{
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++)
{
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();
}
......@@ -2379,19 +2379,21 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
var il = dm.GetILGenerator();
bool isStruct = type.IsValueType;
bool haveInt32Arg1 = false;
var sizeLocal = (LocalBuilder)null;
il.Emit(OpCodes.Ldarg_1); // stack is now [untyped-param]
LocalBuilder typedParameterLocal;
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]
}
else
{
il.DeclareLocal(type); // 0
typedParameterLocal = il.DeclareLocal(type);
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.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)
{
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(OpCodes.Ldarg_0); // stack is now [parameters] [custom] [command]
il.Emit(OpCodes.Ldstr, prop.Name); // stack is now [parameters] [custom] [command] [name]
......@@ -2485,7 +2487,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
// this actually represents special handling for list types;
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.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]
if (prop.PropertyType.IsValueType)
{
......@@ -2519,7 +2521,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
if (dbType == DbType.Object && prop.PropertyType == typeof(object)) // includes dynamic
{
// 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(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)
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.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]
bool checkForNull;
if (prop.PropertyType.IsValueType)
......@@ -2588,10 +2590,9 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
}
if (checkForNull)
{
if ((dbType == DbType.String || dbType == DbType.AnsiString) && !haveInt32Arg1)
if ((dbType == DbType.String || dbType == DbType.AnsiString) && sizeLocal == null)
{
il.DeclareLocal(typeof(int));
haveInt32Arg1 = true;
sizeLocal = il.DeclareLocal(typeof(int));
}
// relative stack: [boxed value]
il.Emit(OpCodes.Dup);// relative stack: [boxed value] [boxed value]
......@@ -2604,7 +2605,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
if (dbType == DbType.String || dbType == DbType.AnsiString)
{
EmitInt32(il, 0);
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Stloc, sizeLocal);
}
if (allDone != null) il.Emit(OpCodes.Br_S, allDone.Value);
il.MarkLabel(notNull);
......@@ -2621,7 +2622,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
il.MarkLabel(isLong);
EmitInt32(il, -1); // [string] [-1]
il.MarkLabel(lenDone);
il.Emit(OpCodes.Stloc_1); // [string]
il.Emit(OpCodes.Stloc, sizeLocal); // [string]
}
if (prop.PropertyType.FullName == LinqBinary)
{
......@@ -2646,11 +2647,11 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
{
var endOfSize = il.DefineLabel();
// 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.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.MarkLabel(endOfSize);
......@@ -2703,7 +2704,7 @@ internal static IList<LiteralToken> GetLiteralTokens(string sql)
if (prop != null)
{
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
Type propType = prop.PropertyType;
var typeCode = Type.GetTypeCode(propType);
......@@ -3034,9 +3035,9 @@ private static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, Lo
}
if (initAndLoad)
{
il.Emit(OpCodes.Ldloca, (short)found.LocalIndex);
il.Emit(OpCodes.Ldloca, found);
il.Emit(OpCodes.Initobj, type);
il.Emit(OpCodes.Ldloca, (short)found.LocalIndex);
il.Emit(OpCodes.Ldloca, found);
il.Emit(OpCodes.Ldobj, type);
}
return found;
......@@ -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++)
{
......@@ -3134,7 +3135,7 @@ private static void GenerateValueTupleDeserializer(Type valueTupleType, IDataRea
LoadReaderValueOrBranchToDBNullLabel(
il,
startBound + i,
ref enumDeclareLocal,
ref stringEnumLocal,
valueCopyLocal: null,
reader.GetFieldType(startBound + i),
targetType,
......@@ -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)
{
var currentIndexDiagnosticLocal = il.DeclareLocal(typeof(int));
il.DeclareLocal(type);
var returnValueLocal = il.DeclareLocal(type);
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();
......@@ -3182,7 +3183,7 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
Dictionary<Type, LocalBuilder> structLocals = null;
if (type.IsValueType)
{
il.Emit(OpCodes.Ldloca_S, (byte)1);
il.Emit(OpCodes.Ldloca, returnValueLocal);
il.Emit(OpCodes.Initobj, type);
}
else
......@@ -3210,12 +3211,11 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
}
il.Emit(OpCodes.Newobj, explicitConstr);
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Stloc, returnValueLocal);
supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type);
if (supportInitialize)
{
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc, returnValueLocal);
il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.BeginInit)), null);
}
}
......@@ -3231,11 +3231,11 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
if (ctor.GetParameters().Length == 0)
{
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Stloc, returnValueLocal);
supportInitialize = typeof(ISupportInitialize).IsAssignableFrom(type);
if (supportInitialize)
{
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc, returnValueLocal);
il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.BeginInit)), null);
}
}
......@@ -3249,11 +3249,11 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
il.BeginExceptionBlock();
if (type.IsValueType)
{
il.Emit(OpCodes.Ldloca_S, (byte)1);// [target]
il.Emit(OpCodes.Ldloca, returnValueLocal); // [target]
}
else if (specializedConstructor == null)
{
il.Emit(OpCodes.Ldloc_1);// [target]
il.Emit(OpCodes.Ldloc, returnValueLocal); // [target]
}
var members = (specializedConstructor != null
......@@ -3264,7 +3264,8 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
bool first = true;
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;
foreach (var item in members)
{
......@@ -3279,7 +3280,7 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
EmitInt32(il, index);
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)
{
......@@ -3336,7 +3337,7 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
{
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldnull); // stack is now [null]
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Stloc, returnValueLocal);
il.Emit(OpCodes.Br, allDone);
}
......@@ -3355,10 +3356,10 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
{
il.Emit(OpCodes.Newobj, specializedConstructor);
}
il.Emit(OpCodes.Stloc_1); // stack is empty
il.Emit(OpCodes.Stloc, returnValueLocal); // stack is empty
if (supportInitialize)
{
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc, returnValueLocal);
il.EmitCall(OpCodes.Callvirt, typeof(ISupportInitialize).GetMethod(nameof(ISupportInitialize.EndInit)), null);
}
}
......@@ -3366,11 +3367,10 @@ private static void GenerateDeserializerFromMap(Type type, IDataReader reader, i
il.BeginCatchBlock(typeof(Exception)); // stack is Exception
il.Emit(OpCodes.Ldloc, currentIndexDiagnosticLocal); // stack is Exception, index
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.EndExceptionBlock();
il.Emit(OpCodes.Ldloc_1); // stack is [rval]
if (type.IsValueType)
{
il.Emit(OpCodes.Box, type);
......@@ -3382,10 +3382,10 @@ private static void LoadDefaultValue(ILGenerator il, Type type)
{
if (type.IsValueType)
{
int localIndex = il.DeclareLocal(type).LocalIndex;
LoadLocalAddress(il, localIndex);
var local = il.DeclareLocal(type);
il.Emit(OpCodes.Ldloca, local);
il.Emit(OpCodes.Initobj, type);
LoadLocal(il, localIndex);
il.Emit(OpCodes.Ldloc, local);
}
else
{
......@@ -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();
il.Emit(OpCodes.Ldarg_0); // stack is now [...][reader]
......@@ -3403,7 +3403,7 @@ private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int ind
if (valueCopyLocal != null)
{
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?))
......@@ -3427,15 +3427,15 @@ private static void LoadReaderValueOrBranchToDBNullLabel(ILGenerator il, int ind
Type numericType = Enum.GetUnderlyingType(unboxType);
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]
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.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.EmitCall(OpCodes.Call, enumParse, null); // stack is now [...][enum-as-object]
il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [...][typed-value]
......@@ -3589,64 +3589,6 @@ private static MethodInfo ResolveOperator(MethodInfo[] methods, Type from, Type
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>
/// Throws a data exception, only used internally
/// </summary>
......
......@@ -93,6 +93,14 @@ public static IDataReader Create(IDbCommand cmd, IDataReader reader)
cmd.Dispose();
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
{
......
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