From e9ade58ee743ae9e10eb8e7fb63cd1734e8cf159 Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Fri, 14 Mar 2014 13:19:59 +0200 Subject: [PATCH 1/2] SPRNET-1571 SPRNET-1572 set OracleCommand's BindByName to true * add native ODP.NET 12 provider * add managed ODP.NET 12 provider --- BreakingChanges.txt | 1 + .../Spring.Data/Data/Common/DbProvider.cs | 56 +++--- .../Spring.Data/Data/Common/dbproviders.xml | 161 +++++++++++++++++- .../Data/Common/DbProviderFactoryTests.cs | 117 ++++++++++--- .../Spring.Data.Tests.2010.csproj | 3 + test/Spring/Spring.Data.Tests/packages.config | 1 + 6 files changed, 275 insertions(+), 64 deletions(-) diff --git a/BreakingChanges.txt b/BreakingChanges.txt index 515ee323..0d66a73f 100644 --- a/BreakingChanges.txt +++ b/BreakingChanges.txt @@ -8,6 +8,7 @@ Changes (1.3.2 to 2.0) 3. Most of members marked as Obsolete before 2.0 release were removed. +4. DbProvider automatically sets BindByName to true for Oracle's ODP.NET OracleCommand instances when created Changes (1.3.1 to 1.3.2) ======================== diff --git a/src/Spring/Spring.Data/Data/Common/DbProvider.cs b/src/Spring/Spring.Data/Data/Common/DbProvider.cs index 0b5fad00..299a3860 100644 --- a/src/Spring/Spring.Data/Data/Common/DbProvider.cs +++ b/src/Spring/Spring.Data/Data/Common/DbProvider.cs @@ -20,6 +20,7 @@ using System; using System.Data; + using Spring.Expressions; using Spring.Reflection.Dynamic; using Spring.Util; @@ -32,12 +33,13 @@ namespace Spring.Data.Common public class DbProvider : IDbProvider { private string connectionString; - private IDbMetadata dbMetadata; - private IDynamicConstructor newCommand; - private IDynamicConstructor newConnection; - private IDynamicConstructor newCommandBuilder; - private IDynamicConstructor newDataAdapter; - private IDynamicConstructor newParameter; + private readonly IDbMetadata dbMetadata; + private readonly IDynamicConstructor newCommand; + private readonly IDynamicProperty commandBindByName; + private readonly IDynamicConstructor newConnection; + private readonly IDynamicConstructor newCommandBuilder; + private readonly IDynamicConstructor newDataAdapter; + private readonly IDynamicConstructor newParameter; /// /// Initializes a new instance of the class. @@ -47,6 +49,14 @@ namespace Spring.Data.Common { this.dbMetadata = dbMetadata; newCommand = DynamicConstructor.Create(dbMetadata.CommandType.GetConstructor(Type.EmptyTypes)); + + // Oracle needs custom bind by name property set to true as it's false by default + var bindByNameProperty = dbMetadata.CommandType.GetProperty("BindByName"); + if (bindByNameProperty != null && bindByNameProperty.CanWrite) + { + commandBindByName = DynamicProperty.Create(bindByNameProperty); + } + newConnection = DynamicConstructor.Create(dbMetadata.ConnectionType.GetConstructor(Type.EmptyTypes)); newCommandBuilder = DynamicConstructor.Create(dbMetadata.CommandBuilderType.GetConstructor(Type.EmptyTypes)); newDataAdapter = DynamicConstructor.Create(dbMetadata.DataAdapterType.GetConstructor(Type.EmptyTypes)); @@ -60,7 +70,12 @@ namespace Spring.Data.Common /// An new public IDbCommand CreateCommand() { - return newCommand.Invoke(ObjectUtils.EmptyObjects) as IDbCommand; + var command = newCommand.Invoke(ObjectUtils.EmptyObjects) as IDbCommand; + if (command != null && commandBindByName != null) + { + commandBindByName.SetValue(command, dbMetadata.BindByName); + } + return command; } /// @@ -188,20 +203,16 @@ namespace Spring.Data.Common /// The provider specific error code public string ExtractError(Exception e) { - if (!StringUtils.IsNullOrEmpty(dbMetadata.ErrorCodeExceptionExpression)) { return ExpressionEvaluator.GetValue(e, dbMetadata.ErrorCodeExceptionExpression).ToString(); - } + } else { - return "Could not extract error code exception type." + e.GetType(); + return "Could not extract error code exception type." + e.GetType(); } - } - - /// /// Determines whether the provided exception is in fact related /// to database access. This can be provider dependent in .NET 1.1 since @@ -215,7 +226,6 @@ namespace Spring.Data.Common /// public bool IsDataAccessException(Exception e) { - if (e is System.Data.Common.DbException) { return true; @@ -225,21 +235,5 @@ namespace Spring.Data.Common return false; } } - - /// - /// Determines whether is data access exception in .NET 1.1 for the specified exception. - /// - /// The candidate exception. - /// - /// true if is data access exception in .NET 1.1 for the specified exception; otherwise, false. - /// - private bool IsDataAccessExceptionBCL11(Exception e) - { - if (e == null) - { - return false; - } - return e.GetType().IsAssignableFrom(DbMetadata.ExceptionType); - } } -} +} \ No newline at end of file diff --git a/src/Spring/Spring.Data/Data/Common/dbproviders.xml b/src/Spring/Spring.Data/Data/Common/dbproviders.xml index 804c3476..2de8d0ef 100644 --- a/src/Spring/Spring.Data/Data/Common/dbproviders.xml +++ b/src/Spring/Spring.Data/Data/Common/dbproviders.xml @@ -500,7 +500,6 @@ - @@ -551,11 +550,163 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 900,903,904,917,936,942,17006 + + + 17003 + + + 1 + + + 17002,17447 + + + 1,1400,1722,2291,2292 + + + 54 + + + 8177 + + + 60 + + + + + + - diff --git a/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs b/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs index 1a35bbb0..171375b6 100644 --- a/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs +++ b/test/Spring/Spring.Data.Tests/Data/Common/DbProviderFactoryTests.cs @@ -23,7 +23,9 @@ using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Threading; + using NUnit.Framework; + using Spring.Context; using Spring.Context.Support; using Spring.Threading; @@ -41,7 +43,7 @@ namespace Spring.Data.Common public class AsyncTestDbProviderFactory : AsyncTestTask { - private string providerName; + private readonly string providerName; public AsyncTestDbProviderFactory(int iterations, string providerName) : base(iterations) @@ -66,12 +68,12 @@ namespace Spring.Data.Common //Other tests in this assembly will have already initialized the internal context that is part of DbProviderFactory //Reset it back to null so that tests for specifiying additional database providers will be able 're-initialize' //the internal Context of DbProviderFactory. - //Spring.Objects.Factory.Xml.NamespaceParserRegistry.RegisterParser(typeof(Spring.Data.Config.DatabaseNamespaceParser)); + //Spring.Objects.Factory.Xml.NamespaceParserRegistry.RegisterParser(typeof(Spring.Data.Config.DatabaseNamespaceParser)); if (DbProviderFactory.ApplicationContext != null) { - FieldInfo fieldInfo = typeof (DbProviderFactory).GetField("ctx", BindingFlags.NonPublic | BindingFlags.Static); - fieldInfo.SetValue(null, null); - } + FieldInfo fieldInfo = typeof (DbProviderFactory).GetField("ctx", BindingFlags.NonPublic | BindingFlags.Static); + fieldInfo.SetValue(null, null); + } ctx = new XmlApplicationContext("assembly://Spring.Data.Tests/Spring.Data.Common/DbProviderFactoryTests.xml"); } @@ -82,17 +84,16 @@ namespace Spring.Data.Common AsyncTestTask t2 = new AsyncTestDbProviderFactory(1000, "SqlServer-2.0").Start(); AsyncTestTask t3 = new AsyncTestDbProviderFactory(1000, "SqlServer-2.0").Start(); AsyncTestTask t4 = new AsyncTestDbProviderFactory(1000, "SqlServer-2.0").Start(); - + t1.AssertNoException(); t2.AssertNoException(); t3.AssertNoException(); t4.AssertNoException(); - } [Test] public void AdditionalResourceName() - { + { IDbProvider provider = DbProviderFactory.GetDbProvider("Test-SqlServer-2.0"); Assert.IsNotNull(provider); } @@ -100,11 +101,10 @@ namespace Spring.Data.Common [Test] public void BadErrorExpression() { - IDbProvider provider = DbProviderFactory.GetDbProvider("Test-SqlServer-2.0-BadErrorCodeExpression"); Assert.IsNotNull(provider); string errorCode = provider.ExtractError(new Exception("foo")); - Assert.AreEqual("156",errorCode); + Assert.AreEqual("156", errorCode); } [Test] @@ -126,8 +126,7 @@ namespace Spring.Data.Common Assert.IsNotNull(provider.CreateParameter()); Assert.AreEqual("@Foo", provider.CreateParameterName("Foo")); } - - + [Test] public void DefaultInstanceWithOleDb20() { @@ -140,7 +139,7 @@ namespace Spring.Data.Common Assert.IsNotNull(provider.CreateParameter()); Assert.AreEqual("?", provider.CreateParameterName("Foo")); } - + [Test] public void DefaultInstanceWithMicrsoftOracleClient20() { @@ -155,7 +154,7 @@ namespace Spring.Data.Common } #if NET_4_0 - + [Test] public void DefaultInstanceWithSqlServer40() { @@ -184,19 +183,82 @@ namespace Spring.Data.Common } #endif - //[Test] - //Comment in for specific testing with oracle as can't put oracle client in public code repository - public void DefaultInstanceWithOracleClient20() + [Test] + public void DefaultInstanceWithOracleClient10_20() { - IDbProvider provider = DbProviderFactory.GetDbProvider("OracleODP-2.0"); - Assert.AreEqual("Oracle, Oracle provider V2.102.2.20", provider.DbMetadata.ProductName); - Assert.IsNotNull(provider.CreateCommand()); + if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.102.2.20, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) + { + Assert.Inconclusive("oracle data access libs not found, skipping test"); + } + + AssertOracleProvider("OracleODP-2.0", "Oracle, Oracle provider V2.102.2.20"); + } + + [Test] + public void DefaultInstanceWithOracleClient11_20() + { + if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) + { + Assert.Inconclusive("oracle data access libs not found, skipping test"); + } + + AssertOracleProvider("OracleODP-11-2.0", "Oracle, Oracle provider V2.112.3.0"); + } + + [Test] + public void DefaultInstanceWithOracleClient12_20() + { + if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) + { + Assert.Inconclusive("oracle data access libs not found, skipping test"); + } + + AssertOracleProvider("OracleODP-12-2.0", "Oracle, Oracle provider V2.121.1.0"); + } + + [Test] + public void DefaultInstanceWithOracleClient12_40() + { + if (Type.GetType("Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) + { + Assert.Inconclusive("oracle data access libs not found, skipping test"); + } + + AssertOracleProvider("OracleODP-12-4.0", "Oracle, Oracle provider V4.121.1.0"); + } + + [Test] + public void DefaultInstanceWithOracleManagedClient11_40() + { + if (Type.GetType("Oracle.ManagedDataAccess.Client.OracleConnection, Oracle.ManagedDataAccess, Version=4.121.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342") == null) + { + Assert.Inconclusive("oracle data access libs not found, skipping test"); + } + + AssertOracleProvider("OracleODP-Managed-12-4.0", "Oracle, Oracle Managed provider V4.121.1.0"); + } + + private static void AssertOracleProvider(string providerName, string productName) + { + IDbProvider provider = DbProviderFactory.GetDbProvider(providerName); + Assert.AreEqual(productName, provider.DbMetadata.ProductName); + + var command = provider.CreateCommand(); + Assert.IsNotNull(command); + + // check if parameter has readable BindByName property + var property = command.GetType().GetProperty("BindByName"); + if (property != null) + { + var bindByNameValue = property.GetValue(command, null); + Assert.That(bindByNameValue, Is.EqualTo(provider.DbMetadata.BindByName), "BindByName had wrong value"); + } + Assert.IsNotNull(provider.CreateCommandBuilder()); Assert.IsNotNull(provider.CreateConnection()); Assert.IsNotNull(provider.CreateDataAdapter()); Assert.IsNotNull(provider.CreateParameter()); - Assert.AreEqual(":Foo", provider.CreateParameterName("Foo")); - + Assert.AreEqual(":Foo", provider.CreateParameterName("Foo")); } /* @@ -218,22 +280,21 @@ namespace Spring.Data.Common //Initialize internal application context. factory DbProviderFactory.GetDbProvider("SqlServer-2.0"); IApplicationContext ctx = DbProviderFactory.ApplicationContext; - IList dbProviderNames = ctx.GetObjectNamesForType(typeof(IDbProvider)); - Assert.IsTrue(dbProviderNames.Count > 0); - + IList dbProviderNames = ctx.GetObjectNamesForType(typeof (IDbProvider)); + Assert.IsTrue(dbProviderNames.Count > 0); } private void AssertIsSqlServer2005(IDbProvider provider) { Assert.AreEqual("Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0", - provider.DbMetadata.ProductName); + provider.DbMetadata.ProductName); AssertCommonSqlServerErrorCodes(provider); } private void AssertIsSqlServer40(IDbProvider provider) { Assert.AreEqual("Microsoft SQL Server, provider V4.0.0.0 in framework .NET V4.0", - provider.DbMetadata.ProductName); + provider.DbMetadata.ProductName); AssertCommonSqlServerErrorCodes(provider); } @@ -248,4 +309,4 @@ namespace Spring.Data.Common Assert.IsFalse(Array.IndexOf(codes.BadSqlGrammarCodes, "1xx56") >= 0); } } -} +} \ No newline at end of file diff --git a/test/Spring/Spring.Data.Tests/Spring.Data.Tests.2010.csproj b/test/Spring/Spring.Data.Tests/Spring.Data.Tests.2010.csproj index 9a0e3934..0301abce 100644 --- a/test/Spring/Spring.Data.Tests/Spring.Data.Tests.2010.csproj +++ b/test/Spring/Spring.Data.Tests/Spring.Data.Tests.2010.csproj @@ -84,6 +84,9 @@ False ..\..\..\packages\NUnit.2.6.3\lib\nunit.framework.dll + + ..\..\..\packages\odp.net.managed.121.1.1\lib\net40\Oracle.ManagedDataAccess.dll + False ..\..\..\lib\Net\2.0\Rhino.Mocks.dll diff --git a/test/Spring/Spring.Data.Tests/packages.config b/test/Spring/Spring.Data.Tests/packages.config index ee2f82e4..9c7eb68b 100644 --- a/test/Spring/Spring.Data.Tests/packages.config +++ b/test/Spring/Spring.Data.Tests/packages.config @@ -2,4 +2,5 @@ + \ No newline at end of file From 991a8b1bd108c141cfda19649161a2c6d4e3a9ec Mon Sep 17 00:00:00 2001 From: sbohlen Date: Sat, 15 Mar 2014 09:12:02 -0400 Subject: [PATCH 2/2] add discriminator to respect CLR version (in addition to OS version) as a factor in choosing which FORMATTER-related expectations to test against --- .../Globalization/CultureInfoUtils.cs | 5 +++++ .../Formatters/CurrencyFormatterTests.cs | 12 ++++++------ .../Formatters/DateTimeFormatterTests.cs | 11 +++++++---- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/test/Spring/Spring.Core.Tests/Globalization/CultureInfoUtils.cs b/test/Spring/Spring.Core.Tests/Globalization/CultureInfoUtils.cs index dbcca79c..181debc8 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/CultureInfoUtils.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/CultureInfoUtils.cs @@ -66,5 +66,10 @@ namespace Spring.Globalization { get { return Environment.OSVersion.Version.Major >= 6 && Environment.OSVersion.Version.Minor >= 2; } } + + public static bool ClrIsVersion4OrLater + { + get { return Environment.Version.Major >= 4; } + } } } diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/CurrencyFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/CurrencyFormatterTests.cs index b82e46ad..dee506fa 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/CurrencyFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/CurrencyFormatterTests.cs @@ -66,7 +66,7 @@ namespace Spring.Globalization.Formatters fmt = new CurrencyFormatter(CultureInfoUtils.SerbianLatinCultureName); - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual("1.234,00 din.", fmt.Format(1234)); Assert.AreEqual("1.234,56 din.", fmt.Format(1234.56)); @@ -83,7 +83,7 @@ namespace Spring.Globalization.Formatters fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual("1.234,00 дин.", fmt.Format(1234)); Assert.AreEqual("1.234,56 дин.", fmt.Format(1234.56)); @@ -111,7 +111,7 @@ namespace Spring.Globalization.Formatters fmt = new CurrencyFormatter(CultureInfoUtils.SerbianLatinCultureName); - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual(1234, fmt.Parse("1.234,00 din.")); Assert.AreEqual(1234.56, fmt.Parse("1.234,56 din.")); @@ -128,7 +128,7 @@ namespace Spring.Globalization.Formatters fmt = new CurrencyFormatter(CultureInfoUtils.SerbianCyrillicCultureName); - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual(1234, fmt.Parse("1.234,00 дин.")); Assert.AreEqual(1234.56, fmt.Parse("1.234,56 дин.")); @@ -168,7 +168,7 @@ namespace Spring.Globalization.Formatters fmt.GroupSizes = new int[] { 1, 2 }; fmt.GroupSeparator = "'"; - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual("1'23'4,00 дин.", fmt.Format(1234)); Assert.AreEqual("1'23'4,56 дин.", fmt.Format(1234.56)); @@ -207,7 +207,7 @@ namespace Spring.Globalization.Formatters fmt.GroupSizes = new int[] { 1, 2 }; fmt.GroupSeparator = "'"; - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual(1234, fmt.Parse("1'23'4,00 дин.")); Assert.AreEqual(1234.56, fmt.Parse("1'23'4,56 дин.")); diff --git a/test/Spring/Spring.Core.Tests/Globalization/Formatters/DateTimeFormatterTests.cs b/test/Spring/Spring.Core.Tests/Globalization/Formatters/DateTimeFormatterTests.cs index 2fb7af9d..f7e5c7a1 100644 --- a/test/Spring/Spring.Core.Tests/Globalization/Formatters/DateTimeFormatterTests.cs +++ b/test/Spring/Spring.Core.Tests/Globalization/Formatters/DateTimeFormatterTests.cs @@ -68,7 +68,10 @@ namespace Spring.Globalization.Formatters fmt = new DateTimeFormatter("D", CultureInfoUtils.SerbianLatinCultureName); - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + Console.WriteLine("Steve: " + Environment.Version); + + + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual("14. avgust 2004.", fmt.Format(new DateTime(2004, 8, 14))); Assert.AreEqual("24. avgust 1974.", fmt.Format(new DateTime(1974, 8, 24))); @@ -81,7 +84,7 @@ namespace Spring.Globalization.Formatters fmt = new DateTimeFormatter("dd-MMM-yyyy", CultureInfoUtils.SerbianCyrillicCultureName); - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual("14-авг.-2004", fmt.Format(new DateTime(2004, 8, 14))); Assert.AreEqual("24-авг.-1974", fmt.Format(new DateTime(1974, 8, 24))); @@ -107,7 +110,7 @@ namespace Spring.Globalization.Formatters fmt = new DateTimeFormatter("D", CultureInfoUtils.SerbianLatinCultureName); - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("14. avgust 2004.")); Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("24. avgust 1974.")); @@ -120,7 +123,7 @@ namespace Spring.Globalization.Formatters fmt = new DateTimeFormatter("dd-MMM-yyyy", CultureInfoUtils.SerbianCyrillicCultureName); - if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7) + if (CultureInfoUtils.OperatingSystemIsLaterThanWindows7 && CultureInfoUtils.ClrIsVersion4OrLater) { Assert.AreEqual(new DateTime(2004, 8, 14), fmt.Parse("14-авг.-2004")); Assert.AreEqual(new DateTime(1974, 8, 24), fmt.Parse("24-авг.-1974"));