Skip to content

HHH-15133 - Use specified result-type to better infer "shape" of query results with implicit selections #4890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2447,7 +2447,7 @@ public void test_hql_relational_comparisons_example_7() {
Object[].class)
.getResultList();
//end::hql-relational-comparisons-example[]
assertEquals(2, phonePayments.size());
assertEquals(3, phonePayments.size());
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,10 @@ public QueryImplementor createQuery(String queryString) {

@Override
public SelectionQuery<?> createSelectionQuery(String hqlString) {
return internalCreateSelectionQuery( hqlString, null );
}

private <R> SelectionQuery<R> internalCreateSelectionQuery(String hqlString, Class<R> expectedResultType) {
checkOpen();
pulseTransactionCoordinator();
delayedAfterCompletion();
Expand All @@ -667,19 +671,40 @@ public SelectionQuery<?> createSelectionQuery(String hqlString) {
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation(
hqlString,
s -> queryEngine.getHqlTranslator().translate( hqlString )
expectedResultType,
(s) -> queryEngine.getHqlTranslator().translate( hqlString, expectedResultType )
);

if ( !( hqlInterpretation.getSqmStatement() instanceof SqmSelectStatement ) ) {
throw new IllegalSelectQueryException( "Expecting a selection query, but found `" + hqlString + "`", hqlString );
}

final SqmSelectionQuery<?> query = new SqmSelectionQueryImpl<>( hqlString, hqlInterpretation, this );
query.setComment( hqlString );
final SqmSelectionQueryImpl<?> query = new SqmSelectionQueryImpl<>(
hqlString,
hqlInterpretation,
expectedResultType,
this
);

if ( expectedResultType != null ) {
final Class<?> resultType = query.getResultType();
if ( ! expectedResultType.isAssignableFrom( resultType ) ) {
throw new QueryTypeMismatchException(
String.format(
Locale.ROOT,
"Query result-type error - expecting `%s`, but found `%s`",
expectedResultType.getName(),
resultType.getName()
)
);
}
}

query.setComment( hqlString );
applyQuerySettingsAndHints( query );

return query;
//noinspection unchecked
return (SelectionQuery<R>) query;
}
catch (RuntimeException e) {
markForRollbackOnly();
Expand All @@ -689,32 +714,17 @@ public SelectionQuery<?> createSelectionQuery(String hqlString) {

@Override
public <R> SelectionQuery<R> createSelectionQuery(String hqlString, Class<R> expectedResultType) {
final SelectionQuery<?> selectQuery = createSelectionQuery( hqlString );
//noinspection unchecked
final Class<?> resultType = ( (SqmSelectionQueryImpl<R>) selectQuery ).getResultType();
if ( resultType == null || expectedResultType.isAssignableFrom( resultType ) ) {
//noinspection unchecked
return (SelectionQuery<R>) selectQuery;
}

throw new QueryTypeMismatchException(
String.format(
Locale.ROOT,
"Query result-type error - expecting `%s`, but found `%s`",
expectedResultType.getName(),
resultType.getName()
)
);
return internalCreateSelectionQuery( hqlString, expectedResultType );
}

@Override
public <R> SelectionQuery<R> createSelectionQuery(CriteriaQuery<R> criteria) {
SqmUtil.verifyIsSelectStatement( (SqmStatement<?>) criteria, null );
return new SqmSelectionQueryImpl<>( (SqmSelectStatement<R>) criteria, this );
return new SqmSelectionQueryImpl<>( (SqmSelectStatement<R>) criteria, criteria.getResultType(), this );
}

@Override
public <T> QueryImplementor<T> createQuery(String queryString, Class<T> resultClass) {
public <T> QueryImplementor<T> createQuery(String queryString, Class<T> expectedResultType) {
checkOpen();
pulseTransactionCoordinator();
delayedAfterCompletion();
Expand All @@ -727,9 +737,10 @@ public <T> QueryImplementor<T> createQuery(String queryString, Class<T> resultCl
queryString,
interpretationCache.resolveHqlInterpretation(
queryString,
s -> queryEngine.getHqlTranslator().translate( queryString )
expectedResultType,
s -> queryEngine.getHqlTranslator().translate( queryString, expectedResultType )
),
resultClass,
expectedResultType,
this
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,26 @@
import jakarta.persistence.TupleElement;

import org.hibernate.HibernateException;
import org.hibernate.query.TypedTupleTransformer;
import org.hibernate.transform.ResultTransformer;

/**
* ResultTransformer adapter for handling Tuple results from Native queries
*
* @author Arnold Galovics
*/
public class NativeQueryTupleTransformer implements ResultTransformer<Tuple> {
public class NativeQueryTupleTransformer implements ResultTransformer<Tuple>, TypedTupleTransformer<Tuple> {

@Override
public Tuple transformTuple(Object[] tuple, String[] aliases) {
return new NativeTupleImpl( tuple, aliases );
}

@Override
public Class<Tuple> getTransformedType() {
return Tuple.class;
}

private static class NativeTupleElementImpl<X> implements TupleElement<X> {

private final Class<? extends X> javaType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;

/**
Expand Down Expand Up @@ -171,7 +171,7 @@ public Callback getCallback() {
}

},
RowTransformerPassThruImpl.instance(),
RowTransformerStandardImpl.instance(),
ListResultsConsumer.UniqueSemantic.FILTER
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;

import org.jboss.logging.Logger;
Expand Down Expand Up @@ -233,7 +233,7 @@ public Callback getCallback() {
}

},
RowTransformerPassThruImpl.instance(),
RowTransformerStandardImpl.instance(),
ListResultsConsumer.UniqueSemantic.FILTER
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;

/**
Expand Down Expand Up @@ -158,7 +158,7 @@ public Callback getCallback() {
}

},
RowTransformerPassThruImpl.instance(),
RowTransformerStandardImpl.instance(),
ListResultsConsumer.UniqueSemantic.FILTER
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
import org.hibernate.sql.results.internal.ResultsHelper;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;

/**
Expand Down Expand Up @@ -159,7 +159,7 @@ public Callback getCallback() {
}

},
RowTransformerPassThruImpl.instance(),
RowTransformerStandardImpl.instance(),
ListResultsConsumer.UniqueSemantic.FILTER
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,11 @@ public ResultListTransformer getResultListTransformer() {
return null;
}

@Override
public Boolean isDeDuplicationEnabled() {
return false;
}

@Override
public Boolean isResultCachingEnabled() {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;

import org.jboss.logging.Logger;
Expand Down Expand Up @@ -332,7 +332,7 @@ public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry e
}
}
},
RowTransformerPassThruImpl.instance(),
RowTransformerStandardImpl.instance(),
ListResultsConsumer.UniqueSemantic.FILTER
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;

/**
Expand Down Expand Up @@ -198,7 +198,7 @@ public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry e
}
}
},
RowTransformerPassThruImpl.instance(),
RowTransformerStandardImpl.instance(),
ListResultsConsumer.UniqueSemantic.FILTER
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;

import org.jboss.logging.Logger;
Expand Down Expand Up @@ -152,7 +152,7 @@ public T load(
session,
subSelectFetchableKeysHandler
),
RowTransformerPassThruImpl.instance(),
RowTransformerStandardImpl.instance(),
ListResultsConsumer.UniqueSemantic.FILTER
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.sql.results.spi.RowTransformer;

Expand Down Expand Up @@ -92,7 +92,7 @@ public JdbcSelect getJdbcSelect() {
}

protected RowTransformer<T> getRowTransformer() {
return RowTransformerPassThruImpl.instance();
return RowTransformerStandardImpl.instance();
}

public T load(Object restrictedValue, SharedSessionContractImplementor session) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* 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;

/**
* Extension to TupleTransformer exposing the transformation target type.
*
* @apiNote This is mainly intended for use in equality checking while applying
* result de-duplication for queries.
*
* @author Steve Ebersole
*/
public interface TypedTupleTransformer<T> extends TupleTransformer<T> {
/**
* The type resulting from this transformation
*/
Class<T> getTransformedType();
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ public interface HqlTranslator {
* Performs the interpretation of a HQL/JPQL query string to SQM.
*
* @param hql The HQL/JPQL query string to interpret
* @param expectedResultType The type specified when creating the query
*
* @return The semantic representation of the incoming query.
*/
<R> SqmStatement<R> translate(String hql);
<R> SqmStatement<R> translate(String hql, Class<R> expectedResultType);

/**
* Give the translator a chance to "shut down" if it needs to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public NamedSqmQueryMemento makeCopy(String name) {

@Override
public void validate(QueryEngine queryEngine) {
queryEngine.getHqlTranslator().translate( hqlString );
queryEngine.getHqlTranslator().translate( hqlString, null );
}

@Override
Expand Down
Loading