Skip to content

Commit 3875011

Browse files
bahusoidcsharper2010fredericDelaporte
authored
Support association joins from main query to be used in subqueries (#3369)
Fixes #3334 Co-authored-by: CSharper2010 <csharper2010@googlemail.com> Co-authored-by: Frédéric Delaporte <12201973+fredericDelaporte@users.noreply.github.com>
1 parent 0fdb589 commit 3875011

File tree

13 files changed

+683
-136
lines changed

13 files changed

+683
-136
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using NUnit.Framework;
12+
13+
namespace NHibernate.Test.NHSpecificTest.GH1228
14+
{
15+
using System.Threading.Tasks;
16+
[TestFixture]
17+
public class FixtureAsync : BugTestCase
18+
{
19+
[Test]
20+
public async Task TestThetaJoinOnAssociationInSubQueryAsync()
21+
{
22+
using var s = OpenSession();
23+
var queryThatWorks = s.CreateQuery(
24+
@"
25+
SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT
26+
WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv
27+
, ROOT.Folder AS ROOT_Folder
28+
WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1
29+
))
30+
AND ROOT.Name = 'SomeName'");
31+
await (queryThatWorks.ListAsync());
32+
33+
queryThatWorks = s.CreateQuery(
34+
@"
35+
SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT
36+
WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet
37+
, ROOT.Folders AS ROOT_Folder
38+
WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName'
39+
))
40+
AND ROOT.Id = 1");
41+
await (queryThatWorks.ListAsync());
42+
}
43+
44+
[Test]
45+
public async Task TestAnsiJoinOnAssociationInSubQueryAsync()
46+
{
47+
if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin)
48+
Assert.Ignore("Dialect doesn't support this test case");
49+
50+
using var s = OpenSession();
51+
var queryThatCreatesWrongSQL = s.CreateQuery(
52+
@"
53+
SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT
54+
WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv
55+
JOIN ROOT.Folder AS ROOT_Folder
56+
WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1
57+
))
58+
AND ROOT.Name = 'SomeName'");
59+
await (queryThatCreatesWrongSQL.ListAsync());
60+
61+
// The only assertion here is that the generated SQL is valid and can be executed.
62+
// With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder.
63+
queryThatCreatesWrongSQL = s.CreateQuery(
64+
@"
65+
SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT
66+
WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet
67+
JOIN ROOT.Folders AS ROOT_Folder
68+
WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName'
69+
))
70+
AND ROOT.Id = 1");
71+
await (queryThatCreatesWrongSQL.ListAsync());
72+
// The only assertion here is that the generated SQL is valid and can be executed.
73+
// With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder.
74+
}
75+
76+
[Test]
77+
public async Task TestOtherAnsiJoinOnAssociationInSubQueryAsync()
78+
{
79+
using var s = OpenSession();
80+
81+
// The only assertion here is that the generated SQL is valid and can be executed.
82+
// With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder.
83+
var queryThatCreatesWrongSQL = s.CreateQuery(
84+
@"
85+
SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT
86+
WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet
87+
JOIN sheet.Folder AS folder
88+
WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName'
89+
))
90+
AND ROOT.Id = 1");
91+
await (queryThatCreatesWrongSQL.ListAsync());
92+
93+
// The only assertion here is that the generated SQL is valid and can be executed.
94+
// With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder.
95+
queryThatCreatesWrongSQL = s.CreateQuery(
96+
@"
97+
SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT
98+
WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv
99+
JOIN inv.Folders AS folder
100+
WHERE folder = ROOT.Folder AND inv.Id = 1
101+
))
102+
AND ROOT.Name = 'SomeName'");
103+
await (queryThatCreatesWrongSQL.ListAsync());
104+
}
105+
}
106+
}
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System.Collections.Generic;
12+
using System.Runtime.CompilerServices;
13+
using NUnit.Framework;
14+
15+
namespace NHibernate.Test.NHSpecificTest.GH3334
16+
{
17+
using System.Threading.Tasks;
18+
[TestFixture]
19+
public class FixtureAsync : BugTestCase
20+
{
21+
[OneTimeSetUp]
22+
public void OneTimeSetUp()
23+
{
24+
using var session = OpenSession();
25+
using var t = session.BeginTransaction();
26+
var parent = new Entity
27+
{
28+
Name = "Parent1",
29+
Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "GrandChild" } } }
30+
};
31+
session.Save(parent);
32+
parent = new Entity
33+
{
34+
Name = "Parent2",
35+
Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "XGrandChild" } } }
36+
};
37+
var other = new OtherEntity { Name = "ABC", Entities = {parent}};
38+
parent.OtherEntity = other;
39+
session.Save(parent);
40+
session.Save(other);
41+
t.Commit();
42+
}
43+
44+
[OneTimeTearDown]
45+
public void OneTimeTearDown()
46+
{
47+
using var session = OpenSession();
48+
using var transaction = session.BeginTransaction();
49+
50+
session.CreateQuery("delete from ChildEntity").ExecuteUpdate();
51+
session.CreateQuery("delete from GrandChildEntity").ExecuteUpdate();
52+
session.CreateQuery("delete from Entity").ExecuteUpdate();
53+
session.CreateQuery("delete from OtherEntity").ExecuteUpdate();
54+
55+
transaction.Commit();
56+
}
57+
58+
protected override bool AppliesTo(Dialect.Dialect dialect)
59+
{
60+
return TestDialect.SupportsCorrelatedColumnsInSubselectJoin;
61+
}
62+
63+
public class TestCaseItem
64+
{
65+
public string Name { get; }
66+
public string Hql { get; }
67+
public int LineNumber { get; }
68+
69+
public TestCaseItem(string name, string hql, [CallerLineNumber] int lineNumber = 0)
70+
{
71+
Name = name;
72+
Hql = hql;
73+
LineNumber = lineNumber;
74+
}
75+
76+
public override string ToString() => $"{LineNumber:0000}: {Name}";
77+
}
78+
79+
public static IEnumerable<TestCaseItem> GetNoExceptionOnExecuteQueryTestCases()
80+
{
81+
/* does not work because of inner join or theta join created for many-to-one
82+
@"
83+
SELECT ROOT
84+
FROM Entity AS ROOT
85+
WHERE
86+
EXISTS
87+
(FROM ELEMENTS(ROOT.Children) AS child
88+
WHERE
89+
child.Child.Name like 'G%'
90+
OR ROOT.OtherEntity.Name like 'A%'
91+
)");*/
92+
93+
yield return new("Basic Elements case 1 FoundViaGrandChildG", @"
94+
SELECT ROOT
95+
FROM Entity AS ROOT
96+
WHERE
97+
EXISTS
98+
(FROM ELEMENTS(ROOT.Children) AS child
99+
LEFT JOIN child.Child AS grandChild
100+
WHERE
101+
grandChild.Name like 'G%'
102+
)");
103+
yield return new("Basic Elements case 2 FoundViaOtherEntityA", @"
104+
SELECT ROOT
105+
FROM Entity AS ROOT
106+
WHERE
107+
EXISTS
108+
(FROM ELEMENTS(ROOT.OtherEntity) AS otherEntity
109+
WHERE
110+
otherEntity.Name like 'A%'
111+
)");
112+
yield return new("HQL Elements FoundViaGrandChildG", @"
113+
SELECT ROOT
114+
FROM Entity AS ROOT
115+
WHERE
116+
EXISTS
117+
(FROM ELEMENTS(ROOT.Children) AS child
118+
LEFT JOIN child.Child AS grandChild
119+
LEFT JOIN ROOT.OtherEntity AS otherEntity
120+
WHERE
121+
grandChild.Name like 'G%'
122+
OR otherEntity.Name like 'G%'
123+
)");
124+
yield return new("HQL Elements FoundViaOtherEntityA", @"
125+
SELECT ROOT
126+
FROM Entity AS ROOT
127+
WHERE
128+
EXISTS
129+
(FROM ELEMENTS(ROOT.Children) AS child
130+
LEFT JOIN child.Child AS grandChild
131+
LEFT JOIN ROOT.OtherEntity AS otherEntity
132+
WHERE
133+
grandChild.Name like 'A%'
134+
OR otherEntity.Name like 'A%'
135+
)");
136+
yield return new("HQL Entity FoundViaGrandChildG", @"
137+
SELECT ROOT
138+
FROM Entity AS ROOT
139+
WHERE
140+
EXISTS
141+
(FROM ChildEntity AS child
142+
LEFT JOIN child.Child AS grandChild
143+
LEFT JOIN ROOT.OtherEntity AS otherEntity
144+
WHERE
145+
child.Parent = ROOT
146+
AND (
147+
grandChild.Name like 'G%'
148+
OR otherEntity.Name like 'G%'
149+
)
150+
)");
151+
yield return new("HQL Entity FoundViaOtherEntityA", @"
152+
SELECT ROOT
153+
FROM Entity AS ROOT
154+
WHERE
155+
EXISTS
156+
(FROM ChildEntity AS child
157+
LEFT JOIN child.Child AS grandChild
158+
LEFT JOIN ROOT.OtherEntity AS otherEntity
159+
WHERE
160+
child.Parent = ROOT
161+
AND (
162+
grandChild.Name like 'A%'
163+
OR otherEntity.Name like 'A%'
164+
)
165+
)");
166+
yield return new("FROM ROOT.Children FoundViaGrandChildG", @"
167+
SELECT ROOT
168+
FROM Entity AS ROOT
169+
WHERE
170+
EXISTS
171+
(FROM ROOT.Children AS child
172+
LEFT JOIN child.Child AS grandChild
173+
WHERE
174+
grandChild.Name like 'G%'
175+
)");
176+
yield return new("FROM ROOT.OtherEntity FoundViaOtherEntityA", @"
177+
SELECT ROOT
178+
FROM Entity AS ROOT
179+
WHERE
180+
EXISTS
181+
(FROM ROOT.OtherEntity AS otherEntity
182+
LEFT JOIN ChildEntity AS child ON child.Parent = ROOT
183+
LEFT JOIN child.Child AS grandChild
184+
WHERE
185+
grandChild.Name like 'A%'
186+
OR otherEntity.Name like 'A%'
187+
)");
188+
}
189+
190+
[Test, TestCaseSource(nameof(GetNoExceptionOnExecuteQueryTestCases))]
191+
public async Task NoExceptionOnExecuteQueryAsync(TestCaseItem testCase)
192+
{
193+
using var session = OpenSession();
194+
var q = session.CreateQuery(testCase.Hql);
195+
Assert.That(await (q.ListAsync()), Has.Count.EqualTo(1));
196+
}
197+
198+
protected override bool CheckDatabaseWasCleaned()
199+
{
200+
// same set of objects for each test
201+
return true;
202+
}
203+
}
204+
}

0 commit comments

Comments
 (0)