initial work on support for discrim-inheritance;
started design doc about SQM model, building and translation; initial work on `#load` support (strange error in BasicFormatterImpl as part of SqlStatementLogger)
This commit is contained in:
parent
26d914f414
commit
31e2423d8a
|
@ -0,0 +1,29 @@
|
||||||
|
== SQM
|
||||||
|
|
||||||
|
The Semantic Query Model (SQM) is Hibernate's representation of an HQL or Criteria query's semantic (meaning). This
|
||||||
|
representation is modeled as an "abstract syntax tree" (AST) - meaning it is a structured tree of nodes where each node
|
||||||
|
represrents an atomic piece of the query. E.g. `SqmSelectClause` represents the query's select clause as you might
|
||||||
|
imagine. That `SqmSelectClause` is ultimately a collection of one or more `SqmSelection` references representing the
|
||||||
|
individual selections to be returned from the query (called the domain results).
|
||||||
|
|
||||||
|
=== The Model
|
||||||
|
|
||||||
|
This SQM model uses the Hibernate domain model, which is Hibernate's extension to the JPA model. This model contains no
|
||||||
|
relational mapping information, it simply describes the domain model in mostly Java terms although it does incorporate
|
||||||
|
"classifications" of the type system. E.g. it understand that `Customer` is an entity, but contains no information
|
||||||
|
about the tables it maps to nor its columns.
|
||||||
|
|
||||||
|
See the `design/type-system-domain.adoc` design doc. For details about this domain model
|
||||||
|
|
||||||
|
|
||||||
|
=== Building an SQM
|
||||||
|
|
||||||
|
|
||||||
|
=== Interpreting an SQM
|
||||||
|
|
||||||
|
Ultimately Hibernate needs to talk with the database to fulfill these query executions. This is currently a 2-step process.
|
||||||
|
|
||||||
|
First we convert the SQM into a new AST called the SQL AST. This is an AST that is more "SQL-y". It's nodes are defined
|
||||||
|
in terms of Hibernate's mapping model which is the model that actually does understand the relational mapping.
|
||||||
|
See `design/type-system-mapping.adoc` for details about this model. Part of this conversion step is to resolving
|
||||||
|
domain model references to mapping model references...
|
|
@ -95,6 +95,8 @@ public class BasicFormatterImpl implements Formatter {
|
||||||
String lcToken;
|
String lcToken;
|
||||||
|
|
||||||
public FormatProcess(String sql) {
|
public FormatProcess(String sql) {
|
||||||
|
assert sql != null : "SQL to format should not be null";
|
||||||
|
|
||||||
tokens = new StringTokenizer(
|
tokens = new StringTokenizer(
|
||||||
sql,
|
sql,
|
||||||
"()+*/-=<>'`\"[]," + StringHelper.WHITESPACE,
|
"()+*/-=<>'`\"[]," + StringHelper.WHITESPACE,
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.internal;
|
package org.hibernate.loader.internal;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
@ -14,9 +15,11 @@ import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.loader.entity.BatchingEntityLoaderBuilder;
|
||||||
import org.hibernate.loader.spi.InternalFetchProfile;
|
import org.hibernate.loader.spi.InternalFetchProfile;
|
||||||
import org.hibernate.loader.spi.SingleIdEntityLoader;
|
import org.hibernate.loader.spi.SingleIdEntityLoader;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,14 +48,21 @@ public class SingleIdEntityLoaderStandardImpl<T> implements SingleIdEntityLoader
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T load(Object key, LockOptions lockOptions, SharedSessionContractImplementor session) {
|
public T load(Object key, LockOptions lockOptions, SharedSessionContractImplementor session) {
|
||||||
|
// todo (6.0) : TEMPORARY - use the legacy loaders
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
return (T) BatchingEntityLoaderBuilder.getBuilder( session.getFactory() )
|
||||||
|
.buildLoader( (OuterJoinLoadable) entityDescriptor, -1, lockOptions.getLockMode(), session.getFactory(), session.getLoadQueryInfluencers() )
|
||||||
|
.load( (Serializable) key, null, session, lockOptions );
|
||||||
|
|
||||||
|
|
||||||
// todo (6.0) : see `org.hibernate.loader.internal.StandardSingleIdEntityLoader#load` in "upstream" 6.0 branch
|
// todo (6.0) : see `org.hibernate.loader.internal.StandardSingleIdEntityLoader#load` in "upstream" 6.0 branch
|
||||||
// - and integrate as much as possible with the `o.h.loader.plan` stuff leveraging the similarities
|
// - and integrate as much as possible with the `o.h.loader.plan` stuff leveraging the similarities
|
||||||
// between the legacy LoadPlan stuff and DomainResult, Assembler, etc.
|
// between the legacy LoadPlan stuff and DomainResult, Assembler, etc.
|
||||||
|
//
|
||||||
final JdbcSelect jdbcSelect = resolveJdbcSelect( lockOptions, session );
|
// final JdbcSelect jdbcSelect = resolveJdbcSelect( lockOptions, session );
|
||||||
|
//
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
// throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.spi;
|
package org.hibernate.loader.spi;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
|
@ -17,6 +20,7 @@ import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
import org.hibernate.sql.ast.tree.from.RootTableGroupProducer;
|
import org.hibernate.sql.ast.tree.from.RootTableGroupProducer;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract for things that can be loaded by a Loader.
|
* Contract for things that can be loaded by a Loader.
|
||||||
|
@ -40,6 +44,7 @@ public interface Loadable extends ModelPart, RootTableGroupProducer {
|
||||||
LockMode lockMode,
|
LockMode lockMode,
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValuedModelPart {
|
||||||
|
String ROLE_NAME = "{discriminator}";
|
||||||
|
}
|
|
@ -33,6 +33,10 @@ public interface EntityMappingType extends ManagedMappingType {
|
||||||
|
|
||||||
EntityVersionMapping getVersionMapping();
|
EntityVersionMapping getVersionMapping();
|
||||||
|
|
||||||
|
default EntityDiscriminatorMapping getDiscriminatorMapping() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
NaturalIdMapping getNaturalIdMapping();
|
NaturalIdMapping getNaturalIdMapping();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker interface for parts of the application domain model that are virtual - do not
|
||||||
|
* actually exist in the model classes
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface VirtualModelPart extends ModelPart {
|
||||||
|
}
|
|
@ -121,8 +121,8 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
|
||||||
getMappedColumnExpression()
|
getMappedColumnExpression()
|
||||||
),
|
),
|
||||||
sqlAstProcessingState -> new ColumnReference(
|
sqlAstProcessingState -> new ColumnReference(
|
||||||
getMappedColumnExpression(),
|
|
||||||
tableReference.getIdentificationVariable(),
|
tableReference.getIdentificationVariable(),
|
||||||
|
getMappedColumnExpression(),
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
||||||
)
|
)
|
||||||
|
@ -149,8 +149,8 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
|
||||||
getMappedColumnExpression()
|
getMappedColumnExpression()
|
||||||
),
|
),
|
||||||
sqlAstProcessingState -> new ColumnReference(
|
sqlAstProcessingState -> new ColumnReference(
|
||||||
getMappedColumnExpression(),
|
|
||||||
tableReference.getIdentificationVariable(),
|
tableReference.getIdentificationVariable(),
|
||||||
|
getMappedColumnExpression(),
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
||||||
)
|
)
|
||||||
|
|
|
@ -189,8 +189,8 @@ public class EmbeddedAttributeMapping
|
||||||
attrColumnExpr
|
attrColumnExpr
|
||||||
),
|
),
|
||||||
sqlAstProcessingState -> new ColumnReference(
|
sqlAstProcessingState -> new ColumnReference(
|
||||||
attrColumnExpr,
|
|
||||||
tableReference.getIdentificationVariable(),
|
tableReference.getIdentificationVariable(),
|
||||||
|
attrColumnExpr,
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
sqlAstCreationState.getCreationContext().getSessionFactory()
|
sqlAstCreationState.getCreationContext().getSessionFactory()
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
/*
|
||||||
|
* 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.LockMode;
|
||||||
|
import org.hibernate.engine.FetchStrategy;
|
||||||
|
import org.hibernate.engine.FetchTiming;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
|
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.query.sqm.sql.SqlAstCreationState;
|
||||||
|
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
|
import org.hibernate.sql.results.internal.domain.basic.BasicFetch;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
|
import org.hibernate.sql.results.spi.Fetch;
|
||||||
|
import org.hibernate.sql.results.spi.FetchParent;
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class EntityDiscriminatorMappingImpl implements EntityDiscriminatorMapping {
|
||||||
|
private final EntityPersister entityDescriptor;
|
||||||
|
|
||||||
|
private final String tableExpression;
|
||||||
|
private final String mappedColumnExpression;
|
||||||
|
|
||||||
|
private final BasicType mappingType;
|
||||||
|
|
||||||
|
public EntityDiscriminatorMappingImpl(
|
||||||
|
EntityPersister entityDescriptor,
|
||||||
|
String tableExpression,
|
||||||
|
String mappedColumnExpression,
|
||||||
|
BasicType mappingType) {
|
||||||
|
this.entityDescriptor = entityDescriptor;
|
||||||
|
this.tableExpression = tableExpression;
|
||||||
|
this.mappedColumnExpression = mappedColumnExpression;
|
||||||
|
this.mappingType = mappingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getContainingTableExpression() {
|
||||||
|
return tableExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMappedColumnExpression() {
|
||||||
|
return mappedColumnExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BasicValueConverter getConverter() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFetchableName() {
|
||||||
|
return ROLE_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FetchStrategy getMappedFetchStrategy() {
|
||||||
|
return FetchStrategy.IMMEDIATE_JOIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Fetch generateFetch(
|
||||||
|
FetchParent fetchParent,
|
||||||
|
NavigablePath fetchablePath,
|
||||||
|
FetchTiming fetchTiming,
|
||||||
|
boolean selected,
|
||||||
|
LockMode lockMode,
|
||||||
|
String resultVariable,
|
||||||
|
DomainResultCreationState creationState) {
|
||||||
|
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||||
|
final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup(
|
||||||
|
fetchParent.getNavigablePath()
|
||||||
|
);
|
||||||
|
|
||||||
|
assert tableGroup != null;
|
||||||
|
|
||||||
|
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, creationState );
|
||||||
|
|
||||||
|
return new BasicFetch(
|
||||||
|
sqlSelection.getValuesArrayPosition(),
|
||||||
|
fetchParent,
|
||||||
|
fetchablePath,
|
||||||
|
this,
|
||||||
|
false,
|
||||||
|
getConverter(),
|
||||||
|
fetchTiming,
|
||||||
|
creationState
|
||||||
|
);
|
||||||
|
}
|
||||||
|
private SqlSelection resolveSqlSelection(TableGroup tableGroup, DomainResultCreationState creationState) {
|
||||||
|
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||||
|
|
||||||
|
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
|
||||||
|
|
||||||
|
return expressionResolver.resolveSqlSelection(
|
||||||
|
expressionResolver.resolveSqlExpression(
|
||||||
|
SqlExpressionResolver.createColumnReferenceKey(
|
||||||
|
tableReference,
|
||||||
|
getMappedColumnExpression()
|
||||||
|
),
|
||||||
|
sqlAstProcessingState -> new ColumnReference(
|
||||||
|
tableReference.getIdentificationVariable(),
|
||||||
|
getMappedColumnExpression(),
|
||||||
|
mappingType.getJdbcMapping(),
|
||||||
|
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
getMappedTypeDescriptor().getMappedJavaTypeDescriptor(),
|
||||||
|
creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JavaTypeDescriptor getJavaTypeDescriptor() {
|
||||||
|
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MappingType getMappedTypeDescriptor() {
|
||||||
|
return mappingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JdbcMapping getJdbcMapping() {
|
||||||
|
return mappingType.getJdbcMapping();
|
||||||
|
}
|
||||||
|
}
|
|
@ -135,8 +135,8 @@ public class MappingModelCreationHelper {
|
||||||
final Expression expression = expressionResolver.resolveSqlExpression(
|
final Expression expression = expressionResolver.resolveSqlExpression(
|
||||||
SqlExpressionResolver.createColumnReferenceKey( rootTableReference, pkColumnName ),
|
SqlExpressionResolver.createColumnReferenceKey( rootTableReference, pkColumnName ),
|
||||||
sqlAstProcessingState -> new ColumnReference(
|
sqlAstProcessingState -> new ColumnReference(
|
||||||
pkColumnName,
|
|
||||||
rootTableReference.getIdentificationVariable(),
|
rootTableReference.getIdentificationVariable(),
|
||||||
|
pkColumnName,
|
||||||
( (BasicValuedMapping) entityPersister.getIdentifierType() ).getJdbcMapping(),
|
( (BasicValuedMapping) entityPersister.getIdentifierType() ).getJdbcMapping(),
|
||||||
creationProcess.getCreationContext().getSessionFactory()
|
creationProcess.getCreationContext().getSessionFactory()
|
||||||
)
|
)
|
||||||
|
@ -167,8 +167,8 @@ public class MappingModelCreationHelper {
|
||||||
final Expression expression = expressionResolver.resolveSqlExpression(
|
final Expression expression = expressionResolver.resolveSqlExpression(
|
||||||
SqlExpressionResolver.createColumnReferenceKey( rootTableReference, pkColumnName ),
|
SqlExpressionResolver.createColumnReferenceKey( rootTableReference, pkColumnName ),
|
||||||
sqlAstProcessingState -> new ColumnReference(
|
sqlAstProcessingState -> new ColumnReference(
|
||||||
pkColumnName,
|
|
||||||
rootTable,
|
rootTable,
|
||||||
|
pkColumnName,
|
||||||
( (BasicValuedModelPart) entityPersister.getIdentifierType() ).getJdbcMapping(),
|
( (BasicValuedModelPart) entityPersister.getIdentifierType() ).getJdbcMapping(),
|
||||||
creationProcess.getCreationContext().getSessionFactory()
|
creationProcess.getCreationContext().getSessionFactory()
|
||||||
)
|
)
|
||||||
|
|
|
@ -31,6 +31,7 @@ import java.util.TreeSet;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.EntityMode;
|
import org.hibernate.EntityMode;
|
||||||
|
@ -104,7 +105,6 @@ import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.FilterHelper;
|
import org.hibernate.internal.FilterHelper;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
|
||||||
import org.hibernate.jdbc.Expectation;
|
import org.hibernate.jdbc.Expectation;
|
||||||
import org.hibernate.jdbc.Expectations;
|
import org.hibernate.jdbc.Expectations;
|
||||||
import org.hibernate.jdbc.TooManyRowsAffectedException;
|
import org.hibernate.jdbc.TooManyRowsAffectedException;
|
||||||
|
@ -134,6 +134,7 @@ import org.hibernate.metadata.ClassMetadata;
|
||||||
import org.hibernate.metamodel.RepresentationMode;
|
import org.hibernate.metamodel.RepresentationMode;
|
||||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.AttributeMetadata;
|
import org.hibernate.metamodel.mapping.AttributeMetadata;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.EntityVersionMapping;
|
import org.hibernate.metamodel.mapping.EntityVersionMapping;
|
||||||
|
@ -144,6 +145,7 @@ import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||||
import org.hibernate.metamodel.mapping.Queryable;
|
import org.hibernate.metamodel.mapping.Queryable;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadata;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMetadata;
|
||||||
|
import org.hibernate.metamodel.mapping.internal.EntityDiscriminatorMappingImpl;
|
||||||
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
|
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
|
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
|
||||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||||
|
@ -179,6 +181,7 @@ import org.hibernate.sql.ast.spi.SqlAliasStemHelper;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||||
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
|
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
|
@ -1180,6 +1183,7 @@ public abstract class AbstractEntityPersister
|
||||||
LockMode lockMode,
|
LockMode lockMode,
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAstCreationContext creationContext) {
|
SqlAstCreationContext creationContext) {
|
||||||
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
||||||
|
|
||||||
|
@ -1274,8 +1278,8 @@ public abstract class AbstractEntityPersister
|
||||||
rootPkColumnName
|
rootPkColumnName
|
||||||
),
|
),
|
||||||
sqlAstProcessingState -> new ColumnReference(
|
sqlAstProcessingState -> new ColumnReference(
|
||||||
rootPkColumnName,
|
|
||||||
rootTableReference.getIdentificationVariable(),
|
rootTableReference.getIdentificationVariable(),
|
||||||
|
rootPkColumnName,
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
getFactory()
|
getFactory()
|
||||||
)
|
)
|
||||||
|
@ -1288,8 +1292,8 @@ public abstract class AbstractEntityPersister
|
||||||
fkColumnName
|
fkColumnName
|
||||||
),
|
),
|
||||||
sqlAstProcessingState -> new ColumnReference(
|
sqlAstProcessingState -> new ColumnReference(
|
||||||
fkColumnName,
|
|
||||||
joinedTableReference.getIdentificationVariable(),
|
joinedTableReference.getIdentificationVariable(),
|
||||||
|
fkColumnName,
|
||||||
jdbcMapping,
|
jdbcMapping,
|
||||||
getFactory()
|
getFactory()
|
||||||
)
|
)
|
||||||
|
@ -5404,18 +5408,22 @@ public abstract class AbstractEntityPersister
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final String concreteEntityName = getEntityTuplizer().determineConcreteSubclassEntityName(
|
// todo (6.0) : this previously used `org.hibernate.tuple.entity.EntityTuplizer#determineConcreteSubclassEntityName`
|
||||||
instance,
|
// - we may need something similar here...
|
||||||
factory
|
|
||||||
);
|
if ( getRepresentationStrategy().getInstantiator().isInstance( instance, factory ) ) {
|
||||||
if ( concreteEntityName == null || getEntityName().equals( concreteEntityName ) ) {
|
|
||||||
// the contract of EntityTuplizer.determineConcreteSubclassEntityName says that returning null
|
|
||||||
// is an indication that the specified entity-name (this.getEntityName) should be used.
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
return factory.getEntityPersister( concreteEntityName );
|
if ( hasSubclasses() ) {
|
||||||
|
for ( EntityMappingType sub : subclassMappingTypes.values() ) {
|
||||||
|
if ( sub.getEntityPersister().getRepresentationStrategy().getInstantiator().isInstance( instance, factory ) ) {
|
||||||
|
return sub.getEntityPersister();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6048,6 +6056,7 @@ public abstract class AbstractEntityPersister
|
||||||
private EntityIdentifierMapping identifierMapping;
|
private EntityIdentifierMapping identifierMapping;
|
||||||
private NaturalIdMapping naturalIdMapping;
|
private NaturalIdMapping naturalIdMapping;
|
||||||
private EntityVersionMapping versionMapping;
|
private EntityVersionMapping versionMapping;
|
||||||
|
private EntityDiscriminatorMapping discriminatorMapping;
|
||||||
|
|
||||||
private SortedMap<String, AttributeMapping> declaredAttributeMappings = new TreeMap<>();
|
private SortedMap<String, AttributeMapping> declaredAttributeMappings = new TreeMap<>();
|
||||||
private Collection<AttributeMapping> attributeMappings;
|
private Collection<AttributeMapping> attributeMappings;
|
||||||
|
@ -6088,6 +6097,18 @@ public abstract class AbstractEntityPersister
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( getDiscriminatorType() == null ) {
|
||||||
|
discriminatorMapping = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
discriminatorMapping = new EntityDiscriminatorMappingImpl(
|
||||||
|
this,
|
||||||
|
getRootTableName(),
|
||||||
|
getDiscriminatorColumnName(),
|
||||||
|
(BasicType) getDiscriminatorType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel();
|
final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel();
|
||||||
|
|
||||||
int stateArrayPosition = superMappingType == null ? 0 : superMappingType.getNumberOfAttributeMappings();
|
int stateArrayPosition = superMappingType == null ? 0 : superMappingType.getNumberOfAttributeMappings();
|
||||||
|
@ -6285,6 +6306,11 @@ public abstract class AbstractEntityPersister
|
||||||
return versionMapping;
|
return versionMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityDiscriminatorMapping getDiscriminatorMapping() {
|
||||||
|
return discriminatorMapping;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<AttributeMapping> getAttributeMappings() {
|
public Collection<AttributeMapping> getAttributeMappings() {
|
||||||
if ( attributeMappings == null ) {
|
if ( attributeMappings == null ) {
|
||||||
|
|
|
@ -14,8 +14,11 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.boot.model.relational.Database;
|
import org.hibernate.boot.model.relational.Database;
|
||||||
import org.hibernate.cache.spi.access.EntityDataAccess;
|
import org.hibernate.cache.spi.access.EntityDataAccess;
|
||||||
|
@ -37,10 +40,23 @@ 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.persister.spi.PersisterCreationContext;
|
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||||
|
import org.hibernate.query.ComparisonOperator;
|
||||||
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
|
||||||
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.ColumnReference;
|
||||||
|
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.type.AssociationType;
|
import org.hibernate.type.AssociationType;
|
||||||
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.DiscriminatorType;
|
import org.hibernate.type.DiscriminatorType;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
@ -847,4 +863,60 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
||||||
public FilterAliasGenerator getFilterAliasGenerator(String rootAlias) {
|
public FilterAliasGenerator getFilterAliasGenerator(String rootAlias) {
|
||||||
return new DynamicFilterAliasGenerator( qualifiedTableNames, rootAlias );
|
return new DynamicFilterAliasGenerator( qualifiedTableNames, rootAlias );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableGroup createRootTableGroup(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
String explicitSourceAlias,
|
||||||
|
JoinType tableReferenceJoinType,
|
||||||
|
LockMode lockMode,
|
||||||
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
|
SqlAstCreationContext creationContext) {
|
||||||
|
final TableGroup tableGroup = super.createRootTableGroup(
|
||||||
|
navigablePath,
|
||||||
|
explicitSourceAlias,
|
||||||
|
tableReferenceJoinType,
|
||||||
|
lockMode,
|
||||||
|
aliasBaseGenerator,
|
||||||
|
sqlExpressionResolver,
|
||||||
|
additionalPredicateCollectorAccess,
|
||||||
|
creationContext
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( needsDiscriminator() ) {
|
||||||
|
final Predicate discriminatorPredicate = createDiscriminatorPredicate(
|
||||||
|
tableGroup,
|
||||||
|
sqlExpressionResolver,
|
||||||
|
creationContext
|
||||||
|
);
|
||||||
|
additionalPredicateCollectorAccess.get().accept( discriminatorPredicate );
|
||||||
|
}
|
||||||
|
|
||||||
|
return tableGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Predicate createDiscriminatorPredicate(
|
||||||
|
TableGroup tableGroup,
|
||||||
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
|
SqlAstCreationContext creationContext) {
|
||||||
|
return new ComparisonPredicate(
|
||||||
|
sqlExpressionResolver.resolveSqlExpression(
|
||||||
|
SqlExpressionResolver.createColumnReferenceKey( tableGroup.getPrimaryTableReference(), getDiscriminatorColumnName() ),
|
||||||
|
sqlAstProcessingState -> new ColumnReference(
|
||||||
|
tableGroup.getPrimaryTableReference().getIdentificationVariable(),
|
||||||
|
getDiscriminatorColumnName(),
|
||||||
|
( (BasicType) getDiscriminatorType() ).getJdbcMapping(),
|
||||||
|
getFactory()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
ComparisonOperator.EQUAL,
|
||||||
|
new QueryLiteral<>(
|
||||||
|
getDiscriminatorValue(),
|
||||||
|
( (BasicType) getDiscriminatorType() ),
|
||||||
|
Clause.WHERE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi
|
||||||
/**
|
/**
|
||||||
* The constructor signature for {@link EntityPersister} implementations
|
* The constructor signature for {@link EntityPersister} implementations
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"WeakerAccess", "deprecation"})
|
||||||
public static final Class[] ENTITY_PERSISTER_CONSTRUCTOR_ARGS = new Class[] {
|
public static final Class[] ENTITY_PERSISTER_CONSTRUCTOR_ARGS = new Class[] {
|
||||||
PersistentClass.class,
|
PersistentClass.class,
|
||||||
EntityDataAccess.class,
|
EntityDataAccess.class,
|
||||||
|
@ -47,6 +48,7 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi
|
||||||
/**
|
/**
|
||||||
* The constructor signature for {@link CollectionPersister} implementations
|
* The constructor signature for {@link CollectionPersister} implementations
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"WeakerAccess", "deprecation"})
|
||||||
public static final Class[] COLLECTION_PERSISTER_CONSTRUCTOR_ARGS = new Class[] {
|
public static final Class[] COLLECTION_PERSISTER_CONSTRUCTOR_ARGS = new Class[] {
|
||||||
Collection.class,
|
Collection.class,
|
||||||
CollectionDataAccess.class,
|
CollectionDataAccess.class,
|
||||||
|
@ -66,7 +68,7 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi
|
||||||
PersistentClass entityBinding,
|
PersistentClass entityBinding,
|
||||||
EntityDataAccess entityCacheAccessStrategy,
|
EntityDataAccess entityCacheAccessStrategy,
|
||||||
NaturalIdDataAccess naturalIdCacheAccessStrategy,
|
NaturalIdDataAccess naturalIdCacheAccessStrategy,
|
||||||
PersisterCreationContext creationContext) throws HibernateException {
|
@SuppressWarnings("deprecation") PersisterCreationContext creationContext) throws HibernateException {
|
||||||
// If the metadata for the entity specified an explicit persister class, use it...
|
// If the metadata for the entity specified an explicit persister class, use it...
|
||||||
Class<? extends EntityPersister> persisterClass = entityBinding.getEntityPersisterClass();
|
Class<? extends EntityPersister> persisterClass = entityBinding.getEntityPersisterClass();
|
||||||
if ( persisterClass == null ) {
|
if ( persisterClass == null ) {
|
||||||
|
@ -83,13 +85,12 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings( {"unchecked"})
|
|
||||||
private EntityPersister createEntityPersister(
|
private EntityPersister createEntityPersister(
|
||||||
Class<? extends EntityPersister> persisterClass,
|
Class<? extends EntityPersister> persisterClass,
|
||||||
PersistentClass entityBinding,
|
PersistentClass entityBinding,
|
||||||
EntityDataAccess entityCacheAccessStrategy,
|
EntityDataAccess entityCacheAccessStrategy,
|
||||||
NaturalIdDataAccess naturalIdCacheAccessStrategy,
|
NaturalIdDataAccess naturalIdCacheAccessStrategy,
|
||||||
PersisterCreationContext creationContext) {
|
@SuppressWarnings("deprecation") PersisterCreationContext creationContext) {
|
||||||
try {
|
try {
|
||||||
final Constructor<? extends EntityPersister> constructor = persisterClass.getConstructor( ENTITY_PERSISTER_CONSTRUCTOR_ARGS );
|
final Constructor<? extends EntityPersister> constructor = persisterClass.getConstructor( ENTITY_PERSISTER_CONSTRUCTOR_ARGS );
|
||||||
try {
|
try {
|
||||||
|
@ -116,7 +117,7 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi
|
||||||
throw new MappingException( "Could not instantiate persister " + persisterClass.getName(), e );
|
throw new MappingException( "Could not instantiate persister " + persisterClass.getName(), e );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (MappingException e) {
|
catch (HibernateException e) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
|
@ -129,7 +130,7 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi
|
||||||
public CollectionPersister createCollectionPersister(
|
public CollectionPersister createCollectionPersister(
|
||||||
Collection collectionBinding,
|
Collection collectionBinding,
|
||||||
CollectionDataAccess cacheAccessStrategy,
|
CollectionDataAccess cacheAccessStrategy,
|
||||||
PersisterCreationContext creationContext) throws HibernateException {
|
@SuppressWarnings("deprecation") PersisterCreationContext creationContext) throws HibernateException {
|
||||||
// If the metadata for the collection specified an explicit persister class, use it
|
// If the metadata for the collection specified an explicit persister class, use it
|
||||||
Class<? extends CollectionPersister> persisterClass = collectionBinding.getCollectionPersisterClass();
|
Class<? extends CollectionPersister> persisterClass = collectionBinding.getCollectionPersisterClass();
|
||||||
if ( persisterClass == null ) {
|
if ( persisterClass == null ) {
|
||||||
|
@ -140,12 +141,11 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi
|
||||||
return createCollectionPersister( persisterClass, collectionBinding, cacheAccessStrategy, creationContext );
|
return createCollectionPersister( persisterClass, collectionBinding, cacheAccessStrategy, creationContext );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings( {"unchecked"})
|
|
||||||
private CollectionPersister createCollectionPersister(
|
private CollectionPersister createCollectionPersister(
|
||||||
Class<? extends CollectionPersister> persisterClass,
|
Class<? extends CollectionPersister> persisterClass,
|
||||||
Collection collectionBinding,
|
Collection collectionBinding,
|
||||||
CollectionDataAccess cacheAccessStrategy,
|
CollectionDataAccess cacheAccessStrategy,
|
||||||
PersisterCreationContext creationContext) {
|
@SuppressWarnings("deprecation") PersisterCreationContext creationContext) {
|
||||||
try {
|
try {
|
||||||
Constructor<? extends CollectionPersister> constructor = persisterClass.getConstructor( COLLECTION_PERSISTER_CONSTRUCTOR_ARGS );
|
Constructor<? extends CollectionPersister> constructor = persisterClass.getConstructor( COLLECTION_PERSISTER_CONSTRUCTOR_ARGS );
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -96,6 +96,7 @@ import org.hibernate.sql.ast.JoinType;
|
||||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
|
||||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||||
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
|
||||||
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
|
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
|
||||||
|
@ -278,6 +279,8 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
public QuerySpec visitQuerySpec(SqmQuerySpec sqmQuerySpec) {
|
public QuerySpec visitQuerySpec(SqmQuerySpec sqmQuerySpec) {
|
||||||
final QuerySpec sqlQuerySpec = new QuerySpec( processingStateStack.isEmpty(), sqmQuerySpec.getFromClause().getNumberOfRoots() );
|
final QuerySpec sqlQuerySpec = new QuerySpec( processingStateStack.isEmpty(), sqmQuerySpec.getFromClause().getNumberOfRoots() );
|
||||||
|
|
||||||
|
additionalRestrictions = null;
|
||||||
|
|
||||||
processingStateStack.push(
|
processingStateStack.push(
|
||||||
new SqlAstQuerySpecProcessingStateImpl(
|
new SqlAstQuerySpecProcessingStateImpl(
|
||||||
sqlQuerySpec,
|
sqlQuerySpec,
|
||||||
|
@ -308,6 +311,10 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( additionalRestrictions != null ) {
|
||||||
|
sqlQuerySpec.applyPredicate( additionalRestrictions );
|
||||||
|
}
|
||||||
|
|
||||||
// todo : group-by
|
// todo : group-by
|
||||||
// todo : having
|
// todo : having
|
||||||
|
|
||||||
|
@ -412,6 +419,8 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Predicate additionalRestrictions;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
protected void consumeFromClauseRoot(SqmRoot<?> sqmRoot) {
|
protected void consumeFromClauseRoot(SqmRoot<?> sqmRoot) {
|
||||||
log.tracef( "Resolving SqmRoot [%s] to TableGroup", sqmRoot );
|
log.tracef( "Resolving SqmRoot [%s] to TableGroup", sqmRoot );
|
||||||
|
@ -427,6 +436,7 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
LockMode.NONE,
|
LockMode.NONE,
|
||||||
sqlAliasBaseManager,
|
sqlAliasBaseManager,
|
||||||
getSqlExpressionResolver(),
|
getSqlExpressionResolver(),
|
||||||
|
() -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate ),
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -512,6 +522,7 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
determineLockMode( sqmJoin.getExplicitAlias() ),
|
determineLockMode( sqmJoin.getExplicitAlias() ),
|
||||||
sqlAliasBaseManager,
|
sqlAliasBaseManager,
|
||||||
getSqlExpressionResolver(),
|
getSqlExpressionResolver(),
|
||||||
|
() -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate ),
|
||||||
getCreationContext()
|
getCreationContext()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -539,6 +550,7 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
determineLockMode( sqmJoin.getExplicitAlias() ),
|
determineLockMode( sqmJoin.getExplicitAlias() ),
|
||||||
sqlAliasBaseManager,
|
sqlAliasBaseManager,
|
||||||
getSqlExpressionResolver(),
|
getSqlExpressionResolver(),
|
||||||
|
() -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate ),
|
||||||
getCreationContext()
|
getCreationContext()
|
||||||
);
|
);
|
||||||
fromClauseIndex.register( sqmJoin, tableGroup );
|
fromClauseIndex.register( sqmJoin, tableGroup );
|
||||||
|
|
|
@ -52,8 +52,8 @@ public class BasicValuedPathInterpretation<T> implements AssignableSqmPathInterp
|
||||||
mapping.getMappedColumnExpression()
|
mapping.getMappedColumnExpression()
|
||||||
),
|
),
|
||||||
sacs -> new ColumnReference(
|
sacs -> new ColumnReference(
|
||||||
mapping.getMappedColumnExpression(),
|
|
||||||
tableReference.getIdentificationVariable(),
|
tableReference.getIdentificationVariable(),
|
||||||
|
mapping.getMappedColumnExpression(),
|
||||||
mapping.getJdbcMapping(),
|
mapping.getJdbcMapping(),
|
||||||
sqlAstCreationState.getCreationContext().getSessionFactory()
|
sqlAstCreationState.getCreationContext().getSessionFactory()
|
||||||
)
|
)
|
||||||
|
|
|
@ -29,8 +29,8 @@ public class ColumnReference implements Expression {
|
||||||
private final JdbcMapping jdbcMapping;
|
private final JdbcMapping jdbcMapping;
|
||||||
|
|
||||||
public ColumnReference(
|
public ColumnReference(
|
||||||
String columnExpression,
|
|
||||||
String qualifier,
|
String qualifier,
|
||||||
|
String columnExpression,
|
||||||
JdbcMapping jdbcMapping,
|
JdbcMapping jdbcMapping,
|
||||||
SessionFactoryImplementor sessionFactory) {
|
SessionFactoryImplementor sessionFactory) {
|
||||||
this(
|
this(
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.sql.ast.tree.from;
|
package org.hibernate.sql.ast.tree.from;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
@ -13,6 +16,7 @@ import org.hibernate.query.sqm.sql.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.JoinType;
|
import org.hibernate.sql.ast.JoinType;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contract for things that can produce the {@link TableGroup} that is the root of a
|
* Contract for things that can produce the {@link TableGroup} that is the root of a
|
||||||
|
@ -31,5 +35,6 @@ public interface RootTableGroupProducer extends TableGroupProducer, ModelPartCon
|
||||||
LockMode lockMode,
|
LockMode lockMode,
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
SqlExpressionResolver sqlExpressionResolver,
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
|
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||||
SqlAstCreationContext creationContext);
|
SqlAstCreationContext creationContext);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
* 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.orm.test.metamodel.mapping;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import javax.persistence.DiscriminatorColumn;
|
||||||
|
import javax.persistence.DiscriminatorValue;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||||
|
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.hamcrest.CoreMatchers;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
InheritanceTests.Customer.class,
|
||||||
|
InheritanceTests.DomesticCustomer.class,
|
||||||
|
InheritanceTests.ForeignCustomer.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@ServiceRegistry
|
||||||
|
@SessionFactory
|
||||||
|
public class InheritanceTests {
|
||||||
|
@Test
|
||||||
|
public void basicTest(SessionFactoryScope scope) {
|
||||||
|
final EntityPersister customerDescriptor = scope.getSessionFactory()
|
||||||
|
.getMetamodel()
|
||||||
|
.findEntityDescriptor( Customer.class );
|
||||||
|
final EntityPersister domesticCustomerDescriptor = scope.getSessionFactory()
|
||||||
|
.getMetamodel()
|
||||||
|
.findEntityDescriptor( DomesticCustomer.class );
|
||||||
|
final EntityPersister foreignCustomerDescriptor = scope.getSessionFactory()
|
||||||
|
.getMetamodel()
|
||||||
|
.findEntityDescriptor( ForeignCustomer.class );
|
||||||
|
|
||||||
|
assert customerDescriptor.isTypeOrSuperType( customerDescriptor );
|
||||||
|
assert ! customerDescriptor.isTypeOrSuperType( domesticCustomerDescriptor );
|
||||||
|
assert ! customerDescriptor.isTypeOrSuperType( foreignCustomerDescriptor );
|
||||||
|
|
||||||
|
assert domesticCustomerDescriptor.isTypeOrSuperType( customerDescriptor );
|
||||||
|
assert domesticCustomerDescriptor.isTypeOrSuperType( domesticCustomerDescriptor );
|
||||||
|
assert ! domesticCustomerDescriptor.isTypeOrSuperType( foreignCustomerDescriptor );
|
||||||
|
|
||||||
|
assert foreignCustomerDescriptor.isTypeOrSuperType( customerDescriptor );
|
||||||
|
assert ! foreignCustomerDescriptor.isTypeOrSuperType( domesticCustomerDescriptor );
|
||||||
|
assert foreignCustomerDescriptor.isTypeOrSuperType( foreignCustomerDescriptor );
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void createTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.persist( new DomesticCustomer( 1, "domestic", "123" ) );
|
||||||
|
session.persist( new ForeignCustomer( 2, "foreign", "987" ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanupTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
session.createQuery( "from DomesticCustomer", DomesticCustomer.class ).list().forEach(
|
||||||
|
cust -> session.delete( cust )
|
||||||
|
);
|
||||||
|
session.createQuery( "from ForeignCustomer", ForeignCustomer.class ).list().forEach(
|
||||||
|
cust -> session.delete( cust )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@FailureExpected
|
||||||
|
public void rootQueryExecutionTest(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
{
|
||||||
|
final List<Customer> results = session.createQuery(
|
||||||
|
"select c from Customer c",
|
||||||
|
Customer.class
|
||||||
|
).list();
|
||||||
|
|
||||||
|
assertThat( results.size(), is( 2 ) );
|
||||||
|
|
||||||
|
for ( Customer result : results ) {
|
||||||
|
if ( result.getId() == 1 ) {
|
||||||
|
assertThat( result, instanceOf( DomesticCustomer.class ) );
|
||||||
|
assertThat( ( (DomesticCustomer) result ).getTaxId(), is( "123" ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertThat( result.getId(), is( 2 ) );
|
||||||
|
assertThat( ( (ForeignCustomer) result ).getVat(), is( "987" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void subclassQueryExecutionTest(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
{
|
||||||
|
final DomesticCustomer result = session.createQuery(
|
||||||
|
"select c from DomesticCustomer c",
|
||||||
|
DomesticCustomer.class
|
||||||
|
).uniqueResult();
|
||||||
|
|
||||||
|
assertThat( result, notNullValue() );
|
||||||
|
assertThat( result.getId(), is( 1 ) );
|
||||||
|
assertThat( result.getName(), is( "domestic" ) );
|
||||||
|
assertThat( result.getTaxId(), is( "123" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
final ForeignCustomer result = session.createQuery(
|
||||||
|
"select c from ForeignCustomer c",
|
||||||
|
ForeignCustomer.class
|
||||||
|
).uniqueResult();
|
||||||
|
|
||||||
|
assertThat( result, notNullValue() );
|
||||||
|
assertThat( result.getId(), is( 2 ) );
|
||||||
|
assertThat( result.getName(), is( "foreign" ) );
|
||||||
|
assertThat( result.getVat(), is( "987" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "Customer" )
|
||||||
|
@Inheritance( strategy = InheritanceType.SINGLE_TABLE )
|
||||||
|
@Table( name = "customer" )
|
||||||
|
@DiscriminatorColumn( name = "cust_type" )
|
||||||
|
public static abstract class Customer {
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Customer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "DomesticCustomer" )
|
||||||
|
@DiscriminatorValue( "dc" )
|
||||||
|
public static class DomesticCustomer extends Customer {
|
||||||
|
private String taxId;
|
||||||
|
|
||||||
|
public DomesticCustomer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DomesticCustomer(Integer id, String name, String taxId) {
|
||||||
|
super( id, name );
|
||||||
|
this.taxId = taxId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTaxId() {
|
||||||
|
return taxId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTaxId(String taxId) {
|
||||||
|
this.taxId = taxId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "ForeignCustomer" )
|
||||||
|
@DiscriminatorValue( "fc" )
|
||||||
|
public static class ForeignCustomer extends Customer {
|
||||||
|
private String vat;
|
||||||
|
|
||||||
|
public ForeignCustomer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ForeignCustomer(Integer id, String name, String vat) {
|
||||||
|
super( id, name );
|
||||||
|
this.vat = vat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVat() {
|
||||||
|
return vat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVat(String vat) {
|
||||||
|
this.vat = vat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -25,5 +25,3 @@ javax.persistence.validation.mode=NONE
|
||||||
hibernate.service.allow_crawling=false
|
hibernate.service.allow_crawling=false
|
||||||
hibernate.session.events.log=true
|
hibernate.session.events.log=true
|
||||||
hibernate.hql.bulk_id_strategy.global_temporary.drop_tables=true
|
hibernate.hql.bulk_id_strategy.global_temporary.drop_tables=true
|
||||||
|
|
||||||
hibernate.bytecode.use_reflection_optimizer=true
|
|
Loading…
Reference in New Issue