Skip to content

Commit

Permalink
HHH-11437 - Entity joins are not polymorphic
Browse files Browse the repository at this point in the history
  • Loading branch information
beikov authored and dreab8 committed Feb 16, 2017
1 parent 1e8077f commit 3d6f8eb
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 14 deletions.
Expand Up @@ -89,6 +89,10 @@ public void applyTreatAsDeclarations(Set<String> treatAsDeclarations) {
this.treatAsDeclarations.addAll( treatAsDeclarations ); this.treatAsDeclarations.addAll( treatAsDeclarations );
} }


protected Set<String> getTreatAsDeclarations() {
return treatAsDeclarations;
}



/** /**
* Create a full, although shallow, copy. * Create a full, although shallow, copy.
Expand Down Expand Up @@ -436,7 +440,7 @@ private void addSubclassJoins(
); );
} }


private boolean isIncluded(String alias) { protected boolean isIncluded(String alias) {
return selector != null && selector.includeSubclasses( alias ); return selector != null && selector.includeSubclasses( alias );
} }


Expand Down
Expand Up @@ -8,6 +8,7 @@


import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set;


import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.MappingException; import org.hibernate.MappingException;
Expand All @@ -16,6 +17,7 @@
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes; import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.hql.internal.ast.HqlSqlWalker; import org.hibernate.hql.internal.ast.HqlSqlWalker;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable; import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.Queryable; import org.hibernate.persister.entity.Queryable;
Expand Down Expand Up @@ -126,11 +128,34 @@ public JoinFragment toJoinFragment(
} }


final StringBuilder buffer = new StringBuilder(); final StringBuilder buffer = new StringBuilder();
buffer.append( joinString ) final AbstractEntityPersister joinable = (AbstractEntityPersister) entityType.getAssociatedJoinable(factory);
.append( entityTableText )
buffer.append( joinString );

Set<String> treatAsDeclarations = getTreatAsDeclarations();
final boolean include = includeAllSubclassJoins && isIncluded( entityTableAlias );
String fromFragment = joinable.fromJoinFragment( entityTableAlias, true, include, treatAsDeclarations );
String whereFragment = joinable.whereJoinFragment( entityTableAlias, true, include, treatAsDeclarations );

// We need a table group only when having e.g. a left join of a polymorphic entity
// fromFragment is empty if the entity is non-polymorphic
// Inner joined entity joins can avoid using the table grouping since the condition can be moved to the where clause
boolean renderTableGroup = !fromFragment.isEmpty() && joinType != JoinType.INNER_JOIN;

if ( renderTableGroup ) {
buffer.append( '(' );
}

buffer.append( entityTableText )
.append( ' ' ) .append( ' ' )
.append( entityTableAlias ) .append( entityTableAlias );
.append( " on " );
if ( renderTableGroup ) {
buffer.append( fromFragment )
.append( ')' );
}

buffer.append( " on " );


final String filters = entityType.getOnCondition( final String filters = entityType.getOnCondition(
entityTableAlias, entityTableAlias,
Expand All @@ -139,23 +164,54 @@ public JoinFragment toJoinFragment(
Collections.<String>emptySet() Collections.<String>emptySet()
); );


buffer.append( filters ); if ( fromFragment.isEmpty() || renderTableGroup ) {
if ( withClauseFragment != null ) { buffer.append( filters );
if ( StringHelper.isNotEmpty( filters ) ) { if ( withClauseFragment != null ) {
buffer.append( " and " ); if ( StringHelper.isNotEmpty( filters ) ) {
buffer.append( " and " );
}
buffer.append( withClauseFragment );
} }
buffer.append( withClauseFragment );
} }
else {
// We know there is a fromFragment and that we shouldn't render a table group
// This means the entity is polymorphic and the entity join is an inner join
// We move the with clause stuff to the where clause but still need to have a valid on condition
buffer.append( "1=1" );
buffer.append( fromFragment );

// Proper capacity to avoid resizing
StringBuilder whereBuffer = new StringBuilder(
10
+ whereFragment.length()
+ filters.length()
+ withClauseFragment.length()
);
whereBuffer.append(whereFragment);
if ( !filters.isEmpty() ) {
whereBuffer.append( " and " );
whereBuffer.append( filters );
}
if ( !withClauseFragment.isEmpty() ) {
whereBuffer.append( " and " );
whereBuffer.append( withClauseFragment );
}


return new EntityJoinJoinFragment( buffer.toString() ); whereFragment = whereBuffer.toString();
}

return new EntityJoinJoinFragment( buffer.toString(), whereFragment );
} }

} }


private static class EntityJoinJoinFragment extends JoinFragment { private static class EntityJoinJoinFragment extends JoinFragment {
private final String fragmentString; private final String fragmentString;
private final String whereFragment;


public EntityJoinJoinFragment(String fragmentString) { public EntityJoinJoinFragment(String fragmentString, String whereFragment) {
this.fragmentString = fragmentString; this.fragmentString = fragmentString;
this.whereFragment = whereFragment;
} }


@Override @Override
Expand Down Expand Up @@ -192,7 +248,7 @@ public String toFromFragmentString() {


@Override @Override
public String toWhereFragmentString() { public String toWhereFragmentString() {
return null; return whereFragment;
} }


@Override @Override
Expand Down
Expand Up @@ -60,7 +60,7 @@ public void setUp(){


@Test @Test
@TestForIssue(jiraKey = "HHH-11437") @TestForIssue(jiraKey = "HHH-11437")
public void testOnClauseUsesNonDrivingTableAlias() { public void testOnClauseUsesSuperclassAttribute() {
doInJPA( this::entityManagerFactory, entityManager -> { doInJPA( this::entityManagerFactory, entityManager -> {
List<Book> result = entityManager.createQuery( "SELECT DISTINCT b1 FROM Book b1 JOIN Book b2 ON b1.price = b2.price", Book.class ) List<Book> result = entityManager.createQuery( "SELECT DISTINCT b1 FROM Book b1 JOIN Book b2 ON b1.price = b2.price", Book.class )
.getResultList(); .getResultList();
Expand Down

0 comments on commit 3d6f8eb

Please sign in to comment.