Skip to content

Commit 9427018

Browse files
authored
Add multiple arguments support for ISQLFunction (#2316)
1 parent 8ac6fa3 commit 9427018

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+883
-120
lines changed

src/NHibernate/Criterion/SqlFunctionProjection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ private IType GetReturnType(ICriteria criteria, ICriteriaQuery criteriaQuery)
125125

126126
var resultType = returnType ?? returnTypeProjection?.GetTypes(criteria, criteriaQuery).FirstOrDefault();
127127

128-
return sqlFunction.ReturnType(resultType, criteriaQuery.Factory);
128+
return sqlFunction.GetReturnType(new[] {resultType}, criteriaQuery.Factory, true);
129129
}
130130

131131
public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)

src/NHibernate/Dialect/DB2Dialect.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public DB2Dialect()
131131
RegisterFunction("length", new StandardSQLFunction("length", NHibernateUtil.Int32));
132132
RegisterFunction("ltrim", new StandardSQLFunction("ltrim"));
133133

134-
RegisterFunction("mod", new StandardSQLFunction("mod", NHibernateUtil.Int32));
134+
RegisterFunction("mod", new ModulusFunction(true, false));
135135

136136
RegisterFunction("substring", new StandardSQLFunction("substr", NHibernateUtil.String));
137137

src/NHibernate/Dialect/Dialect.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ protected Dialect()
9494
RegisterFunction("coalesce", new StandardSQLFunction("coalesce"));
9595
RegisterFunction("nullif", new StandardSQLFunction("nullif"));
9696
RegisterFunction("abs", new StandardSQLFunction("abs"));
97-
RegisterFunction("mod", new StandardSQLFunction("mod", NHibernateUtil.Int32));
97+
RegisterFunction("mod", new ModulusFunction(false, false));
9898
RegisterFunction("sqrt", new StandardSQLFunction("sqrt", NHibernateUtil.Double));
9999
RegisterFunction("upper", new StandardSQLFunction("upper"));
100100
RegisterFunction("lower", new StandardSQLFunction("lower"));

src/NHibernate/Dialect/FirebirdDialect.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Generic;
34
using System.Data;
45
using System.Data.Common;
56
using NHibernate.Dialect.Function;
@@ -147,7 +148,7 @@ public CastedFunction(string name, IType returnType) : base(name, returnType, fa
147148

148149
public override SqlString Render(IList args, ISessionFactoryImplementor factory)
149150
{
150-
return new SqlString("cast('", Name, "' as ", FunctionReturnType.SqlTypes(factory)[0].ToString(), ")");
151+
return new SqlString("cast('", FunctionName, "' as ", FunctionReturnType.SqlTypes(factory)[0].ToString(), ")");
151152
}
152153
}
153154

@@ -160,7 +161,7 @@ public CurrentTimeStamp() : base("current_timestamp", NHibernateUtil.LocalDateTi
160161

161162
public override SqlString Render(IList args, ISessionFactoryImplementor factory)
162163
{
163-
return new SqlString(Name);
164+
return new SqlString(FunctionName);
164165
}
165166
}
166167

@@ -205,7 +206,7 @@ public override string SelectGUIDString
205206
}
206207

207208
[Serializable]
208-
private class PositionFunction : ISQLFunction
209+
private class PositionFunction : ISQLFunction, ISQLFunctionExtended
209210
{
210211
// The cast is needed, at least in the case that ?3 is a named integer parameter, otherwise firebird will generate an error.
211212
// We have a unit test to cover this potential firebird bug.
@@ -214,11 +215,28 @@ private class PositionFunction : ISQLFunction
214215
private static readonly ISQLFunction LocateWith3Params = new SQLFunctionTemplate(NHibernateUtil.Int32,
215216
"position(?1, ?2, cast(?3 as int))");
216217

218+
// Since v5.3
219+
[Obsolete("Use GetReturnType method instead.")]
217220
public IType ReturnType(IType columnType, IMapping mapping)
218221
{
219222
return NHibernateUtil.Int32;
220223
}
221224

225+
/// <inheritdoc />
226+
public IType GetReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
227+
{
228+
return NHibernateUtil.Int32;
229+
}
230+
231+
/// <inheritdoc />
232+
public IType GetEffectiveReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
233+
{
234+
return GetReturnType(argumentTypes, mapping, throwOnError);
235+
}
236+
237+
/// <inheritdoc />
238+
public string FunctionName => "position";
239+
222240
public bool HasArguments
223241
{
224242
get { return true; }
@@ -418,7 +436,8 @@ private void OverrideStandardHQLFunctions()
418436
RegisterFunction("nullif", new StandardSafeSQLFunction("nullif", 2));
419437
RegisterFunction("lower", new StandardSafeSQLFunction("lower", NHibernateUtil.String, 1));
420438
RegisterFunction("upper", new StandardSafeSQLFunction("upper", NHibernateUtil.String, 1));
421-
RegisterFunction("mod", new StandardSafeSQLFunction("mod", NHibernateUtil.Double, 2));
439+
// Modulo does not throw for decimal parameters but they are casted to int by Firebird, which produces unexpected results
440+
RegisterFunction("mod", new ModulusFunction(false, false));
422441
RegisterFunction("str", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as VARCHAR(255))"));
423442
RegisterFunction("strguid", new StandardSQLFunction("uuid_to_char", NHibernateUtil.String));
424443
RegisterFunction("sysdate", new CastedFunction("today", NHibernateUtil.Date));
@@ -437,7 +456,7 @@ private void RegisterFirebirdServerEmbeddedFunctions()
437456
RegisterFunction("yesterday", new CastedFunction("yesterday", NHibernateUtil.Date));
438457
RegisterFunction("tomorrow", new CastedFunction("tomorrow", NHibernateUtil.Date));
439458
RegisterFunction("now", new CastedFunction("now", NHibernateUtil.DateTime));
440-
RegisterFunction("iif", new StandardSafeSQLFunction("iif", 3));
459+
RegisterFunction("iif", new IifSafeSQLFunction());
441460
// New embedded functions in FB 2.0 (http://www.firebirdsql.org/rlsnotes20/rnfbtwo-str.html#str-string-func)
442461
RegisterFunction("char_length", new StandardSafeSQLFunction("char_length", NHibernateUtil.Int64, 1));
443462
RegisterFunction("bit_length", new StandardSafeSQLFunction("bit_length", NHibernateUtil.Int64, 1));

src/NHibernate/Dialect/Function/AnsiSubstringFunction.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
35
using System.Text;
46
using NHibernate.Engine;
57
using NHibernate.SqlCommand;
@@ -22,15 +24,34 @@ namespace NHibernate.Dialect.Function
2224
///]]>
2325
/// </remarks>
2426
[Serializable]
25-
public class AnsiSubstringFunction : ISQLFunction
27+
public class AnsiSubstringFunction : ISQLFunction, ISQLFunctionExtended
2628
{
2729
#region ISQLFunction Members
2830

31+
// Since v5.3
32+
[Obsolete("Use GetReturnType method instead.")]
2933
public IType ReturnType(IType columnType, IMapping mapping)
3034
{
3135
return NHibernateUtil.String;
3236
}
3337

38+
/// <inheritdoc />
39+
public IType GetReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
40+
{
41+
#pragma warning disable 618
42+
return ReturnType(argumentTypes.FirstOrDefault(), mapping);
43+
#pragma warning restore 618
44+
}
45+
46+
/// <inheritdoc />
47+
public IType GetEffectiveReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
48+
{
49+
return GetReturnType(argumentTypes, mapping, throwOnError);
50+
}
51+
52+
/// <inheritdoc />
53+
public string FunctionName => "substring";
54+
3455
public bool HasArguments
3556
{
3657
get { return true; }

src/NHibernate/Dialect/Function/AnsiTrimEmulationFunction.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Collections;
33
using System.Collections.Generic;
4-
4+
using System.Linq;
55
using NHibernate.Engine;
66
using NHibernate.SqlCommand;
77
using NHibernate.Type;
@@ -17,7 +17,7 @@ namespace NHibernate.Dialect.Function
1717
/// functionality.
1818
/// </summary>
1919
[Serializable]
20-
public class AnsiTrimEmulationFunction : ISQLFunction, IFunctionGrammar
20+
public class AnsiTrimEmulationFunction : ISQLFunction, IFunctionGrammar, ISQLFunctionExtended
2121
{
2222
private static readonly ISQLFunction LeadingSpaceTrim = new SQLFunctionTemplate(NHibernateUtil.String, "ltrim( ?1 )");
2323
private static readonly ISQLFunction TrailingSpaceTrim = new SQLFunctionTemplate(NHibernateUtil.String, "rtrim( ?1 )");
@@ -76,11 +76,30 @@ public AnsiTrimEmulationFunction(string replaceFunction)
7676

7777
#region ISQLFunction Members
7878

79+
// Since v5.3
80+
[Obsolete("Use GetReturnType method instead.")]
7981
public IType ReturnType(IType columnType, IMapping mapping)
8082
{
8183
return NHibernateUtil.String;
8284
}
8385

86+
/// <inheritdoc />
87+
public IType GetReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
88+
{
89+
#pragma warning disable 618
90+
return ReturnType(argumentTypes.FirstOrDefault(), mapping);
91+
#pragma warning restore 618
92+
}
93+
94+
/// <inheritdoc />
95+
public IType GetEffectiveReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
96+
{
97+
return GetReturnType(argumentTypes, mapping, throwOnError);
98+
}
99+
100+
/// <inheritdoc />
101+
public string FunctionName => null;
102+
84103
public bool HasArguments
85104
{
86105
get { return true; }
Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
2+
using System.Collections.Generic;
23
using NHibernate.Engine;
3-
using NHibernate.SqlTypes;
44
using NHibernate.Type;
55

66
namespace NHibernate.Dialect.Function
@@ -10,27 +10,22 @@ class AvgQueryFunctionInfo : ClassicAggregateFunction
1010
{
1111
public AvgQueryFunctionInfo() : base("avg", false) { }
1212

13+
// Since v5.3
14+
[Obsolete("Use GetReturnType method instead.")]
1315
public override IType ReturnType(IType columnType, IMapping mapping)
1416
{
15-
if (columnType == null)
16-
{
17-
throw new ArgumentNullException("columnType");
18-
}
19-
SqlType[] sqlTypes;
20-
try
21-
{
22-
sqlTypes = columnType.SqlTypes(mapping);
23-
}
24-
catch (MappingException me)
25-
{
26-
throw new QueryException(me);
27-
}
17+
return GetReturnType(new[] {columnType}, mapping, true);
18+
}
2819

29-
if (sqlTypes.Length != 1)
20+
/// <inheritdoc />
21+
public override IType GetReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
22+
{
23+
if (!TryGetArgumentType(argumentTypes, mapping, throwOnError, out _, out _))
3024
{
31-
throw new QueryException("multi-column type can not be in avg()");
25+
return null;
3226
}
27+
3328
return NHibernateUtil.Double;
3429
}
3530
}
36-
}
31+
}

src/NHibernate/Dialect/Function/BitwiseFunctionOperation.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
35
using NHibernate.Engine;
46
using NHibernate.SqlCommand;
57
using NHibernate.Type;
@@ -27,8 +29,9 @@ namespace NHibernate.Dialect.Function
2729
/// Treats bitwise operations as SQL function calls.
2830
/// </summary>
2931
[Serializable]
30-
public class BitwiseFunctionOperation : ISQLFunction
32+
public class BitwiseFunctionOperation : ISQLFunction, ISQLFunctionExtended
3133
{
34+
// TODO 6.0: convert FunctionName to read-only auto-property
3235
private readonly string _functionName;
3336

3437
/// <summary>
@@ -45,11 +48,30 @@ public BitwiseFunctionOperation(string functionName)
4548
#region ISQLFunction Members
4649

4750
/// <inheritdoc />
51+
// Since v5.3
52+
[Obsolete("Use GetReturnType method instead.")]
4853
public IType ReturnType(IType columnType, IMapping mapping)
4954
{
5055
return NHibernateUtil.Int64;
5156
}
5257

58+
/// <inheritdoc />
59+
public IType GetReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
60+
{
61+
#pragma warning disable 618
62+
return ReturnType(argumentTypes.FirstOrDefault(), mapping);
63+
#pragma warning restore 618
64+
}
65+
66+
/// <inheritdoc />
67+
public virtual IType GetEffectiveReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
68+
{
69+
return GetReturnType(argumentTypes, mapping, throwOnError);
70+
}
71+
72+
/// <inheritdoc />
73+
public string FunctionName => _functionName;
74+
5375
/// <inheritdoc />
5476
public bool HasArguments => true;
5577

src/NHibernate/Dialect/Function/BitwiseNativeOperation.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
35
using NHibernate.Engine;
46
using NHibernate.SqlCommand;
57
using NHibernate.Type;
@@ -32,7 +34,7 @@ namespace NHibernate.Dialect.Function
3234
/// Treats bitwise operations as native operations.
3335
/// </summary>
3436
[Serializable]
35-
public class BitwiseNativeOperation : ISQLFunction
37+
public class BitwiseNativeOperation : ISQLFunction, ISQLFunctionExtended
3638
{
3739
private readonly string _sqlOpToken;
3840
private readonly bool _isUnary;
@@ -65,11 +67,30 @@ public BitwiseNativeOperation(string sqlOpToken, bool isUnary)
6567
#region ISQLFunction Members
6668

6769
/// <inheritdoc />
70+
// Since v5.3
71+
[Obsolete("Use GetReturnType method instead.")]
6872
public IType ReturnType(IType columnType, IMapping mapping)
6973
{
7074
return NHibernateUtil.Int64;
7175
}
7276

77+
/// <inheritdoc />
78+
public IType GetReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
79+
{
80+
#pragma warning disable 618
81+
return ReturnType(argumentTypes.FirstOrDefault(), mapping);
82+
#pragma warning restore 618
83+
}
84+
85+
/// <inheritdoc />
86+
public virtual IType GetEffectiveReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
87+
{
88+
return GetReturnType(argumentTypes, mapping, throwOnError);
89+
}
90+
91+
/// <inheritdoc />
92+
public string FunctionName => null;
93+
7394
/// <inheritdoc />
7495
public bool HasArguments => true;
7596

src/NHibernate/Dialect/Function/CastFunction.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
35
using System.Xml;
46
using NHibernate.Engine;
57
using NHibernate.SqlCommand;
@@ -12,17 +14,36 @@ namespace NHibernate.Dialect.Function
1214
/// ANSI-SQL style cast(foo as type) where the type is a NHibernate type
1315
/// </summary>
1416
[Serializable]
15-
public class CastFunction : ISQLFunction, IFunctionGrammar
17+
public class CastFunction : ISQLFunction, IFunctionGrammar, ISQLFunctionExtended
1618
{
1719
#region ISQLFunction Members
1820

21+
// Since v5.3
22+
[Obsolete("Use GetReturnType method instead.")]
1923
public IType ReturnType(IType columnType, IMapping mapping)
2024
{
2125
//note there is a weird implementation in the client side
2226
//TODO: cast that use only costant are not supported in SELECT. Ex: cast(5 as string)
2327
return columnType;
2428
}
2529

30+
/// <inheritdoc />
31+
public IType GetReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
32+
{
33+
#pragma warning disable 618
34+
return ReturnType(argumentTypes.FirstOrDefault(), mapping);
35+
#pragma warning restore 618
36+
}
37+
38+
/// <inheritdoc />
39+
public virtual IType GetEffectiveReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
40+
{
41+
return GetReturnType(argumentTypes, mapping, throwOnError);
42+
}
43+
44+
/// <inheritdoc />
45+
public string FunctionName => "cast";
46+
2647
public bool HasArguments
2748
{
2849
get { return true; }

0 commit comments

Comments
 (0)