Seems there is a bug somewhere either in query parsing or joins processing in hibernate 6.1.7+ That code & query works fine in all prev. versions from hibernate 3 to 5 I have a named query: ``` <query>SELECT COUNT(adminPermission) FROM org.broadleafcommerce.openadmin.server.security.domain.AdminPermission adminPermission LEFT OUTER JOIN adminPermission.allChildPermissions childPermission LEFT OUTER JOIN childPermission.qualifiedEntities childQualifiedEntity LEFT OUTER JOIN adminPermission.qualifiedEntities qualifiedEntity LEFT OUTER JOIN adminPermission.allRoles role LEFT OUTER JOIN role.allUsers roleUser LEFT OUTER JOIN adminPermission.allUsers permissionUser WHERE (roleUser = :adminUser OR permissionUser = :adminUser) AND (adminPermission.type = :type OR adminPermission.type = 'ALL' OR childPermission.type = :type OR childPermission.type = 'ALL') AND (qualifiedEntity.ceilingEntityFullyQualifiedName = :ceilingEntity OR childQualifiedEntity.ceilingEntityFullyQualifiedName = :ceilingEntity) </query> ``` There OneToMany and ManyToMany through JoinTable asossiations it this is important I debugged a bit and see that it processes condition (roleUser = :adminUser OR permissionUser = :adminUser) and finds a join LEFT OUTER JOIN role.allUsers roleUser so it finds alias "roleUser", logic goes into org.hibernate.query.hql.internal.QuerySplitter.UnmappedPolymorphismReplacer#visitSetJoin where it does: final SqmSetJoin copy = new SqmSetJoin<>( findSqmFromCopy( join.getLhs() ), so join.getLhs() will return another join LEFT OUTER JOIN adminPermission.allRoles role so it finds alias "role" And in org.hibernate.query.hql.internal.QuerySplitter.UnmappedPolymorphismReplacer#findSqmFromCopy it does return (X) sqmFrom.accept( this ); So it will do a recursive call that will eventually come to org.hibernate.query.hql.internal.QuerySplitter.UnmappedPolymorphismReplacer#visitSetJoin again, where it will process join with alias "role" and in org.hibernate.query.hql.internal.QuerySplitter.UnmappedPolymorphismReplacer#visitJoins will register that alias, and also it will do join.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) ); where "role" join will reference "roleUser" join via joins.forEach( consumer ); in org.hibernate.query.sqm.tree.domain.AbstractSqmFrom#visitSqmJoins it will process it and also registers via org.hibernate.query.hql.internal.SqmPathRegistryImpl#register(org.hibernate.query.sqm.tree.domain.SqmPath<?>) so now registry map knows about "role" and "roleUser" joins and recursion ends and it eventually continues to process "roleUse" join - where we start recursion... and it again will attempt to register org.hibernate.query.hql.internal.SqmPathRegistryImpl#register(org.hibernate.query.sqm.tree.domain.SqmPath<?>) where it fails with exception... So there is something wrong on how "multi-level joins" are handled. |