diff --git a/src/NHibernate.Test/Async/Hql/HQLFunctions.cs b/src/NHibernate.Test/Async/Hql/HQLFunctions.cs index fa16f2ca8c9..a9c304aaa66 100644 --- a/src/NHibernate.Test/Async/Hql/HQLFunctions.cs +++ b/src/NHibernate.Test/Async/Hql/HQLFunctions.cs @@ -310,7 +310,6 @@ public async Task SubStringAsync() [Test] public async Task LocateAsync() { - AssumeFunctionSupported("locate"); using (ISession s = OpenSession()) { Animal a1 = new Animal("abcdef", 20); diff --git a/src/NHibernate.Test/Async/Linq/FunctionTests.cs b/src/NHibernate.Test/Async/Linq/FunctionTests.cs index 3097015a7e8..f65b9dc9854 100644 --- a/src/NHibernate.Test/Async/Linq/FunctionTests.cs +++ b/src/NHibernate.Test/Async/Linq/FunctionTests.cs @@ -13,8 +13,8 @@ using System.Text.RegularExpressions; using NHibernate.DomainModel; using NHibernate.DomainModel.Northwind.Entities; -using NHibernate.Linq; using NUnit.Framework; +using NHibernate.Linq; namespace NHibernate.Test.Linq { @@ -195,9 +195,6 @@ where e.FirstName.StartsWith("An") [Test] public async Task CharIndexFunctionAsync() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var raw = await ((from e in db.Employees select e.FirstName).ToListAsync()); var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf('a') == 0).ToList(); @@ -214,9 +211,6 @@ where lowerName.IndexOf('a') == 0 [Test] public async Task CharIndexOffsetNegativeFunctionAsync() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var raw = await ((from e in db.Employees select e.FirstName).ToListAsync()); var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf('a', 2) == -1).ToList(); @@ -233,9 +227,6 @@ where lowerName.IndexOf('a', 2) == -1 [Test] public async Task IndexOfFunctionExpressionAsync() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var raw = await ((from e in db.Employees select e.FirstName).ToListAsync()); var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf("an") == 0).ToList(); @@ -252,9 +243,6 @@ where lowerName.IndexOf("an") == 0 [Test] public async Task IndexOfFunctionProjectionAsync() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var raw = await ((from e in db.Employees select e.FirstName).ToListAsync()); var expected = raw.Select(x => x.ToLower()).Where(x => x.Contains("a")).Select(x => x.IndexOf("a", 1)).ToList(); @@ -271,9 +259,6 @@ where lowerName.Contains("a") [Test] public async Task TwoFunctionExpressionAsync() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var query = from e in db.Employees where e.FirstName.IndexOf("A") == e.BirthDate.Value.Month select e.FirstName; diff --git a/src/NHibernate.Test/Hql/HQLFunctions.cs b/src/NHibernate.Test/Hql/HQLFunctions.cs index 89671f6a025..1a2b80b0efd 100644 --- a/src/NHibernate.Test/Hql/HQLFunctions.cs +++ b/src/NHibernate.Test/Hql/HQLFunctions.cs @@ -299,7 +299,6 @@ public void SubString() [Test] public void Locate() { - AssumeFunctionSupported("locate"); using (ISession s = OpenSession()) { Animal a1 = new Animal("abcdef", 20); diff --git a/src/NHibernate.Test/Linq/FunctionTests.cs b/src/NHibernate.Test/Linq/FunctionTests.cs index 81c369b0374..127429d11b8 100644 --- a/src/NHibernate.Test/Linq/FunctionTests.cs +++ b/src/NHibernate.Test/Linq/FunctionTests.cs @@ -3,7 +3,6 @@ using System.Text.RegularExpressions; using NHibernate.DomainModel; using NHibernate.DomainModel.Northwind.Entities; -using NHibernate.Linq; using NUnit.Framework; namespace NHibernate.Test.Linq @@ -184,9 +183,6 @@ where e.FirstName.StartsWith("An") [Test] public void CharIndexFunction() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var raw = (from e in db.Employees select e.FirstName).ToList(); var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf('a') == 0).ToList(); @@ -203,9 +199,6 @@ where lowerName.IndexOf('a') == 0 [Test] public void CharIndexOffsetNegativeFunction() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var raw = (from e in db.Employees select e.FirstName).ToList(); var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf('a', 2) == -1).ToList(); @@ -222,9 +215,6 @@ where lowerName.IndexOf('a', 2) == -1 [Test] public void IndexOfFunctionExpression() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var raw = (from e in db.Employees select e.FirstName).ToList(); var expected = raw.Select(x => x.ToLower()).Where(x => x.IndexOf("an") == 0).ToList(); @@ -241,9 +231,6 @@ where lowerName.IndexOf("an") == 0 [Test] public void IndexOfFunctionProjection() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var raw = (from e in db.Employees select e.FirstName).ToList(); var expected = raw.Select(x => x.ToLower()).Where(x => x.Contains("a")).Select(x => x.IndexOf("a", 1)).ToList(); @@ -260,9 +247,6 @@ where lowerName.Contains("a") [Test] public void TwoFunctionExpression() { - if (!TestDialect.SupportsLocate) - Assert.Ignore("Locate function not supported."); - var query = from e in db.Employees where e.FirstName.IndexOf("A") == e.BirthDate.Value.Month select e.FirstName; diff --git a/src/NHibernate.Test/TestCase.cs b/src/NHibernate.Test/TestCase.cs index 14fc4ad1460..d98586d2201 100644 --- a/src/NHibernate.Test/TestCase.cs +++ b/src/NHibernate.Test/TestCase.cs @@ -440,7 +440,6 @@ protected DateTime RoundForDialect(DateTime value) private static readonly Dictionary> DialectsNotSupportingStandardFunction = new Dictionary> { - {"locate", new HashSet {typeof (SQLiteDialect)}}, {"bit_length", new HashSet {typeof (SQLiteDialect)}}, {"extract", new HashSet {typeof (SQLiteDialect)}}, { diff --git a/src/NHibernate.Test/TestDialect.cs b/src/NHibernate.Test/TestDialect.cs index c62c4a7cb28..cc925423d2a 100644 --- a/src/NHibernate.Test/TestDialect.cs +++ b/src/NHibernate.Test/TestDialect.cs @@ -44,7 +44,6 @@ public bool NativeGeneratorSupportsBulkInsertion public virtual bool SupportsOperatorAll => true; public virtual bool SupportsOperatorSome => true; - public virtual bool SupportsLocate => true; public virtual bool SupportsFullJoin => true; diff --git a/src/NHibernate.Test/TestDialects/SQLiteTestDialect.cs b/src/NHibernate.Test/TestDialects/SQLiteTestDialect.cs index 3bfbefc2c7f..b0be2bd35e5 100644 --- a/src/NHibernate.Test/TestDialects/SQLiteTestDialect.cs +++ b/src/NHibernate.Test/TestDialects/SQLiteTestDialect.cs @@ -22,11 +22,6 @@ public override bool SupportsOperatorSome get { return false; } } - public override bool SupportsLocate - { - get { return false; } - } - public override bool SupportsFullJoin { get { return false; } diff --git a/src/NHibernate/Dialect/SQLiteDialect.cs b/src/NHibernate/Dialect/SQLiteDialect.cs index fa71342185f..39233fd2b56 100644 --- a/src/NHibernate/Dialect/SQLiteDialect.cs +++ b/src/NHibernate/Dialect/SQLiteDialect.cs @@ -1,10 +1,14 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Linq; using System.Text; using NHibernate.Dialect.Function; +using NHibernate.Engine; using NHibernate.SqlCommand; +using NHibernate.Type; using NHibernate.Util; namespace NHibernate.Dialect @@ -109,6 +113,7 @@ protected virtual void RegisterFunctions() RegisterFunction("trim", new AnsiTrimEmulationFunction()); RegisterFunction("replace", new StandardSafeSQLFunction("replace", NHibernateUtil.String, 3)); RegisterFunction("chr", new StandardSQLFunction("char", NHibernateUtil.Character)); + RegisterFunction("locate", new LocateFunction()); RegisterFunction("mod", new ModulusFunctionTemplate(false)); @@ -513,5 +518,72 @@ protected override bool CastingIsRequired(string sqlType) return true; } } + + [Serializable] + private class LocateFunction : ISQLFunction, ISQLFunctionExtended + { + // Since v5.3 + [Obsolete("Use GetReturnType method instead.")] + public IType ReturnType(IType columnType, IMapping mapping) + { + return NHibernateUtil.Int32; + } + + /// + public IType GetReturnType(IEnumerable argumentTypes, IMapping mapping, bool throwOnError) + { +#pragma warning disable 618 + return ReturnType(argumentTypes.FirstOrDefault(), mapping); +#pragma warning restore 618 + } + + /// + public IType GetEffectiveReturnType(IEnumerable argumentTypes, IMapping mapping, bool throwOnError) + { + return GetReturnType(argumentTypes, mapping, throwOnError); + } + + /// + public string Name => "instr"; + + public bool HasArguments => true; + + public bool HasParenthesesIfNoArguments => true; + + public SqlString Render(IList args, ISessionFactoryImplementor factory) + { + if (args.Count != 2 && args.Count != 3) + { + throw new QueryException("'locate' function takes 2 or 3 arguments. Provided count: " + args.Count); + } + + if (args.Count == 2) + { + return new SqlString("instr(", args[1], ", ", args[0], ")"); + } + + var text = args[1]; + var value = args[0]; + var startIndex = args[2]; + //ifnull( + // nullif( + // instr(substr(text, startIndex), value) + // , 0) + // + startIndex -1 + //, 0) + return + new SqlString( + "ifnull(nullif(instr(substr(", + text, + ", ", + startIndex, + "), ", + value, + "), 0) + ", + startIndex, + " -1, 0)" + ); + } + } } }