HHH-15390 Calling SqmQuery#getSqmStatement()#toHqlString() causes ClassCastExpection when using distinct in Criteria or HQL query

This commit is contained in:
Andrea Boriero 2022-07-08 17:07:02 +02:00 committed by Andrea Boriero
parent fac6b0c1f7
commit 35fb490aaa
15 changed files with 68 additions and 65 deletions

View File

@ -19,10 +19,8 @@ import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmAggregateFunction;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.predicate.Predicate;
/**
* @author Christian Beikov
@ -107,14 +105,16 @@ public class SelfRenderingSqmAggregateFunction<T> extends SelfRenderingSqmFuncti
sb.append( '(' );
int i = 1;
if ( arguments.get( 0 ) instanceof SqmDistinct<?> ) {
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( ' ' );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
i = 2;
arguments.get( 0 ).appendHqlString( sb );
if ( arguments.size() > 1 ) {
sb.append( ' ' );
arguments.get( 1 ).appendHqlString( sb );
i = 2;
}
}
for ( ; i < arguments.size(); i++ ) {
sb.append(", ");
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
arguments.get( i ).appendHqlString( sb );
}
sb.append( ')' );

View File

@ -21,12 +21,10 @@ import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmOrderedSetAggregateFunction;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmOrderByClause;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.SortSpecification;
/**
@ -145,14 +143,16 @@ public class SelfRenderingSqmOrderedSetAggregateFunction<T> extends SelfRenderin
sb.append( '(' );
int i = 1;
if ( arguments.get( 0 ) instanceof SqmDistinct<?> ) {
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( ' ' );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
i = 2;
arguments.get( 0 ).appendHqlString( sb );
if ( arguments.size() > 1 ) {
sb.append( ' ' );
arguments.get( 1 ).appendHqlString( sb );
i = 2;
}
}
for ( ; i < arguments.size(); i++ ) {
sb.append(", ");
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
arguments.get( i ).appendHqlString( sb );
}
sb.append( ')' );

View File

@ -19,10 +19,8 @@ import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmWindowFunction;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.sql.ast.tree.SqlAstNode;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.predicate.Predicate;
/**
* @author Christian Beikov
@ -127,14 +125,16 @@ public class SelfRenderingSqmWindowFunction<T> extends SelfRenderingSqmFunction<
sb.append( '(' );
int i = 1;
if ( arguments.get( 0 ) instanceof SqmDistinct<?> ) {
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( ' ' );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
i = 2;
arguments.get( 0 ).appendHqlString( sb );
if ( arguments.size() > 1 ) {
sb.append( ' ' );
arguments.get( 1 ).appendHqlString( sb );
i = 2;
}
}
for ( ; i < arguments.size(); i++ ) {
sb.append(", ");
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
arguments.get( i ).appendHqlString( sb );
}
sb.append( ')' );

View File

@ -83,7 +83,6 @@ import org.hibernate.metamodel.mapping.SelectableMappings;
import org.hibernate.metamodel.mapping.SqlExpressible;
import org.hibernate.metamodel.mapping.SqlTypedMapping;
import org.hibernate.metamodel.mapping.ValueMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.metamodel.mapping.internal.SqlTypedMappingImpl;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
@ -96,7 +95,6 @@ import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.metamodel.model.domain.SimpleDomainType;
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
import org.hibernate.query.derived.AnonymousTupleTableGroupProducer;
import org.hibernate.query.derived.AnonymousTupleType;
@ -323,7 +321,6 @@ import org.hibernate.sql.ast.tree.expression.TrimSpecification;
import org.hibernate.sql.ast.tree.expression.UnaryOperation;
import org.hibernate.sql.ast.tree.from.CorrelatedPluralTableGroup;
import org.hibernate.sql.ast.tree.from.CorrelatedTableGroup;
import org.hibernate.sql.ast.tree.from.LazyTableGroup;
import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.PluralTableGroup;
import org.hibernate.sql.ast.tree.from.QueryPartTableGroup;
@ -332,7 +329,6 @@ import org.hibernate.sql.ast.tree.from.SyntheticVirtualTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.VirtualTableGroup;
import org.hibernate.sql.ast.tree.insert.InsertStatement;
@ -1503,7 +1499,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
if ( selectableNode instanceof SqmPath<?> ) {
prepareForSelection( (SqmPath<?>) selectableNode );
}
final DomainResultProducer<?> argumentResultProducer = (DomainResultProducer<?>) selectableNode.accept( this );
final DomainResultProducer<?> argumentResultProducer = (DomainResultProducer<?>) sqmArgument.accept( this );
dynamicInstantiation.addArgument( sqmArgument.getAlias(), argumentResultProducer, this );
}

View File

@ -15,7 +15,7 @@ import org.hibernate.type.descriptor.java.JavaType;
*
* @author Steve Ebersole
*/
public interface SqmTypedNode<T> extends SqmNode, SqmExpressibleAccessor<T> {
public interface SqmTypedNode<T> extends SqmNode, SqmExpressibleAccessor<T>, SqmVisitableNode {
/**
* The Java type descriptor for this node.
*/

View File

@ -19,7 +19,7 @@ import org.hibernate.query.sqm.tree.SqmVisitableNode;
/**
* @author Gavin King
*/
public class SqmCastTarget<T> extends AbstractSqmNode implements SqmTypedNode<T>, SqmVisitableNode {
public class SqmCastTarget<T> extends AbstractSqmNode implements SqmTypedNode<T> {
private final ReturnableType<T> type;
private final Long length;
private final Integer precision;

View File

@ -12,12 +12,11 @@ import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
/**
* @author Gavin King
*/
public class SqmDistinct<T> extends AbstractSqmNode implements SqmTypedNode<T>, SqmVisitableNode {
public class SqmDistinct<T> extends AbstractSqmNode implements SqmTypedNode<T> {
private final SqmExpression<T> expression;

View File

@ -14,12 +14,11 @@ import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
/**
* @author Gavin King
*/
public class SqmDurationUnit<T> extends AbstractSqmNode implements SqmTypedNode<T>, SqmVisitableNode {
public class SqmDurationUnit<T> extends AbstractSqmNode implements SqmTypedNode<T> {
private final TemporalUnit unit;
private final ReturnableType<T> type;

View File

@ -14,12 +14,11 @@ import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
/**
* @author Gavin King
*/
public class SqmExtractUnit<T> extends AbstractSqmNode implements SqmTypedNode<T>, SqmVisitableNode {
public class SqmExtractUnit<T> extends AbstractSqmNode implements SqmTypedNode<T> {
private final TemporalUnit unit;
private final ReturnableType<T> type;

View File

@ -18,7 +18,6 @@ import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.sql.ast.tree.expression.Expression;
/**
@ -74,38 +73,38 @@ public abstract class SqmFunction<T> extends AbstractSqmExpression<T>
switch ( functionName ) {
case "cast": {
sb.append( "cast(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
sb.append( " as " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
arguments.get( 1 ).appendHqlString( sb );
sb.append( ')' );
break;
}
case "extract": {
sb.append( "extract(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
sb.append( " from " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
arguments.get( 1 ).appendHqlString( sb );
sb.append( ')' );
break;
}
case "format": {
sb.append( "format(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
sb.append( " as " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
arguments.get( 1 ).appendHqlString( sb );
sb.append( ')' );
break;
}
case "overlay": {
sb.append( "overlay(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
sb.append( " placing " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
arguments.get( 1 ).appendHqlString( sb );
sb.append( " from " );
( (SqmSelectableNode<?>) arguments.get( 2 ) ).appendHqlString( sb );
arguments.get( 2 ).appendHqlString( sb );
if ( arguments.size() == 4 ) {
sb.append( " for " );
( (SqmSelectableNode<?>) arguments.get( 3 ) ).appendHqlString( sb );
arguments.get( 3 ).appendHqlString( sb );
}
sb.append( ')' );
break;
@ -114,19 +113,19 @@ public abstract class SqmFunction<T> extends AbstractSqmExpression<T>
sb.append( "trim(" );
switch ( arguments.size() ) {
case 1:
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
break;
case 2:
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
sb.append( " from " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
arguments.get( 1 ).appendHqlString( sb );
break;
case 3:
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
sb.append( ' ' );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
arguments.get( 1 ).appendHqlString( sb );
sb.append( " from " );
( (SqmSelectableNode<?>) arguments.get( 3 ) ).appendHqlString( sb );
arguments.get( 3 ).appendHqlString( sb );
break;
}
sb.append( ')' );
@ -134,20 +133,20 @@ public abstract class SqmFunction<T> extends AbstractSqmExpression<T>
}
case "pad": {
sb.append( "pad(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
sb.append( " with" );
for ( int i = 1; i < arguments.size(); i++ ) {
sb.append( ' ' );
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
arguments.get( i ).appendHqlString( sb );
}
sb.append( ')' );
break;
}
case "position": {
sb.append( "position(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
sb.append( " in " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
arguments.get( 1 ).appendHqlString( sb );
sb.append( ')' );
break;
}
@ -162,7 +161,7 @@ public abstract class SqmFunction<T> extends AbstractSqmExpression<T>
sb.append( '(' );
for ( int i = 1; i < arguments.size(); i++ ) {
sb.append( ", " );
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
arguments.get( i ).appendHqlString( sb );
}
sb.append( ')' );

View File

@ -10,11 +10,9 @@ import org.hibernate.query.sqm.TrimSpec;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
/**
* Needed to pass TrimSpecification as an SqmExpression when we call out to
@ -22,7 +20,7 @@ import org.hibernate.query.sqm.tree.SqmVisitableNode;
*
* @author Steve Ebersole
*/
public class SqmTrimSpecification extends AbstractSqmNode implements SqmTypedNode<Void>, SqmVisitableNode {
public class SqmTrimSpecification extends AbstractSqmNode implements SqmTypedNode<Void> {
private final TrimSpec specification;
public SqmTrimSpecification(TrimSpec specification, NodeBuilder nodeBuilder) {

View File

@ -220,10 +220,10 @@ public class SqmDynamicInstantiation<T>
sb.append( instantiationTarget.getTargetTypeDescriptor().getJavaTypeClass().getTypeName() );
}
sb.append( '(' );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
arguments.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < arguments.size(); i++ ) {
sb.append(", ");
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
arguments.get( i ).appendHqlString( sb );
}
sb.append( ')' );

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.tree.select;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
@ -50,4 +51,17 @@ public class SqmDynamicInstantiationArgument<T> implements SqmAliasedNode<T> {
public NodeBuilder nodeBuilder() {
return nodeBuilder;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return selectableNode.accept( walker );
}
@Override
public void appendHqlString(StringBuilder sb) {
selectableNode.appendHqlString( sb );
if ( alias != null ) {
sb.append( " as " ).append( alias );
}
}
}

View File

@ -12,7 +12,6 @@ import jakarta.persistence.criteria.Selection;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
/**
* Defines a SQM AST node that can be used as a selection in the query,
@ -20,7 +19,7 @@ import org.hibernate.query.sqm.tree.SqmVisitableNode;
*
* @author Steve Ebersole
*/
public interface SqmSelectableNode<T> extends JpaSelection<T>, SqmTypedNode<T>, SqmVisitableNode {
public interface SqmSelectableNode<T> extends JpaSelection<T>, SqmTypedNode<T> {
/**
* Visit each of this selectable's direct sub-selectables - used to
* support JPA's {@link Selection} model (which is really a "selectable",

View File

@ -10,14 +10,13 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
/**
* Represents an individual selection within a select clause.
*
* @author Steve Ebersole
*/
public class SqmSelection<T> extends AbstractSqmNode implements SqmAliasedNode<T>, SqmVisitableNode {
public class SqmSelection<T> extends AbstractSqmNode implements SqmAliasedNode<T> {
private final SqmSelectableNode<T> selectableNode;
private final String alias;