Re-enable more tests.

* Make sure subselect fetch registrations are per navigable path
* Consider the result class for native queries
* Fix issues with nested property references
* Fix list expansion issues for native queries
This commit is contained in:
Christian Beikov 2022-02-17 19:01:21 +01:00
parent 40bcb97232
commit 73e9859fea
24 changed files with 88 additions and 59 deletions

View File

@ -6,16 +6,20 @@
*/
package org.hibernate.engine.spi;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.query.spi.NavigablePath;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
/**
* Encapsulates details related to entities which contain sub-select-fetchable
@ -97,16 +101,14 @@ public class SubselectFetch {
TableGroup tableGroup,
List<JdbcParameter> jdbcParameters,
JdbcParameterBindings jdbcParameterBindings) {
final SubselectFetch subselectFetch = new SubselectFetch(
null,
return new StandardRegistrationHandler(
batchFetchQueue,
sqlAst.getQuerySpec(),
tableGroup,
jdbcParameters,
jdbcParameterBindings,
new HashSet<>()
jdbcParameterBindings
);
return new StandardRegistrationHandler( batchFetchQueue, subselectFetch );
}
public static RegistrationHandler createRegistrationHandler(
@ -124,25 +126,48 @@ public class SubselectFetch {
}
public interface RegistrationHandler {
void addKey(EntityKey key);
void addKey(EntityKey key, LoadingEntityEntry entry);
}
private static final RegistrationHandler NO_OP_REG_HANDLER = new RegistrationHandler() {
@Override
public void addKey(EntityKey key) {
public void addKey(EntityKey key, LoadingEntityEntry entry) {
}
} ;
public static class StandardRegistrationHandler implements RegistrationHandler {
private final BatchFetchQueue batchFetchQueue;
private final SubselectFetch subselectFetch;
private final QuerySpec loadingSqlAst;
private final TableGroup ownerTableGroup;
private final List<JdbcParameter> loadingJdbcParameters;
private final JdbcParameterBindings loadingJdbcParameterBindings;
private final Map<NavigablePath, SubselectFetch> subselectFetches = new HashMap<>();
private StandardRegistrationHandler(BatchFetchQueue batchFetchQueue, SubselectFetch subselectFetch) {
private StandardRegistrationHandler(
BatchFetchQueue batchFetchQueue,
QuerySpec loadingSqlAst,
TableGroup ownerTableGroup,
List<JdbcParameter> loadingJdbcParameters,
JdbcParameterBindings loadingJdbcParameterBindings) {
this.batchFetchQueue = batchFetchQueue;
this.subselectFetch = subselectFetch;
this.loadingSqlAst = loadingSqlAst;
this.ownerTableGroup = ownerTableGroup;
this.loadingJdbcParameters = loadingJdbcParameters;
this.loadingJdbcParameterBindings = loadingJdbcParameterBindings;
}
public void addKey(EntityKey key) {
public void addKey(EntityKey key, LoadingEntityEntry entry) {
final SubselectFetch subselectFetch = subselectFetches.computeIfAbsent(
entry.getEntityInitializer().getNavigablePath(),
navigablePath -> new SubselectFetch(
null,
loadingSqlAst,
ownerTableGroup,
loadingJdbcParameters,
loadingJdbcParameterBindings,
new HashSet<>()
)
);
subselectFetch.resultingEntityKeys.add( key );
batchFetchQueue.addSubselect( key, subselectFetch );
}

View File

@ -757,7 +757,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
// dynamic native (SQL) query handling
@Override @SuppressWarnings("rawtypes")
public NativeQueryImplementor createNativeQuery(String sqlString) {
public NativeQueryImpl createNativeQuery(String sqlString) {
checkOpen();
pulseTransactionCoordinator();
delayedAfterCompletion();
@ -808,13 +808,16 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
//note: we're doing something a bit funny here to work around
// the clashing signatures declared by the supertypes
public NativeQueryImplementor createNativeQuery(String sqlString, Class resultClass) {
NativeQueryImplementor query = createNativeQuery( sqlString );
NativeQueryImpl query = createNativeQuery( sqlString );
if ( Tuple.class.equals(resultClass) ) {
query.setTupleTransformer( new NativeQueryTupleTransformer() );
}
else if ( getFactory().getMappingMetamodel().isEntityClass(resultClass) ) {
query.addEntity( "alias1", resultClass.getName(), LockMode.READ );
}
else {
query.addScalar( 1, resultClass );
}
return query;
}

View File

@ -219,7 +219,7 @@ public class CollectionLoaderBatchKey implements CollectionLoader {
@Override
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
subSelectFetchableKeysHandler.addKey( entityKey );
subSelectFetchableKeysHandler.addKey( entityKey, entry );
}
@Override

View File

@ -134,7 +134,7 @@ public class CollectionLoaderSingleKey implements CollectionLoader {
@Override
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
subSelectFetchableKeysHandler.addKey( entityKey );
subSelectFetchableKeysHandler.addKey( entityKey, entry );
}
@Override

View File

@ -145,7 +145,7 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader {
@Override
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
subSelectFetchableKeysHandler.addKey( entityKey );
subSelectFetchableKeysHandler.addKey( entityKey, entry );
}
@Override

View File

@ -328,7 +328,7 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
@Override
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
if ( subSelectFetchableKeysHandler != null ) {
subSelectFetchableKeysHandler.addKey( entityKey );
subSelectFetchableKeysHandler.addKey( entityKey, entry );
}
}
},

View File

@ -194,7 +194,7 @@ public class MultiNaturalIdLoadingBatcher {
@Override
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
if ( subSelectFetchableKeysHandler != null ) {
subSelectFetchableKeysHandler.addKey( entityKey );
subSelectFetchableKeysHandler.addKey( entityKey, entry );
}
}
},

View File

@ -214,7 +214,7 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
@Override
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
subSelectFetchableKeysHandler.addKey( entityKey );
subSelectFetchableKeysHandler.addKey( entityKey, entry );
}
@Override

View File

@ -199,6 +199,9 @@ public abstract class SimpleValue implements KeyValue {
}
public void sortColumns(int[] originalOrder) {
if ( columns.size() == 1 ) {
return;
}
final Selectable[] originalColumns = columns.toArray(new Selectable[0]);
final boolean[] originalInsertability = ArrayHelper.toBooleanArray( insertability );
final boolean[] originalUpdatability = ArrayHelper.toBooleanArray( updatability );

View File

@ -170,7 +170,7 @@ public abstract class ToOne extends SimpleValue implements Fetchable, SortableVa
value = entityBinding.getIdentifier();
}
else {
value = entityBinding.getProperty( getReferencedPropertyName() ).getValue();
value = entityBinding.getRecursiveProperty( getReferencedPropertyName() ).getValue();
}
if ( value instanceof Component ) {
final Component component = (Component) value;

View File

@ -163,7 +163,7 @@ public class EntityCollectionPart
this.targetKeyPropertyNames = targetKeyPropertyNames;
}
else {
final Type propertyType = entityBinding.getProperty( referencedPropertyName ).getType();
final Type propertyType = entityBinding.getRecursiveProperty( referencedPropertyName ).getType();
final CompositeType compositeType;
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
&& compositeType.getPropertyNames().length == 1 ) {

View File

@ -950,7 +950,7 @@ public class MappingModelCreationHelper {
);
}
final ModelPart modelPart = referencedEntityDescriptor.findSubPart( referencedPropertyName );
final ModelPart modelPart = referencedEntityDescriptor.findByPath( referencedPropertyName );
if ( modelPart instanceof ToOneAttributeMapping ) {
setReferencedAttributeForeignKeyDescriptor(
attributeMapping,
@ -991,7 +991,7 @@ public class MappingModelCreationHelper {
fkTarget = referencedEntityDescriptor.getIdentifierMapping();
}
else {
fkTarget = referencedEntityDescriptor.findAttributeMapping( bootValueMapping.getReferencedPropertyName() );
fkTarget = referencedEntityDescriptor.findByPath( bootValueMapping.getReferencedPropertyName() );
}
if ( fkTarget instanceof BasicValuedModelPart ) {
@ -1277,7 +1277,7 @@ public class MappingModelCreationHelper {
.getBootModel()
.getEntityBinding(
referencedEntityDescriptor.getEntityName() );
Property property = entityBinding.getProperty( referencedPropertyName );
Property property = entityBinding.getRecursiveProperty( referencedPropertyName );
interpretToOneKeyDescriptor(
referencedAttributeMapping,
property,

View File

@ -417,7 +417,7 @@ public class ToOneAttributeMapping
else {
final PersistentClass entityBinding = bootValue.getBuildingContext().getMetadataCollector()
.getEntityBinding( entityMappingType.getEntityName() );
final Type propertyType = entityBinding.getProperty( referencedPropertyName ).getType();
final Type propertyType = entityBinding.getRecursiveProperty( referencedPropertyName ).getType();
final CompositeType compositeType;
if ( propertyType.isComponentType() && ( compositeType = (CompositeType) propertyType ).isEmbedded()
&& compositeType.getPropertyNames().length == 1 ) {

View File

@ -40,7 +40,7 @@ public class QueryParameterNamedImpl<T> extends AbstractQueryParameter<T> {
public static <T> QueryParameterNamedImpl<T> fromNativeQuery(String name) {
return new QueryParameterNamedImpl<>(
name,
false,
true,
null
);
}

View File

@ -44,7 +44,7 @@ public class QueryParameterPositionalImpl<T> extends AbstractQueryParameter<T> {
public static <T> QueryParameterPositionalImpl<T> fromNativeQuery(int position) {
return new QueryParameterPositionalImpl<>(
position,
false,
true,
null
);
}

View File

@ -50,13 +50,19 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
final Function<String, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver();
ForeignKeyDescriptor foreignKeyDescriptor = fetchable.getForeignKeyDescriptor();
final String associationKeyPropertyName;
final NavigablePath associationKeyFetchPath;
if ( fetchable.getReferencedPropertyName() == null ) {
associationKeyPropertyName = fetchable.getEntityMappingType().getIdentifierMapping().getPartName();
associationKeyFetchPath = relativePath.append( associationKeyPropertyName );
}
else {
associationKeyPropertyName = fetchable.getReferencedPropertyName();
NavigablePath path = relativePath;
for ( String part : associationKeyPropertyName.split( "\\." ) ) {
path = path.append( part );
}
associationKeyFetchPath = path;
}
final NavigablePath associationKeyFetchPath = relativePath.append( associationKeyPropertyName );
final FetchBuilder explicitAssociationKeyFetchBuilder = fetchBuilderResolver
.apply( associationKeyFetchPath.getFullPath() );
final Map<NavigablePath, FetchBuilder> fetchBuilders;

View File

@ -850,9 +850,9 @@ public abstract class AbstractCommonQueryContract implements CommonQueryContract
if ( param.allowsMultiValuedBinding() ) {
final BindableType<?> hibernateType = param.getHibernateType();
if ( hibernateType == null || isInstance( hibernateType, value ) ) {
if ( value instanceof Collection ) {
if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) {
//noinspection rawtypes
setParameterList( name, (Collection) value );
return setParameterList( name, (Collection) value );
}
}
}
@ -939,9 +939,9 @@ public abstract class AbstractCommonQueryContract implements CommonQueryContract
if ( param.allowsMultiValuedBinding() ) {
final BindableType<?> hibernateType = param.getHibernateType();
if ( hibernateType == null || isInstance( hibernateType, value ) ) {
if ( value instanceof Collection ) {
if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) {
//noinspection rawtypes,unchecked
setParameterList( param, (Collection) value );
return setParameterList( param, (Collection) value );
}
}
}
@ -950,6 +950,10 @@ public abstract class AbstractCommonQueryContract implements CommonQueryContract
return this;
}
private boolean isRegisteredAsBasicType(Class<?> valueClass) {
return getSession().getTypeConfiguration().getBasicTypeForJavaType( valueClass ) != null;
}
@Override
public <P> CommonQueryContract setParameter(int position, P value, Class<P> javaType) {
final JavaType<P> javaDescriptor = getSession().getFactory()

View File

@ -851,6 +851,15 @@ public class NativeQueryImpl<R>
return registerBuilder( Builders.scalar( columnAlias ) );
}
public NativeQueryImplementor<R> addScalar(int position, Class<?> type) {
return registerBuilder(
Builders.scalar(
position,
getSessionFactory().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( type )
)
);
}
protected NativeQueryImplementor<R> registerBuilder(ResultBuilder builder) {
resultSetMapping.addResultBuilder( builder );
return this;

View File

@ -8,7 +8,6 @@ package org.hibernate.query.sqm.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@ -25,7 +24,6 @@ import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.query.IllegalQueryOperationException;
import org.hibernate.query.TupleTransformer;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.spi.DomainQueryExecutionContext;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryOptions;
@ -57,10 +55,6 @@ import org.hibernate.sql.results.internal.TupleMetadata;
import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.sql.results.spi.RowTransformer;
import jakarta.persistence.Tuple;
import jakarta.persistence.TupleElement;
import jakarta.persistence.criteria.CompoundSelection;
import static org.hibernate.query.sqm.internal.QuerySqmImpl.CRITERIA_HQL_STRING;
/**
@ -112,7 +106,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
new SqmJdbcExecutionContextAdapter( executionContext, jdbcSelect ) {
@Override
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
subSelectFetchKeyHandler.addKey( entityKey );
subSelectFetchKeyHandler.addKey( entityKey, entry );
}
@Override

View File

@ -43,7 +43,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jdbc.SQLStatementInspector;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.NotImplementedYet;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
@ -191,7 +190,6 @@ public class SubselectFetchCollectionFromBatchTest {
@Test
@TestForIssue( jiraKey = "HHH-10679")
@NotImplementedYet( strict = false, reason = "Need to check why this fails" )
public void testMultiSubselectFetchSamePersisterQueryList(SessionFactoryScope scope) {
final Long[] createdIds = scope.fromTransaction( (s) -> {
EmployeeGroup group1 = new EmployeeGroup();

View File

@ -17,6 +17,7 @@
<hibernate-mapping package="org.hibernate.orm.test.propertyref.partial">
<class name="Person" table="PART_COMP_PROPREF_PERS">
<cache usage="nonstrict-read-write"/>
<id name="id">
<generator class="increment"/>
</id>
@ -27,6 +28,7 @@
</class>
<class name="Account" table="PART_COMP_PROPREF_ACCT">
<cache usage="nonstrict-read-write"/>
<id name="number" column="accnum"/>
<many-to-one name="owner" property-ref="identity.ssn"/>
</class>

View File

@ -9,14 +9,10 @@ package org.hibernate.orm.test.propertyref.partial;
import org.hibernate.Hibernate;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.NotImplementedYet;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.Test;
import static org.hibernate.cfg.AvailableSettings.DEFAULT_CACHE_CONCURRENCY_STRATEGY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -26,14 +22,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author Gavin King
*/
@ServiceRegistry( settings = @Setting( name = DEFAULT_CACHE_CONCURRENCY_STRATEGY, value = "nonstrict-read-write" ) )
@DomainModel( xmlMappings = "org/hibernate/orm/test/propertyref/partial/Mapping.hbm.xml" )
@SessionFactory
@NotImplementedYet( strict = false )
public class PartialComponentPropertyRefTest {
// need to simply comment this out as the failure here occurs while building the SF which is the fixture
// @Test
@Test
public void testComponentPropertyRef(SessionFactoryScope scope) {
scope.inTransaction( (s) -> {
Person p = new Person();

View File

@ -18,7 +18,6 @@ import org.hibernate.query.Query;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.NotImplementedYet;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
@ -36,11 +35,6 @@ import static org.assertj.core.api.Assertions.assertThat;
public class NativeQueryScrollableResultsTests {
@Test
@NotImplementedYet(
strict = false,
reason = "java.lang.NullPointerException\n" +
"\tat org.hibernate.sql.exec.internal.AbstractJdbcParameter.bindParameterValue(AbstractJdbcParameter.java:102)"
)
public void testSetParameters(SessionFactoryScope scope) {
scope.inTransaction( (s) -> {
final List<BigInteger> params = new ArrayList<>();

View File

@ -14,7 +14,6 @@ import org.hibernate.transform.ResultTransformer;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.NotImplementedYet;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
@ -33,7 +32,6 @@ public class ResultTransformerTest {
@Test
@JiraKey( "HHH-3694" )
@NotImplementedYet( strict = false, reason = "More problems with hbm.xml sql resultset mappings" )
public void testResultTransformerIsAppliedToScrollableResults(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
final PartnerA a = new PartnerA();
@ -58,7 +56,7 @@ public class ResultTransformerTest {
q.setResultTransformer(
(ResultTransformer) (arg0, arg1) -> {
// return only the PartnerA object from the query
return arg0[1];
return ( (Contract) arg0[0] ).getA();
}
);