-
Notifications
You must be signed in to change notification settings - Fork 933
Add support for single-argument truncate to dialects that do not support it natively #1597
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,9 +12,20 @@ namespace NHibernate.Dialect.Function | |
[Serializable] | ||
public class RoundEmulatingSingleParameterFunction : ISQLFunction | ||
{ | ||
private static readonly ISQLFunction SingleParamRound = new SQLFunctionTemplate(null, "round(?1, 0)"); | ||
private readonly ISQLFunction _singleParamRound; | ||
private readonly ISQLFunction _round; | ||
private readonly string _name; | ||
|
||
private static readonly ISQLFunction Round = new StandardSQLFunction("round"); | ||
/// <summary> | ||
/// Constructs a <c>RoundEmulatingSingleParameterFunction</c>. | ||
/// </summary> | ||
/// <param name="name">The SQL name of the round function to call.</param> | ||
public RoundEmulatingSingleParameterFunction(string name) | ||
{ | ||
_singleParamRound = new SQLFunctionTemplate(null, $"{name}(?1, 0)"); | ||
_round = new StandardSQLFunction(name); | ||
_name = name; | ||
} | ||
|
||
public IType ReturnType(IType columnType, IMapping mapping) => columnType; | ||
|
||
|
@@ -24,9 +35,9 @@ public class RoundEmulatingSingleParameterFunction : ISQLFunction | |
|
||
public SqlString Render(IList args, ISessionFactoryImplementor factory) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be much lightweight if we rewrite this function explicitly not using the template functions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Either I do not get what you are thinking about, or it will be slightly more CPU lightweight but with a lot more code, rewriting a var buf = new SqlStringBuilder();
buf.Add(_name)
.Add("(");
for (var i = 0; i < args.Count; i++)
{
var arg = args[i];
if (arg is Parameter || arg is SqlString)
{
buf.AddObject(arg);
}
else
{
buf.Add(arg.ToString());
}
if (i < (args.Count - 1)) buf.Add(", ");
}
if (args.Count == 1)
buf.Add(", 0");
return buf.Add(")").ToSqlString(); And this is an almost duplicate of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would you need a loop here? You have 2 arguments.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be breaking for dialects supporting more than two arguments (SQL-Server |
||
return args.Count == 1 ? SingleParamRound.Render(args, factory) : Round.Render(args, factory); | ||
return args.Count == 1 ? _singleParamRound.Render(args, factory) : _round.Render(args, factory); | ||
} | ||
|
||
public override string ToString() => "round"; | ||
public override string ToString() => _name; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,7 +69,9 @@ public PostgreSQLDialect() | |
RegisterFunction("mod", new SQLFunctionTemplate(NHibernateUtil.Int32, "((?1) % (?2))")); | ||
|
||
RegisterFunction("sign", new StandardSQLFunction("sign", NHibernateUtil.Int32)); | ||
RegisterFunction("round", new RoundFunction()); | ||
RegisterFunction("round", new RoundFunction(false)); | ||
RegisterFunction("truncate", new RoundFunction(true)); | ||
RegisterFunction("trunc", new RoundFunction(true)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As written here, I consider supporting dialect specific names ( |
||
|
||
// Trigonometric functions. | ||
RegisterFunction("acos", new StandardSQLFunction("acos", NHibernateUtil.Double)); | ||
|
@@ -322,12 +324,34 @@ public override string CurrentTimestampSelectString | |
private class RoundFunction : ISQLFunction | ||
{ | ||
private static readonly ISQLFunction Round = new StandardSQLFunction("round"); | ||
private static readonly ISQLFunction Truncate = new StandardSQLFunction("trunc"); | ||
|
||
// PostgreSQL round with two arguments only accepts decimal as input, thus the cast. | ||
// PostgreSQL round/trunc with two arguments only accepts decimal as input, thus the cast. | ||
// It also yields only decimal, but for emulating similar behavior to other databases, we need | ||
// to have it converted to the original input type, which will be done by NHibernate thanks to | ||
// not specifying the function type. | ||
private static readonly ISQLFunction RoundWith2Params = new SQLFunctionTemplate(null, "round(cast(?1 as numeric), ?2)"); | ||
private static readonly ISQLFunction TruncateWith2Params = new SQLFunctionTemplate(null, "trunc(cast(?1 as numeric), ?2)"); | ||
|
||
private readonly ISQLFunction _singleParamFunction; | ||
private readonly ISQLFunction _twoParamFunction; | ||
private readonly string _name; | ||
|
||
public RoundFunction(bool truncate) | ||
{ | ||
if (truncate) | ||
{ | ||
_singleParamFunction = Truncate; | ||
_twoParamFunction = TruncateWith2Params; | ||
_name = "truncate"; | ||
} | ||
else | ||
{ | ||
_singleParamFunction = Round; | ||
_twoParamFunction = RoundWith2Params; | ||
_name = "round"; | ||
} | ||
} | ||
|
||
public IType ReturnType(IType columnType, IMapping mapping) => columnType; | ||
|
||
|
@@ -337,10 +361,10 @@ private class RoundFunction : ISQLFunction | |
|
||
public SqlString Render(IList args, ISessionFactoryImplementor factory) | ||
{ | ||
return args.Count == 2 ? RoundWith2Params.Render(args, factory) : Round.Render(args, factory); | ||
return args.Count == 2 ? _twoParamFunction.Render(args, factory) : _singleParamFunction.Render(args, factory); | ||
} | ||
|
||
public override string ToString() => "round"; | ||
public override string ToString() => _name; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,12 +140,13 @@ protected virtual void RegisterMathFunctions() | |
RegisterFunction("radians", new StandardSQLFunction("radians", NHibernateUtil.Double)); | ||
RegisterFunction("rand", new StandardSQLFunction("rand", NHibernateUtil.Double)); | ||
RegisterFunction("remainder", new StandardSQLFunction("remainder")); | ||
RegisterFunction("round", new StandardSQLFunction("round")); | ||
RegisterFunction("round", new RoundEmulatingSingleParameterFunction("round")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tested with an Anywhere 17, using this custom driver. |
||
RegisterFunction("sign", new StandardSQLFunction("sign", NHibernateUtil.Int32)); | ||
RegisterFunction("sin", new StandardSQLFunction("sin", NHibernateUtil.Double)); | ||
RegisterFunction("sqrt", new StandardSQLFunction("sqrt", NHibernateUtil.Double)); | ||
RegisterFunction("tan", new StandardSQLFunction("tan", NHibernateUtil.Double)); | ||
RegisterFunction("truncate", new StandardSQLFunction("truncate")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed, it was an invalid registration. |
||
RegisterFunction("truncnum", new RoundEmulatingSingleParameterFunction("truncnum")); | ||
RegisterFunction("truncate", new RoundEmulatingSingleParameterFunction("truncnum")); | ||
} | ||
|
||
protected virtual void RegisterXmlFunctions() | ||
|
@@ -343,8 +344,6 @@ protected virtual void RegisterMiscellaneousFunctions() | |
RegisterFunction("transactsql", new StandardSQLFunction("transactsql", NHibernateUtil.String)); | ||
RegisterFunction("varexists", new StandardSQLFunction("varexists", NHibernateUtil.Int32)); | ||
RegisterFunction("watcomsql", new StandardSQLFunction("watcomsql", NHibernateUtil.String)); | ||
RegisterFunction("truncnum", new StandardSafeSQLFunction("truncnum", 2)); | ||
RegisterFunction("truncate", new StandardSafeSQLFunction("truncnum", 2)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved to |
||
} | ||
|
||
#region private static readonly string[] DialectKeywords = { ... } | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Class is public, so you need to add a default constructor.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For avoiding a breaking change? This class has not yet been released. It was not existing in 5.0.3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. Fine then.