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

Reduce cast usage for COUNT aggregate and add support for Mssql count_big #2061

Merged
merged 6 commits into from
Apr 1, 2020

Conversation

maca88
Copy link
Contributor

@maca88 maca88 commented Mar 15, 2019

This is a continuation of #2036, which extends the cast reduce usage for count aggregate function. In addition, this PR introduces count_big sql function that is used when using LongCount and MsSql2000Dialect overrides it to use the specific Sql Server count_big function (by default count is used).

@maca88
Copy link
Contributor Author

maca88 commented Feb 21, 2020

Rebased and renamed to ISQLFunction extension interface as it will be used in all ISQLFunction implementations which I will address in a separate PR. Initially, I planned to deprecate ISQLFunction.ReturnType in favor of the newly added ISQLFunctionExtended.GetEffectiveReturnType method but it turned out that it would produce an unwanted breaking change. For example the following test would fail in Sql Server:

object count = s.CreateQuery("select count(*) from Simple").UniqueResult();
Assert.IsTrue(count is Int64);

because count effective return type in Sql Server is an int. So the idea is that ISQLFunction.ReturnType should return the same type no matter what database is used, which is basically what it does today, except for some functions which IMO should be corrected:

  • length: in Firebird and Oracle dialects returns Int64, SysbaseASE9 returns string (very suspicious) and in other dialect returns Int32.
  • mod: in Firebird dialect returns Double where in other dialects returns Int32

The intention of ISQLFunctionExtended.GetEffectiveReturnType method is be used by higher level api like linq in order to determine whether a cast or a transparent cast is needed.

@maca88 maca88 changed the title WIP - Reduce cast usage for COUNT aggregate and add support for Mssql count_big Reduce cast usage for COUNT aggregate and add support for Mssql count_big Feb 21, 2020
src/NHibernate/Dialect/Function/ISQLFunction.cs Outdated Show resolved Hide resolved
@@ -286,7 +286,8 @@ protected virtual void RegisterKeywords()

protected virtual void RegisterFunctions()
{
RegisterFunction("count", new CountBigQueryFunction());
RegisterFunction("count", new CountQueryFunction());
RegisterFunction("count_big", new CountBigQueryFunction());
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this still causing the breaking change you were writing about?

For example the following test would fail in Sql Server:

object count = s.CreateQuery("select count(*) from Simple").UniqueResult();
Assert.IsTrue(count is Int64);

because count effective return type in Sql Server is an int.

This changes the registration of HQL count for SQL-Server to map to SQL-Server count instead of count_big, which returns an int32 and fails if the count is bigger.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Isn't this still causing the breaking change you were writing about?

For HQL nothing is changed, the new GetEffectiveReturnType method is used only for Linq queries. CountQueryFunction.ReturnType still returns Int64, which is what HQL uses to determine the type, so hql queries using count will always be casted to Int64.

@@ -150,7 +150,7 @@ selectExpr
;

count
: ^(COUNT { Out("count("); } ( distinctOrAll ) ? countExpr { Out(")"); } )
: ^(c=COUNT { OutAggregateFunctionName(c); Out("("); } ( distinctOrAll ) ? countExpr { Out(")"); } )
Copy link
Member

Choose a reason for hiding this comment

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

Does this invalidate my previous comment? I mean, was this causing the SQL-Server HQL count to count_big mapping to be ignored by this piece of code, causing NHibernate to anyway use SQL-Server int32 count?

Copy link
Contributor Author

@maca88 maca88 Mar 29, 2020

Choose a reason for hiding this comment

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

I mean, was this causing the SQL-Server HQL count to count_big mapping to be ignored by this piece of code, causing NHibernate to anyway use SQL-Server int32 count?

Correct, count was hardcoded, which was the reason why changing from count to count_big in CountBigQueryFunction didn't worked.

hazzik
hazzik previously approved these changes Mar 30, 2020
@hazzik hazzik dismissed stale reviews from fredericDelaporte and themself via 83715ee March 31, 2020 20:15
@fredericDelaporte fredericDelaporte merged commit c0f5042 into nhibernate:master Apr 1, 2020
@fredericDelaporte fredericDelaporte added this to the 5.3 milestone Apr 1, 2020
georgi-yakimov pushed a commit to georgi-yakimov/nhibernate-core that referenced this pull request Apr 16, 2020
…_big (nhibernate#2061)

Co-authored-by: Alexander Zaytsev <hazzik@gmail.com>
/// <summary>
/// The function name or <see langword="null"/> when multiple functions/operators/statements are used.
/// </summary>
string FunctionName { get; }
Copy link
Member

Choose a reason for hiding this comment

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

I think this should be renamed to Name to reduce need of obsoleting things.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why not, renamed in #2359.

@@ -19,6 +20,19 @@ public AggregateNode(IToken token)
{
}

public string FunctionName
Copy link
Member

Choose a reason for hiding this comment

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

I think this could be an overgeneralization and should be refactored into a node-specific code unless you see that it can be extended for functions other than count and count_big

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This may be extended for string concatenation, which is supported by some databases (Sql server, MySql, Postgresql and Oracle), where different function names are used (LISTAGG, GROUP_CONCAT, STRING_AGG).

Copy link

Choose a reason for hiding this comment

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

@maca88 can you provide some sort of prototype of string_agg? I'm dying to use this with linq provider

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To my knowledge it is not possible to implement it without modifying NHibernate source code. It is on my todo list for the next release, so unfortunately you will have to wait.

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.

4 participants