Various fixes

* Resolve return type for SUM according to JPA spec
* Specify invariant return types for SQRT and MOD as required by the JPA spec
* Fix JPA tuple element access support
* Fix join management for JPA related methods
* Handle optional escape character for like predicate
* Implement type inference for result arms of case expressions
* Implement min/max element/index functions as sub-query
* Implement min/max function support
* Implement emptiness, exists and member of predicate for JPA Criteria
* Implement size function as sub-query
* Implement group by entity alias by using FK key
This commit is contained in:
Christian Beikov 2021-03-23 16:13:46 +01:00
parent 46a16c605a
commit e22dc55adb
36 changed files with 681 additions and 245 deletions

View File

@ -6,11 +6,25 @@
*/
package org.hibernate.dialect.function;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Types;
import java.util.List;
import java.util.Arrays;
import java.util.function.Supplier;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
@ -1476,7 +1490,87 @@ public class CommonFunctionFactory {
.setExactArgumentCount(1)
.register();
final TypeConfiguration typeConfiguration = queryEngine.getTypeConfiguration();
final BasicType<Long> longType = typeConfiguration.getBasicTypeForJavaType( Long.class );
final BasicType<Double> doubleType = typeConfiguration.getBasicTypeForJavaType( Double.class );
final BasicType<BigInteger> bigIntegerType = typeConfiguration.getBasicTypeForJavaType( BigInteger.class );
final BasicType<BigDecimal> bigDecimalType = typeConfiguration.getBasicTypeForJavaType( BigDecimal.class );
// Resolve according to JPA spec 4.8.5
// SUM returns Long when applied to state fields of integral types (other than BigInteger);
// Double when applied to state fields of floating point types;
// BigInteger when applied to state fields of type BigInteger;
// and BigDecimal when applied to state fields of type BigDecimal.
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("sum")
.setReturnTypeResolver( new FunctionReturnTypeResolver() {
@Override
public AllowableFunctionReturnType<?> resolveFunctionReturnType(AllowableFunctionReturnType<?> impliedType, List<SqmTypedNode<?>> arguments, TypeConfiguration typeConfiguration) {
final AllowableFunctionReturnType<?> argType = StandardFunctionReturnTypeResolvers.extractArgumentType(
arguments,
1
);
final BasicType<?> basicType;
if ( argType instanceof BasicType<?> ) {
basicType = (BasicType<?>) argType;
}
else {
basicType = typeConfiguration.getBasicTypeForJavaType( argType.getJavaType() );
if ( basicType == null ) {
return impliedType;
}
}
switch ( basicType.getJdbcTypeDescriptor().getJdbcTypeCode() ) {
case Types.SMALLINT:
case Types.TINYINT:
case Types.INTEGER:
case Types.BIGINT:
return longType;
case Types.FLOAT:
case Types.REAL:
case Types.DOUBLE:
return doubleType;
case Types.DECIMAL:
case Types.NUMERIC:
if ( BigInteger.class.isAssignableFrom( basicType.getJavaType() ) ) {
return bigIntegerType;
}
else {
return bigDecimalType;
}
}
// Better use the implied type than throwing an exception
return impliedType;
}
@Override
public BasicValuedMapping resolveFunctionReturnType(Supplier<BasicValuedMapping> impliedTypeAccess, List<? extends SqlAstNode> arguments) {
// Resolve according to JPA spec 4.8.5
final BasicValuedMapping specifiedArgType = StandardFunctionReturnTypeResolvers.extractArgumentValuedMapping(
arguments,
1
);
switch ( specifiedArgType.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode() ) {
case Types.SMALLINT:
case Types.TINYINT:
case Types.INTEGER:
case Types.BIGINT:
return longType;
case Types.FLOAT:
case Types.REAL:
case Types.DOUBLE:
return doubleType;
case Types.DECIMAL:
case Types.NUMERIC:
if ( BigInteger.class.isAssignableFrom( specifiedArgType.getJdbcMapping().getJavaTypeDescriptor().getJavaTypeClass() ) ) {
return bigIntegerType;
}
else {
return bigDecimalType;
}
}
return impliedTypeAccess.get();
}
} )
.setExactArgumentCount(1)
.register();
@ -1511,6 +1605,8 @@ public class CommonFunctionFactory {
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("mod")
// According to JPA spec 4.6.17.2.2.
.setInvariantType( StandardBasicTypes.INTEGER )
.setExactArgumentCount(2)
.register();
@ -1524,6 +1620,8 @@ public class CommonFunctionFactory {
.register();
queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("sqrt")
// According to JPA spec 4.6.17.2.2.
.setInvariantType( StandardBasicTypes.DOUBLE )
.setExactArgumentCount(1)
.register();

View File

@ -793,7 +793,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
.getHqlQueryMemento( queryName );
if ( namedHqlDescriptor != null ) {
HqlQueryImplementor query = namedHqlDescriptor.toQuery( this, resultType );
HqlQueryImplementor<T> query = namedHqlDescriptor.toQuery( this, resultType );
query.setComment( "dynamic HQL query" );
applyQuerySettingsAndHints( query );
return query;
@ -805,10 +805,13 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
.getNativeQueryMemento( queryName );
if ( namedNativeDescriptor != null ) {
if( resultType == null){
resultType = (Class<T>) namedNativeDescriptor.getResultMappingClass();
final NativeQueryImplementor<T> query;
if ( resultType == null) {
query = namedNativeDescriptor.toQuery( this );
}
else {
query = namedNativeDescriptor.toQuery( this, resultType );
}
NativeQueryImplementor query = namedNativeDescriptor.toQuery( this, resultType );
query.setComment( "dynamic native SQL query" );
applyQuerySettingsAndHints( query );
return query;

View File

@ -10,6 +10,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.LockOptions;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices;
@ -130,14 +131,19 @@ public class SingleUniqueKeyEntityLoaderStandard<T> implements SingleUniqueKeyEn
true
);
int size = list.size();
assert size <= 1;
if ( size == 0 ) {
return null;
switch ( list.size() ) {
case 0:
return null;
case 1:
//noinspection unchecked
return (T) list.get( 0 );
}
//noinspection unchecked
return (T) list.get( 0 );
throw new HibernateException(
"More than one row with the given identifier was found: " +
ukValue +
", for class: " +
entityDescriptor.getEntityName()
);
}
@Override

View File

@ -28,7 +28,7 @@ class ListAttributeImpl<X, E> extends AbstractPluralAttribute<X, List<E>, E> imp
super( builder, metadataContext );
//noinspection unchecked
this.indexPathSource = (SqmPathSource) SqmMappingModelHelper.resolveSqmPathSource(
this.indexPathSource = (SqmPathSource) SqmMappingModelHelper.resolveSqmKeyPathSource(
getName(),
builder.getListIndexOrMapKeyType(),
BindableType.PLURAL_ATTRIBUTE

View File

@ -29,7 +29,7 @@ class MapAttributeImpl<X, K, V> extends AbstractPluralAttribute<X, Map<K, V>, V>
MapAttributeImpl(PluralAttributeBuilder<X, Map<K, V>, V, K> xceBuilder, MetadataContext metadataContext) {
super( xceBuilder, metadataContext );
this.keyPathSource = SqmMappingModelHelper.resolveSqmPathSource(
this.keyPathSource = SqmMappingModelHelper.resolveSqmKeyPathSource(
CollectionPart.Nature.INDEX.getName(),
xceBuilder.getListIndexOrMapKeyType(),
BindableType.PLURAL_ATTRIBUTE

View File

@ -24,6 +24,7 @@ import org.hibernate.procedure.spi.ProcedureParameterImplementor;
import org.hibernate.query.named.AbstractNamedQueryMemento;
import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryImplementor;
/**
* Implementation of NamedCallableQueryMemento
@ -121,7 +122,7 @@ public class NamedCallableQueryMementoImpl extends AbstractNamedQueryMemento imp
public ProcedureCall makeProcedureCall(
SharedSessionContractImplementor session,
String... resultSetMappingNames) {
return new ProcedureCallImpl( session, this, resultSetMappingNames );
return new ProcedureCallImpl<>( session, this, resultSetMappingNames );
}
@Override
@ -132,8 +133,8 @@ public class NamedCallableQueryMementoImpl extends AbstractNamedQueryMemento imp
}
@Override
public ProcedureCallImplementor<?> toQuery(SharedSessionContractImplementor session) {
return makeProcedureCall( session );
public <T> QueryImplementor<T> toQuery(SharedSessionContractImplementor session) {
return new ProcedureCallImpl<>( session, this );
}
@Override

View File

@ -17,6 +17,7 @@ import org.hibernate.query.hql.spi.HqlQueryImplementor;
import org.hibernate.query.hql.spi.NamedHqlQueryMemento;
import org.hibernate.query.named.AbstractNamedQueryMemento;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.sqm.internal.QuerySqmImpl;
import org.jboss.logging.Logger;
@ -128,7 +129,7 @@ public class NamedHqlQueryMementoImpl extends AbstractNamedQueryMemento implemen
}
@Override
public HqlQueryImplementor<?> toQuery(SharedSessionContractImplementor session) {
public <T> QueryImplementor<T> toQuery(SharedSessionContractImplementor session) {
return toQuery( session, null );
}

View File

@ -16,6 +16,7 @@ import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
import org.hibernate.query.named.AbstractNamedQueryMemento;
import org.hibernate.query.named.NameableQuery;
import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.query.spi.QueryImplementor;
/**
* NamedQueryMemento for HQL queries
@ -36,7 +37,7 @@ public interface NamedHqlQueryMemento extends NamedQueryMemento {
/**
* Convert the memento into an untyped executable query
*/
HqlQueryImplementor<?> toQuery(SharedSessionContractImplementor session);
<T> QueryImplementor<T> toQuery(SharedSessionContractImplementor session);
Integer getFirstResult();

View File

@ -54,7 +54,7 @@ public interface NamedQueryMemento {
*/
NamedQueryMemento makeCopy(String name);
QueryImplementor<?> toQuery(SharedSessionContractImplementor session);
<T> QueryImplementor<T> toQuery(SharedSessionContractImplementor session);
<T> QueryImplementor<T> toQuery(SharedSessionContractImplementor session, Class<T> javaType);
interface ParameterMemento {

View File

@ -33,6 +33,7 @@ import org.hibernate.query.sqm.sql.SqmTranslatorFactory;
import org.hibernate.query.sqm.sql.StandardSqmTranslatorFactory;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.type.spi.TypeConfiguration;
import java.util.Map;
import java.util.function.Supplier;
@ -75,6 +76,7 @@ public class QueryEngine {
sqmTranslatorFactory,
sessionFactory.getServiceRegistry().getService( NativeQueryInterpreter.class ),
buildInterpretationCache( sessionFactory::getStatistics, sessionFactory.getProperties() ),
metadata.getTypeConfiguration(),
dialect,
queryEngineOptions.getCustomSqmFunctionRegistry(),
sessionFactory.getServiceRegistry()
@ -88,6 +90,7 @@ public class QueryEngine {
private final NativeQueryInterpreter nativeQueryInterpreter;
private final QueryInterpretationCache interpretationCache;
private final SqmFunctionRegistry sqmFunctionRegistry;
private final TypeConfiguration typeConfiguration;
private final int preferredSqlTypeCodeForBoolean;
public QueryEngine(
@ -99,6 +102,7 @@ public class QueryEngine {
SqmTranslatorFactory sqmTranslatorFactory,
NativeQueryInterpreter nativeQueryInterpreter,
QueryInterpretationCache interpretationCache,
TypeConfiguration typeConfiguration,
Dialect dialect,
SqmFunctionRegistry userDefinedRegistry,
ServiceRegistry serviceRegistry) {
@ -116,6 +120,7 @@ public class QueryEngine {
);
this.sqmFunctionRegistry = new SqmFunctionRegistry();
this.typeConfiguration = typeConfiguration;
this.preferredSqlTypeCodeForBoolean = preferredSqlTypeCodeForBoolean;
dialect.initializeFunctionRegistry( this );
if ( userDefinedRegistry != null ) {
@ -151,6 +156,7 @@ public class QueryEngine {
this.nativeQueryInterpreter = nativeQueryInterpreter;
this.sqmFunctionRegistry = new SqmFunctionRegistry();
this.typeConfiguration = jpaMetamodel.getTypeConfiguration();
this.preferredSqlTypeCodeForBoolean = preferredSqlTypeCodeForBoolean;
dialect.initializeFunctionRegistry( this );
@ -336,6 +342,10 @@ public class QueryEngine {
return sqmFunctionRegistry;
}
public TypeConfiguration getTypeConfiguration() {
return typeConfiguration;
}
public void close() {
if ( namedObjectRepository != null ) {
namedObjectRepository.close();

View File

@ -14,6 +14,7 @@ import org.hibernate.FlushMode;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.named.AbstractNamedQueryMemento;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
import org.hibernate.query.sql.spi.NativeQueryImplementor;
@ -26,8 +27,8 @@ import org.hibernate.query.sql.spi.NativeQueryImplementor;
public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento implements NamedNativeQueryMemento {
private final String sqlString;
private String resultSetMappingName;
private Class resultSetMappingClass;
private final String resultSetMappingName;
private final Class<?> resultSetMappingClass;
private final Set<String> querySpaces;
@ -59,7 +60,9 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
hints
);
this.sqlString = sqlString;
this.resultSetMappingName = resultSetMappingName;
this.resultSetMappingName = resultSetMappingName == null || resultSetMappingName.isEmpty()
? null
: resultSetMappingName;
this.resultSetMappingClass = resultSetMappingClass;
this.querySpaces = querySpaces;
}
@ -117,19 +120,17 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
}
@Override
public NativeQueryImplementor toQuery(SharedSessionContractImplementor session) {
return new NativeQueryImpl( this, session );
public <T> NativeQueryImplementor<T> toQuery(SharedSessionContractImplementor session) {
return new NativeQueryImpl<>( this, session );
}
@Override
@SuppressWarnings("unchecked")
public <T> NativeQueryImplementor<T> toQuery(SharedSessionContractImplementor session, Class<T> resultType) {
return new NativeQueryImpl( this, resultType, session );
return new NativeQueryImpl<>( this, resultType, session );
}
@Override
@SuppressWarnings("unchecked")
public <T> NativeQueryImplementor<T> toQuery(SharedSessionContractImplementor session, String resultSetMappingName) {
return new NativeQueryImpl( this, resultSetMappingName, session );
return new NativeQueryImpl<>( this, resultSetMappingName, session );
}
}

View File

@ -16,6 +16,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.named.AbstractNamedQueryMemento;
import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.sql.internal.NamedNativeQueryMementoImpl;
/**
@ -50,7 +51,7 @@ public interface NamedNativeQueryMemento extends NamedQueryMemento {
* Convert the memento into an untyped executable query
*/
@Override
NativeQueryImplementor<?> toQuery(SharedSessionContractImplementor session);
<T> NativeQueryImplementor<T> toQuery(SharedSessionContractImplementor session);
/**
* Convert the memento into a typed executable query

View File

@ -582,18 +582,18 @@ public interface NodeBuilder extends HibernateCriteriaBuilder {
SqmPredicate notLike(Expression<String> x, String pattern, char escapeChar);
@Override
<T> SqmInPredicate in(Expression<? extends T> expression);
<T> SqmInPredicate<T> in(Expression<? extends T> expression);
@Override
<T> SqmInPredicate in(Expression<? extends T> expression, Expression<? extends T>... values);
<T> SqmInPredicate<T> in(Expression<? extends T> expression, Expression<? extends T>... values);
@Override
<T> SqmInPredicate in(Expression<? extends T> expression, T... values);
<T> SqmInPredicate<T> in(Expression<? extends T> expression, T... values);
@Override
<T> SqmInPredicate in(Expression<? extends T> expression, List<T> values);
<T> SqmInPredicate<T> in(Expression<? extends T> expression, List<T> values);
<T> SqmInPredicate in(Expression<? extends T> expression, SqmSubQuery<T> subQuery);
<T> SqmInPredicate<T> in(Expression<? extends T> expression, SqmSubQuery<T> subQuery);
@Override
SqmPredicate exists(Subquery<?> subquery);

View File

@ -146,13 +146,13 @@ public interface SemanticQueryWalker<T> {
T visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path);
T visitMaxElementPath(SqmMaxElementPath path);
T visitMaxElementPath(SqmMaxElementPath<?> path);
T visitMinElementPath(SqmMinElementPath path);
T visitMinElementPath(SqmMinElementPath<?> path);
T visitMaxIndexPath(SqmMaxIndexPath path);
T visitMaxIndexPath(SqmMaxIndexPath<?> path);
T visitMinIndexPath(SqmMinIndexPath path);
T visitMinIndexPath(SqmMinIndexPath<?> path);
T visitTreatedPath(SqmTreatedPath<?, ?> sqmTreatedPath);
@ -168,7 +168,7 @@ public interface SemanticQueryWalker<T> {
T visitSelectClause(SqmSelectClause selectClause);
T visitSelection(SqmSelection selection);
T visitSelection(SqmSelection<?> selection);
T visitValues(SqmValues values);
@ -178,7 +178,7 @@ public interface SemanticQueryWalker<T> {
T visitDynamicInstantiation(SqmDynamicInstantiation<?> sqmDynamicInstantiation);
default T visitJpaCompoundSelection(SqmJpaCompoundSelection selection) {
default T visitJpaCompoundSelection(SqmJpaCompoundSelection<?> selection) {
throw new NotYetImplementedFor6Exception( getClass() );
}

View File

@ -8,6 +8,7 @@ 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;
import javax.persistence.Tuple;
@ -45,7 +46,7 @@ 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.RowTransformerTupleTransformerAdapter;
import org.hibernate.sql.results.internal.TupleElementImpl;
import org.hibernate.sql.results.internal.TupleMetadata;
import org.hibernate.sql.results.spi.RowTransformer;
/**
@ -136,17 +137,12 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
if ( Tuple.class.isAssignableFrom( resultType ) ) {
// resultType is Tuple..
if ( queryOptions.getTupleTransformer() == null ) {
final List<TupleElement<?>> tupleElementList = new ArrayList<>( selections.size() );
final Map<TupleElement<?>, Integer> tupleElementMap = new IdentityHashMap<>( selections.size() );
for ( int i = 0; i < selections.size(); i++ ) {
final SqmSelection selection = selections.get( i );
tupleElementList.add(
new TupleElementImpl<>(
selection.getSelectableNode().getJavaTypeDescriptor().getJavaTypeClass(),
selection.getAlias()
)
);
final SqmSelection<?> selection = selections.get( i );
tupleElementMap.put( selection.getSelectableNode(), i );
}
return (RowTransformer<R>) new RowTransformerJpaTupleImpl( tupleElementList );
return (RowTransformer<R>) new RowTransformerJpaTupleImpl( new TupleMetadata( tupleElementMap ) );
}
throw new IllegalArgumentException(

View File

@ -491,7 +491,7 @@ public class QuerySqmImpl<R>
queryOptions.getGraph() != null ||
hasLimit
);
ExecutionContext executionContextToUse;
final ExecutionContext executionContextToUse;
if ( queryOptions.hasLimit() && containsCollectionFetches ) {
boolean fail = getSessionFactory().getSessionFactoryOptions().isFailOnPaginationOverCollectionFetchEnabled();
if (fail) {

View File

@ -70,6 +70,7 @@ import org.hibernate.query.sqm.tree.domain.SqmBagJoin;
import org.hibernate.query.sqm.tree.domain.SqmListJoin;
import org.hibernate.query.sqm.tree.domain.SqmMapJoin;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmSetJoin;
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
@ -94,10 +95,13 @@ import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmEmptinessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmExistsPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate;
import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
@ -507,7 +511,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
public <N extends Number> SqmExpression<N> sum(Expression<N> argument) {
return getFunctionDescriptor("sum").generateSqmExpression(
(SqmTypedNode<?>) argument,
(AllowableFunctionReturnType<N>) ( (SqmExpression<N>) argument ).getNodeType(),
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
@ -545,12 +549,14 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
@Override
public <X extends Comparable<? super X>> SqmExpression<X> greatest(Expression<X> argument) {
throw new NotYetImplementedFor6Exception();
return queryEngine.getSqmFunctionRegistry().findFunctionDescriptor( "max" )
.generateSqmExpression( (SqmTypedNode<?>) argument, null, queryEngine, getTypeConfiguration() );
}
@Override
public <X extends Comparable<? super X>> SqmExpression<X> least(Expression<X> argument) {
throw new NotYetImplementedFor6Exception();
return queryEngine.getSqmFunctionRegistry().findFunctionDescriptor( "min" )
.generateSqmExpression( (SqmTypedNode<?>) argument, null, queryEngine, getTypeConfiguration() );
}
@Override
@ -747,10 +753,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
//noinspection unchecked
return getFunctionDescriptor("sqrt").generateSqmExpression(
(SqmTypedNode<?>) x,
(AllowableFunctionReturnType<Double>) QueryHelper.highestPrecedenceType2(
((SqmExpression<?>) x).getNodeType(),
StandardBasicTypes.DOUBLE
),
null,
queryEngine,
getJpaMetamodel().getTypeConfiguration()
);
@ -1876,32 +1879,32 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
@Override
public <C extends Collection<?>> SqmPredicate isEmpty(Expression<C> collection) {
throw new NotYetImplementedFor6Exception();
return new SqmEmptinessPredicate( (SqmPluralValuedSimplePath) collection, false, this );
}
@Override
public <C extends Collection<?>> SqmPredicate isNotEmpty(Expression<C> collection) {
throw new NotYetImplementedFor6Exception();
return new SqmEmptinessPredicate( (SqmPluralValuedSimplePath) collection, true, this );
}
@Override
public <E, C extends Collection<E>> SqmPredicate isMember(Expression<E> elem, Expression<C> collection) {
throw new NotYetImplementedFor6Exception();
return new SqmMemberOfPredicate( (SqmExpression<?>) elem, (SqmPath<?>) collection, false, this );
}
@Override
public <E, C extends Collection<E>> SqmPredicate isMember(E elem, Expression<C> collection) {
throw new NotYetImplementedFor6Exception();
return new SqmMemberOfPredicate( value( elem ), (SqmPath<?>) collection, false, this );
}
@Override
public <E, C extends Collection<E>> SqmPredicate isNotMember(Expression<E> elem, Expression<C> collection) {
throw new NotYetImplementedFor6Exception();
return new SqmMemberOfPredicate( (SqmExpression<?>) elem, (SqmPath<?>) collection, true, this );
}
@Override
public <E, C extends Collection<E>> SqmPredicate isNotMember(E elem, Expression<C> collection) {
throw new NotYetImplementedFor6Exception();
return new SqmMemberOfPredicate( value( elem ), (SqmPath<?>) collection, true, this );
}
@Override
@ -1993,30 +1996,29 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
}
@Override
public <T> SqmInPredicate in(Expression<? extends T> expression) {
//noinspection unchecked
return new SqmInListPredicate( (SqmExpression) expression, this );
@SuppressWarnings("unchecked")
public <T> SqmInPredicate<T> in(Expression<? extends T> expression) {
return new SqmInListPredicate<>( (SqmExpression<T>) expression, this );
}
@Override
@SuppressWarnings("unchecked")
public <T> SqmInPredicate in(Expression<? extends T> expression, Expression<? extends T>... values) {
final SqmInListPredicate predicate = new SqmInListPredicate( (SqmExpression) expression, this );
public <T> SqmInPredicate<T> in(Expression<? extends T> expression, Expression<? extends T>... values) {
final SqmInListPredicate<T> predicate = new SqmInListPredicate<>( (SqmExpression<T>) expression, this );
for ( Expression<? extends T> value : values ) {
predicate.addExpression( (SqmExpression) value );
predicate.addExpression( (SqmExpression<T>) value );
}
return predicate;
}
@Override
@SuppressWarnings("unchecked")
public <T> SqmInPredicate in(Expression<? extends T> expression, T... values) {
final SqmExpression sqmExpression = (SqmExpression) expression;
final SqmInListPredicate predicate = new SqmInListPredicate( sqmExpression, this );
public <T> SqmInPredicate<T> in(Expression<? extends T> expression, T... values) {
final SqmExpression<T> sqmExpression = (SqmExpression<T>) expression;
final SqmInListPredicate<T> predicate = new SqmInListPredicate<>( sqmExpression, this );
for ( T value : values ) {
//noinspection unchecked
predicate.addExpression(
new SqmLiteral( value, sqmExpression.getNodeType(), this )
new SqmLiteral<>( value, sqmExpression.getNodeType(), this )
);
}
return predicate;
@ -2024,35 +2026,35 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext {
@Override
@SuppressWarnings("unchecked")
public <T> SqmInPredicate in(Expression<? extends T> expression, List<T> values) {
final SqmExpression sqmExpression = (SqmExpression) expression;
final SqmInListPredicate predicate = new SqmInListPredicate( sqmExpression, this );
public <T> SqmInPredicate<T> in(Expression<? extends T> expression, List<T> values) {
final SqmExpression<T> sqmExpression = (SqmExpression<T>) expression;
final SqmInListPredicate<T> predicate = new SqmInListPredicate<>( sqmExpression, this );
for ( T value : values ) {
predicate.addExpression(
new SqmLiteral( value, sqmExpression.getNodeType(), this )
new SqmLiteral<>( value, sqmExpression.getNodeType(), this )
);
}
return predicate;
}
@Override
public <T> SqmInPredicate in(Expression<? extends T> expression, SqmSubQuery<T> subQuery) {
//noinspection unchecked
return new SqmInSubQueryPredicate( (SqmExpression) expression, subQuery, this );
@SuppressWarnings("unchecked")
public <T> SqmInPredicate<T> in(Expression<? extends T> expression, SqmSubQuery<T> subQuery) {
return new SqmInSubQueryPredicate<>( (SqmExpression<T>) expression, subQuery, this );
}
@Override
public SqmPredicate exists(Subquery<?> subquery) {
throw new NotYetImplementedFor6Exception();
public SqmPredicate exists(Subquery<?> subQuery) {
return new SqmExistsPredicate( (SqmExpression<?>) subQuery, this );
}
@Override
public <M extends Map<?, ?>> SqmPredicate isMapEmpty(JpaExpression<M> mapExpression) {
throw new NotYetImplementedFor6Exception();
return new SqmEmptinessPredicate( (SqmPluralValuedSimplePath<?>) mapExpression, false, this );
}
@Override
public <M extends Map<?, ?>> SqmPredicate isMapNotEmpty(JpaExpression<M> mapExpression) {
throw new NotYetImplementedFor6Exception();
return new SqmEmptinessPredicate( (SqmPluralValuedSimplePath<?>) mapExpression, true, this );
}
}

View File

@ -31,6 +31,7 @@ import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.domain.AbstractSqmSpecificPluralPartPath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.sql.ast.tree.from.TableGroup;
@ -59,6 +60,14 @@ public class SqmMappingModelHelper {
return sessionFactory.getMetamodel().entityPersister( hibernateEntityName );
}
public static <J> SqmPathSource<J> resolveSqmKeyPathSource(
String name,
DomainType<J> valueDomainType,
Bindable.BindableType jpaBindableType) {
// todo (6.0): the key path source must create a special path for the key
return resolveSqmPathSource( name, valueDomainType, jpaBindableType );
}
public static <J> SqmPathSource<J> resolveSqmPathSource(
String name,
DomainType<J> valueDomainType,
@ -137,6 +146,12 @@ public class SqmMappingModelHelper {
return container.findSubPart( sqmPath.getNavigablePath().getLocalName(), container );
}
// Plural path parts are not joined and thus also have no table group
if ( sqmPath instanceof AbstractSqmSpecificPluralPartPath<?> ) {
final TableGroup lhsTableGroup = tableGroupLocator.apply( sqmPath.getLhs().getLhs().getNavigablePath() );
return lhsTableGroup.getModelPart().findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
}
final TableGroup lhsTableGroup = tableGroupLocator.apply( sqmPath.getLhs().getNavigablePath() );
return lhsTableGroup.getModelPart().findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
}

View File

@ -200,7 +200,7 @@ public class StandardFunctionReturnTypeResolvers {
return false;
}
private static AllowableFunctionReturnType<?> extractArgumentType(List<SqmTypedNode<?>> arguments, int position) {
public static AllowableFunctionReturnType<?> extractArgumentType(List<SqmTypedNode<?>> arguments, int position) {
final SqmTypedNode<?> specifiedArgument = arguments.get( position-1 );
final SqmExpressable<?> specifiedArgType = specifiedArgument.getNodeType();
if ( !(specifiedArgType instanceof AllowableFunctionReturnType) ) {
@ -218,7 +218,7 @@ public class StandardFunctionReturnTypeResolvers {
return (AllowableFunctionReturnType<?>) specifiedArgType;
}
private static BasicValuedMapping extractArgumentValuedMapping(List<? extends SqlAstNode> arguments, int position) {
public static BasicValuedMapping extractArgumentValuedMapping(List<? extends SqlAstNode> arguments, int position) {
final SqlAstNode specifiedArgument = arguments.get( position-1 );
final MappingModelExpressable<?> specifiedArgType = specifiedArgument instanceof Expression
? ( (Expression) specifiedArgument ).getExpressionType()

View File

@ -85,12 +85,14 @@ import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmWhereClause;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.query.sqm.tree.select.SqmQueryGroup;
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
import org.hibernate.query.sqm.tree.select.SqmQuerySpec;
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
@ -287,22 +289,22 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
}
@Override
public Object visitMaxElementPath(SqmMaxElementPath path) {
public Object visitMaxElementPath(SqmMaxElementPath<?> path) {
return path;
}
@Override
public Object visitMinElementPath(SqmMinElementPath path) {
public Object visitMinElementPath(SqmMinElementPath<?> path) {
return path;
}
@Override
public Object visitMaxIndexPath(SqmMaxIndexPath path) {
public Object visitMaxIndexPath(SqmMaxIndexPath<?> path) {
return path;
}
@Override
public Object visitMinIndexPath(SqmMinIndexPath path) {
public Object visitMinIndexPath(SqmMinIndexPath<?> path) {
return path;
}
@ -325,11 +327,19 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
}
@Override
public Object visitSelection(SqmSelection selection) {
public Object visitSelection(SqmSelection<?> selection) {
selection.getSelectableNode().accept( this );
return selection;
}
@Override
public Object visitJpaCompoundSelection(SqmJpaCompoundSelection<?> selection) {
for ( SqmSelectableNode<?> selectionItem : selection.getSelectionItems() ) {
selectionItem.accept( this );
}
return selection;
}
@Override
public Object visitValues(SqmValues values) {
for ( SqmExpression<?> expression : values.getExpressions() ) {
@ -399,7 +409,9 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
public Object visitLikePredicate(SqmLikePredicate predicate) {
predicate.getMatchExpression().accept( this );
predicate.getPattern().accept( this );
predicate.getEscapeCharacter().accept( this );
if ( predicate.getEscapeCharacter() != null ) {
predicate.getEscapeCharacter().accept( this );
}
return predicate;
}

View File

@ -86,6 +86,8 @@ import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sqm.InterpretationException;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker;
@ -107,11 +109,17 @@ import org.hibernate.query.sqm.tree.cte.SqmCteTable;
import org.hibernate.query.sqm.tree.cte.SqmCteTableColumn;
import org.hibernate.query.sqm.tree.cte.SqmSearchClauseSpecification;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.AbstractSqmSpecificPluralPartPath;
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmMapEntryReference;
import org.hibernate.query.sqm.tree.domain.SqmIndexedCollectionAccessPath;
import org.hibernate.query.sqm.tree.domain.SqmMaxElementPath;
import org.hibernate.query.sqm.tree.domain.SqmMaxIndexPath;
import org.hibernate.query.sqm.tree.domain.SqmMinElementPath;
import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
@ -124,6 +132,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCollate;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
@ -205,6 +214,7 @@ import org.hibernate.sql.ast.spi.SqlAstQueryPartProcessingState;
import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.cte.CteColumn;
import org.hibernate.sql.ast.tree.cte.CteStatement;
@ -1458,7 +1468,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
@Override
public Object visitSelection(SqmSelection<?> sqmSelection) {
public Void visitSelection(SqmSelection<?> sqmSelection) {
currentSqlSelectionCollector().next();
final Map<String, DomainResultProducer<?>> resultProducers;
if ( sqmSelection.getSelectableNode() instanceof SqmJpaCompoundSelection<?> ) {
@ -3452,26 +3462,23 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
@Override
public CaseSimpleExpression visitSimpleCaseExpression(SqmCaseSimple<?, ?> expression) {
SqmExpressable<?> resultType = expression.getNodeType();
List<CaseSimpleExpression.WhenFragment> whenFragments = new ArrayList<>( expression.getWhenFragments().size() );
for ( SqmCaseSimple.WhenFragment<?, ?> whenFragment : expression.getWhenFragments() ) {
resultType = QueryHelper.highestPrecedenceType2( resultType, whenFragment.getResult().getNodeType() );
whenFragments.add(
new CaseSimpleExpression.WhenFragment(
(Expression) whenFragment.getCheckValue().accept( this ),
(Expression) whenFragment.getResult().accept( this )
visitWithInferredType( whenFragment.getResult(), expression )
)
);
}
Expression otherwise = null;
if ( expression.getOtherwise() != null ) {
resultType = QueryHelper.highestPrecedenceType2( resultType, expression.getOtherwise().getNodeType() );
otherwise = (Expression) expression.getOtherwise().accept( this );
otherwise = visitWithInferredType( expression.getOtherwise(), expression );
}
final CaseSimpleExpression result = new CaseSimpleExpression(
resolveMappingExpressable( resultType ),
resolveMappingExpressable( expression.getNodeType() ),
(Expression) expression.getFixture().accept( this ),
whenFragments,
otherwise
@ -3482,26 +3489,23 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
@Override
public CaseSearchedExpression visitSearchedCaseExpression(SqmCaseSearched<?> expression) {
SqmExpressable<?> resultType = expression.getNodeType();
List<CaseSearchedExpression.WhenFragment> whenFragments = new ArrayList<>( expression.getWhenFragments().size() );
for ( SqmCaseSearched.WhenFragment<?> whenFragment : expression.getWhenFragments() ) {
resultType = QueryHelper.highestPrecedenceType2( resultType, whenFragment.getResult().getNodeType() );
whenFragments.add(
new CaseSearchedExpression.WhenFragment(
(Predicate) whenFragment.getPredicate().accept( this ),
(Expression) whenFragment.getResult().accept( this )
visitWithInferredType( whenFragment.getResult(), expression )
)
);
}
Expression otherwise = null;
if ( expression.getOtherwise() != null ) {
resultType = QueryHelper.highestPrecedenceType2( resultType, expression.getOtherwise().getNodeType() );
otherwise = (Expression) expression.getOtherwise().accept( this );
otherwise = visitWithInferredType( expression.getOtherwise(), expression );
}
final CaseSearchedExpression result = new CaseSearchedExpression(
resolveMappingExpressable( resultType ),
resolveMappingExpressable( expression.getNodeType() ),
whenFragments,
otherwise
);
@ -3509,6 +3513,16 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return result;
}
private <T> T visitWithInferredType(SqmExpression<?> expression, SqmExpression<?> inferred) {
inferrableTypeAccessStack.push( () -> determineValueMapping( inferred ) );
try {
return (T) expression.accept( this );
}
finally {
inferrableTypeAccessStack.pop();
}
}
@Override
public Object visitAny(SqmAny<?> sqmAny) {
return new Any(
@ -3591,6 +3605,170 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
);
}
@Override
public Expression visitMaxElementPath(SqmMaxElementPath<?> path) {
return createCorrelatedAggregateSubQuery( path, false, true );
}
@Override
public Expression visitMinElementPath(SqmMinElementPath<?> path) {
return createCorrelatedAggregateSubQuery( path, false, false );
}
@Override
public Expression visitMaxIndexPath(SqmMaxIndexPath<?> path) {
return createCorrelatedAggregateSubQuery( path, true, true );
}
@Override
public Expression visitMinIndexPath(SqmMinIndexPath<?> path) {
return createCorrelatedAggregateSubQuery( path, true, false );
}
@Override
public Expression visitPluralAttributeSizeFunction(SqmCollectionSize function) {
final SqmPath<?> pluralPath = function.getPluralPath();
final PluralAttributeMapping mappingModelExpressable = (PluralAttributeMapping) determineValueMapping(
pluralPath );
final FromClauseAccess parentFromClauseAccess = getFromClauseAccess();
final QuerySpec subQuerySpec = new QuerySpec( false );
pushProcessingState(
new SqlAstQueryPartProcessingStateImpl(
subQuerySpec,
getCurrentProcessingState(),
this,
currentClauseStack::getCurrent
)
);
try {
final TableGroup tableGroup = mappingModelExpressable.createRootTableGroup(
pluralPath.getNavigablePath(),
null,
true,
LockOptions.NONE.getLockMode(),
() -> subQuerySpec::applyPredicate,
this,
creationContext
);
getFromClauseAccess().registerTableGroup( pluralPath.getNavigablePath(), tableGroup );
subQuerySpec.getFromClause().addRoot( tableGroup );
final AbstractSqmSelfRenderingFunctionDescriptor functionDescriptor = (AbstractSqmSelfRenderingFunctionDescriptor) creationContext
.getSessionFactory()
.getQueryEngine()
.getSqmFunctionRegistry()
.findFunctionDescriptor( "count" );
final BasicType<Integer> integerType = creationContext.getDomainModel()
.getTypeConfiguration()
.getBasicTypeForJavaType( Integer.class );
final Expression expression = new SelfRenderingFunctionSqlAstExpression(
functionDescriptor.getName(),
functionDescriptor::render,
Collections.singletonList( new QueryLiteral<>( 1, integerType ) ),
integerType,
integerType
);
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, expression ) );
subQuerySpec.applyPredicate(
mappingModelExpressable.getKeyDescriptor().generateJoinPredicate(
parentFromClauseAccess.findTableGroup( pluralPath.getNavigablePath().getParent() ),
tableGroup,
SqlAstJoinType.INNER,
getSqlExpressionResolver(),
creationContext
)
);
}
finally {
popProcessingStateStack();
}
return subQuerySpec;
}
@Override
public Object visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path) {
// SemanticQueryBuilder applies the index expression to the generated join
return path.getLhs().accept( this );
}
protected Expression createCorrelatedAggregateSubQuery(
AbstractSqmSpecificPluralPartPath<?> pluralPartPath,
boolean index,
boolean max) {
final PluralAttributeMapping mappingModelExpressable = (PluralAttributeMapping) determineValueMapping(
pluralPartPath.getPluralDomainPath() );
final FromClauseAccess parentFromClauseAccess = getFromClauseAccess();
final QuerySpec subQuerySpec = new QuerySpec( false );
pushProcessingState(
new SqlAstQueryPartProcessingStateImpl(
subQuerySpec,
getCurrentProcessingState(),
this,
currentClauseStack::getCurrent
)
);
try {
final TableGroup tableGroup = mappingModelExpressable.createRootTableGroup(
pluralPartPath.getNavigablePath(),
null,
true,
LockOptions.NONE.getLockMode(),
() -> subQuerySpec::applyPredicate,
this,
creationContext
);
getFromClauseAccess().registerTableGroup( pluralPartPath.getNavigablePath(), tableGroup );
subQuerySpec.getFromClause().addRoot( tableGroup );
final AbstractSqmSelfRenderingFunctionDescriptor functionDescriptor = (AbstractSqmSelfRenderingFunctionDescriptor) creationContext
.getSessionFactory()
.getQueryEngine()
.getSqmFunctionRegistry()
.findFunctionDescriptor( max ? "max" : "min" );
final CollectionPart collectionPart = index
? mappingModelExpressable.getIndexDescriptor()
: mappingModelExpressable.getElementDescriptor();
final List<SqlAstNode> arguments = new ArrayList<>( 1 );
collectionPart.forEachSelection(
(selectionIndex, selectionMapping) -> {
arguments.add(
new ColumnReference(
tableGroup.getTableReference( selectionMapping.getContainingTableExpression() ),
selectionMapping,
creationContext.getSessionFactory()
)
);
}
);
final Expression expression = new SelfRenderingFunctionSqlAstExpression(
functionDescriptor.getName(),
functionDescriptor::render,
arguments,
(AllowableFunctionReturnType<?>) collectionPart.getJdbcMappings().get( 0 ),
collectionPart
);
subQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, expression ) );
subQuerySpec.applyPredicate(
mappingModelExpressable.getKeyDescriptor().generateJoinPredicate(
parentFromClauseAccess.findTableGroup( pluralPartPath.getPluralDomainPath().getNavigablePath().getParent() ),
tableGroup,
SqlAstJoinType.INNER,
getSqlExpressionResolver(),
creationContext
)
);
}
finally {
popProcessingStateStack();
}
return subQuerySpec;
}
// @Override
// public Object visitPluralAttributeElementBinding(PluralAttributeElementBinding binding) {

View File

@ -46,7 +46,6 @@ import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
/**
* Convenience base class for SqmFrom implementations
*
@ -55,7 +54,7 @@ import org.hibernate.query.sqm.tree.from.SqmRoot;
public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements SqmFrom<O,T> {
private String alias;
private List<SqmJoin<T,?>> joins;
private List<SqmJoin<T, ?>> joins;
protected AbstractSqmFrom(
NavigablePath navigablePath,
@ -133,12 +132,12 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
@Override
public List<SqmJoin<T,?>> getSqmJoins() {
public List<SqmJoin<T, ?>> getSqmJoins() {
return joins == null ? Collections.emptyList() : Collections.unmodifiableList( joins );
}
@Override
public void addSqmJoin(SqmJoin<T,?> join) {
public void addSqmJoin(SqmJoin<T, ?> join) {
if ( joins == null ) {
joins = new ArrayList<>();
}
@ -146,7 +145,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
@Override
public void visitSqmJoins(Consumer<SqmJoin<T,?>> consumer) {
public void visitSqmJoins(Consumer<SqmJoin<T, ?>> consumer) {
if ( joins != null ) {
joins.forEach( consumer );
}
@ -190,84 +189,105 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
@Override
@SuppressWarnings("unchecked")
public <A> SqmSingularJoin<T, A> join(SingularAttribute<? super T, A> attribute, JoinType jt) {
return buildSingularJoin( (SingularPersistentAttribute) attribute, SqmJoinType.from( jt ), false );
final SqmSingularJoin<T, A> join = buildSingularJoin( (SingularPersistentAttribute<? super T, A>) attribute, SqmJoinType.from( jt ), false );
addSqmJoin( join );
return join;
}
@Override
@SuppressWarnings("unchecked")
public <A> SqmBagJoin<T,A> join(CollectionAttribute<? super T, A> attribute) {
public <A> SqmBagJoin<T, A> join(CollectionAttribute<? super T, A> attribute) {
return join( attribute, JoinType.INNER );
}
@Override
@SuppressWarnings("unchecked")
public SqmBagJoin join(CollectionAttribute attribute, JoinType jt) {
return buildBagJoin( (BagPersistentAttribute) attribute, SqmJoinType.from( jt ), false );
public <E> SqmBagJoin<T, E> join(CollectionAttribute<? super T, E> attribute, JoinType jt) {
final SqmBagJoin<T, E> join = buildBagJoin( (BagPersistentAttribute<T, E>) attribute, SqmJoinType.from( jt ), false );
addSqmJoin( join );
return join;
}
@Override
@SuppressWarnings("unchecked")
public SqmSetJoin join(SetAttribute attribute) {
public <E> SqmSetJoin<T, E> join(SetAttribute<? super T, E> attribute) {
return join( attribute, JoinType.INNER );
}
@Override
@SuppressWarnings("unchecked")
public SqmSetJoin join(SetAttribute attribute, JoinType jt) {
return buildSetJoin( (SetPersistentAttribute) attribute, SqmJoinType.from( jt ), false );
public <E> SqmSetJoin<T, E> join(SetAttribute<? super T, E> attribute, JoinType jt) {
final SqmSetJoin<T, E> join = buildSetJoin(
(SetPersistentAttribute<? super T, E>) attribute,
SqmJoinType.from( jt ),
false
);
addSqmJoin( join );
return join;
}
@Override
@SuppressWarnings("unchecked")
public SqmListJoin join(ListAttribute attribute) {
public <E> SqmListJoin<T, E> join(ListAttribute<? super T, E> attribute) {
return join( attribute, JoinType.INNER );
}
@Override
@SuppressWarnings("unchecked")
public SqmListJoin join(ListAttribute attribute, JoinType jt) {
return buildListJoin( (ListPersistentAttribute) attribute, SqmJoinType.from( jt ), false );
public <E> SqmListJoin<T, E> join(ListAttribute<? super T, E> attribute, JoinType jt) {
final SqmListJoin<T, E> join = buildListJoin(
(ListPersistentAttribute<? super T, E>) attribute,
SqmJoinType.from( jt ),
false
);
addSqmJoin( join );
return join;
}
@Override
@SuppressWarnings("unchecked")
public SqmMapJoin join(MapAttribute attribute) {
public <K, V> SqmMapJoin<T, K, V> join(MapAttribute<? super T, K, V> attribute) {
return join( attribute, JoinType.INNER );
}
@Override
@SuppressWarnings("unchecked")
public SqmMapJoin join(MapAttribute attribute, JoinType jt) {
return buildMapJoin( (MapPersistentAttribute) attribute, SqmJoinType.from( jt ), false );
public <K, V> SqmMapJoin<T, K, V> join(MapAttribute<? super T, K, V> attribute, JoinType jt) {
final SqmMapJoin<T, K, V> join = buildMapJoin(
(MapPersistentAttribute<? super T, K, V>) attribute,
SqmJoinType.from( jt ),
false
);
addSqmJoin( join );
return join;
}
@Override
@SuppressWarnings("unchecked")
public SqmAttributeJoin join(String attributeName) {
public <X, Y> SqmAttributeJoin<X, Y> join(String attributeName) {
return join( attributeName, JoinType.INNER );
}
@Override
@SuppressWarnings("unchecked")
public SqmAttributeJoin join(String attributeName, JoinType jt) {
public <X, Y> SqmAttributeJoin<X, Y> join(String attributeName, JoinType jt) {
final SqmPathSource<?> subPathSource = getReferencedPathSource().findSubPathSource( attributeName );
return buildJoin( subPathSource, SqmJoinType.from( jt ), false );
return (SqmAttributeJoin<X, Y>) buildJoin( subPathSource, SqmJoinType.from( jt ), false );
}
@Override
@SuppressWarnings("unchecked")
public SqmBagJoin joinCollection(String attributeName) {
public <X, Y> SqmBagJoin<X, Y> joinCollection(String attributeName) {
return joinCollection( attributeName, JoinType.INNER );
}
@Override
@SuppressWarnings("unchecked")
public SqmBagJoin joinCollection(String attributeName, JoinType jt) {
public <X, Y> SqmBagJoin<X, Y> joinCollection(String attributeName, JoinType jt) {
final SqmPathSource<?> joinedPathSource = getReferencedPathSource().findSubPathSource( attributeName );
if ( joinedPathSource instanceof BagPersistentAttribute ) {
return buildBagJoin( (BagPersistentAttribute) joinedPathSource, SqmJoinType.from( jt ), false );
final SqmBagJoin<T, Y> join = buildBagJoin(
(BagPersistentAttribute<T, Y>) joinedPathSource,
SqmJoinType.from( jt ),
false
);
addSqmJoin( join );
return (SqmBagJoin<X, Y>) join;
}
throw new IllegalArgumentException(
@ -282,18 +302,23 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
@Override
@SuppressWarnings("unchecked")
public SqmSetJoin joinSet(String attributeName) {
public <X, Y> SqmSetJoin<X, Y> joinSet(String attributeName) {
return joinSet( attributeName, JoinType.INNER );
}
@Override
@SuppressWarnings("unchecked")
public SqmSetJoin joinSet(String attributeName, JoinType jt) {
public <X, Y> SqmSetJoin<X, Y> joinSet(String attributeName, JoinType jt) {
final SqmPathSource<?> joinedPathSource = getReferencedPathSource().findSubPathSource( attributeName );
if ( joinedPathSource instanceof SetPersistentAttribute ) {
return buildSetJoin( (SetPersistentAttribute) joinedPathSource, SqmJoinType.from( jt ), false );
final SqmSetJoin<T, Y> join = buildSetJoin(
(SetPersistentAttribute<T, Y>) joinedPathSource,
SqmJoinType.from( jt ),
false
);
addSqmJoin( join );
return (SqmSetJoin<X, Y>) join;
}
throw new IllegalArgumentException(
@ -308,18 +333,23 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
@Override
@SuppressWarnings("unchecked")
public SqmListJoin joinList(String attributeName) {
public <X, Y> SqmListJoin<X, Y> joinList(String attributeName) {
return joinList( attributeName, JoinType.INNER );
}
@Override
@SuppressWarnings("unchecked")
public SqmListJoin joinList(String attributeName, JoinType jt) {
public <X, Y> SqmListJoin<X, Y> joinList(String attributeName, JoinType jt) {
final SqmPathSource<?> joinedPathSource = getReferencedPathSource().findSubPathSource( attributeName );
if ( joinedPathSource instanceof ListPersistentAttribute ) {
return buildListJoin( (ListPersistentAttribute) joinedPathSource, SqmJoinType.from( jt ), false );
final SqmListJoin<T, Y> join = buildListJoin(
(ListPersistentAttribute<T, Y>) joinedPathSource,
SqmJoinType.from( jt ),
false
);
addSqmJoin( join );
return (SqmListJoin<X, Y>) join;
}
throw new IllegalArgumentException(
@ -334,18 +364,23 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
@Override
@SuppressWarnings("unchecked")
public SqmMapJoin joinMap(String attributeName) {
public <X, K, V> SqmMapJoin<X, K, V> joinMap(String attributeName) {
return joinMap( attributeName, JoinType.INNER );
}
@Override
@SuppressWarnings("unchecked")
public SqmMapJoin joinMap(String attributeName, JoinType jt) {
public <X, K, V> SqmMapJoin<X, K, V> joinMap(String attributeName, JoinType jt) {
final SqmPathSource<?> joinedPathSource = getReferencedPathSource().findSubPathSource( attributeName );
if ( joinedPathSource instanceof MapPersistentAttribute ) {
return buildMapJoin( (MapPersistentAttribute) joinedPathSource, SqmJoinType.from( jt ), false );
if ( joinedPathSource instanceof MapPersistentAttribute<?, ?, ?> ) {
final SqmMapJoin<T, K, V> join = buildMapJoin(
(MapPersistentAttribute<T, K, V>) joinedPathSource,
SqmJoinType.from( jt ),
false
);
addSqmJoin( join );
return (SqmMapJoin<X, K, V>) join;
}
throw new IllegalArgumentException(
@ -374,12 +409,14 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
@Override
@SuppressWarnings("unchecked")
public <A> SqmSingularJoin<T,A> fetch(SingularAttribute<? super T, A> attribute, JoinType jt) {
return buildSingularJoin(
(SingularPersistentAttribute) attribute,
public <A> SqmSingularJoin<T, A> fetch(SingularAttribute<? super T, A> attribute, JoinType jt) {
final SqmSingularJoin<T, A> join = buildSingularJoin(
(SingularPersistentAttribute<? super T, A>) attribute,
SqmJoinType.from( jt ),
true
);
addSqmJoin( join );
return join;
}
@Override
@ -391,7 +428,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
@SuppressWarnings("unchecked")
public <A> SqmAttributeJoin<T, A> fetch(PluralAttribute<? super T, ?, A> attribute, JoinType jt) {
return buildJoin(
(PluralPersistentAttribute) attribute,
(PluralPersistentAttribute<? super T, ?, A>) attribute,
SqmJoinType.from( jt ),
true
);
@ -404,47 +441,52 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
@Override
@SuppressWarnings("unchecked")
public <X,A> SqmAttributeJoin<X,A> fetch(String attributeName, JoinType jt) {
final SqmPathSource<?> fetchedPathSource = getReferencedPathSource().findSubPathSource( attributeName );
return buildJoin( fetchedPathSource, SqmJoinType.from( jt ), true );
public <X, A> SqmAttributeJoin<X, A> fetch(String attributeName, JoinType jt) {
final SqmPathSource<A> fetchedPathSource = (SqmPathSource<A>) getReferencedPathSource()
.findSubPathSource( attributeName );
return (SqmAttributeJoin<X, A>) buildJoin(
fetchedPathSource,
SqmJoinType.from( jt ),
true
);
}
private <A> SqmAttributeJoin buildJoin(
private <A> SqmAttributeJoin<T, A> buildJoin(
SqmPathSource<A> joinedPathSource,
SqmJoinType joinType,
boolean fetched) {
final SqmAttributeJoin sqmJoin;
if ( joinedPathSource instanceof SingularPersistentAttribute ) {
final SqmAttributeJoin<T, A> sqmJoin;
if ( joinedPathSource instanceof SingularPersistentAttribute<?, ?> ) {
sqmJoin = buildSingularJoin(
(SingularPersistentAttribute<T,A>) joinedPathSource,
(SingularPersistentAttribute<T, A>) joinedPathSource,
joinType,
fetched
);
}
else if ( joinedPathSource instanceof BagPersistentAttribute ) {
else if ( joinedPathSource instanceof BagPersistentAttribute<?, ?> ) {
sqmJoin = buildBagJoin(
(BagPersistentAttribute) joinedPathSource,
(BagPersistentAttribute<T, A>) joinedPathSource,
joinType,
fetched
);
}
else if ( joinedPathSource instanceof ListPersistentAttribute ) {
else if ( joinedPathSource instanceof ListPersistentAttribute<?, ?> ) {
sqmJoin = buildListJoin(
(ListPersistentAttribute) joinedPathSource,
(ListPersistentAttribute<T, A>) joinedPathSource,
joinType,
fetched
);
}
else if ( joinedPathSource instanceof MapPersistentAttribute ) {
else if ( joinedPathSource instanceof MapPersistentAttribute<?, ?, ?> ) {
sqmJoin = buildMapJoin(
(MapPersistentAttribute) joinedPathSource,
(MapPersistentAttribute<T, ?, A>) joinedPathSource,
joinType,
fetched
);
}
else if ( joinedPathSource instanceof SetPersistentAttribute ) {
else if ( joinedPathSource instanceof SetPersistentAttribute<?, ?> ) {
sqmJoin = buildSetJoin(
(SetPersistentAttribute) joinedPathSource,
(SetPersistentAttribute<T, A>) joinedPathSource,
joinType,
fetched
);
@ -464,15 +506,15 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
return sqmJoin;
}
private <A> SqmSingularJoin<T,A> buildSingularJoin(
SingularPersistentAttribute<T,A> attribute,
@SuppressWarnings("unchecked")
private <A> SqmSingularJoin<T, A> buildSingularJoin(
SingularPersistentAttribute<? super T, A> attribute,
SqmJoinType joinType,
boolean fetched) {
if ( attribute.getSqmPathType() instanceof ManagedDomainType ) {
//noinspection unchecked
return new SqmSingularJoin(
return new SqmSingularJoin<>(
this,
attribute,
(SingularPersistentAttribute<T, A>) attribute,
null,
joinType,
fetched,
@ -481,17 +523,16 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
throw new SemanticException( "Attribute [" + attribute + "] is not joinable" );
}
@SuppressWarnings("unchecked")
private <E> SqmBagJoin<T,E> buildBagJoin(
BagPersistentAttribute attribute,
private <E> SqmBagJoin<T, E> buildBagJoin(
BagPersistentAttribute<? super T, E> attribute,
SqmJoinType joinType,
boolean fetched) {
return new SqmBagJoin(
return new SqmBagJoin<>(
this,
attribute,
(BagPersistentAttribute<T, E>)attribute,
null,
joinType,
fetched,
@ -500,13 +541,13 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
@SuppressWarnings("unchecked")
private <E> SqmListJoin<T,E> buildListJoin(
ListPersistentAttribute attribute,
private <E> SqmListJoin<T, E> buildListJoin(
ListPersistentAttribute<? super T, E> attribute,
SqmJoinType joinType,
boolean fetched) {
return new SqmListJoin(
return new SqmListJoin<>(
this,
attribute,
(ListPersistentAttribute<T, E>) attribute,
null,
joinType,
fetched,
@ -515,13 +556,13 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
@SuppressWarnings("unchecked")
private <K,V> SqmMapJoin<T,K,V> buildMapJoin(
MapPersistentAttribute attribute,
private <K, V> SqmMapJoin<T, K, V> buildMapJoin(
MapPersistentAttribute<? super T, K, V> attribute,
SqmJoinType joinType,
boolean fetched) {
return new SqmMapJoin(
return new SqmMapJoin<>(
this,
attribute,
(MapPersistentAttribute<T, K, V>) attribute,
null,
joinType,
fetched,
@ -530,13 +571,13 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
}
@SuppressWarnings("unchecked")
private <E> SqmSetJoin<T,E> buildSetJoin(
SetPersistentAttribute attribute,
private <E> SqmSetJoin<T, E> buildSetJoin(
SetPersistentAttribute<? super T, E> attribute,
SqmJoinType joinType,
boolean fetched) {
return new SqmSetJoin(
return new SqmSetJoin<>(
this,
attribute,
(SetPersistentAttribute<T, E>) attribute,
null,
joinType,
fetched,

View File

@ -28,7 +28,7 @@ public class SqmIndexedCollectionAccessPath<T> extends AbstractSqmPath<T> implem
SqmExpression<?> selectorExpression) {
//noinspection unchecked
super(
pluralDomainPath.getNavigablePath().append( "[]" ),
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), "[]" ),
(PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource(),
pluralDomainPath,
pluralDomainPath.nodeBuilder()
@ -50,7 +50,8 @@ public class SqmIndexedCollectionAccessPath<T> extends AbstractSqmPath<T> implem
@Override
public NavigablePath getNavigablePath() {
// todo (6.0) : this would require some String-ified form of the selector
return null;
// return null;
return super.getNavigablePath();
}
@Override

View File

@ -23,7 +23,7 @@ public class SqmMaxElementPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
public SqmMaxElementPath(SqmPath<?> pluralDomainPath) {
//noinspection unchecked
super(
pluralDomainPath.getNavigablePath().append( NAVIGABLE_NAME ),
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
pluralDomainPath,
(PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource()
);

View File

@ -25,7 +25,7 @@ public class SqmMaxIndexPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
public SqmMaxIndexPath(SqmPath<?> pluralDomainPath) {
//noinspection unchecked
super(
pluralDomainPath.getNavigablePath().append( NAVIGABLE_NAME ),
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
pluralDomainPath,
(PluralPersistentAttribute<?, ?, T>) pluralDomainPath.getReferencedPathSource()
);

View File

@ -23,7 +23,7 @@ public class SqmMinElementPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
public SqmMinElementPath(SqmPath<?> pluralDomainPath) {
//noinspection unchecked
super(
pluralDomainPath.getNavigablePath().append( NAVIGABLE_NAME ),
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
pluralDomainPath,
(PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource()
);

View File

@ -25,7 +25,7 @@ public class SqmMinIndexPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
public SqmMinIndexPath(SqmPath<?> pluralDomainPath) {
//noinspection unchecked
super(
pluralDomainPath.getNavigablePath().append( NAVIGABLE_NAME ),
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ),
pluralDomainPath,
(PluralPersistentAttribute<?, ?, T>) pluralDomainPath.getReferencedPathSource()
);

View File

@ -85,7 +85,7 @@ public class SqmJpaCompoundSelection<T>
}
@Override
public List<? extends JpaSelection<?>> getSelectionItems() {
public List<SqmSelectableNode<?>> getSelectionItems() {
return selectableNodes;
}

View File

@ -315,7 +315,9 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
@SuppressWarnings("unchecked")
public SqmSelectStatement<T> select(Selection<? extends T> selection) {
getQuerySpec().setSelection( (JpaSelection<T>) selection );
setResultType( (Class<T>) selection.getJavaType() );
if ( getResultType() == null ) {
setResultType( (Class<T>) selection.getJavaType() );
}
return this;
}
@ -324,7 +326,9 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
for ( Selection<?> selection : selections ) {
getQuerySpec().getSelectClause().add( (SqmExpression<?>) selection, selection.getAlias() );
}
setResultType( (Class<T>) Object[].class );
if ( getResultType() == null ) {
setResultType( (Class<T>) Object[].class );
}
return this;
}
@ -333,7 +337,9 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
for ( Selection<?> selection : selectionList ) {
getQuerySpec().getSelectClause().add( (SqmExpression<?>) selection, selection.getAlias() );
}
setResultType( (Class<T>) Object[].class );
if ( getResultType() == null ) {
setResultType( (Class<T>) Object[].class );
}
return this;
}

View File

@ -38,10 +38,14 @@ import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.query.ComparisonOperator;
@ -2650,11 +2654,27 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
appendSql( ( (Loadable) tableGroup.getModelPart() ).getIdentifierColumnNames()[0] );
}
else if ( modelPart instanceof PluralAttributeMapping ) {
CollectionPart elementDescriptor = ( (PluralAttributeMapping) modelPart ).getElementDescriptor();
final CollectionPart elementDescriptor = ( (PluralAttributeMapping) modelPart ).getElementDescriptor();
if ( elementDescriptor instanceof BasicValuedCollectionPart ) {
String mappedColumnExpression = ( (BasicValuedCollectionPart) elementDescriptor ).getSelectionExpression();
appendSql( mappedColumnExpression );
}
else if ( elementDescriptor instanceof EntityCollectionPart ) {
final ForeignKeyDescriptor foreignKeyDescriptor = ( (EntityCollectionPart) elementDescriptor ).getForeignKeyDescriptor();
if ( foreignKeyDescriptor instanceof SimpleForeignKeyDescriptor ) {
foreignKeyDescriptor.visitTargetColumns(
(selectionIndex, selectionMapping) -> appendSql( selectionMapping.getSelectionExpression() )
);
}
}
}
else if ( modelPart instanceof ToOneAttributeMapping ) {
final ForeignKeyDescriptor foreignKeyDescriptor = ( (ToOneAttributeMapping) modelPart ).getForeignKeyDescriptor();
if ( foreignKeyDescriptor instanceof SimpleForeignKeyDescriptor ) {
foreignKeyDescriptor.visitTargetColumns(
(selectionIndex, selectionMapping) -> appendSql( selectionMapping.getSelectionExpression() )
);
}
}
else {
throw new NotYetImplementedFor6Exception( getClass() );
@ -3190,7 +3210,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
@Override
public void visitCaseSimpleExpression(CaseSimpleExpression caseSimpleExpression) {
appendSql( "case" );
appendSql( "case " );
caseSimpleExpression.getFixture().accept( this );
for ( CaseSimpleExpression.WhenFragment whenFragment : caseSimpleExpression.getWhenFragments() ) {
appendSql( " when " );

View File

@ -16,6 +16,8 @@ import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
@ -57,17 +59,16 @@ public class CaseSimpleExpression implements Expression, DomainResultProducer {
public DomainResult createDomainResult(
String resultVariable,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
// return new BasicResultImpl(
// resultVariable,
// creationState.getSqlExpressionResolver().resolveSqlSelection(
// this,
// getType().getJavaTypeDescriptor(),
// creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
// ),
// getType()
// );
final JavaTypeDescriptor javaTypeDescriptor = type.getJdbcMappings().get( 0 ).getJavaTypeDescriptor();
return new BasicResult(
creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(
this,
javaTypeDescriptor,
creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
).getValuesArrayPosition(),
resultVariable,
javaTypeDescriptor
);
}
public List<WhenFragment> getWhenFragments() {

View File

@ -7,9 +7,7 @@
package org.hibernate.sql.results.internal;
import java.util.List;
import javax.persistence.Tuple;
import javax.persistence.TupleElement;
import org.hibernate.sql.results.spi.RowTransformer;
@ -19,15 +17,15 @@ import org.hibernate.sql.results.spi.RowTransformer;
* @author Steve Ebersole
*/
public class RowTransformerJpaTupleImpl implements RowTransformer<Tuple> {
private final List<TupleElement<?>> tupleElements;
private final TupleMetadata tupleMetadata;
public RowTransformerJpaTupleImpl(List<TupleElement<?>> tupleElements) {
this.tupleElements = tupleElements;
public RowTransformerJpaTupleImpl(TupleMetadata tupleMetadata) {
this.tupleMetadata = tupleMetadata;
}
@Override
public Tuple transformRow(Object[] row) {
return new TupleImpl( tupleElements, row );
return new TupleImpl( tupleMetadata, row );
}
@Override

View File

@ -17,19 +17,19 @@ import org.hibernate.query.JpaTuple;
* @author Steve Ebersole
*/
public class TupleImpl implements JpaTuple {
private final List<TupleElement<?>> tupleElements;
private final TupleMetadata tupleMetadata;
private final Object[] row;
public TupleImpl(List<TupleElement<?>> tupleElements, Object[] row) {
this.tupleElements = tupleElements;
public TupleImpl(TupleMetadata tupleMetadata, Object[] row) {
this.tupleMetadata = tupleMetadata;
this.row = row;
}
@Override
@SuppressWarnings("unchecked")
public <X> X get(TupleElement<X> tupleElement) {
int index = tupleElements.indexOf( tupleElement );
if ( index < 0 ) {
final Integer index = tupleMetadata.get( tupleElement );
if ( index == null ) {
throw new IllegalArgumentException(
"Requested tuple element did not correspond to element in the result tuple"
);
@ -59,21 +59,8 @@ public class TupleImpl implements JpaTuple {
@Override
public Object get(String alias) {
int index = -1;
if ( alias != null ) {
alias = alias.trim();
if ( alias.length() > 0 ) {
int i = 0;
for ( TupleElement selection : tupleElements ) {
if ( alias.equals( selection.getAlias() ) ) {
index = i;
break;
}
i++;
}
}
}
if ( index < 0 ) {
Integer index = tupleMetadata.get( alias );
if ( index == null ) {
throw new IllegalArgumentException(
"Given alias [" + alias + "] did not correspond to an element in the result tuple"
);
@ -115,8 +102,7 @@ public class TupleImpl implements JpaTuple {
}
@Override
@SuppressWarnings("unchecked")
public List<TupleElement<?>> getElements() {
return tupleElements;
return tupleMetadata.getList();
}
}

View File

@ -0,0 +1,58 @@
/*
* 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 java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.TupleElement;
/**
* Metadata about the tuple structure.
*
* @author Christian Beikov
*/
public final class TupleMetadata {
private final Map<TupleElement<?>, Integer> index;
private Map<String, Integer> nameIndex;
private List<TupleElement<?>> list;
public TupleMetadata(Map<TupleElement<?>, Integer> index) {
this.index = index;
}
public Integer get(TupleElement<?> tupleElement) {
return index.get( tupleElement );
}
public Integer get(String name) {
Map<String, Integer> nameIndex = this.nameIndex;
if ( nameIndex == null ) {
nameIndex = new HashMap<>( index.size() );
for ( Map.Entry<TupleElement<?>, Integer> entry : index.entrySet() ) {
nameIndex.put( entry.getKey().getAlias(), entry.getValue() );
}
this.nameIndex = nameIndex = Collections.unmodifiableMap( nameIndex );
}
return nameIndex.get( name );
}
public List<TupleElement<?>> getList() {
List<TupleElement<?>> list = this.list;
if ( list == null ) {
final TupleElement<?>[] array = new TupleElement[index.size()];
for ( Map.Entry<TupleElement<?>, Integer> entry : index.entrySet() ) {
array[entry.getValue()] = entry.getKey();
}
this.list = list = Collections.unmodifiableList( Arrays.asList( array ) );
}
return list;
}
}

View File

@ -138,7 +138,7 @@ public interface JdbcTypeDescriptor extends Serializable {
}
default boolean isTemporal() {
switch ( getSqlType() ) {
switch ( getJdbcType() ) {
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:

View File

@ -168,7 +168,7 @@ public class FunctionTests {
assertThat( session.createQuery("select round(32.12345,2)").getSingleResult(), is(32.12f) );
assertThat( session.createQuery("select mod(3,2)").getSingleResult(), is(1) );
assertThat( session.createQuery("select 3%2").getSingleResult(), is(1) );
assertThat( session.createQuery("select sqrt(9.0)").getSingleResult(), is(3.0f) );
assertThat( session.createQuery("select sqrt(9.0)").getSingleResult(), is(3.0d) );
}
);
}