Skip to content

Support association joins from main query to be used in subqueries #3369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


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 TestAnsiJoinOnAssociationInSubQueryAsync()
{
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());
}
}
}
204 changes: 204 additions & 0 deletions src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


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<TestCaseItem> 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;
}
}
}
Loading