perf work

This commit is contained in:
Steve Ebersole 2019-10-09 11:40:48 -05:00
parent 2502f4c108
commit 6f77e0d261
38 changed files with 470 additions and 288 deletions

View File

@ -1255,9 +1255,7 @@ public void addUniquePropertyReference(String referencedClass, String propertyNa
@Override @Override
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
public void addUniqueConstraints(Table table, List uniqueConstraints) { public void addUniqueConstraints(Table table, List uniqueConstraints) {
List<UniqueConstraintHolder> constraintHolders = new ArrayList<>( List<UniqueConstraintHolder> constraintHolders = new ArrayList<>( uniqueConstraints.size() );
CollectionHelper.determineProperSizing( uniqueConstraints.size() )
);
int keyNameBase = determineCurrentNumberOfUniqueConstraintHolders( table ); int keyNameBase = determineCurrentNumberOfUniqueConstraintHolders( table );
for ( String[] columns : ( List<String[]> ) uniqueConstraints ) { for ( String[] columns : ( List<String[]> ) uniqueConstraints ) {

View File

@ -781,7 +781,7 @@ public static List<UniqueConstraintHolder> buildUniqueConstraintHolders(UniqueCo
result = java.util.Collections.emptyList(); result = java.util.Collections.emptyList();
} }
else { else {
result = new ArrayList<UniqueConstraintHolder>( CollectionHelper.determineProperSizing( annotations.length ) ); result = CollectionHelper.arrayList( annotations.length );
for ( UniqueConstraint uc : annotations ) { for ( UniqueConstraint uc : annotations ) {
result.add( result.add(
new UniqueConstraintHolder() new UniqueConstraintHolder()

View File

@ -614,14 +614,13 @@ public <T> QueryImplementor<T> createQuery(String queryString, Class<T> resultCl
try { try {
final QueryEngine queryEngine = getFactory().getQueryEngine(); final QueryEngine queryEngine = getFactory().getQueryEngine();
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache(); final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
final SqmStatement sqm = interpretationCache.resolveSqmStatement(
queryString,
s -> queryEngine.getHqlTranslator().interpret( queryString )
);
final QuerySqmImpl query = new QuerySqmImpl( final QuerySqmImpl query = new QuerySqmImpl(
queryString, queryString,
sqm, interpretationCache.resolveHqlInterpretation(
queryString,
s -> queryEngine.getHqlTranslator().interpret( queryString )
),
resultClass, resultClass,
this this
); );
@ -886,7 +885,6 @@ public <T> QueryImplementor<T> createQuery(CriteriaQuery<T> criteriaQuery) {
try { try {
return new QuerySqmImpl<>( return new QuerySqmImpl<>(
"<criteria>",
(SqmStatement) criteriaQuery, (SqmStatement) criteriaQuery,
criteriaQuery.getResultType(), criteriaQuery.getResultType(),
this this
@ -902,7 +900,6 @@ public QueryImplementor createQuery(CriteriaUpdate criteriaUpdate) {
checkOpen(); checkOpen();
try { try {
return new QuerySqmImpl<>( return new QuerySqmImpl<>(
"<criteria>",
(SqmUpdateStatement) criteriaUpdate, (SqmUpdateStatement) criteriaUpdate,
null, null,
this this
@ -918,7 +915,6 @@ public QueryImplementor createQuery(CriteriaDelete criteriaDelete) {
checkOpen(); checkOpen();
try { try {
return new QuerySqmImpl<>( return new QuerySqmImpl<>(
"<criteria>",
(SqmDeleteStatement) criteriaDelete, (SqmDeleteStatement) criteriaDelete,
null, null,
this this

View File

@ -28,25 +28,13 @@ public static String toLoggableString(NavigableRole role) {
return UNREFERENCED; return UNREFERENCED;
} }
if ( role.isRoot() ) { return role.getFullPath();
return StringHelper.collapse( role.getFullPath() );
}
else {
assert role.getParent() != null;
return StringHelper.collapse( role.getParent().getFullPath() ) + '.' + role.getNavigableName();
}
} }
public static String toLoggableString(NavigablePath path) { public static String toLoggableString(NavigablePath path) {
assert path != null; assert path != null;
if ( path.isRoot() ) { return path.getFullPath();
return StringHelper.collapse( path.getFullPath() );
}
else {
assert path.getParent() != null;
return StringHelper.collapse( path.getParent().getFullPath() ) + '.' + path.getLocalName();
}
} }
public static String toLoggableString(NavigableRole role, Object key) { public static String toLoggableString(NavigableRole role, Object key) {

View File

@ -25,6 +25,7 @@
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public final class CollectionHelper { public final class CollectionHelper {
public static final int DEFAULT_LIST_CAPACITY = 10;
public static final int MINIMUM_INITIAL_CAPACITY = 16; public static final int MINIMUM_INITIAL_CAPACITY = 16;
public static final float LOAD_FACTOR = 0.75f; public static final float LOAD_FACTOR = 0.75f;
@ -178,8 +179,8 @@ public static <K, V> ConcurrentHashMap<K, V> concurrentMap(int expectedNumberOfE
return new ConcurrentHashMap<K, V>( size, loadFactor ); return new ConcurrentHashMap<K, V>( size, loadFactor );
} }
public static <T> ArrayList<T> arrayList(int anticipatedSize) { public static <T> ArrayList<T> arrayList(int expectedNumberOfElements) {
return new ArrayList<T>( anticipatedSize ); return new ArrayList<>( Math.max( expectedNumberOfElements + 1, DEFAULT_LIST_CAPACITY ) );
} }
public static <T> Set<T> makeCopy(Set<T> source) { public static <T> Set<T> makeCopy(Set<T> source) {

View File

@ -251,20 +251,35 @@ public void visitJdbcTypes(
@Override @Override
public Object disassemble(Object value, SharedSessionContractImplementor session) { public Object disassemble(Object value, SharedSessionContractImplementor session) {
throw new NotYetImplementedFor6Exception( getClass() );
return null;
} }
@Override @Override
public void visitDisassembledJdbcValues( public void visitDisassembledJdbcValues(
Object value, Clause clause, JdbcValuesConsumer valuesConsumer, SharedSessionContractImplementor session) { Object value,
Clause clause,
JdbcValuesConsumer valuesConsumer,
SharedSessionContractImplementor session) {
throw new NotYetImplementedFor6Exception( getClass() );
} }
@Override @Override
public void visitJdbcValues( public void visitJdbcValues(
Object value, Clause clause, JdbcValuesConsumer valuesConsumer, SharedSessionContractImplementor session) { Object value,
Clause clause,
JdbcValuesConsumer valuesConsumer,
SharedSessionContractImplementor session) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public int getNumberOfAttributeMappings() {
return attributeMappings.size();
}
@Override
public int getNumberOfDeclaredAttributeMappings() {
return getNumberOfAttributeMappings();
} }
@Override @Override

View File

@ -18,6 +18,9 @@
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface ManagedMappingType extends MappingType, FetchableContainer { public interface ManagedMappingType extends MappingType, FetchableContainer {
int getNumberOfAttributeMappings();
int getNumberOfDeclaredAttributeMappings();
Collection<AttributeMapping> getAttributeMappings(); Collection<AttributeMapping> getAttributeMappings();
/** /**

View File

@ -156,6 +156,7 @@ public void applySqlSelections(
@Override @Override
public Fetch generateFetch( public Fetch generateFetch(
FetchParent fetchParent, FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming, FetchTiming fetchTiming,
boolean selected, boolean selected,
LockMode lockMode, LockMode lockMode,
@ -173,6 +174,7 @@ public Fetch generateFetch(
return new BasicFetch( return new BasicFetch(
sqlSelection.getValuesArrayPosition(), sqlSelection.getValuesArrayPosition(),
fetchParent, fetchParent,
fetchablePath,
this, this,
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(), getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
getConverter(), getConverter(),

View File

@ -6,7 +6,6 @@
*/ */
package org.hibernate.metamodel.mapping.internal; package org.hibernate.metamodel.mapping.internal;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -15,6 +14,8 @@
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
@ -38,7 +39,6 @@
import org.hibernate.sql.ast.tree.from.CompositeTableGroup; import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.internal.domain.composite.CompositeFetch; import org.hibernate.sql.results.internal.domain.composite.CompositeFetch;
import org.hibernate.sql.results.internal.domain.composite.CompositeResult; import org.hibernate.sql.results.internal.domain.composite.CompositeResult;
@ -47,6 +47,7 @@
import org.hibernate.sql.results.spi.Fetch; import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent; import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.sql.results.spi.Fetchable; import org.hibernate.sql.results.spi.Fetchable;
import org.hibernate.type.spi.TypeConfiguration;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -106,6 +107,23 @@ public List<String> getMappedColumnExpressions() {
return Arrays.asList( attrColumnNames ); return Arrays.asList( attrColumnNames );
} }
@Override
public void visitJdbcTypes(
Consumer<JdbcMapping> action,
Clause clause,
TypeConfiguration typeConfiguration) {
getEmbeddableTypeDescriptor().visitJdbcTypes( action, clause, typeConfiguration );
}
@Override
public void visitJdbcValues(
Object value,
Clause clause,
JdbcValuesConsumer valuesConsumer,
SharedSessionContractImplementor session) {
getEmbeddableTypeDescriptor().visitJdbcValues( value, clause, valuesConsumer, session );
}
@Override @Override
public <T> DomainResult<T> createDomainResult( public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath, NavigablePath navigablePath,
@ -132,13 +150,14 @@ public void applySqlSelections(
@Override @Override
public Fetch generateFetch( public Fetch generateFetch(
FetchParent fetchParent, FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming, FetchTiming fetchTiming,
boolean selected, boolean selected,
LockMode lockMode, LockMode lockMode,
String resultVariable, String resultVariable,
DomainResultCreationState creationState) { DomainResultCreationState creationState) {
return new CompositeFetch( return new CompositeFetch(
fetchParent.getNavigablePath().append( getFetchableName() ), fetchablePath,
this, this,
fetchParent, fetchParent,
fetchTiming, fetchTiming,
@ -152,7 +171,7 @@ public Expression toSqlExpression(
Clause clause, Clause clause,
SqmToSqlAstConverter walker, SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) { SqlAstCreationState sqlAstCreationState) {
final List<ColumnReference> columnReferences = new ArrayList<>(); final List<ColumnReference> columnReferences = CollectionHelper.arrayList( attrColumnNames.length );
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() ); final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
getEmbeddableTypeDescriptor().visitJdbcTypes( getEmbeddableTypeDescriptor().visitJdbcTypes(

View File

@ -29,6 +29,7 @@
import java.util.TreeMap; import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
@ -103,6 +104,7 @@
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;
@ -5313,16 +5315,24 @@ public Object[] getPropertyValues(Object object) {
return accessOptimizer.getPropertyValues( object ); return accessOptimizer.getPropertyValues( object );
} }
else { else {
final List<Object> values = new ArrayList<>(); final Object[] values = new Object[ getNumberOfAttributeMappings() ];
final AtomicInteger index = new AtomicInteger( 0 );
//noinspection Convert2Lambda
visitAttributeMappings( visitAttributeMappings(
attributeMapping -> { new Consumer<AttributeMapping>() {
final AttributeMetadata attributeMetadata = attributeMapping.getAttributeMetadataAccess() @Override
.resolveAttributeMetadata( this ); public void accept(AttributeMapping mapping) {
values.add( attributeMetadata.getPropertyAccess().getGetter().get( object ) ); values[ index.getAndIncrement() ] = mapping.getAttributeMetadataAccess()
.resolveAttributeMetadata( AbstractEntityPersister.this )
.getPropertyAccess()
.getGetter()
.get( object );
}
} }
); );
return values.toArray();
return values;
} }
} }
@ -6040,6 +6050,7 @@ public CacheEntry buildCacheEntry(Object entity, Object[] state, Object version,
private EntityVersionMapping versionMapping; private EntityVersionMapping versionMapping;
private SortedMap<String, AttributeMapping> declaredAttributeMappings = new TreeMap<>(); private SortedMap<String, AttributeMapping> declaredAttributeMappings = new TreeMap<>();
private Collection<AttributeMapping> attributeMappings;
private ReflectionOptimizer.AccessOptimizer accessOptimizer; private ReflectionOptimizer.AccessOptimizer accessOptimizer;
@ -6079,7 +6090,7 @@ public void prepareMappingModel(MappingModelCreationProcess creationProcess) {
final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel(); final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel();
int stateArrayPosition = superMappingType == null ? 0 : superMappingType.getAttributeMappings().size(); int stateArrayPosition = superMappingType == null ? 0 : superMappingType.getNumberOfAttributeMappings();
for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) { for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) {
final NonIdentifierAttribute runtimeAttrDefinition = currentEntityMetamodel.getProperties()[i]; final NonIdentifierAttribute runtimeAttrDefinition = currentEntityMetamodel.getProperties()[i];
@ -6126,6 +6137,20 @@ public void linkWithSubType(EntityMappingType sub, MappingModelCreationProcess c
subclassMappingTypes.put( sub.getEntityName(), sub ); subclassMappingTypes.put( sub.getEntityName(), sub );
} }
@Override
public int getNumberOfAttributeMappings() {
if ( attributeMappings == null ) {
// force calculation of `attributeMappings`
getAttributeMappings();
}
return attributeMappings.size();
}
@Override
public int getNumberOfDeclaredAttributeMappings() {
return declaredAttributeMappings.size();
}
@Override @Override
public boolean isTypeOrSuperType(EntityMappingType targetType) { public boolean isTypeOrSuperType(EntityMappingType targetType) {
if ( targetType == null ) { if ( targetType == null ) {
@ -6260,8 +6285,6 @@ public EntityVersionMapping getVersionMapping() {
return versionMapping; return versionMapping;
} }
private Collection<AttributeMapping> attributeMappings;
@Override @Override
public Collection<AttributeMapping> getAttributeMappings() { public Collection<AttributeMapping> getAttributeMappings() {
if ( attributeMappings == null ) { if ( attributeMappings == null ) {

View File

@ -118,6 +118,18 @@ default String getSqlAliasStem() {
return SqlAliasStemHelper.INSTANCE.generateStemFromEntityName( getEntityName() ); return SqlAliasStemHelper.INSTANCE.generateStemFromEntityName( getEntityName() );
} }
@Override
default int getNumberOfAttributeMappings() {
// for backwards-compatibility
return getAttributeMappings().size();
}
@Override
default int getNumberOfDeclaredAttributeMappings() {
// for backwards-compatibility
return getAttributeMappings().size();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// stuff that is persister-centric and/or EntityInfo-centric ~~~~~~~~~~~~~~ // stuff that is persister-centric and/or EntityInfo-centric ~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -17,6 +17,7 @@
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import static org.hibernate.internal.CoreLogging.messageLogger; import static org.hibernate.internal.CoreLogging.messageLogger;
@ -39,7 +40,7 @@ public GetterMethodImpl(Class containerClass, String propertyName, Method getter
@Override @Override
public Object get(Object owner) { public Object get(Object owner) {
try { try {
return getterMethod.invoke( owner ); return getterMethod.invoke( owner, ArrayHelper.EMPTY_OBJECT_ARRAY );
} }
catch (InvocationTargetException ite) { catch (InvocationTargetException ite) {
throw new PropertyAccessException( throw new PropertyAccessException(

View File

@ -24,14 +24,12 @@ public class NavigablePath implements DotIdentifierSequence {
public static final String IDENTIFIER_MAPPER_PROPERTY = "_identifierMapper"; public static final String IDENTIFIER_MAPPER_PROPERTY = "_identifierMapper";
private final NavigablePath parent; private final NavigablePath parent;
private final String localName;
private final String fullPath; private final String fullPath;
private final int hashCode; private final int hashCode;
public NavigablePath(NavigablePath parent, String navigableName) { public NavigablePath(NavigablePath parent, String navigableName) {
this.parent = parent; this.parent = parent;
this.localName = navigableName;
// the _identifierMapper is a "hidden property" on entities with composite keys. // the _identifierMapper is a "hidden property" on entities with composite keys.
// concatenating it will prevent the path from correctly being used to look up // concatenating it will prevent the path from correctly being used to look up
@ -54,31 +52,12 @@ public NavigablePath(NavigablePath parent, String navigableName) {
this.hashCode = fullPath.hashCode(); this.hashCode = fullPath.hashCode();
} }
public NavigablePath(NavigablePath parent, String navigableName, String alias) {
assert parent != null;
this.parent = parent;
this.localName = navigableName;
final String prefix;
final String parentFullPath = parent.getFullPath();
prefix = StringHelper.isEmpty( parentFullPath )
? ""
: parentFullPath + '.';
this.fullPath = alias == null ? prefix : prefix + '(' + alias + ')';
this.hashCode = fullPath.hashCode();
}
public NavigablePath(String localName) { public NavigablePath(String localName) {
this( localName, null ); this( localName, null );
} }
public NavigablePath(String rootName, String alias) { public NavigablePath(String rootName, String alias) {
this.parent = null; this.parent = null;
this.localName = rootName;
this.fullPath = alias == null ? rootName : rootName + '(' + alias + ')'; this.fullPath = alias == null ? rootName : rootName + '(' + alias + ')';
@ -102,7 +81,7 @@ public NavigablePath getParent() {
} }
public String getLocalName() { public String getLocalName() {
return localName; return parent == null ? fullPath : StringHelper.unqualify( fullPath );
} }
public String getFullPath() { public String getFullPath() {

View File

@ -180,7 +180,7 @@ public SqmFromClause visitFromClause(SqmFromClause fromClause) {
final SqmFromClause previousCurrent = currentFromClauseCopy; final SqmFromClause previousCurrent = currentFromClauseCopy;
try { try {
SqmFromClause copy = new SqmFromClause(); SqmFromClause copy = new SqmFromClause( fromClause.getNumberOfRoots() );
currentFromClauseCopy = copy; currentFromClauseCopy = copy;
super.visitFromClause( fromClause ); super.visitFromClause( fromClause );
return copy; return copy;

View File

@ -804,7 +804,7 @@ public SqmFromClause visitFromClause(HqlParser.FromClauseContext parserFromClaus
treatHandlerStack.push( new TreatHandlerFromClause() ); treatHandlerStack.push( new TreatHandlerFromClause() );
try { try {
final SqmFromClause fromClause = new SqmFromClause(); final SqmFromClause fromClause = new SqmFromClause( parserFromClause.fromClauseSpace().size() );
for ( HqlParser.FromClauseSpaceContext parserSpace : parserFromClause.fromClauseSpace() ) { for ( HqlParser.FromClauseSpaceContext parserSpace : parserFromClause.fromClauseSpace() ) {
final SqmRoot sqmPathRoot = visitFromClauseSpace( parserSpace ); final SqmRoot sqmPathRoot = visitFromClauseSpace( parserSpace );
fromClause.addRoot( sqmPathRoot ); fromClause.addRoot( sqmPathRoot );

View File

@ -7,12 +7,15 @@
package org.hibernate.query.internal; package org.hibernate.query.internal;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
import org.hibernate.query.ParameterMetadata; import org.hibernate.query.spi.HqlInterpretation;
import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryInterpretationCache; import org.hibernate.query.spi.QueryInterpretationCache;
import org.hibernate.query.spi.SelectQueryPlan; import org.hibernate.query.spi.SelectQueryPlan;
import org.hibernate.query.sql.spi.ParameterInterpretation; import org.hibernate.query.sql.spi.ParameterInterpretation;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.SqmStatement;
/** /**
@ -25,14 +28,10 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation
public static final QueryInterpretationCacheDisabledImpl INSTANCE = new QueryInterpretationCacheDisabledImpl(); public static final QueryInterpretationCacheDisabledImpl INSTANCE = new QueryInterpretationCacheDisabledImpl();
@Override @Override
public SelectQueryPlan getSelectQueryPlan(Key key) { public SelectQueryPlan resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan> creator) {
return null; return null;
} }
@Override
public void cacheSelectQueryPlan(Key key, SelectQueryPlan plan) {
}
@Override @Override
public NonSelectQueryPlan getNonSelectQueryPlan(Key key) { public NonSelectQueryPlan getNonSelectQueryPlan(Key key) {
return null; return null;
@ -43,8 +42,36 @@ public void cacheNonSelectQueryPlan(Key key, NonSelectQueryPlan plan) {
} }
@Override @Override
public SqmStatement resolveSqmStatement(String queryString, Function<String, SqmStatement<?>> creator) { public HqlInterpretation resolveHqlInterpretation(String queryString, Function<String, SqmStatement<?>> creator) {
return creator.apply( queryString ); final SqmStatement<?> sqmStatement = creator.apply( queryString );
final DomainParameterXref domainParameterXref;
final ParameterMetadataImplementor parameterMetadata;
if ( sqmStatement.getSqmParameters().isEmpty() ) {
domainParameterXref = DomainParameterXref.empty();
parameterMetadata = ParameterMetadataImpl.EMPTY;
}
else {
domainParameterXref = DomainParameterXref.from( sqmStatement );
parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
}
return new HqlInterpretation() {
@Override
public SqmStatement getSqmStatement() {
return sqmStatement;
}
@Override
public ParameterMetadataImplementor getParameterMetadata() {
return parameterMetadata;
}
@Override
public DomainParameterXref getDomainParameterXref() {
return domainParameterXref;
}
};
} }
@Override @Override

View File

@ -7,14 +7,19 @@
package org.hibernate.query.internal; package org.hibernate.query.internal;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap; import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
import org.hibernate.query.QueryLogger; import org.hibernate.query.QueryLogger;
import org.hibernate.query.spi.HqlInterpretation;
import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryInterpretationCache; import org.hibernate.query.spi.QueryInterpretationCache;
import org.hibernate.query.spi.QueryPlan; import org.hibernate.query.spi.QueryPlan;
import org.hibernate.query.spi.SelectQueryPlan; import org.hibernate.query.spi.SelectQueryPlan;
import org.hibernate.query.spi.SimpleHqlInterpretationImpl;
import org.hibernate.query.sql.spi.ParameterInterpretation; import org.hibernate.query.sql.spi.ParameterInterpretation;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.SqmStatement;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -29,8 +34,12 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
/** /**
* The default strong reference count. * The default strong reference count.
*
* @deprecated No longer used
*/ */
@Deprecated
public static final int DEFAULT_PARAMETER_METADATA_MAX_COUNT = 128; public static final int DEFAULT_PARAMETER_METADATA_MAX_COUNT = 128;
/** /**
* The default soft reference count. * The default soft reference count.
*/ */
@ -41,27 +50,31 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
*/ */
private final BoundedConcurrentHashMap<Key, QueryPlan> queryPlanCache; private final BoundedConcurrentHashMap<Key, QueryPlan> queryPlanCache;
private final BoundedConcurrentHashMap<String, SqmStatement<?>> sqmStatementCache; private final BoundedConcurrentHashMap<String, HqlInterpretation> hqlInterpretationCache;
private final BoundedConcurrentHashMap<String, ParameterInterpretation> nativeQueryParamCache; private final BoundedConcurrentHashMap<String, ParameterInterpretation> nativeQueryParamCache;
public QueryInterpretationCacheStandardImpl(int maxQueryPlanCount) { public QueryInterpretationCacheStandardImpl(int maxQueryPlanCount) {
log.debugf( "Starting QueryPlanCache(%s)", maxQueryPlanCount ); log.debugf( "Starting QueryPlanCache(%s)", maxQueryPlanCount );
queryPlanCache = new BoundedConcurrentHashMap<>( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS ); queryPlanCache = new BoundedConcurrentHashMap<>( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS );
sqmStatementCache = new BoundedConcurrentHashMap<>( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS ); hqlInterpretationCache = new BoundedConcurrentHashMap<>( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS );
nativeQueryParamCache = new BoundedConcurrentHashMap<>( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS ); nativeQueryParamCache = new BoundedConcurrentHashMap<>( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS );
} }
@Override @Override
public SelectQueryPlan getSelectQueryPlan(Key key) { public SelectQueryPlan resolveSelectQueryPlan(
Key key,
Supplier<SelectQueryPlan> creator) {
log.tracef( "QueryPlan#getSelectQueryPlan(%s)", key ); log.tracef( "QueryPlan#getSelectQueryPlan(%s)", key );
return (SelectQueryPlan) queryPlanCache.get( key );
final SelectQueryPlan cached = (SelectQueryPlan) queryPlanCache.get( key );
if ( cached != null ) {
return cached;
} }
@Override final SelectQueryPlan plan = creator.get();
public void cacheSelectQueryPlan(Key key, SelectQueryPlan plan) { queryPlanCache.put( key, plan );
log.tracef( "QueryPlan#cacheSelectQueryPlan(%s)", key ); return plan;
queryPlanCache.putIfAbsent( key, plan );
} }
@Override @Override
@ -76,17 +89,37 @@ public void cacheNonSelectQueryPlan(Key key, NonSelectQueryPlan plan) {
} }
@Override @Override
public SqmStatement resolveSqmStatement( public HqlInterpretation resolveHqlInterpretation(
String queryString, String queryString,
Function<String, SqmStatement<?>> creator) { Function<String, SqmStatement<?>> creator) {
log.tracef( "QueryPlan#resolveSqmStatement(%s)", queryString ); log.tracef( "QueryPlan#resolveHqlInterpretation( `%s` )", queryString );
return sqmStatementCache.computeIfAbsent(
queryString, final HqlInterpretation cached = hqlInterpretationCache.get( queryString );
s -> { if ( cached != null ) {
log.debugf( "Creating and caching SqmStatement - %s", queryString ); return cached;
return creator.apply( queryString );
} }
);
log.debugf( "Creating and caching HqlInterpretation - %s", queryString );
final SqmStatement<?> sqmStatement = creator.apply( queryString );
final DomainParameterXref domainParameterXref;
final ParameterMetadataImplementor parameterMetadata;
if ( sqmStatement.getSqmParameters().isEmpty() ) {
domainParameterXref = DomainParameterXref.empty();
parameterMetadata = ParameterMetadataImpl.EMPTY;
}
else {
domainParameterXref = DomainParameterXref.from( sqmStatement );
parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
}
final HqlInterpretation interpretation = new SimpleHqlInterpretationImpl(
sqmStatement,
parameterMetadata,
domainParameterXref);
hqlInterpretationCache.put( queryString, interpretation );
return interpretation;
} }
@Override @Override

View File

@ -0,0 +1,15 @@
package org.hibernate.query.spi;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.tree.SqmStatement;
/**
* @author Steve Ebersole
*/
public interface HqlInterpretation {
SqmStatement getSqmStatement();
ParameterMetadataImplementor getParameterMetadata();
DomainParameterXref getDomainParameterXref();
}

View File

@ -16,6 +16,7 @@
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.query.spi.NativeQueryInterpreter;
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.internal.util.config.ConfigurationHelper; import org.hibernate.internal.util.config.ConfigurationHelper;
@ -64,6 +65,7 @@ public static QueryEngine from(
private final SqmCriteriaNodeBuilder criteriaBuilder; private final SqmCriteriaNodeBuilder criteriaBuilder;
private final HqlTranslator hqlTranslator; private final HqlTranslator hqlTranslator;
private final SqmTranslatorFactory sqmTranslatorFactory; private final SqmTranslatorFactory sqmTranslatorFactory;
private final NativeQueryInterpreter nativeQueryInterpreter;
private final QueryInterpretationCache interpretationCache; private final QueryInterpretationCache interpretationCache;
private final SqmFunctionRegistry sqmFunctionRegistry; private final SqmFunctionRegistry sqmFunctionRegistry;
@ -101,6 +103,8 @@ public QueryEngine(
serviceRegistry serviceRegistry
); );
this.nativeQueryInterpreter = serviceRegistry.getService( NativeQueryInterpreter.class );
this.interpretationCache = buildInterpretationCache( properties ); this.interpretationCache = buildInterpretationCache( properties );
this.sqmFunctionRegistry = new SqmFunctionRegistry(); this.sqmFunctionRegistry = new SqmFunctionRegistry();
@ -163,20 +167,21 @@ private static QueryInterpretationCache buildInterpretationCache(Map properties)
final boolean explicitUseCache = ConfigurationHelper.getBoolean( final boolean explicitUseCache = ConfigurationHelper.getBoolean(
AvailableSettings.QUERY_PLAN_CACHE_ENABLED, AvailableSettings.QUERY_PLAN_CACHE_ENABLED,
properties, properties,
false // enabled by default
true
); );
final Integer explicitMaxPlanCount = ConfigurationHelper.getInteger( final Integer explicitMaxPlanSize = ConfigurationHelper.getInteger(
AvailableSettings.QUERY_PLAN_CACHE_MAX_SIZE, AvailableSettings.QUERY_PLAN_CACHE_MAX_SIZE,
properties properties
); );
if ( explicitUseCache || ( explicitMaxPlanCount != null && explicitMaxPlanCount > 0 ) ) { if ( explicitUseCache || ( explicitMaxPlanSize != null && explicitMaxPlanSize > 0 ) ) {
return new QueryInterpretationCacheStandardImpl( final int size = explicitMaxPlanSize != null
explicitMaxPlanCount != null ? explicitMaxPlanSize
? explicitMaxPlanCount : QueryInterpretationCacheStandardImpl.DEFAULT_QUERY_PLAN_MAX_COUNT;
: QueryInterpretationCacheStandardImpl.DEFAULT_QUERY_PLAN_MAX_COUNT
); return new QueryInterpretationCacheStandardImpl( size );
} }
else { else {
// disabled // disabled
@ -218,6 +223,10 @@ public SqmTranslatorFactory getSqmTranslatorFactory() {
return sqmTranslatorFactory; return sqmTranslatorFactory;
} }
public NativeQueryInterpreter getNativeQueryInterpreter() {
return nativeQueryInterpreter;
}
public QueryInterpretationCache getInterpretationCache() { public QueryInterpretationCache getInterpretationCache() {
return interpretationCache; return interpretationCache;
} }

View File

@ -7,14 +7,14 @@
package org.hibernate.query.spi; package org.hibernate.query.spi;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.query.sql.spi.ParameterInterpretation; import org.hibernate.query.sql.spi.ParameterInterpretation;
import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.SqmStatement;
/** /**
* A cache for QueryPlans used (and produced) by the translation * Cache for various parts of translating or interpreting queries.
* and execution of a query.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -23,13 +23,15 @@ public interface QueryInterpretationCache {
interface Key { interface Key {
} }
SelectQueryPlan getSelectQueryPlan(Key key); SelectQueryPlan resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan> creator);
void cacheSelectQueryPlan(Key key, SelectQueryPlan plan);
NonSelectQueryPlan getNonSelectQueryPlan(Key key); NonSelectQueryPlan getNonSelectQueryPlan(Key key);
void cacheNonSelectQueryPlan(Key key, NonSelectQueryPlan plan); void cacheNonSelectQueryPlan(Key key, NonSelectQueryPlan plan);
SqmStatement resolveSqmStatement(String queryString, Function<String, SqmStatement<?>> creator); /**
* todo (6.0) : Doesn't holding these separate from the QueryPlans lead to extra, unnecessary memory use?
*/
HqlInterpretation resolveHqlInterpretation(String queryString, Function<String, SqmStatement<?>> creator);
ParameterInterpretation resolveNativeQueryParameters(String queryString, Function<String, ParameterInterpretation> creator); ParameterInterpretation resolveNativeQueryParameters(String queryString, Function<String, ParameterInterpretation> creator);
@ -45,4 +47,5 @@ interface Key {
* memory until they are replaced by others. It is not considered a memory leak as the cache is bounded. * memory until they are replaced by others. It is not considered a memory leak as the cache is bounded.
*/ */
void close(); void close();
} }

View File

@ -0,0 +1,43 @@
/*
* 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.query.spi;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.tree.SqmStatement;
/**
* @author Steve Ebersole
*/
public class SimpleHqlInterpretationImpl implements HqlInterpretation {
private final SqmStatement sqmStatement;
private final ParameterMetadataImplementor parameterMetadata;
private final DomainParameterXref domainParameterXref;
public SimpleHqlInterpretationImpl(
SqmStatement sqmStatement,
ParameterMetadataImplementor parameterMetadata,
DomainParameterXref domainParameterXref) {
this.sqmStatement = sqmStatement;
this.parameterMetadata = parameterMetadata;
this.domainParameterXref = domainParameterXref;
}
@Override
public SqmStatement getSqmStatement() {
return sqmStatement;
}
@Override
public ParameterMetadataImplementor getParameterMetadata() {
return parameterMetadata;
}
@Override
public DomainParameterXref getDomainParameterXref() {
return domainParameterXref;
}
}

View File

@ -76,6 +76,7 @@
import org.hibernate.query.sql.spi.NamedNativeQueryMemento; import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
import org.hibernate.query.sql.spi.NativeQueryImplementor; import org.hibernate.query.sql.spi.NativeQueryImplementor;
import org.hibernate.query.sql.spi.NativeSelectQueryDefinition; import org.hibernate.query.sql.spi.NativeSelectQueryDefinition;
import org.hibernate.query.sql.spi.NativeSelectQueryPlan;
import org.hibernate.query.sql.spi.NonSelectInterpretationsKey; import org.hibernate.query.sql.spi.NonSelectInterpretationsKey;
import org.hibernate.query.sql.spi.ParameterInterpretation; import org.hibernate.query.sql.spi.ParameterInterpretation;
import org.hibernate.query.sql.spi.SelectInterpretationsKey; import org.hibernate.query.sql.spi.SelectInterpretationsKey;
@ -112,6 +113,7 @@ public class NativeQueryImpl<R>
private boolean autoDiscoverTypes; private boolean autoDiscoverTypes;
private Serializable collectionKey; private Serializable collectionKey;
private NativeQueryInterpreter nativeQueryInterpreter;
/** /**
* Constructs a NativeQueryImpl given a sql query defined in the mappings. * Constructs a NativeQueryImpl given a sql query defined in the mappings.
@ -344,33 +346,31 @@ protected List<R> doList() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private SelectQueryPlan<R> resolveSelectQueryPlan() { private SelectQueryPlan<R> resolveSelectQueryPlan() {
final NativeQueryInterpreter interpreter = getSessionFactory().getServiceRegistry().getService( NativeQueryInterpreter.class );
SelectQueryPlan<R> queryPlan = null; SelectQueryPlan<R> queryPlan = null;
final JdbcValuesMappingProducer resultSetMapping = getJdbcValuesMappingProducer(); final JdbcValuesMappingProducer resultSetMapping = getJdbcValuesMappingProducer();
final RowTransformer rowTransformer = resolveRowTransformer();
final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( resultSetMapping ); final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( resultSetMapping );
if ( cacheKey != null ) { if ( cacheKey != null ) {
queryPlan = getSession().getFactory().getQueryEngine().getInterpretationCache().getSelectQueryPlan( cacheKey ); return getSession().getFactory().getQueryEngine().getInterpretationCache().resolveSelectQueryPlan(
cacheKey,
this::createQueryPlan
);
}
else {
return createQueryPlan();
}
} }
if ( queryPlan == null ) { private NativeSelectQueryPlan<R> createQueryPlan() {
queryPlan = interpreter.createQueryPlan( final RowTransformer rowTransformer = resolveRowTransformer();
return getSessionFactory().getQueryEngine().getNativeQueryInterpreter().createQueryPlan(
generateSelectQueryDefinition(), generateSelectQueryDefinition(),
getSessionFactory() getSessionFactory()
); );
if ( cacheKey != null ) {
getSession().getFactory()
.getQueryEngine()
.getInterpretationCache()
.cacheSelectQueryPlan( cacheKey, queryPlan );
}
}
return queryPlan;
} }
private JdbcValuesMappingProducer getJdbcValuesMappingProducer() { private JdbcValuesMappingProducer getJdbcValuesMappingProducer() {

View File

@ -15,6 +15,7 @@
import java.util.TreeMap; import java.util.TreeMap;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.query.QueryLogger; import org.hibernate.query.QueryLogger;
import org.hibernate.query.internal.QueryParameterNamedImpl; import org.hibernate.query.internal.QueryParameterNamedImpl;
import org.hibernate.query.internal.QueryParameterPositionalImpl; import org.hibernate.query.internal.QueryParameterPositionalImpl;
@ -42,9 +43,6 @@ public class DomainParameterXref {
* SQM statement * SQM statement
*/ */
public static DomainParameterXref from(SqmStatement<?> sqmStatement) { public static DomainParameterXref from(SqmStatement<?> sqmStatement) {
final Map<QueryParameterImplementor<?>, List<SqmParameter>> sqmParamsByQueryParam = new IdentityHashMap<>();
final Map<SqmParameter, QueryParameterImplementor<?>> queryParamBySqmParam = new IdentityHashMap<>();
// `xrefMap` is used to help maintain the proper cardinality between an // `xrefMap` is used to help maintain the proper cardinality between an
// SqmParameter and a QueryParameter. Multiple SqmParameter references // SqmParameter and a QueryParameter. Multiple SqmParameter references
// can map to the same QueryParameter. Consider, e.g., // can map to the same QueryParameter. Consider, e.g.,
@ -90,6 +88,13 @@ else if ( o1 instanceof SqmJpaCriteriaParameterWrapper
return empty(); return empty();
} }
final Map<QueryParameterImplementor<?>, List<SqmParameter>> sqmParamsByQueryParam = new IdentityHashMap<>();
final int sqmParamCount = parameterResolutions.getSqmParameters().size();
final Map<SqmParameter, QueryParameterImplementor<?>> queryParamBySqmParam = new IdentityHashMap<>(
CollectionHelper.determineProperSizing( sqmParamCount )
);
for ( SqmParameter<?> sqmParameter : parameterResolutions.getSqmParameters() ) { for ( SqmParameter<?> sqmParameter : parameterResolutions.getSqmParameters() ) {
if ( sqmParameter instanceof JpaCriteriaParameter ) { if ( sqmParameter instanceof JpaCriteriaParameter ) {
// see discussion on `SqmJpaCriteriaParameterWrapper#accept` // see discussion on `SqmJpaCriteriaParameterWrapper#accept`
@ -181,6 +186,10 @@ public Set<QueryParameterImplementor<?>> getQueryParameters() {
return sqmParamsByQueryParam.keySet(); return sqmParamsByQueryParam.keySet();
} }
public int getQueryParameterCount() {
return sqmParamsByQueryParam.size();
}
/** /**
* Get the mapping of all QueryParameters to the List of its corresponding * Get the mapping of all QueryParameters to the List of its corresponding
* SqmParameters * SqmParameters

View File

@ -35,6 +35,7 @@
import org.hibernate.query.internal.QueryOptionsImpl; import org.hibernate.query.internal.QueryOptionsImpl;
import org.hibernate.query.internal.QueryParameterBindingsImpl; import org.hibernate.query.internal.QueryParameterBindingsImpl;
import org.hibernate.query.spi.AbstractQuery; import org.hibernate.query.spi.AbstractQuery;
import org.hibernate.query.spi.HqlInterpretation;
import org.hibernate.query.spi.MutableQueryOptions; import org.hibernate.query.spi.MutableQueryOptions;
import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.spi.ParameterMetadataImplementor; import org.hibernate.query.spi.ParameterMetadataImplementor;
@ -72,9 +73,9 @@ public class QuerySqmImpl<R>
private final SqmStatement sqmStatement; private final SqmStatement sqmStatement;
private final Class resultType; private final Class resultType;
private final ParameterMetadataImplementor parameterMetadata;
private final DomainParameterXref domainParameterXref; private final DomainParameterXref domainParameterXref;
private final ParameterMetadataImpl parameterMetadata;
private final QueryParameterBindingsImpl parameterBindings; private final QueryParameterBindingsImpl parameterBindings;
private final QueryOptionsImpl queryOptions = new QueryOptionsImpl(); private final QueryOptionsImpl queryOptions = new QueryOptionsImpl();
@ -141,27 +142,57 @@ protected void applyOptions(NamedHqlQueryMemento memento) {
} }
} }
/**
* Form used for HQL queries
*/
public QuerySqmImpl( public QuerySqmImpl(
String hqlString, String hqlString,
HqlInterpretation hqlInterpretation,
Class resultType,
SharedSessionContractImplementor producer) {
super( producer );
this.hqlString = hqlString;
this.resultType = resultType;
this.sqmStatement = hqlInterpretation.getSqmStatement();
if ( resultType != null ) {
SqmUtil.verifyIsSelectStatement( sqmStatement );
//noinspection unchecked
checkQueryReturnType( (SqmSelectStatement<R>) sqmStatement, resultType, producer.getFactory() );
}
this.parameterMetadata = hqlInterpretation.getParameterMetadata();
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, producer.getFactory() );
}
/**
* Form used for criteria queries
*/
public QuerySqmImpl(
SqmStatement sqmStatement, SqmStatement sqmStatement,
Class resultType, Class resultType,
SharedSessionContractImplementor producer) { SharedSessionContractImplementor producer) {
super( producer ); super( producer );
SqmUtil.verifyIsSelectStatement( sqmStatement );
checkQueryReturnType( (SqmSelectStatement<R>) sqmStatement, resultType, producer.getFactory() );
if ( resultType != null ) { if ( resultType != null ) {
if ( sqmStatement instanceof SqmDmlStatement ) { if ( sqmStatement instanceof SqmSelectStatement ) {
//noinspection unchecked
checkQueryReturnType( (SqmSelectStatement<R>) sqmStatement, resultType, producer.getFactory() );
}
else {
assert sqmStatement instanceof SqmDmlStatement;
throw new IllegalArgumentException( "Non-select queries cannot be typed" ); throw new IllegalArgumentException( "Non-select queries cannot be typed" );
} }
} }
this.hqlString = hqlString; this.hqlString = "<criteria>";
this.sqmStatement = sqmStatement; this.sqmStatement = sqmStatement;
this.resultType = resultType; this.resultType = resultType;
this.domainParameterXref = DomainParameterXref.from( sqmStatement ); this.domainParameterXref = DomainParameterXref.from( sqmStatement );
if ( ! domainParameterXref.hasParameters() ) { if ( ! domainParameterXref.hasParameters() ) {
this.parameterMetadata = ParameterMetadataImpl.EMPTY; this.parameterMetadata = ParameterMetadataImpl.EMPTY;
@ -391,29 +422,24 @@ private boolean requiresTxn(LockMode lockMode) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private SelectQueryPlan<R> resolveSelectQueryPlan() { private SelectQueryPlan<R> resolveSelectQueryPlan() {
// resolve (or make) the QueryPlan. This QueryPlan might be an // resolve (or make) the QueryPlan. This QueryPlan might be an aggregation of multiple plans.
// aggregation of multiple plans. QueryPlans can be cached, except //
// for in certain circumstances, the determination of which occurs in // QueryPlans can be cached, except for in certain circumstances
// SqmInterpretationsKey#generateFrom - if SqmInterpretationsKey#generateFrom // - the determination of these circumstances occurs in SqmInterpretationsKey#generateFrom.
// returns null the query is not cacheable // If SqmInterpretationsKey#generateFrom returns null the query is not cacheable
SelectQueryPlan<R> queryPlan = null;
final QueryInterpretationCache.Key cacheKey = SqmInterpretationsKey.generateFrom( this ); final QueryInterpretationCache.Key cacheKey = SqmInterpretationsKey.generateFrom( this );
if ( cacheKey != null ) { if ( cacheKey != null ) {
queryPlan = getSession().getFactory().getQueryEngine().getInterpretationCache().getSelectQueryPlan( cacheKey ); return getSession().getFactory().getQueryEngine().getInterpretationCache().resolveSelectQueryPlan(
cacheKey,
this::buildSelectQueryPlan
);
} }
else {
if ( queryPlan == null ) { return buildSelectQueryPlan();
queryPlan = buildSelectQueryPlan();
if ( cacheKey != null ) {
getSession().getFactory().getQueryEngine().getInterpretationCache().cacheSelectQueryPlan( cacheKey, queryPlan );
} }
} }
return queryPlan;
}
private SelectQueryPlan<R> buildSelectQueryPlan() { private SelectQueryPlan<R> buildSelectQueryPlan() {
final SqmSelectStatement[] concreteSqmStatements = QuerySplitter.split( final SqmSelectStatement[] concreteSqmStatements = QuerySplitter.split(
(SqmSelectStatement) getSqmStatement(), (SqmSelectStatement) getSqmStatement(),

View File

@ -17,6 +17,7 @@
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.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.Bindable; import org.hibernate.metamodel.mapping.Bindable;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelExpressable;
@ -81,7 +82,10 @@ public static Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParam
return Collections.emptyMap(); return Collections.emptyMap();
} }
final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> result = new IdentityHashMap<>(); final int queryParameterCount = domainParameterXref.getQueryParameterCount();
final Map<QueryParameterImplementor<?>, Map<SqmParameter, List<JdbcParameter>>> result = new IdentityHashMap<>(
CollectionHelper.determineProperSizing( queryParameterCount )
);
for ( Map.Entry<QueryParameterImplementor<?>, List<SqmParameter>> entry : for ( Map.Entry<QueryParameterImplementor<?>, List<SqmParameter>> entry :
domainParameterXref.getSqmParamByQueryParam().entrySet() ) { domainParameterXref.getSqmParamByQueryParam().entrySet() ) {

View File

@ -276,7 +276,7 @@ public SelectStatement visitSelectStatement(SqmSelectStatement statement) {
@Override @Override
public QuerySpec visitQuerySpec(SqmQuerySpec sqmQuerySpec) { public QuerySpec visitQuerySpec(SqmQuerySpec sqmQuerySpec) {
final QuerySpec sqlQuerySpec = new QuerySpec( processingStateStack.isEmpty() ); final QuerySpec sqlQuerySpec = new QuerySpec( processingStateStack.isEmpty(), sqmQuerySpec.getFromClause().getNumberOfRoots() );
processingStateStack.push( processingStateStack.push(
new SqlAstQuerySpecProcessingStateImpl( new SqlAstQuerySpecProcessingStateImpl(
@ -737,12 +737,12 @@ protected MappingModelExpressable<?> determineValueMapping(SqmExpression<?> sqmE
} }
if ( sqmExpression instanceof SqmPath ) { if ( sqmExpression instanceof SqmPath ) {
log.debugf( "Determining mapping-model type for SqmPath : " + sqmExpression ); log.debugf( "Determining mapping-model type for SqmPath : %s ", sqmExpression );
return SqmMappingModelHelper.resolveMappingModelExpressable( sqmExpression, this ); return SqmMappingModelHelper.resolveMappingModelExpressable( sqmExpression, this );
} }
log.debugf( "Determining mapping-model type for generalized SqmExpression : " + sqmExpression ); log.debugf( "Determining mapping-model type for generalized SqmExpression : %s", sqmExpression );
final SqmExpressable<?> nodeType = sqmExpression.getNodeType(); final SqmExpressable<?> nodeType = sqmExpression.getNodeType();
final MappingModelExpressable valueMapping = getCreationContext().getDomainModel().resolveMappingExpressable( nodeType ); final MappingModelExpressable valueMapping = getCreationContext().getDomainModel().resolveMappingExpressable( nodeType );
@ -763,7 +763,7 @@ protected MappingModelExpressable<?> determineValueMapping(SqmExpression<?> sqmE
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
protected MappingModelExpressable<?> determineValueMapping(SqmParameter<?> sqmParameter) { protected MappingModelExpressable<?> determineValueMapping(SqmParameter<?> sqmParameter) {
log.debugf( "Determining mapping-model type for SqmParameter : " + sqmParameter ); log.debugf( "Determining mapping-model type for SqmParameter : %s", sqmParameter );
final QueryParameterImplementor<?> queryParameter = domainParameterXref.getQueryParameter( sqmParameter ); final QueryParameterImplementor<?> queryParameter = domainParameterXref.getQueryParameter( sqmParameter );
final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter ); final QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter );

View File

@ -12,8 +12,6 @@
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.domain.SqmPath;

View File

@ -6,7 +6,6 @@
*/ */
package org.hibernate.query.sqm.sql.internal; package org.hibernate.query.sqm.sql.internal;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -21,6 +20,7 @@
import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.GraphImplementor; import org.hibernate.graph.spi.GraphImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
@ -71,7 +71,8 @@ public class StandardSqmSelectToSqlAstConverter
private final LoadQueryInfluencers fetchInfluencers; private final LoadQueryInfluencers fetchInfluencers;
private final CircularFetchDetector circularFetchDetector = new CircularFetchDetector(); private final CircularFetchDetector circularFetchDetector = new CircularFetchDetector();
private final List<DomainResult> domainResults = new ArrayList<>(); // prepare for 10 root selections to avoid list growth in most cases
private final List<DomainResult> domainResults = CollectionHelper.arrayList( 10 );
private GraphImplementor<?> currentJpaGraphNode; private GraphImplementor<?> currentJpaGraphNode;
@ -154,9 +155,12 @@ private DomainResultProducer resolveDomainResultProducer(SqmSelection sqmSelecti
@Override @Override
public List<Fetch> visitFetches(FetchParent fetchParent) { public List<Fetch> visitFetches(FetchParent fetchParent) {
final List<Fetch> fetches = new ArrayList(); final List<Fetch> fetches = CollectionHelper.arrayList( fetchParent.getReferencedMappingType().getNumberOfAttributeMappings() );
final Consumer<Fetchable> fetchableConsumer = fetchable -> { //noinspection Convert2Lambda
final Consumer<Fetchable> fetchableConsumer = new Consumer<Fetchable>() {
@Override
public void accept(Fetchable fetchable) {
final Fetch biDirectionalFetch = circularFetchDetector.findBiDirectionalFetch( final Fetch biDirectionalFetch = circularFetchDetector.findBiDirectionalFetch(
fetchParent, fetchParent,
fetchable fetchable
@ -178,6 +182,7 @@ public List<Fetch> visitFetches(FetchParent fetchParent) {
finally { finally {
fetchDepth--; fetchDepth--;
} }
}
}; };
// todo (6.0) : determine how to best handle TREAT // todo (6.0) : determine how to best handle TREAT
@ -297,6 +302,7 @@ else if ( fetchDepth > maxDepth ) {
try { try {
return fetchable.generateFetch( return fetchable.generateFetch(
fetchParent, fetchParent,
fetchablePath,
fetchTiming, fetchTiming,
joined, joined,
lockMode, lockMode,

View File

@ -328,6 +328,6 @@ public SqmPath get(MapAttribute map) {
@Override @Override
public String toString() { public String toString() {
return getClass().getSimpleName() + '(' + navigablePath.getFullPath() + ')'; return getClass().getSimpleName() + "(" + navigablePath.getFullPath() + ")";
} }
} }

View File

@ -64,12 +64,12 @@ public <X> X accept(SemanticQueryWalker<X> walker) {
@Override @Override
public <S extends T> SqmTreatedPath<T, S> treatAs(Class<S> treatJavaType) throws PathException { public <S extends T> SqmTreatedPath<T, S> treatAs(Class<S> treatJavaType) throws PathException {
throw new UnsupportedOperationException(); throw new PathException( "Embeddable paths cannot be TREAT-ed" );
} }
@Override @Override
public <S extends T> SqmTreatedPath<T, S> treatAs(EntityDomainType<S> treatTarget) throws PathException { public <S extends T> SqmTreatedPath<T, S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
return null; throw new PathException( "Embeddable paths cannot be TREAT-ed" );
} }
// @Override // @Override

View File

@ -10,6 +10,7 @@
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.sql.ast.spi.SqlAstWalker; import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.sql.ast.tree.SqlAstNode;
@ -19,9 +20,14 @@
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class FromClause implements SqlAstNode { public class FromClause implements SqlAstNode {
private final List<TableGroup> roots = new ArrayList<>(); private final List<TableGroup> roots;
public FromClause() { public FromClause() {
roots = new ArrayList<>();
}
public FromClause(int expectedNumberOfRoots) {
roots = CollectionHelper.arrayList( expectedNumberOfRoots );
} }
public List<TableGroup> getRoots() { public List<TableGroup> getRoots() {

View File

@ -24,7 +24,7 @@
public class QuerySpec implements SqlAstNode, PredicateContainer { public class QuerySpec implements SqlAstNode, PredicateContainer {
private final boolean isRoot; private final boolean isRoot;
private final FromClause fromClause = new FromClause(); private final FromClause fromClause;
private final SelectClause selectClause = new SelectClause(); private final SelectClause selectClause = new SelectClause();
private Predicate whereClauseRestrictions; private Predicate whereClauseRestrictions;
@ -34,6 +34,12 @@ public class QuerySpec implements SqlAstNode, PredicateContainer {
public QuerySpec(boolean isRoot) { public QuerySpec(boolean isRoot) {
this.isRoot = isRoot; this.isRoot = isRoot;
this.fromClause = new FromClause();
}
public QuerySpec(boolean isRoot, int expectedNumberOfRoots) {
this.isRoot = isRoot;
this.fromClause = new FromClause( expectedNumberOfRoots );
} }
/** /**

View File

@ -99,6 +99,7 @@ public FetchStrategy getMappedFetchStrategy() {
@Override @Override
public Fetch generateFetch( public Fetch generateFetch(
FetchParent fetchParent, FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming, FetchTiming fetchTiming,
boolean selected, boolean selected,
LockMode lockMode, LockMode lockMode,

View File

@ -39,13 +39,14 @@ public class BasicFetch<T> implements Fetch, BasicResultMappingNode<T> {
public BasicFetch( public BasicFetch(
int valuesArrayPosition, int valuesArrayPosition,
FetchParent fetchParent, FetchParent fetchParent,
NavigablePath fetchablePath,
BasicValuedModelPart valuedMapping, BasicValuedModelPart valuedMapping,
boolean nullable, boolean nullable,
BasicValueConverter valueConverter, BasicValueConverter valueConverter,
FetchTiming fetchTiming, FetchTiming fetchTiming,
DomainResultCreationState creationState) { DomainResultCreationState creationState) {
this.nullable = nullable; this.nullable = nullable;
this.navigablePath = fetchParent.getNavigablePath().append( valuedMapping.getFetchableName() ); this.navigablePath = fetchablePath;
this.fetchParent = fetchParent; this.fetchParent = fetchParent;
this.valuedMapping = valuedMapping; this.valuedMapping = valuedMapping;

View File

@ -10,6 +10,8 @@
import java.util.List; import java.util.List;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.AttributeMapping;
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.EntityValuedModelPart; import org.hibernate.metamodel.mapping.EntityValuedModelPart;
@ -34,7 +36,7 @@ public abstract class AbstractEntityResultNode extends AbstractFetchParent imple
private final EntityMappingType targetType; private final EntityMappingType targetType;
private final List<DomainResult> attributeDomainResults = new ArrayList<>(); private final List<DomainResult> attributeDomainResults;
public AbstractEntityResultNode( public AbstractEntityResultNode(
EntityValuedModelPart referencedModelPart, EntityValuedModelPart referencedModelPart,
@ -92,18 +94,20 @@ public AbstractEntityResultNode(
); );
} }
// entityDescriptor.visitAttributeMappings(
// mapping -> attributeDomainResults.add(
// mapping.createDomainResult(
// navigablePath.append( mapping.getAttributeName() ),
// entityTableGroup,
// null,
// creationState
// )
// )
// );
// todo (6.0) : handle other special navigables such as discriminator, row-id, tenant-id, etc // todo (6.0) : handle other special navigables such as discriminator, row-id, tenant-id, etc
attributeDomainResults = CollectionHelper.arrayList( entityDescriptor.getNumberOfAttributeMappings() );
entityDescriptor.visitAttributeMappings(
mapping -> attributeDomainResults.add(
mapping.createDomainResult(
navigablePath.append( mapping.getAttributeName() ),
entityTableGroup,
null,
creationState
)
)
);
} }
@Override @Override

View File

@ -37,7 +37,7 @@ default SqlAliasBaseManager getSqlAliasBaseManager() {
* BiFunction<FetchParent,Fetchable,LockMode> lockModeResolver) * BiFunction<FetchParent,Fetchable,LockMode> lockModeResolver)
* *
* [1] `selected` refers to the named parameter in * [1] `selected` refers to the named parameter in
* {@link Fetchable#generateFetch(FetchParent, org.hibernate.engine.FetchTiming, boolean, LockMode, String, DomainResultCreationState)}. * {@link Fetchable#generateFetch(FetchParent, org.hibernate.query.NavigablePath, org.hibernate.engine.FetchTiming, boolean, LockMode, String, DomainResultCreationState)}.
* For {@link org.hibernate.engine.FetchTiming#IMMEDIATE}, this boolean value indicates * For {@link org.hibernate.engine.FetchTiming#IMMEDIATE}, this boolean value indicates
* whether the values for the generated assembler/initializers are or should be available in * whether the values for the generated assembler/initializers are or should be available in
* the {@link JdbcValues} being processed. For {@link org.hibernate.engine.FetchTiming#DELAYED} this * the {@link JdbcValues} being processed. For {@link org.hibernate.engine.FetchTiming#DELAYED} this

View File

@ -10,6 +10,7 @@
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming; import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -26,6 +27,7 @@ public interface Fetchable extends ModelPart {
Fetch generateFetch( Fetch generateFetch(
FetchParent fetchParent, FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming, FetchTiming fetchTiming,
boolean selected, boolean selected,
LockMode lockMode, LockMode lockMode,

View File

@ -11,15 +11,12 @@
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.internal.util.SerializationHelper;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor; import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.SerializableTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators; import org.hibernate.type.descriptor.sql.SqlTypeDescriptorIndicators;
import org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.type.spi.TypeConfigurationAware; import org.hibernate.type.spi.TypeConfigurationAware;
@ -74,19 +71,34 @@ private void performInjections(JavaTypeDescriptor descriptor) {
// descriptor access // descriptor access
public <T> JavaTypeDescriptor<T> getDescriptor(Class<T> javaType) { public <T> JavaTypeDescriptor<T> getDescriptor(Class<T> javaType) {
return RegistryHelper.INSTANCE.resolveDescriptor( return resolveDescriptor( javaType );
descriptorsByClass, // return RegistryHelper.INSTANCE.resolveDescriptor(
javaType, // descriptorsByClass,
() -> { // javaType,
log.debugf( // () -> {
"Could not find matching scoped JavaTypeDescriptor for requested Java class [%s]; " + // log.debugf(
"falling back to static registry", // "Could not find matching scoped JavaTypeDescriptor for requested Java class [%s]; " +
javaType.getName() // "falling back to static registry",
); // javaType.getName()
// );
return org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry.INSTANCE.getDescriptor( javaType ); //
} // if ( Serializable.class.isAssignableFrom( javaType ) ) {
); // return new SerializableTypeDescriptor( javaType );
// }
//
// if ( !AttributeConverter.class.isAssignableFrom( javaType ) ) {
// log.debugf(
// "Could not find matching JavaTypeDescriptor for requested Java class [%s]; using fallback. " +
// "This means Hibernate does not know how to perform certain basic operations in relation to this Java type." +
// "",
// javaType.getName()
// );
// checkEqualsAndHashCode( javaType );
// }
//
// return new FallbackJavaTypeDescriptor<>( javaType );
// }
// );
} }
public void addDescriptor(JavaTypeDescriptor descriptor) { public void addDescriptor(JavaTypeDescriptor descriptor) {
@ -103,15 +115,15 @@ public void addDescriptor(JavaTypeDescriptor descriptor) {
} }
public <J> JavaTypeDescriptor<J> resolveDescriptor(Class<J> javaType, Supplier<JavaTypeDescriptor<J>> creator) { public <J> JavaTypeDescriptor<J> resolveDescriptor(Class<J> javaType, Supplier<JavaTypeDescriptor<J>> creator) {
final JavaTypeDescriptor cached = descriptorsByClass.get( javaType );
if ( cached != null ) {
//noinspection unchecked //noinspection unchecked
return descriptorsByClass.computeIfAbsent( return cached;
javaType,
jt -> {
final JavaTypeDescriptor<J> jtd = creator.get();
performInjections( jtd );
return jtd;
} }
);
final JavaTypeDescriptor<J> created = creator.get();
descriptorsByClass.put( javaType, created );
return created;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -126,7 +138,7 @@ public <J> JavaTypeDescriptor<J> resolveDescriptor(Class<J> javaType) {
fallbackDescriptor = new EnumJavaTypeDescriptor( javaType ); fallbackDescriptor = new EnumJavaTypeDescriptor( javaType );
} }
else if ( Serializable.class.isAssignableFrom( javaType ) ) { else if ( Serializable.class.isAssignableFrom( javaType ) ) {
fallbackDescriptor = new OnTheFlySerializableJavaDescriptor( javaType ); fallbackDescriptor = new SerializableTypeDescriptor( javaType );
} }
else { else {
fallbackDescriptor = new JavaTypeDescriptorBasicAdaptor( javaType ); fallbackDescriptor = new JavaTypeDescriptorBasicAdaptor( javaType );
@ -146,7 +158,7 @@ public JavaTypeDescriptor<?> resolveDynamicDescriptor(String typeName) {
return new DynamicJtd(); return new DynamicJtd();
} }
private class DynamicJtd implements JavaTypeDescriptor<Map> { private static class DynamicJtd implements JavaTypeDescriptor<Map> {
@Override @Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) { public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
@ -172,64 +184,4 @@ public Class<Map> getJavaTypeClass() {
return Map.class; return Map.class;
} }
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private class OnTheFlySerializableJavaDescriptor<T extends Serializable> extends AbstractTypeDescriptor<T> {
private final SqlTypeDescriptor sqlTypeDescriptor;
public OnTheFlySerializableJavaDescriptor(Class<T> type) {
super( type );
// todo (6.0) : would be nice to expose for config by user
// todo (6.0) : ^^ might also be nice to allow them to plug in a "JavaTypeDescriptorResolver"
// - that allows them to hook into the #getDescriptor call either as the primary or as a fallback
log.debugf(
"Could not find matching JavaTypeDescriptor for requested Java class [%s]; using fallback via its Serializable interface. " +
"This means Hibernate does not know how to perform certain basic operations in relation to this Java type" +
"which can lead to those operations having a large performance impact. Consider registering these " +
"JavaTypeDescriptors with the %s during bootstrap, either directly or through a registered %s " +
"accessing the %s ",
getJavaType().getName(),
JavaTypeDescriptorRegistry.class.getName(),
TypeContributor.class.getName(),
TypeConfiguration.class.getName()
);
sqlTypeDescriptor = VarbinaryTypeDescriptor.INSTANCE;
}
@Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) {
return sqlTypeDescriptor;
}
@Override
public <X> X unwrap(T value, Class<X> type, WrapperOptions options) {
if ( type.equals( byte[].class ) ) {
throw new UnsupportedOperationException( "Cannot unwrap Serializable to format other than byte[]" );
}
return (X) SerializationHelper.serialize( value );
}
@Override
@SuppressWarnings("unchecked")
public <X> T wrap(X value, WrapperOptions options) {
if ( value == null ) {
return null;
}
if ( value.getClass().equals( byte[].class ) ) {
throw new UnsupportedOperationException( "Cannot unwrap Serializable to format other than byte[]" );
}
final byte[] bytes = (byte[]) value;
return (T) SerializationHelper.deserialize( bytes );
}
}
} }