Skip to content

Commit bd3fa29

Browse files
authored
Add locate support for SQLite (#2392)
* It supported since Release 3.7.15 On 2012-12-12) * Simulate locate(text, value, startIndex)
1 parent 1d8fb9c commit bd3fa29

File tree

8 files changed

+73
-41
lines changed

8 files changed

+73
-41
lines changed

src/NHibernate.Test/Async/Hql/HQLFunctions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,6 @@ public async Task SubStringAsync()
310310
[Test]
311311
public async Task LocateAsync()
312312
{
313-
AssumeFunctionSupported("locate");
314313
using (ISession s = OpenSession())
315314
{
316315
Animal a1 = new Animal("abcdef", 20);

src/NHibernate.Test/Async/Linq/FunctionTests.cs

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
using System.Text.RegularExpressions;
1414
using NHibernate.DomainModel;
1515
using NHibernate.DomainModel.Northwind.Entities;
16-
using NHibernate.Linq;
1716
using NUnit.Framework;
17+
using NHibernate.Linq;
1818

1919
namespace NHibernate.Test.Linq
2020
{
@@ -195,9 +195,6 @@ where e.FirstName.StartsWith("An")
195195
[Test]
196196
public async Task CharIndexFunctionAsync()
197197
{
198-
if (!TestDialect.SupportsLocate)
199-
Assert.Ignore("Locate function not supported.");
200-
201198
var raw = await ((from e in db.Employees select e.FirstName).ToListAsync());
202199
var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf('a') == 0).ToList();
203200

@@ -214,9 +211,6 @@ where lowerName.IndexOf('a') == 0
214211
[Test]
215212
public async Task CharIndexOffsetNegativeFunctionAsync()
216213
{
217-
if (!TestDialect.SupportsLocate)
218-
Assert.Ignore("Locate function not supported.");
219-
220214
var raw = await ((from e in db.Employees select e.FirstName).ToListAsync());
221215
var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf('a', 2) == -1).ToList();
222216

@@ -233,9 +227,6 @@ where lowerName.IndexOf('a', 2) == -1
233227
[Test]
234228
public async Task IndexOfFunctionExpressionAsync()
235229
{
236-
if (!TestDialect.SupportsLocate)
237-
Assert.Ignore("Locate function not supported.");
238-
239230
var raw = await ((from e in db.Employees select e.FirstName).ToListAsync());
240231
var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf("an") == 0).ToList();
241232

@@ -252,9 +243,6 @@ where lowerName.IndexOf("an") == 0
252243
[Test]
253244
public async Task IndexOfFunctionProjectionAsync()
254245
{
255-
if (!TestDialect.SupportsLocate)
256-
Assert.Ignore("Locate function not supported.");
257-
258246
var raw = await ((from e in db.Employees select e.FirstName).ToListAsync());
259247
var expected = raw.Select(x => x.ToLower()).Where(x => x.Contains("a")).Select(x => x.IndexOf("a", 1)).ToList();
260248

@@ -271,9 +259,6 @@ where lowerName.Contains("a")
271259
[Test]
272260
public async Task TwoFunctionExpressionAsync()
273261
{
274-
if (!TestDialect.SupportsLocate)
275-
Assert.Ignore("Locate function not supported.");
276-
277262
var query = from e in db.Employees
278263
where e.FirstName.IndexOf("A") == e.BirthDate.Value.Month
279264
select e.FirstName;

src/NHibernate.Test/Hql/HQLFunctions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,6 @@ public void SubString()
299299
[Test]
300300
public void Locate()
301301
{
302-
AssumeFunctionSupported("locate");
303302
using (ISession s = OpenSession())
304303
{
305304
Animal a1 = new Animal("abcdef", 20);

src/NHibernate.Test/Linq/FunctionTests.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Text.RegularExpressions;
44
using NHibernate.DomainModel;
55
using NHibernate.DomainModel.Northwind.Entities;
6-
using NHibernate.Linq;
76
using NUnit.Framework;
87

98
namespace NHibernate.Test.Linq
@@ -184,9 +183,6 @@ where e.FirstName.StartsWith("An")
184183
[Test]
185184
public void CharIndexFunction()
186185
{
187-
if (!TestDialect.SupportsLocate)
188-
Assert.Ignore("Locate function not supported.");
189-
190186
var raw = (from e in db.Employees select e.FirstName).ToList();
191187
var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf('a') == 0).ToList();
192188

@@ -203,9 +199,6 @@ where lowerName.IndexOf('a') == 0
203199
[Test]
204200
public void CharIndexOffsetNegativeFunction()
205201
{
206-
if (!TestDialect.SupportsLocate)
207-
Assert.Ignore("Locate function not supported.");
208-
209202
var raw = (from e in db.Employees select e.FirstName).ToList();
210203
var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf('a', 2) == -1).ToList();
211204

@@ -222,9 +215,6 @@ where lowerName.IndexOf('a', 2) == -1
222215
[Test]
223216
public void IndexOfFunctionExpression()
224217
{
225-
if (!TestDialect.SupportsLocate)
226-
Assert.Ignore("Locate function not supported.");
227-
228218
var raw = (from e in db.Employees select e.FirstName).ToList();
229219
var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf("an") == 0).ToList();
230220

@@ -241,9 +231,6 @@ where lowerName.IndexOf("an") == 0
241231
[Test]
242232
public void IndexOfFunctionProjection()
243233
{
244-
if (!TestDialect.SupportsLocate)
245-
Assert.Ignore("Locate function not supported.");
246-
247234
var raw = (from e in db.Employees select e.FirstName).ToList();
248235
var expected = raw.Select(x => x.ToLower()).Where(x => x.Contains("a")).Select(x => x.IndexOf("a", 1)).ToList();
249236

@@ -260,9 +247,6 @@ where lowerName.Contains("a")
260247
[Test]
261248
public void TwoFunctionExpression()
262249
{
263-
if (!TestDialect.SupportsLocate)
264-
Assert.Ignore("Locate function not supported.");
265-
266250
var query = from e in db.Employees
267251
where e.FirstName.IndexOf("A") == e.BirthDate.Value.Month
268252
select e.FirstName;

src/NHibernate.Test/TestCase.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,6 @@ protected DateTime RoundForDialect(DateTime value)
440440
private static readonly Dictionary<string, HashSet<System.Type>> DialectsNotSupportingStandardFunction =
441441
new Dictionary<string, HashSet<System.Type>>
442442
{
443-
{"locate", new HashSet<System.Type> {typeof (SQLiteDialect)}},
444443
{"bit_length", new HashSet<System.Type> {typeof (SQLiteDialect)}},
445444
{"extract", new HashSet<System.Type> {typeof (SQLiteDialect)}},
446445
{

src/NHibernate.Test/TestDialect.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public bool NativeGeneratorSupportsBulkInsertion
4444

4545
public virtual bool SupportsOperatorAll => true;
4646
public virtual bool SupportsOperatorSome => true;
47-
public virtual bool SupportsLocate => true;
4847

4948
public virtual bool SupportsFullJoin => true;
5049

src/NHibernate.Test/TestDialects/SQLiteTestDialect.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ public override bool SupportsOperatorSome
2222
get { return false; }
2323
}
2424

25-
public override bool SupportsLocate
26-
{
27-
get { return false; }
28-
}
29-
3025
public override bool SupportsFullJoin
3126
{
3227
get { return false; }

src/NHibernate/Dialect/SQLiteDialect.cs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34
using System.Data;
45
using System.Data.Common;
6+
using System.Linq;
57
using System.Text;
68
using NHibernate.Dialect.Function;
9+
using NHibernate.Engine;
710
using NHibernate.SqlCommand;
11+
using NHibernate.Type;
812
using NHibernate.Util;
913

1014
namespace NHibernate.Dialect
@@ -109,6 +113,7 @@ protected virtual void RegisterFunctions()
109113
RegisterFunction("trim", new AnsiTrimEmulationFunction());
110114
RegisterFunction("replace", new StandardSafeSQLFunction("replace", NHibernateUtil.String, 3));
111115
RegisterFunction("chr", new StandardSQLFunction("char", NHibernateUtil.Character));
116+
RegisterFunction("locate", new LocateFunction());
112117

113118
RegisterFunction("mod", new ModulusFunctionTemplate(false));
114119

@@ -513,5 +518,72 @@ protected override bool CastingIsRequired(string sqlType)
513518
return true;
514519
}
515520
}
521+
522+
[Serializable]
523+
private class LocateFunction : ISQLFunction, ISQLFunctionExtended
524+
{
525+
// Since v5.3
526+
[Obsolete("Use GetReturnType method instead.")]
527+
public IType ReturnType(IType columnType, IMapping mapping)
528+
{
529+
return NHibernateUtil.Int32;
530+
}
531+
532+
/// <inheritdoc />
533+
public IType GetReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
534+
{
535+
#pragma warning disable 618
536+
return ReturnType(argumentTypes.FirstOrDefault(), mapping);
537+
#pragma warning restore 618
538+
}
539+
540+
/// <inheritdoc />
541+
public IType GetEffectiveReturnType(IEnumerable<IType> argumentTypes, IMapping mapping, bool throwOnError)
542+
{
543+
return GetReturnType(argumentTypes, mapping, throwOnError);
544+
}
545+
546+
/// <inheritdoc />
547+
public string Name => "instr";
548+
549+
public bool HasArguments => true;
550+
551+
public bool HasParenthesesIfNoArguments => true;
552+
553+
public SqlString Render(IList args, ISessionFactoryImplementor factory)
554+
{
555+
if (args.Count != 2 && args.Count != 3)
556+
{
557+
throw new QueryException("'locate' function takes 2 or 3 arguments. Provided count: " + args.Count);
558+
}
559+
560+
if (args.Count == 2)
561+
{
562+
return new SqlString("instr(", args[1], ", ", args[0], ")");
563+
}
564+
565+
var text = args[1];
566+
var value = args[0];
567+
var startIndex = args[2];
568+
//ifnull(
569+
// nullif(
570+
// instr(substr(text, startIndex), value)
571+
// , 0)
572+
// + startIndex -1
573+
//, 0)
574+
return
575+
new SqlString(
576+
"ifnull(nullif(instr(substr(",
577+
text,
578+
", ",
579+
startIndex,
580+
"), ",
581+
value,
582+
"), 0) + ",
583+
startIndex,
584+
" -1, 0)"
585+
);
586+
}
587+
}
516588
}
517589
}

0 commit comments

Comments
 (0)