Commit df77f394 authored by Marc Gravell's avatar Marc Gravell

Add SQLITE to test builds; add tests for issues #466 and #467; fix #466 by...

Add SQLITE to test builds; add tests for issues #466 and #467; fix #466 by adding retry-with-fallback flags strategy
parent 8e9cc49f
{
"profiles": {
"test": {
"commandName": "test",
"sdkVersion": "dnx-clr-win-x86.1.0.0-rc1-update1"
}
}
}
\ No newline at end of file
...@@ -41,6 +41,12 @@ ...@@ -41,6 +41,12 @@
#if POSTGRESQL #if POSTGRESQL
using Npgsql; using Npgsql;
#endif #endif
#if SQLITE
using Microsoft.Data.Sqlite;
#endif
#if ASYNC
using System.Threading.Tasks;
#endif
#if COREFX #if COREFX
namespace System.ComponentModel { namespace System.ComponentModel {
...@@ -3532,5 +3538,106 @@ public class TPTable ...@@ -3532,5 +3538,106 @@ public class TPTable
public int Value { get; set; } public int Value { get; set; }
} }
#endif #endif
#if SQLITE
[FactSqlite]
public void Issue466_SqliteHatesOptimizations()
{
using (var connection = GetSqliteConnection())
{
SqlMapper.ResetTypeHandlers();
var row = connection.Query<HazNameId>("select 42 as Id").First();
row.Id.IsEqualTo(42);
row = connection.Query<HazNameId>("select 42 as Id").First();
row.Id.IsEqualTo(42);
SqlMapper.ResetTypeHandlers();
row = connection.QueryFirst<HazNameId>("select 42 as Id");
row.Id.IsEqualTo(42);
row = connection.QueryFirst<HazNameId>("select 42 as Id");
row.Id.IsEqualTo(42);
}
}
#if ASYNC
[FactSqlite]
public async Task Issue466_SqliteHatesOptimizations_Async()
{
using (var connection = GetSqliteConnection())
{
SqlMapper.ResetTypeHandlers();
var row = (await connection.QueryAsync<HazNameId>("select 42 as Id")).First();
row.Id.IsEqualTo(42);
row = (await connection.QueryAsync<HazNameId>("select 42 as Id")).First();
row.Id.IsEqualTo(42);
SqlMapper.ResetTypeHandlers();
row = await connection.QueryFirstAsync<HazNameId>("select 42 as Id");
row.Id.IsEqualTo(42);
row = await connection.QueryFirstAsync<HazNameId>("select 42 as Id");
row.Id.IsEqualTo(42);
}
}
[FactSqlite]
public void Isse467_SqliteLikesParametersWithPrefix()
{
Isse467_SqliteParameterNaming(true);
}
[FactSqlite]
public void Isse467_SqliteHatesParametersWithoutPrefix()
{ // see issue 375 / 467
#if DNX
try {
Isse467_SqliteParameterNaming(false);
throw new Exception("Expected failure");
} catch(InvalidOperationException ex)
{
ex.Message.IsEqualTo("Must add values for the following parameters: @foo");
}
#else
Isse467_SqliteParameterNaming(false);
#endif
}
private void Isse467_SqliteParameterNaming(bool prefix)
{
using (var connection = GetSqliteConnection())
{
var cmd = connection.CreateCommand();
cmd.CommandText = "select @foo";
cmd.Parameters.Add(prefix ? "@foo" : "foo", SqliteType.Integer).Value = 42;
var i = Convert.ToInt32(cmd.ExecuteScalar());
i.IsEqualTo(42);
}
}
#endif
public class FactSqliteAttribute : FactAttribute
{
public override string Skip
{
get { return unavailable ?? base.Skip; }
set { base.Skip = value; }
}
private static string unavailable;
static FactSqliteAttribute()
{
try
{
using (GetSqliteConnection()) { }
}
catch (Exception ex)
{
unavailable = $"Sqlite is unavailable: {ex.Message}";
}
}
}
protected static SqliteConnection GetSqliteConnection(bool open = true)
{
var connection = new SqliteConnection("Data Source=:memory:");
if (open) connection.Open();
return connection;
}
#endif
} }
} }
...@@ -36,8 +36,7 @@ ...@@ -36,8 +36,7 @@
"MASSIVE", "MASSIVE",
"ORMLITE", "ORMLITE",
"SOMA", "SOMA",
"SIMPLEDATA", "SIMPLEDATA"
"SQLITE"
] ]
}, },
"frameworkAssemblies": { "frameworkAssemblies": {
...@@ -81,8 +80,7 @@ ...@@ -81,8 +80,7 @@
"ORMLITE", "ORMLITE",
"SOMA", "SOMA",
"SIMPLEDATA", "SIMPLEDATA",
"XUNIT2", "XUNIT2"
"SQLITE"
] ]
}, },
"frameworkAssemblies": { "frameworkAssemblies": {
...@@ -117,10 +115,11 @@ ...@@ -117,10 +115,11 @@
}, },
"dotnet5.4": { "dotnet5.4": {
"compilationOptions": { "compilationOptions": {
"define": [ "ASYNC", "COREFX" ] "define": [ "ASYNC", "COREFX", "XUNIT2", "SQLITE" ]
}, },
"dependencies": { "dependencies": {
"Microsoft.CSharp": "4.0.1-*", "Microsoft.CSharp": "4.0.1-*",
"Microsoft.Data.Sqlite": "1.0.0-rc1-final",
"System.Collections": "4.0.11-*", "System.Collections": "4.0.11-*",
"System.Console": "4.0.0-*", "System.Console": "4.0.0-*",
"System.Data.SqlClient": "4.0.0-*", "System.Data.SqlClient": "4.0.0-*",
...@@ -147,7 +146,8 @@ ...@@ -147,7 +146,8 @@
"ORMLITE", "ORMLITE",
"SOMA", "SOMA",
"SIMPLEDATA", "SIMPLEDATA",
"XUNIT2" "XUNIT2",
"SQLITE"
] ]
}, },
"frameworkAssemblies": { "frameworkAssemblies": {
...@@ -163,6 +163,7 @@ ...@@ -163,6 +163,7 @@
}, },
"EntityFramework": "6.1.3", "EntityFramework": "6.1.3",
"FirebirdSql.Data.FirebirdClient": "4.10.0", "FirebirdSql.Data.FirebirdClient": "4.10.0",
"Microsoft.Data.Sqlite": "1.0.0-rc1-final",
"Microsoft.SqlServer.Compact": "4.0.8876.1", "Microsoft.SqlServer.Compact": "4.0.8876.1",
"Microsoft.SqlServer.Types": "11.0.2", "Microsoft.SqlServer.Types": "11.0.2",
"MySql.Data": "6.9.8", "MySql.Data": "6.9.8",
...@@ -183,9 +184,10 @@ ...@@ -183,9 +184,10 @@
}, },
"dnxcore50": { "dnxcore50": {
"compilationOptions": { "compilationOptions": {
"define": [ "COREFX", "ASYNC", "DNX" ] "define": [ "COREFX", "ASYNC", "DNX", "XUNIT2", "SQLITE" ]
}, },
"dependencies": { "dependencies": {
"Microsoft.Data.Sqlite": "1.0.0-rc1-final",
"System.Text.RegularExpressions": "4.0.11-*", "System.Text.RegularExpressions": "4.0.11-*",
"xunit": "2.2.0-beta1-build3239", "xunit": "2.2.0-beta1-build3239",
"xunit.runner.dnx": "2.1.0-rc1-build204" "xunit.runner.dnx": "2.1.0-rc1-build204"
......
...@@ -194,6 +194,16 @@ public static Task<object> QuerySingleOrDefaultAsync(this IDbConnection cnn, Typ ...@@ -194,6 +194,16 @@ public static Task<object> QuerySingleOrDefaultAsync(this IDbConnection cnn, Typ
return QueryRowAsync<object>(cnn, Row.SingleOrDefault, type, command); return QueryRowAsync<object>(cnn, Row.SingleOrDefault, type, command);
} }
private static Task<DbDataReader> ExecuteReaderWithFlagsFallbackAsync(DbCommand cmd, bool wasClosed, CommandBehavior behavior, CancellationToken cancellationToken)
{
var task = cmd.ExecuteReaderAsync(GetBehavior(wasClosed, behavior), cancellationToken);
if (task.Status == TaskStatus.Faulted && DisableCommandBehaviorOptimizations(behavior, task.Exception.InnerException))
{ // we can retry; this time it will have different flags
task = cmd.ExecuteReaderAsync(GetBehavior(wasClosed, behavior), cancellationToken);
}
return task;
}
private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command) private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command)
{ {
object param = command.Parameters; object param = command.Parameters;
...@@ -207,7 +217,7 @@ private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, ...@@ -207,7 +217,7 @@ private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn,
try try
{ {
if (wasClosed) await ((DbConnection)cnn).OpenAsync(cancel).ConfigureAwait(false); if (wasClosed) await ((DbConnection)cnn).OpenAsync(cancel).ConfigureAwait(false);
reader = await cmd.ExecuteReaderAsync(GetBehavior(wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult), cancel).ConfigureAwait(false); reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, cancel).ConfigureAwait(false);
var tuple = info.Deserializer; var tuple = info.Deserializer;
int hash = GetColumnHash(reader); int hash = GetColumnHash(reader);
...@@ -269,9 +279,9 @@ private static async Task<T> QueryRowAsync<T>(this IDbConnection cnn, Row row, T ...@@ -269,9 +279,9 @@ private static async Task<T> QueryRowAsync<T>(this IDbConnection cnn, Row row, T
try try
{ {
if (wasClosed) await ((DbConnection)cnn).OpenAsync(cancel).ConfigureAwait(false); if (wasClosed) await ((DbConnection)cnn).OpenAsync(cancel).ConfigureAwait(false);
reader = await cmd.ExecuteReaderAsync(GetBehavior(wasClosed, (row & Row.Single) != 0 reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, (row & Row.Single) != 0
? CommandBehavior.SequentialAccess | CommandBehavior.SingleResult // need to allow multiple rows, to check fail condition ? CommandBehavior.SequentialAccess | CommandBehavior.SingleResult // need to allow multiple rows, to check fail condition
: CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow), cancel).ConfigureAwait(false); : CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow, cancel).ConfigureAwait(false);
T result = default(T); T result = default(T);
if (await reader.ReadAsync(cancel).ConfigureAwait(false) && reader.FieldCount != 0) if (await reader.ReadAsync(cancel).ConfigureAwait(false) && reader.FieldCount != 0)
...@@ -644,7 +654,7 @@ private static async Task<int> ExecuteImplAsync(IDbConnection cnn, CommandDefini ...@@ -644,7 +654,7 @@ private static async Task<int> ExecuteImplAsync(IDbConnection cnn, CommandDefini
{ {
if (wasClosed) await ((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); if (wasClosed) await ((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false);
using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader))
using (var reader = await cmd.ExecuteReaderAsync(GetBehavior(wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult), command.CancellationToken).ConfigureAwait(false)) using (var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, command.CancellationToken).ConfigureAwait(false))
{ {
if (!command.Buffered) wasClosed = false; // handing back open reader; rely on command-behavior if (!command.Buffered) wasClosed = false; // handing back open reader; rely on command-behavior
var results = MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(null, CommandDefinition.ForCallback(command.Parameters), map, splitOn, reader, identity, true); var results = MultiMapImpl<TFirst, TSecond, TThird, TFourth, TFifth, TSixth, TSeventh, TReturn>(null, CommandDefinition.ForCallback(command.Parameters), map, splitOn, reader, identity, true);
...@@ -691,7 +701,7 @@ private static async Task<IEnumerable<TReturn>> MultiMapAsync<TReturn>(this IDbC ...@@ -691,7 +701,7 @@ private static async Task<IEnumerable<TReturn>> MultiMapAsync<TReturn>(this IDbC
try { try {
if (wasClosed) await ((DbConnection)cnn).OpenAsync().ConfigureAwait(false); if (wasClosed) await ((DbConnection)cnn).OpenAsync().ConfigureAwait(false);
using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader)) using (var cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader))
using (var reader = await cmd.ExecuteReaderAsync(GetBehavior(wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult), command.CancellationToken).ConfigureAwait(false)) { using (var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, command.CancellationToken).ConfigureAwait(false)) {
var results = MultiMapImpl<TReturn>(null, default(CommandDefinition), types, map, splitOn, reader, identity, true); var results = MultiMapImpl<TReturn>(null, default(CommandDefinition), types, map, splitOn, reader, identity, true);
return command.Buffered ? results.ToList() : results; return command.Buffered ? results.ToList() : results;
} }
...@@ -741,7 +751,7 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn, ...@@ -741,7 +751,7 @@ public static async Task<GridReader> QueryMultipleAsync(this IDbConnection cnn,
{ {
if (wasClosed) await ((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); if (wasClosed) await ((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false);
cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader); cmd = (DbCommand)command.SetupCommand(cnn, info.ParamReader);
reader = await cmd.ExecuteReaderAsync(GetBehavior(wasClosed, CommandBehavior.SequentialAccess), command.CancellationToken).ConfigureAwait(false); reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess, command.CancellationToken).ConfigureAwait(false);
var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters, command.AddToCache, command.CancellationToken); var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters, command.AddToCache, command.CancellationToken);
wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader
...@@ -818,7 +828,7 @@ private static async Task<IDataReader> ExecuteReaderImplAsync(IDbConnection cnn, ...@@ -818,7 +828,7 @@ private static async Task<IDataReader> ExecuteReaderImplAsync(IDbConnection cnn,
{ {
cmd = (DbCommand)command.SetupCommand(cnn, paramReader); cmd = (DbCommand)command.SetupCommand(cnn, paramReader);
if (wasClosed) await ((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false); if (wasClosed) await ((DbConnection)cnn).OpenAsync(command.CancellationToken).ConfigureAwait(false);
var reader = await cmd.ExecuteReaderAsync(GetBehavior(wasClosed, CommandBehavior.Default), command.CancellationToken).ConfigureAwait(false); var reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.Default, command.CancellationToken).ConfigureAwait(false);
wasClosed = false; wasClosed = false;
return reader; return reader;
} }
......
...@@ -237,6 +237,7 @@ private static void ResetTypeHandlers(bool clone) ...@@ -237,6 +237,7 @@ private static void ResetTypeHandlers(bool clone)
{ {
AddSqlDataRecordsTypeHandler(clone); AddSqlDataRecordsTypeHandler(clone);
} catch { } } catch { }
allowedCommandBehaviors = DefaultAllowedCommandBehaviors;
#endif #endif
} }
#if !COREFX #if !COREFX
...@@ -877,7 +878,7 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD ...@@ -877,7 +878,7 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD
{ {
if (wasClosed) cnn.Open(); if (wasClosed) cnn.Open();
cmd = command.SetupCommand(cnn, info.ParamReader); cmd = command.SetupCommand(cnn, info.ParamReader);
reader = cmd.ExecuteReader(GetBehavior(wasClosed, CommandBehavior.SequentialAccess)); reader = ExecuteReaderWithFlagsFallback(cmd, wasClosed, CommandBehavior.SequentialAccess);
var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters, command.AddToCache); var result = new GridReader(cmd, reader, identity, command.Parameters as DynamicParameters, command.AddToCache);
cmd = null; // now owned by result cmd = null; // now owned by result
...@@ -900,7 +901,22 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD ...@@ -900,7 +901,22 @@ private static GridReader QueryMultipleImpl(this IDbConnection cnn, ref CommandD
throw; throw;
} }
} }
private static IDataReader ExecuteReaderWithFlagsFallback(IDbCommand cmd, bool wasClosed, CommandBehavior behavior)
{
try
{
return cmd.ExecuteReader(GetBehavior(wasClosed, behavior));
}
catch (ArgumentException ex)
{ // thanks, Sqlite!
if (DisableCommandBehaviorOptimizations(behavior, ex))
{
// we can retry; this time it will have different flags
return cmd.ExecuteReader(GetBehavior(wasClosed, behavior));
}
throw;
}
}
private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType) private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType)
{ {
object param = command.Parameters; object param = command.Parameters;
...@@ -916,7 +932,7 @@ private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefini ...@@ -916,7 +932,7 @@ private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefini
cmd = command.SetupCommand(cnn, info.ParamReader); cmd = command.SetupCommand(cnn, info.ParamReader);
if (wasClosed) cnn.Open(); if (wasClosed) cnn.Open();
reader = cmd.ExecuteReader(GetBehavior(wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)); reader = ExecuteReaderWithFlagsFallback(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult);
wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader
// with the CloseConnection flag, so the reader will deal with the connection; we // with the CloseConnection flag, so the reader will deal with the connection; we
// still need something in the "finally" to ensure that broken SQL still results // still need something in the "finally" to ensure that broken SQL still results
...@@ -1005,9 +1021,9 @@ private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefiniti ...@@ -1005,9 +1021,9 @@ private static T QueryRowImpl<T>(IDbConnection cnn, Row row, ref CommandDefiniti
cmd = command.SetupCommand(cnn, info.ParamReader); cmd = command.SetupCommand(cnn, info.ParamReader);
if (wasClosed) cnn.Open(); if (wasClosed) cnn.Open();
reader = cmd.ExecuteReader(GetBehavior(wasClosed, (row & Row.Single) != 0 reader = ExecuteReaderWithFlagsFallback(cmd, wasClosed, (row & Row.Single) != 0
? CommandBehavior.SequentialAccess | CommandBehavior.SingleResult // need to allow multiple rows, to check fail condition ? CommandBehavior.SequentialAccess | CommandBehavior.SingleResult // need to allow multiple rows, to check fail condition
: CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)); : CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow);
wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader wasClosed = false; // *if* the connection was closed and we got this far, then we now have a reader
T result = default(T); T result = default(T);
...@@ -1262,7 +1278,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string ...@@ -1262,7 +1278,7 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string
{ {
ownedCommand = command.SetupCommand(cnn, cinfo.ParamReader); ownedCommand = command.SetupCommand(cnn, cinfo.ParamReader);
if (wasClosed) cnn.Open(); if (wasClosed) cnn.Open();
ownedReader = ownedCommand.ExecuteReader(GetBehavior(wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)); ownedReader = ExecuteReaderWithFlagsFallback(ownedCommand, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult);
reader = ownedReader; reader = ownedReader;
} }
DeserializerState deserializer = default(DeserializerState); DeserializerState deserializer = default(DeserializerState);
...@@ -1305,9 +1321,25 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string ...@@ -1305,9 +1321,25 @@ public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string
} }
} }
} }
const CommandBehavior DefaultAllowedCommandBehaviors = ~((CommandBehavior)0);
static CommandBehavior allowedCommandBehaviors = DefaultAllowedCommandBehaviors;
private static bool DisableCommandBehaviorOptimizations(CommandBehavior behavior, Exception ex)
{
if(allowedCommandBehaviors == DefaultAllowedCommandBehaviors
&& (behavior & (CommandBehavior.SingleResult | CommandBehavior.SingleRow)) != 0)
{
if (ex.Message.Contains(nameof(CommandBehavior.SingleResult))
|| ex.Message.Contains(nameof(CommandBehavior.SingleRow)))
{ // some providers just just allow these, so: try again without them and stop issuing them
allowedCommandBehaviors = ~(CommandBehavior.SingleResult | CommandBehavior.SingleRow);
return true;
}
}
return false;
}
private static CommandBehavior GetBehavior(bool close, CommandBehavior @default) private static CommandBehavior GetBehavior(bool close, CommandBehavior @default)
{ {
return close ? (@default | CommandBehavior.CloseConnection) : @default; return (close ? (@default | CommandBehavior.CloseConnection) : @default) & allowedCommandBehaviors;
} }
static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn, IDataReader reader, Identity identity, bool finalize) static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, CommandDefinition command, Type[] types, Func<object[], TReturn> map, string splitOn, IDataReader reader, Identity identity, bool finalize)
{ {
...@@ -1330,7 +1362,7 @@ static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, Comman ...@@ -1330,7 +1362,7 @@ static IEnumerable<TReturn> MultiMapImpl<TReturn>(this IDbConnection cnn, Comman
{ {
ownedCommand = command.SetupCommand(cnn, cinfo.ParamReader); ownedCommand = command.SetupCommand(cnn, cinfo.ParamReader);
if (wasClosed) cnn.Open(); if (wasClosed) cnn.Open();
ownedReader = ownedCommand.ExecuteReader(GetBehavior(wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)); ownedReader = ExecuteReaderWithFlagsFallback(ownedCommand, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult);
reader = ownedReader; reader = ownedReader;
} }
DeserializerState deserializer; DeserializerState deserializer;
...@@ -2522,7 +2554,7 @@ private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefin ...@@ -2522,7 +2554,7 @@ private static IDataReader ExecuteReaderImpl(IDbConnection cnn, ref CommandDefin
{ {
cmd = command.SetupCommand(cnn, paramReader); cmd = command.SetupCommand(cnn, paramReader);
if (wasClosed) cnn.Open(); if (wasClosed) cnn.Open();
var reader = cmd.ExecuteReader(GetBehavior(wasClosed, commandBehavior)); var reader = ExecuteReaderWithFlagsFallback(cmd, wasClosed, commandBehavior);
wasClosed = false; // don't dispose before giving it to them! wasClosed = false; // don't dispose before giving it to them!
disposeCommand = false; disposeCommand = false;
// note: command.FireOutputCallbacks(); would be useless here; parameters come at the **end** of the TDS stream // note: command.FireOutputCallbacks(); would be useless here; parameters come at the **end** of the TDS stream
......
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