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:
parent
46a16c605a
commit
e22dc55adb
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
|
|
|
@ -85,7 +85,7 @@ public class SqmJpaCompoundSelection<T>
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<? extends JpaSelection<?>> getSelectionItems() {
|
||||
public List<SqmSelectableNode<?>> getSelectionItems() {
|
||||
return selectableNodes;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 " );
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue