Skip to content

HHH 11544 - Test and fix #1844

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
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,28 @@ public JoinSequence addJoin(
String alias,
JoinType joinType,
String[] referencingKey) throws MappingException {
joins.add( new Join( factory, associationType, alias, joinType, referencingKey ) );
joins.add( new Join( factory, associationType, alias, joinType, new String[][] { referencingKey } ) );
return this;
}

/**
* Add a join to this sequence
*
* @param associationType The type of the association representing the join
* @param alias The RHS alias for the join
* @param joinType The type of join (INNER, etc)
* @param referencingKeys The LHS columns for the join condition
*
* @return The Join memento
*
* @throws MappingException Generally indicates a problem resolving the associationType to a {@link Joinable}
*/
public JoinSequence addJoin(
AssociationType associationType,
String alias,
JoinType joinType,
String[][] referencingKeys) throws MappingException {
joins.add( new Join( factory, associationType, alias, joinType, referencingKeys ) );
return this;
}

Expand Down Expand Up @@ -242,8 +263,7 @@ else if ( needsTableGroupJoin( joins, withClauseFragment ) ) {
join.getAlias(),
join.getLHSColumns(),
JoinHelper.getRHSColumnNames( join.getAssociationType(), factory ),
join.joinType,
""
join.joinType
);
}
addSubclassJoins(
Expand All @@ -263,17 +283,28 @@ else if ( needsTableGroupJoin( joins, withClauseFragment ) ) {
joinFragment.addFromFragmentString( " on " );

final String rhsAlias = first.getAlias();
final String[] lhsColumns = first.getLHSColumns();
final String[][] lhsColumns = first.getLHSColumns();
final String[] rhsColumns = JoinHelper.getRHSColumnNames( first.getAssociationType(), factory );
for ( int j=0; j < lhsColumns.length; j++) {
joinFragment.addFromFragmentString( lhsColumns[j] );
joinFragment.addFromFragmentString( "=" );
joinFragment.addFromFragmentString( rhsAlias );
joinFragment.addFromFragmentString( "." );
joinFragment.addFromFragmentString( rhsColumns[j] );
if ( j < lhsColumns.length - 1 ) {
joinFragment.addFromFragmentString( " and " );
if ( lhsColumns.length > 1 ) {
joinFragment.addFromFragmentString( "(" );
}
for ( int i = 0; i < lhsColumns.length; i++ ) {
for ( int j = 0; j < lhsColumns[i].length; j++ ) {
joinFragment.addFromFragmentString( lhsColumns[i][j] );
joinFragment.addFromFragmentString( "=" );
joinFragment.addFromFragmentString( rhsAlias );
joinFragment.addFromFragmentString( "." );
joinFragment.addFromFragmentString( rhsColumns[j] );
if ( j < lhsColumns[i].length - 1 ) {
joinFragment.addFromFragmentString( " and " );
}
}
if ( i < lhsColumns.length - 1 ) {
joinFragment.addFromFragmentString( " or " );
}
}
if ( lhsColumns.length > 1 ) {
joinFragment.addFromFragmentString( ")" );
}

joinFragment.addFromFragmentString( " and " );
Expand Down Expand Up @@ -568,14 +599,14 @@ public static final class Join {
private final Joinable joinable;
private final JoinType joinType;
private final String alias;
private final String[] lhsColumns;
private final String[][] lhsColumns;

Join(
SessionFactoryImplementor factory,
AssociationType associationType,
String alias,
JoinType joinType,
String[] lhsColumns) throws MappingException {
String[][] lhsColumns) throws MappingException {
this.associationType = associationType;
this.joinable = associationType.getAssociatedJoinable( factory );
this.alias = alias;
Expand All @@ -599,7 +630,7 @@ public JoinType getJoinType() {
return joinType;
}

public String[] getLHSColumns() {
public String[][] getLHSColumns() {
return lhsColumns;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
*/
package org.hibernate.hql.internal.ast.tree;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import org.hibernate.QueryException;
import org.hibernate.engine.internal.JoinSequence;
import org.hibernate.hql.internal.CollectionProperties;
Expand All @@ -16,6 +21,7 @@
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister;
Expand Down Expand Up @@ -483,11 +489,6 @@ private void dereferenceEntityJoin(String classAlias, EntityType propertyType, b
boolean useFoundFromElement = found && canReuse( classAlias, elem );

if ( !useFoundFromElement ) {
// If this is an implied join in a from element, then use the impled join type which is part of the
// tree parser's state (set by the gramamar actions).
JoinSequence joinSequence = getSessionFactoryHelper()
.createJoinSequence( impliedJoin, propertyType, tableAlias, joinType, joinColumns );

// If the lhs of the join is a "component join", we need to go back to the
// first non-component-join as the origin to properly link aliases and
// join columns
Expand All @@ -501,24 +502,88 @@ private void dereferenceEntityJoin(String classAlias, EntityType propertyType, b

String role = lhsFromElement.getClassName() + "." + propertyName;

FromElementFactory factory = new FromElementFactory(
currentFromClause,
lhsFromElement,
joinPath,
classAlias,
joinColumns,
impliedJoin
);
elem = factory.createEntityJoin(
associatedEntityName,
tableAlias,
joinSequence,
fetch,
getWalker().isInFrom(),
propertyType,
role,
joinPath
);
if ( joinColumns.length == 0 ) {
// When no columns are available, this is a special join that involves multiple subtypes
String lhsTableAlias = getLhs().getFromElement().getTableAlias();

AbstractEntityPersister persister = (AbstractEntityPersister) lhsFromElement.getEntityPersister();
Set<String> subclassEntityNames = (Set<String>) persister.getEntityMetamodel()
.getSubclassEntityNames();
// We will collect all the join columns from the LHS subtypes here
List<String[]> polymorphicJoinColumns = new ArrayList<>( subclassEntityNames.size() );

OUTER:
for ( String subclassEntityName : subclassEntityNames ) {
AbstractEntityPersister subclassPersister = (AbstractEntityPersister) getSessionFactoryHelper().getFactory()
.getMetamodel()
.entityPersister( subclassEntityName );
joinColumns = subclassPersister.toColumns( lhsTableAlias, propertyPath );

if ( joinColumns.length == 0 ) {
// The subtype does not have a "concrete" mapping for the property path
continue;
}

// Check for duplicates like this since we will mostly have just a few candidates
for ( String[] existingColumns : polymorphicJoinColumns ) {
if ( Arrays.deepEquals( existingColumns, joinColumns ) ) {
continue OUTER;
}
}
polymorphicJoinColumns.add( joinColumns );
}

String[][] polyJoinColumns = ArrayHelper.to2DStringArray( polymorphicJoinColumns );

// Special join sequence that uses the poly join columns
JoinSequence joinSequence = getSessionFactoryHelper()
.createJoinSequence( impliedJoin, propertyType, tableAlias, joinType, polyJoinColumns );

FromElementFactory factory = new FromElementFactory(
currentFromClause,
lhsFromElement,
joinPath,
classAlias,
new String[0],
impliedJoin
);

elem = factory.createEntityJoin(
associatedEntityName,
tableAlias,
joinSequence,
fetch,
getWalker().isInFrom(),
propertyType,
role,
joinPath
);
}
else {
// If this is an implied join in a from element, then use the impled join type which is part of the
// tree parser's state (set by the gramamar actions).
JoinSequence joinSequence = getSessionFactoryHelper()
.createJoinSequence( impliedJoin, propertyType, tableAlias, joinType, joinColumns );

FromElementFactory factory = new FromElementFactory(
currentFromClause,
lhsFromElement,
joinPath,
classAlias,
joinColumns,
impliedJoin
);
elem = factory.createEntityJoin(
associatedEntityName,
tableAlias,
joinSequence,
fetch,
getWalker().isInFrom(),
propertyType,
role,
joinPath
);
}
}
else {
// NOTE : addDuplicateAlias() already performs nullness checks on the alias.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,24 @@ public JoinSequence createJoinSequence(boolean implicit, AssociationType associa
return joinSequence;
}

/**
* Generate a join sequence representing the given association type.
*
* @param implicit Should implicit joins (theta-style) or explicit joins (ANSI-style) be rendered
* @param associationType The type representing the thing to be joined into.
* @param tableAlias The table alias to use in qualifying the join conditions
* @param joinType The type of join to render (inner, outer, etc); see {@link org.hibernate.sql.JoinFragment}
* @param columns The columns making up the condition of the join.
*
* @return The generated join sequence.
*/
public JoinSequence createJoinSequence(boolean implicit, AssociationType associationType, String tableAlias, JoinType joinType, String[][] columns) {
JoinSequence joinSequence = createJoinSequence();
joinSequence.setUseThetaStyle( implicit ); // Implicit joins use theta style (WHERE pk = fk), explicit joins use JOIN (afterQuery from)
joinSequence.addJoin( associationType, tableAlias, joinType, columns );
return joinSequence;
}

/**
* Create a join sequence rooted at the given collection.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
*/
package org.hibernate.loader.plan.exec.internal;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.AssertionFailure;
Expand All @@ -16,6 +19,7 @@
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl;
import org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl;
import org.hibernate.loader.plan.exec.process.spi.ReaderCollector;
Expand All @@ -38,6 +42,7 @@
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.CollectionPropertyNames;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.OuterJoinLoadable;
Expand Down Expand Up @@ -257,14 +262,59 @@ else if ( !StringHelper.isEmpty( joinConditions ) ) {
getJoinedAssociationTypeOrNull( join )
);

joinFragment.addJoin(
joinable.getTableName(),
rhsTableAlias,
join.resolveAliasedLeftHandSideJoinConditionColumns( lhsTableAlias ),
join.resolveNonAliasedRightHandSideJoinConditionColumns(),
join.isRightHandSideRequired() ? JoinType.INNER_JOIN : JoinType.LEFT_OUTER_JOIN,
additionalJoinConditions
);
String[] joinColumns = join.resolveAliasedLeftHandSideJoinConditionColumns( lhsTableAlias );
if ( joinColumns.length == 0 ) {
// When no columns are available, this is a special join that involves multiple subtypes
AbstractEntityPersister persister = (AbstractEntityPersister) ( (EntityQuerySpace) join.getLeftHandSide() ).getEntityPersister();
Set<String> subclassEntityNames = (Set<String>) persister.getEntityMetamodel()
.getSubclassEntityNames();
// We will collect all the join columns from the LHS subtypes here
List<String[]> polymorphicJoinColumns = new ArrayList<>( subclassEntityNames.size() );

OUTER:
for ( String subclassEntityName : subclassEntityNames ) {
AbstractEntityPersister subclassPersister = (AbstractEntityPersister) factory.getMetamodel()
.entityPersister( subclassEntityName );
joinColumns = subclassPersister.toColumns(
lhsTableAlias,
( (JoinDefinedByMetadata) join ).getJoinedPropertyName()
);

if ( joinColumns.length == 0 ) {
// The subtype does not have a "concrete" mapping for the property path
continue;
}

// Check for duplicates like this since we will mostly have just a few candidates
for ( String[] existingColumns : polymorphicJoinColumns ) {
if ( Arrays.deepEquals( existingColumns, joinColumns ) ) {
continue OUTER;
}
}
polymorphicJoinColumns.add( joinColumns );
}

String[][] polyJoinColumns = ArrayHelper.to2DStringArray( polymorphicJoinColumns );

joinFragment.addJoin(
joinable.getTableName(),
rhsTableAlias,
polyJoinColumns,
join.resolveNonAliasedRightHandSideJoinConditionColumns(),
join.isRightHandSideRequired() ? JoinType.INNER_JOIN : JoinType.LEFT_OUTER_JOIN,
additionalJoinConditions
);
}
else {
joinFragment.addJoin(
joinable.getTableName(),
rhsTableAlias,
joinColumns,
join.resolveNonAliasedRightHandSideJoinConditionColumns(),
join.isRightHandSideRequired() ? JoinType.INNER_JOIN : JoinType.LEFT_OUTER_JOIN,
additionalJoinConditions
);
}
joinFragment.addJoins(
joinable.fromJoinFragment( rhsTableAlias, false, true ),
joinable.whereJoinFragment( rhsTableAlias, false, true )
Expand Down
Loading