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

NH-4087 - Fix decimal parameter with scale above 5 #708

Merged
merged 2 commits into from
Nov 26, 2017

Conversation

fredericDelaporte
Copy link
Member

@fredericDelaporte fredericDelaporte commented Oct 3, 2017

NH-4087 (#1196) - Fix decimal parameter with scale above 5

  • Cease defining default precision/scale in SQL Server driver unless explicitly configured
  • Allow Firebird to adjust its default parameter type cast
  • Use dialect configurable default scale/precision

namespace NHibernate.Test.DriverTest
{
[TestFixture]
public class OdbcDriverFixture : TestCase
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy paste of SqlClientDriverFixture which was executed for ODBC too, but with some specific test asserting ignore when it was ODBC. Now separated in its own fixture, with only non-ignored tests.

Assert.That(m.StringProp, Is.EqualTo("a"), "StringProp");
Assert.That(m.StringClob, Is.EqualTo("a"), "StringClob");
Assert.That(m.BinaryBlob, Is.EqualTo(new byte[] { 1, 2, 3 }), "BinaryBlob");
Assert.That(m.Binary, Is.EqualTo(new byte[] { 4, 5, 6 }), "BinaryBlob");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test was previously just saving/updating without checking values.


t.Rollback();
}
}

[Test]
public void DefaultPrecisionScale()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added test for new decimal precision/Scale settings.

/// <summary>
/// Supports condition not bound to any data, like "where @p1 = @p2".
/// </summary>
public virtual bool SupportsNonDataBoundCondition => true;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from #703, I will have to resolve a conflict on one of those PR depending on merge order. But I was needing this.

}

[Test]
public void HighScaleParameterSelect()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting with this one, new tests for checking "high" scale decimal are not truncated.

if (Dialect is FirebirdDialect)
{
configuration.SetProperty(Environment.ParameterDefaultDecimalPrecision, "18");
configuration.SetProperty(Environment.ParameterDefaultDecimalScale, "9");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to Firebird needing an explicit cast in some queries, injected by its driver, we must set its default scale/precision according to what the application needs. (Applications having varying needs will be stuck by this Firebird limitation, unless they use separated session factories just for those varying needs...)

return _fbDialect.GetTypeName(sqlType);
return _fbDialect.GetTypeName(SqlTypeFactory.GetSqlType(sqlType.DbType, _dbDecimalPrecision, _dbDecimalScale));
}
return _fbDialect.GetCastTypeName(sqlType);
Copy link
Member Author

@fredericDelaporte fredericDelaporte Oct 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This GetCastTypeName is quite a terrible method, hopefully having few usages. It disregards the type Length/Precision/Scale and use instead Column.DefaultLength/Column.DefaultPrecision/Column.DefaultScale, which are 255/19/2.
This causes all string types to be cast to a 255 length. Decimal type are trim down to 18 precision by dialect, but anyway, since the type resolution currently compares provided length with the max for the type, which is well below 255 for decimal, it always uses the default for decimal type, which for Firebird is decimal(18,5). Otherwise we would have got a truncation at 2 digits after dot.
I will fill another Jira for that method.

SqlClientDriver.SetVariableLengthParameterSize(dbParam, sqlType);
}
SqlClientDriver.SetVariableLengthParameterSize(dbParam, sqlType, _dbDecimalPrecision, _dbDecimalScale);
}
Copy link
Member Author

@fredericDelaporte fredericDelaporte Oct 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it really make sense to set length for SqlServerCe? I believe its sole purpose it to optimize query plan cache usage, but does SqlServerCe have a query plan cache?

@fredericDelaporte
Copy link
Member Author

fredericDelaporte commented Oct 4, 2017

Allow Firebird to adjust its default parameter type cast

This part would be mostly obsoleted by what I am doing for NH-4088 in #709.

@fredericDelaporte
Copy link
Member Author

Rebased, changed due to prepare_sql issues if decimal scale and precision are not always set: now SQL Server driver follows the defaults settable in dialect, instead of some hard-coded defaults. So it allows working around the issue by adjusting those defaults.

}

// Used from SqlServerCeDriver as well
public static void SetVariableLengthParameterSize(DbParameter dbParam, SqlType sqlType)
public static void SetVariableLengthParameterSize(
DbParameter dbParam, SqlType sqlType, byte defaultDecimalPrecision, byte defaultDecimalScale)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If doing that in 5.1, I guess we will have to add back previous method but flagged obsolete, for avoiding a possible breaking change.

@fredericDelaporte
Copy link
Member Author

Rebased and adjusted for having no more breaking changes.

 * Use dialect configurable default scale/precision
 * Fixes nhibernate#1187
@fredericDelaporte
Copy link
Member Author

Rebased, reworded.

@fredericDelaporte
Copy link
Member Author

Anything against merging this ?

@hazzik
Copy link
Member

hazzik commented Nov 26, 2017

@fredericDelaporte absolutely nothing apart I don't understand how it works.

@fredericDelaporte
Copy link
Member Author

The trouble: currently SqlClientDriver set a hard coded scale (5) and precision (28) on decimal parameters when their parameter definition does not specify it. (They may be deduced and set by the HQL query parsing in some cases, but not in all cases.) This causes issues when the parameter value need a higher scale than 5.

With 5.0, a configurable default scale (10) and default precision (28) have been introduced, currently used when a cast is issued in HQL or Linq.

This PR uses them instead of the hard coded non configurable ones from SqlClientDriver. So now the user can control the default scale of decimal parameter, and adjust it to its needs, instead of being limited to 5.

This PR also adds tests for checking for all dialects we can now use decimal with a scale higher than 5. The Sql client driver test fixture is also split in two, because it was actually also testing the Odbc driver, which was complexifying it and causing issues for the sql client driver changes tests. Now there is an odbc driver fixture on its own, along with the Sql client driver fixture purged from Odbc specific bits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants