diff --git a/Dapper NET40/SqlMapper.cs b/Dapper NET40/SqlMapper.cs
index b40826ddfa731527e339d38a31a7056c138c1389..e46b6466acad01eeb96479166aba360e4a526b40 100644
--- a/Dapper NET40/SqlMapper.cs
+++ b/Dapper NET40/SqlMapper.cs
@@ -47,7 +47,7 @@ public enum CommandFlags
///
/// Should the plan cache be bypassed?
///
- NoCache = 4
+ NoCache = 4,
}
///
/// Represents the key aspects of a sql operation
@@ -2044,18 +2044,14 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter
info = new CacheInfo();
if (identity.parametersType != null)
{
+ Action reader;
if (exampleParameters is IDynamicParameters)
{
- info.ParamReader = (cmd, obj) => { ((IDynamicParameters)obj).AddParameters(cmd, identity); };
+ reader = (cmd, obj) => { ((IDynamicParameters)obj).AddParameters(cmd, identity); };
}
-#if CSHARP30
else if (exampleParameters is IEnumerable>)
-#else
- // special-case dictionary and `dynamic`
- else if (exampleParameters is IEnumerable> || exampleParameters is System.Dynamic.IDynamicMetaObjectProvider)
-#endif
{
- info.ParamReader = (cmd, obj) =>
+ reader = (cmd, obj) =>
{
IDynamicParameters mapped = new DynamicParameters(obj);
mapped.AddParameters(cmd, identity);
@@ -2064,14 +2060,67 @@ private static CacheInfo GetCacheInfo(Identity identity, object exampleParameter
else
{
var literals = GetLiteralTokens(identity.sql);
- info.ParamReader = CreateParamInfoGenerator(identity, false, true, literals);
+ reader = CreateParamInfoGenerator(identity, false, true, literals);
}
+ if((identity.commandType == null || identity.commandType == CommandType.Text) && ShouldPassByPosition(identity.sql))
+ {
+ var tail = reader;
+ var sql = identity.sql;
+ reader = (cmd, obj) =>
+ {
+ tail(cmd, obj);
+ PassByPosition(cmd);
+ };
+ }
+ info.ParamReader = reader;
}
if(addToCache) SetQueryCache(identity, info);
}
return info;
}
+ private static bool ShouldPassByPosition(string sql)
+ {
+ return sql != null && sql.IndexOf('?') >= 0 && pseudoPositional.IsMatch(sql);
+ }
+
+ private static void PassByPosition(IDbCommand cmd)
+ {
+ if (cmd.Parameters.Count == 0) return;
+
+ Dictionary parameters = new Dictionary(StringComparer.InvariantCulture);
+
+ foreach(IDbDataParameter param in cmd.Parameters)
+ {
+ if (!string.IsNullOrEmpty(param.ParameterName)) parameters[param.ParameterName] = param;
+ }
+ HashSet consumed = new HashSet(StringComparer.InvariantCulture);
+ cmd.Parameters.Clear();
+
+ cmd.CommandText = pseudoPositional.Replace(cmd.CommandText, match =>
+ {
+ string key = match.Groups[1].Value;
+ IDbDataParameter param;
+ if (!consumed.Add(key))
+ {
+ throw new InvalidOperationException("When passing parameters by position, each parameter can only be referenced once");
+ }
+ else if (parameters.TryGetValue(key, out param))
+ {
+ // if found, return the anonymous token "?"
+ cmd.Parameters.Add(param);
+ parameters.Remove(key);
+ consumed.Add(key);
+ return "?";
+ }
+ else
+ {
+ // otherwise, leave alone for simple debugging
+ return match.Value;
+ }
+ });
+ }
+
private static Func GetDeserializer(Type type, IDataReader reader, int startBound, int length, bool returnNullIfFirstMissing)
{
#if !CSHARP30
@@ -2682,14 +2731,14 @@ public static void PackListParameters(IDbCommand command, string namePrefix, obj
private static IEnumerable FilterParameters(IEnumerable parameters, string sql)
{
- return parameters.Where(p => Regex.IsMatch(sql, @"[?@:]" + p.Name + "([^a-zA-Z0-9_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant));
+ return parameters.Where(p => Regex.IsMatch(sql, @"[?@:]" + p.Name + "([^a-z0-9_]+|$)", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.CultureInvariant));
}
-
// look for ? / @ / : *by itself*
- static readonly Regex smellsLikeOleDb = new Regex(@"(?
/// Represents a placeholder for a value that should be replaced as a literal value in the resulting sql
///
@@ -4280,13 +4329,7 @@ public DynamicParameters(object template)
/// EG: AddDynamicParams(new {A = 1, B = 2}) // will add property A and B to the dynamic
///
///
- public void AddDynamicParams(
-#if CSHARP30
-object param
-#else
-dynamic param
-#endif
-)
+ public void AddDynamicParams(object param)
{
var obj = param as object;
if (obj != null)
@@ -4304,11 +4347,7 @@ dynamic param
{
foreach (var kvp in dictionary)
{
-#if CSHARP30
Add(kvp.Key, kvp.Value, null, null, null);
-#else
- Add(kvp.Key, kvp.Value);
-#endif
}
}
}
diff --git a/Tests/Assert.cs b/Tests/Assert.cs
index 67ab422515cbcfe8ed542fbd34fc4bb53fe5a06c..f9f19a9c09a8e49d5082b89eb96a2a7147b2a674 100644
--- a/Tests/Assert.cs
+++ b/Tests/Assert.cs
@@ -24,6 +24,10 @@ public static void IsSequenceEqualTo(this IEnumerable obj, IEnumerable
}
}
+ public static void Fail()
+ {
+ throw new ApplicationException("Expectation failed");
+ }
public static void IsFalse(this bool b)
{
if (b)
diff --git a/Tests/DapperTests NET40.csproj b/Tests/DapperTests NET40.csproj
index e3fba3eb92a0e24be5aa54d9b07f731289886210..ee6ef2a013e338ead829fa94b6248008b94ebfe8 100644
--- a/Tests/DapperTests NET40.csproj
+++ b/Tests/DapperTests NET40.csproj
@@ -47,6 +47,9 @@
..\packages\EntityFramework.6.1.0\lib\net45\EntityFramework.SqlServer.dll
+
+ ..\packages\FirebirdSql.Data.FirebirdClient.4.5.1.0\lib\net45\FirebirdSql.Data.FirebirdClient.dll
+
False
..\packages\FSharp.Core.4.0.0\lib\FSharp.Core.dll
@@ -264,6 +267,7 @@
+
diff --git a/Tests/Tests.cs b/Tests/Tests.cs
index d7763451fde8d35673ec6b87da553c5a9cf54bdd..40c2664af2174a12507c58c90dca13f7785cfb5e 100644
--- a/Tests/Tests.cs
+++ b/Tests/Tests.cs
@@ -18,6 +18,7 @@
using System.Data.Entity.Spatial;
using Microsoft.SqlServer.Types;
using System.Data.SqlTypes;
+using FirebirdSql.Data.FirebirdClient;
#if POSTGRESQL
using Npgsql;
#endif
@@ -498,7 +499,7 @@ public void TestExtraFields()
// see http://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
- using (var conn = new System.Data.OleDb.OleDbConnection(Program.OleDbConnectionString))
+ using (var conn = ConnectViaOledb())
{
var row = conn.Query("select Id = ?, Age = ?",
new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
@@ -510,6 +511,13 @@ public void TestOleDbParameters()
}
}
+ System.Data.OleDb.OleDbConnection ConnectViaOledb()
+ {
+ var conn = new System.Data.OleDb.OleDbConnection(Program.OleDbConnectionString);
+ conn.Open();
+ return conn;
+ }
+
public void TestStrongType()
{
var guid = Guid.NewGuid();
@@ -3851,6 +3859,131 @@ public void AllowIDictionaryParameters()
connection.Query("SELECT @param1", parameters);
}
+
+
+ public void Issue178_SqlServer()
+ {
+ const string sql = @"select count(*) from Issue178";
+ try { connection.Execute("drop table Issue178"); } catch { }
+ try { connection.Execute("create table Issue178(id int not null)"); } catch { }
+ // raw ADO.net
+ var sqlCmd = new SqlCommand(sql, connection);
+ using (IDataReader reader1 = sqlCmd.ExecuteReader())
+ {
+ Assert.IsTrue(reader1.Read());
+ reader1.GetInt32(0).IsEqualTo(0);
+ Assert.IsFalse(reader1.Read());
+ Assert.IsFalse(reader1.NextResult());
+ }
+
+ // dapper
+ using (var reader2 = connection.ExecuteReader(sql))
+ {
+ Assert.IsTrue(reader2.Read());
+ reader2.GetInt32(0).IsEqualTo(0);
+ Assert.IsFalse(reader2.Read());
+ Assert.IsFalse(reader2.NextResult());
+ }
+ }
+
+ public void Issue178_Firebird() // we expect this to fail due to a bug in Firebird; a PR to fix it has been submitted
+ {
+ var cs = @"initial catalog=localhost:database;user id=SYSDBA;password=masterkey";
+
+ using (var connection = new FbConnection(cs))
+ {
+ connection.Open();
+ const string sql = @"select count(*) from Issue178";
+ try { connection.Execute("drop table Issue178"); } catch { }
+ try { connection.Execute("create table Issue178(id int not null)"); } catch { }
+ // raw ADO.net
+ var sqlCmd = new FbCommand(sql, connection);
+ using (IDataReader reader1 = sqlCmd.ExecuteReader())
+ {
+ Assert.IsTrue(reader1.Read());
+ reader1.GetInt32(0).IsEqualTo(0);
+ Assert.IsFalse(reader1.Read());
+ Assert.IsFalse(reader1.NextResult());
+ }
+
+ // dapper
+ using (var reader2 = connection.ExecuteReader(sql))
+ {
+ Assert.IsTrue(reader2.Read());
+ reader2.GetInt32(0).IsEqualTo(0);
+ Assert.IsFalse(reader2.Read());
+ Assert.IsFalse(reader2.NextResult());
+ }
+ }
+ }
+
+ public void PseudoPositionalParameters_Simple()
+ {
+ using (var connection = ConnectViaOledb())
+ {
+ int value = connection.Query("select ?x? + ?y_2? + ?z?", new { x = 1, y_2 = 3, z = 5, z2 = 24 }).Single();
+ value.IsEqualTo(9);
+ }
+ }
+ public void PseudoPositionalParameters_Dynamic()
+ {
+ using (var connection = ConnectViaOledb())
+ {
+ var args = new DynamicParameters();
+ args.Add("x", 1);
+ args.Add("y_2", 3);
+ args.Add("z", 5);
+ args.Add("z2", 24);
+ int value = connection.Query("select ?x? + ?y_2? + ?z?", args).Single();
+ value.IsEqualTo(9);
+ }
+ }
+ public void PseudoPositionalParameters_ReusedParameter()
+ {
+ using (var connection = ConnectViaOledb())
+ {
+ try
+ {
+ int value = connection.Query("select ?x? + ?y_2? + ?x?", new { x = 1, y_2 = 3 }).Single();
+ Assert.Fail();
+ }
+ catch (InvalidOperationException ex)
+ {
+ ex.Message.IsEqualTo("When passing parameters by position, each parameter can only be referenced once");
+ }
+ }
+ }
+
+ public void PseudoPositionalParameters_ExecSingle()
+ {
+ using (var connection = ConnectViaOledb())
+ {
+ var data = new { x = 6 };
+ connection.Execute("create table #named_single(val int not null)");
+ int count = connection.Execute("insert #named_single (val) values (?x?)", data);
+ int sum = (int)connection.ExecuteScalar("select sum(val) from #named_single");
+ count.IsEqualTo(1);
+ sum.IsEqualTo(6);
+ }
+ }
+ public void PseudoPositionalParameters_ExecMulti()
+ {
+ using (var connection = ConnectViaOledb())
+ {
+ var data = new[]
+ {
+ new { x = 1, y = 1 },
+ new { x = 3, y = 1 },
+ new { x = 6, y = 1 },
+ };
+ connection.Execute("create table #named_multi(val int not null)");
+ int count = connection.Execute("insert #named_multi (val) values (?x?)", data);
+ int sum = (int)connection.ExecuteScalar("select sum(val) from #named_multi");
+ count.IsEqualTo(3);
+ sum.IsEqualTo(10);
+ }
+ }
+
#if POSTGRESQL
class Cat
diff --git a/Tests/packages.config b/Tests/packages.config
index 666be145f2096ced3b1876e9b0ce9ca7ea6852ad..bcaaf7693604a569c49cc6fb6c16e6fae509f855 100644
--- a/Tests/packages.config
+++ b/Tests/packages.config
@@ -1,6 +1,7 @@
+
diff --git a/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net40-client/FirebirdSql.Data.FirebirdClient.dll b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net40-client/FirebirdSql.Data.FirebirdClient.dll
new file mode 100644
index 0000000000000000000000000000000000000000..cf21151825f07cb2148918b09efc1fe6629edbe0
Binary files /dev/null and b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net40-client/FirebirdSql.Data.FirebirdClient.dll differ
diff --git a/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net40-client/FirebirdSql.Data.FirebirdClient.pdb b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net40-client/FirebirdSql.Data.FirebirdClient.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..0097c7a95a751ae269ab7f831f38cfda7a783129
Binary files /dev/null and b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net40-client/FirebirdSql.Data.FirebirdClient.pdb differ
diff --git a/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net45/FirebirdSql.Data.FirebirdClient.dll b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net45/FirebirdSql.Data.FirebirdClient.dll
new file mode 100644
index 0000000000000000000000000000000000000000..c63b88a2e862e713b594fdf61ccd5257b6388ebd
Binary files /dev/null and b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net45/FirebirdSql.Data.FirebirdClient.dll differ
diff --git a/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net45/FirebirdSql.Data.FirebirdClient.pdb b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net45/FirebirdSql.Data.FirebirdClient.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..1d56e3eb0f48f0f45876351a8c665129ac7ea02c
Binary files /dev/null and b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/lib/net45/FirebirdSql.Data.FirebirdClient.pdb differ
diff --git a/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/readme.txt b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/readme.txt
new file mode 100644
index 0000000000000000000000000000000000000000..85ba85bacaa29fd6115b1078d92fd12ce1bf79bd
--- /dev/null
+++ b/packages/FirebirdSql.Data.FirebirdClient.4.5.1.0/readme.txt
@@ -0,0 +1,35 @@
+README - FirebirdClient ADO.NET 2.0 Data provider for Firebird
+==============================================================
+
+This project is supported by:
+-----------------------------
+
+ Sean Leyne (Broadview Software)
+ SMS-Timing
+
+
+Developement list
+-----------------
+
+You can subscribe to the developement list at:
+
+ http://lists.sourceforge.net/lists/listinfo/firebird-net-provider
+
+
+You can access to the lastest developement sources through SVN, see:
+
+ https://sourceforge.net/p/firebird/NETProvider/
+
+
+Reporting Bugs
+--------------
+
+Yo can report bugs using two ways:
+
+1. Sending it to the developement list.
+2. Thru the Firebird Project tracker (category DNET):
+
+
+ http://tracker.firebirdsql.org/DNET
+
+