Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OracleSuppressDecimalInvalidCastException setting #3028

Merged
merged 2 commits into from
Mar 13, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions doc/reference/modules/configuration.xml
Original file line number Diff line number Diff line change
@@ -1215,6 +1215,58 @@ var session = sessions.OpenSession(conn);
</para>
</entry>
</row>
<row>
<entry>
<literal>oracle.use_binary_floating_point_types</literal>
</entry>
<entry>
<para>
Set whether NHibernate should map .Net <literal>double</literal> and <literal>float</literal>
to Oracle <literal>BINARY_DOUBLE</literal> and <literal>BINARY_FLOAT</literal> types or use
Oracle <literal>DOUBLE</literal> and <literal>FLOAT</literal> types.
</para>
<para>
Oracle 10g introduced <literal>BINARY_DOUBLE</literal> and <literal>BINARY_FLOAT</literal>
types which are compatible with .NET <literal>double</literal> and <literal>float</literal>
types, while Oracle <literal>DOUBLE</literal> and <literal>FLOAT</literal> are not. Oracle
<literal>DOUBLE</literal> and <literal>FLOAT</literal> types do not conform to the IEEE
standard as they are internally implemented as <literal>NUMBER</literal> type, which
makes them an exact numeric type.
</para>
<para>
<emphasis role="strong">eg.</emphasis>
<literal>true</literal> for using Oracle <literal>BINARY_DOUBLE</literal> and
<literal>BINARY_FLOAT</literal> types | <literal>false</literal> for using Oracle
<literal>DOUBLE</literal> and <literal>FLOAT</literal> types.
</para>
<para>
<literal>false</literal> by default. See
<ulink url="https://docs.oracle.com/database/121/TTSQL/types.htm#TTSQL126">ANSI SQL data types</ulink>.
</para>
</entry>
</row>
<row>
<entry>
<literal>oracle.suppress_decimal_invalid_cast_exception</literal>
</entry>
<entry>
<para>
This setting specifies whether to suppress or not the <literal>InvalidCastException</literal>
and return a rounded-off 28 precision value if the Oracle <literal>NUMBER</literal> value
has more than a 28 precision.
</para>
<para>
<emphasis role="strong">eg.</emphasis>
<literal>true</literal> for suppressing the exception | <literal>false</literal> for letting
the exception be raised.
</para>
<para>
<literal>false</literal> by default. See
<ulink url="https://docs.oracle.com/en/database/oracle/oracle-data-access-components/19.3/odpnt/DataReaderSuppressGetDecimalInvalidCastException.html">SuppressGetDecimalInvalidCastException</ulink>.
This setting works only with ODP.NET 19.10 or newer.
</para>
</entry>
</row>
<row>
<entry>
<literal>odbc.explicit_datetime_scale</literal>
80 changes: 80 additions & 0 deletions src/NHibernate.Test/Async/NHSpecificTest/GH2641/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using System.Linq;
using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Dialect;
using NHibernate.Mapping.ByCode;
using NUnit.Framework;
using NHibernate.Linq;

namespace NHibernate.Test.NHSpecificTest.GH2641
{
using System.Threading.Tasks;
[TestFixture]
public class FixtureAsync : TestCaseMappingByCode
{
protected override void OnSetUp()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var entity = new Entity {Id = 1, Value = 0.00000000000000422030887989616};
session.Save(entity);

transaction.Commit();
}
}

protected override void OnTearDown()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
session.CreateQuery("delete from System.Object").ExecuteUpdate();

transaction.Commit();
}
}

protected override void Configure(Configuration configuration)
{
configuration.SetProperty(Environment.OracleSuppressDecimalInvalidCastException, "true");
}

protected override bool AppliesTo(Dialect.Dialect dialect)
{
return Dialect is Oracle8iDialect;
}

[Test]
public async Task ShouldNotThrowAsync()
{
using (var session = OpenSession())
{
await (session.Query<Entity>().ToListAsync());
}
}

protected override HbmMapping GetMappings()
{
var mapper = new ModelMapper();
mapper.Class<Entity>(
m =>
{
m.Table("Entity");
m.Id(x => x.Id, (i) => i.Generator(Generators.Assigned));
m.Property(x => x.Value);
});
return mapper.CompileMappingForAllExplicitlyAddedEntities();
}
}
}
11 changes: 11 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH2641/Entity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace NHibernate.Test.NHSpecificTest.GH2641
{
[Serializable]
public class Entity
{
public virtual int Id { get; set; }
public virtual double Value { get; set; }
}
}
68 changes: 68 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH2641/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System.Linq;
using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Dialect;
using NHibernate.Mapping.ByCode;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.GH2641
{
[TestFixture]
public class Fixture : TestCaseMappingByCode
{
protected override void OnSetUp()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var entity = new Entity {Id = 1, Value = 0.00000000000000422030887989616};
session.Save(entity);

transaction.Commit();
}
}

protected override void OnTearDown()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
session.CreateQuery("delete from System.Object").ExecuteUpdate();

transaction.Commit();
}
}

protected override void Configure(Configuration configuration)
{
configuration.SetProperty(Environment.OracleSuppressDecimalInvalidCastException, "true");
}

protected override bool AppliesTo(Dialect.Dialect dialect)
{
return Dialect is Oracle8iDialect;
}

[Test]
public void ShouldNotThrow()
{
using (var session = OpenSession())
{
session.Query<Entity>().ToList();
}
}

protected override HbmMapping GetMappings()
{
var mapper = new ModelMapper();
mapper.Class<Entity>(
m =>
{
m.Table("Entity");
m.Id(x => x.Id, (i) => i.Generator(Generators.Assigned));
m.Property(x => x.Value);
});
return mapper.CompileMappingForAllExplicitlyAddedEntities();
}
}
}
109 changes: 109 additions & 0 deletions src/NHibernate/AdoNet/DbCommandWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using System.Data;
using System.Data.Common;

namespace NHibernate.AdoNet
{
/// <summary>
/// A <see cref="DbCommand"/> wrapper that implements the required members.
/// </summary>
internal partial class DbCommandWrapper : DbCommand
{
public DbCommandWrapper(DbCommand command)
{
Command = command;
}

/// <summary>
/// The wrapped command.
/// </summary>
public DbCommand Command { get; }

/// <inheritdoc />
public override void Cancel()
{
Command.Cancel();
}

/// <inheritdoc />
public override int ExecuteNonQuery()
{
return Command.ExecuteNonQuery();
}

/// <inheritdoc />
public override object ExecuteScalar()
{
return Command.ExecuteScalar();
}

/// <inheritdoc />
public override void Prepare()
{
Command.Prepare();
}

/// <inheritdoc />
public override string CommandText
{
get => Command.CommandText;
set => Command.CommandText = value;
}

/// <inheritdoc />
public override int CommandTimeout
{
get => Command.CommandTimeout;
set => Command.CommandTimeout = value;
}

/// <inheritdoc />
public override CommandType CommandType
{
get => Command.CommandType;
set => Command.CommandType = value;
}

/// <inheritdoc />
public override UpdateRowSource UpdatedRowSource
{
get => Command.UpdatedRowSource;
set => Command.UpdatedRowSource = value;
}

/// <inheritdoc />
protected override DbConnection DbConnection
{
get => Command.Connection;
set => Command.Connection = value;
}

/// <inheritdoc />
protected override DbParameterCollection DbParameterCollection => Command.Parameters;

/// <inheritdoc />
protected override DbTransaction DbTransaction
{
get => Command.Transaction;
set => Command.Transaction = value;
}

/// <inheritdoc />
public override bool DesignTimeVisible
{
get => Command.DesignTimeVisible;
set => Command.DesignTimeVisible = value;
}

/// <inheritdoc />
protected override DbParameter CreateDbParameter()
{
return Command.CreateParameter();
}

/// <inheritdoc />
protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
{
return Command.ExecuteReader(behavior);
}
}
}
3 changes: 2 additions & 1 deletion src/NHibernate/AdoNet/HanaBatchingBatcher.cs
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
using System.Data.Common;
using System.Text;
using NHibernate.AdoNet.Util;
using NHibernate.Driver;
using NHibernate.Exceptions;

namespace NHibernate.AdoNet
@@ -34,7 +35,7 @@ public HanaBatchingBatcher(ConnectionManager connectionManager, IInterceptor int
public override void AddToBatch(IExpectation expectation)
{
// HanaCommands are cloneable
if (!(CurrentCommand is ICloneable cloneableCurrentCommand))
if (!(Driver.UnwrapDbCommand(CurrentCommand) is ICloneable cloneableCurrentCommand))
throw new InvalidOperationException("Current command is not an ICloneable");

var batchUpdate = CurrentCommand;
3 changes: 2 additions & 1 deletion src/NHibernate/AdoNet/MySqlClientBatchingBatcher.cs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
using System.Data.Common;
using System.Text;
using NHibernate.AdoNet.Util;
using NHibernate.Driver;
using NHibernate.Exceptions;

namespace NHibernate.AdoNet
@@ -63,7 +64,7 @@ public override void AddToBatch(IExpectation expectation)
{
Log.Debug("Adding to batch:{0}", lineWithParameters);
}
currentBatch.Append(batchUpdate);
currentBatch.Append(Driver.UnwrapDbCommand(batchUpdate));

if (currentBatch.CountOfCommands >= batchSize)
{
6 changes: 4 additions & 2 deletions src/NHibernate/AdoNet/OracleDataClientBatchingBatcher.cs
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
using System.Data.Common;
using System.Text;
using NHibernate.AdoNet.Util;
using NHibernate.Driver;
using NHibernate.Exceptions;

namespace NHibernate.AdoNet
@@ -156,9 +157,10 @@ protected override int CountOfStatementsInCurrentBatch
private void SetArrayBindCount(int arraySize)
{
//TODO: cache the property info.
var objType = _currentBatch.GetType();
var command = Driver.UnwrapDbCommand(_currentBatch);
var objType = command.GetType();
var propInfo = objType.GetProperty("ArrayBindCount");
propInfo.SetValue(_currentBatch, arraySize, null);
propInfo.SetValue(command, arraySize, null);
}

public override int BatchSize
4 changes: 2 additions & 2 deletions src/NHibernate/AdoNet/SqlClientBatchingBatcher.cs
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@ public override void AddToBatch(IExpectation expectation)
{
Log.Debug("Adding to batch:{0}", lineWithParameters);
}
_currentBatch.Append((System.Data.SqlClient.SqlCommand)batchUpdate);
_currentBatch.Append((System.Data.SqlClient.SqlCommand) Driver.UnwrapDbCommand(batchUpdate));

if (_currentBatch.CountOfCommands >= _batchSize)
{
@@ -99,7 +99,7 @@ public override Task AddToBatchAsync(IExpectation expectation, CancellationToken
{
Log.Debug("Adding to batch:{0}", lineWithParameters);
}
_currentBatch.Append((System.Data.SqlClient.SqlCommand) batchUpdate);
_currentBatch.Append((System.Data.SqlClient.SqlCommand) Driver.UnwrapDbCommand(batchUpdate));

if (_currentBatch.CountOfCommands >= _batchSize)
{
51 changes: 51 additions & 0 deletions src/NHibernate/Async/AdoNet/DbCommandWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using System.Data;
using System.Data.Common;

namespace NHibernate.AdoNet
{
using System.Threading.Tasks;
using System.Threading;
internal partial class DbCommandWrapper : DbCommand
{

/// <inheritdoc />
public override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<int>(cancellationToken);
}
return Command.ExecuteNonQueryAsync(cancellationToken);
}

/// <inheritdoc />
public override Task<object> ExecuteScalarAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<object>(cancellationToken);
}
return Command.ExecuteScalarAsync(cancellationToken);
}

/// <inheritdoc />
protected override Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return Task.FromCanceled<DbDataReader>(cancellationToken);
}
return Command.ExecuteReaderAsync(behavior, cancellationToken);
}
}
}
3 changes: 2 additions & 1 deletion src/NHibernate/Async/AdoNet/HanaBatchingBatcher.cs
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
using System.Data.Common;
using System.Text;
using NHibernate.AdoNet.Util;
using NHibernate.Driver;
using NHibernate.Exceptions;

namespace NHibernate.AdoNet
@@ -25,7 +26,7 @@ public partial class HanaBatchingBatcher : AbstractBatcher
public override Task AddToBatchAsync(IExpectation expectation, CancellationToken cancellationToken)
{
// HanaCommands are cloneable
if (!(CurrentCommand is ICloneable cloneableCurrentCommand))
if (!(Driver.UnwrapDbCommand(CurrentCommand) is ICloneable cloneableCurrentCommand))
throw new InvalidOperationException("Current command is not an ICloneable");
if (cancellationToken.IsCancellationRequested)
{
3 changes: 2 additions & 1 deletion src/NHibernate/Async/AdoNet/MySqlClientBatchingBatcher.cs
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
using System.Data.Common;
using System.Text;
using NHibernate.AdoNet.Util;
using NHibernate.Driver;
using NHibernate.Exceptions;

namespace NHibernate.AdoNet
@@ -48,7 +49,7 @@ public override async Task AddToBatchAsync(IExpectation expectation, Cancellatio
{
Log.Debug("Adding to batch:{0}", lineWithParameters);
}
currentBatch.Append(batchUpdate);
currentBatch.Append(Driver.UnwrapDbCommand(batchUpdate));

if (currentBatch.CountOfCommands >= batchSize)
{
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
using System.Data.Common;
using System.Text;
using NHibernate.AdoNet.Util;
using NHibernate.Driver;
using NHibernate.Exceptions;

namespace NHibernate.AdoNet
39 changes: 39 additions & 0 deletions src/NHibernate/Async/Driver/OracleDataClientDriverBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using NHibernate.AdoNet;
using NHibernate.Engine.Query;
using NHibernate.SqlTypes;
using NHibernate.Util;

namespace NHibernate.Driver
{
public abstract partial class OracleDataClientDriverBase : ReflectionBasedDriver, IEmbeddedBatcherFactoryProvider
{
private partial class OracleDbCommandWrapper : DbCommandWrapper
{

protected override async Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var reader = await (Command.ExecuteReaderAsync(behavior, cancellationToken)).ConfigureAwait(false);
_suppressDecimalInvalidCastExceptionSetter(reader, true);

return reader;
}
}
}
}
13 changes: 13 additions & 0 deletions src/NHibernate/Cfg/Environment.cs
Original file line number Diff line number Diff line change
@@ -348,6 +348,19 @@ public static string Version
/// </remarks>
public const string OracleUseBinaryFloatingPointTypes = "oracle.use_binary_floating_point_types";

/// <summary>
/// This setting specifies whether to suppress the InvalidCastException and return a rounded-off 28 precision value
/// if the Oracle NUMBER value has more than 28 precision.
/// <para>
/// <see langword="false"/> by default.
/// </para>
/// </summary>
/// <remarks>
/// See https://docs.oracle.com/en/database/oracle/oracle-data-access-components/19.3/odpnt/DataReaderSuppressGetDecimalInvalidCastException.html
/// This setting works only with ODP.NET 19.10 or newer.
/// </remarks>
public const string OracleSuppressDecimalInvalidCastException = "oracle.suppress_decimal_invalid_cast_exception";

/// <summary>
/// <para>
/// Firebird with FirebirdSql.Data.FirebirdClient may be unable to determine the type
10 changes: 10 additions & 0 deletions src/NHibernate/Driver/DriverBase.cs
Original file line number Diff line number Diff line change
@@ -46,6 +46,16 @@ protected bool IsPrepareSqlEnabled
public abstract DbConnection CreateConnection();
public abstract DbCommand CreateCommand();

/// <summary>
/// Unwraps the <see cref="DbCommand"/> in case it is wrapped, otherwise the same instance is returned.
/// </summary>
/// <param name="command">The command to unwrap.</param>
/// <returns>The unwrapped command.</returns>
public virtual DbCommand UnwrapDbCommand(DbCommand command)
{
return command;
}

/// <summary>
/// Begin an ADO <see cref="DbTransaction" />.
/// </summary>
12 changes: 12 additions & 0 deletions src/NHibernate/Driver/DriverExtensions.cs
Original file line number Diff line number Diff line change
@@ -48,5 +48,17 @@ public static DbTransaction BeginTransaction(this IDriver driver, IsolationLevel
}
return connection.BeginTransaction(isolationLevel);
}

// 6.0 TODO: merge into IDriver
/// <summary>
/// Unwraps the <see cref="DbCommand"/> in case it is wrapped, otherwise the same instance is returned.
/// </summary>
/// <param name="driver">The driver.</param>
/// <param name="command">The command to unwrap.</param>
/// <returns>The unwrapped command.</returns>
public static DbCommand UnwrapDbCommand(this IDriver driver, DbCommand command)
{
return driver is DriverBase driverBase ? driverBase.UnwrapDbCommand(command) : command;
}
}
}
54 changes: 53 additions & 1 deletion src/NHibernate/Driver/OracleDataClientDriverBase.cs
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using NHibernate.AdoNet;
using NHibernate.Engine.Query;
using NHibernate.SqlTypes;
@@ -17,14 +19,33 @@ namespace NHibernate.Driver
/// on the NHibernate forums in this
/// <a href="http://sourceforge.net/forum/message.php?msg_id=2952662">post</a>.
/// </remarks>
public abstract class OracleDataClientDriverBase : ReflectionBasedDriver, IEmbeddedBatcherFactoryProvider
public abstract partial class OracleDataClientDriverBase : ReflectionBasedDriver, IEmbeddedBatcherFactoryProvider
{
private partial class OracleDbCommandWrapper : DbCommandWrapper
{
private readonly Action<object, bool> _suppressDecimalInvalidCastExceptionSetter;

public OracleDbCommandWrapper(DbCommand command, Action<object, bool> suppressDecimalInvalidCastExceptionSetter) : base(command)
{
_suppressDecimalInvalidCastExceptionSetter = suppressDecimalInvalidCastExceptionSetter;
}

protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
{
var reader = Command.ExecuteReader(behavior);
_suppressDecimalInvalidCastExceptionSetter(reader, true);

return reader;
}
}

private const string _commandClassName = "OracleCommand";

private static readonly SqlType _guidSqlType = new SqlType(DbType.Binary, 16);

private readonly Action<object, bool> _commandBindByNameSetter;
private readonly Action<object, object> _parameterOracleDbTypeSetter;
private readonly Action<object, bool> _suppressDecimalInvalidCastExceptionSetter;
private readonly object _oracleDbTypeRefCursor;
private readonly object _oracleDbTypeXmlType;
private readonly object _oracleDbTypeBlob;
@@ -62,6 +83,12 @@ private OracleDataClientDriverBase(string driverAssemblyName, string clientNames
_oracleDbTypeNChar = Enum.Parse(oracleDbTypeEnum, "NChar");
_oracleDbTypeBinaryDouble = Enum.Parse(oracleDbTypeEnum, "BinaryDouble");
_oracleDbTypeBinaryFloat = Enum.Parse(oracleDbTypeEnum, "BinaryFloat");

var oracleDataReader = ReflectHelper.TypeFromAssembly(clientNamespace + ".OracleDataReader", driverAssemblyName, true);
if (oracleDataReader.GetProperty("SuppressGetDecimalInvalidCastException") != null)
{
_suppressDecimalInvalidCastExceptionSetter = DelegateHelper.BuildPropertySetter<bool>(oracleDataReader, "SuppressGetDecimalInvalidCastException");
}
}

/// <inheritdoc/>
@@ -72,6 +99,7 @@ public override void Configure(IDictionary<string, string> settings)
// If changing the default value, keep it in sync with Oracle8iDialect.Configure.
UseNPrefixedTypesForUnicode = PropertiesHelper.GetBoolean(Cfg.Environment.OracleUseNPrefixedTypesForUnicode, settings, false);
UseBinaryFloatingPointTypes = PropertiesHelper.GetBoolean(Cfg.Environment.OracleUseBinaryFloatingPointTypes, settings, false);
SuppressDecimalInvalidCastException = PropertiesHelper.GetBoolean(Cfg.Environment.OracleSuppressDecimalInvalidCastException, settings, false);
}

/// <summary>
@@ -94,6 +122,8 @@ public override void Configure(IDictionary<string, string> settings)
/// </summary>
public bool UseBinaryFloatingPointTypes { get; private set; }

public bool SuppressDecimalInvalidCastException { get; private set; }

/// <inheritdoc/>
public override bool UseNamedPrefixInSql => true;

@@ -168,6 +198,7 @@ private void InitializeParameter(DbParameter dbParam, string name, object oracle
protected override void OnBeforePrepare(DbCommand command)
{
base.OnBeforePrepare(command);
command = UnwrapDbCommand(command);

// need to explicitly turn on named parameter binding
// http://tgaw.wordpress.com/2006/03/03/ora-01722-with-odp-and-command-parameters/
@@ -190,6 +221,27 @@ protected override void OnBeforePrepare(DbCommand command)
command.Parameters.Insert(0, outCursor);
}

public override DbCommand CreateCommand()
{
var command = base.CreateCommand();
if (!SuppressDecimalInvalidCastException)
{
return command;
}

if (_suppressDecimalInvalidCastExceptionSetter == null)
{
throw new NotSupportedException("OracleDataReader.SuppressGetDecimalInvalidCastException property is supported only in ODP.NET version 19.10 or newer");
}

return new OracleDbCommandWrapper(command, _suppressDecimalInvalidCastExceptionSetter);
}

public override DbCommand UnwrapDbCommand(DbCommand command)
{
return command is OracleDbCommandWrapper wrapper ? wrapper.Command : command;
}

System.Type IEmbeddedBatcherFactoryProvider.BatcherFactoryClass => typeof(OracleDataClientBatchingBatcherFactory);
}
}
11 changes: 11 additions & 0 deletions src/NHibernate/nhibernate-configuration.xsd
Original file line number Diff line number Diff line change
@@ -278,6 +278,17 @@
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="oracle.suppress_decimal_invalid_cast_exception">
<xs:annotation>
<xs:documentation>
This setting specifies whether to suppress the InvalidCastException and return a rounded-off
28 precision value if the Oracle NUMBER value has more than 28 precision.
False by default.
See https://docs.oracle.com/en/database/oracle/oracle-data-access-components/19.3/odpnt/DataReaderSuppressGetDecimalInvalidCastException.html
This setting works only with ODP.NET 19.10 or newer.
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="firebird.disable_parameter_casting">
<xs:annotation>
<xs:documentation>