Include the WITH clause AST in the FromElement so that column references can be analyzed

This commit is contained in:
Christian Beikov 2019-11-02 15:37:21 +01:00 committed by Andrea Boriero
parent 05e6a41e5f
commit 0c0248d448
4 changed files with 40 additions and 34 deletions

View File

@ -509,7 +509,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
SqlGenerator sql = new SqlGenerator( getSessionFactoryHelper().getFactory() );
sql.whereExpr( hqlSqlWithNode.getFirstChild() );
fromElement.setWithClauseFragment( "(" + sql.getSQL() + ")" );
fromElement.setWithClauseFragment( hqlSqlWithNode.getFirstChild(), "(" + sql.getSQL() + ")" );
}
catch (SemanticException e) {
throw e;

View File

@ -13,6 +13,7 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import antlr.collections.AST;
import org.hibernate.QueryException;
import org.hibernate.engine.internal.JoinSequence;
import org.hibernate.hql.internal.CollectionProperties;
@ -69,6 +70,7 @@ public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, Pa
private boolean useWhereFragment = true;
private List<FromElement> destinations;
private boolean manyToMany;
private AST withClauseAst;
private String withClauseFragment;
private boolean dereferencedBySuperclassProperty;
private boolean dereferencedBySubclassProperty;
@ -627,11 +629,16 @@ public class FromElement extends HqlSqlWalkerNode implements DisplayableNode, Pa
isAllPropertyFetch = fetch;
}
public AST getWithClauseAst() {
return withClauseAst;
}
public String getWithClauseFragment() {
return withClauseFragment;
}
public void setWithClauseFragment(String withClauseFragment) {
public void setWithClauseFragment(AST ast, String withClauseFragment) {
this.withClauseAst = ast;
this.withClauseFragment = withClauseFragment;
}

View File

@ -103,24 +103,6 @@ public class JoinProcessor implements SqlTokenTypes {
}
}
private <T extends AST> List<T> findAllNodes(AST node, Class<T> clazz) {
ArrayList<T> found = new ArrayList<>();
doFindAllNodes( node, clazz, found );
return found;
}
private <T extends AST> void doFindAllNodes(AST node, Class<T> clazz, List<T> found) {
if ( clazz.isAssignableFrom( node.getClass() ) ) {
found.add( (T) node );
}
if ( node.getFirstChild() != null ) {
doFindAllNodes( node.getFirstChild(), clazz, found );
}
if ( node.getNextSibling() != null ) {
doFindAllNodes( node.getNextSibling(), clazz, found );
}
}
private Set<String> findQueryReferencedTables(QueryNode query) {
if ( !walker.getSessionFactoryHelper()
.getFactory()
@ -150,16 +132,15 @@ public class JoinProcessor implements SqlTokenTypes {
Set<String> result = new HashSet<>();
// Find tables referenced by FromReferenceNodes
List<FromReferenceNode> fromReferenceNodes = findAllNodes( query, FromReferenceNode.class );
for ( FromReferenceNode node : fromReferenceNodes ) {
String[] tables = node.getReferencedTables();
if ( tables != null ) {
for ( String table : tables ) {
result.add( table );
}
collectReferencedTables( new ASTIterator( query ), result );
for (FromElement fromElement : (List<FromElement>) query.getFromClause().getFromElements()) {
AST withClauseAst = fromElement.getWithClauseAst();
if ( withClauseAst != null ) {
collectReferencedTables( new ASTIterator( withClauseAst ), result );
}
}
// Find tables referenced by fromElementsForLoad
if ( query.getSelectClause() != null ) {
for ( Object element : query.getSelectClause().getFromElementsForLoad() ) {
@ -178,6 +159,21 @@ public class JoinProcessor implements SqlTokenTypes {
return result;
}
private void collectReferencedTables(ASTIterator iterator, Set<String> result) {
while ( iterator.hasNext() ) {
AST node = iterator.nextNode();
if ( node instanceof FromReferenceNode ) {
FromReferenceNode fromReferenceNode = (FromReferenceNode) node;
String[] tables = fromReferenceNode.getReferencedTables();
if ( tables != null ) {
for ( String table : tables ) {
result.add( table );
}
}
}
}
}
public void processJoins(QueryNode query) {
final FromClause fromClause = query.getFromClause();

View File

@ -54,6 +54,13 @@ public class HHH13670Test extends BaseCoreFunctionalTestCase {
});
}
@Test
public void testDereferenceSuperClassAttributeInWithClause() {
doInJPA(this::sessionFactory, em -> {
em.createQuery("SELECT subB_0.id FROM SubB subB_0 LEFT JOIN subB_0.other subA_0 ON subA_0.id = subB_0.parent.id", Tuple.class).getResultList();
});
}
@Test
public void testRootTypeJoinWithGroupJoins() {
doInJPA(this::sessionFactory, em -> {
@ -99,13 +106,6 @@ public class HHH13670Test extends BaseCoreFunctionalTestCase {
return new Class<?>[] { Super.class, SubA.class, SubB.class };
}
@Override
protected void configure(Configuration configuration) {
super.afterConfigurationBuilt( configuration );
// Uncomment to fix tests
// configuration.setProperty( AvailableSettings.OMIT_JOIN_OF_SUPERCLASS_TABLES, "false" );
}
@Entity(name = "Super")
@Inheritance(strategy = InheritanceType.JOINED)
public static class Super<SubType extends Super> {
@ -134,6 +134,9 @@ public class HHH13670Test extends BaseCoreFunctionalTestCase {
@Entity(name = "SubB")
public static class SubB extends Super<SubA> {
@ManyToOne(fetch = FetchType.LAZY)
Super other;
SubB() {}
SubB(Long id, Super parent) {