Introduce SqmVisitableNode#appendHqlString to support indexed collection access paths

This commit is contained in:
Christian Beikov 2021-06-22 13:22:20 +02:00
parent 97127fa1c5
commit 8e0864af10
85 changed files with 1184 additions and 12 deletions

View File

@ -1566,7 +1566,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
"where current_date() > key( p.callHistory )", Phone.class )
.getResultList();
//end::hql-collection-expressions-example[]
assertEquals(2, phones.size());
assertEquals( 1, phones.size() );
});
}

View File

@ -144,6 +144,13 @@ public class FullyQualifiedReflectivePathTerminal
public void applyInferableType(SqmExpressable type) {
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( getParent().getFullPath() );
sb.append( '.' );
sb.append( getLocalName() );
}
@Override
public SqmExpression<Long> asLong() {
return null;

View File

@ -13,7 +13,9 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
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.predicate.Predicate;
/**
@ -51,4 +53,29 @@ public class SelfRenderingSqmAggregateFunction<T> extends SelfRenderingSqmFuncti
getMappingModelExpressable( walker, resultType )
);
}
@Override
public void appendHqlString(StringBuilder sb) {
final List<SqmTypedNode<?>> arguments = getArguments();
sb.append( getFunctionName() );
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;
}
for ( ; i < arguments.size(); i++ ) {
sb.append(", ");
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
}
sb.append( ')' );
if ( filter != null ) {
sb.append( " filter (where " );
filter.appendHqlString( sb );
sb.append( ')' );
}
}
}

View File

@ -19,4 +19,12 @@ public interface SqmVisitableNode extends SqmNode {
* Accept the walker per visitation
*/
<X> X accept(SemanticQueryWalker<X> walker);
void appendHqlString(StringBuilder sb);
default String toHqlString() {
StringBuilder sb = new StringBuilder();
appendHqlString( sb );
return sb.toString();
}
}

View File

@ -8,6 +8,10 @@ package org.hibernate.query.sqm.tree.cte;
import java.util.List;
import org.hibernate.query.NullPrecedence;
import org.hibernate.query.SortOrder;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.sql.ast.tree.cte.CteColumn;
import org.hibernate.sql.ast.tree.cte.CteMaterialization;
import org.hibernate.sql.ast.tree.cte.CteSearchClauseKind;
import org.hibernate.query.sqm.NodeBuilder;
@ -15,6 +19,7 @@ import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.AbstractSqmNode;
import org.hibernate.query.sqm.tree.SqmStatement;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
import org.hibernate.sql.ast.tree.cte.SearchClauseSpecification;
/**
* @author Steve Ebersole
@ -112,4 +117,74 @@ public class SqmCteStatement<T> extends AbstractSqmNode implements SqmVisitableN
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitCteStatement( this );
}
public void appendHqlString(StringBuilder sb) {
sb.append( cteTable.getCteName() );
sb.append( " (" );
final List<SqmCteTableColumn> columns = cteTable.getColumns();
sb.append( columns.get( 0 ).getColumnName() );
for ( int i = 1; i < columns.size(); i++ ) {
sb.append( ", " );
sb.append( columns.get( i ).getColumnName() );
}
sb.append( ") as " );
if ( getMaterialization() != CteMaterialization.UNDEFINED ) {
sb.append( getMaterialization() ).append( ' ' );
}
sb.append( '(' );
getCteDefinition().appendHqlString( sb );
sb.append( ')' );
String separator;
if ( getSearchClauseKind() != null ) {
sb.append( " search " );
if ( getSearchClauseKind() == CteSearchClauseKind.DEPTH_FIRST ) {
sb.append( " depth " );
}
else {
sb.append( " breadth " );
}
sb.append( " first by " );
separator = "";
for ( SqmSearchClauseSpecification searchBySpecification : getSearchBySpecifications() ) {
sb.append( separator );
sb.append( searchBySpecification.getCteColumn().getColumnName() );
if ( searchBySpecification.getSortOrder() != null ) {
if ( searchBySpecification.getSortOrder() == SortOrder.ASCENDING ) {
sb.append( " asc" );
}
else {
sb.append( " desc" );
}
if ( searchBySpecification.getNullPrecedence() != null ) {
if ( searchBySpecification.getNullPrecedence() == NullPrecedence.FIRST ) {
sb.append( " nulls first" );
}
else {
sb.append( " nulls last" );
}
}
}
separator = ", ";
}
}
if ( getCycleMarkColumn() != null ) {
sb.append( " cycle " );
separator = "";
for ( SqmCteTableColumn cycleColumn : getCycleColumns() ) {
sb.append( separator );
sb.append( cycleColumn.getColumnName() );
separator = ", ";
}
sb.append( " set " );
sb.append( getCycleMarkColumn().getColumnName() );
sb.append( " to '" );
sb.append( getCycleValue() );
sb.append( "' default '" );
sb.append( getNoCycleValue() );
sb.append( "'" );
}
}
}

View File

@ -36,7 +36,6 @@ public class SqmDeleteStatement<T>
public SqmDeleteStatement(SqmRoot<T> target, SqmQuerySource querySource, NodeBuilder nodeBuilder) {
super( target, querySource, nodeBuilder );
this.querySource = SqmQuerySource.HQL;
}
public SqmDeleteStatement(Class<T> targetEntity, SqmQuerySource querySource, NodeBuilder nodeBuilder) {
@ -122,4 +121,17 @@ public class SqmDeleteStatement<T>
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitDeleteStatement( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "delete from " );
sb.append( getTarget().getEntityName() );
if ( getTarget().getExplicitAlias() != null ) {
sb.append( ' ' ).append( getTarget().getExplicitAlias() );
}
if ( whereClause != null && whereClause.getPredicate() != null ) {
sb.append( " where " );
whereClause.getPredicate().appendHqlString( sb );
}
}
}

View File

@ -597,4 +597,15 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
nodeBuilder()
);
}
@Override
public void appendHqlString(StringBuilder sb) {
if ( alias == null ) {
// If we don't have an alias, this is the best we can do to at least ensure uniqueness
sb.append( "alias_" ).append( System.identityHashCode( this ) );
}
else {
sb.append( alias );
}
}
}

View File

@ -42,4 +42,13 @@ public abstract class AbstractSqmSimplePath<T> extends AbstractSqmPath<T> implem
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public void appendHqlString(StringBuilder sb) {
if ( getLhs() != null ) {
getLhs().appendHqlString( sb );
sb.append( '.' );
}
sb.append( getReferencedPathSource().getPathName() );
}
}

View File

@ -47,4 +47,11 @@ public class SqmBasicValuedEntityTypePath<T> extends SqmBasicValuedSimplePath<T>
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitEntityTypeLiteralExpression( literal );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "type(" );
super.appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -28,7 +28,7 @@ public class SqmIndexedCollectionAccessPath<T> extends AbstractSqmPath<T> implem
SqmExpression<?> selectorExpression) {
//noinspection unchecked
super(
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), "[]" ),
pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), selectorExpression.toHqlString() ),
(PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource(),
pluralDomainPath,
pluralDomainPath.nodeBuilder()
@ -83,4 +83,12 @@ public class SqmIndexedCollectionAccessPath<T> extends AbstractSqmPath<T> implem
throw new UnsupportedOperationException( );
}
@Override
public void appendHqlString(StringBuilder sb) {
getLhs().appendHqlString( sb );
sb.append( '[' );
selectorExpression.appendHqlString( sb );
sb.append( ']' );
}
}

View File

@ -107,6 +107,12 @@ public class SqmMapEntryReference<K,V>
return nodeBuilder;
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "entry(" );
mapPath.appendHqlString( sb );
sb.append( ')' );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA (ugh)

View File

@ -52,4 +52,11 @@ public class SqmMaxElementPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitMaxElementPath( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "maxelement(" );
getLhs().appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -60,4 +60,11 @@ public class SqmMaxIndexPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitMaxIndexPath( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "maxindex(" );
getLhs().appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -52,4 +52,11 @@ public class SqmMinElementPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitMinElementPath( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "minelement(" );
getLhs().appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -61,4 +61,11 @@ public class SqmMinIndexPath<T> extends AbstractSqmSpecificPluralPartPath<T> {
return walker.visitMinIndexPath( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "minindex(" );
getLhs().appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -51,4 +51,13 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
//noinspection unchecked
return new SqmTreatedBagJoin( wrappedPath, treatTarget, getAlias() );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getName() );
sb.append( ')' );
}
}

View File

@ -50,4 +50,13 @@ public class SqmTreatedCrossJoin<T, S extends T> extends SqmCrossJoin<S> impleme
//noinspection unchecked
return (EntityDomainType) wrappedPath.getReferencedPathSource();
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getName() );
sb.append( ')' );
}
}

View File

@ -14,11 +14,11 @@ import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
* @author Steve Ebersole
*/
public class SqmTreatedEntityJoin<T, S extends T> extends SqmEntityJoin<S> implements SqmTreatedPath<T,S> {
private final SqmEntityJoin<T> wrapped;
private final SqmEntityJoin<T> wrappedPath;
private final EntityDomainType<S> treatTarget;
public SqmTreatedEntityJoin(
SqmEntityJoin<T> wrapped,
SqmEntityJoin<T> wrappedPath,
EntityDomainType<S> treatTarget,
String alias,
SqmJoinType joinType) {
@ -26,9 +26,9 @@ public class SqmTreatedEntityJoin<T, S extends T> extends SqmEntityJoin<S> imple
treatTarget,
alias,
joinType,
wrapped.getRoot()
wrappedPath.getRoot()
);
this.wrapped = wrapped;
this.wrappedPath = wrappedPath;
this.treatTarget = treatTarget;
}
@ -39,12 +39,21 @@ public class SqmTreatedEntityJoin<T, S extends T> extends SqmEntityJoin<S> imple
@Override
public SqmPath<T> getWrappedPath() {
return wrapped;
return wrappedPath;
}
@Override
public EntityDomainType<S> getReferencedPathSource() {
//noinspection unchecked
return (EntityDomainType<S>) wrapped.getReferencedPathSource();
return (EntityDomainType<S>) wrappedPath.getReferencedPathSource();
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getName() );
sb.append( ')' );
}
}

View File

@ -66,4 +66,13 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
//noinspection unchecked
return new SqmTreatedListJoin( wrappedPath, treatTarget, getAlias() );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getName() );
sb.append( ')' );
}
}

View File

@ -60,4 +60,13 @@ public class SqmTreatedMapJoin<O,K,V, S extends V> extends SqmMapJoin<O,K,S> imp
getAlias()
);
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getName() );
sb.append( ')' );
}
}

View File

@ -93,4 +93,13 @@ public class SqmTreatedRoot<T, S extends T> extends SqmRoot<S> implements SqmTre
}
);
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getName() );
sb.append( ')' );
}
}

View File

@ -68,4 +68,13 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
//noinspection unchecked
return new SqmTreatedSetJoin( wrappedPath, treatTarget, getAlias() );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getName() );
sb.append( ')' );
}
}

View File

@ -70,4 +70,13 @@ public class SqmTreatedSimplePath<T, S extends T>
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitTreatedPath( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getName() );
sb.append( ')' );
}
}

View File

@ -63,4 +63,13 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
//noinspection unchecked
return new SqmTreatedSingularJoin( wrappedPath, treatTarget, getAlias() );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getName() );
sb.append( ')' );
}
}

View File

@ -135,4 +135,15 @@ public class JpaCriteriaParameter<T>
public NamedCallableQueryMemento.ParameterMemento toMemento() {
throw new UnsupportedOperationException( "ParameterMemento cannot be extracted from Criteria query parameter" );
}
@Override
public void appendHqlString(StringBuilder sb) {
if ( getName() == null ) {
sb.append( value );
}
else {
sb.append( ':' );
sb.append( getName() );
}
}
}

View File

@ -33,4 +33,8 @@ public class SqmAliasedNodeRef extends AbstractSqmExpression<Integer> {
// `BaseSqmToSqlAstConverter#resolveGroupOrOrderByExpression`
throw new UnsupportedOperationException();
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( position );
}
}

View File

@ -32,4 +32,10 @@ public class SqmAny<T> extends AbstractSqmExpression<T> {
return walker.visitAny( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "any " );
subquery.appendHqlString( sb );
}
}

View File

@ -106,4 +106,13 @@ public class SqmBinaryArithmetic<T> extends AbstractSqmExpression<T> implements
return getOperator().toLoggableText( lhsOperand.asLoggableText(), rhsOperand.asLoggableText() );
}
@Override
public void appendHqlString(StringBuilder sb) {
lhsOperand.appendHqlString( sb );
sb.append( ' ' );
sb.append( operator.getOperatorSqlText() );
sb.append( ' ' );
rhsOperand.appendHqlString( sb );
}
}

View File

@ -39,4 +39,10 @@ public class SqmByUnit extends AbstractSqmExpression<Long> {
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitByUnit( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
duration.appendHqlString( sb );
sb.append( " by " );
sb.append( unit.getUnit() );
}
}

View File

@ -110,6 +110,23 @@ public class SqmCaseSearched<R>
}
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "case" );
for ( WhenFragment<R> whenFragment : whenFragments ) {
sb.append( " when " );
whenFragment.predicate.appendHqlString( sb );
sb.append( " then " );
whenFragment.result.appendHqlString( sb );
}
if ( otherwise != null ) {
sb.append( " else " );
otherwise.appendHqlString( sb );
}
sb.append( " end" );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA

View File

@ -118,6 +118,24 @@ public class SqmCaseSimple<T,R>
}
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "case " );
fixture.appendHqlString( sb );
for ( WhenFragment<T, R> whenFragment : whenFragments ) {
sb.append( " when " );
whenFragment.checkValue.appendHqlString( sb );
sb.append( " then " );
whenFragment.result.appendHqlString( sb );
}
if ( otherwise != null ) {
sb.append( " else " );
otherwise.appendHqlString( sb );
}
sb.append( " end" );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA

View File

@ -83,4 +83,23 @@ public class SqmCastTarget<T> extends AbstractSqmNode implements SqmTypedNode<T>
public SqmExpressable getNodeType() {
return type;
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( type.getTypeName() );
if ( length != null ) {
sb.append( '(' );
sb.append( length );
sb.append( ')' );
}
else if ( precision != null ) {
sb.append( '(' );
sb.append( precision );
if ( scale != null ) {
sb.append( ", " );
sb.append( scale );
}
sb.append( ')' );
}
}
}

View File

@ -64,6 +64,17 @@ public class SqmCoalesce<T> extends AbstractSqmExpression<T> implements JpaCoale
return "coalesce(...)";
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "coalesce(" );
arguments.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < arguments.size(); i++ ) {
sb.append(", ");
arguments.get( i ).appendHqlString( sb );
}
sb.append( ')' );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA

View File

@ -35,4 +35,11 @@ public class SqmCollate<T> extends AbstractSqmExpression<T> {
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitCollate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
expression.appendHqlString( sb );
sb.append( " collate " );
sb.append( collation );
}
}

View File

@ -45,6 +45,13 @@ public class SqmCollectionSize extends AbstractSqmExpression<Integer> implements
return "SIZE(" + pluralPath.asLoggableText() + ")";
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "size(" );
pluralPath.appendHqlString( sb );
sb.append( ')' );
}
// @Override
// public DomainResult createDomainResult(
// String resultVariable,

View File

@ -39,4 +39,9 @@ public class SqmDistinct<T> extends AbstractSqmNode implements SqmTypedNode<T>,
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitDistinct(this);
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "distinct" );
}
}

View File

@ -19,8 +19,8 @@ import org.hibernate.query.sqm.tree.SqmVisitableNode;
* @author Gavin King
*/
public class SqmDurationUnit<T> extends AbstractSqmNode implements SqmTypedNode<T>, SqmVisitableNode {
private TemporalUnit unit;
private AllowableFunctionReturnType<T> type;
private final TemporalUnit unit;
private final AllowableFunctionReturnType<T> type;
public SqmDurationUnit(TemporalUnit unit, AllowableFunctionReturnType<T> type, NodeBuilder nodeBuilder) {
super( nodeBuilder );
@ -34,7 +34,7 @@ public class SqmDurationUnit<T> extends AbstractSqmNode implements SqmTypedNode<
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitDurationUnit(this);
return walker.visitDurationUnit( this );
}
public TemporalUnit getUnit() {
@ -45,6 +45,11 @@ public class SqmDurationUnit<T> extends AbstractSqmNode implements SqmTypedNode<
public SqmExpressable<T> getNodeType() {
return type;
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( unit );
}
}

View File

@ -128,4 +128,11 @@ public class SqmEnumLiteral<E extends Enum<E>> extends AbstractSqmExpression<E>
return walker.visitEnumLiteral( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( enumValue.getDeclaringClass().getTypeName() );
sb.append( '.' );
sb.append( enumValueName );
}
}

View File

@ -31,5 +31,10 @@ public class SqmEvery<T> extends AbstractSqmExpression<T> {
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitEvery( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "all " );
subquery.appendHqlString( sb );
}
}

View File

@ -45,6 +45,11 @@ public class SqmExtractUnit<T> extends AbstractSqmNode implements SqmTypedNode<T
public SqmExpressable<T> getNodeType() {
return type;
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( unit );
}
}

View File

@ -119,6 +119,11 @@ public class SqmFieldLiteral<T> implements SqmExpression<T>, SqmExpressable<T>,
return walker.visitFieldLiteral( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
SqmLiteral.appendHqlString( sb, getJavaTypeDescriptor(), getValue() );
}
@Override
public NodeBuilder nodeBuilder() {
return nodeBuilder;

View File

@ -27,4 +27,9 @@ public class SqmFormat extends SqmLiteral<String> {
public <R> R accept(SemanticQueryWalker<R> walker) {
return walker.visitFormat( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( getLiteralValue() );
}
}

View File

@ -17,6 +17,7 @@ import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
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;
import java.util.ArrayList;
@ -68,6 +69,110 @@ public abstract class SqmFunction<T> extends AbstractSqmExpression<T>
return walker.visitFunction( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
// Special case a few functions with special syntax for rendering...
// Unless we introduce dedicated SqmXXX classes that override this method, we have to render it this way
switch ( functionName ) {
case "cast": {
sb.append( "cast(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( " as " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
sb.append( ')' );
break;
}
case "extract": {
sb.append( "extract(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( " from " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
sb.append( ')' );
break;
}
case "format": {
sb.append( "format(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( " as " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
sb.append( ')' );
break;
}
case "overlay": {
sb.append( "overlay(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( " placing " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
sb.append( " from " );
( (SqmSelectableNode<?>) arguments.get( 2 ) ).appendHqlString( sb );
if ( arguments.size() == 4 ) {
sb.append( " for " );
( (SqmSelectableNode<?>) arguments.get( 3 ) ).appendHqlString( sb );
}
sb.append( ')' );
break;
}
case "trim": {
sb.append( "trim(" );
switch ( arguments.size() ) {
case 1:
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
break;
case 2:
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( " from " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
break;
case 3:
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( ' ' );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
sb.append( " from " );
( (SqmSelectableNode<?>) arguments.get( 3 ) ).appendHqlString( sb );
break;
}
sb.append( ')' );
break;
}
case "pad": {
sb.append( "pad(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( " with" );
for ( int i = 1; i < arguments.size(); i++ ) {
sb.append( ' ' );
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
}
sb.append( ')' );
break;
}
case "position": {
sb.append( "position(" );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
sb.append( " in " );
( (SqmSelectableNode<?>) arguments.get( 1 ) ).appendHqlString( sb );
sb.append( ')' );
break;
}
default: {
sb.append( functionName );
if ( arguments.isEmpty() ) {
if ( functionDescriptor.alwaysIncludesParentheses() ) {
sb.append( "()" );
}
return;
}
sb.append( '(' );
for ( int i = 1; i < arguments.size(); i++ ) {
sb.append( ", " );
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
}
sb.append( ')' );
break;
}
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SemanticPathPart

View File

@ -110,6 +110,11 @@ public class SqmJpaCriteriaParameterWrapper<T>
// nothing to do
}
@Override
public void appendHqlString(StringBuilder sb) {
jpaCriteriaParameter.appendHqlString( sb );
}
// @Override
// public Expression toSqlExpression(
// Clause clause,

View File

@ -10,6 +10,7 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Represents a literal value in the sqm, e.g.<ul>
@ -45,4 +46,27 @@ public class SqmLiteral<T>
return "Literal( " + value + ")";
}
@Override
public void appendHqlString(StringBuilder sb) {
appendHqlString( sb, getJavaTypeDescriptor(), value );
}
public static <T> void appendHqlString(StringBuilder sb, JavaTypeDescriptor<T> javaTypeDescriptor, T value) {
final String string = javaTypeDescriptor.toString( value );
if ( javaTypeDescriptor.getJavaTypeClass() == String.class ) {
sb.append( '\'' );
for ( int i = 0; i < string.length(); i++ ) {
final char c = string.charAt( i );
if ( c == '\'' ) {
sb.append( '\'' );
}
sb.append( c );
}
sb.append( '\'' );
}
else {
sb.append( string );
}
}
}

View File

@ -85,4 +85,9 @@ public class SqmLiteralEntityType<T>
throw new HqlInterpretationException( "Cannot dereference an entity name" );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( entityType.getName() );
}
}

View File

@ -36,4 +36,9 @@ public class SqmLiteralNull<T> extends SqmLiteral<T> {
}
private static SqmExpressable NULL_TYPE = () -> null;
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "null" );
}
}

View File

@ -55,4 +55,10 @@ public class SqmNamedParameter<T> extends AbstractSqmParameter<T> {
public SqmParameter<T> copy() {
return new SqmNamedParameter<>( getName(), allowMultiValuedBinding(), this.getNodeType(), nodeBuilder() );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( ':' );
sb.append( getName() );
}
}

View File

@ -41,4 +41,11 @@ public class SqmParameterizedEntityType<T> extends AbstractSqmExpression<T> impl
return walker.visitParameterizedEntityTypeExpression( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "type(" );
discriminatorSource.appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -59,4 +59,10 @@ public class SqmPositionalParameter<T> extends AbstractSqmParameter<T> {
return "?" + getPosition();
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( '?' );
sb.append( getPosition() );
}
}

View File

@ -61,4 +61,12 @@ public class SqmRestrictedSubQueryExpression<T> extends AbstractSqmExpression<T>
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitRestrictedSubQueryExpression( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( modifier );
sb.append( " (" );
subQuery.appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -32,4 +32,9 @@ public class SqmSelfRenderingExpression<T> extends AbstractSqmExpression<T> {
//noinspection unchecked
return (X) renderer.apply( walker );
}
@Override
public void appendHqlString(StringBuilder sb) {
throw new UnsupportedOperationException();
}
}

View File

@ -22,5 +22,9 @@ public class SqmStar extends AbstractSqmExpression<Object> {
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitStar( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "*" );
}
}

View File

@ -43,5 +43,16 @@ public class SqmSummarization<T> extends AbstractSqmExpression<T> {
ROLLUP,
CUBE
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( kind );
sb.append( " (" );
groupings.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < groupings.size(); i++ ) {
sb.append(", ");
groupings.get( i ).appendHqlString( sb );
}
sb.append( ')' );
}
}

View File

@ -44,6 +44,13 @@ public class SqmToDuration<T> extends AbstractSqmExpression<T> {
public String asLoggableText() {
return magnitude.asLoggableText() + " " + unit.getUnit();
}
@Override
public void appendHqlString(StringBuilder sb) {
magnitude.appendHqlString( sb );
sb.append( ' ' );
sb.append( unit.getUnit() );
}
}

View File

@ -46,4 +46,9 @@ public class SqmTrimSpecification extends AbstractSqmNode implements SqmTypedNod
public SqmExpressable getNodeType() {
return null;
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( specification );
}
}

View File

@ -82,6 +82,17 @@ public class SqmTuple<T>
return walker.visitTuple( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( '(' );
groupedExpressions.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < groupedExpressions.size(); i++ ) {
sb.append(", ");
groupedExpressions.get( i ).appendHqlString( sb );
}
sb.append( ')' );
}
@Override
public String asLoggableText() {
return toString();

View File

@ -50,4 +50,9 @@ public class SqmUnaryOperation<T> extends AbstractSqmExpression<T> implements Sq
public String asLoggableText() {
return ( operation == UnaryArithmeticOperator.UNARY_MINUS ? '-' : '+' ) + operand.asLoggableText();
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( operation == UnaryArithmeticOperator.UNARY_MINUS ? '-' : '+' );
operand.appendHqlString( sb );
}
}

View File

@ -57,4 +57,19 @@ public abstract class AbstractSqmInsertStatement<T> extends AbstractSqmDmlStatem
insertionTargetPaths.forEach( consumer );
}
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "insert into " );
sb.append( getTarget().getEntityName() );
if ( insertionTargetPaths != null && !insertionTargetPaths.isEmpty() ) {
sb.append( '(' );
insertionTargetPaths.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < insertionTargetPaths.size(); i++ ) {
sb.append( ", " );
insertionTargetPaths.get( i ).appendHqlString( sb );
}
sb.append( ')' );
}
}
}

View File

@ -57,4 +57,11 @@ public class SqmInsertSelectStatement<T> extends AbstractSqmInsertStatement<T> i
// insert has no predicate
return null;
}
@Override
public void appendHqlString(StringBuilder sb) {
super.appendHqlString( sb );
sb.append( ' ' );
selectQueryPart.appendHqlString( sb );
}
}

View File

@ -10,6 +10,7 @@ import org.hibernate.query.criteria.JpaPredicate;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import java.util.ArrayList;
@ -38,4 +39,27 @@ public class SqmInsertValuesStatement<T> extends AbstractSqmInsertStatement<T> {
public JpaPredicate getRestriction() {
return null;
}
@Override
public void appendHqlString(StringBuilder sb) {
super.appendHqlString( sb );
sb.append( " values (" );
appendValues( valuesList.get( 0 ), sb );
for ( int i = 1; i < valuesList.size(); i++ ) {
sb.append( ", " );
appendValues( valuesList.get( i ), sb );
}
sb.append( ')' );
}
private static void appendValues(SqmValues sqmValues, StringBuilder sb) {
final List<SqmExpression<?>> expressions = sqmValues.getExpressions();
sb.append( '(' );
expressions.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < expressions.size(); i++ ) {
sb.append( ", " );
expressions.get( i ).appendHqlString( sb );
}
sb.append( ')' );
}
}

View File

@ -63,4 +63,25 @@ public class SqmAndPredicate extends AbstractSqmPredicate implements SqmJunctive
public SqmPredicate not() {
return new SqmNegatedPredicate( this, nodeBuilder() );
}
@Override
public void appendHqlString(StringBuilder sb) {
if ( leftHandPredicate instanceof SqmOrPredicate ) {
sb.append( '(' );
leftHandPredicate.appendHqlString( sb );
sb.append( ')' );
}
else {
leftHandPredicate.appendHqlString( sb );
}
sb.append( " and " );
if ( rightHandPredicate instanceof SqmOrPredicate ) {
sb.append( '(' );
rightHandPredicate.appendHqlString( sb );
sb.append( ')' );
}
else {
rightHandPredicate.appendHqlString( sb );
}
}
}

View File

@ -58,4 +58,16 @@ public class SqmBetweenPredicate extends AbstractNegatableSqmPredicate {
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitBetweenPredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
expression.appendHqlString( sb );
if ( isNegated() ) {
sb.append( " not" );
}
sb.append( " between " );
lowerBound.appendHqlString( sb );
sb.append( " and " );
upperBound.appendHqlString( sb );
}
}

View File

@ -46,4 +46,9 @@ public class SqmBooleanExpressionPredicate extends AbstractNegatableSqmPredicate
public List<Expression<Boolean>> getExpressions() {
return Collections.singletonList( booleanExpression );
}
@Override
public void appendHqlString(StringBuilder sb) {
booleanExpression.appendHqlString( sb );
}
}

View File

@ -66,4 +66,13 @@ public class SqmComparisonPredicate extends AbstractNegatableSqmPredicate {
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitComparisonPredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
leftHandExpression.appendHqlString( sb );
sb.append( ' ' );
sb.append( operator.sqlText() );
sb.append( ' ' );
rightHandExpression.appendHqlString( sb );
}
}

View File

@ -32,4 +32,15 @@ public class SqmEmptinessPredicate extends AbstractNegatableSqmPredicate {
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitIsEmptyPredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
pluralPath.appendHqlString( sb );
if ( isNegated() ) {
sb.append( " is not empty" );
}
else {
sb.append( " is empty" );
}
}
}

View File

@ -33,4 +33,15 @@ public class SqmExistsPredicate extends AbstractNegatableSqmPredicate {
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitExistsPredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
if ( isNegated() ) {
sb.append( "not exists " );
}
else {
sb.append( "exists " );
}
expression.appendHqlString( sb );
}
}

View File

@ -47,4 +47,10 @@ public class SqmGroupedPredicate extends AbstractSqmPredicate {
public SqmPredicate not() {
return new SqmNegatedPredicate( this, nodeBuilder() );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( '(' );
subPredicate.appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -123,4 +123,19 @@ public class SqmInListPredicate<T> extends AbstractNegatableSqmPredicate impleme
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitInListPredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
testExpression.appendHqlString( sb );
if ( isNegated() ) {
sb.append( " not" );
}
sb.append( " in (" );
listExpressions.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < listExpressions.size(); i++ ) {
sb.append( ", " );
listExpressions.get( i ).appendHqlString( sb );
}
sb.append( ')' );
}
}

View File

@ -82,4 +82,14 @@ public class SqmInSubQueryPredicate<T> extends AbstractNegatableSqmPredicate imp
public SqmInPredicate<T> value(JpaExpression value) {
throw new UnsupportedOperationException( );
}
@Override
public void appendHqlString(StringBuilder sb) {
testExpression.appendHqlString( sb );
if ( isNegated() ) {
sb.append( " not" );
}
sb.append( " in " );
subQueryExpression.appendHqlString( sb );
}
}

View File

@ -70,4 +70,18 @@ public class SqmLikePredicate extends AbstractNegatableSqmPredicate {
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitLikePredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
matchExpression.appendHqlString( sb );
if ( isNegated() ) {
sb.append( " not" );
}
sb.append( " like " );
pattern.appendHqlString( sb );
if ( escapeCharacter != null ) {
sb.append( " escape " );
escapeCharacter.appendHqlString( sb );
}
}
}

View File

@ -46,4 +46,14 @@ public class SqmMemberOfPredicate extends AbstractNegatableSqmPredicate {
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitMemberOfPredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
leftHandExpression.appendHqlString( sb );
if ( isNegated() ) {
sb.append( " not" );
}
sb.append( " member of " );
pluralPath.appendHqlString( sb );
}
}

View File

@ -37,4 +37,11 @@ public class SqmNegatedPredicate extends AbstractNegatableSqmPredicate {
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitNegatedPredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "not (" );
wrappedPredicate.appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -33,4 +33,15 @@ public class SqmNullnessPredicate extends AbstractNegatableSqmPredicate {
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitIsNullPredicate( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
expression.appendHqlString( sb );
if ( isNegated() ) {
sb.append( " is not null" );
}
else {
sb.append( " is null" );
}
}
}

View File

@ -64,4 +64,25 @@ public class SqmOrPredicate extends AbstractSqmExpression<Boolean> implements Sq
public List<Expression<Boolean>> getExpressions() {
return Arrays.asList( leftHandPredicate, rightHandPredicate );
}
@Override
public void appendHqlString(StringBuilder sb) {
if ( leftHandPredicate instanceof SqmAndPredicate ) {
sb.append( '(' );
leftHandPredicate.appendHqlString( sb );
sb.append( ')' );
}
else {
leftHandPredicate.appendHqlString( sb );
}
sb.append( " or " );
if ( rightHandPredicate instanceof SqmAndPredicate ) {
sb.append( '(' );
rightHandPredicate.appendHqlString( sb );
sb.append( ')' );
}
else {
rightHandPredicate.appendHqlString( sb );
}
}
}

View File

@ -236,4 +236,20 @@ public abstract class AbstractSqmSelectQuery<T>
// this.offset = (ExpressionImplementor) offset;
// return this;
// }
public void appendHqlString(StringBuilder sb) {
if ( !cteStatements.isEmpty() ) {
sb.append( "with " );
if ( withRecursive ) {
sb.append( "recursive " );
}
for ( SqmCteStatement<?> value : cteStatements.values() ) {
value.appendHqlString( sb );
sb.append( ", " );
}
sb.setLength( sb.length() - 2 );
}
sqmQueryPart.appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -171,6 +171,28 @@ public class SqmDynamicInstantiation<T>
return walker.visitDynamicInstantiation( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "new " );
if ( instantiationTarget.getNature() == LIST ) {
sb.append( "list" );
}
else if ( instantiationTarget.getNature() == MAP ) {
sb.append( "map" );
}
else {
sb.append( instantiationTarget.getTargetTypeDescriptor().getJavaTypeClass().getTypeName() );
}
sb.append( '(' );
( (SqmSelectableNode<?>) arguments.get( 0 ) ).appendHqlString( sb );
for ( int i = 1; i < arguments.size(); i++ ) {
sb.append(", ");
( (SqmSelectableNode<?>) arguments.get( i ) ).appendHqlString( sb );
}
sb.append( ')' );
}
@SuppressWarnings("unused")
public SqmDynamicInstantiation<T> makeShallowCopy() {
return new SqmDynamicInstantiation<>( getInstantiationTarget(), nodeBuilder() );

View File

@ -109,4 +109,14 @@ public class SqmJpaCompoundSelection<T>
return walker.visitJpaCompoundSelection( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
selectableNodes.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < selectableNodes.size(); i++ ) {
sb.append(", ");
selectableNodes.get( i ).appendHqlString( sb );
}
}
}

View File

@ -103,4 +103,27 @@ public class SqmQueryGroup<T> extends SqmQueryPart<T> implements JpaQueryGroup<T
public SqmQueryGroup<T> setFetch(JpaExpression<?> fetch, FetchClauseType fetchClauseType) {
return (SqmQueryGroup<T>) super.setFetch( fetch, fetchClauseType );
}
@Override
public void appendHqlString(StringBuilder sb) {
appendQueryPart( queryParts.get( 0 ), sb );
for ( int i = 1; i < queryParts.size(); i++ ) {
sb.append( ' ' );
sb.append( setOperator.sqlString() );
sb.append( ' ' );
appendQueryPart( queryParts.get( i ), sb );
}
super.appendHqlString( sb );
}
private static void appendQueryPart(SqmQueryPart<?> queryPart, StringBuilder sb) {
final boolean needsParenthesis = !queryPart.isSimpleQueryPart();
if ( needsParenthesis ) {
sb.append( '(' );
}
queryPart.appendHqlString( sb );
if ( needsParenthesis ) {
sb.append( ')' );
}
}
}

View File

@ -147,4 +147,41 @@ public abstract class SqmQueryPart<T> implements SqmVisitableNode, JpaQueryPart<
setFetchExpression( (SqmExpression<?>) fetch, fetchClauseType );
return this;
}
public void appendHqlString(StringBuilder sb) {
if ( orderByClause == null ) {
return;
}
sb.append( " order by " );
final List<SqmSortSpecification> sortSpecifications = orderByClause.getSortSpecifications();
sortSpecifications.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < sortSpecifications.size(); i++ ) {
sb.append( ", " );
sortSpecifications.get( i ).appendHqlString( sb );
}
if ( offsetExpression != null ) {
sb.append( " offset " );
offsetExpression.appendHqlString( sb );
sb.append( " rows " );
}
if ( fetchExpression != null ) {
sb.append( " fetch first " );
fetchExpression.appendHqlString( sb );
switch ( fetchClauseType ) {
case ROWS_ONLY:
sb.append( " rows only" );
break;
case ROWS_WITH_TIES:
sb.append( " rows with ties" );
break;
case PERCENT_ONLY:
sb.append( " percent only" );
break;
case PERCENT_WITH_TIES:
sb.append( " percent with ties" );
break;
}
}
}
}

View File

@ -27,6 +27,8 @@ import org.hibernate.query.sqm.tree.SqmNode;
import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
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.SqmFromClauseContainer;
@ -325,4 +327,137 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
setFetchExpression( (SqmExpression<?>) fetch, fetchClauseType );
return this;
}
@Override
public void appendHqlString(StringBuilder sb) {
if ( selectClause != null ) {
sb.append( "select " );
if ( selectClause.isDistinct() ) {
sb.append( "distinct " );
}
final List<SqmSelection> selections = selectClause.getSelections();
selections.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < selections.size(); i++ ) {
sb.append( ", " );
selections.get( i ).appendHqlString( sb );
}
}
if ( fromClause != null ) {
sb.append( " from " );
String separator = "";
for ( SqmRoot<?> root : fromClause.getRoots() ) {
sb.append( separator );
if ( root.isCorrelated() ) {
if ( root.containsOnlyInnerJoins() ) {
appendJoins( root, root.getCorrelationParent().getExplicitAlias(), sb );
}
else {
sb.append( root.getCorrelationParent().getExplicitAlias() );
if ( root.getExplicitAlias() != null ) {
sb.append( ' ' ).append( root.getExplicitAlias() );
}
appendJoins( root, sb );
}
}
else {
sb.append( root.getEntityName() );
if ( root.getExplicitAlias() != null ) {
sb.append( ' ' ).append( root.getExplicitAlias() );
}
appendJoins( root, sb );
}
separator = ", ";
}
}
if ( whereClause != null && whereClause.getPredicate() != null ) {
sb.append( " where " );
whereClause.getPredicate().appendHqlString( sb );
}
if ( !groupByClauseExpressions.isEmpty() ) {
sb.append( " group by " );
groupByClauseExpressions.get( 0 ).appendHqlString( sb );
for ( int i = 1; i < groupByClauseExpressions.size(); i++ ) {
sb.append( ", " );
groupByClauseExpressions.get( i ).appendHqlString( sb );
}
}
if ( havingClausePredicate != null ) {
sb.append( " having " );
havingClausePredicate.appendHqlString( sb );
}
super.appendHqlString( sb );
}
private void appendJoins(SqmFrom<?, ?> sqmFrom, StringBuilder sb) {
for ( SqmJoin<?, ?> sqmJoin : sqmFrom.getSqmJoins() ) {
switch ( sqmJoin.getSqmJoinType() ) {
case LEFT:
sb.append( " left join " );
break;
case RIGHT:
sb.append( " right join " );
break;
case INNER:
sb.append( " join " );
break;
case FULL:
sb.append( " full join " );
break;
case CROSS:
sb.append( " cross join " );
break;
}
if ( sqmJoin instanceof SqmAttributeJoin<?, ?> ) {
final SqmAttributeJoin<?, ?> attributeJoin = (SqmAttributeJoin<?, ?>) sqmJoin;
sb.append( sqmFrom.getExplicitAlias() ).append( '.' );
sb.append( (attributeJoin).getAttribute().getName() );
if ( sqmJoin.getExplicitAlias() != null ) {
sb.append( ' ' ).append( sqmJoin.getExplicitAlias() );
}
if ( attributeJoin.getJoinPredicate() != null ) {
sb.append( " on " );
attributeJoin.getJoinPredicate().appendHqlString( sb );
}
appendJoins( sqmJoin, sb );
}
else if ( sqmJoin instanceof SqmCrossJoin<?> ) {
sb.append( ( (SqmCrossJoin<?>) sqmJoin ).getEntityName() );
if ( sqmJoin.getExplicitAlias() != null ) {
sb.append( ' ' ).append( sqmJoin.getExplicitAlias() );
}
appendJoins( sqmJoin, sb );
}
else if ( sqmJoin instanceof SqmEntityJoin<?> ) {
final SqmEntityJoin<?> sqmEntityJoin = (SqmEntityJoin<?>) sqmJoin;
sb.append( (sqmEntityJoin).getEntityName() );
if ( sqmJoin.getExplicitAlias() != null ) {
sb.append( ' ' ).append( sqmJoin.getExplicitAlias() );
}
if ( sqmEntityJoin.getJoinPredicate() != null ) {
sb.append( " on " );
sqmEntityJoin.getJoinPredicate().appendHqlString( sb );
}
appendJoins( sqmJoin, sb );
}
else {
throw new UnsupportedOperationException( "Unsupported join: " + sqmJoin );
}
}
}
private void appendJoins(SqmFrom<?, ?> sqmFrom, String correlationPrefix, StringBuilder sb) {
String separator = "";
for ( SqmJoin<?, ?> sqmJoin : sqmFrom.getSqmJoins() ) {
assert sqmJoin instanceof SqmAttributeJoin<?, ?>;
sb.append( separator );
sb.append( correlationPrefix ).append( '.' );
sb.append( ( (SqmAttributeJoin<?, ?>) sqmJoin ).getAttribute().getName() );
if ( sqmJoin.getExplicitAlias() != null ) {
sb.append( ' ' ).append( sqmJoin.getExplicitAlias() );
}
appendJoins( sqmJoin, sb );
separator = ", ";
}
}
}

View File

@ -54,4 +54,12 @@ public class SqmSelection<T> extends AbstractSqmNode implements SqmAliasedNode<T
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitSelection( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
selectableNode.appendHqlString( sb );
if ( selectableNode.getAlias() != null ) {
sb.append( " as " ).append( selectableNode.getAlias() );
}
}
}

View File

@ -76,4 +76,28 @@ public class SqmSortSpecification implements JpaOrder {
public boolean isAscending() {
return sortOrder == SortOrder.ASCENDING;
}
public void appendHqlString(StringBuilder sb) {
sortExpression.appendHqlString( sb );
if ( sortOrder == SortOrder.DESCENDING ) {
sb.append( " desc" );
if ( nullPrecedence != null ) {
if ( nullPrecedence == NullPrecedence.FIRST ) {
sb.append( " nulls first" );
}
else {
sb.append( " nulls last" );
}
}
}
else if ( nullPrecedence != null ) {
sb.append( " asc" );
if ( nullPrecedence == NullPrecedence.FIRST ) {
sb.append( " nulls first" );
}
else {
sb.append( " nulls last" );
}
}
}
}

View File

@ -407,4 +407,11 @@ public class SqmSubQuery<T> extends AbstractSqmSelectQuery<T> implements SqmSele
return walker.visitSubQueryExpression( this );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( '(' );
super.appendHqlString( sb );
sb.append( ')' );
}
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.query.sqm.tree.update;
import java.util.List;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
@ -182,4 +183,34 @@ public class SqmUpdateStatement<T>
}
setClause.addAssignment( new SqmAssignment( targetPath, value ) );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "update " );
if ( versioned ) {
sb.append( "versioned " );
}
sb.append( getTarget().getEntityName() );
if ( getTarget().getExplicitAlias() != null ) {
sb.append( ' ' ).append( getTarget().getExplicitAlias() );
}
sb.append( " set " );
final List<SqmAssignment> assignments = setClause.getAssignments();
appendAssignment( assignments.get( 0 ), sb );
for ( int i = 1; i < assignments.size(); i++ ) {
sb.append( ", " );
appendAssignment( assignments.get( i ), sb );
}
if ( whereClause != null && whereClause.getPredicate() != null ) {
sb.append( " where " );
whereClause.getPredicate().appendHqlString( sb );
}
}
private static void appendAssignment(SqmAssignment sqmAssignment, StringBuilder sb) {
sqmAssignment.getTargetPath().appendHqlString( sb );
sb.append( " = " );
sqmAssignment.getValue().appendHqlString( sb );
}
}