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:
parent
e0ffa498b1
commit
76000201eb
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
} );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue