/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.consume.spi;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.persister.entity.spi.EntityPersister;
import org.hibernate.persister.queryable.spi.EntityValuedExpressableType;
import org.hibernate.persister.queryable.spi.PolymorphicEntityValuedExpressableType;
import org.hibernate.query.sqm.ParsingException;
import org.hibernate.query.sqm.produce.internal.NavigableBindingHelper;
import org.hibernate.query.sqm.tree.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.SqmQuerySpec;
import org.hibernate.query.sqm.tree.SqmSelectStatement;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.SqmUpdateStatement;
import org.hibernate.query.sqm.tree.expression.BinaryArithmeticSqmExpression;
import org.hibernate.query.sqm.tree.expression.ConcatSqmExpression;
import org.hibernate.query.sqm.tree.expression.ConstantEnumSqmExpression;
import org.hibernate.query.sqm.tree.expression.ConstantFieldSqmExpression;
import org.hibernate.query.sqm.tree.expression.EntityTypeLiteralSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralBigDecimalSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralBigIntegerSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralCharacterSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralDoubleSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralFalseSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralFloatSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralIntegerSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralLongSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralNullSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralStringSqmExpression;
import org.hibernate.query.sqm.tree.expression.LiteralTrueSqmExpression;
import org.hibernate.query.sqm.tree.expression.NamedParameterSqmExpression;
import org.hibernate.query.sqm.tree.expression.PositionalParameterSqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SubQuerySqmExpression;
import org.hibernate.query.sqm.tree.expression.UnaryOperationSqmExpression;
import org.hibernate.query.sqm.tree.expression.domain.SqmAttributeReference;
import org.hibernate.query.sqm.tree.expression.domain.SqmNavigableReference;
import org.hibernate.query.sqm.tree.expression.domain.SqmNavigableSourceReference;
import org.hibernate.query.sqm.tree.expression.domain.SqmPluralAttributeReference;
import org.hibernate.query.sqm.tree.expression.domain.SqmSingularAttributeReference;
import org.hibernate.query.sqm.tree.expression.function.AvgFunctionSqmExpression;
import org.hibernate.query.sqm.tree.expression.function.ConcatFunctionSqmExpression;
import org.hibernate.query.sqm.tree.expression.function.CountFunctionSqmExpression;
import org.hibernate.query.sqm.tree.expression.function.CountStarFunctionSqmExpression;
import org.hibernate.query.sqm.tree.expression.function.GenericFunctionSqmExpression;
import org.hibernate.query.sqm.tree.expression.function.MaxFunctionSqmExpression;
import org.hibernate.query.sqm.tree.expression.function.MinFunctionSqmExpression;
import org.hibernate.query.sqm.tree.expression.function.SumFunctionSqmExpression;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmFromClause;
import org.hibernate.query.sqm.tree.from.SqmFromElementSpace;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.internal.SqmSelectStatementImpl;
import org.hibernate.query.sqm.tree.order.SqmOrderByClause;
import org.hibernate.query.sqm.tree.order.SqmSortSpecification;
import org.hibernate.query.sqm.tree.paging.SqmLimitOffsetClause;
import org.hibernate.query.sqm.tree.predicate.AndSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.BetweenSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.EmptinessSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.GroupedSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.InListSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.InSubQuerySqmPredicate;
import org.hibernate.query.sqm.tree.predicate.LikeSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.MemberOfSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.NegatedSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.NullnessSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.OrSqmPredicate;
import org.hibernate.query.sqm.tree.predicate.RelationalSqmPredicate;
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.SqmDynamicInstantiationArgument;
import org.hibernate.query.sqm.tree.select.SqmSelectClause;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.query.sqm.tree.set.SqmAssignment;
import org.hibernate.query.sqm.tree.set.SqmSetClause;
/**
* Handles splitting queries containing unmapped polymorphic references.
*
* @author Steve Ebersole
*/
public class QuerySplitter {
public static SqmSelectStatement[] split(SqmSelectStatement statement) {
// We only allow unmapped polymorphism in a very restricted way. Specifically,
// the unmapped polymorphic reference can only be a root and can be the only
// root. Use that restriction to locate the unmapped polymorphic reference
SqmRoot unmappedPolymorphicReference = null;
for ( SqmFromElementSpace fromElementSpace : statement.getQuerySpec().getFromClause().getFromElementSpaces() ) {
if ( PolymorphicEntityValuedExpressableType.class.isInstance( fromElementSpace.getRoot().getBinding().getReferencedNavigable() ) ) {
unmappedPolymorphicReference = fromElementSpace.getRoot();
}
}
if ( unmappedPolymorphicReference == null ) {
return new SqmSelectStatement[] { statement };
}
final PolymorphicEntityValuedExpressableType<?> unmappedPolymorphicDescriptor = (PolymorphicEntityValuedExpressableType) unmappedPolymorphicReference.getBinding().getReferencedNavigable();
final SqmSelectStatement[] expanded = new SqmSelectStatement[ unmappedPolymorphicDescriptor.getImplementors().size() ];
int i = -1;
for ( EntityPersister<?> mappedDescriptor : unmappedPolymorphicDescriptor.getImplementors() ) {
i++;
final UnmappedPolymorphismReplacer replacer = new UnmappedPolymorphismReplacer(
statement,
unmappedPolymorphicReference,
mappedDescriptor
);
expanded[i] = replacer.visitSelectStatement( statement );
}
return expanded;
}
@SuppressWarnings("unchecked")
private static class UnmappedPolymorphismReplacer extends BaseSemanticQueryWalker {
private final SqmRoot unmappedPolymorphicFromElement;
private final EntityValuedExpressableType mappedDescriptor;
private Map<SqmFrom,SqmFrom> sqmFromSqmCopyMap = new HashMap<>();
private Map<SqmNavigableReference, SqmNavigableReference> navigableBindingCopyMap = new HashMap<>();
private UnmappedPolymorphismReplacer(
SqmSelectStatement selectStatement,
SqmRoot unmappedPolymorphicFromElement,
EntityValuedExpressableType mappedDescriptor) {
this.unmappedPolymorphicFromElement = unmappedPolymorphicFromElement;
this.mappedDescriptor = mappedDescriptor;
}
@Override
public SqmStatement visitStatement(SqmStatement statement) {
throw new UnsupportedOperationException( "Not valid" );
}
@Override
public SqmUpdateStatement visitUpdateStatement(SqmUpdateStatement statement) {
throw new UnsupportedOperationException( "Not valid" );
}
@Override
public SqmSetClause visitSetClause(SqmSetClause setClause) {
throw new UnsupportedOperationException( "Not valid" );
}
@Override
public SqmAssignment visitAssignment(SqmAssignment assignment) {
throw new UnsupportedOperationException( "Not valid" );
}
@Override
public SqmDeleteStatement visitDeleteStatement(SqmDeleteStatement statement) {
throw new UnsupportedOperationException( "Not valid" );
}
@Override
public SqmSelectStatement visitSelectStatement(SqmSelectStatement statement) {
final SqmSelectStatementImpl copy = new SqmSelectStatementImpl();
copy.applyQuerySpec( visitQuerySpec( statement.getQuerySpec() ) );
return copy;
}
@Override
public SqmQuerySpec visitQuerySpec(SqmQuerySpec querySpec) {
// NOTE : it is important that we visit the SqmFromClause first so that the
// fromElementCopyMap gets built before other parts of the queryspec
// are visited
return new SqmQuerySpec(
visitFromClause( querySpec.getFromClause() ),
visitSelectClause( querySpec.getSelectClause() ),
visitWhereClause( querySpec.getWhereClause() ),
visitOrderByClause( querySpec.getOrderByClause() ),
visitLimitOffsetClause( querySpec.getLimitOffsetClause() )
);
}
private SqmFromClause currentFromClauseCopy = null;
@Override
public SqmFromClause visitFromClause(SqmFromClause fromClause) {
final SqmFromClause previousCurrent = currentFromClauseCopy;
try {
SqmFromClause copy = new SqmFromClause();
currentFromClauseCopy = copy;
super.visitFromClause( fromClause );
return copy;
}
finally {
currentFromClauseCopy = previousCurrent;
}
}
private SqmFromElementSpace currentFromElementSpaceCopy;
@Override
public SqmFromElementSpace visitFromElementSpace(SqmFromElementSpace fromElementSpace) {
if ( currentFromClauseCopy == null ) {
throw new ParsingException( "Current SqmFromClause copy was null" );
}
final SqmFromElementSpace previousCurrent = currentFromElementSpaceCopy;
try {
SqmFromElementSpace copy = currentFromClauseCopy.makeFromElementSpace();
currentFromElementSpaceCopy = copy;
super.visitFromElementSpace( fromElementSpace );
return copy;
}
finally {
currentFromElementSpaceCopy = previousCurrent;
}
}
// todo : it is really the bindings we want to keep track of..
@Override
public SqmRoot visitRootEntityFromElement(SqmRoot rootEntityFromElement) {
final SqmNavigableSourceReference existingCopy = (SqmNavigableSourceReference) navigableBindingCopyMap.get( rootEntityFromElement.getBinding() );
if ( existingCopy != null ) {
return (SqmRoot) existingCopy.getExportedFromElement();
}
if ( currentFromElementSpaceCopy == null ) {
throw new ParsingException( "Current FromElementSpace copy was null" );
}
if ( currentFromElementSpaceCopy.getRoot() != null ) {
throw new ParsingException( "FromElementSpace copy already contains root." );
}
final SqmRoot copy;
if ( rootEntityFromElement == unmappedPolymorphicFromElement ) {
copy = new SqmRoot(
currentFromElementSpaceCopy,
rootEntityFromElement.getUniqueIdentifier(),
rootEntityFromElement.getIdentificationVariable(),
mappedDescriptor
);
}
else {
copy = new SqmRoot(
currentFromElementSpaceCopy,
rootEntityFromElement.getUniqueIdentifier(),
rootEntityFromElement.getIdentificationVariable(),
rootEntityFromElement.getBinding().getReferencedNavigable()
);
}
navigableBindingCopyMap.put( rootEntityFromElement.getBinding(), copy.getBinding() );
return copy;
}
@Override
public SqmCrossJoin visitCrossJoinedFromElement(SqmCrossJoin joinedFromElement) {
final SqmNavigableSourceReference existingCopy = (SqmNavigableSourceReference) navigableBindingCopyMap.get( joinedFromElement.getBinding() );
if ( existingCopy != null ) {
return (SqmCrossJoin) existingCopy.getExportedFromElement();
}
if ( currentFromElementSpaceCopy == null ) {
throw new ParsingException( "Current FromElementSpace copy was null" );
}
final SqmCrossJoin copy = new SqmCrossJoin(
currentFromElementSpaceCopy,
joinedFromElement.getUniqueIdentifier(),
joinedFromElement.getIdentificationVariable(),
joinedFromElement.getBinding().getReferencedNavigable()
);
navigableBindingCopyMap.put( joinedFromElement.getBinding(), copy.getBinding() );
return copy;
}
@Override
public SqmEntityJoin visitQualifiedEntityJoinFromElement(SqmEntityJoin joinedFromElement) {
final SqmNavigableSourceReference existingCopy = (SqmNavigableSourceReference) navigableBindingCopyMap.get( joinedFromElement.getBinding() );
if ( existingCopy != null ) {
return (SqmEntityJoin) existingCopy.getExportedFromElement();
}
if ( currentFromElementSpaceCopy == null ) {
throw new ParsingException( "Current FromElementSpace copy was null" );
}
final SqmEntityJoin copy = new SqmEntityJoin(
currentFromElementSpaceCopy,
joinedFromElement.getUniqueIdentifier(),
joinedFromElement.getIdentificationVariable(),
joinedFromElement.getBinding().getReferencedNavigable(),
joinedFromElement.getJoinType()
);
navigableBindingCopyMap.put( joinedFromElement.getBinding(), copy.getBinding() );
return copy;
}
@Override
public SqmAttributeJoin visitQualifiedAttributeJoinFromElement(SqmAttributeJoin joinedFromElement) {
final SqmSingularAttributeReference existingCopy = (SqmSingularAttributeReference) navigableBindingCopyMap.get( joinedFromElement.getBinding() );
if ( existingCopy != null ) {
return (SqmAttributeJoin) existingCopy.getExportedFromElement();
}
if ( currentFromElementSpaceCopy == null ) {
throw new ParsingException( "Current FromElementSpace copy was null" );
}
if ( joinedFromElement.getAttributeBinding().getExportedFromElement() == null ) {
throw new ParsingException( "Could not determine attribute join's LHS for copy" );
}
return makeCopy( joinedFromElement );
}
private SqmAttributeJoin makeCopy(SqmAttributeJoin fromElement) {
assert fromElement.getAttributeBinding().getSourceReference() != null;
if ( fromElement == null ) {
return null;
}
final SqmNavigableSourceReference sourceBindingCopy = (SqmNavigableSourceReference) navigableBindingCopyMap.get(
fromElement.getAttributeBinding().getSourceReference()
);
if ( sourceBindingCopy == null ) {
throw new ParsingException( "Could not determine attribute join's LHS for copy" );
}
assert NavigableBindingHelper.resolveExportedFromElement( sourceBindingCopy ).getContainingSpace() == currentFromElementSpaceCopy;
final SqmAttributeReference attributeBindingCopy = (SqmAttributeReference) NavigableBindingHelper.createNavigableBinding(
sourceBindingCopy,
fromElement.getAttributeBinding().getReferencedNavigable()
);
final SqmAttributeJoin copy = new SqmAttributeJoin(
sourceBindingCopy.getExportedFromElement(),
attributeBindingCopy,
fromElement.getUniqueIdentifier(),
fromElement.getIdentificationVariable(),
fromElement.getIntrinsicSubclassIndicator(),
fromElement.getJoinType(),
fromElement.isFetched()
);
navigableBindingCopyMap.put( fromElement.getAttributeBinding(), copy.getAttributeBinding() );
return copy;
}
@Override
public SqmSelectClause visitSelectClause(SqmSelectClause selectClause) {
SqmSelectClause copy = new SqmSelectClause( selectClause.isDistinct() );
for ( SqmSelection selection : selectClause.getSelections() ) {
copy.addSelection( visitSelection( selection ) );
}
return copy;
}
@Override
public SqmSelection visitSelection(SqmSelection selection) {
return new SqmSelection(
(SqmExpression) selection.getExpression().accept( this ),
selection.getAlias()
);
}
@Override
public SqmDynamicInstantiation visitDynamicInstantiation(SqmDynamicInstantiation dynamicInstantiation) {
SqmDynamicInstantiation copy = dynamicInstantiation.makeShallowCopy();
for ( SqmDynamicInstantiationArgument aliasedArgument : dynamicInstantiation.getArguments() ) {
copy.addArgument(
new SqmDynamicInstantiationArgument(
(SqmExpression) aliasedArgument.getExpression().accept( this ),
aliasedArgument.getAlias()
)
);
}
return copy;
}
@Override
public SqmWhereClause visitWhereClause(SqmWhereClause whereClause) {
if ( whereClause == null ) {
return null;
}
return new SqmWhereClause( (SqmPredicate) whereClause.getPredicate().accept( this ) );
}
@Override
public GroupedSqmPredicate visitGroupedPredicate(GroupedSqmPredicate predicate) {
return new GroupedSqmPredicate( (SqmPredicate) predicate.accept( this ) );
}
@Override
public AndSqmPredicate visitAndPredicate(AndSqmPredicate predicate) {
return new AndSqmPredicate(
(SqmPredicate) predicate.getLeftHandPredicate().accept( this ),
(SqmPredicate) predicate.getRightHandPredicate().accept( this )
);
}
@Override
public OrSqmPredicate visitOrPredicate(OrSqmPredicate predicate) {
return new OrSqmPredicate(
(SqmPredicate) predicate.getLeftHandPredicate().accept( this ),
(SqmPredicate) predicate.getRightHandPredicate().accept( this )
);
}
@Override
public RelationalSqmPredicate visitRelationalPredicate(RelationalSqmPredicate predicate) {
return new RelationalSqmPredicate(
predicate.getOperator(),
(SqmExpression) predicate.getLeftHandExpression().accept( this ),
(SqmExpression) predicate.getRightHandExpression().accept( this )
);
}
@Override
public EmptinessSqmPredicate visitIsEmptyPredicate(EmptinessSqmPredicate predicate) {
return new EmptinessSqmPredicate(
(SqmPluralAttributeReference) predicate.getExpression().accept( this ),
predicate.isNegated()
);
}
@Override
public NullnessSqmPredicate visitIsNullPredicate(NullnessSqmPredicate predicate) {
return new NullnessSqmPredicate(
(SqmExpression) predicate.getExpression().accept( this ),
predicate.isNegated()
);
}
@Override
public BetweenSqmPredicate visitBetweenPredicate(BetweenSqmPredicate predicate) {
return new BetweenSqmPredicate(
(SqmExpression) predicate.getExpression().accept( this ),
(SqmExpression) predicate.getLowerBound().accept( this ),
(SqmExpression) predicate.getUpperBound().accept( this ),
predicate.isNegated()
);
}
@Override
public LikeSqmPredicate visitLikePredicate(LikeSqmPredicate predicate) {
return new LikeSqmPredicate(
(SqmExpression) predicate.getMatchExpression().accept( this ),
(SqmExpression) predicate.getPattern().accept( this ),
(SqmExpression) predicate.getEscapeCharacter().accept( this )
);
}
@Override
public MemberOfSqmPredicate visitMemberOfPredicate(MemberOfSqmPredicate predicate) {
final SqmAttributeReference attributeReferenceCopy = resolveAttributeReference( predicate.getPluralAttributeReference() );
// NOTE : no type check b4 cast as it is assumed that the initial SQM producer
// already verified that the path resolves to a plural attribute
return new MemberOfSqmPredicate( (SqmPluralAttributeReference) attributeReferenceCopy );
}
// private DomainReferenceBinding resolveDomainReferenceBinding(DomainReferenceBinding binding) {
// DomainReferenceBinding copy = navigableBindingCopyMap.get( binding );
// if ( copy == null ) {
// copy = makeDomainReferenceBindingCopy( binding );
// navigableBindingCopyMap.put( binding, copy );
// }
// return copy;
// }
// private DomainReferenceBinding makeDomainReferenceBindingCopy(DomainReferenceBinding binding) {
// if ( binding instanceof AttributeBinding ) {
// final AttributeBinding attributeBinding = (AttributeBinding) binding;
// return new AttributeBinding(
// resolveDomainReferenceBinding( attributeBinding.getLhs() ),
// attributeBinding.getBoundDomainReference(),
// attributeBinding.getFromElement()
// );
// }
// else if ( binding instanceof )
// }
// todo (6.0) : broker in SqmNavigableReference instead?
private SqmAttributeReference resolveAttributeReference(SqmAttributeReference attributeBinding) {
// its an attribute join... there has to be a source
assert attributeBinding.getSourceReference() != null;
SqmAttributeReference attributeBindingCopy = (SqmAttributeReference) navigableBindingCopyMap.get( attributeBinding );
if ( attributeBindingCopy == null ) {
attributeBindingCopy = makeCopy( attributeBinding );
}
return attributeBindingCopy;
}
private SqmAttributeReference makeCopy(SqmAttributeReference attributeReference) {
// its an attribute join... there has to be a source
assert attributeReference.getSourceReference() != null;
assert !navigableBindingCopyMap.containsKey( attributeReference );
final SqmAttributeJoin originalJoin = (SqmAttributeJoin) sqmFromSqmCopyMap.get( attributeReference.getExportedFromElement() );
final SqmNavigableSourceReference sourceBindingCopy = (SqmNavigableSourceReference) navigableBindingCopyMap.get(
attributeReference.getSourceReference()
);
if ( sourceBindingCopy == null ) {
throw new ParsingException( "Could not resolve NavigableSourceBinding copy during query splitting" );
}
final SqmSingularAttributeReference attributeBindingCopy = NavigableBindingHelper.createSingularAttributeBinding(
sourceBindingCopy,
attributeReference.getReferencedNavigable()
);
navigableBindingCopyMap.put( attributeReference, attributeBindingCopy );
return attributeBindingCopy;
}
@Override
public NegatedSqmPredicate visitNegatedPredicate(NegatedSqmPredicate predicate) {
return new NegatedSqmPredicate(
(SqmPredicate) predicate.getWrappedPredicate().accept( this )
);
}
@Override
public InListSqmPredicate visitInListPredicate(InListSqmPredicate predicate) {
InListSqmPredicate copy = new InListSqmPredicate(
(SqmExpression) predicate.getTestExpression().accept( this )
);
for ( SqmExpression expression : predicate.getListExpressions() ) {
copy.addExpression( (SqmExpression) expression.accept( this ) );
}
return copy;
}
@Override
public InSubQuerySqmPredicate visitInSubQueryPredicate(InSubQuerySqmPredicate predicate) {
return new InSubQuerySqmPredicate(
(SqmExpression) predicate.getTestExpression().accept( this ),
visitSubQueryExpression( predicate.getSubQueryExpression() )
);
}
@Override
public SqmOrderByClause visitOrderByClause(SqmOrderByClause orderByClause) {
if ( orderByClause == null ) {
return null;
}
SqmOrderByClause copy = new SqmOrderByClause();
for ( SqmSortSpecification sortSpecification : orderByClause.getSortSpecifications() ) {
copy.addSortSpecification( visitSortSpecification( sortSpecification ) );
}
return copy;
}
@Override
public SqmSortSpecification visitSortSpecification(SqmSortSpecification sortSpecification) {
return new SqmSortSpecification(
(SqmExpression) sortSpecification.getSortExpression().accept( this ),
sortSpecification.getCollation(),
sortSpecification.getSortOrder()
);
}
@Override
public SqmLimitOffsetClause visitLimitOffsetClause(SqmLimitOffsetClause limitOffsetClause) {
if ( limitOffsetClause == null ) {
return null;
}
return new SqmLimitOffsetClause(
(SqmExpression) limitOffsetClause.getLimitExpression().accept( this ),
(SqmExpression) limitOffsetClause.getOffsetExpression().accept( this )
);
}
@Override
public PositionalParameterSqmExpression visitPositionalParameterExpression(PositionalParameterSqmExpression expression) {
return new PositionalParameterSqmExpression( expression.getPosition(), expression.allowMultiValuedBinding() );
}
@Override
public NamedParameterSqmExpression visitNamedParameterExpression(NamedParameterSqmExpression expression) {
return new NamedParameterSqmExpression( expression.getName(), expression.allowMultiValuedBinding() );
}
@Override
public EntityTypeLiteralSqmExpression visitEntityTypeLiteralExpression(EntityTypeLiteralSqmExpression expression) {
return new EntityTypeLiteralSqmExpression( expression.getExpressionType() );
}
@Override
public UnaryOperationSqmExpression visitUnaryOperationExpression(UnaryOperationSqmExpression expression) {
return new UnaryOperationSqmExpression(
expression.getOperation(),
(SqmExpression) expression.getOperand().accept( this )
);
}
@Override
public Object visitAttributeReferenceExpression(SqmAttributeReference attributeBinding) {
assert attributeBinding.getSourceReference() != null;
SqmAttributeReference attributeBindingCopy = (SqmAttributeReference) navigableBindingCopyMap.get( attributeBinding );
if ( attributeBindingCopy == null ) {
attributeBindingCopy = (SqmAttributeReference) NavigableBindingHelper.createNavigableBinding(
attributeBinding.getSourceReference(),
attributeBinding.getReferencedNavigable()
);
navigableBindingCopyMap.put( attributeBinding, attributeBindingCopy );
}
return attributeBindingCopy;
}
@Override
public GenericFunctionSqmExpression visitGenericFunction(GenericFunctionSqmExpression expression) {
List<SqmExpression> argumentsCopy = new ArrayList<>();
for ( SqmExpression argument : expression.getArguments() ) {
argumentsCopy.add( (SqmExpression) argument.accept( this ) );
}
return new GenericFunctionSqmExpression(
expression.getFunctionName(),
expression.getExpressionType(),
argumentsCopy
);
}
@Override
public AvgFunctionSqmExpression visitAvgFunction(AvgFunctionSqmExpression expression) {
return new AvgFunctionSqmExpression(
(SqmExpression) expression.getArgument().accept( this ),
expression.isDistinct(),
expression.getExpressionType()
);
}
@Override
public CountStarFunctionSqmExpression visitCountStarFunction(CountStarFunctionSqmExpression expression) {
return new CountStarFunctionSqmExpression(
expression.isDistinct(),
expression.getExpressionType()
);
}
@Override
public CountFunctionSqmExpression visitCountFunction(CountFunctionSqmExpression expression) {
return new CountFunctionSqmExpression(
(SqmExpression) expression.getArgument().accept( this ),
expression.isDistinct(),
expression.getExpressionType()
);
}
@Override
public MaxFunctionSqmExpression visitMaxFunction(MaxFunctionSqmExpression expression) {
return new MaxFunctionSqmExpression(
(SqmExpression) expression.getArgument().accept( this ),
expression.isDistinct(),
expression.getExpressionType()
);
}
@Override
public MinFunctionSqmExpression visitMinFunction(MinFunctionSqmExpression expression) {
return new MinFunctionSqmExpression(
(SqmExpression) expression.getArgument().accept( this ),
expression.isDistinct(),
expression.getExpressionType()
);
}
@Override
public SumFunctionSqmExpression visitSumFunction(SumFunctionSqmExpression expression) {
return new SumFunctionSqmExpression(
(SqmExpression) expression.getArgument().accept( this ),
expression.isDistinct(),
expression.getExpressionType()
);
}
@Override
public LiteralStringSqmExpression visitLiteralStringExpression(LiteralStringSqmExpression expression) {
return new LiteralStringSqmExpression( expression.getLiteralValue(), expression.getExpressionType() );
}
@Override
public LiteralCharacterSqmExpression visitLiteralCharacterExpression(LiteralCharacterSqmExpression expression) {
return new LiteralCharacterSqmExpression( expression.getLiteralValue(), expression.getExpressionType() );
}
@Override
public LiteralDoubleSqmExpression visitLiteralDoubleExpression(LiteralDoubleSqmExpression expression) {
return new LiteralDoubleSqmExpression( expression.getLiteralValue(), expression.getExpressionType() );
}
@Override
public LiteralIntegerSqmExpression visitLiteralIntegerExpression(LiteralIntegerSqmExpression expression) {
return new LiteralIntegerSqmExpression( expression.getLiteralValue(), expression.getExpressionType() );
}
@Override
public LiteralBigIntegerSqmExpression visitLiteralBigIntegerExpression(LiteralBigIntegerSqmExpression expression) {
return new LiteralBigIntegerSqmExpression( expression.getLiteralValue(), expression.getExpressionType() );
}
@Override
public LiteralBigDecimalSqmExpression visitLiteralBigDecimalExpression(LiteralBigDecimalSqmExpression expression) {
return new LiteralBigDecimalSqmExpression( expression.getLiteralValue(), expression.getExpressionType() );
}
@Override
public LiteralFloatSqmExpression visitLiteralFloatExpression(LiteralFloatSqmExpression expression) {
return new LiteralFloatSqmExpression( expression.getLiteralValue(), expression.getExpressionType() );
}
@Override
public LiteralLongSqmExpression visitLiteralLongExpression(LiteralLongSqmExpression expression) {
return new LiteralLongSqmExpression( expression.getLiteralValue(), expression.getExpressionType() );
}
@Override
public LiteralTrueSqmExpression visitLiteralTrueExpression(LiteralTrueSqmExpression expression) {
return new LiteralTrueSqmExpression( expression.getExpressionType() );
}
@Override
public LiteralFalseSqmExpression visitLiteralFalseExpression(LiteralFalseSqmExpression expression) {
return new LiteralFalseSqmExpression( expression.getExpressionType() );
}
@Override
public LiteralNullSqmExpression visitLiteralNullExpression(LiteralNullSqmExpression expression) {
return new LiteralNullSqmExpression();
}
@Override
public ConcatSqmExpression visitConcatExpression(ConcatSqmExpression expression) {
return new ConcatSqmExpression(
(SqmExpression) expression.getLeftHandOperand().accept( this ),
(SqmExpression) expression.getRightHandOperand().accept( this )
);
}
@Override
public ConcatFunctionSqmExpression visitConcatFunction(ConcatFunctionSqmExpression expression) {
final List<SqmExpression> arguments = new ArrayList<>();
for ( SqmExpression argument : expression.getExpressions() ) {
arguments.add( (SqmExpression) argument.accept( this ) );
}
return new ConcatFunctionSqmExpression(
expression.getFunctionResultType(),
arguments
);
}
@Override
@SuppressWarnings("unchecked")
public ConstantEnumSqmExpression visitConstantEnumExpression(ConstantEnumSqmExpression expression) {
return new ConstantEnumSqmExpression( expression.getValue(), expression.getExpressionType() );
}
@Override
@SuppressWarnings("unchecked")
public ConstantFieldSqmExpression visitConstantFieldExpression(ConstantFieldSqmExpression expression) {
return new ConstantFieldSqmExpression( expression.getSourceField(), expression.getValue(), expression.getExpressionType() );
}
@Override
public BinaryArithmeticSqmExpression visitBinaryArithmeticExpression(BinaryArithmeticSqmExpression expression) {
return new BinaryArithmeticSqmExpression(
expression.getOperation(),
(SqmExpression) expression.getLeftHandOperand().accept( this ),
(SqmExpression) expression.getRightHandOperand().accept( this ),
expression.getExpressionType()
);
}
@Override
public SubQuerySqmExpression visitSubQueryExpression(SubQuerySqmExpression expression) {
return new SubQuerySqmExpression(
visitQuerySpec( expression.getQuerySpec() ),
// assume already validated
expression.getQuerySpec().getSelectClause().getSelections().get( 0 ).getExpression().getExpressionType()
);
}
}
}