perf work
This commit is contained in:
parent
2502f4c108
commit
6f77e0d261
|
@ -1255,9 +1255,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
|
|||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public void addUniqueConstraints(Table table, List uniqueConstraints) {
|
||||
List<UniqueConstraintHolder> constraintHolders = new ArrayList<>(
|
||||
CollectionHelper.determineProperSizing( uniqueConstraints.size() )
|
||||
);
|
||||
List<UniqueConstraintHolder> constraintHolders = new ArrayList<>( uniqueConstraints.size() );
|
||||
|
||||
int keyNameBase = determineCurrentNumberOfUniqueConstraintHolders( table );
|
||||
for ( String[] columns : ( List<String[]> ) uniqueConstraints ) {
|
||||
|
|
|
@ -781,7 +781,7 @@ public class TableBinder {
|
|||
result = java.util.Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
result = new ArrayList<UniqueConstraintHolder>( CollectionHelper.determineProperSizing( annotations.length ) );
|
||||
result = CollectionHelper.arrayList( annotations.length );
|
||||
for ( UniqueConstraint uc : annotations ) {
|
||||
result.add(
|
||||
new UniqueConstraintHolder()
|
||||
|
|
|
@ -614,14 +614,13 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
try {
|
||||
final QueryEngine queryEngine = getFactory().getQueryEngine();
|
||||
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
|
||||
final SqmStatement sqm = interpretationCache.resolveSqmStatement(
|
||||
queryString,
|
||||
s -> queryEngine.getHqlTranslator().interpret( queryString )
|
||||
);
|
||||
|
||||
final QuerySqmImpl query = new QuerySqmImpl(
|
||||
queryString,
|
||||
sqm,
|
||||
interpretationCache.resolveHqlInterpretation(
|
||||
queryString,
|
||||
s -> queryEngine.getHqlTranslator().interpret( queryString )
|
||||
),
|
||||
resultClass,
|
||||
this
|
||||
);
|
||||
|
@ -886,7 +885,6 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
|
||||
try {
|
||||
return new QuerySqmImpl<>(
|
||||
"<criteria>",
|
||||
(SqmStatement) criteriaQuery,
|
||||
criteriaQuery.getResultType(),
|
||||
this
|
||||
|
@ -902,7 +900,6 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
checkOpen();
|
||||
try {
|
||||
return new QuerySqmImpl<>(
|
||||
"<criteria>",
|
||||
(SqmUpdateStatement) criteriaUpdate,
|
||||
null,
|
||||
this
|
||||
|
@ -918,7 +915,6 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
checkOpen();
|
||||
try {
|
||||
return new QuerySqmImpl<>(
|
||||
"<criteria>",
|
||||
(SqmDeleteStatement) criteriaDelete,
|
||||
null,
|
||||
this
|
||||
|
|
|
@ -28,25 +28,13 @@ public class LoggingHelper {
|
|||
return UNREFERENCED;
|
||||
}
|
||||
|
||||
if ( role.isRoot() ) {
|
||||
return StringHelper.collapse( role.getFullPath() );
|
||||
}
|
||||
else {
|
||||
assert role.getParent() != null;
|
||||
return StringHelper.collapse( role.getParent().getFullPath() ) + '.' + role.getNavigableName();
|
||||
}
|
||||
return role.getFullPath();
|
||||
}
|
||||
|
||||
public static String toLoggableString(NavigablePath path) {
|
||||
assert path != null;
|
||||
|
||||
if ( path.isRoot() ) {
|
||||
return StringHelper.collapse( path.getFullPath() );
|
||||
}
|
||||
else {
|
||||
assert path.getParent() != null;
|
||||
return StringHelper.collapse( path.getParent().getFullPath() ) + '.' + path.getLocalName();
|
||||
}
|
||||
return path.getFullPath();
|
||||
}
|
||||
|
||||
public static String toLoggableString(NavigableRole role, Object key) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.function.Function;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public final class CollectionHelper {
|
||||
public static final int DEFAULT_LIST_CAPACITY = 10;
|
||||
public static final int MINIMUM_INITIAL_CAPACITY = 16;
|
||||
public static final float LOAD_FACTOR = 0.75f;
|
||||
|
||||
|
@ -178,8 +179,8 @@ public final class CollectionHelper {
|
|||
return new ConcurrentHashMap<K, V>( size, loadFactor );
|
||||
}
|
||||
|
||||
public static <T> ArrayList<T> arrayList(int anticipatedSize) {
|
||||
return new ArrayList<T>( anticipatedSize );
|
||||
public static <T> ArrayList<T> arrayList(int expectedNumberOfElements) {
|
||||
return new ArrayList<>( Math.max( expectedNumberOfElements + 1, DEFAULT_LIST_CAPACITY ) );
|
||||
}
|
||||
|
||||
public static <T> Set<T> makeCopy(Set<T> source) {
|
||||
|
|
|
@ -251,20 +251,35 @@ public class EmbeddableMappingType implements ManagedMappingType {
|
|||
|
||||
@Override
|
||||
public Object disassemble(Object value, SharedSessionContractImplementor session) {
|
||||
|
||||
return null;
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDisassembledJdbcValues(
|
||||
Object value, Clause clause, JdbcValuesConsumer valuesConsumer, SharedSessionContractImplementor session) {
|
||||
|
||||
Object value,
|
||||
Clause clause,
|
||||
JdbcValuesConsumer valuesConsumer,
|
||||
SharedSessionContractImplementor session) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
|
|
|
@ -18,6 +18,9 @@ import org.hibernate.sql.results.spi.FetchableContainer;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ManagedMappingType extends MappingType, FetchableContainer {
|
||||
int getNumberOfAttributeMappings();
|
||||
int getNumberOfDeclaredAttributeMappings();
|
||||
|
||||
Collection<AttributeMapping> getAttributeMappings();
|
||||
|
||||
/**
|
||||
|
|
|
@ -156,6 +156,7 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
|
|||
@Override
|
||||
public Fetch generateFetch(
|
||||
FetchParent fetchParent,
|
||||
NavigablePath fetchablePath,
|
||||
FetchTiming fetchTiming,
|
||||
boolean selected,
|
||||
LockMode lockMode,
|
||||
|
@ -173,6 +174,7 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
|
|||
return new BasicFetch(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
fetchParent,
|
||||
fetchablePath,
|
||||
this,
|
||||
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
|
||||
getConverter(),
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -15,6 +14,8 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
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.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
|
@ -38,7 +39,6 @@ import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
|||
import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
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.results.internal.domain.composite.CompositeFetch;
|
||||
import org.hibernate.sql.results.internal.domain.composite.CompositeResult;
|
||||
|
@ -47,6 +47,7 @@ import org.hibernate.sql.results.spi.DomainResultCreationState;
|
|||
import org.hibernate.sql.results.spi.Fetch;
|
||||
import org.hibernate.sql.results.spi.FetchParent;
|
||||
import org.hibernate.sql.results.spi.Fetchable;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -106,6 +107,23 @@ public class EmbeddedAttributeMapping
|
|||
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
|
||||
public <T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
|
@ -132,13 +150,14 @@ public class EmbeddedAttributeMapping
|
|||
@Override
|
||||
public Fetch generateFetch(
|
||||
FetchParent fetchParent,
|
||||
NavigablePath fetchablePath,
|
||||
FetchTiming fetchTiming,
|
||||
boolean selected,
|
||||
LockMode lockMode,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return new CompositeFetch(
|
||||
fetchParent.getNavigablePath().append( getFetchableName() ),
|
||||
fetchablePath,
|
||||
this,
|
||||
fetchParent,
|
||||
fetchTiming,
|
||||
|
@ -152,7 +171,7 @@ public class EmbeddedAttributeMapping
|
|||
Clause clause,
|
||||
SqmToSqlAstConverter walker,
|
||||
SqlAstCreationState sqlAstCreationState) {
|
||||
final List<ColumnReference> columnReferences = new ArrayList<>();
|
||||
final List<ColumnReference> columnReferences = CollectionHelper.arrayList( attrColumnNames.length );
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
|
||||
|
||||
getEmbeddableTypeDescriptor().visitJdbcTypes(
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.SortedSet;
|
|||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
|
@ -103,6 +104,7 @@ import org.hibernate.internal.CoreMessageLogger;
|
|||
import org.hibernate.internal.FilterHelper;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
import org.hibernate.jdbc.TooManyRowsAffectedException;
|
||||
|
@ -5313,16 +5315,24 @@ public abstract class AbstractEntityPersister
|
|||
return accessOptimizer.getPropertyValues( object );
|
||||
}
|
||||
else {
|
||||
final List<Object> values = new ArrayList<>();
|
||||
final Object[] values = new Object[ getNumberOfAttributeMappings() ];
|
||||
final AtomicInteger index = new AtomicInteger( 0 );
|
||||
|
||||
//noinspection Convert2Lambda
|
||||
visitAttributeMappings(
|
||||
attributeMapping -> {
|
||||
final AttributeMetadata attributeMetadata = attributeMapping.getAttributeMetadataAccess()
|
||||
.resolveAttributeMetadata( this );
|
||||
values.add( attributeMetadata.getPropertyAccess().getGetter().get( object ) );
|
||||
new Consumer<AttributeMapping>() {
|
||||
@Override
|
||||
public void accept(AttributeMapping mapping) {
|
||||
values[ index.getAndIncrement() ] = mapping.getAttributeMetadataAccess()
|
||||
.resolveAttributeMetadata( AbstractEntityPersister.this )
|
||||
.getPropertyAccess()
|
||||
.getGetter()
|
||||
.get( object );
|
||||
}
|
||||
}
|
||||
);
|
||||
return values.toArray();
|
||||
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6040,6 +6050,7 @@ public abstract class AbstractEntityPersister
|
|||
private EntityVersionMapping versionMapping;
|
||||
|
||||
private SortedMap<String, AttributeMapping> declaredAttributeMappings = new TreeMap<>();
|
||||
private Collection<AttributeMapping> attributeMappings;
|
||||
|
||||
private ReflectionOptimizer.AccessOptimizer accessOptimizer;
|
||||
|
||||
|
@ -6079,7 +6090,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
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++ ) {
|
||||
final NonIdentifierAttribute runtimeAttrDefinition = currentEntityMetamodel.getProperties()[i];
|
||||
|
@ -6126,6 +6137,20 @@ public abstract class AbstractEntityPersister
|
|||
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
|
||||
public boolean isTypeOrSuperType(EntityMappingType targetType) {
|
||||
if ( targetType == null ) {
|
||||
|
@ -6260,8 +6285,6 @@ public abstract class AbstractEntityPersister
|
|||
return versionMapping;
|
||||
}
|
||||
|
||||
private Collection<AttributeMapping> attributeMappings;
|
||||
|
||||
@Override
|
||||
public Collection<AttributeMapping> getAttributeMappings() {
|
||||
if ( attributeMappings == null ) {
|
||||
|
|
|
@ -118,6 +118,18 @@ public interface EntityPersister extends EntityDefinition, EntityValuedModelPart
|
|||
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 ~~~~~~~~~~~~~~
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.PropertyAccessException;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
|
||||
|
@ -39,7 +40,7 @@ public class GetterMethodImpl implements Getter {
|
|||
@Override
|
||||
public Object get(Object owner) {
|
||||
try {
|
||||
return getterMethod.invoke( owner );
|
||||
return getterMethod.invoke( owner, ArrayHelper.EMPTY_OBJECT_ARRAY );
|
||||
}
|
||||
catch (InvocationTargetException ite) {
|
||||
throw new PropertyAccessException(
|
||||
|
|
|
@ -24,14 +24,12 @@ public class NavigablePath implements DotIdentifierSequence {
|
|||
public static final String IDENTIFIER_MAPPER_PROPERTY = "_identifierMapper";
|
||||
|
||||
private final NavigablePath parent;
|
||||
private final String localName;
|
||||
private final String fullPath;
|
||||
|
||||
private final int hashCode;
|
||||
|
||||
public NavigablePath(NavigablePath parent, String navigableName) {
|
||||
this.parent = parent;
|
||||
this.localName = navigableName;
|
||||
|
||||
// the _identifierMapper is a "hidden property" on entities with composite keys.
|
||||
// concatenating it will prevent the path from correctly being used to look up
|
||||
|
@ -54,31 +52,12 @@ public class NavigablePath implements DotIdentifierSequence {
|
|||
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) {
|
||||
this( localName, null );
|
||||
}
|
||||
|
||||
public NavigablePath(String rootName, String alias) {
|
||||
this.parent = null;
|
||||
this.localName = rootName;
|
||||
|
||||
this.fullPath = alias == null ? rootName : rootName + '(' + alias + ')';
|
||||
|
||||
|
@ -102,7 +81,7 @@ public class NavigablePath implements DotIdentifierSequence {
|
|||
}
|
||||
|
||||
public String getLocalName() {
|
||||
return localName;
|
||||
return parent == null ? fullPath : StringHelper.unqualify( fullPath );
|
||||
}
|
||||
|
||||
public String getFullPath() {
|
||||
|
|
|
@ -180,7 +180,7 @@ public class QuerySplitter {
|
|||
final SqmFromClause previousCurrent = currentFromClauseCopy;
|
||||
|
||||
try {
|
||||
SqmFromClause copy = new SqmFromClause();
|
||||
SqmFromClause copy = new SqmFromClause( fromClause.getNumberOfRoots() );
|
||||
currentFromClauseCopy = copy;
|
||||
super.visitFromClause( fromClause );
|
||||
return copy;
|
||||
|
|
|
@ -804,7 +804,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
|
|||
treatHandlerStack.push( new TreatHandlerFromClause() );
|
||||
|
||||
try {
|
||||
final SqmFromClause fromClause = new SqmFromClause();
|
||||
final SqmFromClause fromClause = new SqmFromClause( parserFromClause.fromClauseSpace().size() );
|
||||
for ( HqlParser.FromClauseSpaceContext parserSpace : parserFromClause.fromClauseSpace() ) {
|
||||
final SqmRoot sqmPathRoot = visitFromClauseSpace( parserSpace );
|
||||
fromClause.addRoot( sqmPathRoot );
|
||||
|
|
|
@ -7,12 +7,15 @@
|
|||
package org.hibernate.query.internal;
|
||||
|
||||
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.ParameterMetadataImplementor;
|
||||
import org.hibernate.query.spi.QueryInterpretationCache;
|
||||
import org.hibernate.query.spi.SelectQueryPlan;
|
||||
import org.hibernate.query.sql.spi.ParameterInterpretation;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
|
||||
/**
|
||||
|
@ -25,14 +28,10 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation
|
|||
public static final QueryInterpretationCacheDisabledImpl INSTANCE = new QueryInterpretationCacheDisabledImpl();
|
||||
|
||||
@Override
|
||||
public SelectQueryPlan getSelectQueryPlan(Key key) {
|
||||
public SelectQueryPlan resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan> creator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheSelectQueryPlan(Key key, SelectQueryPlan plan) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public NonSelectQueryPlan getNonSelectQueryPlan(Key key) {
|
||||
return null;
|
||||
|
@ -43,8 +42,36 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmStatement resolveSqmStatement(String queryString, Function<String, SqmStatement<?>> creator) {
|
||||
return creator.apply( queryString );
|
||||
public HqlInterpretation resolveHqlInterpretation(String queryString, Function<String, SqmStatement<?>> creator) {
|
||||
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
|
||||
|
|
|
@ -7,14 +7,19 @@
|
|||
package org.hibernate.query.internal;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.internal.util.collections.BoundedConcurrentHashMap;
|
||||
import org.hibernate.query.QueryLogger;
|
||||
import org.hibernate.query.spi.HqlInterpretation;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.spi.ParameterMetadataImplementor;
|
||||
import org.hibernate.query.spi.QueryInterpretationCache;
|
||||
import org.hibernate.query.spi.QueryPlan;
|
||||
import org.hibernate.query.spi.SelectQueryPlan;
|
||||
import org.hibernate.query.spi.SimpleHqlInterpretationImpl;
|
||||
import org.hibernate.query.sql.spi.ParameterInterpretation;
|
||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -29,8 +34,12 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
|
|||
|
||||
/**
|
||||
* The default strong reference count.
|
||||
*
|
||||
* @deprecated No longer used
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int DEFAULT_PARAMETER_METADATA_MAX_COUNT = 128;
|
||||
|
||||
/**
|
||||
* The default soft reference count.
|
||||
*/
|
||||
|
@ -41,27 +50,31 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
|
|||
*/
|
||||
private final BoundedConcurrentHashMap<Key, QueryPlan> queryPlanCache;
|
||||
|
||||
private final BoundedConcurrentHashMap<String, SqmStatement<?>> sqmStatementCache;
|
||||
private final BoundedConcurrentHashMap<String, HqlInterpretation> hqlInterpretationCache;
|
||||
private final BoundedConcurrentHashMap<String, ParameterInterpretation> nativeQueryParamCache;
|
||||
|
||||
public QueryInterpretationCacheStandardImpl(int maxQueryPlanCount) {
|
||||
log.debugf( "Starting QueryPlanCache(%s)", maxQueryPlanCount );
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectQueryPlan getSelectQueryPlan(Key key) {
|
||||
public SelectQueryPlan resolveSelectQueryPlan(
|
||||
Key key,
|
||||
Supplier<SelectQueryPlan> creator) {
|
||||
log.tracef( "QueryPlan#getSelectQueryPlan(%s)", key );
|
||||
return (SelectQueryPlan) queryPlanCache.get( key );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheSelectQueryPlan(Key key, SelectQueryPlan plan) {
|
||||
log.tracef( "QueryPlan#cacheSelectQueryPlan(%s)", key );
|
||||
queryPlanCache.putIfAbsent( key, plan );
|
||||
final SelectQueryPlan cached = (SelectQueryPlan) queryPlanCache.get( key );
|
||||
if ( cached != null ) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
final SelectQueryPlan plan = creator.get();
|
||||
queryPlanCache.put( key, plan );
|
||||
return plan;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -76,17 +89,37 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmStatement resolveSqmStatement(
|
||||
public HqlInterpretation resolveHqlInterpretation(
|
||||
String queryString,
|
||||
Function<String, SqmStatement<?>> creator) {
|
||||
log.tracef( "QueryPlan#resolveSqmStatement(%s)", queryString );
|
||||
return sqmStatementCache.computeIfAbsent(
|
||||
queryString,
|
||||
s -> {
|
||||
log.debugf( "Creating and caching SqmStatement - %s", queryString );
|
||||
return creator.apply( queryString );
|
||||
}
|
||||
);
|
||||
log.tracef( "QueryPlan#resolveHqlInterpretation( `%s` )", queryString );
|
||||
|
||||
final HqlInterpretation cached = hqlInterpretationCache.get( queryString );
|
||||
if ( cached != null ) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -16,6 +16,7 @@ import org.hibernate.cfg.AvailableSettings;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
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.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
|
@ -64,6 +65,7 @@ public class QueryEngine {
|
|||
private final SqmCriteriaNodeBuilder criteriaBuilder;
|
||||
private final HqlTranslator hqlTranslator;
|
||||
private final SqmTranslatorFactory sqmTranslatorFactory;
|
||||
private final NativeQueryInterpreter nativeQueryInterpreter;
|
||||
private final QueryInterpretationCache interpretationCache;
|
||||
private final SqmFunctionRegistry sqmFunctionRegistry;
|
||||
|
||||
|
@ -101,6 +103,8 @@ public class QueryEngine {
|
|||
serviceRegistry
|
||||
);
|
||||
|
||||
this.nativeQueryInterpreter = serviceRegistry.getService( NativeQueryInterpreter.class );
|
||||
|
||||
this.interpretationCache = buildInterpretationCache( properties );
|
||||
|
||||
this.sqmFunctionRegistry = new SqmFunctionRegistry();
|
||||
|
@ -163,20 +167,21 @@ public class QueryEngine {
|
|||
final boolean explicitUseCache = ConfigurationHelper.getBoolean(
|
||||
AvailableSettings.QUERY_PLAN_CACHE_ENABLED,
|
||||
properties,
|
||||
false
|
||||
// enabled by default
|
||||
true
|
||||
);
|
||||
|
||||
final Integer explicitMaxPlanCount = ConfigurationHelper.getInteger(
|
||||
final Integer explicitMaxPlanSize = ConfigurationHelper.getInteger(
|
||||
AvailableSettings.QUERY_PLAN_CACHE_MAX_SIZE,
|
||||
properties
|
||||
);
|
||||
|
||||
if ( explicitUseCache || ( explicitMaxPlanCount != null && explicitMaxPlanCount > 0 ) ) {
|
||||
return new QueryInterpretationCacheStandardImpl(
|
||||
explicitMaxPlanCount != null
|
||||
? explicitMaxPlanCount
|
||||
: QueryInterpretationCacheStandardImpl.DEFAULT_QUERY_PLAN_MAX_COUNT
|
||||
);
|
||||
if ( explicitUseCache || ( explicitMaxPlanSize != null && explicitMaxPlanSize > 0 ) ) {
|
||||
final int size = explicitMaxPlanSize != null
|
||||
? explicitMaxPlanSize
|
||||
: QueryInterpretationCacheStandardImpl.DEFAULT_QUERY_PLAN_MAX_COUNT;
|
||||
|
||||
return new QueryInterpretationCacheStandardImpl( size );
|
||||
}
|
||||
else {
|
||||
// disabled
|
||||
|
@ -218,6 +223,10 @@ public class QueryEngine {
|
|||
return sqmTranslatorFactory;
|
||||
}
|
||||
|
||||
public NativeQueryInterpreter getNativeQueryInterpreter() {
|
||||
return nativeQueryInterpreter;
|
||||
}
|
||||
|
||||
public QueryInterpretationCache getInterpretationCache() {
|
||||
return interpretationCache;
|
||||
}
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
package org.hibernate.query.spi;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.query.sql.spi.ParameterInterpretation;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
|
||||
/**
|
||||
* A cache for QueryPlans used (and produced) by the translation
|
||||
* and execution of a query.
|
||||
* Cache for various parts of translating or interpreting queries.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -23,13 +23,15 @@ public interface QueryInterpretationCache {
|
|||
interface Key {
|
||||
}
|
||||
|
||||
SelectQueryPlan getSelectQueryPlan(Key key);
|
||||
void cacheSelectQueryPlan(Key key, SelectQueryPlan plan);
|
||||
SelectQueryPlan resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan> creator);
|
||||
|
||||
NonSelectQueryPlan getNonSelectQueryPlan(Key key);
|
||||
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);
|
||||
|
||||
|
@ -45,4 +47,5 @@ public interface QueryInterpretationCache {
|
|||
* memory until they are replaced by others. It is not considered a memory leak as the cache is bounded.
|
||||
*/
|
||||
void close();
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -76,6 +76,7 @@ import org.hibernate.query.spi.SelectQueryPlan;
|
|||
import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
|
||||
import org.hibernate.query.sql.spi.NativeQueryImplementor;
|
||||
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.ParameterInterpretation;
|
||||
import org.hibernate.query.sql.spi.SelectInterpretationsKey;
|
||||
|
@ -112,6 +113,7 @@ public class NativeQueryImpl<R>
|
|||
private boolean autoDiscoverTypes;
|
||||
|
||||
private Serializable collectionKey;
|
||||
private NativeQueryInterpreter nativeQueryInterpreter;
|
||||
|
||||
/**
|
||||
* Constructs a NativeQueryImpl given a sql query defined in the mappings.
|
||||
|
@ -344,33 +346,31 @@ public class NativeQueryImpl<R>
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
private SelectQueryPlan<R> resolveSelectQueryPlan() {
|
||||
final NativeQueryInterpreter interpreter = getSessionFactory().getServiceRegistry().getService( NativeQueryInterpreter.class );
|
||||
|
||||
SelectQueryPlan<R> queryPlan = null;
|
||||
|
||||
|
||||
final JdbcValuesMappingProducer resultSetMapping = getJdbcValuesMappingProducer();
|
||||
final RowTransformer rowTransformer = resolveRowTransformer();
|
||||
|
||||
final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( resultSetMapping );
|
||||
if ( cacheKey != null ) {
|
||||
queryPlan = getSession().getFactory().getQueryEngine().getInterpretationCache().getSelectQueryPlan( cacheKey );
|
||||
}
|
||||
|
||||
if ( queryPlan == null ) {
|
||||
queryPlan = interpreter.createQueryPlan(
|
||||
generateSelectQueryDefinition(),
|
||||
getSessionFactory()
|
||||
return getSession().getFactory().getQueryEngine().getInterpretationCache().resolveSelectQueryPlan(
|
||||
cacheKey,
|
||||
this::createQueryPlan
|
||||
);
|
||||
if ( cacheKey != null ) {
|
||||
getSession().getFactory()
|
||||
.getQueryEngine()
|
||||
.getInterpretationCache()
|
||||
.cacheSelectQueryPlan( cacheKey, queryPlan );
|
||||
}
|
||||
}
|
||||
else {
|
||||
return createQueryPlan();
|
||||
}
|
||||
}
|
||||
|
||||
return queryPlan;
|
||||
private NativeSelectQueryPlan<R> createQueryPlan() {
|
||||
final RowTransformer rowTransformer = resolveRowTransformer();
|
||||
|
||||
return getSessionFactory().getQueryEngine().getNativeQueryInterpreter().createQueryPlan(
|
||||
generateSelectQueryDefinition(),
|
||||
getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
private JdbcValuesMappingProducer getJdbcValuesMappingProducer() {
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.Set;
|
|||
import java.util.TreeMap;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.query.QueryLogger;
|
||||
import org.hibernate.query.internal.QueryParameterNamedImpl;
|
||||
import org.hibernate.query.internal.QueryParameterPositionalImpl;
|
||||
|
@ -42,9 +43,6 @@ public class DomainParameterXref {
|
|||
* SQM statement
|
||||
*/
|
||||
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
|
||||
// SqmParameter and a QueryParameter. Multiple SqmParameter references
|
||||
// can map to the same QueryParameter. Consider, e.g.,
|
||||
|
@ -90,6 +88,13 @@ public class DomainParameterXref {
|
|||
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() ) {
|
||||
if ( sqmParameter instanceof JpaCriteriaParameter ) {
|
||||
// see discussion on `SqmJpaCriteriaParameterWrapper#accept`
|
||||
|
@ -181,6 +186,10 @@ public class DomainParameterXref {
|
|||
return sqmParamsByQueryParam.keySet();
|
||||
}
|
||||
|
||||
public int getQueryParameterCount() {
|
||||
return sqmParamsByQueryParam.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mapping of all QueryParameters to the List of its corresponding
|
||||
* SqmParameters
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.hibernate.query.internal.ParameterMetadataImpl;
|
|||
import org.hibernate.query.internal.QueryOptionsImpl;
|
||||
import org.hibernate.query.internal.QueryParameterBindingsImpl;
|
||||
import org.hibernate.query.spi.AbstractQuery;
|
||||
import org.hibernate.query.spi.HqlInterpretation;
|
||||
import org.hibernate.query.spi.MutableQueryOptions;
|
||||
import org.hibernate.query.spi.NonSelectQueryPlan;
|
||||
import org.hibernate.query.spi.ParameterMetadataImplementor;
|
||||
|
@ -72,9 +73,9 @@ public class QuerySqmImpl<R>
|
|||
private final SqmStatement sqmStatement;
|
||||
private final Class resultType;
|
||||
|
||||
private final ParameterMetadataImplementor parameterMetadata;
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
|
||||
private final ParameterMetadataImpl parameterMetadata;
|
||||
private final QueryParameterBindingsImpl parameterBindings;
|
||||
|
||||
private final QueryOptionsImpl queryOptions = new QueryOptionsImpl();
|
||||
|
@ -141,27 +142,57 @@ public class QuerySqmImpl<R>
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form used for HQL queries
|
||||
*/
|
||||
public QuerySqmImpl(
|
||||
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,
|
||||
Class resultType,
|
||||
SharedSessionContractImplementor producer) {
|
||||
super( producer );
|
||||
|
||||
SqmUtil.verifyIsSelectStatement( sqmStatement );
|
||||
checkQueryReturnType( (SqmSelectStatement<R>) sqmStatement, resultType, producer.getFactory() );
|
||||
|
||||
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" );
|
||||
}
|
||||
}
|
||||
|
||||
this.hqlString = hqlString;
|
||||
this.hqlString = "<criteria>";
|
||||
this.sqmStatement = sqmStatement;
|
||||
this.resultType = resultType;
|
||||
|
||||
|
||||
this.domainParameterXref = DomainParameterXref.from( sqmStatement );
|
||||
if ( ! domainParameterXref.hasParameters() ) {
|
||||
this.parameterMetadata = ParameterMetadataImpl.EMPTY;
|
||||
|
@ -391,27 +422,22 @@ public class QuerySqmImpl<R>
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
private SelectQueryPlan<R> resolveSelectQueryPlan() {
|
||||
// resolve (or make) the QueryPlan. This QueryPlan might be an
|
||||
// aggregation of multiple plans. QueryPlans can be cached, except
|
||||
// for in certain circumstances, the determination of which occurs in
|
||||
// SqmInterpretationsKey#generateFrom - if SqmInterpretationsKey#generateFrom
|
||||
// returns null the query is not cacheable
|
||||
|
||||
SelectQueryPlan<R> queryPlan = null;
|
||||
// resolve (or make) the QueryPlan. This QueryPlan might be an aggregation of multiple plans.
|
||||
//
|
||||
// QueryPlans can be cached, except for in certain circumstances
|
||||
// - the determination of these circumstances occurs in SqmInterpretationsKey#generateFrom.
|
||||
// If SqmInterpretationsKey#generateFrom returns null the query is not cacheable
|
||||
|
||||
final QueryInterpretationCache.Key cacheKey = SqmInterpretationsKey.generateFrom( this );
|
||||
if ( cacheKey != null ) {
|
||||
queryPlan = getSession().getFactory().getQueryEngine().getInterpretationCache().getSelectQueryPlan( cacheKey );
|
||||
return getSession().getFactory().getQueryEngine().getInterpretationCache().resolveSelectQueryPlan(
|
||||
cacheKey,
|
||||
this::buildSelectQueryPlan
|
||||
);
|
||||
}
|
||||
|
||||
if ( queryPlan == null ) {
|
||||
queryPlan = buildSelectQueryPlan();
|
||||
if ( cacheKey != null ) {
|
||||
getSession().getFactory().getQueryEngine().getInterpretationCache().cacheSelectQueryPlan( cacheKey, queryPlan );
|
||||
}
|
||||
else {
|
||||
return buildSelectQueryPlan();
|
||||
}
|
||||
|
||||
return queryPlan;
|
||||
}
|
||||
|
||||
private SelectQueryPlan<R> buildSelectQueryPlan() {
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.mapping.Bindable;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
|
@ -81,7 +82,10 @@ public class SqmUtil {
|
|||
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 :
|
||||
domainParameterXref.getSqmParamByQueryParam().entrySet() ) {
|
||||
|
|
|
@ -276,7 +276,7 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
|
||||
@Override
|
||||
public QuerySpec visitQuerySpec(SqmQuerySpec sqmQuerySpec) {
|
||||
final QuerySpec sqlQuerySpec = new QuerySpec( processingStateStack.isEmpty() );
|
||||
final QuerySpec sqlQuerySpec = new QuerySpec( processingStateStack.isEmpty(), sqmQuerySpec.getFromClause().getNumberOfRoots() );
|
||||
|
||||
processingStateStack.push(
|
||||
new SqlAstQuerySpecProcessingStateImpl(
|
||||
|
@ -737,12 +737,12 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
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 MappingModelExpressable valueMapping = getCreationContext().getDomainModel().resolveMappingExpressable( nodeType );
|
||||
|
||||
|
@ -763,7 +763,7 @@ public abstract class BaseSqmToSqlAstConverter
|
|||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
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 QueryParameterBinding<?> binding = domainParameterBindings.getBinding( queryParameter );
|
||||
|
|
|
@ -12,8 +12,6 @@ import org.hibernate.NotYetImplementedFor6Exception;
|
|||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
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.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.sql.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
@ -21,6 +20,7 @@ import org.hibernate.engine.profile.FetchProfile;
|
|||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.graph.spi.AttributeNodeImplementor;
|
||||
import org.hibernate.graph.spi.GraphImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
@ -71,7 +71,8 @@ public class StandardSqmSelectToSqlAstConverter
|
|||
private final LoadQueryInfluencers fetchInfluencers;
|
||||
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;
|
||||
|
||||
|
@ -154,29 +155,33 @@ public class StandardSqmSelectToSqlAstConverter
|
|||
|
||||
@Override
|
||||
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 -> {
|
||||
final Fetch biDirectionalFetch = circularFetchDetector.findBiDirectionalFetch(
|
||||
fetchParent,
|
||||
fetchable
|
||||
);
|
||||
//noinspection Convert2Lambda
|
||||
final Consumer<Fetchable> fetchableConsumer = new Consumer<Fetchable>() {
|
||||
@Override
|
||||
public void accept(Fetchable fetchable) {
|
||||
final Fetch biDirectionalFetch = circularFetchDetector.findBiDirectionalFetch(
|
||||
fetchParent,
|
||||
fetchable
|
||||
);
|
||||
|
||||
if ( biDirectionalFetch != null ) {
|
||||
fetches.add( biDirectionalFetch );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
fetchDepth++;
|
||||
final Fetch fetch = buildFetch( fetchParent, fetchable );
|
||||
|
||||
if ( fetch != null ) {
|
||||
fetches.add( fetch );
|
||||
if ( biDirectionalFetch != null ) {
|
||||
fetches.add( biDirectionalFetch );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
fetchDepth++;
|
||||
final Fetch fetch = buildFetch( fetchParent, fetchable );
|
||||
|
||||
if ( fetch != null ) {
|
||||
fetches.add( fetch );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
fetchDepth--;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
fetchDepth--;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -297,6 +302,7 @@ public class StandardSqmSelectToSqlAstConverter
|
|||
try {
|
||||
return fetchable.generateFetch(
|
||||
fetchParent,
|
||||
fetchablePath,
|
||||
fetchTiming,
|
||||
joined,
|
||||
lockMode,
|
||||
|
|
|
@ -328,6 +328,6 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + '(' + navigablePath.getFullPath() + ')';
|
||||
return getClass().getSimpleName() + "(" + navigablePath.getFullPath() + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,12 +64,12 @@ public class SqmEmbeddedValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
|
|||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
|
||||
|
@ -19,9 +20,14 @@ import org.hibernate.sql.ast.tree.SqlAstNode;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class FromClause implements SqlAstNode {
|
||||
private final List<TableGroup> roots = new ArrayList<>();
|
||||
private final List<TableGroup> roots;
|
||||
|
||||
public FromClause() {
|
||||
roots = new ArrayList<>();
|
||||
}
|
||||
|
||||
public FromClause(int expectedNumberOfRoots) {
|
||||
roots = CollectionHelper.arrayList( expectedNumberOfRoots );
|
||||
}
|
||||
|
||||
public List<TableGroup> getRoots() {
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.hibernate.sql.ast.tree.predicate.PredicateContainer;
|
|||
public class QuerySpec implements SqlAstNode, PredicateContainer {
|
||||
private final boolean isRoot;
|
||||
|
||||
private final FromClause fromClause = new FromClause();
|
||||
private final FromClause fromClause;
|
||||
private final SelectClause selectClause = new SelectClause();
|
||||
|
||||
private Predicate whereClauseRestrictions;
|
||||
|
@ -34,6 +34,12 @@ public class QuerySpec implements SqlAstNode, PredicateContainer {
|
|||
|
||||
public QuerySpec(boolean isRoot) {
|
||||
this.isRoot = isRoot;
|
||||
this.fromClause = new FromClause();
|
||||
}
|
||||
|
||||
public QuerySpec(boolean isRoot, int expectedNumberOfRoots) {
|
||||
this.isRoot = isRoot;
|
||||
this.fromClause = new FromClause( expectedNumberOfRoots );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -99,6 +99,7 @@ public class RootBiDirectionalFetchImpl implements BiDirectionalFetch, Fetchable
|
|||
@Override
|
||||
public Fetch generateFetch(
|
||||
FetchParent fetchParent,
|
||||
NavigablePath fetchablePath,
|
||||
FetchTiming fetchTiming,
|
||||
boolean selected,
|
||||
LockMode lockMode,
|
||||
|
|
|
@ -39,13 +39,14 @@ public class BasicFetch<T> implements Fetch, BasicResultMappingNode<T> {
|
|||
public BasicFetch(
|
||||
int valuesArrayPosition,
|
||||
FetchParent fetchParent,
|
||||
NavigablePath fetchablePath,
|
||||
BasicValuedModelPart valuedMapping,
|
||||
boolean nullable,
|
||||
BasicValueConverter valueConverter,
|
||||
FetchTiming fetchTiming,
|
||||
DomainResultCreationState creationState) {
|
||||
this.nullable = nullable;
|
||||
this.navigablePath = fetchParent.getNavigablePath().append( valuedMapping.getFetchableName() );
|
||||
this.navigablePath = fetchablePath;
|
||||
|
||||
this.fetchParent = fetchParent;
|
||||
this.valuedMapping = valuedMapping;
|
||||
|
|
|
@ -10,6 +10,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
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.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
|
@ -34,7 +36,7 @@ public abstract class AbstractEntityResultNode extends AbstractFetchParent imple
|
|||
|
||||
private final EntityMappingType targetType;
|
||||
|
||||
private final List<DomainResult> attributeDomainResults = new ArrayList<>();
|
||||
private final List<DomainResult> attributeDomainResults;
|
||||
|
||||
public AbstractEntityResultNode(
|
||||
EntityValuedModelPart referencedModelPart,
|
||||
|
@ -92,18 +94,20 @@ public abstract class AbstractEntityResultNode extends AbstractFetchParent imple
|
|||
);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
attributeDomainResults = CollectionHelper.arrayList( entityDescriptor.getNumberOfAttributeMappings() );
|
||||
|
||||
entityDescriptor.visitAttributeMappings(
|
||||
mapping -> attributeDomainResults.add(
|
||||
mapping.createDomainResult(
|
||||
navigablePath.append( mapping.getAttributeName() ),
|
||||
entityTableGroup,
|
||||
null,
|
||||
creationState
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -37,7 +37,7 @@ public interface DomainResultCreationState {
|
|||
* BiFunction<FetchParent,Fetchable,LockMode> lockModeResolver)
|
||||
*
|
||||
* [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
|
||||
* 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
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -26,6 +27,7 @@ public interface Fetchable extends ModelPart {
|
|||
|
||||
Fetch generateFetch(
|
||||
FetchParent fetchParent,
|
||||
NavigablePath fetchablePath,
|
||||
FetchTiming fetchTiming,
|
||||
boolean selected,
|
||||
LockMode lockMode,
|
||||
|
|
|
@ -11,15 +11,12 @@ import java.util.Map;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
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.java.AbstractTypeDescriptor;
|
||||
import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor;
|
||||
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.SqlTypeDescriptorIndicators;
|
||||
import org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.type.spi.TypeConfigurationAware;
|
||||
|
||||
|
@ -74,19 +71,34 @@ public class JavaTypeDescriptorRegistry implements JavaTypeDescriptorBaseline.Ba
|
|||
// descriptor access
|
||||
|
||||
public <T> JavaTypeDescriptor<T> getDescriptor(Class<T> javaType) {
|
||||
return RegistryHelper.INSTANCE.resolveDescriptor(
|
||||
descriptorsByClass,
|
||||
javaType,
|
||||
() -> {
|
||||
log.debugf(
|
||||
"Could not find matching scoped JavaTypeDescriptor for requested Java class [%s]; " +
|
||||
"falling back to static registry",
|
||||
javaType.getName()
|
||||
);
|
||||
|
||||
return org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry.INSTANCE.getDescriptor( javaType );
|
||||
}
|
||||
);
|
||||
return resolveDescriptor( javaType );
|
||||
// return RegistryHelper.INSTANCE.resolveDescriptor(
|
||||
// descriptorsByClass,
|
||||
// javaType,
|
||||
// () -> {
|
||||
// log.debugf(
|
||||
// "Could not find matching scoped JavaTypeDescriptor for requested Java class [%s]; " +
|
||||
// "falling back to static registry",
|
||||
// javaType.getName()
|
||||
// );
|
||||
//
|
||||
// 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) {
|
||||
|
@ -103,15 +115,15 @@ public class JavaTypeDescriptorRegistry implements JavaTypeDescriptorBaseline.Ba
|
|||
}
|
||||
|
||||
public <J> JavaTypeDescriptor<J> resolveDescriptor(Class<J> javaType, Supplier<JavaTypeDescriptor<J>> creator) {
|
||||
//noinspection unchecked
|
||||
return descriptorsByClass.computeIfAbsent(
|
||||
javaType,
|
||||
jt -> {
|
||||
final JavaTypeDescriptor<J> jtd = creator.get();
|
||||
performInjections( jtd );
|
||||
return jtd;
|
||||
}
|
||||
);
|
||||
final JavaTypeDescriptor cached = descriptorsByClass.get( javaType );
|
||||
if ( cached != null ) {
|
||||
//noinspection unchecked
|
||||
return cached;
|
||||
}
|
||||
|
||||
final JavaTypeDescriptor<J> created = creator.get();
|
||||
descriptorsByClass.put( javaType, created );
|
||||
return created;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -126,7 +138,7 @@ public class JavaTypeDescriptorRegistry implements JavaTypeDescriptorBaseline.Ba
|
|||
fallbackDescriptor = new EnumJavaTypeDescriptor( javaType );
|
||||
}
|
||||
else if ( Serializable.class.isAssignableFrom( javaType ) ) {
|
||||
fallbackDescriptor = new OnTheFlySerializableJavaDescriptor( javaType );
|
||||
fallbackDescriptor = new SerializableTypeDescriptor( javaType );
|
||||
}
|
||||
else {
|
||||
fallbackDescriptor = new JavaTypeDescriptorBasicAdaptor( javaType );
|
||||
|
@ -146,7 +158,7 @@ public class JavaTypeDescriptorRegistry implements JavaTypeDescriptorBaseline.Ba
|
|||
return new DynamicJtd();
|
||||
}
|
||||
|
||||
private class DynamicJtd implements JavaTypeDescriptor<Map> {
|
||||
private static class DynamicJtd implements JavaTypeDescriptor<Map> {
|
||||
@Override
|
||||
public SqlTypeDescriptor getJdbcRecommendedSqlType(SqlTypeDescriptorIndicators context) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -172,64 +184,4 @@ public class JavaTypeDescriptorRegistry implements JavaTypeDescriptorBaseline.Ba
|
|||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue