Skip to content
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

Invalid SQL for exist queries with many to many relation. #3512

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

jskrobko
Copy link
Contributor

Hello @rbygrave ,
We have identified the following issue: when performing an exists query with a One-To-Many relationship, correct SQL is generated regardless of whether an id is present or not. (The generated SQL does not include unnecessary joins).
However, when executing the same type of query with a Many-To-Many relationship, different SQL is being generated:

  • without id: the SQL is incorrect. It contains sq1.id = t0.null.
  • with id: the SQL works, but includes an unnecessary join: left join mt_permission t1 on t1.id = t1z_.mt_permission_id.

Perhaps you could take a look at this. We have 2 tests with asserts where we are expecting different results.

Juri

@jskrobko
Copy link
Contributor Author

Error: TestM2MQueryAndIds.testM2MWithId:59
expected: "select distinct t0.id from mt_role t0 left join mt_role_permission t1z_ on t1z_.mt_role_id = t0.id where exists (select 1 from mt_permission sq1 where sq1.name = ? and (sq1.id = t1z_.mt_permission_id))"
but was: "select distinct t0.id from mt_role t0 left join mt_role_permission t1z_ on t1z_.mt_role_id = t0.id left join mt_permission t1 on t1.id = t1z_.mt_permission_id where exists (select 1 from mt_permission sq1 where sq1.name = ? and (sq1.id = t1.id))"
Error: Errors:
Error: TestM2MQueryAndIds.testM2MWithoutId:74 » Persistence Query threw SQLException:Syntax error in SQL statement "select t0.id from mt_role t0 where exists (select 1 from mt_permission sq1 where sq1.name = ? and (sq1.id = t0.[*]null))"; expected "identifier"; SQL statement:
select t0.id from mt_role t0 where exists (select 1 from mt_permission sq1 where sq1.name = ? and (sq1.id = t0.null)) [42001-220] Bind values:[null] Query was:select t0.id from mt_role t0 where exists (select 1 from mt_permission sq1 where sq1.name = ? and (sq1.id = t0.null))

@rbygrave
Copy link
Member

without id is .raw("(sq1.id = permissions)") and with id is .raw("(sq1.id = permissions.id)")

The "without id" expression isn't valid.

I am thinking that is confusing due to how ManyToOne paths get translated to the foreign key column. In this case, permissions is a ToMany path and so it literally only gets translated into a table alias and not a table alias + column. Hence we end up with t0.null.

with id: the SQL works, but includes an unnecessary join

That is because this path is a ManyToMany, so we get the join to the "hidden" intersection table and the join to the other side of the ManyToMany.

@jskrobko
Copy link
Contributor Author

Hello Rob,
We discussed this again as a team. We were not aware that a query without 'id' is not valid.
We can confirm that the result is correct in both O2M, M2M, and M2O when using '.id'. The only point here is that the query in M2M can still be optimized (remove additional 'join').

Do you still want to pursue this further? Otherwise, the issue can be closed.
Thank you.
Juri

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

Successfully merging this pull request may close these issues.

2 participants