From 296cbb88bd81d8c3735e673286cb28d1e3ce929a Mon Sep 17 00:00:00 2001 From: Gavin Date: Wed, 11 Jan 2023 10:36:04 +0100 Subject: [PATCH] fix queries like 'select ... where ...' with no 'from' clause this was another bug that resulted from the unnecessary use of the untypesafe getChild() method in SemanticQueryBuilder. It's really important that we migrate away from that, who knows how many other bugs are lurking? --- .../hql/internal/SemanticQueryBuilder.java | 50 +++++++------------ .../orm/test/query/hql/FunctionTests.java | 32 ++++++++++++ 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java index 9bd704cd81..7753c400b5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java @@ -291,7 +291,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem Class expectedResultType, SqmCreationOptions creationOptions, SqmCreationContext creationContext) { - return new SemanticQueryBuilder( expectedResultType, creationOptions, creationContext ).visitStatement( hqlParseTree ); + return new SemanticQueryBuilder<>( expectedResultType, creationOptions, creationContext ).visitStatement( hqlParseTree ); } private final Class expectedResultType; @@ -843,7 +843,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem } final String searchAttributeName = visitIdentifier( (HqlParser.IdentifierContext) ctx.getChild( ctx.getChildCount() - 1 ) ); final HqlParser.SearchSpecificationsContext searchCtx = (HqlParser.SearchSpecificationsContext) ctx.getChild( 4 ); - final List searchOrders = new ArrayList<>( ( searchCtx.getChildCount() + 1 ) >> 1 );; + final List searchOrders = new ArrayList<>( ( searchCtx.getChildCount() + 1 ) >> 1 ); final List children = searchCtx.children; final JpaCteCriteriaType type = cteDefinition.getType(); for ( int i = 0; i < children.size(); i += 2 ) { @@ -913,9 +913,9 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem } @Override - public SqmQueryPart visitQuerySpecExpression(HqlParser.QuerySpecExpressionContext ctx) { + public SqmQueryPart visitQuerySpecExpression(HqlParser.QuerySpecExpressionContext ctx) { final List children = ctx.children; - final SqmQueryPart queryPart = visitQuery( (HqlParser.QueryContext) children.get( 0 ) ); + final SqmQueryPart queryPart = visitQuery( (HqlParser.QueryContext) children.get( 0 ) ); if ( children.size() > 1 ) { visitQueryOrder( queryPart, (HqlParser.QueryOrderContext) children.get( 1 ) ); } @@ -1115,28 +1115,14 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem } @Override - public SqmQuerySpec visitQuery(HqlParser.QueryContext ctx) { - //noinspection unchecked - final SqmQuerySpec sqmQuerySpec = (SqmQuerySpec) currentQuerySpec(); - final int fromIndex; - if ( ctx.getChild( 0 ) instanceof HqlParser.FromClauseContext ) { - fromIndex = 0; - } - else { - fromIndex = 1; - } + public SqmQuerySpec visitQuery(HqlParser.QueryContext ctx) { + final SqmQuerySpec sqmQuerySpec = currentQuerySpec(); // visit from-clause first!!! - visitFromClause( (HqlParser.FromClauseContext) ctx.getChild( fromIndex ) ); + visitFromClause( ctx.fromClause() ); final SqmSelectClause selectClause; - if ( fromIndex == 1 ) { - selectClause = visitSelectClause( (HqlParser.SelectClauseContext) ctx.getChild( 0 ) ); - } - else if ( ctx.getChild( ctx.getChildCount() - 1 ) instanceof HqlParser.SelectClauseContext ) { - selectClause = visitSelectClause( (HqlParser.SelectClauseContext) ctx.getChild( ctx.getChildCount() - 1 ) ); - } - else { + if ( ctx.selectClause() == null ) { if ( creationOptions.useStrictJpaCompliance() ) { throw new StrictJpaComplianceViolation( "Encountered implicit select-clause, but strict JPQL compliance was requested", @@ -1146,24 +1132,22 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem log.debugf( "Encountered implicit select clause : %s", ctx.getText() ); selectClause = buildInferredSelectClause( sqmQuerySpec.getFromClause() ); } + else { + selectClause = visitSelectClause( ctx.selectClause() ); + } sqmQuerySpec.setSelectClause( selectClause ); - int currentIndex = fromIndex + 1; final SqmWhereClause whereClause = new SqmWhereClause( creationContext.getNodeBuilder() ); - if ( currentIndex < ctx.getChildCount() && ctx.getChild( currentIndex ) instanceof HqlParser.WhereClauseContext ) { - whereClause.setPredicate( (SqmPredicate) ctx.getChild( currentIndex++ ).accept( this ) ); + if ( ctx.whereClause() != null ) { + whereClause.setPredicate( (SqmPredicate) ctx.whereClause().accept( this ) ); } sqmQuerySpec.setWhereClause( whereClause ); - if ( currentIndex < ctx.getChildCount() && ctx.getChild( currentIndex ) instanceof HqlParser.GroupByClauseContext ) { - sqmQuerySpec.setGroupByClauseExpressions( - visitGroupByClause( (HqlParser.GroupByClauseContext) ctx.getChild( currentIndex++ ) ) - ); + if ( ctx.groupByClause() != null ) { + sqmQuerySpec.setGroupByClauseExpressions( visitGroupByClause( ctx.groupByClause() ) ); } - if ( currentIndex < ctx.getChildCount() && ctx.getChild( currentIndex ) instanceof HqlParser.HavingClauseContext ) { - sqmQuerySpec.setHavingClausePredicate( - visitHavingClause( (HqlParser.HavingClauseContext) ctx.getChild( currentIndex ) ) - ); + if ( ctx.havingClause() != null ) { + sqmQuerySpec.setHavingClausePredicate( visitHavingClause( ctx.havingClause() ) ); } return sqmQuerySpec; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java index 5c7db71b97..157330d46e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java @@ -1604,4 +1604,36 @@ public class FunctionTests { ); } + @Test + public void testIn(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + assertEquals( 1, + session.createQuery("select 1 where 1 in (:list)") + .setParameterList("list",List.of(1,2)) + .list().size() ); + assertEquals( 0, + session.createQuery("select 1 where 1 in (:list)") + .setParameterList("list",List.of(0,3,2)) + .list().size() ); + assertEquals( 0, + session.createQuery("select 1 where 1 in (:list)") + .setParameterList("list",List.of()) + .list().size() ); + assertEquals( 1, + session.createQuery("select 1 where 1 in :list") + .setParameterList("list",List.of(1,2)) + .list().size() ); + assertEquals( 0, + session.createQuery("select 1 where 1 in :list") + .setParameterList("list",List.of(0,3,2)) + .list().size() ); + assertEquals( 0, + session.createQuery("select 1 where 1 in :list") + .setParameterList("list",List.of()) + .list().size() ); + } + ); + } + } \ No newline at end of file