Skip to content

Casting to object and back to interface in Subquery causes incorrect SQL #2858

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

Closed
PleasantD opened this issue Jul 14, 2021 · 2 comments
Closed

Comments

@PleasantD
Copy link
Contributor

This is a regression introduced in v5.3.0

I have two different examples of how casting to object and back to an interface of a mapped type cause errors. However they both happen only when one part of the query expression casts to object and another part casts back to the interface of a mapped class. This leads me to think they may be closely related.

Prerequisites

  • Mapped objects have interfaces defined and the Query and casts use the interfaces instead of the mapped types
  • At some point the entities are cast to object and a later part of the query casts them back to the interface type

In our code this casting is done within code that is generating dynamic expressions and queries based on metadata, and hence needs to cast to object at certain steps.

Problem

Casting back to the interface in a subquery with outer joins causes the SQL to generate the wrong SQL.
The subquery also contains a coalesce which should be projected to the subquery's SELECT clause.
Instead the coalesce is ignored and the subquery has two selected columns, which is not allowed.

Example Code

var usedDepartments = session.Query<ITimeChunk>()
    .SelectMany(x => ((IEnumerable<object>) x.Issue.Departments).DefaultIfEmpty().Select(d => (object) ((Guid?) ((Guid?) (((IDepartment) d).Id) ?? x.Issue.Project.Department.Id))))
    .Where(id => id != null)
    .Select(id => (Guid?) id);

var result = session.Query<IDepartment>()
    .Where(d => usedDepartments.Contains(d.Id))
    .Select(d => new { d.Id, d.Name });

Error

  Message: 
    NHibernate.Exceptions.GenericADOException : could not execute query
    [ select department0_.Id as col_0_0_, department0_.Name as col_1_0_ from Department department0_ where department0_.Id in (select department4_.Id, project6_.DepartmentId from TimeChunk timechunk1_ left outer join Issue issue2_ on timechunk1_.IssueId=issue2_.Id left outer join IssuesToDepartments department3_ on issue2_.Id=department3_.issue_key left outer join Department department4_ on department3_.elt=department4_.Id left outer join Project project6_ on issue2_.ProjectId=project6_.Id where coalesce(department4_.Id, project6_.DepartmentId) is not null) ]
    [SQL: select department0_.Id as col_0_0_, department0_.Name as col_1_0_ from Department department0_ where department0_.Id in (select department4_.Id, project6_.DepartmentId from TimeChunk timechunk1_ left outer join Issue issue2_ on timechunk1_.IssueId=issue2_.Id left outer join IssuesToDepartments department3_ on issue2_.Id=department3_.issue_key left outer join Department department4_ on department3_.elt=department4_.Id left outer join Project project6_ on issue2_.ProjectId=project6_.Id where coalesce(department4_.Id, project6_.DepartmentId) is not null)]
      ----> Npgsql.PostgresException : 42601: subquery has too many columns
    Data:
      Severity: ERROR
      SqlState: 42601
      Code: 42601
      MessageText: subquery has too many columns
      Position: 118
      File: parse_expr.c
      Line: 1979
      Routine: transformSubLink
      actual-sql-query: select department0_.Id as col_0_0_, department0_.Name as col_1_0_ from Department department0_ where department0_.Id in (select department4_.Id, project6_.DepartmentId from TimeChunk timechunk1_ left outer join Issue issue2_ on timechunk1_.IssueId=issue2_.Id left outer join IssuesToDepartments department3_ on issue2_.Id=department3_.issue_key left outer join Department department4_ on department3_.elt=department4_.Id left outer join Project project6_ on issue2_.ProjectId=project6_.Id where coalesce(department4_.Id, project6_.DepartmentId) is not null)
@PleasantD
Copy link
Contributor Author

Unit test for the above example
GH2858.zip

@fredericDelaporte
Copy link
Member

Fixed by #2879.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants