initial work on joined inheritance, implemented root queries
This commit is contained in:
parent
7120b8bd40
commit
bef4fc1fde
|
@ -108,7 +108,10 @@ import org.hibernate.sql.CaseFragment;
|
||||||
import org.hibernate.sql.ForUpdateFragment;
|
import org.hibernate.sql.ForUpdateFragment;
|
||||||
import org.hibernate.sql.JoinFragment;
|
import org.hibernate.sql.JoinFragment;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
||||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
|
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
|
||||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
|
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
|
||||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
|
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
|
||||||
|
@ -1782,6 +1785,34 @@ public abstract class Dialect implements ConversionContext {
|
||||||
return new ANSICaseFragment();
|
return new ANSICaseFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void visitCaseSearchedExpression(
|
||||||
|
CaseSearchedExpression caseSearchedExpression,
|
||||||
|
StringBuilder sqlBuffer,
|
||||||
|
SqlAstWalker sqlAstWalker) {
|
||||||
|
sqlBuffer.append( "case " );
|
||||||
|
|
||||||
|
for ( CaseSearchedExpression.WhenFragment whenFragment : caseSearchedExpression.getWhenFragments() ) {
|
||||||
|
sqlBuffer.append( " when " );
|
||||||
|
whenFragment.getPredicate().accept( sqlAstWalker );
|
||||||
|
sqlBuffer.append( " then " );
|
||||||
|
whenFragment.getResult().accept( sqlAstWalker );
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression otherwise = caseSearchedExpression.getOtherwise();
|
||||||
|
if ( otherwise != null ) {
|
||||||
|
sqlBuffer.append( " else " );
|
||||||
|
otherwise.accept( sqlAstWalker );
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlBuffer.append( " end" );
|
||||||
|
|
||||||
|
String columnExpression = caseSearchedExpression.getColumnExpression();
|
||||||
|
|
||||||
|
if ( columnExpression != null ) {
|
||||||
|
sqlBuffer.append( " as " ).append( columnExpression );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The fragment used to insert a row without specifying any column values.
|
* The fragment used to insert a row without specifying any column values.
|
||||||
* This is not possible on some databases.
|
* This is not possible on some databases.
|
||||||
|
|
|
@ -34,21 +34,28 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EntityDiscriminatorMappingImpl implements EntityDiscriminatorMapping {
|
public class EntityDiscriminatorMappingImpl implements EntityDiscriminatorMapping {
|
||||||
private final EntityPersister entityDescriptor;
|
private final EntityPersister entityPersister;
|
||||||
|
|
||||||
private final String tableExpression;
|
private final String tableExpression;
|
||||||
private final String mappedColumnExpression;
|
private String mappedColumnExpression;
|
||||||
|
|
||||||
private final BasicType mappingType;
|
private final BasicType mappingType;
|
||||||
|
|
||||||
public EntityDiscriminatorMappingImpl(
|
public EntityDiscriminatorMappingImpl(
|
||||||
EntityPersister entityDescriptor,
|
EntityPersister entityPersister,
|
||||||
String tableExpression,
|
String tableExpression,
|
||||||
String mappedColumnExpression,
|
String mappedColumnExpression,
|
||||||
BasicType mappingType) {
|
BasicType mappingType) {
|
||||||
this.entityDescriptor = entityDescriptor;
|
this( entityPersister, tableExpression, mappingType );
|
||||||
this.tableExpression = tableExpression;
|
|
||||||
this.mappedColumnExpression = mappedColumnExpression;
|
this.mappedColumnExpression = mappedColumnExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityDiscriminatorMappingImpl(
|
||||||
|
EntityPersister entityPersister,
|
||||||
|
String tableExpression,
|
||||||
|
BasicType mappingType) {
|
||||||
|
this.entityPersister = entityPersister;
|
||||||
|
this.tableExpression = tableExpression;
|
||||||
this.mappingType = mappingType;
|
this.mappingType = mappingType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +139,7 @@ public class EntityDiscriminatorMappingImpl implements EntityDiscriminatorMappin
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SqlSelection resolveSqlSelection(TableGroup tableGroup, DomainResultCreationState creationState) {
|
protected SqlSelection resolveSqlSelection(TableGroup tableGroup, DomainResultCreationState creationState) {
|
||||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||||
|
|
||||||
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
|
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
|
||||||
|
@ -169,4 +176,8 @@ public class EntityDiscriminatorMappingImpl implements EntityDiscriminatorMappin
|
||||||
public JdbcMapping getJdbcMapping() {
|
public JdbcMapping getJdbcMapping() {
|
||||||
return mappingType.getJdbcMapping();
|
return mappingType.getJdbcMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected EntityPersister getEntityPersister(){
|
||||||
|
return entityPersister;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public class JoinedSubclassDiscriminatorMappingImpl extends EntityDiscriminatorMappingImpl {
|
||||||
|
|
||||||
|
private final CaseSearchedExpression caseSearchedExpression;
|
||||||
|
|
||||||
|
public JoinedSubclassDiscriminatorMappingImpl(
|
||||||
|
EntityPersister entityDescriptor,
|
||||||
|
String tableExpression,
|
||||||
|
CaseSearchedExpression caseSearchedExpression,
|
||||||
|
BasicType mappingType) {
|
||||||
|
super( entityDescriptor, tableExpression, mappingType );
|
||||||
|
this.caseSearchedExpression = caseSearchedExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SqlSelection resolveSqlSelection(TableGroup tableGroup, DomainResultCreationState creationState) {
|
||||||
|
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState()
|
||||||
|
.getSqlExpressionResolver();
|
||||||
|
|
||||||
|
return expressionResolver.resolveSqlSelection(
|
||||||
|
expressionResolver.resolveSqlExpression(
|
||||||
|
getMappedColumnExpression(),
|
||||||
|
sqlAstProcessingState -> caseSearchedExpression
|
||||||
|
),
|
||||||
|
getMappedTypeDescriptor().getMappedJavaTypeDescriptor(),
|
||||||
|
creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.boot.model.relational.Database;
|
import org.hibernate.boot.model.relational.Database;
|
||||||
|
@ -42,14 +43,35 @@ import org.hibernate.mapping.Selectable;
|
||||||
import org.hibernate.mapping.Subclass;
|
import org.hibernate.mapping.Subclass;
|
||||||
import org.hibernate.mapping.Table;
|
import org.hibernate.mapping.Table;
|
||||||
import org.hibernate.mapping.Value;
|
import org.hibernate.mapping.Value;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.JoinedSubclassDiscriminatorMappingImpl;
|
||||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||||
import org.hibernate.sql.CaseFragment;
|
import org.hibernate.sql.CaseFragment;
|
||||||
import org.hibernate.sql.InFragment;
|
import org.hibernate.sql.InFragment;
|
||||||
import org.hibernate.sql.Insert;
|
import org.hibernate.sql.Insert;
|
||||||
import org.hibernate.sql.SelectFragment;
|
import org.hibernate.sql.SelectFragment;
|
||||||
|
import org.hibernate.sql.ast.Clause;
|
||||||
|
import org.hibernate.sql.ast.JoinType;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
|
import org.hibernate.sql.results.internal.domain.entity.JoinedSubclassResultImpl;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResult;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.spi.Fetchable;
|
import org.hibernate.sql.results.spi.Fetchable;
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.DiscriminatorType;
|
import org.hibernate.type.DiscriminatorType;
|
||||||
import org.hibernate.type.StandardBasicTypes;
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
|
import org.hibernate.type.StringType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
@ -130,9 +152,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
private final boolean[] isNullableTable;
|
private final boolean[] isNullableTable;
|
||||||
private final boolean[] isInverseTable;
|
private final boolean[] isInverseTable;
|
||||||
|
|
||||||
// private final String tableName;
|
private final Map<String, String> discriminatorValuesByTableName;
|
||||||
//
|
private final Map<String, String> subclassNameByTableName;
|
||||||
// private final String superClassTableName;
|
|
||||||
|
|
||||||
//INITIALIZATION:
|
//INITIALIZATION:
|
||||||
|
|
||||||
|
@ -211,16 +232,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
|
throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
|
||||||
}
|
}
|
||||||
|
|
||||||
// final PersistentClass superclass = persistentClass.getSuperclass();
|
|
||||||
// if ( superclass != null ) {
|
|
||||||
// superClassTableName = determineTableName( superclass.getTable(), jdbcEnvironment );
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// superClassTableName = null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// tableName = determineTableName( persistentClass.getTable(), jdbcEnvironment );
|
|
||||||
|
|
||||||
//MULTITABLES
|
//MULTITABLES
|
||||||
|
|
||||||
final int idColumnSpan = getIdentifierColumnSpan();
|
final int idColumnSpan = getIdentifierColumnSpan();
|
||||||
|
@ -513,6 +524,10 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
subclassClosure[subclassSpan - 1] = getEntityName();
|
subclassClosure[subclassSpan - 1] = getEntityName();
|
||||||
if ( persistentClass.isPolymorphic() ) {
|
if ( persistentClass.isPolymorphic() ) {
|
||||||
subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
|
subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
|
||||||
|
|
||||||
|
discriminatorValuesByTableName = new HashMap<>( subclassSpan + 1 );
|
||||||
|
subclassNameByTableName = new HashMap<>( subclassSpan + 1);
|
||||||
|
discriminatorValuesByTableName.put( persistentClass.getTable().getName(), discriminatorSQLString);
|
||||||
discriminatorValues = new String[subclassSpan];
|
discriminatorValues = new String[subclassSpan];
|
||||||
discriminatorValues[subclassSpan - 1] = discriminatorSQLString;
|
discriminatorValues[subclassSpan - 1] = discriminatorSQLString;
|
||||||
notNullColumnTableNumbers = new int[subclassSpan];
|
notNullColumnTableNumbers = new int[subclassSpan];
|
||||||
|
@ -529,6 +544,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
notNullColumnNames[subclassSpan - 1] = subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
|
notNullColumnNames[subclassSpan - 1] = subclassTableKeyColumnClosure[id][0]; //( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
subclassNameByTableName = Collections.EMPTY_MAP;
|
||||||
|
discriminatorValuesByTableName = Collections.EMPTY_MAP;
|
||||||
discriminatorValues = null;
|
discriminatorValues = null;
|
||||||
notNullColumnTableNumbers = null;
|
notNullColumnTableNumbers = null;
|
||||||
notNullColumnNames = null;
|
notNullColumnNames = null;
|
||||||
|
@ -539,6 +556,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
while ( iter.hasNext() ) {
|
while ( iter.hasNext() ) {
|
||||||
Subclass sc = (Subclass) iter.next();
|
Subclass sc = (Subclass) iter.next();
|
||||||
subclassClosure[k] = sc.getEntityName();
|
subclassClosure[k] = sc.getEntityName();
|
||||||
|
subclassNameByTableName.put( sc.getTable().getName(), sc.getClassName() );
|
||||||
try {
|
try {
|
||||||
if ( persistentClass.isPolymorphic() ) {
|
if ( persistentClass.isPolymorphic() ) {
|
||||||
final Object discriminatorValue;
|
final Object discriminatorValue;
|
||||||
|
@ -567,7 +585,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
// "foo.class = Bar" works in HQL
|
// "foo.class = Bar" works in HQL
|
||||||
discriminatorValue = sc.getSubclassId();
|
discriminatorValue = sc.getSubclassId();
|
||||||
}
|
}
|
||||||
|
discriminatorValuesByTableName.put( sc.getTable().getName(), discriminatorValue.toString() );
|
||||||
subclassesByDiscriminatorValue.put( discriminatorValue, sc.getEntityName() );
|
subclassesByDiscriminatorValue.put( discriminatorValue, sc.getEntityName() );
|
||||||
discriminatorValues[k] = discriminatorValue.toString();
|
discriminatorValues[k] = discriminatorValue.toString();
|
||||||
int id = getTableId(
|
int id = getTableId(
|
||||||
|
@ -1127,24 +1145,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
throw new HibernateException( "Could not locate table which owns column [" + columnName + "] referenced in order-by mapping" );
|
throw new HibernateException( "Could not locate table which owns column [" + columnName + "] referenced in order-by mapping" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void buildDiscriminatorMapping() {
|
|
||||||
if ( hasSubclasses() ) {
|
|
||||||
super.buildDiscriminatorMapping();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<Fetchable> getStaticFetchableList() {
|
|
||||||
if ( staticFetchableList == null ) {
|
|
||||||
staticFetchableList = new ArrayList<>( getAttributeMappings().size() );
|
|
||||||
visitAttributeMappings( attributeMapping -> staticFetchableList.add( (Fetchable) attributeMapping ) );
|
|
||||||
|
|
||||||
}
|
|
||||||
return staticFetchableList;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FilterAliasGenerator getFilterAliasGenerator(String rootAlias) {
|
public FilterAliasGenerator getFilterAliasGenerator(String rootAlias) {
|
||||||
return new DynamicFilterAliasGenerator(subclassTableNameClosure, rootAlias);
|
return new DynamicFilterAliasGenerator(subclassTableNameClosure, rootAlias);
|
||||||
|
@ -1154,4 +1154,117 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
||||||
public boolean canOmitSuperclassTableJoin() {
|
public boolean canOmitSuperclassTableJoin() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> DomainResult<T> createDomainResult(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
TableGroup tableGroup,
|
||||||
|
String resultVariable,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
if ( hasSubclasses() ) {
|
||||||
|
//noinspection unchecked
|
||||||
|
return new JoinedSubclassResultImpl( navigablePath, this, resultVariable, creationState );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return super.createDomainResult( navigablePath, tableGroup, resultVariable, creationState );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableGroup createRootTableGroup(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
String explicitSourceAlias,
|
||||||
|
JoinType tableReferenceJoinType,
|
||||||
|
LockMode lockMode,
|
||||||
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
|
SqlAstCreationContext creationContext) {
|
||||||
|
if ( hasSubclasses() ) {
|
||||||
|
tableReferenceJoinType = JoinType.LEFT;
|
||||||
|
}
|
||||||
|
return super.createRootTableGroup(
|
||||||
|
navigablePath,
|
||||||
|
explicitSourceAlias,
|
||||||
|
tableReferenceJoinType,
|
||||||
|
lockMode,
|
||||||
|
aliasBaseGenerator,
|
||||||
|
sqlExpressionResolver,
|
||||||
|
additionalPredicateCollectorAccess,
|
||||||
|
creationContext
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityDiscriminatorMapping getDiscriminatorMapping(TableGroup tableGroup) {
|
||||||
|
return new JoinedSubclassDiscriminatorMappingImpl(
|
||||||
|
this,
|
||||||
|
getRootTableName(),
|
||||||
|
getCaseSearchedExpression( tableGroup ),
|
||||||
|
(BasicType) getDiscriminatorType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CaseSearchedExpression getCaseSearchedExpression(TableGroup entityTableGroup) {
|
||||||
|
final TableReference primaryTableReference = entityTableGroup.getPrimaryTableReference();
|
||||||
|
final List<TableReferenceJoin> tableReferenceJoins = entityTableGroup.getTableReferenceJoins();
|
||||||
|
final BasicType discriminatorType = (BasicType) getDiscriminatorType();
|
||||||
|
final CaseSearchedExpression caseSearchedExpression = new CaseSearchedExpression( discriminatorType );
|
||||||
|
|
||||||
|
caseSearchedExpression.setColumnExpression( getDiscriminatorColumnName() );
|
||||||
|
|
||||||
|
tableReferenceJoins.forEach(
|
||||||
|
tableReferenceJoin -> {
|
||||||
|
final TableReference joinedTableReference = tableReferenceJoin.getJoinedTableReference();
|
||||||
|
final EntityPersister entityDescriptor = getFactory().getMetamodel()
|
||||||
|
.findEntityDescriptor( subclassNameByTableName.get( joinedTableReference.getTableExpression() ) );
|
||||||
|
if ( entityDescriptor instanceof JoinedSubclassEntityPersister ) {
|
||||||
|
addWhen(
|
||||||
|
caseSearchedExpression,
|
||||||
|
joinedTableReference,
|
||||||
|
( (JoinedSubclassEntityPersister) entityDescriptor )
|
||||||
|
.getIdentifierColumnReferenceForCaseExpression( joinedTableReference ),
|
||||||
|
discriminatorType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
addWhen(
|
||||||
|
caseSearchedExpression,
|
||||||
|
primaryTableReference,
|
||||||
|
getIdentifierColumnReferenceForCaseExpression( primaryTableReference ),
|
||||||
|
discriminatorType
|
||||||
|
);
|
||||||
|
|
||||||
|
return caseSearchedExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addWhen(
|
||||||
|
CaseSearchedExpression caseSearchedExpression,
|
||||||
|
TableReference table,
|
||||||
|
ColumnReference identifierColumnReference,
|
||||||
|
BasicType resultType) {
|
||||||
|
final Predicate predicate = new NullnessPredicate( identifierColumnReference, true );
|
||||||
|
final Expression expression =
|
||||||
|
new QueryLiteral<>(
|
||||||
|
discriminatorValuesByTableName.get( table.getTableExpression() ),
|
||||||
|
resultType,
|
||||||
|
Clause.SELECT
|
||||||
|
);
|
||||||
|
|
||||||
|
caseSearchedExpression.when( predicate, expression );
|
||||||
|
}
|
||||||
|
|
||||||
|
private ColumnReference getIdentifierColumnReferenceForCaseExpression(TableReference primaryTableReference) {
|
||||||
|
List<JdbcMapping> jdbcMappings = getIdentifierMapping().getJdbcMappings( getFactory().getTypeConfiguration() );
|
||||||
|
JdbcMapping jdbcMapping = jdbcMappings.get( 0 );
|
||||||
|
|
||||||
|
return new ColumnReference(
|
||||||
|
primaryTableReference.getIdentificationVariable(),
|
||||||
|
getIdentifierColumnNames()[0],
|
||||||
|
jdbcMapping,
|
||||||
|
getFactory()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.SortOrder;
|
import org.hibernate.SortOrder;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.internal.util.collections.Stack;
|
import org.hibernate.internal.util.collections.Stack;
|
||||||
|
@ -83,9 +84,12 @@ public abstract class AbstractSqlAstWalker
|
||||||
|
|
||||||
private final Stack<Clause> clauseStack = new StandardStack<>();
|
private final Stack<Clause> clauseStack = new StandardStack<>();
|
||||||
|
|
||||||
|
private final Dialect dialect;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
protected AbstractSqlAstWalker(SessionFactoryImplementor sessionFactory) {
|
protected AbstractSqlAstWalker(SessionFactoryImplementor sessionFactory) {
|
||||||
this.sessionFactory = sessionFactory;
|
this.sessionFactory = sessionFactory;
|
||||||
|
this.dialect = sessionFactory.getJdbcServices().getDialect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -426,9 +430,7 @@ public abstract class AbstractSqlAstWalker
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitSqlSelectionExpression(SqlSelectionExpression expression) {
|
public void visitSqlSelectionExpression(SqlSelectionExpression expression) {
|
||||||
final boolean useSelectionPosition = getSessionFactory().getJdbcServices()
|
final boolean useSelectionPosition = dialect.replaceResultVariableInOrderByClauseWithPosition();
|
||||||
.getDialect()
|
|
||||||
.replaceResultVariableInOrderByClauseWithPosition();
|
|
||||||
|
|
||||||
if ( useSelectionPosition ) {
|
if ( useSelectionPosition ) {
|
||||||
appendSql( Integer.toString( expression.getSelection().getJdbcResultSetIndex() ) );
|
appendSql( Integer.toString( expression.getSelection().getJdbcResultSetIndex() ) );
|
||||||
|
@ -740,19 +742,7 @@ public abstract class AbstractSqlAstWalker
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression) {
|
public void visitCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression) {
|
||||||
appendSql( "case " );
|
dialect.visitCaseSearchedExpression( caseSearchedExpression, sqlBuffer, this );
|
||||||
|
|
||||||
for ( CaseSearchedExpression.WhenFragment whenFragment : caseSearchedExpression.getWhenFragments() ) {
|
|
||||||
appendSql( " when " );
|
|
||||||
whenFragment.getPredicate().accept( this );
|
|
||||||
appendSql( " then " );
|
|
||||||
whenFragment.getResult().accept( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
appendSql( " else " );
|
|
||||||
caseSearchedExpression.getOtherwise().accept( this );
|
|
||||||
|
|
||||||
appendSql( " end" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -843,7 +833,7 @@ public abstract class AbstractSqlAstWalker
|
||||||
appendSql(
|
appendSql(
|
||||||
literalFormatter.toJdbcLiteral(
|
literalFormatter.toJdbcLiteral(
|
||||||
queryLiteral.getValue(),
|
queryLiteral.getValue(),
|
||||||
sessionFactory.getJdbcServices().getJdbcEnvironment().getDialect(),
|
dialect,
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,25 +10,39 @@ package org.hibernate.sql.ast.tree.expression;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
|
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||||
|
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
|
||||||
import org.hibernate.sql.results.spi.DomainResult;
|
import org.hibernate.sql.results.spi.DomainResult;
|
||||||
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class CaseSearchedExpression implements Expression, DomainResultProducer {
|
public class CaseSearchedExpression implements Expression, DomainResultProducer {
|
||||||
private final MappingModelExpressable type;
|
private final BasicType type;
|
||||||
|
|
||||||
private List<WhenFragment> whenFragments = new ArrayList<>();
|
private List<WhenFragment> whenFragments = new ArrayList<>();
|
||||||
private Expression otherwise;
|
private Expression otherwise;
|
||||||
|
private String columnExpression;
|
||||||
|
|
||||||
public CaseSearchedExpression(MappingModelExpressable type) {
|
public CaseSearchedExpression(MappingModelExpressable type) {
|
||||||
this.type = type;
|
this.type = (BasicType) type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColumnExpression(String columnExpression) {
|
||||||
|
this.columnExpression = columnExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getColumnExpression(){
|
||||||
|
return columnExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WhenFragment> getWhenFragments() {
|
public List<WhenFragment> getWhenFragments() {
|
||||||
|
@ -52,17 +66,36 @@ public class CaseSearchedExpression implements Expression, DomainResultProducer
|
||||||
public DomainResult createDomainResult(
|
public DomainResult createDomainResult(
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
|
||||||
|
|
||||||
// return new BasicResultImpl(
|
final SqlSelection sqlSelection = creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(
|
||||||
// resultVariable,
|
this,
|
||||||
// creationState.getSqlExpressionResolver().resolveSqlSelection(
|
type.getExpressableJavaTypeDescriptor(),
|
||||||
// this,
|
creationState.getSqlAstCreationState()
|
||||||
// getType().getJavaTypeDescriptor(),
|
.getCreationContext()
|
||||||
// creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
|
.getSessionFactory()
|
||||||
// ),
|
.getTypeConfiguration()
|
||||||
// getType()
|
);
|
||||||
// );
|
|
||||||
|
//noinspection unchecked
|
||||||
|
return new BasicResult(
|
||||||
|
sqlSelection.getValuesArrayPosition(),
|
||||||
|
resultVariable,
|
||||||
|
type.getExpressableJavaTypeDescriptor()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqlSelection createSqlSelection(
|
||||||
|
int jdbcPosition,
|
||||||
|
int valuesArrayPosition,
|
||||||
|
JavaTypeDescriptor javaTypeDescriptor,
|
||||||
|
TypeConfiguration typeConfiguration) {
|
||||||
|
return new SqlSelectionImpl(
|
||||||
|
jdbcPosition,
|
||||||
|
valuesArrayPosition,
|
||||||
|
this,
|
||||||
|
type.getJdbcMapping()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -64,8 +64,9 @@ public abstract class AbstractEntityResultNode extends AbstractFetchParent imple
|
||||||
creationState
|
creationState
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( entityDescriptor.getDiscriminatorMapping() != null ) {
|
final EntityDiscriminatorMapping discriminatorMapping = getDiscriminatorMapping( entityDescriptor, entityTableGroup );
|
||||||
discriminatorResult = entityDescriptor.getDiscriminatorMapping().createDomainResult(
|
if ( discriminatorMapping != null ) {
|
||||||
|
discriminatorResult = discriminatorMapping.createDomainResult(
|
||||||
navigablePath.append( EntityDiscriminatorMapping.ROLE_NAME ),
|
navigablePath.append( EntityDiscriminatorMapping.ROLE_NAME ),
|
||||||
entityTableGroup,
|
entityTableGroup,
|
||||||
null,
|
null,
|
||||||
|
@ -90,6 +91,12 @@ public abstract class AbstractEntityResultNode extends AbstractFetchParent imple
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected EntityDiscriminatorMapping getDiscriminatorMapping(
|
||||||
|
EntityMappingType entityDescriptor,
|
||||||
|
TableGroup entityTableGroup) {
|
||||||
|
return entityDescriptor.getDiscriminatorMapping();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityValuedModelPart getReferencedMappingContainer() {
|
public EntityValuedModelPart getReferencedMappingContainer() {
|
||||||
return getEntityValuedModelPart();
|
return getEntityValuedModelPart();
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.sql.results.internal.domain.entity;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||||
|
import org.hibernate.persister.entity.JoinedSubclassEntityPersister;
|
||||||
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.results.spi.AssemblerCreationState;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResultAssembler;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrea Boriero
|
||||||
|
*/
|
||||||
|
public class JoinedSubclassResultImpl extends EntityResultImpl {
|
||||||
|
public JoinedSubclassResultImpl(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
EntityValuedModelPart entityValuedModelPart,
|
||||||
|
String resultVariable,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
super( navigablePath, entityValuedModelPart, resultVariable, creationState );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DomainResultAssembler createResultAssembler(
|
||||||
|
Consumer initializerCollector,
|
||||||
|
AssemblerCreationState creationState) {
|
||||||
|
// todo (6.0) : seems like here is where we ought to determine the SQL selection mappings
|
||||||
|
|
||||||
|
final EntityRootInitializer initializer = new EntityRootInitializer(
|
||||||
|
this,
|
||||||
|
getNavigablePath(),
|
||||||
|
getLockMode(),
|
||||||
|
getIdentifierResult(),
|
||||||
|
getDiscriminatorResult(),
|
||||||
|
getVersionResult(),
|
||||||
|
initializerCollector,
|
||||||
|
creationState
|
||||||
|
);
|
||||||
|
|
||||||
|
return new EntityAssembler( getResultJavaTypeDescriptor(), initializer );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected EntityDiscriminatorMapping getDiscriminatorMapping(
|
||||||
|
EntityMappingType entityDescriptor,
|
||||||
|
TableGroup entityTableGroup) {
|
||||||
|
final JoinedSubclassEntityPersister joinedSubclassEntityPersister = (JoinedSubclassEntityPersister) entityDescriptor;
|
||||||
|
if ( joinedSubclassEntityPersister.hasSubclasses() ) {
|
||||||
|
return joinedSubclassEntityPersister.getDiscriminatorMapping( entityTableGroup );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,7 +77,6 @@ public class JoinedInheritanceTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected
|
|
||||||
public void rootQueryExecutionTest(SessionFactoryScope scope) {
|
public void rootQueryExecutionTest(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
|
|
Loading…
Reference in New Issue