HHH-15133 - Use specified result-type to better infer "shape" of query results with implicit selections
This commit is contained in:
parent
cb4691e98e
commit
cac18ae0c7
|
@ -658,6 +658,10 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
|
||||
@Override
|
||||
public SelectionQuery<?> createSelectionQuery(String hqlString) {
|
||||
return internalCreateSelectionQuery( hqlString, null );
|
||||
}
|
||||
|
||||
private <R> SelectionQuery<R> internalCreateSelectionQuery(String hqlString, Class<R> expectedResultType) {
|
||||
checkOpen();
|
||||
pulseTransactionCoordinator();
|
||||
delayedAfterCompletion();
|
||||
|
@ -667,19 +671,40 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
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();
|
||||
|
@ -689,32 +714,17 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
|
||||
@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();
|
||||
|
@ -727,9 +737,10 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
queryString,
|
||||
interpretationCache.resolveHqlInterpretation(
|
||||
queryString,
|
||||
s -> queryEngine.getHqlTranslator().translate( queryString )
|
||||
expectedResultType,
|
||||
s -> queryEngine.getHqlTranslator().translate( queryString, expectedResultType )
|
||||
),
|
||||
resultClass,
|
||||
expectedResultType,
|
||||
this
|
||||
);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.hibernate.sql.exec.spi.Callback;
|
|||
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;
|
||||
|
||||
/**
|
||||
|
@ -171,7 +171,7 @@ public class CollectionElementLoaderByIndex implements Loader {
|
|||
}
|
||||
|
||||
},
|
||||
RowTransformerPassThruImpl.instance(),
|
||||
RowTransformerStandardImpl.instance(),
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
||||
|
|
|
@ -35,7 +35,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.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;
|
||||
|
@ -233,7 +233,7 @@ public class CollectionLoaderBatchKey implements CollectionLoader {
|
|||
}
|
||||
|
||||
},
|
||||
RowTransformerPassThruImpl.instance(),
|
||||
RowTransformerStandardImpl.instance(),
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
||||
|
|
|
@ -33,7 +33,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.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
|
||||
/**
|
||||
|
@ -158,7 +158,7 @@ public class CollectionLoaderSingleKey implements CollectionLoader {
|
|||
}
|
||||
|
||||
},
|
||||
RowTransformerPassThruImpl.instance(),
|
||||
RowTransformerStandardImpl.instance(),
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.hibernate.sql.exec.spi.JdbcSelect;
|
|||
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;
|
||||
|
||||
/**
|
||||
|
@ -159,7 +159,7 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader {
|
|||
}
|
||||
|
||||
},
|
||||
RowTransformerPassThruImpl.instance(),
|
||||
RowTransformerStandardImpl.instance(),
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
||||
|
|
|
@ -47,7 +47,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.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;
|
||||
|
@ -331,7 +331,7 @@ public class MultiIdLoaderStandard<T> implements MultiIdEntityLoader<T> {
|
|||
}
|
||||
}
|
||||
},
|
||||
RowTransformerPassThruImpl.instance(),
|
||||
RowTransformerStandardImpl.instance(),
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,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.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
|
||||
/**
|
||||
|
@ -197,7 +197,7 @@ public class MultiNaturalIdLoadingBatcher {
|
|||
}
|
||||
}
|
||||
},
|
||||
RowTransformerPassThruImpl.instance(),
|
||||
RowTransformerStandardImpl.instance(),
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,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.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;
|
||||
|
@ -151,7 +151,7 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
|
|||
session,
|
||||
subSelectFetchableKeysHandler
|
||||
),
|
||||
RowTransformerPassThruImpl.instance(),
|
||||
RowTransformerStandardImpl.instance(),
|
||||
ListResultsConsumer.UniqueSemantic.FILTER
|
||||
);
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.hibernate.sql.exec.spi.Callback;
|
|||
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;
|
||||
|
||||
|
@ -91,7 +91,7 @@ public class SingleIdLoadPlan<T> implements SingleEntityLoadPlan {
|
|||
}
|
||||
|
||||
protected RowTransformer<T> getRowTransformer() {
|
||||
return RowTransformerPassThruImpl.instance();
|
||||
return RowTransformerStandardImpl.instance();
|
||||
}
|
||||
|
||||
public T load(Object restrictedValue, SharedSessionContractImplementor session) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -127,7 +127,7 @@ public class NamedHqlQueryMementoImpl extends AbstractNamedQueryMemento implemen
|
|||
|
||||
@Override
|
||||
public void validate(QueryEngine queryEngine) {
|
||||
queryEngine.getHqlTranslator().translate( hqlString );
|
||||
queryEngine.getHqlTranslator().translate( hqlString, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,6 +31,9 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.metamodel.Bindable;
|
||||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.QueryException;
|
||||
|
@ -193,9 +196,6 @@ import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.metamodel.Bindable;
|
||||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
|
@ -269,16 +269,18 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
}
|
||||
|
||||
/**
|
||||
* Main entry point into analysis of HQL/JPQL parse tree - producing a semantic model of the
|
||||
* query.
|
||||
* Main entry point into analysis of HQL/JPQL parse tree - producing
|
||||
* a semantic model of the query.
|
||||
*/
|
||||
public static <R> SqmStatement<R> buildSemanticModel(
|
||||
HqlParser.StatementContext hqlParseTree,
|
||||
Class<R> expectedResultType,
|
||||
SqmCreationOptions creationOptions,
|
||||
SqmCreationContext creationContext) {
|
||||
return new SemanticQueryBuilder<R>( creationOptions, creationContext ).visitStatement( hqlParseTree );
|
||||
return new SemanticQueryBuilder<R>( expectedResultType, creationOptions, creationContext ).visitStatement( hqlParseTree );
|
||||
}
|
||||
|
||||
private final Class<R> expectedResultType;
|
||||
private final SqmCreationOptions creationOptions;
|
||||
private final SqmCreationContext creationContext;
|
||||
|
||||
|
@ -294,7 +296,11 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
private ParameterCollector parameterCollector;
|
||||
private ParameterStyle parameterStyle;
|
||||
|
||||
public SemanticQueryBuilder(SqmCreationOptions creationOptions, SqmCreationContext creationContext) {
|
||||
public SemanticQueryBuilder(
|
||||
Class<R> expectedResultType,
|
||||
SqmCreationOptions creationOptions,
|
||||
SqmCreationContext creationContext) {
|
||||
this.expectedResultType = expectedResultType;
|
||||
this.creationOptions = creationOptions;
|
||||
this.creationContext = creationContext;
|
||||
this.dotIdentifierConsumerStack = new StandardStack<>( new BasicDotIdentifierConsumer( this ) );
|
||||
|
@ -868,20 +874,42 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
// for now, this is slightly different than the legacy behavior where
|
||||
// the root and each non-fetched-join was selected. For now, here, we simply
|
||||
// select the root
|
||||
final SqmSelectClause selectClause = new SqmSelectClause(
|
||||
false,
|
||||
fromClause.getNumberOfRoots(),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
final SqmSelectClause selectClause;
|
||||
|
||||
final boolean expectingArray = expectedResultType != null && expectedResultType.isArray();
|
||||
if ( expectingArray ) {
|
||||
// triggers legacy interpretation of returning all roots
|
||||
// and non-fetched joins
|
||||
selectClause = new SqmSelectClause(
|
||||
false,
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
else {
|
||||
selectClause = new SqmSelectClause(
|
||||
false,
|
||||
fromClause.getNumberOfRoots(),
|
||||
creationContext.getNodeBuilder()
|
||||
);
|
||||
}
|
||||
|
||||
fromClause.visitRoots( (sqmRoot) -> {
|
||||
selectClause.addSelection( new SqmSelection<>( sqmRoot, sqmRoot.getAlias(), creationContext.getNodeBuilder() ) );
|
||||
if ( expectingArray ) {
|
||||
applyJoinsToInferredSelectClause( sqmRoot, selectClause );
|
||||
}
|
||||
} );
|
||||
|
||||
fromClause.visitRoots(
|
||||
sqmRoot -> selectClause.addSelection(
|
||||
new SqmSelection<>( sqmRoot, sqmRoot.getAlias(), creationContext.getNodeBuilder() )
|
||||
)
|
||||
);
|
||||
return selectClause;
|
||||
}
|
||||
|
||||
private void applyJoinsToInferredSelectClause(SqmFrom<?,?> sqm, SqmSelectClause selectClause) {
|
||||
sqm.visitSqmJoins( (sqmJoin) -> {
|
||||
selectClause.addSelection( new SqmSelection<>( sqmJoin, sqmJoin.getAlias(), creationContext.getNodeBuilder() ) );
|
||||
applyJoinsToInferredSelectClause( sqmJoin, selectClause );
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmSelectClause visitSelectClause(HqlParser.SelectClauseContext ctx) {
|
||||
// todo (6.0) : primer a select-clause-specific SemanticPathPart into the stack
|
||||
|
|
|
@ -13,12 +13,12 @@ import org.hibernate.grammars.hql.HqlLexer;
|
|||
import org.hibernate.grammars.hql.HqlParser;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.hql.HqlLogging;
|
||||
import org.hibernate.query.sqm.InterpretationException;
|
||||
import org.hibernate.query.hql.HqlTranslator;
|
||||
import org.hibernate.query.hql.spi.SqmCreationOptions;
|
||||
import org.hibernate.query.sqm.InterpretationException;
|
||||
import org.hibernate.query.sqm.ParsingException;
|
||||
import org.hibernate.query.sqm.internal.SqmTreePrinter;
|
||||
import org.hibernate.query.sqm.spi.SqmCreationContext;
|
||||
import org.hibernate.query.hql.spi.SqmCreationOptions;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
|
||||
import org.antlr.v4.runtime.ANTLRErrorListener;
|
||||
|
@ -71,7 +71,7 @@ public class StandardHqlTranslator implements HqlTranslator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <R> SqmStatement<R> translate(String query) {
|
||||
public <R> SqmStatement<R> translate(String query, Class<R> expectedResultType) {
|
||||
HqlLogging.QUERY_LOGGER.debugf( "HQL : " + query );
|
||||
|
||||
final HqlParser.StatementContext hqlParseTree = parseHql( query );
|
||||
|
@ -80,6 +80,7 @@ public class StandardHqlTranslator implements HqlTranslator {
|
|||
try {
|
||||
final SqmStatement<R> sqmStatement = SemanticQueryBuilder.buildSemanticModel(
|
||||
hqlParseTree,
|
||||
expectedResultType,
|
||||
sqmCreationOptions,
|
||||
sqmCreationContext
|
||||
);
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.hibernate.boot.spi.BootstrapContext;
|
|||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
|
||||
import org.hibernate.query.hql.HqlTranslator;
|
||||
import org.hibernate.query.named.NamedObjectRepository;
|
||||
import org.hibernate.query.named.NamedQueryMemento;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
|
@ -212,9 +211,7 @@ public class NamedObjectRepositoryImpl implements NamedObjectRepository {
|
|||
public Map<String, HibernateException> checkNamedQueries(QueryEngine queryEngine) {
|
||||
Map<String,HibernateException> errors = new HashMap<>();
|
||||
|
||||
final HqlTranslator sqmProducer = queryEngine.getHqlTranslator();
|
||||
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
|
||||
final boolean cachingEnabled = interpretationCache.isEnabled();
|
||||
|
||||
// Check named HQL queries
|
||||
log.debugf( "Checking %s named HQL queries", sqmMementoMap.size() );
|
||||
|
@ -224,7 +221,8 @@ public class NamedObjectRepositoryImpl implements NamedObjectRepository {
|
|||
String queryString = hqlMemento.getHqlString();
|
||||
interpretationCache.resolveHqlInterpretation(
|
||||
queryString,
|
||||
s -> queryEngine.getHqlTranslator().translate( queryString )
|
||||
null,
|
||||
s -> queryEngine.getHqlTranslator().translate( queryString, null )
|
||||
);
|
||||
}
|
||||
catch ( HibernateException e ) {
|
||||
|
|
|
@ -60,7 +60,7 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation
|
|||
}
|
||||
|
||||
@Override
|
||||
public HqlInterpretation resolveHqlInterpretation(String queryString, Function<String, SqmStatement<?>> creator) {
|
||||
public HqlInterpretation resolveHqlInterpretation(String queryString, Class<?> expectedResultType, Function<String, SqmStatement<?>> creator) {
|
||||
final StatisticsImplementor statistics = statisticsSupplier.get();
|
||||
final boolean stats = statistics.isStatisticsEnabled();
|
||||
final long startTime = ( stats ) ? System.nanoTime() : 0L;
|
||||
|
|
|
@ -101,14 +101,23 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
|
|||
@Override
|
||||
public HqlInterpretation resolveHqlInterpretation(
|
||||
String queryString,
|
||||
Class<?> expectedResultType,
|
||||
Function<String, SqmStatement<?>> creator) {
|
||||
log.tracef( "QueryPlan#resolveHqlInterpretation( `%s` )", queryString );
|
||||
final StatisticsImplementor statistics = statisticsSupplier.get();
|
||||
final boolean stats = statistics.isStatisticsEnabled();
|
||||
final long startTime = ( stats ) ? System.nanoTime() : 0L;
|
||||
|
||||
final String cacheKey;
|
||||
if ( expectedResultType != null && expectedResultType.isArray() ) {
|
||||
cacheKey = queryString + "_array";
|
||||
}
|
||||
else {
|
||||
cacheKey = queryString;
|
||||
}
|
||||
|
||||
final DomainParameterXref domainParameterXref;
|
||||
HqlInterpretation hqlInterpretation = hqlInterpretationCache.get( queryString );
|
||||
HqlInterpretation hqlInterpretation = hqlInterpretationCache.get( cacheKey );
|
||||
if ( hqlInterpretation == null ) {
|
||||
log.debugf( "Creating and caching HqlInterpretation - %s", queryString );
|
||||
final SqmStatement<?> sqmStatement = creator.apply( queryString );
|
||||
|
@ -124,7 +133,7 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
|
|||
}
|
||||
|
||||
hqlInterpretation = new SimpleHqlInterpretationImpl( sqmStatement, parameterMetadata, domainParameterXref );
|
||||
hqlInterpretationCache.put( queryString, hqlInterpretation );
|
||||
hqlInterpretationCache.put( cacheKey, hqlInterpretation );
|
||||
|
||||
if ( stats ) {
|
||||
final long endTime = System.nanoTime();
|
||||
|
|
|
@ -35,7 +35,7 @@ public interface QueryInterpretationCache {
|
|||
int getNumberOfCachedHqlInterpretations();
|
||||
int getNumberOfCachedQueryPlans();
|
||||
|
||||
HqlInterpretation resolveHqlInterpretation(String queryString, Function<String, SqmStatement<?>> creator);
|
||||
HqlInterpretation resolveHqlInterpretation(String queryString, Class<?> expectedResultType, Function<String, SqmStatement<?>> creator);
|
||||
|
||||
<R> SelectQueryPlan<R> resolveSelectQueryPlan(Key key, Supplier<SelectQueryPlan<R>> creator);
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
|
@ -23,6 +22,7 @@ import org.hibernate.internal.EmptyScrollableResults;
|
|||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.query.IllegalQueryOperationException;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.query.TupleTransformer;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
|
@ -47,9 +47,10 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
|||
import org.hibernate.sql.exec.spi.JdbcSelect;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerArrayImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerJpaTupleImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerSingularReturnImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
|
||||
import org.hibernate.sql.results.internal.TupleMetadata;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
|
@ -66,7 +67,6 @@ import static org.hibernate.query.sqm.internal.QuerySqmImpl.CRITERIA_HQL_STRING;
|
|||
*/
|
||||
public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||
private final SqmSelectStatement<?> sqm;
|
||||
private final String hql;
|
||||
private final DomainParameterXref domainParameterXref;
|
||||
private final RowTransformer<R> rowTransformer;
|
||||
private final SqmInterpreter<List<R>, Void> listInterpreter;
|
||||
|
@ -82,7 +82,6 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
TupleMetadata tupleMetadata,
|
||||
QueryOptions queryOptions) {
|
||||
this.sqm = sqm;
|
||||
this.hql = hql;
|
||||
this.domainParameterXref = domainParameterXref;
|
||||
|
||||
this.rowTransformer = determineRowTransformer( sqm, resultType, tupleMetadata, queryOptions );
|
||||
|
@ -175,16 +174,21 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
Class<R> resultType,
|
||||
TupleMetadata tupleMetadata,
|
||||
QueryOptions queryOptions) {
|
||||
if ( resultType == null || resultType.isArray() ) {
|
||||
if ( queryOptions.getTupleTransformer() != null ) {
|
||||
return makeRowTransformerTupleTransformerAdapter( sqm, queryOptions );
|
||||
}
|
||||
else {
|
||||
return RowTransformerPassThruImpl.instance();
|
||||
}
|
||||
if ( queryOptions.getTupleTransformer() != null ) {
|
||||
return makeRowTransformerTupleTransformerAdapter( sqm, queryOptions );
|
||||
}
|
||||
|
||||
// NOTE : if we get here, a result-type of some kind (other than Object[].class) was specified
|
||||
if ( resultType == null ) {
|
||||
return RowTransformerStandardImpl.instance();
|
||||
}
|
||||
|
||||
if ( resultType.isArray() ) {
|
||||
return (RowTransformer<R>) RowTransformerArrayImpl.instance();
|
||||
}
|
||||
|
||||
// NOTE : if we get here :
|
||||
// 1) there is no TupleTransformer specified
|
||||
// 2) an explicit result-type, other than an array, was specified
|
||||
|
||||
final List<SqmSelection<?>> selections = sqm.getQueryPart().getFirstQuerySpec().getSelectClause().getSelections();
|
||||
if ( tupleMetadata != null ) {
|
||||
|
|
|
@ -142,19 +142,20 @@ public class QuerySqmImpl<R>
|
|||
*/
|
||||
public QuerySqmImpl(
|
||||
NamedHqlQueryMementoImpl memento,
|
||||
Class<R> resultType,
|
||||
Class<R> expectedResultType,
|
||||
SharedSessionContractImplementor session) {
|
||||
super( session );
|
||||
|
||||
this.hql = memento.getHqlString();
|
||||
this.resultType = resultType;
|
||||
this.resultType = expectedResultType;
|
||||
|
||||
final SessionFactoryImplementor factory = session.getFactory();
|
||||
final QueryEngine queryEngine = factory.getQueryEngine();
|
||||
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
|
||||
final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation(
|
||||
hql,
|
||||
(s) -> queryEngine.getHqlTranslator().translate( hql )
|
||||
expectedResultType,
|
||||
(s) -> queryEngine.getHqlTranslator().translate( hql, expectedResultType )
|
||||
);
|
||||
|
||||
this.sqm = hqlInterpretation.getSqmStatement();
|
||||
|
|
|
@ -93,24 +93,39 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
public SqmSelectionQueryImpl(
|
||||
String hql,
|
||||
HqlInterpretation hqlInterpretation,
|
||||
Class<R> expectedResultType,
|
||||
SharedSessionContractImplementor session) {
|
||||
super( session );
|
||||
this.hql = hql;
|
||||
|
||||
//noinspection unchecked
|
||||
this.sqm = (SqmSelectStatement<R>) hqlInterpretation.getSqmStatement();
|
||||
|
||||
this.parameterMetadata = hqlInterpretation.getParameterMetadata();
|
||||
this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
|
||||
|
||||
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
|
||||
|
||||
visitQueryReturnType( sqm.getQueryPart(), null, getSessionFactory() );
|
||||
this.resultType = null;
|
||||
visitQueryReturnType( sqm.getQueryPart(), expectedResultType, getSessionFactory() );
|
||||
this.resultType = determineResultType( sqm, expectedResultType );
|
||||
|
||||
setComment( hql );
|
||||
this.tupleMetadata = null;
|
||||
}
|
||||
|
||||
private static <T> Class<T> determineResultType(SqmSelectStatement<?> sqm, Class<?> expectedResultType) {
|
||||
if ( expectedResultType == null || ! expectedResultType.isArray() ) {
|
||||
final List<SqmSelection<?>> selections = sqm.getQuerySpec().getSelectClause().getSelections();
|
||||
if ( selections.size() == 1 ) {
|
||||
final SqmSelection<?> sqmSelection = selections.get( 0 );
|
||||
//noinspection unchecked
|
||||
return (Class<T>) sqmSelection.getNodeJavaType().getJavaTypeClass();
|
||||
}
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (Class<T>) Object[].class;
|
||||
}
|
||||
|
||||
public SqmSelectionQueryImpl(
|
||||
NamedHqlQueryMementoImpl memento,
|
||||
Class<R> resultType,
|
||||
|
@ -124,7 +139,8 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
final QueryInterpretationCache interpretationCache = queryEngine.getInterpretationCache();
|
||||
final HqlInterpretation hqlInterpretation = interpretationCache.resolveHqlInterpretation(
|
||||
hql,
|
||||
(s) -> queryEngine.getHqlTranslator().translate( hql )
|
||||
resultType,
|
||||
(s) -> queryEngine.getHqlTranslator().translate( hql, resultType )
|
||||
);
|
||||
|
||||
SqmUtil.verifyIsSelectStatement( hqlInterpretation.getSqmStatement(), hql );
|
||||
|
@ -147,12 +163,14 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
NamedCriteriaQueryMementoImpl memento,
|
||||
Class<R> resultType,
|
||||
SharedSessionContractImplementor session) {
|
||||
this( (SqmSelectStatement<R>) memento.getSqmStatement(), session);
|
||||
//noinspection unchecked
|
||||
this( (SqmSelectStatement<R>) memento.getSqmStatement(), resultType, session);
|
||||
applyOptions( memento );
|
||||
}
|
||||
|
||||
public SqmSelectionQueryImpl(
|
||||
SqmSelectStatement<R> criteria,
|
||||
Class<R> expectedResultType,
|
||||
SharedSessionContractImplementor session) {
|
||||
super( session );
|
||||
this.hql = CRITERIA_HQL_STRING;
|
||||
|
@ -181,29 +199,19 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R> implemen
|
|||
// We don't set a null value, unless the type is also null which is the case when using HibernateCriteriaBuilder.value
|
||||
if ( value != null || jpaCriteriaParameter.getNodeType() == null ) {
|
||||
// Use the anticipated type for binding the value if possible
|
||||
getQueryParameterBindings().getBinding( jpaCriteriaParameter )
|
||||
getQueryParameterBindings()
|
||||
.getBinding( jpaCriteriaParameter )
|
||||
.setBindValue( value, jpaCriteriaParameter.getAnticipatedType() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.resultType = determineResultType( sqm );
|
||||
this.resultType = determineResultType( sqm, expectedResultType );
|
||||
visitQueryReturnType( sqm.getQueryPart(), expectedResultType, getSessionFactory() );
|
||||
|
||||
visitQueryReturnType( sqm.getQueryPart(), resultType, getSessionFactory() );
|
||||
setComment( hql );
|
||||
this.tupleMetadata = buildTupleMetadata( sqm, resultType );
|
||||
}
|
||||
|
||||
private static <T> Class<T> determineResultType(SqmSelectStatement<?> sqm) {
|
||||
final List<SqmSelection<?>> selections = sqm.getQuerySpec().getSelectClause().getSelections();
|
||||
if ( selections.size() == 1 ) {
|
||||
final SqmSelection<?> sqmSelection = selections.get( 0 );
|
||||
//noinspection unchecked
|
||||
return (Class<T>) sqmSelection.getNodeJavaType().getJavaTypeClass();
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (Class<T>) Object[].class;
|
||||
this.tupleMetadata = buildTupleMetadata( sqm, expectedResultType );
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.query.sqm.spi;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
|
|
|
@ -253,18 +253,10 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
|
|||
checkSelectionIsJpaCompliant( selection );
|
||||
}
|
||||
}
|
||||
|
||||
final Selection<? extends T> resultSelection;
|
||||
Class<T> resultType = getResultType();
|
||||
if ( resultType == Object.class ) {
|
||||
setResultType( resultType = (Class<T>) Object[].class );
|
||||
}
|
||||
if ( Tuple.class.isAssignableFrom( resultType ) ) {
|
||||
resultSelection = ( Selection<? extends T> ) nodeBuilder().tuple( selections );
|
||||
}
|
||||
else if ( resultType.isArray() ) {
|
||||
resultSelection = nodeBuilder().array( resultType, selections );
|
||||
}
|
||||
else if ( Object.class.equals( resultType ) ) {
|
||||
if ( resultType == null || resultType == Object.class ) {
|
||||
switch ( selections.length ) {
|
||||
case 0: {
|
||||
throw new IllegalArgumentException(
|
||||
|
@ -276,10 +268,17 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
|
|||
break;
|
||||
}
|
||||
default: {
|
||||
setResultType( (Class<T>) Object[].class );
|
||||
resultSelection = ( Selection<? extends T> ) nodeBuilder().array( selections );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( Tuple.class.isAssignableFrom( resultType ) ) {
|
||||
resultSelection = ( Selection<? extends T> ) nodeBuilder().tuple( selections );
|
||||
}
|
||||
else if ( resultType.isArray() ) {
|
||||
resultSelection = nodeBuilder().array( resultType, selections );
|
||||
}
|
||||
else {
|
||||
resultSelection = nodeBuilder().construct( resultType, selections );
|
||||
}
|
||||
|
@ -295,38 +294,39 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
|
|||
checkSelectionIsJpaCompliant( selection );
|
||||
}
|
||||
}
|
||||
|
||||
final Selection<? extends T> resultSelection;
|
||||
Class<T> resultType = getResultType();
|
||||
if ( resultType == null ) {
|
||||
setResultType( resultType = (Class<T>) Object[].class );
|
||||
}
|
||||
final List<? extends JpaSelection<?>> jpaSelectionList = (List<? extends JpaSelection<?>>) (List<?>) selectionList;
|
||||
if ( Tuple.class.isAssignableFrom( resultType ) ) {
|
||||
resultSelection = ( Selection<? extends T> ) nodeBuilder().tuple( jpaSelectionList );
|
||||
}
|
||||
else if ( resultType.isArray() ) {
|
||||
resultSelection = nodeBuilder().array( resultType, jpaSelectionList );
|
||||
}
|
||||
else if ( Object.class.equals( resultType ) ) {
|
||||
switch ( selectionList.size() ) {
|
||||
final Class<T> resultType = getResultType();
|
||||
final List<? extends JpaSelection<?>> selections = (List<? extends JpaSelection<?>>) (List<?>) selectionList;
|
||||
if ( resultType == null || resultType == Object.class ) {
|
||||
switch ( selections.size() ) {
|
||||
case 0: {
|
||||
throw new IllegalArgumentException(
|
||||
"empty selections passed to criteria query typed as Object"
|
||||
);
|
||||
}
|
||||
case 1: {
|
||||
resultSelection = ( Selection<? extends T> ) selectionList.get( 0 );
|
||||
resultSelection = ( Selection<? extends T> ) selections.get( 0 );
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
resultSelection = ( Selection<? extends T> ) nodeBuilder().array( jpaSelectionList );
|
||||
setResultType( (Class<T>) Object[].class );
|
||||
resultSelection = ( Selection<? extends T> ) nodeBuilder().array( selections );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
resultSelection = nodeBuilder().construct( resultType, jpaSelectionList );
|
||||
else if ( Tuple.class.isAssignableFrom( resultType ) ) {
|
||||
resultSelection = ( Selection<? extends T> ) nodeBuilder().tuple( selections );
|
||||
}
|
||||
else if ( resultType.isArray() ) {
|
||||
resultSelection = nodeBuilder().array( resultType, selections );
|
||||
}
|
||||
else {
|
||||
resultSelection = nodeBuilder().construct( resultType, selections );
|
||||
}
|
||||
|
||||
getQuerySpec().getSelectClause().setSelection( (SqmSelectableNode<?>) resultSelection );
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ import org.hibernate.sql.exec.spi.ExecutionContext;
|
|||
import org.hibernate.sql.results.NoMoreOutputsException;
|
||||
import org.hibernate.sql.results.internal.ResultsHelper;
|
||||
import org.hibernate.sql.results.internal.RowProcessingStateStandardImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||
import org.hibernate.sql.results.jdbc.internal.DirectResultSetAccess;
|
||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesResultSetImpl;
|
||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesSourceProcessingStateStandardImpl;
|
||||
|
@ -229,7 +229,7 @@ public class OutputsImpl implements Outputs {
|
|||
final RowReader<Object[]> rowReader = (RowReader<Object[]>) ResultsHelper.createRowReader(
|
||||
executionContext,
|
||||
null,
|
||||
RowTransformerPassThruImpl.INSTANCE,
|
||||
RowTransformerStandardImpl.INSTANCE,
|
||||
jdbcValues
|
||||
);
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
|
|||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.internal.ResultsHelper;
|
||||
import org.hibernate.sql.results.internal.RowProcessingStateStandardImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
|
||||
import org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess;
|
||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesCacheHit;
|
||||
|
@ -346,10 +346,9 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
|
|||
|
||||
if ( rowTransformer == null ) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final TupleTransformer<R> tupleTransformer = (TupleTransformer<R>)
|
||||
executionContext.getQueryOptions().getTupleTransformer();
|
||||
final TupleTransformer<R> tupleTransformer = (TupleTransformer<R>) executionContext.getQueryOptions().getTupleTransformer();
|
||||
if ( tupleTransformer == null ) {
|
||||
rowTransformer = RowTransformerPassThruImpl.instance();
|
||||
rowTransformer = RowTransformerStandardImpl.instance();
|
||||
}
|
||||
else {
|
||||
final List<DomainResult<?>> domainResults = jdbcValues.getValuesMapping().getDomainResults();
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.sql.results.internal;
|
||||
|
||||
import org.hibernate.sql.results.spi.RowTransformer;
|
||||
|
||||
/**
|
||||
* RowTransformer used when an array is explicitly specified as the return type
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class RowTransformerArrayImpl implements RowTransformer<Object[]> {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final RowTransformerArrayImpl INSTANCE = new RowTransformerArrayImpl();
|
||||
|
||||
public static RowTransformerArrayImpl instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] transformRow(Object[] row) {
|
||||
return row;
|
||||
}
|
||||
}
|
|
@ -10,23 +10,27 @@ import org.hibernate.Incubating;
|
|||
import org.hibernate.sql.results.spi.RowTransformer;
|
||||
|
||||
/**
|
||||
* Essentially a no-op transformer - simply passes the result through
|
||||
* The standard RowTransformer - <ol>
|
||||
* <li>if the row array has just a single dimension, the value from that dimension (index zero) is returned</li>
|
||||
* <li>otherwise, the array itself is returned</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public class RowTransformerPassThruImpl<T> implements RowTransformer<T> {
|
||||
public class RowTransformerStandardImpl<T> implements RowTransformer<T> {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final RowTransformerPassThruImpl INSTANCE = new RowTransformerPassThruImpl();
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static final RowTransformerStandardImpl INSTANCE = new RowTransformerStandardImpl();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> RowTransformerPassThruImpl<T> instance() {
|
||||
public static <T> RowTransformerStandardImpl<T> instance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private RowTransformerPassThruImpl() {
|
||||
private RowTransformerStandardImpl() {
|
||||
}
|
||||
|
||||
@Override
|
|
@ -807,16 +807,7 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
criteria.where( criteriaBuilder.equal( root.get( "id" ), testData.prod1Id ) );
|
||||
|
||||
Product prod = session.createQuery( criteria )
|
||||
.setResultTransformer(new ResultTransformer<Product>() {
|
||||
@Override
|
||||
public Product transformTuple(Object[] tuple, String[] aliases) {
|
||||
return (Product) tuple[0];
|
||||
}
|
||||
@Override
|
||||
public List<Product> transformList(List<Product> resultList) {
|
||||
return ResultTransformer.super.transformList(resultList);
|
||||
}
|
||||
})
|
||||
.setTupleTransformer( (tuple, aliases) -> (Product) tuple[0] )
|
||||
.uniqueResult();
|
||||
|
||||
assertNotNull( prod );
|
||||
|
|
|
@ -184,7 +184,7 @@ public class EntityJoinTest {
|
|||
final HqlTranslator hqlTranslator = queryEngine.getHqlTranslator();
|
||||
final SqmTranslatorFactory sqmTranslatorFactory = queryEngine.getSqmTranslatorFactory();
|
||||
|
||||
final SqmStatement<Object> sqm = hqlTranslator.translate( qry );
|
||||
final SqmStatement<Object> sqm = hqlTranslator.translate( qry, null );
|
||||
|
||||
final SqmTranslator<SelectStatement> selectTranslator = sqmTranslatorFactory.createSelectTranslator(
|
||||
(SqmSelectStatement<?>) sqm,
|
||||
|
|
|
@ -35,7 +35,7 @@ public class MutationTests {
|
|||
final SqmDeleteStatement<?> sqmDelete = (SqmDeleteStatement<?>) scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( "delete BasicEntity" );
|
||||
.translate( "delete BasicEntity", null );
|
||||
|
||||
assertThat( sqmDelete, notNullValue() );
|
||||
assertThat( sqmDelete.getTarget().getEntityName(), is( BasicEntity.class.getName() ) );
|
||||
|
@ -47,7 +47,7 @@ public class MutationTests {
|
|||
final SqmDeleteStatement<?> sqmDelete = (SqmDeleteStatement<?>) scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( "delete BasicEntity where data = 'abc'" );
|
||||
.translate( "delete BasicEntity where data = 'abc'", null );
|
||||
|
||||
assertThat( sqmDelete, notNullValue() );
|
||||
assertThat( sqmDelete.getTarget().getEntityName(), is( BasicEntity.class.getName() ) );
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.query.results;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.query.SelectionQuery;
|
||||
|
||||
import org.hibernate.testing.orm.domain.StandardDomainModel;
|
||||
import org.hibernate.testing.orm.domain.retail.Product;
|
||||
import org.hibernate.testing.orm.domain.retail.Vendor;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel( standardModels = StandardDomainModel.RETAIL )
|
||||
@SessionFactory
|
||||
public class ImplicitSelectWithJoinTests {
|
||||
private static final String HQL = "from Product p join p.vendor v where v.name like '%Steve%'";
|
||||
private static final String HQL2 = "select p " + HQL;
|
||||
|
||||
@Test
|
||||
public void testNoExpectedType(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
final SelectionQuery<?> query = session.createSelectionQuery( HQL );
|
||||
|
||||
{
|
||||
final List<?> results = query.list();
|
||||
assertThat( results ).hasSize( 1 );
|
||||
final Object result = results.get( 0 );
|
||||
assertThat( result ).isInstanceOf( Product.class );
|
||||
}
|
||||
|
||||
{
|
||||
final ScrollableResults<?> results = query.scroll();
|
||||
assertThat( results.next() ).isTrue();
|
||||
final Object result = results.get();
|
||||
assertThat( result ).isInstanceOf( Product.class );
|
||||
assertThat( results.next() ).isFalse();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProductResult(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
final SelectionQuery<Product> query = session.createSelectionQuery( HQL, Product.class );
|
||||
|
||||
{
|
||||
final List<Product> results = query.list();
|
||||
assertThat( results ).hasSize( 1 );
|
||||
final Product result = results.get( 0 );
|
||||
assertThat( result ).isNotNull();
|
||||
}
|
||||
|
||||
{
|
||||
final ScrollableResults<Product> results = query.scroll();
|
||||
assertThat( results.next() ).isTrue();
|
||||
final Product result = results.get();
|
||||
assertThat( result ).isNotNull();
|
||||
assertThat( results.next() ).isFalse();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrayResult(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
final SelectionQuery<Object[]> query = session.createSelectionQuery( HQL, Object[].class );
|
||||
|
||||
{
|
||||
final List<Object[]> results = query.list();
|
||||
assertThat( results ).hasSize( 1 );
|
||||
final Object[] result = results.get( 0 );
|
||||
assertThat( result ).isNotNull();
|
||||
assertThat( result ).hasSize( 2 );
|
||||
assertThat( result[ 0 ] ).isNotNull();
|
||||
assertThat( result[ 1 ] ).isNotNull();
|
||||
}
|
||||
|
||||
{
|
||||
final ScrollableResults<Object[]> results = query.scroll();
|
||||
assertThat( results.next() ).isTrue();
|
||||
final Object[] result = results.get();
|
||||
assertThat( results.next() ).isFalse();
|
||||
assertThat( result ).isNotNull();
|
||||
assertThat( result ).hasSize( 2 );
|
||||
assertThat( result[ 0 ] ).isNotNull();
|
||||
assertThat( result[ 1 ] ).isNotNull();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExplicitSingleSelectionArrayResult(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
final SelectionQuery<Object[]> query = session.createSelectionQuery( HQL2, Object[].class );
|
||||
|
||||
{
|
||||
final List<Object[]> results = query.list();
|
||||
assertThat( results ).hasSize( 1 );
|
||||
|
||||
final Object[] result = results.get( 0 );
|
||||
assertThat( result ).isNotNull();
|
||||
assertThat( result ).hasSize( 1 );
|
||||
assertThat( result[ 0 ] ).isNotNull();
|
||||
assertThat( result[ 0 ] ).isInstanceOf( Product.class );
|
||||
}
|
||||
|
||||
{
|
||||
final ScrollableResults<Object[]> results = query.scroll();
|
||||
assertThat( results.next() ).isTrue();
|
||||
final Object[] result = results.get();
|
||||
assertThat( results.next() ).isFalse();
|
||||
assertThat( result ).isNotNull();
|
||||
assertThat( result ).hasSize( 1 );
|
||||
assertThat( result[ 0 ] ).isNotNull();
|
||||
assertThat( result[ 0 ] ).isInstanceOf( Product.class );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExplicitSingleSelectionProductResult(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
final SelectionQuery<Product> query = session.createSelectionQuery( HQL2, Product.class );
|
||||
|
||||
{
|
||||
final List<Product> results = query.list();
|
||||
assertThat( results ).hasSize( 1 );
|
||||
final Product result = results.get( 0 );
|
||||
assertThat( result ).isNotNull();
|
||||
}
|
||||
|
||||
{
|
||||
final ScrollableResults<Product> results = query.scroll();
|
||||
assertThat( results.next() ).isTrue();
|
||||
final Product result = results.get();
|
||||
assertThat( result ).isNotNull();
|
||||
assertThat( results.next() ).isFalse();
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void prepareTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
final Vendor vendor = new Vendor( 1, "Steve's Curios", "Acme Corp." );
|
||||
final Product product = new Product( 10, UUID.randomUUID(), vendor );
|
||||
session.persist( vendor );
|
||||
session.persist( product );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void dropTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
session.createMutationQuery( "delete Product" ).executeUpdate();
|
||||
session.createMutationQuery( "delete Vendor" ).executeUpdate();
|
||||
} );
|
||||
}
|
||||
}
|
|
@ -59,7 +59,10 @@ public abstract class BaseSqmUnitTest
|
|||
}
|
||||
|
||||
public static SqmSelectStatement<?> interpretSelect(String hql, SessionFactoryImplementor sessionFactory) {
|
||||
return (SqmSelectStatement<?>) sessionFactory.getQueryEngine().getHqlTranslator().translate( hql );
|
||||
return (SqmSelectStatement<?>) sessionFactory
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( hql, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -54,7 +54,7 @@ public class IdSelectionTests {
|
|||
final SqmDeleteStatement<?> sqm = (SqmDeleteStatement<?>) scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( "delete SimpleEntityWithSecondaryTables where name = :n" );
|
||||
.translate( "delete SimpleEntityWithSecondaryTables where name = :n", null );
|
||||
|
||||
final DomainParameterXref domainParameterXref = DomainParameterXref.from( sqm );
|
||||
final ParameterMetadataImpl parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
|
||||
|
@ -79,7 +79,7 @@ public class IdSelectionTests {
|
|||
final SqmDeleteStatement<?> sqm = (SqmDeleteStatement<?>) scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( "delete SimpleEntityWithSecondaryTables where data = :d" );
|
||||
.translate( "delete SimpleEntityWithSecondaryTables where data = :d", null );
|
||||
|
||||
final DomainParameterXref domainParameterXref = DomainParameterXref.from( sqm );
|
||||
final ParameterMetadataImpl parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
|
||||
|
@ -104,7 +104,7 @@ public class IdSelectionTests {
|
|||
final SqmDeleteStatement<?> sqm = (SqmDeleteStatement<?>) scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( "delete Customer where name = :n" );
|
||||
.translate( "delete Customer where name = :n", null );
|
||||
|
||||
final DomainParameterXref domainParameterXref = DomainParameterXref.from( sqm );
|
||||
final ParameterMetadataImpl parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
|
||||
|
@ -129,7 +129,7 @@ public class IdSelectionTests {
|
|||
final SqmDeleteStatement<?> sqm = (SqmDeleteStatement<?>) scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( "delete ForeignCustomer where name = :n" );
|
||||
.translate( "delete ForeignCustomer where name = :n", null );
|
||||
|
||||
final DomainParameterXref domainParameterXref = DomainParameterXref.from( sqm );
|
||||
final ParameterMetadataImpl parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
|
||||
|
@ -154,7 +154,7 @@ public class IdSelectionTests {
|
|||
final SqmDeleteStatement<?> sqm = (SqmDeleteStatement<?>) scope.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getHqlTranslator()
|
||||
.translate( "delete ForeignCustomer where vat = :v" );
|
||||
.translate( "delete ForeignCustomer where vat = :v", null );
|
||||
|
||||
final DomainParameterXref domainParameterXref = DomainParameterXref.from( sqm );
|
||||
final ParameterMetadataImpl parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
|
||||
|
|
|
@ -28,7 +28,7 @@ public class AbstractResultTests {
|
|||
protected SelectStatement interpret(String hql, QueryParameterBindings parameterBindings, SessionFactoryImplementor sessionFactory) {
|
||||
final QueryEngine queryEngine = sessionFactory.getQueryEngine();
|
||||
|
||||
final SqmSelectStatement<?> sqm = (SqmSelectStatement<?>) queryEngine.getHqlTranslator().translate( hql );
|
||||
final SqmSelectStatement<?> sqm = (SqmSelectStatement<?>) queryEngine.getHqlTranslator().translate( hql, null );
|
||||
|
||||
final SqmTranslatorFactory sqmTranslatorFactory = queryEngine.getSqmTranslatorFactory();
|
||||
final SqmTranslator<SelectStatement> sqmConverter = sqmTranslatorFactory.createSelectTranslator(
|
||||
|
|
|
@ -20,6 +20,9 @@ import jakarta.persistence.Converter;
|
|||
public class MonetaryAmountConverter implements AttributeConverter<MonetaryAmount,Double> {
|
||||
@Override
|
||||
public Double convertToDatabaseColumn(MonetaryAmount attribute) {
|
||||
if ( attribute == null ) {
|
||||
return null;
|
||||
}
|
||||
return attribute.getNumber().numberValueExact( Double.class );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue