From e33120c74d253fd692b317c689ac0b18a71afa08 Mon Sep 17 00:00:00 2001 From: CSharper2010 Date: Tue, 18 Jul 2023 12:15:10 +0300 Subject: [PATCH 01/15] Test case --- .../NHSpecificTest/GH3334/Entity.cs | 33 ++++ .../NHSpecificTest/GH3334/Fixture.cs | 174 ++++++++++++++++++ .../NHSpecificTest/GH3334/Mappings.hbm.xml | 36 ++++ 3 files changed, 243 insertions(+) create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs new file mode 100644 index 00000000000..864608faf72 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3334 +{ + public class Entity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + public virtual OtherEntity OtherEntity { get; set; } + } + + public class ChildEntity + { + public virtual int Id { get; set; } + public virtual Entity Parent { get; set; } + public virtual string Name { get; set; } + public virtual GrandChildEntity Child { get; set; } + } + + public class GrandChildEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public class OtherEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Entities { get; set; } = new HashSet(); + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs new file mode 100644 index 00000000000..96eabfd456a --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs @@ -0,0 +1,174 @@ +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3334 +{ + [TestFixture] + public class Fixture : BugTestCase + { + [OneTimeSetUp] + public void OneTimeSetUp() + { + using (var session = OpenSession()) + using (var t = session.BeginTransaction()) + { + var parent = new Entity + { + Name = "Parent1", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "GrandChild" } } } + }; + session.Save(parent); + parent = new Entity + { + Name = "Parent2", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "XGrandChild" } } } + }; + var other = new OtherEntity { Name = "ABC", Entities = {parent}}; + parent.OtherEntity = other; + session.Save(parent); + session.Save(other); + t.Commit(); + } + + Sfi.Statistics.IsStatisticsEnabled = true; + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + Sfi.Statistics.IsStatisticsEnabled = false; + + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from GrandChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + session.CreateQuery("delete from OtherEntity").ExecuteUpdate(); + + transaction.Commit(); + } + + public class TestCaseItem + { + public string Name { get; } + public string Hql { get; } + public int LineNumber { get; } + + public TestCaseItem(string name, string hql, [CallerLineNumber] int lineNumber = 0) + { + Name = name; + Hql = hql; + LineNumber = lineNumber; + } + + public override string ToString() => $"{LineNumber:0000}: {Name}"; + } + + public static IEnumerable GetNoExceptionOnExecuteQueryTestCases() + { + /* does not work because of inner join or theta join created for many-to-one + @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + WHERE + child.Child.Name like 'G%' + OR ROOT.OtherEntity.Name like 'A%' + )");*/ + + yield return new("Basic Elements case 1 FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("Basic Elements case 2 FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.OtherEntity) AS otherEntity + WHERE + otherEntity.Name like 'A%' + )"); + yield return new("HQL Elements FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + )"); + yield return new("HQL Elements FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + yield return new("HQL Entity FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + ) + )"); + yield return new("HQL Entity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + ) + )"); + } + + [Test, TestCaseSource(nameof(GetNoExceptionOnExecuteQueryTestCases))] + public void NoExceptionOnExecuteQuery(TestCaseItem testCase) + { + using var session = OpenSession(); + using var _ = session.BeginTransaction(); + + var q = session.CreateQuery(testCase.Hql); + Assert.That(q.List(), Has.Count.EqualTo(1)); + } + + protected override bool CheckDatabaseWasCleaned() + { + // same set of objects for each test + return true; + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml new file mode 100644 index 00000000000..1f5bcdfe8e6 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 57e26233ea57c1a614509d6f6a0202929eaa052c Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 12:45:57 +0300 Subject: [PATCH 02/15] More test cases and clean up --- .../NHSpecificTest/GH3334/Fixture.cs | 66 +++++++++++-------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs index 96eabfd456a..4ee2d1fda55 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs @@ -10,38 +10,32 @@ public class Fixture : BugTestCase [OneTimeSetUp] public void OneTimeSetUp() { - using (var session = OpenSession()) - using (var t = session.BeginTransaction()) + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity { - var parent = new Entity - { - Name = "Parent1", - Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "GrandChild" } } } - }; - session.Save(parent); - parent = new Entity - { - Name = "Parent2", - Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "XGrandChild" } } } - }; - var other = new OtherEntity { Name = "ABC", Entities = {parent}}; - parent.OtherEntity = other; - session.Save(parent); - session.Save(other); - t.Commit(); - } - - Sfi.Statistics.IsStatisticsEnabled = true; + Name = "Parent1", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "GrandChild" } } } + }; + session.Save(parent); + parent = new Entity + { + Name = "Parent2", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "XGrandChild" } } } + }; + var other = new OtherEntity { Name = "ABC", Entities = {parent}}; + parent.OtherEntity = other; + session.Save(parent); + session.Save(other); + t.Commit(); } [OneTimeTearDown] public void OneTimeTearDown() { - Sfi.Statistics.IsStatisticsEnabled = false; - using var session = OpenSession(); using var transaction = session.BeginTransaction(); - + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); session.CreateQuery("delete from GrandChildEntity").ExecuteUpdate(); session.CreateQuery("delete from Entity").ExecuteUpdate(); @@ -153,14 +147,34 @@ grandChild.Name like 'A%' OR otherEntity.Name like 'A%' ) )"); + yield return new("FROM ROOT.Children FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.Children AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("FROM ROOT.OtherEntity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.OtherEntity AS otherEntity + LEFT JOIN ChildEntity AS child ON child.Parent = ROOT + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); } [Test, TestCaseSource(nameof(GetNoExceptionOnExecuteQueryTestCases))] public void NoExceptionOnExecuteQuery(TestCaseItem testCase) { using var session = OpenSession(); - using var _ = session.BeginTransaction(); - var q = session.CreateQuery(testCase.Hql); Assert.That(q.List(), Has.Count.EqualTo(1)); } From 43fefb9f97eeb0d36afe3bc027f8c6bc7b6a8ad4 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 12:46:14 +0300 Subject: [PATCH 03/15] Fix --- src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs | 12 +----------- src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g | 8 ++++++-- src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs | 5 +++++ src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs | 3 +-- .../Hql/Ast/ANTLR/Tree/FromElementFactory.cs | 2 +- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs index 7cc0bcae9c6..070937f3c70 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.cs @@ -832,16 +832,6 @@ void CreateFromJoinElement( HandleWithFragment(fromElement, with); } - - if (fromElement.Parent == null) - { - // Most likely means association join is used in invalid context - // I.e. in subquery: from EntityA a where exists (from EntityB join a.Assocation) - // Maybe we should throw exception instead - fromElement.FromClause.AddChild(fromElement); - if (fromElement.IsImplied) - fromElement.JoinSequence.SetUseThetaStyle(true); - } } if ( log.IsDebugEnabled() ) @@ -930,7 +920,7 @@ private static string GetPropertyPath(DotNode dotNode, IASTNode alias) return lhs.Path + "." + path; } - IASTNode CreateFromElement(string path, IASTNode pathNode, IASTNode alias, IASTNode propertyFetch) + FromElement CreateFromElement(string path, IASTNode pathNode, IASTNode alias, IASTNode propertyFetch) { FromElement fromElement = _currentFromClause.AddFromElement(path, alias); SetPropertyFetch(fromElement, propertyFetch, alias); diff --git a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g index 47b42f286ea..623cc830fd8 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g +++ b/src/NHibernate/Hql/Ast/ANTLR/HqlSqlWalker.g @@ -266,10 +266,14 @@ fromElementList @init{ fromElement! @init { - IASTNode fromElement = null; + FromElement fromElement = null; } // A simple class name, alias element. - : ^(RANGE p=path (a=ALIAS)? (pf=propertyFetch)? ) { fromElement = CreateFromElement($p.p, $p.tree, $a, $pf.tree); } + : ^(RANGE p=path (a=ALIAS)? (pf=propertyFetch)? ) + { + fromElement = CreateFromElement($p.p, $p.tree, $a, $pf.tree); + fromElement.JoinSequence.SetUseThetaStyle(true); + } -> {fromElement != null}? ^({fromElement}) -> | je=joinElement diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs index 39179f1419a..839ea736e5d 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromClause.cs @@ -447,6 +447,11 @@ internal void FinishInit() dependentElement.Parent.InsertChild(index, item); } } + + if (_appendFromElements.Count > 0) + { + _fromElements[0].JoinSequence.SetUseThetaStyle(true); + } _appendFromElements.Clear(); } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs index 79d42962748..8cbb00e25c6 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs @@ -711,8 +711,7 @@ public void SetOrigin(FromElement origin, bool manyToMany) } else { - // Otherwise, the destination node was implied by the FROM clause and the FROM clause processor - // will automatically add it in the right place. + FromClause.AppendFromElement(this); } } diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs index 4f80d774f43..d95a2bfd372 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs @@ -321,7 +321,7 @@ public FromElement CreateEntityJoin( // 1) 'elem' is the "root from-element" in correlated subqueries // 2) The DotNode.useThetaStyleImplicitJoins has been set to true // and 'elem' represents an implicit join - if (elem.FromClause != elem.Origin.FromClause || DotNode.UseThetaStyleImplicitJoins) + if (DotNode.UseThetaStyleImplicitJoins) { // the "root from-element" in correlated subqueries do need this piece elem.Type = HqlSqlWalker.FROM_FRAGMENT; From 2cedbd5328a86d3845b642784d912568a5aa0bde Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 14:26:09 +0300 Subject: [PATCH 04/15] Skip tests for MySql --- src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs | 5 +++++ src/NHibernate.Test/TestDialect.cs | 5 +++++ src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs index 4ee2d1fda55..8ebf4b1d29c 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs @@ -44,6 +44,11 @@ public void OneTimeTearDown() transaction.Commit(); } + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return TestDialect.SupportsCorrelatedColumnsInSubselectJoin; + } + public class TestCaseItem { public string Name { get; } diff --git a/src/NHibernate.Test/TestDialect.cs b/src/NHibernate.Test/TestDialect.cs index 49b2f7e0f69..e7bc20d304f 100644 --- a/src/NHibernate.Test/TestDialect.cs +++ b/src/NHibernate.Test/TestDialect.cs @@ -203,5 +203,10 @@ public bool SupportsSqlType(SqlType sqlType) /// Returns true if you can cancel a query. /// public virtual bool SupportsCancelQuery => true; + + /// + /// Some databases (MySql) don't support using main table aliases in subquery inside join ON clause + /// + public virtual bool SupportsCorrelatedColumnsInSubselectJoin => true; } } diff --git a/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs b/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs index 0ec57f43bc6..ea68e6f19b7 100644 --- a/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs +++ b/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs @@ -14,5 +14,12 @@ public MySQL5TestDialect(Dialect.Dialect dialect) /// This behaviour is documented at: http://dev.mysql.com/doc/refman/5.6/en/update.html /// public override bool SupportsModifyAndSelectSameTable => false; + + /// + /// A correlated column can be present only in the subquery's WHERE clause (and not in the SELECT list, + /// a JOIN or ORDER BY clause, a GROUP BY list, or a HAVING clause). Nor can there be any correlated column inside a derived table in the subquery's FROM list. + /// See https://dev.mysql.com/doc/refman/8.0/en/correlated-subqueries.html + /// + public override bool SupportsCorrelatedColumnsInSubselectJoin => false; } } From d638d3da9085ba7ac677560006d5b7a3c70130f9 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 14:26:44 +0300 Subject: [PATCH 05/15] Return old behavior for implicit joins in subquery --- src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs index 8cbb00e25c6..a22c13e84ff 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElement.cs @@ -707,7 +707,14 @@ public void SetOrigin(FromElement origin, bool manyToMany) { // HHH-276 : implied joins in a subselect where clause - The destination needs to be added // to the destination's from clause. - FromClause.AddChild(this); // Not sure if this is will fix everything, but it works. + FromClause.AddChild(this); + + // Generate correlated implied joins inside subquery implicitly + // As some dialects (MySql) do not support correlated columns to be used in subquery join ON clause + if (IsImplied) + { + JoinSequence.SetUseThetaStyle(true); + } } else { From 05779acf292841704b2d95695348fef661d718ea Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 14:49:22 +0300 Subject: [PATCH 06/15] Clean up testcase for GH1228 --- .../NHSpecificTest/GH1228/Fixture.cs | 110 ++++++------------ 1 file changed, 38 insertions(+), 72 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs index 940b721a90b..c629e9c7ce7 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs @@ -7,126 +7,92 @@ public class Fixture : BugTestCase [Test] public void TestOk() { - using (ISession s = OpenSession()) + using var s = OpenSession(); { - using (ITransaction t = s.BeginTransaction()) - { - try - { - { - var queryThatWorks = s.CreateQuery(@" + var queryThatWorks = s.CreateQuery( + @" SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv , ROOT.Folder AS ROOT_Folder WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 ) ) AND ROOT.Name = 'SomeName'"); - queryThatWorks.List(); - } - { - var queryThatWorks = s.CreateQuery(@" + queryThatWorks.List(); + } + { + var queryThatWorks = s.CreateQuery( + @" SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet , ROOT.Folders AS ROOT_Folder WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' ) ) AND ROOT.Id = 1"); - queryThatWorks.List(); - } - } - finally - { - s.Delete("from Sheet"); - s.Delete("from Folder"); - s.Delete("from Shelf"); - t.Commit(); - } - } + queryThatWorks.List(); } } [Test] public void TestWrongSql() { - using (ISession s = OpenSession()) + using var s = OpenSession(); { - using (ITransaction t = s.BeginTransaction()) - { - try - { - { - var queryThatCreatesWrongSQL = s.CreateQuery(@" + var queryThatCreatesWrongSQL = s.CreateQuery( + @" SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv JOIN ROOT.Folder AS ROOT_Folder WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 ) ) AND ROOT.Name = 'SomeName'"); - queryThatCreatesWrongSQL.List(); - } - { - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - var queryThatCreatesWrongSQL = s.CreateQuery(@" + queryThatCreatesWrongSQL.List(); + } + { + // The only assertion here is that the generated SQL is valid and can be executed. + // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + var queryThatCreatesWrongSQL = s.CreateQuery( + @" SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet JOIN ROOT.Folders AS ROOT_Folder WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' ) ) AND ROOT.Id = 1"); - queryThatCreatesWrongSQL.List(); - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - } - } - finally - { - s.Delete("from Sheet"); - s.Delete("from Folder"); - s.Delete("from Shelf"); - t.Commit(); - } - } + queryThatCreatesWrongSQL.List(); + // The only assertion here is that the generated SQL is valid and can be executed. + // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. } } [Test] - public void Test3() { - using (ISession s = OpenSession()) { - using (ITransaction t = s.BeginTransaction()) { - try { - { - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - var queryThatCreatesWrongSQL = s.CreateQuery(@" + public void Test3() + { + using var s = OpenSession(); + { + // The only assertion here is that the generated SQL is valid and can be executed. + // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + var queryThatCreatesWrongSQL = s.CreateQuery( + @" SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet JOIN sheet.Folder AS folder WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' ) ) AND ROOT.Id = 1"); - queryThatCreatesWrongSQL.List(); - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - } - { - var queryThatCreatesWrongSQL = s.CreateQuery(@" + queryThatCreatesWrongSQL.List(); + // The only assertion here is that the generated SQL is valid and can be executed. + // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + } + { + var queryThatCreatesWrongSQL = s.CreateQuery( + @" SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv JOIN inv.Folders AS folder WHERE folder = ROOT.Folder AND inv.Id = 1 ) ) AND ROOT.Name = 'SomeName'"); - queryThatCreatesWrongSQL.List(); - } - } - finally { - s.Delete("from Sheet"); - s.Delete("from Folder"); - s.Delete("from Shelf"); - t.Commit(); - } - } + queryThatCreatesWrongSQL.List(); } } } From 46b148ca08af61f3de983be45db44e0f99a41268 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 14:51:41 +0300 Subject: [PATCH 07/15] Fix GH1228 test --- src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs index c629e9c7ce7..0c5e064a454 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs @@ -35,6 +35,9 @@ SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT [Test] public void TestWrongSql() { + if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin) + Assert.Ignore("Dialect doesn't support this test case"); + using var s = OpenSession(); { var queryThatCreatesWrongSQL = s.CreateQuery( From 41fc760638aac3f0564b721fcfbae82660671d7d Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 15:22:08 +0300 Subject: [PATCH 08/15] Clean up --- src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs index d95a2bfd372..e9a95769f1f 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/Tree/FromElementFactory.cs @@ -122,10 +122,6 @@ private FromElement CreateFromElementInSubselect( string tableAlias = correlatedSubselect ? fromElement.TableAlias : null; - //To properly generete subselect implicit join is required by SqlGenerator - if (fromElement.IsImplied) - fromElement.JoinSequence.SetUseThetaStyle(true); - // If the from element isn't in the same clause, create a new from element. if (fromElement.FromClause != _fromClause) { From 03d0972cd4bc75fa0ac652e7e640ceb0c53a12e7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 18 Jul 2023 12:48:44 +0000 Subject: [PATCH 09/15] Generate async files --- .../Async/NHSpecificTest/GH3334/Fixture.cs | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs new file mode 100644 index 00000000000..b25d10169a7 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs @@ -0,0 +1,204 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3334 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + [OneTimeSetUp] + public void OneTimeSetUp() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity + { + Name = "Parent1", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "GrandChild" } } } + }; + session.Save(parent); + parent = new Entity + { + Name = "Parent2", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "XGrandChild" } } } + }; + var other = new OtherEntity { Name = "ABC", Entities = {parent}}; + parent.OtherEntity = other; + session.Save(parent); + session.Save(other); + t.Commit(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from GrandChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + session.CreateQuery("delete from OtherEntity").ExecuteUpdate(); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return TestDialect.SupportsCorrelatedColumnsInSubselectJoin; + } + + public class TestCaseItem + { + public string Name { get; } + public string Hql { get; } + public int LineNumber { get; } + + public TestCaseItem(string name, string hql, [CallerLineNumber] int lineNumber = 0) + { + Name = name; + Hql = hql; + LineNumber = lineNumber; + } + + public override string ToString() => $"{LineNumber:0000}: {Name}"; + } + + public static IEnumerable GetNoExceptionOnExecuteQueryTestCases() + { + /* does not work because of inner join or theta join created for many-to-one + @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + WHERE + child.Child.Name like 'G%' + OR ROOT.OtherEntity.Name like 'A%' + )");*/ + + yield return new("Basic Elements case 1 FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("Basic Elements case 2 FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.OtherEntity) AS otherEntity + WHERE + otherEntity.Name like 'A%' + )"); + yield return new("HQL Elements FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + )"); + yield return new("HQL Elements FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + yield return new("HQL Entity FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + ) + )"); + yield return new("HQL Entity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + ) + )"); + yield return new("FROM ROOT.Children FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.Children AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("FROM ROOT.OtherEntity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.OtherEntity AS otherEntity + LEFT JOIN ChildEntity AS child ON child.Parent = ROOT + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + } + + [Test, TestCaseSource(nameof(GetNoExceptionOnExecuteQueryTestCases))] + public async Task NoExceptionOnExecuteQueryAsync(TestCaseItem testCase) + { + using var session = OpenSession(); + var q = session.CreateQuery(testCase.Hql); + Assert.That(await (q.ListAsync()), Has.Count.EqualTo(1)); + } + + protected override bool CheckDatabaseWasCleaned() + { + // same set of objects for each test + return true; + } + } +} From 73bc158e4ebf17cdaa5c8da7a3dc4a68efd7e0c5 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 17:06:56 +0300 Subject: [PATCH 10/15] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com> --- .../NHSpecificTest/GH1228/Fixture.cs | 144 +++++++++--------- .../NHSpecificTest/GH3334/Entity.cs | 4 +- 2 files changed, 70 insertions(+), 78 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs index 0c5e064a454..557d9081395 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs @@ -8,95 +8,87 @@ public class Fixture : BugTestCase public void TestOk() { using var s = OpenSession(); - { - var queryThatWorks = s.CreateQuery( - @" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv - , ROOT.Folder AS ROOT_Folder - WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 - ) ) - AND ROOT.Name = 'SomeName'"); - queryThatWorks.List(); - } - { - var queryThatWorks = s.CreateQuery( - @" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet - , ROOT.Folders AS ROOT_Folder - WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' - ) ) - AND ROOT.Id = 1"); - queryThatWorks.List(); - } + var queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + , ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + queryThatWorks.List(); + + queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + , ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + queryThatWorks.List(); } [Test] - public void TestWrongSql() + public void TestThetaAnsiOnAssociationInSubQuery() { if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin) Assert.Ignore("Dialect doesn't support this test case"); using var s = OpenSession(); - { - var queryThatCreatesWrongSQL = s.CreateQuery( - @" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv - JOIN ROOT.Folder AS ROOT_Folder - WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 - ) ) - AND ROOT.Name = 'SomeName'"); - queryThatCreatesWrongSQL.List(); - } - { - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - var queryThatCreatesWrongSQL = s.CreateQuery( - @" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet - JOIN ROOT.Folders AS ROOT_Folder - WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' - ) ) - AND ROOT.Id = 1"); - queryThatCreatesWrongSQL.List(); - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - } + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + queryThatCreatesWrongSQL.List(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + queryThatCreatesWrongSQL.List(); + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. } [Test] - public void Test3() + public void TestOtherAnsiJoinOnAssociationInSubQuery() { using var s = OpenSession(); - { - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - var queryThatCreatesWrongSQL = s.CreateQuery( - @" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet - JOIN sheet.Folder AS folder - WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' - ) ) - AND ROOT.Id = 1"); - queryThatCreatesWrongSQL.List(); - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - } - { - var queryThatCreatesWrongSQL = s.CreateQuery( - @" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv - JOIN inv.Folders AS folder - WHERE folder = ROOT.Folder AND inv.Id = 1 - ) ) - AND ROOT.Name = 'SomeName'"); - queryThatCreatesWrongSQL.List(); - } + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN sheet.Folder AS folder + WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + queryThatCreatesWrongSQL.List(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN inv.Folders AS folder + WHERE folder = ROOT.Folder AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + queryThatCreatesWrongSQL.List(); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs index 864608faf72..718d3ac3488 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs @@ -6,8 +6,8 @@ public class Entity { public virtual int Id { get; set; } public virtual string Name { get; set; } - public virtual ISet Children { get; set; } = new HashSet(); - public virtual OtherEntity OtherEntity { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + public virtual OtherEntity OtherEntity { get; set; } } public class ChildEntity From 6fa58956889f48836455ee7e035d41b503329511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 18 Jul 2023 21:11:54 +0200 Subject: [PATCH 11/15] Commit forgoten suggestion --- src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs index 557d9081395..2174297f784 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs @@ -5,7 +5,7 @@ namespace NHibernate.Test.NHSpecificTest.GH1228 public class Fixture : BugTestCase { [Test] - public void TestOk() + public void TestThetaJoinOnAssociationInSubQuery() { using var s = OpenSession(); var queryThatWorks = s.CreateQuery( From 2cf2dc36222b37567b8bcbdeac79f1a13501d1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericDelaporte@users.noreply.github.com> Date: Tue, 18 Jul 2023 21:27:02 +0200 Subject: [PATCH 12/15] Generate async version of GH1228 --- src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs index 2174297f784..baf2660983d 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs @@ -2,6 +2,7 @@ namespace NHibernate.Test.NHSpecificTest.GH1228 { + [TestFixture] public class Fixture : BugTestCase { [Test] From 2a1f31d460f6739b753476b3643c6a2507f99357 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 18 Jul 2023 19:29:45 +0000 Subject: [PATCH 13/15] Generate async files --- .../Async/NHSpecificTest/GH1228/Fixture.cs | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs new file mode 100644 index 00000000000..5a78153c884 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs @@ -0,0 +1,106 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH1228 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + [Test] + public async Task TestThetaJoinOnAssociationInSubQueryAsync() + { + using var s = OpenSession(); + var queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + , ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + await (queryThatWorks.ListAsync()); + + queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + , ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + await (queryThatWorks.ListAsync()); + } + + [Test] + public async Task TestThetaAnsiOnAssociationInSubQueryAsync() + { + if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin) + Assert.Ignore("Dialect doesn't support this test case"); + + using var s = OpenSession(); + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + await (queryThatCreatesWrongSQL.ListAsync()); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + await (queryThatCreatesWrongSQL.ListAsync()); + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + } + + [Test] + public async Task TestOtherAnsiJoinOnAssociationInSubQueryAsync() + { + using var s = OpenSession(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN sheet.Folder AS folder + WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + await (queryThatCreatesWrongSQL.ListAsync()); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN inv.Folders AS folder + WHERE folder = ROOT.Folder AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + await (queryThatCreatesWrongSQL.ListAsync()); + } + } +} From 597524f6d25cad8f61910486b9b547cf19550dce Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Tue, 18 Jul 2023 23:32:16 +0300 Subject: [PATCH 14/15] Fix test name --- src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs index baf2660983d..64e4af85e3e 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs @@ -31,7 +31,7 @@ SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT } [Test] - public void TestThetaAnsiOnAssociationInSubQuery() + public void TestAnsiJoinOnAssociationInSubQuery() { if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin) Assert.Ignore("Dialect doesn't support this test case"); From 91f2e61a1c8702118d0ca03639bfb94febc62311 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 18 Jul 2023 20:35:05 +0000 Subject: [PATCH 15/15] Generate async files --- src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs index 5a78153c884..a95df9e5f21 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs @@ -42,7 +42,7 @@ SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT } [Test] - public async Task TestThetaAnsiOnAssociationInSubQueryAsync() + public async Task TestAnsiJoinOnAssociationInSubQueryAsync() { if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin) Assert.Ignore("Dialect doesn't support this test case");