Support HQL 'any'/'some', 'every'/'all', and 'exists' subquery operators

- 'exists' and 'not exists' are predicates
- 'any'/'some' are expression used on RHS of comparison operators, but
  note that they also collide with the HQL aggregate functions of the
  same name
This commit is contained in:
gavinking 2020-02-16 13:07:09 +01:00 committed by Steve Ebersole
parent e0ffa498b1
commit 76000201eb
16 changed files with 475 additions and 18 deletions

View File

@ -372,6 +372,7 @@ predicate
| expression (NOT)? BETWEEN expression AND expression # BetweenPredicate
| expression (NOT)? LIKE expression (likeEscape)? # LikePredicate
| expression comparisonOperator expression # ComparisonPredicate
| EXISTS expression # ExistsPredicate
| MEMBER OF path # MemberOfPredicate
| NOT predicate # NegatedPredicate
| predicate AND predicate # AndPredicate
@ -657,14 +658,6 @@ sumFunction
: SUM LEFT_PAREN DISTINCT? expression RIGHT_PAREN
;
everyFunction
: (EVERY|ALL) LEFT_PAREN DISTINCT? predicate RIGHT_PAREN
;
anyFunction
: (ANY|SOME) LEFT_PAREN DISTINCT? predicate RIGHT_PAREN
;
minFunction
: MIN LEFT_PAREN DISTINCT? expression RIGHT_PAREN
;
@ -677,6 +670,14 @@ countFunction
: COUNT LEFT_PAREN DISTINCT? (expression | ASTERISK) RIGHT_PAREN
;
everyFunction
: (EVERY|ALL) LEFT_PAREN (predicate | subQuery) RIGHT_PAREN
;
anyFunction
: (ANY|SOME) LEFT_PAREN (predicate | subQuery) RIGHT_PAREN
;
standardFunction
: castFunction
| extractFunction

View File

@ -94,6 +94,7 @@ import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.query.sqm.tree.expression.SqmAny;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmByUnit;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
@ -102,6 +103,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.query.sqm.tree.expression.SqmEvery;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.query.sqm.tree.expression.SqmFormat;
@ -130,6 +132,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmEmptinessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmExistsPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
@ -1286,6 +1289,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
throw new ParsingException( "Unexpected IN predicate type [" + ctx.getClass().getSimpleName() + "] : " + ctx.getText() );
}
@Override
public SqmPredicate visitExistsPredicate(HqlParser.ExistsPredicateContext ctx) {
final SqmExpression expression = (SqmExpression) ctx.expression().accept( this );
return new SqmExistsPredicate( expression, creationContext.getNodeBuilder() );
}
@Override
@SuppressWarnings("unchecked")
public Object visitEntityTypeExpression(HqlParser.EntityTypeExpressionContext ctx) {
@ -2886,10 +2895,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
@Override
public SqmExpression visitEveryFunction(HqlParser.EveryFunctionContext ctx) {
final SqmExpression<?> arg = (SqmExpression) ctx.predicate().accept( this );
SqmTypedNode<?> argument = ctx.DISTINCT() != null
? new SqmDistinct<>(arg, getCreationContext().getNodeBuilder())
: arg;
if ( ctx.subQuery()!=null ) {
SqmSubQuery<?> subquery = (SqmSubQuery<?>) ctx.subQuery().accept(this);
return new SqmEvery( subquery, subquery.getNodeType(), creationContext.getNodeBuilder() );
}
final SqmExpression<?> argument = (SqmExpression) ctx.predicate().accept( this );
return getFunctionDescriptor("every").generateSqmExpression(
argument,
@ -2902,10 +2913,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
@Override
public SqmExpression visitAnyFunction(HqlParser.AnyFunctionContext ctx) {
final SqmExpression<?> arg = (SqmExpression) ctx.predicate().accept( this );
SqmTypedNode<?> argument = ctx.DISTINCT() != null
? new SqmDistinct<>(arg, getCreationContext().getNodeBuilder())
: arg;
if ( ctx.subQuery()!=null ) {
SqmSubQuery<?> subquery = (SqmSubQuery<?>) ctx.subQuery().accept(this);
return new SqmAny( subquery, subquery.getNodeType(), creationContext.getNodeBuilder() );
}
final SqmExpression<?> argument = (SqmExpression) ctx.predicate().accept( this );
return getFunctionDescriptor("any").generateSqmExpression(
argument,

View File

@ -22,6 +22,7 @@ import org.hibernate.query.sqm.tree.domain.SqmMinElementPath;
import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.query.sqm.tree.expression.SqmAny;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmByUnit;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
@ -31,6 +32,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.query.sqm.tree.expression.SqmEvery;
import org.hibernate.query.sqm.tree.expression.SqmFormat;
import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmParameterizedEntityType;
@ -61,6 +63,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmEmptinessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmExistsPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
@ -187,6 +190,9 @@ public interface SemanticQueryWalker<T> {
T visitSearchedCaseExpression(SqmCaseSearched<?> expression);
T visitAny(SqmAny<?> sqmAny);
T visitEvery(SqmEvery<?> sqmEvery);
T visitPositionalParameterExpression(SqmPositionalParameter<?> expression);
T visitNamedParameterExpression(SqmNamedParameter<?> expression);
@ -254,6 +260,8 @@ public interface SemanticQueryWalker<T> {
T visitBooleanExpressionPredicate(SqmBooleanExpressionPredicate predicate);
T visitExistsPredicate(SqmExistsPredicate sqmExistsPredicate);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// sorting

View File

@ -28,6 +28,7 @@ import org.hibernate.query.sqm.tree.domain.SqmMinIndexPath;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmAny;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmByUnit;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
@ -38,6 +39,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmEvery;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
@ -67,6 +69,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmEmptinessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmExistsPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
@ -811,6 +814,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
return null;
}
@Override
public Object visitExistsPredicate(SqmExistsPredicate sqmExistsPredicate) {
return null;
}
@Override
public Object visitOrderByClause(SqmOrderByClause orderByClause) {
return null;
@ -891,6 +899,16 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
return null;
}
@Override
public Object visitAny(SqmAny<?> sqmAny) {
return null;
}
@Override
public Object visitEvery(SqmEvery<?> sqmEvery) {
return null;
}
@Override
public Object visitDynamicInstantiation(SqmDynamicInstantiation sqmDynamicInstantiation) {
processStanza(

View File

@ -25,6 +25,7 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmAny;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmByUnit;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
@ -34,6 +35,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCoalesce;
import org.hibernate.query.sqm.tree.expression.SqmCollectionSize;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmEvery;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
import org.hibernate.query.sqm.tree.expression.SqmFormat;
@ -63,6 +65,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBooleanExpressionPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmEmptinessPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmExistsPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
@ -386,6 +389,12 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
return predicate;
}
@Override
public Object visitExistsPredicate(SqmExistsPredicate predicate) {
predicate.getExpression().accept( this );
return predicate;
}
@Override
public Object visitOrderByClause(SqmOrderByClause orderByClause) {
if ( orderByClause == null ) {
@ -583,6 +592,16 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
return expression;
}
@Override
public Object visitAny(SqmAny<?> sqmAny) {
return sqmAny;
}
@Override
public Object visitEvery(SqmEvery<?> sqmEvery) {
return sqmEvery;
}
@Override
public Object visitSearchedCaseExpression(SqmCaseSearched<?> expression) {
return expression;

View File

@ -70,6 +70,7 @@ import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.query.sqm.tree.expression.Conversion;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmAny;
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
import org.hibernate.query.sqm.tree.expression.SqmByUnit;
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
@ -78,6 +79,7 @@ import org.hibernate.query.sqm.tree.expression.SqmCastTarget;
import org.hibernate.query.sqm.tree.expression.SqmDistinct;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmEvery;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmExtractUnit;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
@ -104,6 +106,7 @@ import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmBetweenPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmExistsPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmGroupedPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInListPredicate;
import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate;
@ -133,6 +136,7 @@ import org.hibernate.sql.ast.tree.cte.CteColumn;
import org.hibernate.sql.ast.tree.cte.CteConsumer;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.cte.CteTable;
import org.hibernate.sql.ast.tree.expression.Any;
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
@ -140,6 +144,7 @@ import org.hibernate.sql.ast.tree.expression.CastTarget;
import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.ExtractUnit;
import org.hibernate.sql.ast.tree.expression.Format;
@ -153,6 +158,7 @@ import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.predicate.BetweenPredicate;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.ExistsPredicate;
import org.hibernate.sql.ast.tree.predicate.GroupedPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
@ -2046,6 +2052,22 @@ public abstract class BaseSqmToSqlAstConverter
return result;
}
@Override
public Object visitAny(SqmAny<?> sqmAny) {
return new Any(
visitSubQueryExpression( sqmAny.getSubquery() ),
null //resolveMappingExpressable( sqmAny.getNodeType() )
);
}
@Override
public Object visitEvery(SqmEvery<?> sqmEvery) {
return new Every(
visitSubQueryExpression( sqmEvery.getSubquery() ),
null //resolveMappingExpressable( sqmEvery.getNodeType() )
);
}
@Override
public Object visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral) {
return new QueryLiteral<>(
@ -2303,4 +2325,9 @@ public abstract class BaseSqmToSqlAstConverter
predicate.isNegated()
);
}
@Override
public Object visitExistsPredicate(SqmExistsPredicate predicate) {
return new ExistsPredicate( (QuerySpec) predicate.getExpression().accept( this ) );
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
/**
* @author Gavin King
*/
public class SqmAny<T> extends AbstractSqmExpression<T> {
private final SqmSubQuery<T> subquery;
public SqmAny(SqmSubQuery<T> subquery, SqmExpressable<T> type, NodeBuilder criteriaBuilder) {
super(type, criteriaBuilder);
this.subquery = subquery;
}
public SqmSubQuery<T> getSubquery() {
return subquery;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitAny( this );
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.select.SqmSubQuery;
/**
* @author Gavin King
*/
public class SqmEvery<T> extends AbstractSqmExpression<T> {
private final SqmSubQuery<T> subquery;
public SqmEvery(SqmSubQuery<T> subquery, SqmExpressable<T> type, NodeBuilder criteriaBuilder) {
super(type, criteriaBuilder);
this.subquery = subquery;
}
public SqmSubQuery<T> getSubquery() {
return subquery;
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitEvery( this );
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.tree.predicate;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
/**
* @author Gavin King
*/
public class SqmExistsPredicate extends AbstractNegatableSqmPredicate {
private final SqmExpression<?> expression;
public SqmExistsPredicate(
SqmExpression<?> expression,
NodeBuilder nodeBuilder) {
super( nodeBuilder );
this.expression = expression;
expression.applyInferableType( expression.getNodeType() );
}
public SqmExpression<?> getExpression() {
return expression;
}
@Override
public <T> T accept(SemanticQueryWalker<T> walker) {
return walker.visitExistsPredicate( this );
}
}

View File

@ -9,6 +9,7 @@ package org.hibernate.sql.ast;
import org.hibernate.Incubating;
import org.hibernate.query.sqm.tree.expression.Conversion;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.Any;
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
@ -18,6 +19,7 @@ import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.ExtractUnit;
import org.hibernate.sql.ast.tree.expression.Format;
import org.hibernate.sql.ast.tree.expression.JdbcLiteral;
@ -36,6 +38,7 @@ import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.predicate.BetweenPredicate;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.ExistsPredicate;
import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
import org.hibernate.sql.ast.tree.predicate.GroupedPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
@ -98,6 +101,10 @@ public interface SqlAstWalker {
void visitCaseSimpleExpression(CaseSimpleExpression caseSimpleExpression);
void visitAny(Any any);
void visitEvery(Every every);
void visitSelfRenderingExpression(SelfRenderingExpression expression);
void visitSqlSelectionExpression(SqlSelectionExpression expression);
@ -124,6 +131,8 @@ public interface SqlAstWalker {
void visitInSubQueryPredicate(InSubQueryPredicate inSubQueryPredicate);
void visitExistsPredicate(ExistsPredicate existsPredicate);
void visitJunction(Junction junction);
void visitLikePredicate(LikePredicate likePredicate);

View File

@ -15,6 +15,7 @@ import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.SqlAstTreeLogger;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.ast.tree.delete.DeleteStatement;
import org.hibernate.sql.ast.tree.expression.Any;
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
@ -24,6 +25,7 @@ import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.ExtractUnit;
import org.hibernate.sql.ast.tree.expression.Format;
import org.hibernate.sql.ast.tree.expression.JdbcLiteral;
@ -43,6 +45,7 @@ import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.insert.InsertSelectStatement;
import org.hibernate.sql.ast.tree.predicate.BetweenPredicate;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.ExistsPredicate;
import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
import org.hibernate.sql.ast.tree.predicate.GroupedPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
@ -460,6 +463,16 @@ public class SqlTreePrinter implements SqlAstWalker {
throw new NotYetImplementedFor6Exception();
}
@Override
public void visitAny(Any any) {
}
@Override
public void visitEvery(Every every) {
}
// @Override
// public void visitCoalesceFunction(CoalesceFunction coalesceExpression) {
// throw new NotYetImplementedFor6Exception();
@ -549,6 +562,11 @@ public class SqlTreePrinter implements SqlAstWalker {
);
}
@Override
public void visitExistsPredicate(ExistsPredicate existsPredicate) {
}
@Override
public void visitJunction(Junction junction) {
logNode(

View File

@ -24,6 +24,7 @@ import org.hibernate.query.sqm.sql.internal.EmbeddableValuedPathInterpretation;
import org.hibernate.query.sqm.tree.expression.Conversion;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.Any;
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
@ -33,6 +34,7 @@ import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.ExtractUnit;
import org.hibernate.sql.ast.tree.expression.Format;
@ -54,6 +56,7 @@ import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.from.VirtualTableGroup;
import org.hibernate.sql.ast.tree.predicate.BetweenPredicate;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.ExistsPredicate;
import org.hibernate.sql.ast.tree.predicate.FilterPredicate;
import org.hibernate.sql.ast.tree.predicate.GroupedPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
@ -888,6 +891,17 @@ public abstract class AbstractSqlAstWalker
appendSql( " end" );
}
@Override
public void visitAny(Any any) {
appendSql( "some " );
any.getSubquery().accept( this );
}
@Override
public void visitEvery(Every every) {
appendSql( "all " );
every.getSubquery().accept( this );
}
// @Override
// public void visitGenericParameter(GenericParameter parameter) {
@ -1064,6 +1078,12 @@ public abstract class AbstractSqlAstWalker
visitQuerySpec( inSubQueryPredicate.getSubQuery() );
}
@Override
public void visitExistsPredicate(ExistsPredicate existsPredicate) {
appendSql( "exists " );
existsPredicate.getExpression().accept( this );
}
@Override
public void visitJunction(Junction junction) {
if ( junction.isEmpty() ) {

View File

@ -0,0 +1,39 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.ast.tree.expression;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.select.QuerySpec;
/**
* @author Gavin King
*/
public class Any implements Expression {
private QuerySpec subquery;
private MappingModelExpressable<?> type;
public Any(QuerySpec subquery, MappingModelExpressable<?> type) {
this.subquery = subquery;
this.type = type;
}
public QuerySpec getSubquery() {
return subquery;
}
@Override
public MappingModelExpressable getExpressionType() {
return type;
}
@Override
public void accept(SqlAstWalker walker) {
walker.visitAny( this );
}
}

View File

@ -0,0 +1,39 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.ast.tree.expression;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.select.QuerySpec;
/**
* @author Gavin King
*/
public class Every implements Expression {
private QuerySpec subquery;
private MappingModelExpressable<?> type;
public Every(QuerySpec subquery, MappingModelExpressable<?> type) {
this.subquery = subquery;
this.type = type;
}
public QuerySpec getSubquery() {
return subquery;
}
@Override
public MappingModelExpressable getExpressionType() {
return type;
}
@Override
public void accept(SqlAstWalker walker) {
walker.visitEvery( this );
}
}

View File

@ -0,0 +1,36 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.sql.ast.tree.predicate;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.Expression;
/**
* @author Gavin King
*/
public class ExistsPredicate implements Predicate {
private Expression expression;
public ExistsPredicate(Expression expression) {
this.expression = expression;
}
public Expression getExpression() {
return expression;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTreeWalker.visitExistsPredicate( this );
}
}

View File

@ -0,0 +1,104 @@
/*
* 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.orm.test.query.hql;
import org.hibernate.testing.junit5.SessionFactoryBasedFunctionalTest;
import org.hibernate.testing.orm.domain.gambit.SimpleEntity;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Calendar;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Gavin King
*/
public class SubqueryOperatorsTest extends SessionFactoryBasedFunctionalTest {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] {
SimpleEntity.class,
};
}
@Test
public void testEvery() {
inTransaction(
session -> {
List results = session.createQuery(
"from SimpleEntity o where o.someString >= every (select someString from SimpleEntity)" )
.list();
assertThat( results.size(), is( 1 ) );
} );
}
@Test
public void testAny() {
inTransaction(
session -> {
List results = session.createQuery(
"from SimpleEntity o where o.someString >= any (select someString from SimpleEntity)" )
.list();
assertThat( results.size(), is( 2 ) );
} );
}
@Test
public void testExists() {
inTransaction(
session -> {
List results = session.createQuery(
"from SimpleEntity o where exists (select someString from SimpleEntity where someString>o.someString)" )
.list();
assertThat( results.size(), is( 1 ) );
results = session.createQuery(
"from SimpleEntity o where not exists (select someString from SimpleEntity where someString>o.someString)" )
.list();
assertThat( results.size(), is( 1 ) );
} );
}
@BeforeEach
public void setUp() {
inTransaction(
session -> {
SimpleEntity entity = new SimpleEntity(
1,
Calendar.getInstance().getTime(),
null,
Integer.MAX_VALUE,
Long.MAX_VALUE,
"aaa"
);
session.save( entity );
SimpleEntity second_entity = new SimpleEntity(
2,
Calendar.getInstance().getTime(),
null,
Integer.MIN_VALUE,
Long.MAX_VALUE,
"zzz"
);
session.save( second_entity );
} );
}
@AfterEach
public void tearDown() {
inTransaction(
session -> {
session.createQuery( "delete SimpleEntity" ).executeUpdate();
} );
}
}