From 77c1370e45340cc4f71c2970c1252eb273cfdf54 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 7 Sep 2021 01:12:18 +0200 Subject: [PATCH] HHH-14642, HHH-13717 Various JPA Criteria related fixes * Get rid of unnecessary whitespace and optional keywords in generated SQL * Handle some type inference related issues with some databases requiring to render casted parameters in some situations * Ensure SQM model is fully serializable * Ensure JPA Criteria throws expected exceptions * Make sure JPA Criteria implementations work properly * Move jpa.test.callback and jpa.test.criteria packages * Improve the reuse of SqmPath instances * Get rid of many raw-types related warnings * Make Predicate extend Expression and handle SQL rendering/emulation * Support fetching SqmTuple as array * Implement treat operator support --- docker_db.sh | 2 +- .../org/hibernate/userguide/hql/HQLTest.java | 21 +- .../community/dialect/CUBRIDDialect.java | 7 +- .../community/dialect/CacheDialect.java | 15 +- .../community/dialect/FirebirdDialect.java | 4 +- .../dialect/FirebirdSqlAstTranslator.java | 11 + .../community/dialect/InformixDialect.java | 8 +- .../dialect/InformixSqlAstTranslator.java | 2 +- .../community/dialect/IngresDialect.java | 9 +- .../dialect/IngresSqlAstTranslator.java | 2 +- .../community/dialect/MaxDBDialect.java | 2 +- .../dialect/MaxDBSqlAstTranslator.java | 2 +- .../community/dialect/MimerSQLDialect.java | 11 +- .../community/dialect/RDMSOS2200Dialect.java | 14 +- .../dialect/RDMSOS2200SqlAstTranslator.java | 2 +- .../community/dialect/SQLiteDialect.java | 50 +- .../SybaseAnywhereSqlAstTranslator.java | 56 ++ .../community/dialect/TeradataDialect.java | 13 +- .../community/dialect/TimesTenDialect.java | 12 +- .../dialect/sequence/RDMSSequenceSupport.java | 2 +- .../dialect/InformixDialectTestCase.java | 2 + .../dialect/AbstractHANADialect.java | 33 +- .../hibernate/dialect/CockroachDialect.java | 12 +- .../dialect/CockroachSqlAstTranslator.java | 11 + .../hibernate/dialect/DB2400V7R3Dialect.java | 8 +- .../org/hibernate/dialect/DB2Dialect.java | 5 +- .../dialect/DB2SqlAstTranslator.java | 74 +- .../org/hibernate/dialect/DB2iDialect.java | 4 +- .../org/hibernate/dialect/DerbyDialect.java | 22 +- .../dialect/DerbySqlAstTranslator.java | 96 +- .../java/org/hibernate/dialect/Dialect.java | 3 +- .../java/org/hibernate/dialect/H2Dialect.java | 8 +- .../hibernate/dialect/H2SqlAstTranslator.java | 11 + .../org/hibernate/dialect/HSQLDialect.java | 10 +- .../dialect/HSQLSqlAstTranslator.java | 68 +- .../org/hibernate/dialect/MariaDBDialect.java | 2 +- .../dialect/MariaDBSqlAstTranslator.java | 11 + .../org/hibernate/dialect/MySQLDialect.java | 14 +- .../dialect/MySQLSqlAstTranslator.java | 11 + .../org/hibernate/dialect/OracleDialect.java | 9 +- .../dialect/OracleSqlAstTranslator.java | 4 +- .../hibernate/dialect/PostgreSQLDialect.java | 12 +- .../dialect/PostgreSQLSqlAstTranslator.java | 11 + .../hibernate/dialect/SQLServerDialect.java | 37 +- .../dialect/SQLServerSqlAstTranslator.java | 22 +- .../org/hibernate/dialect/SpannerDialect.java | 8 +- .../hibernate/dialect/SybaseASEDialect.java | 10 +- .../dialect/SybaseASESqlAstTranslator.java | 64 +- .../org/hibernate/dialect/SybaseDialect.java | 13 +- .../dialect/SybaseSqlAstTranslator.java | 56 ++ .../function/CommonFunctionFactory.java | 695 +++++++------- .../dialect/function/DerbyConcatFunction.java | 39 + .../dialect/function/FieldFunction.java | 4 +- .../QuantifiedLeastGreatestEmulation.java | 4 +- .../function/TransactSQLStrFunction.java | 2 +- .../pagination/LegacyDB2LimitHandler.java | 8 +- .../pagination/LegacyOracleLimitHandler.java | 16 +- .../dialect/pagination/LimitLimitHandler.java | 2 +- .../pagination/Oracle12LimitHandler.java | 8 +- .../pagination/SQLServer2005LimitHandler.java | 10 +- .../sequence/DerbySequenceSupport.java | 2 +- .../sequence/SQLServerSequenceSupport.java | 2 +- .../metamodel/mapping/CollectionPart.java | 13 + .../mapping/ForeignKeyDescriptor.java | 18 + .../internal/ToOneAttributeMapping.java | 2 +- .../model/domain/AbstractManagedType.java | 23 + .../model/domain/MapPersistentAttribute.java | 2 +- .../domain/internal/AbstractAttribute.java | 60 +- .../internal/AbstractPluralAttribute.java | 3 + .../domain/internal/BasicSqmPathSource.java | 3 +- .../domain/internal/DiscriminatorSqmPath.java | 14 +- .../internal/DiscriminatorSqmPathSource.java | 5 +- .../model/domain/internal/EntityTypeImpl.java | 26 +- .../domain/internal/JpaMetamodelImpl.java | 26 +- .../domain/internal/ListAttributeImpl.java | 15 + .../domain/internal/MapAttributeImpl.java | 14 + .../NonAggregatedCompositeSqmPathSource.java | 3 +- .../internal/SingularAttributeImpl.java | 2 +- .../entity/AbstractEntityPersister.java | 51 - .../hibernate/query/ComparisonOperator.java | 4 +- .../org/hibernate/query/NavigablePath.java | 4 +- .../hibernate/query/ParameterMetadata.java | 5 + .../criteria/HibernateCriteriaBuilder.java | 16 +- .../org/hibernate/query/criteria/JpaPath.java | 21 + .../query/hql/internal/QuerySplitter.java | 13 +- .../hql/internal/SemanticQueryBuilder.java | 97 +- .../hql/internal/SqmPathRegistryImpl.java | 71 +- .../query/hql/spi/SemanticPathPart.java | 4 +- .../query/hql/spi/SqmPathRegistry.java | 12 +- .../query/internal/ParameterMetadataImpl.java | 53 +- .../internal/QueryParameterBindingImpl.java | 30 +- .../internal/QueryParameterBindingsImpl.java | 9 +- .../org/hibernate/query/spi/QueryEngine.java | 10 + .../query/sqm/IllegalPathUsageException.java | 25 - .../org/hibernate/query/sqm/NodeBuilder.java | 8 +- .../query/sqm/SemanticQueryWalker.java | 28 +- .../hibernate/query/sqm/SqmPathSource.java | 12 +- .../function/NamedSqmFunctionDescriptor.java | 2 +- .../SelfRenderingSqmAggregateFunction.java | 9 +- .../internal/ConcreteSqmSelectQueryPlan.java | 23 +- .../sqm/internal/DomainParameterXref.java | 7 +- .../sqm/internal/ParameterCollector.java | 2 +- .../query/sqm/internal/QuerySqmImpl.java | 48 +- .../sqm/internal/SqmCriteriaNodeBuilder.java | 672 +++++++------ .../sqm/internal/SqmMappingModelHelper.java | 2 +- .../query/sqm/internal/SqmTreePrinter.java | 28 +- .../hibernate/query/sqm/internal/SqmUtil.java | 142 +++ .../MultiTableSqmMutationConverter.java | 4 +- .../cte/AbstractCteMutationHandler.java | 5 +- .../sqm/spi/BaseSemanticQueryWalker.java | 124 ++- .../sqm/sql/BaseSqmToSqlAstConverter.java | 896 +++++++++++++----- .../EntityValuedPathInterpretation.java | 2 +- .../PluralValuedSimplePathInterpretation.java | 14 + .../internal/SqlAstProcessingStateImpl.java | 3 +- .../query/sqm/tree/AbstractSqmNode.java | 4 +- .../AbstractSqmRestrictedDmlStatement.java | 101 ++ .../query/sqm/tree/AbstractSqmStatement.java | 29 +- .../sqm/tree/SqmExpressableAccessor.java | 27 + .../query/sqm/tree/SqmTypedNode.java | 7 +- .../query/sqm/tree/cte/SqmCteTable.java | 3 +- .../query/sqm/tree/cte/SqmCteTableColumn.java | 4 +- .../cte/SqmSearchClauseSpecification.java | 4 +- .../sqm/tree/delete/SqmDeleteStatement.java | 83 +- .../tree/domain/AbstractSqmAttributeJoin.java | 5 +- .../sqm/tree/domain/AbstractSqmFrom.java | 18 +- .../sqm/tree/domain/AbstractSqmJoin.java | 2 +- .../sqm/tree/domain/AbstractSqmPath.java | 21 +- .../tree/domain/AbstractSqmPluralJoin.java | 5 +- .../tree/domain/AbstractSqmSimplePath.java | 4 +- .../AbstractSqmSpecificPluralPartPath.java | 12 +- .../NonAggregatedCompositeSimplePath.java | 2 +- .../query/sqm/tree/domain/SqmBagJoin.java | 5 - .../domain/SqmBasicValuedEntityTypePath.java | 4 +- .../tree/domain/SqmBasicValuedSimplePath.java | 4 +- .../sqm/tree/domain/SqmCorrelatedBagJoin.java | 5 +- .../tree/domain/SqmCorrelatedCrossJoin.java | 9 +- .../tree/domain/SqmCorrelatedEntityJoin.java | 9 +- .../tree/domain/SqmCorrelatedListJoin.java | 5 +- .../sqm/tree/domain/SqmCorrelatedMapJoin.java | 5 +- .../tree/domain/SqmCorrelatedRootJoin.java | 5 +- .../sqm/tree/domain/SqmCorrelatedSetJoin.java | 5 +- .../domain/SqmCorrelatedSingularJoin.java | 5 +- .../domain/SqmEmbeddedValuedSimplePath.java | 4 +- .../domain/SqmEntityValuedSimplePath.java | 10 +- .../SqmIndexedCollectionAccessPath.java | 26 +- .../query/sqm/tree/domain/SqmListJoin.java | 33 +- .../sqm/tree/domain/SqmMapEntryReference.java | 9 +- .../query/sqm/tree/domain/SqmMapJoin.java | 91 +- .../sqm/tree/domain/SqmMaxElementPath.java | 4 +- .../sqm/tree/domain/SqmMaxIndexPath.java | 2 +- .../sqm/tree/domain/SqmMinElementPath.java | 4 +- .../sqm/tree/domain/SqmMinIndexPath.java | 2 +- .../query/sqm/tree/domain/SqmPath.java | 44 +- .../domain/SqmPluralValuedSimplePath.java | 59 +- .../query/sqm/tree/domain/SqmSetJoin.java | 14 +- .../sqm/tree/domain/SqmSingularJoin.java | 14 +- .../sqm/tree/domain/SqmTreatedBagJoin.java | 23 +- .../sqm/tree/domain/SqmTreatedCrossJoin.java | 18 +- .../sqm/tree/domain/SqmTreatedEntityJoin.java | 14 + .../sqm/tree/domain/SqmTreatedListJoin.java | 27 +- .../sqm/tree/domain/SqmTreatedMapJoin.java | 28 +- .../query/sqm/tree/domain/SqmTreatedPath.java | 5 - .../query/sqm/tree/domain/SqmTreatedRoot.java | 15 +- .../sqm/tree/domain/SqmTreatedSetJoin.java | 30 +- .../sqm/tree/domain/SqmTreatedSimplePath.java | 11 + .../tree/domain/SqmTreatedSingularJoin.java | 27 +- .../expression/AbstractSqmExpression.java | 23 +- .../tree/expression/JpaCriteriaParameter.java | 15 +- .../tree/expression/SqmAggregateFunction.java | 22 + .../tree/expression/SqmBinaryArithmetic.java | 4 +- .../tree/expression/SqmLiteralEntityType.java | 6 - .../query/sqm/tree/from/SqmCrossJoin.java | 18 +- .../query/sqm/tree/from/SqmEntityJoin.java | 16 +- .../query/sqm/tree/from/SqmFrom.java | 4 + .../query/sqm/tree/from/SqmFromClause.java | 3 +- .../query/sqm/tree/from/SqmRoot.java | 32 +- .../tree/insert/SqmInsertSelectStatement.java | 1 + .../tree/insert/SqmInsertValuesStatement.java | 2 +- .../query/sqm/tree/insert/SqmValues.java | 3 +- .../sqm/tree/jpa/ParameterCollector.java | 150 ++- .../tree/predicate/AbstractSqmPredicate.java | 99 -- .../SqmBooleanExpressionPredicate.java | 5 +- .../predicate/SqmComparisonPredicate.java | 2 +- .../sqm/tree/predicate/SqmPredicate.java | 2 +- .../tree/select/AbstractSqmSelectQuery.java | 4 +- .../sqm/tree/select/SqmOrderByClause.java | 8 +- .../query/sqm/tree/select/SqmQuerySpec.java | 88 +- .../sqm/tree/select/SqmSelectStatement.java | 248 ++--- .../query/sqm/tree/select/SqmSubQuery.java | 67 +- .../sqm/tree/update/SqmUpdateStatement.java | 91 +- .../sql/ast/SqlAstNodeRenderingMode.java | 6 + .../org/hibernate/sql/ast/SqlAstWalker.java | 3 + .../sql/ast/spi/AbstractSqlAstTranslator.java | 615 ++++++------ .../sql/ast/spi/AggregateFunctionChecker.java | 6 + .../hibernate/sql/ast/spi/SqlAppender.java | 11 +- .../sql/ast/tree/expression/Any.java | 27 +- .../expression/CaseSearchedExpression.java | 3 +- .../tree/expression/CaseSimpleExpression.java | 3 +- .../sql/ast/tree/expression/Collate.java | 23 +- .../sql/ast/tree/expression/Every.java | 27 +- .../ast/tree/expression/NullnessLiteral.java | 23 +- .../sql/ast/tree/expression/SqlTuple.java | 29 +- .../ast/tree/predicate/AbstractPredicate.java | 40 + .../ast/tree/predicate/BetweenPredicate.java | 18 +- .../predicate/BooleanExpressionPredicate.java | 32 + .../tree/predicate/ComparisonPredicate.java | 16 + .../ast/tree/predicate/ExistsPredicate.java | 11 +- .../ast/tree/predicate/FilterPredicate.java | 6 + .../ast/tree/predicate/GroupedPredicate.java | 6 + .../ast/tree/predicate/InListPredicate.java | 24 +- .../tree/predicate/InSubQueryPredicate.java | 19 +- .../sql/ast/tree/predicate/Junction.java | 12 + .../sql/ast/tree/predicate/LikePredicate.java | 28 +- .../ast/tree/predicate/NegatedPredicate.java | 6 + .../ast/tree/predicate/NullnessPredicate.java | 21 +- .../sql/ast/tree/predicate/Predicate.java | 27 +- .../predicate/SelfRenderingPredicate.java | 6 + .../sql/ast/tree/select/QuerySpec.java | 14 +- .../AbstractEmbeddableInitializer.java | 1 + .../internal/DynamicInstantiation.java | 2 +- .../DynamicInstantiationArgument.java | 20 +- .../sql/results/graph/tuple/TupleResult.java | 75 ++ .../graph/tuple/TupleResultAssembler.java | 66 ++ .../CriteriaLiteralWithSingleQuoteTest.java | 147 --- .../test/mapping/NestedEmbeddableTest.java | 13 - .../dialect/Oracle12LimitHandlerTest.java | 6 +- .../dialect/SQLServer2005DialectTestCase.java | 142 +-- .../lockhint/SQLServer2005LockHintsTest.java | 2 +- .../unit/lockhint/SQLServerLockHintsTest.java | 2 +- ...alectSequenceInformationExtractorTest.java | 2 +- ...alectSequenceInformationExtractorTest.java | 2 +- .../CriteriaQueryWithAppliedFilterTest.java | 4 - .../sqm/HqlTranslationNoFactoryTests.java | 2 + .../jpa}/callbacks/CallbackAndDirtyTest.java | 2 +- .../test/jpa}/callbacks/Customer.java | 2 +- .../test/jpa}/callbacks/Employee.java | 2 +- .../test/jpa}/callbacks/Person.java | 2 +- .../PreUpdateBytecodeEnhancementTest.java | 4 +- ...dateCustomEntityDirtinessStrategyTest.java | 4 +- ...PreUpdateDirtyCheckingInterceptorTest.java | 4 +- .../test/jpa}/criteria/Animal.java | 2 +- .../test/jpa}/criteria/Attribute.java | 2 +- .../test => orm/test/jpa}/criteria/Book.java | 3 +- .../test => orm/test/jpa}/criteria/Color.java | 2 +- .../jpa}/criteria/CriteriaCompilingTest.java | 2 +- .../CriteriaQueryTypeQueryAdapterTest.java | 2 +- .../ElementCollectionConverterTest.java | 3 - .../test/jpa}/criteria/Elephant.java | 2 +- .../EntitySuperclassCollectionTest.java | 2 +- .../test => orm/test/jpa}/criteria/Human.java | 2 +- .../test/jpa}/criteria/HumanDTO.java | 2 +- .../test/jpa}/criteria/Industry.java | 2 +- .../hibernate/orm/test/jpa/criteria/Item.java | 3 - .../jpa}/criteria/ItemAttributeConverter.java | 2 +- .../criteria/ManipulationCriteriaTest.java | 2 +- .../MultiTypedBasicAttributesEntity.java | 2 +- .../test/jpa}/criteria/ParameterTest.java | 2 +- .../test/jpa}/criteria/QueryBuilderTest.java | 12 +- .../test => orm/test/jpa}/criteria/Store.java | 2 +- .../criteria/SuperclassCollectionTest.java | 2 +- .../test/jpa}/criteria/TreatJoinTest.java | 10 +- .../test/jpa}/criteria/TreatKeywordTest.java | 12 +- .../test/jpa}/criteria/TreatListJoinTest.java | 2 +- .../alias/CriteriaMultiselectAliasTest.java | 2 +- .../criteria/basic/AggregationResultTest.java | 2 +- .../basic/BasicCriteriaUsageTest.java | 5 +- .../test/jpa}/criteria/basic/ConcatTest.java | 2 +- .../jpa}/criteria/basic/ExpressionsTest.java | 17 +- .../InWithHeterogeneousCollectionTest.java | 2 +- .../jpa}/criteria/basic/ListIndexTest.java | 2 +- .../test/jpa}/criteria/basic/Payment.java | 2 +- .../jpa}/criteria/basic/PredicateTest.java | 4 +- .../test/jpa}/criteria/basic/Wall.java | 2 +- .../ComponentInWhereClauseTest.java | 2 - .../enumcollection/EnumIsMemberTest.java | 2 +- .../jpa}/criteria/enumcollection/User.java | 2 +- .../CriteriaToScrollableResultsFetchTest.java | 2 +- .../jpa}/criteria/fetchscroll/Customer.java | 2 +- .../jpa}/criteria/fetchscroll/Facility.java | 2 +- .../test/jpa}/criteria/fetchscroll/Order.java | 2 +- .../jpa}/criteria/fetchscroll/OrderId.java | 2 +- .../jpa}/criteria/fetchscroll/OrderLine.java | 2 +- .../criteria/fetchscroll/OrderLineId.java | 2 +- .../jpa}/criteria/fetchscroll/Product.java | 2 +- .../jpa}/criteria/fetchscroll/ProductId.java | 2 +- .../criteria/fetchscroll/PurchaseOrg.java | 2 +- .../test/jpa}/criteria/fetchscroll/Site.java | 2 +- .../test/jpa}/criteria/idclass/Helper.java | 2 +- .../test/jpa}/criteria/idclass/HelperId.java | 2 +- .../idclass/IdClassPredicateTest.java | 2 +- .../test/jpa}/criteria/idclass/Tool.java | 2 +- .../test/jpa}/criteria/idclass/Widget.java | 2 +- .../test/jpa}/criteria/idclass/WidgetId.java | 2 +- ...stractCriteriaLiteralHandlingModeTest.java | 12 +- .../CriteriaLiteralHandlingModeAutoTest.java | 4 +- .../CriteriaLiteralHandlingModeBindTest.java | 4 +- ...dlingModeInlineShortNameLowercaseTest.java | 4 +- ...dlingModeInlineShortNameUppercaseTest.java | 4 +- ...CriteriaLiteralHandlingModeInlineTest.java | 4 +- ...CriteriaLiteralHandlingModeInlineTest.java | 4 +- .../test/jpa}/criteria/mapjoin/Customer.java | 2 +- .../jpa}/criteria/mapjoin/CustomerOrder.java | 2 +- .../criteria/mapjoin/MapJoinEntryTest.java | 2 +- .../jpa}/criteria/mapjoin/MapJoinTest.java | 2 +- .../mapjoin/MapJoinTestWithEmbeddable.java | 4 +- ...CriteriaLiteralInSelectExpressionTest.java | 2 +- .../nulliteral/CriteriaLiteralsTest.java | 42 +- .../nulliteral/NullLiteralExpression.java | 2 +- .../test/jpa}/criteria/nulliteral/Person.java | 2 +- .../jpa}/criteria/nulliteral/Subject.java | 2 +- .../criteria/paths/AbstractPathImplTest.java | 2 +- .../jpa}/criteria/paths/FetchAndJoinTest.java | 2 +- .../paths/PluralAttributeExpressionsTest.java | 2 +- .../selectcase/GroupBySelectCaseTest.java | 10 +- .../SelectCaseLiteralHandlingBindTest.java | 15 +- .../criteria/selectcase/SelectCaseTest.java | 9 +- .../simplecase/BasicSimpleCaseTest.java | 2 +- .../AbstractSubqueryInSelectClauseTest.java | 2 +- .../subquery/CorrelatedSubqueryTest.java | 2 +- ...bqueryInSelectClauseJpaComplianceTest.java | 2 +- .../subquery/SubqueryInSelectClauseTest.java | 2 +- .../subquery/UncorrelatedSubqueryTest.java | 2 +- .../criteria/tuple/TupleCriteriaTest.java | 2 +- .../test/jpa/test}/components/Alias.java | 2 +- .../test/jpa/test}/components/Client.java | 2 +- .../components/ComponentCriteriaTest.java | 2 +- .../test/jpa/test}/components/Name.java | 3 +- .../transaction/SynchronizationTypeTest.java | 2 - .../orm/test/query/QueryTimeOutTest.java | 6 +- .../orm/test/query/hql/TupleTest.java | 75 ++ .../orm/test/sql/ast/SmokeTests.java | 12 +- .../SearchedCaseExpressionTest.java | 11 - 332 files changed, 4957 insertions(+), 3227 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyConcatFunction.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/IllegalPathUsageException.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmRestrictedDmlStatement.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmExpressableAccessor.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAggregateFunction.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/AbstractPredicate.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/BooleanExpressionPredicate.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/tuple/TupleResult.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/tuple/TupleResultAssembler.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralWithSingleQuoteTest.java rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/callbacks/CallbackAndDirtyTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/callbacks/Customer.java (95%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/callbacks/Employee.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/callbacks/Person.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/callbacks/PreUpdateBytecodeEnhancementTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/callbacks/PreUpdateCustomEntityDirtinessStrategyTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/callbacks/PreUpdateDirtyCheckingInterceptorTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/Animal.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/Attribute.java (87%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/Book.java (93%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/Color.java (91%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/CriteriaCompilingTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/CriteriaQueryTypeQueryAdapterTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/Elephant.java (89%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/EntitySuperclassCollectionTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/Human.java (89%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/HumanDTO.java (94%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/Industry.java (91%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/ItemAttributeConverter.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/ManipulationCriteriaTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/MultiTypedBasicAttributesEntity.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/ParameterTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/QueryBuilderTest.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/Store.java (94%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/SuperclassCollectionTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/TreatJoinTest.java (95%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/TreatKeywordTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/TreatListJoinTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/alias/CriteriaMultiselectAliasTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/basic/AggregationResultTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/basic/BasicCriteriaUsageTest.java (95%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/basic/ConcatTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/basic/ExpressionsTest.java (92%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/basic/InWithHeterogeneousCollectionTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/basic/ListIndexTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/basic/Payment.java (95%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/basic/PredicateTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/basic/Wall.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/enumcollection/EnumIsMemberTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/enumcollection/User.java (95%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/CriteriaToScrollableResultsFetchTest.java (99%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/Customer.java (94%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/Facility.java (96%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/Order.java (95%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/OrderId.java (91%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/OrderLine.java (96%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/OrderLineId.java (85%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/Product.java (94%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/ProductId.java (90%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/PurchaseOrg.java (96%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/fetchscroll/Site.java (95%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/idclass/Helper.java (94%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/idclass/HelperId.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/idclass/IdClassPredicateTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/idclass/Tool.java (93%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/idclass/Widget.java (95%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/idclass/WidgetId.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/literal/AbstractCriteriaLiteralHandlingModeTest.java (90%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/literal/CriteriaLiteralHandlingModeAutoTest.java (78%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/literal/CriteriaLiteralHandlingModeBindTest.java (81%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameLowercaseTest.java (77%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameUppercaseTest.java (77%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/literal/CriteriaLiteralHandlingModeInlineTest.java (78%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/literal/MySQLCriteriaLiteralHandlingModeInlineTest.java (80%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/mapjoin/Customer.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/mapjoin/CustomerOrder.java (93%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/mapjoin/MapJoinEntryTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/mapjoin/MapJoinTest.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/mapjoin/MapJoinTestWithEmbeddable.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/nulliteral/CriteriaLiteralInSelectExpressionTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/nulliteral/CriteriaLiteralsTest.java (81%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/nulliteral/NullLiteralExpression.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/nulliteral/Person.java (90%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/nulliteral/Subject.java (89%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/paths/AbstractPathImplTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/paths/FetchAndJoinTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/paths/PluralAttributeExpressionsTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/selectcase/GroupBySelectCaseTest.java (83%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/selectcase/SelectCaseLiteralHandlingBindTest.java (88%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/selectcase/SelectCaseTest.java (89%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/simplecase/BasicSimpleCaseTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/subquery/AbstractSubqueryInSelectClauseTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/subquery/CorrelatedSubqueryTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/subquery/SubqueryInSelectClauseJpaComplianceTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/subquery/SubqueryInSelectClauseTest.java (96%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/subquery/UncorrelatedSubqueryTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/criteria/tuple/TupleCriteriaTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test/criteria => orm/test/jpa/test}/components/Alias.java (95%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test/criteria => orm/test/jpa/test}/components/Client.java (94%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test/criteria => orm/test/jpa/test}/components/ComponentCriteriaTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test/criteria => orm/test/jpa/test}/components/Name.java (94%) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/TupleTest.java diff --git a/docker_db.sh b/docker_db.sh index cdbf1f60ac..a0d6940e0c 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -2,7 +2,7 @@ mysql_5_7() { docker rm -f mysql || true - docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_cs + docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_bin # Give the container some time to start OUTPUT= n=0 diff --git a/documentation/src/test/java/org/hibernate/userguide/hql/HQLTest.java b/documentation/src/test/java/org/hibernate/userguide/hql/HQLTest.java index 6608171a6e..fa572c4ec6 100644 --- a/documentation/src/test/java/org/hibernate/userguide/hql/HQLTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/hql/HQLTest.java @@ -27,8 +27,8 @@ import org.hibernate.Session; import org.hibernate.dialect.CockroachDialect; import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.H2Dialect; -import org.hibernate.dialect.MySQL5Dialect; -import org.hibernate.dialect.Oracle8iDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.OracleDialect; import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; @@ -1355,7 +1355,8 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase { }); } - @Test @RequiresDialect(H2Dialect.class) + @Test + @RequiresDialect(H2Dialect.class) public void test_hql_current_time_function_example() { doInJPA( this::entityManagerFactory, entityManager -> { //tag::hql-current-time-function-example[] @@ -1385,8 +1386,8 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase { @Test @RequiresDialect(H2Dialect.class) - @RequiresDialect(Oracle8iDialect.class) - @RequiresDialect(MySQL5Dialect.class) + @RequiresDialect(OracleDialect.class) + @RequiresDialect(MySQLDialect.class) public void test_hql_bit_length_function_example() { doInJPA( this::entityManagerFactory, entityManager -> { //tag::hql-bit-length-function-example[] @@ -1940,7 +1941,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase { @Test @RequiresDialect(H2Dialect.class) @RequiresDialect(PostgreSQLDialect.class) - @RequiresDialect(MySQL5Dialect.class) + @RequiresDialect(MySQLDialect.class) public void test_hql_relational_comparisons_example_3() { doInJPA( this::entityManagerFactory, entityManager -> { @@ -2145,7 +2146,7 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase { @Test @RequiresDialect(H2Dialect.class) @RequiresDialect(PostgreSQLDialect.class) - @RequiresDialect(MySQL5Dialect.class) + @RequiresDialect(MySQLDialect.class) public void test_hql_between_predicate_example_2() { doInJPA( this::entityManagerFactory, entityManager -> { @@ -2399,9 +2400,6 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase { } @Test - @RequiresDialect(H2Dialect.class) - @RequiresDialect(PostgreSQLDialect.class) - @RequiresDialect(MySQL5Dialect.class) public void test_hql_group_by_example_3() { doInJPA( this::entityManagerFactory, entityManager -> { @@ -2421,9 +2419,6 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase { } @Test - @RequiresDialect(H2Dialect.class) - @RequiresDialect(PostgreSQLDialect.class) - @RequiresDialect(MySQL5Dialect.class) public void test_hql_group_by_example_4() { doInJPA( this::entityManagerFactory, entityManager -> { diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java index 261ac5ac94..e1bb0c6a08 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java @@ -167,6 +167,7 @@ public class CUBRIDDialect extends Dialect { CommonFunctionFactory.lastDay( queryEngine ); CommonFunctionFactory.weekQuarter( queryEngine ); CommonFunctionFactory.octetLength( queryEngine ); + CommonFunctionFactory.bitLength( queryEngine ); CommonFunctionFactory.md5( queryEngine ); CommonFunctionFactory.trunc( queryEngine ); CommonFunctionFactory.truncate( queryEngine ); @@ -386,11 +387,11 @@ public class CUBRIDDialect extends Dialect { public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { switch (unit) { case NANOSECOND: - return "adddate(?3, interval (?2)/1e6 millisecond)"; + return "adddate(?3,interval (?2)/1e6 millisecond)"; case NATIVE: - return "adddate(?3, interval ?2 millisecond)"; + return "adddate(?3,interval ?2 millisecond)"; default: - return "adddate(?3, interval ?2 ?1)"; + return "adddate(?3,interval ?2 ?1)"; } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java index 41fab3d3af..faeee55c2f 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java @@ -146,9 +146,10 @@ public class CacheDialect extends Dialect { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", StandardBasicTypes.INTEGER, - "$find(?2, ?1)", - "$find(?2, ?1, ?3)" + "$find(?2,?1)", + "$find(?2,?1,?3)" ).setArgumentListSignature("(pattern, string[, start])"); + CommonFunctionFactory.bitLength_pattern( queryEngine, "($length(?1)*8)" ); useJdbcEscape(queryEngine, "sin"); useJdbcEscape(queryEngine, "cos"); @@ -181,7 +182,7 @@ public class CacheDialect extends Dialect { @Override public String extractPattern(TemporalUnit unit) { - return "datepart(?1, ?2)"; + return "datepart(?1,?2)"; } @Override @@ -189,9 +190,9 @@ public class CacheDialect extends Dialect { switch (unit) { case NANOSECOND: case NATIVE: - return "dateadd(millisecond, (?2)/1e6, ?3)"; + return "dateadd(millisecond,(?2)/1e6,?3)"; default: - return "dateadd(?1, ?2, ?3)"; + return "dateadd(?1,?2,?3)"; } } @@ -200,9 +201,9 @@ public class CacheDialect extends Dialect { switch (unit) { case NANOSECOND: case NATIVE: - return "datediff(millisecond, ?2, ?3)*1e6"; + return "datediff(millisecond,?2,?3)*1e6"; default: - return "datediff(?1, ?2, ?3)"; + return "datediff(?1,?2,?3)"; } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java index 9816a4104b..5d121cc468 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java @@ -248,7 +248,7 @@ public class FirebirdDialect extends Dialect { "locate", StandardBasicTypes.INTEGER, "position(?1 in ?2)", - "position(?1, ?2, ?3)" + "position(?1,?2,?3)" ).setArgumentListSignature( "(pattern, string[, start])" ); functionRegistry.namedDescriptorBuilder( "ascii_val" ) .setExactArgumentCount( 1 ) @@ -593,7 +593,7 @@ public class FirebirdDialect extends Dialect { ? "select rdb$generator_name from rdb$generators" // Note: Firebird 3 has an 'off by increment' bug (fixed in Firebird 4), see // http://tracker.firebirdsql.org/browse/CORE-6084 - : "select rdb$generator_name, rdb$initial_value, rdb$generator_increment from rdb$generators where coalesce(rdb$system_flag, 0) = 0"; + : "select rdb$generator_name,rdb$initial_value,rdb$generator_increment from rdb$generators where coalesce(rdb$system_flag,0)=0"; } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java index ae6a94e600..191a649b19 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java @@ -30,6 +30,7 @@ import org.hibernate.sql.ast.tree.expression.QueryLiteral; import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression; import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; @@ -50,6 +51,16 @@ public class FirebirdSqlAstTranslator extends AbstractS super( sessionFactory, statement ); } + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + if ( getDialect().getVersion() >= 300 ) { + booleanExpressionPredicate.getExpression().accept( this ); + } + else { + super.visitBooleanExpressionPredicate( booleanExpressionPredicate ); + } + } + @Override protected String getForUpdate() { return " with lock"; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java index 0bcc0c86c2..ce95a8aa07 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java @@ -168,8 +168,8 @@ public class InformixDialect extends Dialect { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", StandardBasicTypes.INTEGER, - "instr(?2, ?1)", - "instr(?2, ?1, ?3)" + "instr(?2,?1)", + "instr(?2,?1,?3)" ).setArgumentListSignature("(pattern, string[, start])"); //coalesce() and nullif() both supported since Informix 12 @@ -307,7 +307,7 @@ public class InformixDialect extends Dialect { @Override public String getQuerySequencesString() { - return "select systables.tabname as sequence_name, syssequences.* from syssequences join systables on syssequences.tabid = systables.tabid where tabtype = 'Q'"; + return "select systables.tabname as sequence_name,syssequences.* from syssequences join systables on syssequences.tabid=systables.tabid where tabtype='Q'"; } @Override @@ -322,7 +322,7 @@ public class InformixDialect extends Dialect { @Override public String getFromDual() { - return "from (select 0 from systables where tabid = 1) as dual"; + return "from (select 0 from systables where tabid=1) as dual"; } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java index 39cfeae12b..d3dde81156 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java @@ -145,7 +145,7 @@ public class InformixSqlAstTranslator extends AbstractS @Override protected String getFromDual() { - return " from (select 0 from systables where tabid = 1) as dual"; + return " from (select 0 from systables where tabid=1) dual"; } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java index f9fa4ed037..0701aeae03 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java @@ -235,15 +235,16 @@ public class IngresDialect extends Dialect { CommonFunctionFactory.position( queryEngine ); CommonFunctionFactory.format_dateFormat( queryEngine ); CommonFunctionFactory.dateTrunc( queryEngine ); + CommonFunctionFactory.bitLength_pattern( queryEngine, "octet_length(hex(?1))*4" ); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", StandardBasicTypes.INTEGER, "position(?1 in ?2)", - "(position(?1 in substring(?2 from ?3)) + (?3) - 1)" + "(position(?1 in substring(?2 from ?3))+(?3)-1)" ).setArgumentListSignature("(pattern, string[, start])"); - queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "date_part('?1', ?2)", StandardBasicTypes.INTEGER ); + queryEngine.getSqmFunctionRegistry().registerPattern( "extract", "date_part('?1',?2)", StandardBasicTypes.INTEGER ); CommonFunctionFactory.bitandorxornot_bitAndOrXorNot(queryEngine); @@ -290,13 +291,13 @@ public class IngresDialect extends Dialect { @Override public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { - return "timestampadd(?1, ?2, ?3)"; + return "timestampadd(?1,?2,?3)"; } @Override public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) { - return "timestampdiff(?1, ?2, ?3)"; + return "timestampdiff(?1,?2,?3)"; } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java index 4d6b1c4e57..424f4430cc 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java @@ -151,7 +151,7 @@ public class IngresSqlAstTranslator extends AbstractSql @Override protected String getFromDual() { //this is only necessary if the query has a where clause - return " from (select 0) as dual"; + return " from (select 0) dual"; } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java index 8cf2c2ecbd..1ee27135b9 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java @@ -139,7 +139,7 @@ public class MaxDBDialect extends Dialect { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", - StandardBasicTypes.INTEGER, "index(?2, ?1)", "index(?2, ?1, ?3)" + StandardBasicTypes.INTEGER, "index(?2,?1)", "index(?2,?1,?3)" ).setArgumentListSignature("(pattern, string[, start])"); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java index 1c5dcf72d6..47f6ced982 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java @@ -68,7 +68,7 @@ public class MaxDBSqlAstTranslator extends AbstractSqlA visitDecodeCaseSearchedExpression( caseSearchedExpression ); } else { - visitAnsiCaseSearchedExpression( caseSearchedExpression ); + super.visitCaseSearchedExpression( caseSearchedExpression, inSelect ); } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java index 21a1f2ba58..8b60e3d17e 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java @@ -101,6 +101,7 @@ public class MimerSQLDialect extends Dialect { CommonFunctionFactory.soundex( queryEngine ); CommonFunctionFactory.octetLength( queryEngine ); + CommonFunctionFactory.bitLength( queryEngine ); CommonFunctionFactory.truncate( queryEngine ); CommonFunctionFactory.repeat( queryEngine ); CommonFunctionFactory.pad_repeat( queryEngine ); @@ -161,7 +162,7 @@ public class MimerSQLDialect extends Dialect { public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) { StringBuilder pattern = new StringBuilder(); - pattern.append("cast((?3 - ?2) "); + pattern.append("cast((?3-?2) "); switch (unit) { case NATIVE: case NANOSECOND: @@ -209,13 +210,13 @@ public class MimerSQLDialect extends Dialect { switch ( unit ) { case NATIVE: case NANOSECOND: - return "(?3 + (?2)/1e9 * interval '1' second)"; + return "(?3+(?2)/1e9*interval '1' second)"; case QUARTER: - return "(?3 + (?2) * interval '3' month)"; + return "(?3+(?2)*interval '3' month)"; case WEEK: - return "(?3 + (?2) * interval '7' day)"; + return "(?3+(?2)*interval '7' day)"; default: - return "(?3 + (?2) * interval '1' ?1)"; + return "(?3+(?2)*interval '1' ?1)"; } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java index 991f022e00..7aefe7a70c 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java @@ -223,11 +223,11 @@ public class RDMSOS2200Dialect extends Dialect { public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { switch (unit) { case NANOSECOND: - return "timestampadd('SQL_TSI_FRAC_SECOND', (?2)/1e3, ?3)"; + return "timestampadd('SQL_TSI_FRAC_SECOND',(?2)/1e3,?3)"; case NATIVE: - return "timestampadd('SQL_TSI_FRAC_SECOND', ?2, ?3)"; + return "timestampadd('SQL_TSI_FRAC_SECOND',?2,?3)"; default: - return "dateadd('?1', ?2, ?3)"; + return "dateadd('?1',?2,?3)"; } } @@ -235,11 +235,11 @@ public class RDMSOS2200Dialect extends Dialect { public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) { switch (unit) { case NANOSECOND: - return "timestampdiff('SQL_TSI_FRAC_SECOND', ?2, ?3)*1e3"; + return "timestampdiff('SQL_TSI_FRAC_SECOND',?2,?3)*1e3"; case NATIVE: - return "timestampdiff('SQL_TSI_FRAC_SECOND', ?2, ?3)"; + return "timestampdiff('SQL_TSI_FRAC_SECOND',?2,?3)"; default: - return "dateadd('?1', ?2, ?3)"; + return "dateadd('?1',?2,?3)"; } } @@ -325,7 +325,7 @@ public class RDMSOS2200Dialect extends Dialect { @Override public String getFromDual() { - return "from rdms.rdms_dummy where key_col = 1"; + return "from rdms.rdms_dummy where key_col=1"; } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java index c9b46da12c..7d2bf5d507 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java @@ -138,7 +138,7 @@ public class RDMSOS2200SqlAstTranslator extends Abstrac @Override protected String getFromDual() { - return " from rdms.rdms_dummy where key_col = 1"; + return " from rdms.rdms_dummy where key_col=1"; } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java index 0903563682..cddd912db7 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java @@ -126,27 +126,27 @@ public class SQLiteDialect extends Dialect { public String extractPattern(TemporalUnit unit) { switch ( unit ) { case SECOND: - return "cast(strftime('%S.%f', ?2) as double)"; + return "cast(strftime('%S.%f',?2) as double)"; case MINUTE: - return "strftime('%M', ?2)"; + return "strftime('%M',?2)"; case HOUR: - return "strftime('%H', ?2)"; + return "strftime('%H',?2)"; case DAY: case DAY_OF_MONTH: - return "(strftime('%d', ?2)+1)"; + return "(strftime('%d',?2)+1)"; case MONTH: - return "strftime('%m', ?2)"; + return "strftime('%m',?2)"; case YEAR: - return "strftime('%Y', ?2)"; + return "strftime('%Y',?2)"; case DAY_OF_WEEK: - return "(strftime('%w', ?2)+1)"; + return "(strftime('%w',?2)+1)"; case DAY_OF_YEAR: - return "strftime('%j', ?2)"; + return "strftime('%j',?2)"; case EPOCH: - return "strftime('%s', ?2)"; + return "strftime('%s',?2)"; case WEEK: // Thanks https://stackoverflow.com/questions/15082584/sqlite-return-wrong-week-number-for-2013 - return "((strftime('%j', date(?2, '-3 days', 'weekday 4'))-1)/7+1)"; + return "((strftime('%j',date(?2,'-3 days','weekday 4'))-1)/7+1)"; default: return super.extractPattern(unit); } @@ -158,13 +158,13 @@ public class SQLiteDialect extends Dialect { switch ( unit ) { case NANOSECOND: case NATIVE: - return "datetime(?3, '+?2 seconds')"; + return "datetime(?3,'+?2 seconds')"; case QUARTER: //quarter is not supported in interval literals - return function + "(?3, '+'||(?2*3)||' months')"; + return function + "(?3,'+'||(?2*3)||' months')"; case WEEK: //week is not supported in interval literals - return function + "(?3, '+'||(?2*7)||' days')"; + return function + "(?3,'+'||(?2*7)||' days')"; default: - return function + "(?3, '+?2 ?1s')"; + return function + "(?3,'+?2 ?1s')"; } } @@ -244,20 +244,20 @@ public class SQLiteDialect extends Dialect { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", StandardBasicTypes.INTEGER, - "instr(?2, ?1)", - "instr(?2, ?1, ?3)" + "instr(?2,?1)", + "instr(?2,?1,?3)" ).setArgumentListSignature("(pattern, string[, start])"); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "lpad", StandardBasicTypes.STRING, - "(substr(replace(hex(zeroblob(?2)), '00', ' '), 1, ?2 - length(?1))||?1)", - "(substr(replace(hex(zeroblob(?2)), '00', ?3), 1, ?2 - length(?1))||?1)" + "(substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1))||?1)", + "(substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1))||?1)" ).setArgumentListSignature("(string, length[, padding])"); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", StandardBasicTypes.STRING, - "(?1||substr(replace(hex(zeroblob(?2)), '00', ' '), 1, ?2 - length(?1)))", - "(?1||substr(replace(hex(zeroblob(?2)), '00', ?3), 1, ?2 - length(?1)))" + "(?1||substr(replace(hex(zeroblob(?2)),'00',' '),1,?2-length(?1)))", + "(?1||substr(replace(hex(zeroblob(?2)),'00',?3),1,?2-length(?1)))" ).setArgumentListSignature("(string, length[, padding])"); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "strftime") @@ -269,13 +269,13 @@ public class SQLiteDialect extends Dialect { if (!supportsMathFunctions() ) { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "floor", - "(cast(?1 as int) - (?1 < cast(?1 as int)))" + "(cast(?1 as int)-(?1 cast(?1 as int)))" + "(cast(?1 as int)+(?1>cast(?1 as int)))" ).setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 1 ) ) .setExactArgumentCount( 1 ) .register(); @@ -288,15 +288,15 @@ public class SQLiteDialect extends Dialect { case BOTH: return character == ' ' ? "trim(?1)" - : "trim(?1, '" + character + "')"; + : "trim(?1,'" + character + "')"; case LEADING: return character == ' ' ? "ltrim(?1)" - : "ltrim(?1, '" + character + "')"; + : "ltrim(?1,'" + character + "')"; case TRAILING: return character == ' ' ? "rtrim(?1)" - : "rtrim(?1, '" + character + "')"; + : "rtrim(?1,'" + character + "')"; } throw new UnsupportedOperationException( "Unsupported specification: " + specification ); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java index 684c65dfe8..0c0e949c34 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java @@ -7,14 +7,18 @@ package org.hibernate.community.dialect; import java.util.List; +import java.util.function.Consumer; import org.hibernate.LockMode; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.ast.tree.cte.CteStatement; +import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; +import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.SqlTuple; @@ -36,6 +40,58 @@ public class SybaseAnywhereSqlAstTranslator extends Abs super( sessionFactory, statement ); } + // Sybase Anywhere does not allow CASE expressions where all result arms contain plain parameters. + // At least one result arm must provide some type context for inference, + // so we cast the first result arm if we encounter this condition + + @Override + protected void visitAnsiCaseSearchedExpression( + CaseSearchedExpression caseSearchedExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) { + final List whenFragments = caseSearchedExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSearchedExpression( + caseSearchedExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer ); + } + } + + @Override + protected void visitAnsiCaseSimpleExpression( + CaseSimpleExpression caseSimpleExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) { + final List whenFragments = caseSimpleExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSimpleExpression( + caseSimpleExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer ); + } + } + @Override protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) { super.renderTableReference( tableReference, lockMode ); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TeradataDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TeradataDialect.java index d938b50f28..65f36b2eec 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TeradataDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TeradataDialect.java @@ -178,7 +178,7 @@ public class TeradataDialect extends Dialect { public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) { StringBuilder pattern = new StringBuilder(); //TODO: TOTALLY UNTESTED CODE! - pattern.append("cast((?3 - ?2) "); + pattern.append("cast((?3-?2) "); switch (unit) { case NANOSECOND: case NATIVE: @@ -214,15 +214,15 @@ public class TeradataDialect extends Dialect { //TODO: TOTALLY UNTESTED CODE! switch ( unit ) { case NANOSECOND: - return "(?3 + (?2)/1e9 * interval '1' second)"; + return "(?3+(?2)/1e9*interval '1' second)"; case NATIVE: - return "(?3 + (?2) * interval '1' second)"; + return "(?3+(?2)*interval '1' second)"; case QUARTER: - return "(?3 + (?2) * interval '3' month)"; + return "(?3+(?2)*interval '3' month)"; case WEEK: - return "(?3 + (?2) * interval '7' day)"; + return "(?3+(?2)*interval '7' day)"; default: - return "(?3 + (?2) * interval '1' ?1)"; + return "(?3+(?2)*interval '1' ?1)"; } } @@ -238,6 +238,7 @@ public class TeradataDialect extends Dialect { CommonFunctionFactory.substring_substr( queryEngine ); //also natively supports ANSI-style substring() CommonFunctionFactory.position( queryEngine ); + CommonFunctionFactory.bitLength_pattern( queryEngine, "octet_length(cast(?1 as char))*4" ); queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "mod", "(?1 mod ?2)" ) .setInvariantType( StandardBasicTypes.STRING ) diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java index e4d786f7c8..c7015c5c7a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java @@ -145,8 +145,8 @@ public class TimesTenDialect extends Dialect { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", StandardBasicTypes.INTEGER, - "instr(?2, ?1)", - "instr(?2, ?1, ?3)" + "instr(?2,?1)", + "instr(?2,?1,?3)" ).setArgumentListSignature("(pattern, string[, start])"); } @@ -166,9 +166,9 @@ public class TimesTenDialect extends Dialect { switch (unit) { case NANOSECOND: case NATIVE: - return "timestampadd(sql_tsi_frac_second, ?2, ?3)"; + return "timestampadd(sql_tsi_frac_second,?2,?3)"; default: - return "timestampadd(sql_tsi_?1, ?2, ?3)"; + return "timestampadd(sql_tsi_?1,?2,?3)"; } } @@ -177,9 +177,9 @@ public class TimesTenDialect extends Dialect { switch (unit) { case NANOSECOND: case NATIVE: - return "timestampdiff(sql_tsi_frac_second, ?2, ?3)"; + return "timestampdiff(sql_tsi_frac_second,?2,?3)"; default: - return "timestampdiff(sql_tsi_?1, ?2, ?3)"; + return "timestampdiff(sql_tsi_?1,?2,?3)"; } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/RDMSSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/RDMSSequenceSupport.java index 596dc17b6e..f81276e91a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/RDMSSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/RDMSSequenceSupport.java @@ -30,7 +30,7 @@ public final class RDMSSequenceSupport implements SequenceSupport { @Override public String getFromDual() { // The where clause was added to eliminate this statement from Brute Force Searches. - return " from rdms.rdms_dummy where key_col = 1"; + return " from rdms.rdms_dummy where key_col=1"; } @Override diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixDialectTestCase.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixDialectTestCase.java index af3c69dea8..3775023a16 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixDialectTestCase.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixDialectTestCase.java @@ -46,6 +46,8 @@ public class InformixDialectTestCase extends BaseUnitTestCase { ssr = new StandardServiceRegistryBuilder().build(); queryEngine = new QueryEngine( + null, + null, jpaMetamodel, ValueHandlingMode.BIND, dialect.getPreferredSqlTypeCodeForBoolean(), diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java index 6b62dbb2c3..e849b56c1f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java @@ -819,8 +819,8 @@ public abstract class AbstractHANADialect extends Dialect { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", StandardBasicTypes.INTEGER, - "locate(?2, ?1)", - "locate(?2, ?1, ?3)" + "locate(?2,?1)", + "locate(?2,?1,?3)" ).setArgumentListSignature("(pattern, string[, start])"); CommonFunctionFactory.ceiling_ceil( queryEngine ); @@ -846,6 +846,7 @@ public abstract class AbstractHANADialect extends Dialect { CommonFunctionFactory.format_toVarchar( queryEngine ); CommonFunctionFactory.currentUtcdatetimetimestamp( queryEngine ); CommonFunctionFactory.everyAny_sumCaseCase( queryEngine ); + CommonFunctionFactory.bitLength_pattern( queryEngine, "length(to_binary(?1))*8" ); } @Override @@ -1421,7 +1422,7 @@ public abstract class AbstractHANADialect extends Dialect { conn = connectionProvider.getConnection(); try ( Statement statement = conn.createStatement() ) { try ( ResultSet rs = statement.executeQuery( - "SELECT TOP 1 VALUE, MAP(LAYER_NAME, 'DEFAULT', 1, 'SYSTEM', 2, 'DATABASE', 3, 4) AS LAYER FROM SYS.M_INIFILE_CONTENTS WHERE FILE_NAME='indexserver.ini' AND SECTION='session' AND KEY='max_lob_prefetch_size' ORDER BY LAYER DESC" ) ) { + "SELECT TOP 1 VALUE,MAP(LAYER_NAME,'DEFAULT',1,'SYSTEM',2,'DATABASE',3,4) AS LAYER FROM SYS.M_INIFILE_CONTENTS WHERE FILE_NAME='indexserver.ini' AND SECTION='session' AND KEY='max_lob_prefetch_size' ORDER BY LAYER DESC" ) ) { // This only works if the current user has the privilege INIFILE ADMIN if ( rs.next() ) { maxLobPrefetchSizeDefault = rs.getInt( 1 ); @@ -1645,21 +1646,21 @@ public abstract class AbstractHANADialect extends Dialect { case NANOSECOND: case NATIVE: if ( temporalType == TemporalType.TIME ) { - return "cast(add_nano100('1970-01-01 '||(?3), ?2) as time)"; + return "cast(add_nano100('1970-01-01 '||(?3),?2) as time)"; } else { - return "add_nano100(?3, ?2)"; + return "add_nano100(?3,?2)"; } case QUARTER: - return "add_months(?3, 3*?2)"; + return "add_months(?3,3*?2)"; case WEEK: - return "add_days(?3, 7*?2)"; + return "add_days(?3,7*?2)"; case MINUTE: - return "add_seconds(?3, 60*?2)"; + return "add_seconds(?3,60*?2)"; case HOUR: - return "add_seconds(?3, 3600*?2)"; + return "add_seconds(?3,3600*?2)"; default: - return "add_?1s(?3, ?2)"; + return "add_?1s(?3,?2)"; } } @@ -1672,18 +1673,18 @@ public abstract class AbstractHANADialect extends Dialect { // return "nano100_between(cast(?3 as timestamp), cast(?2 as timestamp))"; // } // else { - return "nano100_between(?2, ?3)"; + return "nano100_between(?2,?3)"; // } case QUARTER: - return "months_between(?2, ?3)/3"; + return "months_between(?2,?3)/3"; case WEEK: - return "days_between(?2, ?3)/7"; + return "days_between(?2,?3)/7"; case MINUTE: - return "seconds_between(?2, ?3)/60"; + return "seconds_between(?2,?3)/60"; case HOUR: - return "seconds_between(?2, ?3)/3600"; + return "seconds_between(?2,?3)/3600"; default: - return "?1s_between(?2, ?3)"; + return "?1s_between(?2,?3)"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java index cd78c8ffb0..6faab71159 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java @@ -229,7 +229,7 @@ public class CockroachDialect extends Dialect { @Override public String getQuerySequencesString() { - return "select sequence_name, sequence_schema, sequence_catalog, start_value, minimum_value, maximum_value, increment from information_schema.sequences"; + return "select sequence_name,sequence_schema,sequence_catalog,start_value,minimum_value,maximum_value,increment from information_schema.sequences"; } @Override @@ -305,15 +305,15 @@ public class CockroachDialect extends Dialect { public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { switch ( unit ) { case NANOSECOND: - return "(?3 + (?2)/1e3 * interval '1 microsecond')"; + return "(?3+(?2)/1e3*interval '1 microsecond')"; case NATIVE: - return "(?3 + (?2) * interval '1 microsecond')"; + return "(?3+(?2)*interval '1 microsecond')"; case QUARTER: //quarter is not supported in interval literals - return "(?3 + (?2) * interval '3 month')"; + return "(?3+(?2)*interval '3 month')"; case WEEK: //week is not supported in interval literals - return "(?3 + (?2) * interval '7 day')"; + return "(?3+(?2)*interval '7 day')"; default: - return "(?3 + (?2) * interval '1 ?1')"; + return "(?3+(?2)*interval '1 ?1')"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachSqlAstTranslator.java index 56298fd57c..a2de8a617b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachSqlAstTranslator.java @@ -13,6 +13,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; @@ -29,6 +30,16 @@ public class CockroachSqlAstTranslator extends Abstract super( sessionFactory, statement ); } + @Override + protected void renderExpressionAsClauseItem(Expression expression) { + expression.accept( this ); + } + + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + booleanExpressionPredicate.getExpression().accept( this ); + } + @Override protected String getForShare() { return " for share"; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2400V7R3Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2400V7R3Dialect.java index 2c2e5377ec..a7c0b52df2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2400V7R3Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2400V7R3Dialect.java @@ -42,8 +42,8 @@ public class DB2400V7R3Dialect extends DB2400Dialect { @Override public String getQuerySequencesString() { return "select distinct sequence_name from qsys2.syssequences " + - "where ( current_schema = '*LIBL' and sequence_schema in ( select schema_name from qsys2.library_list_info ) ) " + - "or sequence_schema = current_schema"; + "where current_schema='*LIBL' and sequence_schema in (select schema_name from qsys2.library_list_info) " + + "or sequence_schema=current_schema"; } @Override @@ -53,8 +53,8 @@ public class DB2400V7R3Dialect extends DB2400Dialect { return sql + " fetch first " + limit + " rows only"; } //nest the main query in an outer select - return "select * from ( select inner2_.*, rownumber() over(order by order of inner2_) as rownumber_ from ( " - + sql + " fetch first " + limit + " rows only ) as inner2_ ) as inner1_ where rownumber_ > " + return "select * from (select inner2_.*,rownumber() over(order by order of inner2_) as rownumber_ from (" + + sql + " fetch first " + limit + " rows only) as inner2_) as inner1_ where rownumber_>" + offset + " order by rownumber_"; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java index 00cfa629b3..82c89a9f29 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -190,6 +190,7 @@ public class DB2Dialect extends Dialect { CommonFunctionFactory.addYearsMonthsDaysHoursMinutesSeconds( queryEngine ); CommonFunctionFactory.yearsMonthsDaysHoursMinutesSecondsBetween( queryEngine ); CommonFunctionFactory.dateTrunc( queryEngine ); + CommonFunctionFactory.bitLength_pattern( queryEngine, "length(?1)*8" ); queryEngine.getSqmFunctionRegistry().register( "format", new DB2FormatEmulation() ); @@ -417,7 +418,7 @@ public class DB2Dialect extends Dialect { default: literal = "0"; } - return "nullif(" + literal + ", " + literal + ')'; + return "nullif(" + literal + "," + literal + ')'; } @Override @@ -657,7 +658,7 @@ public class DB2Dialect extends Dialect { return String.format( Locale.ENGLISH, - "case when %s is null then %s else %s end, %s %s", + "case when %s is null then %s else %s end,%s %s", expression, nullPrecedence == NullPrecedence.FIRST ? "0" : "1", nullPrecedence == NullPrecedence.FIRST ? "1" : "0", diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java index cb68147cd0..dfe83769d2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java @@ -7,16 +7,20 @@ package org.hibernate.dialect; import java.util.List; +import java.util.function.Consumer; import org.hibernate.query.FetchClauseType; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.MutationStatement; import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.ast.tree.delete.DeleteStatement; +import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; +import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.JdbcParameter; @@ -25,6 +29,7 @@ import org.hibernate.sql.ast.tree.expression.NullnessLiteral; import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.insert.InsertStatement; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; @@ -42,6 +47,73 @@ public class DB2SqlAstTranslator extends AbstractSqlAst super( sessionFactory, statement ); } + @Override + protected void renderExpressionAsClauseItem(Expression expression) { + expression.accept( this ); + } + + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + if ( getDialect().getVersion() >= 1100 ) { + booleanExpressionPredicate.getExpression().accept( this ); + } + else { + super.visitBooleanExpressionPredicate( booleanExpressionPredicate ); + } + } + + // DB2 does not allow CASE expressions where all result arms contain plain parameters. + // At least one result arm must provide some type context for inference, + // so we cast the first result arm if we encounter this condition + + @Override + protected void visitAnsiCaseSearchedExpression( + CaseSearchedExpression caseSearchedExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) { + final List whenFragments = caseSearchedExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSearchedExpression( + caseSearchedExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer ); + } + } + + @Override + protected void visitAnsiCaseSimpleExpression( + CaseSimpleExpression caseSimpleExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) { + final List whenFragments = caseSimpleExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSimpleExpression( + caseSimpleExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer ); + } + } + @Override protected String getForUpdate() { return " for read only with rs use and keep update locks"; @@ -146,7 +218,7 @@ public class DB2SqlAstTranslator extends AbstractSqlAst for ( int i = 0; i < size; i++ ) { appendSql( separator ); appendSql( returningColumns.get( i ).getColumnExpression() ); - separator = ", "; + separator = ","; } if ( statement instanceof DeleteStatement ) { appendSql( " from old table (" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java index 0556b9feb0..c2f818d1c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java @@ -79,8 +79,8 @@ public class DB2iDialect extends DB2Dialect { public String getQuerySequencesString() { if ( getIVersion() >= 730 ) { return "select distinct sequence_name from qsys2.syssequences " + - "where ( current_schema = '*LIBL' and sequence_schema in ( select schema_name from qsys2.library_list_info ) ) " + - "or sequence_schema = current_schema"; + "where current_schema='*LIBL' and sequence_schema in (select schema_name from qsys2.library_list_info) " + + "or sequence_schema=current_schema"; } else { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java index 153d015e10..717cedd549 100755 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java @@ -11,6 +11,7 @@ import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.CommonFunctionFactory; +import org.hibernate.dialect.function.DerbyConcatFunction; import org.hibernate.dialect.function.DerbyLpadEmulation; import org.hibernate.dialect.function.DerbyRpadEmulation; import org.hibernate.dialect.function.CaseLeastGreatestEmulation; @@ -183,6 +184,9 @@ public class DerbyDialect extends Dialect { public void initializeFunctionRegistry(QueryEngine queryEngine) { super.initializeFunctionRegistry( queryEngine ); + // Derby needs an actual argument type for aggregates like SUM, AVG, MIN, MAX to determine the result type + CommonFunctionFactory.aggregates( queryEngine, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + CommonFunctionFactory.concat_pipeOperator( queryEngine ); CommonFunctionFactory.cot( queryEngine ); CommonFunctionFactory.chr_char( queryEngine ); @@ -209,6 +213,8 @@ public class DerbyDialect extends Dialect { .setExactArgumentCount( 2 ) .register(); + queryEngine.getSqmFunctionRegistry().register( "concat", new DerbyConcatFunction() ); + //no way I can see to pad with anything other than spaces queryEngine.getSqmFunctionRegistry().register( "lpad", new DerbyLpadEmulation() ); queryEngine.getSqmFunctionRegistry().register( "rpad", new DerbyRpadEmulation() ); @@ -252,14 +258,14 @@ public class DerbyDialect extends Dialect { case DAY_OF_MONTH: return "day(?2)"; case DAY_OF_YEAR: - return "({fn timestampdiff(sql_tsi_day, date(char(year(?2),4)||'-01-01'),?2)}+1)"; + return "({fn timestampdiff(sql_tsi_day,date(char(year(?2),4)||'-01-01'),?2)}+1)"; case DAY_OF_WEEK: // Use the approach as outlined here: https://stackoverflow.com/questions/36357013/day-of-week-from-seconds-since-epoch - return "(mod(mod({fn timestampdiff(sql_tsi_day, {d '1970-01-01'}, ?2)}+4,7)+7,7)+1)"; + return "(mod(mod({fn timestampdiff(sql_tsi_day,{d '1970-01-01'},?2)}+4,7)+7,7)+1)"; case WEEK: // Use the approach as outlined here: https://www.sqlservercentral.com/articles/a-simple-formula-to-calculate-the-iso-week-number // In SQL Server terms this is (DATEPART(dy,DATEADD(dd,DATEDIFF(dd,'17530101',@SomeDate)/7*7,'17530104'))+6)/7 - return "(({fn timestampdiff(sql_tsi_day, date(char(year(?2),4)||'-01-01'),{fn timestampadd(sql_tsi_day, {fn timestampdiff(sql_tsi_day, {d '1753-01-01'}, ?2)}/7*7, {d '1753-01-04'})})}+7)/7)"; + return "(({fn timestampdiff(sql_tsi_day,date(char(year(?2),4)||'-01-01'),{fn timestampadd(sql_tsi_day,{fn timestampdiff(sql_tsi_day,{d '1753-01-01'},?2)}/7*7,{d '1753-01-04'})})}+7)/7)"; case QUARTER: return "((month(?2)+2)/3)"; default: @@ -320,9 +326,9 @@ public class DerbyDialect extends Dialect { switch (unit) { case NANOSECOND: case NATIVE: - return "{fn timestampadd(sql_tsi_frac_second, mod(bigint(?2),1000000000), {fn timestampadd(sql_tsi_second, bigint((?2)/1000000000), ?3)})}"; + return "{fn timestampadd(sql_tsi_frac_second,mod(bigint(?2),1000000000),{fn timestampadd(sql_tsi_second,bigint((?2)/1000000000),?3)})}"; default: - return "{fn timestampadd(sql_tsi_?1, bigint(?2), ?3)}"; + return "{fn timestampadd(sql_tsi_?1,bigint(?2),?3)}"; } } @@ -331,9 +337,9 @@ public class DerbyDialect extends Dialect { switch (unit) { case NANOSECOND: case NATIVE: - return "{fn timestampdiff(sql_tsi_frac_second, ?2, ?3)}"; + return "{fn timestampdiff(sql_tsi_frac_second,?2,?3)}"; default: - return "{fn timestampdiff(sql_tsi_?1, ?2, ?3)}"; + return "{fn timestampdiff(sql_tsi_?1,?2,?3)}"; } } @@ -368,7 +374,7 @@ public class DerbyDialect extends Dialect { public String getQuerySequencesString() { return getVersion() < 1060 ? null - : "select sys.sysschemas.schemaname as sequence_schema, sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid = sys.sysschemas.schemaid"; + : "select sys.sysschemas.schemaname as sequence_schema,sys.syssequences.* from sys.syssequences left join sys.sysschemas on sys.syssequences.schemaid=sys.sysschemas.schemaid"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java index 43f9b92c16..db0956c1b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java @@ -7,24 +7,24 @@ package org.hibernate.dialect; import java.util.List; +import java.util.function.Consumer; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; -import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation; -import org.hibernate.sql.ast.SqlAstWalker; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.ast.tree.cte.CteContainer; import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; +import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.Expression; -import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.expression.Literal; -import org.hibernate.sql.ast.tree.expression.NullnessLiteral; -import org.hibernate.sql.ast.tree.expression.QueryLiteral; import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; +import org.hibernate.sql.ast.tree.predicate.InListPredicate; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.exec.spi.JdbcOperation; @@ -39,6 +39,68 @@ public class DerbySqlAstTranslator extends AbstractSqlA super( sessionFactory, statement ); } + @Override + protected void renderExpressionAsClauseItem(Expression expression) { + expression.accept( this ); + } + + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + booleanExpressionPredicate.getExpression().accept( this ); + } + + // Derby does not allow CASE expressions where all result arms contain plain parameters. + // At least one result arm must provide some type context for inference, + // so we cast the first result arm if we encounter this condition + + @Override + protected void visitAnsiCaseSearchedExpression( + CaseSearchedExpression caseSearchedExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) { + final List whenFragments = caseSearchedExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSearchedExpression( + caseSearchedExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer ); + } + } + + @Override + protected void visitAnsiCaseSimpleExpression( + CaseSimpleExpression caseSimpleExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) { + final List whenFragments = caseSimpleExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSimpleExpression( + caseSimpleExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer ); + } + } + @Override protected String getForUpdate() { return " for update"; @@ -139,6 +201,28 @@ public class DerbySqlAstTranslator extends AbstractSqlA } } + @Override + public void visitInListPredicate(InListPredicate inListPredicate) { + final List listExpressions = inListPredicate.getListExpressions(); + if ( listExpressions.isEmpty() ) { + appendSql( "1=0" ); + return; + } + final Expression testExpression = inListPredicate.getTestExpression(); + if ( isParameter( testExpression ) ) { + renderCasted( testExpression ); + if ( inListPredicate.isNegated() ) { + appendSql( " not" ); + } + appendSql( " in(" ); + renderCommaSeparated( listExpressions ); + appendSql( CLOSE_PARENTHESIS ); + } + else { + super.visitInListPredicate( inListPredicate ); + } + } + @Override protected boolean supportsRowValueConstructorSyntax() { return false; @@ -156,7 +240,7 @@ public class DerbySqlAstTranslator extends AbstractSqlA @Override protected String getFromDual() { - return " from (values 0) as dual"; + return " from (values 0) dual"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index d816640236..60d3d9f6c9 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -70,6 +70,7 @@ import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.query.sqm.sql.SqmTranslatorFactory; import org.hibernate.service.ServiceRegistry; import org.hibernate.sql.*; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory; @@ -475,7 +476,7 @@ public abstract class Dialect implements ConversionContext { //aggregate functions, supported on every database - CommonFunctionFactory.aggregates( queryEngine ); + CommonFunctionFactory.aggregates( queryEngine, SqlAstNodeRenderingMode.DEFAULT ); //the ANSI SQL-defined aggregate functions any() and every() are only //supported on one database, but can be emulated using sum() and case, diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index b56ccf09c9..9f336fb300 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -41,6 +41,7 @@ import org.hibernate.query.sqm.mutation.internal.idtable.AfterUseAction; import org.hibernate.query.sqm.mutation.internal.idtable.IdTable; import org.hibernate.query.sqm.mutation.internal.idtable.LocalTemporaryTableStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory; @@ -155,6 +156,9 @@ public class H2Dialect extends Dialect { public void initializeFunctionRegistry(QueryEngine queryEngine) { super.initializeFunctionRegistry( queryEngine ); + // H2 needs an actual argument type for aggregates like SUM, AVG, MIN, MAX to determine the result type + CommonFunctionFactory.aggregates( queryEngine, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + CommonFunctionFactory.pi( queryEngine ); CommonFunctionFactory.cot( queryEngine ); CommonFunctionFactory.radians( queryEngine ); @@ -246,13 +250,13 @@ public class H2Dialect extends Dialect { @Override public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { - return "dateadd(?1, ?2, ?3)"; + return "dateadd(?1,?2,?3)"; } @Override public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) { - return "datediff(?1, ?2, ?3)"; + return "datediff(?1,?2,?3)"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java index 5b80b296e7..ebe1979b23 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java @@ -18,6 +18,7 @@ import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.exec.spi.JdbcOperation; @@ -32,6 +33,16 @@ public class H2SqlAstTranslator extends AbstractSqlAstT super( sessionFactory, statement ); } + @Override + protected void renderExpressionAsClauseItem(Expression expression) { + expression.accept( this ); + } + + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + booleanExpressionPredicate.getExpression().accept( this ); + } + @Override public void visitOffsetFetchClause(QueryPart queryPart) { if ( isRowsOnlyFetchClauseType( queryPart ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java index 29734b530d..e8ec42332c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java @@ -284,13 +284,13 @@ public class HSQLDialect extends Dialect { switch (unit) { case NANOSECOND: case NATIVE: - pattern.append("timestampadd(sql_tsi_frac_second, ?2, "); //nanos + pattern.append("timestampadd(sql_tsi_frac_second,?2,"); //nanos break; case WEEK: - pattern.append("dateadd('day', ?2*7, "); + pattern.append("dateadd('day',?2*7,"); break; default: - pattern.append("dateadd('?1', ?2, "); + pattern.append("dateadd('?1',?2,"); } if (castTo) { pattern.append("cast(?3 as timestamp)"); @@ -317,14 +317,14 @@ public class HSQLDialect extends Dialect { default: pattern.append("datediff('?1'"); } - pattern.append(", "); + pattern.append(','); if (castFrom) { pattern.append("cast(?2 as timestamp)"); } else { pattern.append("?2"); } - pattern.append(", "); + pattern.append(','); if (castTo) { pattern.append("cast(?3 as timestamp)"); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java index d1ee470b0b..cd82c459bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java @@ -7,6 +7,7 @@ package org.hibernate.dialect; import java.util.List; +import java.util.function.Consumer; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; @@ -15,10 +16,13 @@ import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.ast.tree.cte.CteStatement; +import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; +import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.exec.spi.JdbcOperation; @@ -34,6 +38,68 @@ public class HSQLSqlAstTranslator extends AbstractSqlAs super( sessionFactory, statement ); } + @Override + protected void renderExpressionAsClauseItem(Expression expression) { + expression.accept( this ); + } + + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + booleanExpressionPredicate.getExpression().accept( this ); + } + + // HSQL does not allow CASE expressions where all result arms contain plain parameters. + // At least one result arm must provide some type context for inference, + // so we cast the first result arm if we encounter this condition + + @Override + protected void visitAnsiCaseSearchedExpression( + CaseSearchedExpression caseSearchedExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) { + final List whenFragments = caseSearchedExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSearchedExpression( + caseSearchedExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer ); + } + } + + @Override + protected void visitAnsiCaseSimpleExpression( + CaseSimpleExpression caseSimpleExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) { + final List whenFragments = caseSimpleExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSimpleExpression( + caseSimpleExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer ); + } + } + @Override public boolean supportsFilterClause() { return true; @@ -98,9 +164,7 @@ public class HSQLSqlAstTranslator extends AbstractSqlAs case NOT_DISTINCT_FROM: // HSQL does not like parameters in the distinct from predicate render( lhs, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); - appendSql( " " ); appendSql( operator.sqlText() ); - appendSql( " " ); render( rhs, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); break; default: diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java index ba419c13e0..ef69d2ec0d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java @@ -131,7 +131,7 @@ public class MariaDBDialect extends MySQLDialect { @Override public String getQuerySequencesString() { return getSequenceSupport().supportsSequences() - ? "select table_name from information_schema.TABLES where table_schema = database() and table_type = 'SEQUENCE'" + ? "select table_name from information_schema.TABLES where table_schema=database() and table_type='SEQUENCE'" : super.getQuerySequencesString(); //fancy way to write "null" } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java index 01d7e30ce5..79d052f8d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java @@ -14,6 +14,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; @@ -30,6 +31,16 @@ public class MariaDBSqlAstTranslator extends AbstractSq super( sessionFactory, statement ); } + @Override + protected void renderExpressionAsClauseItem(Expression expression) { + expression.accept( this ); + } + + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + booleanExpressionPredicate.getExpression().accept( this ); + } + @Override protected String getForShare() { return " lock in share mode"; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 0f6ffbd46f..96ed44c0f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -465,11 +465,11 @@ public class MySQLDialect extends Dialect { public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { switch (unit) { case NANOSECOND: - return "timestampadd(microsecond, (?2)/1e3, ?3)"; + return "timestampadd(microsecond,(?2)/1e3,?3)"; case NATIVE: - return "timestampadd(microsecond, ?2, ?3)"; + return "timestampadd(microsecond,?2,?3)"; default: - return "timestampadd(?1, ?2, ?3)"; + return "timestampadd(?1,?2,?3)"; } } @@ -477,11 +477,11 @@ public class MySQLDialect extends Dialect { public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) { switch (unit) { case NANOSECOND: - return "timestampdiff(microsecond, ?2, ?3)*1e3"; + return "timestampdiff(microsecond,?2,?3)*1e3"; case NATIVE: - return "timestampdiff(microsecond, ?2, ?3)"; + return "timestampdiff(microsecond,?2,?3)"; default: - return "timestampdiff(?1, ?2, ?3)"; + return "timestampdiff(?1,?2,?3)"; } } @@ -773,7 +773,7 @@ public class MySQLDialect extends Dialect { else { orderByElement.append( "1 else 0" ); } - orderByElement.append( " end, " ); + orderByElement.append( " end," ); } // Nulls precedence has already been handled so passing NONE value. orderByElement.append( super.renderOrderByElement( expression, collation, order, NullPrecedence.NONE ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java index 16c8419ed6..a35b529c73 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java @@ -14,6 +14,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; @@ -30,6 +31,16 @@ public class MySQLSqlAstTranslator extends AbstractSqlA super( sessionFactory, statement ); } + @Override + protected void renderExpressionAsClauseItem(Expression expression) { + expression.accept( this ); + } + + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + booleanExpressionPredicate.getExpression().accept( this ); + } + @Override protected String getForShare() { return getDialect().getVersion() >= 800 ? " for share" : " lock in share mode"; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java index 35d7305877..e7242adc0b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -172,6 +172,7 @@ public class OracleDialect extends Dialect { CommonFunctionFactory.covarPopSamp( queryEngine ); CommonFunctionFactory.corr( queryEngine ); CommonFunctionFactory.regrLinearRegressionAggregates( queryEngine ); + CommonFunctionFactory.bitLength_pattern( queryEngine, "vsize(?1)*8" ); if ( getVersion() < 900 ) { queryEngine.getSqmFunctionRegistry().register( "coalesce", new NvlCoalesceEmulation() ); @@ -184,8 +185,8 @@ public class OracleDialect extends Dialect { queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "locate", StandardBasicTypes.INTEGER, - "instr(?2, ?1)", - "instr(?2, ?1, ?3)" + "instr(?2,?1)", + "instr(?2,?1,?3)" ).setArgumentListSignature("(pattern, string[, start])"); } @@ -367,7 +368,7 @@ public class OracleDialect extends Dialect { @Override public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { StringBuilder pattern = new StringBuilder(); - pattern.append("(?3 + "); + pattern.append("(?3+"); switch ( unit ) { case YEAR: case QUARTER: @@ -1005,7 +1006,7 @@ public class OracleDialect extends Dialect { @Override public String getCurrentSchemaCommand() { - return "SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL"; + return "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java index 37ff98e0ee..fa27f37636 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java @@ -163,7 +163,7 @@ public class OracleSqlAstTranslator extends AbstractSql appendSql( ')' ); } } - appendSql( " where rownum <= " ); + appendSql( " where rownum<=" ); final Stack clauseStack = getClauseStack(); clauseStack.push( Clause.WHERE ); try { @@ -307,7 +307,7 @@ public class OracleSqlAstTranslator extends AbstractSql visitDecodeCaseSearchedExpression( caseSearchedExpression ); } else { - visitAnsiCaseSearchedExpression( caseSearchedExpression ); + super.visitCaseSearchedExpression( caseSearchedExpression, inSelect ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java index e4ca0e0662..f296943a7e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -175,15 +175,15 @@ public class PostgreSQLDialect extends Dialect { public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { switch ( unit ) { case NANOSECOND: - return "(?3 + (?2)/1e3 * interval '1 microsecond')"; + return "(?3+(?2)/1e3*interval '1 microsecond')"; case NATIVE: - return "(?3 + (?2) * interval '1 second')"; + return "(?3+(?2)*interval '1 second')"; case QUARTER: //quarter is not supported in interval literals - return "(?3 + (?2) * interval '3 month')"; + return "(?3+(?2)*interval '3 month')"; case WEEK: //week is not supported in interval literals - return "(?3 + (?2) * interval '7 day')"; + return "(?3+(?2)*interval '7 day')"; default: - return "(?3 + (?2) * interval '1 ?1')"; + return "(?3+(?2)*interval '1 ?1')"; } } @@ -324,7 +324,7 @@ public class PostgreSQLDialect extends Dialect { "locate", StandardBasicTypes.INTEGER, "position(?1 in ?2)", - "(position(?1 in substring(?2 from ?3)) + (?3) - 1)" + "(position(?1 in substring(?2 from ?3))+(?3)-1)" ).setArgumentListSignature("(pattern, string[, start])"); if ( getVersion() >= 940 ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLSqlAstTranslator.java index e15722f617..d164cc9e84 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLSqlAstTranslator.java @@ -15,6 +15,7 @@ import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; @@ -31,6 +32,16 @@ public class PostgreSQLSqlAstTranslator extends Abstrac super( sessionFactory, statement ); } + @Override + protected void renderExpressionAsClauseItem(Expression expression) { + expression.accept( this ); + } + + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + booleanExpressionPredicate.getExpression().accept( this ); + } + @Override protected void renderMaterializationHint(CteMaterialization materialization) { if ( getDialect().getVersion() >= 1200 ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index 89f1c8386b..576e46e87c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -148,6 +148,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { CommonFunctionFactory.truncate_round( queryEngine ); CommonFunctionFactory.everyAny_sumIif( queryEngine ); + CommonFunctionFactory.bitLength_pattern( queryEngine, "datalength(?1) * 8" ); if ( getVersion() >= 10 ) { CommonFunctionFactory.locate_charindex( queryEngine ); @@ -237,7 +238,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { @Override public String currentTime() { - return "convert(time, getdate())"; + return "convert(time,getdate())"; } @Override @@ -298,24 +299,24 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { lockMode = lockOptions.getLockMode(); } - final String writeLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "updlock, holdlock"; + final String writeLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "updlock,holdlock"; final String readLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock"; - final String noWaitStr = lockOptions.getTimeOut() == LockOptions.NO_WAIT ? ", nowait" : ""; - final String skipLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? ", readpast" : ""; + final String noWaitStr = lockOptions.getTimeOut() == LockOptions.NO_WAIT ? ",nowait" : ""; + final String skipLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? ",readpast" : ""; switch ( lockMode ) { //noinspection deprecation case UPGRADE: case PESSIMISTIC_WRITE: case WRITE: - return tableName + " with (" + writeLockStr + ", rowlock" + noWaitStr + skipLockStr + ")"; + return tableName + " with (" + writeLockStr + ",rowlock" + noWaitStr + skipLockStr + ")"; case PESSIMISTIC_READ: - return tableName + " with (" + readLockStr + ", rowlock" + noWaitStr + skipLockStr + ")"; + return tableName + " with (" + readLockStr + ",rowlock" + noWaitStr + skipLockStr + ")"; case UPGRADE_SKIPLOCKED: - return tableName + " with (updlock, rowlock, readpast" + noWaitStr + ")"; + return tableName + " with (updlock,rowlock,readpast" + noWaitStr + ")"; case UPGRADE_NOWAIT: - return tableName + " with (updlock, holdlock, rowlock, nowait)"; + return tableName + " with (updlock,holdlock,rowlock,nowait)"; default: return tableName; } @@ -327,11 +328,11 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { case UPGRADE_NOWAIT: case PESSIMISTIC_WRITE: case WRITE: - return tableName + " with (updlock, rowlock)"; + return tableName + " with (updlock,rowlock)"; case PESSIMISTIC_READ: - return tableName + " with (holdlock, rowlock)"; + return tableName + " with (holdlock,rowlock)"; case UPGRADE_SKIPLOCKED: - return tableName + " with (updlock, rowlock, readpast)"; + return tableName + " with (updlock,rowlock,readpast)"; default: return tableName; } @@ -501,7 +502,7 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { else { orderByElement.append( "1 else 0" ); } - orderByElement.append( " end, " ); + orderByElement.append( " end," ); } // Nulls precedence has already been handled so passing NONE value. @@ -593,12 +594,12 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { //Java Durations are usually the only thing //we find expressed in nanosecond precision, //and they can easily be very large - return "dateadd(nanosecond, ?2%1000000000, dateadd(second, ?2/1000000000, ?3))"; + return "dateadd(nanosecond,?2%1000000000,dateadd(second,?2/1000000000,?3))"; case NATIVE: //microsecond is the "native" precision - return "dateadd(microsecond, ?2%1000000, dateadd(second, ?2/1000000, ?3))"; + return "dateadd(microsecond,?2%1000000,dateadd(second,?2/1000000,?3))"; default: - return "dateadd(?1, ?2, ?3)"; + return "dateadd(?1,?2,?3)"; } } @@ -607,14 +608,14 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { switch (unit) { case NATIVE: //use microsecond as the "native" precision - return "datediff_big(microsecond, ?2, ?3)"; + return "datediff_big(microsecond,?2,?3)"; default: //datediff() returns an int, and can easily //overflow when dealing with "physical" //durations, so use datediff_big() return unit.normalized() == NANOSECOND - ? "datediff_big(?1, ?2, ?3)" - : "datediff(?1, ?2, ?3)"; + ? "datediff_big(?1,?2,?3)" + : "datediff(?1,?2,?3)"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java index 252e5d1b45..3756e16fc9 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java @@ -66,7 +66,7 @@ public class SQLServerSqlAstTranslator extends Abstract if ( rendersTableReferenceAlias( currentClause ) ) { final String identificationVariable = tableReference.getIdentificationVariable(); if ( identificationVariable != null ) { - appendSql( getDialect().getTableAliasSeparator() ); + appendSql( ' ' ); appendSql( identificationVariable ); } } @@ -82,27 +82,27 @@ public class SQLServerSqlAstTranslator extends Abstract private void renderLockHint(LockMode lockMode) { if ( getDialect().getVersion() >= 9 ) { final int effectiveLockTimeout = getEffectiveLockTimeout( lockMode ); - final String writeLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? "updlock" : "updlock, holdlock"; + final String writeLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? "updlock" : "updlock,holdlock"; final String readLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock"; - final String noWaitStr = effectiveLockTimeout == LockOptions.NO_WAIT ? ", nowait" : ""; - final String skipLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? ", readpast" : ""; + final String noWaitStr = effectiveLockTimeout == LockOptions.NO_WAIT ? ",nowait" : ""; + final String skipLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? ",readpast" : ""; switch ( lockMode ) { //noinspection deprecation case UPGRADE: case PESSIMISTIC_WRITE: case WRITE: - appendSql( " with (" + writeLockStr + ", rowlock" + noWaitStr + skipLockStr + ")" ); + appendSql( " with (" + writeLockStr + ",rowlock" + noWaitStr + skipLockStr + ")" ); break; case PESSIMISTIC_READ: - appendSql( " with (" + readLockStr + ", rowlock" + noWaitStr + skipLockStr + ")" ); + appendSql( " with (" + readLockStr + ",rowlock" + noWaitStr + skipLockStr + ")" ); break; case UPGRADE_SKIPLOCKED: - appendSql( " with (updlock, rowlock, readpast" + noWaitStr + ")" ); + appendSql( " with (updlock,rowlock,readpast" + noWaitStr + ")" ); break; case UPGRADE_NOWAIT: - appendSql( " with (updlock, holdlock, rowlock, nowait)" ); + appendSql( " with (updlock,holdlock,rowlock,nowait)" ); break; } } @@ -113,13 +113,13 @@ public class SQLServerSqlAstTranslator extends Abstract case UPGRADE_NOWAIT: case PESSIMISTIC_WRITE: case WRITE: - appendSql( " with (updlock, rowlock)" ); + appendSql( " with (updlock,rowlock)" ); break; case PESSIMISTIC_READ: - appendSql(" with (holdlock, rowlock)" ); + appendSql(" with (holdlock,rowlock)" ); break; case UPGRADE_SKIPLOCKED: - appendSql( " with (updlock, rowlock, readpast)" ); + appendSql( " with (updlock,rowlock,readpast)" ); break; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java index 9b0a69ddd3..12ee92e35b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java @@ -445,7 +445,7 @@ public class SpannerDialect extends Dialect { case MONTH: throw new SemanticException("illegal unit for timestamp_add(): " + unit); default: - return "timestamp_add(?3, interval ?2 ?1)"; + return "timestamp_add(?3,interval ?2 ?1)"; } } else { @@ -457,7 +457,7 @@ public class SpannerDialect extends Dialect { case NATIVE: throw new SemanticException("illegal unit for date_add(): " + unit); default: - return "date_add(?3, interval ?2 ?1)"; + return "date_add(?3,interval ?2 ?1)"; } } } @@ -471,7 +471,7 @@ public class SpannerDialect extends Dialect { case MONTH: throw new SemanticException("illegal unit for timestamp_diff(): " + unit); default: - return "timestamp_diff(?3, ?2, ?1)"; + return "timestamp_diff(?3,?2,?1)"; } } else { @@ -483,7 +483,7 @@ public class SpannerDialect extends Dialect { case NATIVE: throw new SemanticException("illegal unit for date_diff(): " + unit); default: - return "date_diff(?3, ?2, ?1)"; + return "date_diff(?3,?2,?1)"; } } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java index e73f1dffe9..791bcdbc25 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java @@ -219,13 +219,13 @@ public class SybaseASEDialect extends SybaseDialect { // If the driver or database do not support bigdatetime and bigtime types, // we try to operate on milliseconds instead if ( getVersion() < 1550 || jtdsDriver ) { - return "dateadd(millisecond, ?2/1000000, ?3)"; + return "dateadd(millisecond,?2/1000000,?3)"; } else { - return "dateadd(mcs, ?2/1000, ?3)"; + return "dateadd(mcs,?2/1000,?3)"; } default: - return "dateadd(?1, ?2, ?3)"; + return "dateadd(?1,?2,?3)"; } } @@ -235,9 +235,9 @@ public class SybaseASEDialect extends SybaseDialect { switch ( unit ) { case NANOSECOND: case NATIVE: - return "(datediff(mcs, ?2, ?3)*1000)"; + return "(datediff(mcs,?2,?3)*1000)"; default: - return "datediff(?1, ?2, ?3)"; + return "datediff(?1,?2,?3)"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java index f6352fe0e5..10b05c9e85 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java @@ -7,16 +7,20 @@ package org.hibernate.dialect; import java.util.List; +import java.util.function.Consumer; import org.hibernate.LockMode; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; import org.hibernate.sql.ast.SqlAstJoinType; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.MutationStatement; import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.ast.tree.cte.CteStatement; +import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; +import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.JdbcParameter; @@ -44,6 +48,58 @@ public class SybaseASESqlAstTranslator extends Abstract super( sessionFactory, statement ); } + // Sybase ASE does not allow CASE expressions where all result arms contain plain parameters. + // At least one result arm must provide some type context for inference, + // so we cast the first result arm if we encounter this condition + + @Override + protected void visitAnsiCaseSearchedExpression( + CaseSearchedExpression caseSearchedExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) { + final List whenFragments = caseSearchedExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSearchedExpression( + caseSearchedExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer ); + } + } + + @Override + protected void visitAnsiCaseSimpleExpression( + CaseSimpleExpression caseSimpleExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) { + final List whenFragments = caseSimpleExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSimpleExpression( + caseSimpleExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer ); + } + } + @Override protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) { super.renderTableReference( tableReference, lockMode ); @@ -168,14 +224,13 @@ public class SybaseASESqlAstTranslator extends Abstract boolean rhsNotNullPredicate = lhs instanceof NullnessLiteral || lhs instanceof Literal - || lhs instanceof JdbcParameter; + || isParameter( lhs ); boolean lhsNotNullPredicate = rhs instanceof NullnessLiteral || rhs instanceof Literal - || rhs instanceof JdbcParameter; + || isParameter( rhs ); if ( rhsNotNullPredicate || lhsNotNullPredicate ) { lhs.accept( this ); - appendSql( " " ); switch ( operator ) { case DISTINCT_FROM: appendSql( "<>" ); @@ -194,7 +249,6 @@ public class SybaseASESqlAstTranslator extends Abstract appendSql( operator.sqlText() ); break; } - appendSql( " " ); rhs.accept( this ); if ( lhsNotNullPredicate ) { appendSql( " and " ); @@ -308,7 +362,7 @@ public class SybaseASESqlAstTranslator extends Abstract @Override protected String getFromDual() { - return " from (select 1) as dual(c1)"; + return " from (select 1) dual(c1)"; } private boolean supportsTopClause() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java index 0df9168e38..1abebfe07c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java @@ -215,6 +215,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect { CommonFunctionFactory.replace_strReplace( queryEngine ); CommonFunctionFactory.everyAny_sumCaseCase( queryEngine ); + CommonFunctionFactory.bitLength_pattern( queryEngine, "datalength(?1) * 8" ); } @Override @@ -238,11 +239,11 @@ public class SybaseDialect extends AbstractTransactSQLDialect { if ( to == CastType.STRING ) { switch ( from ) { case DATE: - return "str_replace(convert(varchar, ?1, 102), '.', '-')"; + return "str_replace(convert(varchar,?1,102),'.','-')"; case TIME: - return "convert(varchar, ?1, 108)"; + return "convert(varchar,?1,108)"; case TIMESTAMP: - return "str_replace(convert(varchar, ?1, 23), 'T', ' ')"; + return "str_replace(convert(varchar,?1,23),'T',' ')"; } } return super.castPattern( from, to ); @@ -259,7 +260,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect { @Override public String extractPattern(TemporalUnit unit) { //TODO!! - return "datepart(?1, ?2)"; + return "datepart(?1,?2)"; } @Override @@ -270,13 +271,13 @@ public class SybaseDialect extends AbstractTransactSQLDialect { @Override public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { //TODO!! - return "dateadd(?1, ?2, ?3)"; + return "dateadd(?1,?2,?3)"; } @Override public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) { //TODO!! - return "datediff(?1, ?2, ?3)"; + return "datediff(?1,?2,?3)"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseSqlAstTranslator.java index 107f901e96..8eab3562d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseSqlAstTranslator.java @@ -7,14 +7,18 @@ package org.hibernate.dialect; import java.util.List; +import java.util.function.Consumer; import org.hibernate.LockMode; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.ast.tree.cte.CteStatement; +import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; +import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.SqlTuple; @@ -35,6 +39,58 @@ public class SybaseSqlAstTranslator extends AbstractSql super( sessionFactory, statement ); } + // Sybase does not allow CASE expressions where all result arms contain plain parameters. + // At least one result arm must provide some type context for inference, + // so we cast the first result arm if we encounter this condition + + @Override + protected void visitAnsiCaseSearchedExpression( + CaseSearchedExpression caseSearchedExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSearchedExpression ) ) { + final List whenFragments = caseSearchedExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSearchedExpression( + caseSearchedExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSearchedExpression( caseSearchedExpression, resultRenderer ); + } + } + + @Override + protected void visitAnsiCaseSimpleExpression( + CaseSimpleExpression caseSimpleExpression, + Consumer resultRenderer) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.DEFAULT && areAllResultsParameters( caseSimpleExpression ) ) { + final List whenFragments = caseSimpleExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + super.visitAnsiCaseSimpleExpression( + caseSimpleExpression, + e -> { + if ( e == firstResult ) { + renderCasted( e ); + } + else { + resultRenderer.accept( e ); + } + } + ); + } + else { + super.visitAnsiCaseSimpleExpression( caseSimpleExpression, resultRenderer ); + } + } + @Override protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) { super.renderTableReference( tableReference, lockMode ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java index 4c78b28843..25bfa9b4f5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java @@ -134,7 +134,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "trunc" ) .setArgumentCountBetween( 1, 2 ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setArgumentListSignature("(number[, places])") + .setArgumentListSignature( "(number[, places])" ) .register(); } @@ -142,7 +142,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "truncate" ) .setExactArgumentCount( 2 ) //some databases allow 1 arg but in these it's a synonym for trunc() .setInvariantType( StandardBasicTypes.DOUBLE ) - .setArgumentListSignature("(number, places)") + .setArgumentListSignature( "(number, places)" ) .register(); } @@ -153,7 +153,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "truncate", "round(?1,?2,1)" ) .setExactArgumentCount( 2 ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setArgumentListSignature("(number, places)") + .setArgumentListSignature( "(number, places)" ) .register(); } @@ -165,7 +165,7 @@ public class CommonFunctionFactory { .setArgumentCountBetween( 0, 1 ) .setUseParenthesesWhenNoArgs( true ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setArgumentListSignature("([seed])") + .setArgumentListSignature( "([seed])" ) .register(); } @@ -177,9 +177,11 @@ public class CommonFunctionFactory { } public static void median_percentileCont(QueryEngine queryEngine, boolean over) { - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "median", - "percentile_cont(0.5) within group (order by ?1)" - + (over ? " over()" : "") ) + queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( + "median", + "percentile_cont(0.5) within group (order by ?1)" + + ( over ? " over()" : "" ) + ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); @@ -253,14 +255,14 @@ public class CommonFunctionFactory { public static void regrLinearRegressionAggregates(QueryEngine queryEngine) { Arrays.asList( - "regr_avgx", "regr_avgy", "regr_count", "regr_intercept", "regr_r2", - "regr_slope", "regr_sxx", "regr_sxy", "regr_syy" - ) - .forEach( fnName -> - queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( fnName ) - .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount( 2 ) - .register() + "regr_avgx", "regr_avgy", "regr_count", "regr_intercept", "regr_r2", + "regr_slope", "regr_sxx", "regr_sxy", "regr_syy" + ) + .forEach( + fnName -> queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( fnName ) + .setInvariantType( StandardBasicTypes.DOUBLE ) + .setExactArgumentCount( 2 ) + .register() ); } @@ -331,12 +333,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ltrim" ) .setInvariantType( StandardBasicTypes.STRING ) .setArgumentCountBetween( 1, 2 ) - .setArgumentListSignature("(string[, characters])") + .setArgumentListSignature( "(string[, characters])" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "rtrim" ) .setInvariantType( StandardBasicTypes.STRING ) .setArgumentCountBetween( 1, 2 ) - .setArgumentListSignature("(string[, characters])") + .setArgumentListSignature( "(string[, characters])" ) .register(); } @@ -344,12 +346,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ltrim" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 1 ) - .setArgumentListSignature("(string)") + .setArgumentListSignature( "(string)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "rtrim" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 1 ) - .setArgumentListSignature("(string)") + .setArgumentListSignature( "(string)" ) .register(); } @@ -357,12 +359,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "lpad" ) .setInvariantType( StandardBasicTypes.STRING ) .setArgumentCountBetween( 2, 3 ) - .setArgumentListSignature("(string, length[, padding])") + .setArgumentListSignature( "(string, length[, padding])" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "rpad" ) .setInvariantType( StandardBasicTypes.STRING ) .setArgumentCountBetween( 2, 3 ) - .setArgumentListSignature("(string, length[, padding])") + .setArgumentListSignature( "(string, length[, padding])" ) .register(); } @@ -375,13 +377,13 @@ public class CommonFunctionFactory { StandardBasicTypes.STRING, "lpad(?1,?2,' ')", "lpad(?1,?2,?3)" - ).setArgumentListSignature("(string, length[, padding])"); + ).setArgumentListSignature( "(string, length[, padding])" ); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", StandardBasicTypes.STRING, "rpad(?1,?2,' ')", "rpad(?1,?2,?3)" - ).setArgumentListSignature("(string, length[, padding])"); + ).setArgumentListSignature( "(string, length[, padding])" ); } /** @@ -393,13 +395,13 @@ public class CommonFunctionFactory { StandardBasicTypes.STRING, "(space(?2-len(?1))+?1)", "(replicate(?3,?2-len(?1))+?1)" - ).setArgumentListSignature("(string, length[, padding])"); + ).setArgumentListSignature( "(string, length[, padding])" ); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", StandardBasicTypes.STRING, "(?1+space(?2-len(?1)))", "(?1+replicate(?3,?2-len(?1)))" - ).setArgumentListSignature("(string, length[, padding])"); + ).setArgumentListSignature( "(string, length[, padding])" ); } public static void pad_repeat(QueryEngine queryEngine) { @@ -408,13 +410,13 @@ public class CommonFunctionFactory { StandardBasicTypes.STRING, "(repeat(' ',?2-character_length(?1))||?1)", "(repeat(?3,?2-character_length(?1))||?1)" - ).setArgumentListSignature("(string, length[, padding])"); + ).setArgumentListSignature( "(string, length[, padding])" ); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", StandardBasicTypes.STRING, "(?1||repeat(' ',?2-character_length(?1)))", "(?1||repeat(?3,?2-character_length(?1)))" - ).setArgumentListSignature("(string, length[, padding])"); + ).setArgumentListSignature( "(string, length[, padding])" ); } /** @@ -426,13 +428,13 @@ public class CommonFunctionFactory { StandardBasicTypes.STRING, "lfill(?1,' ',?2)", "lfill(?1,?3,?2)" - ).setArgumentListSignature("(string, length[, padding])"); + ).setArgumentListSignature( "(string, length[, padding])" ); queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( "rpad", StandardBasicTypes.STRING, "rfill(?1,' ',?2)", "rfill(?1,?3,?2)" - ).setArgumentListSignature("(string, length[, padding])"); + ).setArgumentListSignature( "(string, length[, padding])" ); } public static void reverse(QueryEngine queryEngine) { @@ -453,7 +455,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "repeat" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(string, times)") + .setArgumentListSignature( "(string, times)" ) .register(); } @@ -461,12 +463,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "left" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(string, length)") + .setArgumentListSignature( "(string, length)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "right" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(string, length)") + .setArgumentListSignature( "(string, length)" ) .register(); } @@ -474,12 +476,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "left", "substr(?1,1,?2)" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(string, length)") + .setArgumentListSignature( "(string, length)" ) .register(); queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "right", "substr(?1,-?2)" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(string, length)") + .setArgumentListSignature( "(string, length)" ) .register(); } @@ -487,12 +489,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "left", "substr(?1,1,?2)" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(string, length)") + .setArgumentListSignature( "(string, length)" ) .register(); queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "right", "substr(?1,length(?1)-?2+1)" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(string, length)") + .setArgumentListSignature( "(string, length)" ) .register(); } @@ -500,7 +502,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "replicate" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(string, times)") + .setArgumentListSignature( "(string, times)" ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "repeat", "replicate" ); } @@ -523,7 +525,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "instr" ) .setInvariantType( StandardBasicTypes.INTEGER ) .setArgumentCountBetween( 2, 4 ) - .setArgumentListSignature("(string, pattern[, start[, occurrence]])") + .setArgumentListSignature( "(string, pattern[, start[, occurrence]])" ) .register(); } @@ -531,7 +533,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "substr" ) .setInvariantType( StandardBasicTypes.STRING ) .setArgumentCountBetween( 2, 3 ) - .setArgumentListSignature("(string, start[, length])") + .setArgumentListSignature( "(string, start[, length])" ) .register(); } @@ -573,22 +575,22 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_and" ) .setExactArgumentCount( 2 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitand", "bit_and"); + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitand", "bit_and" ); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_or" ) .setExactArgumentCount( 2 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitor", "bit_or"); + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitor", "bit_or" ); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_xor" ) .setExactArgumentCount( 2 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitxor", "bit_xor"); + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitxor", "bit_xor" ); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_not" ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitnot", "bit_not"); + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitnot", "bit_not" ); } /** @@ -598,22 +600,22 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bin_and" ) .setMinArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitand", "bin_and"); + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitand", "bin_and" ); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bin_or" ) .setMinArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitor", "bin_or"); + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitor", "bin_or" ); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bin_xor" ) .setMinArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitxor", "bin_xor"); + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitxor", "bin_xor" ); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bin_not" ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitnot", "bin_not"); + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "bitnot", "bin_not" ); } /** @@ -650,7 +652,7 @@ public class CommonFunctionFactory { .register(); //MySQL has it but how is that even useful? - // queryEngine.getSqmFunctionRegistry().namedTemplateBuilder( "bit_xor" ) +// queryEngine.getSqmFunctionRegistry().namedTemplateBuilder( "bit_xor" ) // .setExactArgumentCount( 1 ) // .register(); } @@ -662,13 +664,13 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "every" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) - .setArgumentListSignature("(predicate)") + .setArgumentListSignature( "(predicate)" ) .register(); queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "any" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) - .setArgumentListSignature("(predicate)") + .setArgumentListSignature( "(predicate)" ) .register(); } @@ -681,17 +683,18 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "bool_and" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) - .setArgumentListSignature("(predicate)") + .setArgumentListSignature( "(predicate)" ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "every", "bool_and" ); queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "bool_or" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) - .setArgumentListSignature("(predicate)") + .setArgumentListSignature( "(predicate)" ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "any", "bool_or" ); } + /** * These are aggregate functions taking one argument, * for databases that have to emulate the boolean @@ -756,34 +759,34 @@ public class CommonFunctionFactory { } public static void dayofweekmonthyear(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("dayofweek") - .setInvariantType(StandardBasicTypes.INTEGER) - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "dayofweek" ) + .setInvariantType( StandardBasicTypes.INTEGER ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("dayofmonth") - .setInvariantType(StandardBasicTypes.INTEGER) - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "dayofmonth" ) + .setInvariantType( StandardBasicTypes.INTEGER ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey("day", "dayofmonth"); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("dayofyear") - .setInvariantType(StandardBasicTypes.INTEGER) - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "day", "dayofmonth" ); + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "dayofyear" ) + .setInvariantType( StandardBasicTypes.INTEGER ) + .setExactArgumentCount( 1 ) .register(); } public static void dayOfWeekMonthYear(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("day_of_week") - .setInvariantType(StandardBasicTypes.INTEGER) - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "day_of_week" ) + .setInvariantType( StandardBasicTypes.INTEGER ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("day_of_month") - .setInvariantType(StandardBasicTypes.INTEGER) - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "day_of_month" ) + .setInvariantType( StandardBasicTypes.INTEGER ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey("day", "day_of_month"); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("day_of_year") - .setInvariantType(StandardBasicTypes.INTEGER) - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "day", "day_of_month" ); + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "day_of_year" ) + .setInvariantType( StandardBasicTypes.INTEGER ) + .setExactArgumentCount( 1 ) .register(); } @@ -828,7 +831,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ceil" ) .setExactArgumentCount( 1 ) // To avoid truncating to a specific data type, we default to using the argument type - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "ceiling", "ceil" ); } @@ -929,7 +932,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "concat", "(?1||?2...)" ) .setInvariantType( StandardBasicTypes.STRING ) // .setMinArgumentCount( 1 ) - .setArgumentListSignature("(string0[, string1[, ...]])") + .setArgumentListSignature( "(string0[, string1[, ...]])" ) .register(); } @@ -940,7 +943,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "concat", "(?1+?2...)" ) .setInvariantType( StandardBasicTypes.STRING ) // .setMinArgumentCount( 1 ) - .setArgumentListSignature("(string0[, string1[, ...]])") + .setArgumentListSignature( "(string0[, string1[, ...]])" ) .register(); } @@ -998,12 +1001,12 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "makedate" ) .setInvariantType( StandardBasicTypes.DATE ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(year, dayofyear)") + .setArgumentListSignature( "(year, dayofyear)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "maketime" ) .setInvariantType( StandardBasicTypes.TIME ) .setExactArgumentCount( 3 ) - .setArgumentListSignature("(hour, min, sec)") + .setArgumentListSignature( "(hour, min, sec)" ) .register(); } @@ -1076,50 +1079,50 @@ public class CommonFunctionFactory { .setUseParenthesesWhenNoArgs( false ) .register(); - queryEngine.getSqmFunctionRegistry().noArgsBuilder("local_time", "localtime") + queryEngine.getSqmFunctionRegistry().noArgsBuilder( "local_time", "localtime" ) .setInvariantType( StandardBasicTypes.LOCAL_TIME ) .setUseParenthesesWhenNoArgs( false ) .register(); - queryEngine.getSqmFunctionRegistry().noArgsBuilder("local_datetime", "localtimestamp") + queryEngine.getSqmFunctionRegistry().noArgsBuilder( "local_datetime", "localtimestamp" ) .setInvariantType( StandardBasicTypes.LOCAL_DATE_TIME ) .setUseParenthesesWhenNoArgs( false ) .register(); } public static void trigonometry(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("sin") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "sin" ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("cos") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "cos" ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("tan") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "tan" ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("asin") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "asin" ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("acos") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "acos" ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("atan") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "atan" ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("atan2") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "atan2" ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount(2) + .setExactArgumentCount( 2 ) .register(); } @@ -1127,14 +1130,14 @@ public class CommonFunctionFactory { * Transact-SQL atan2 is misspelled */ public static void atan2_atn2(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "atan2", "atn2") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "atan2", "atn2" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 2 ) .register(); } public static void coalesce(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("coalesce") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "coalesce" ) .setMinArgumentCount( 1 ) .register(); } @@ -1143,15 +1146,15 @@ public class CommonFunctionFactory { * SAP DB */ public static void coalesce_value(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("value") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "value" ) .setMinArgumentCount( 1 ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "coalesce", "value" ); } public static void nullif(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("nullif") - .setExactArgumentCount(2) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "nullif" ) + .setExactArgumentCount( 2 ) .register(); } @@ -1159,7 +1162,7 @@ public class CommonFunctionFactory { * ANSI SQL-style */ public static void length_characterLength(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("character_length") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "character_length" ) .setInvariantType( StandardBasicTypes.INTEGER ) .setExactArgumentCount( 1 ) .register(); @@ -1191,16 +1194,23 @@ public class CommonFunctionFactory { } public static void octetLength(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("octet_length") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "octet_length" ) .setInvariantType( StandardBasicTypes.INTEGER ) .setExactArgumentCount( 1 ) .register(); } public static void bitLength(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("bit_length") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_length" ) .setInvariantType( StandardBasicTypes.INTEGER ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) + .register(); + } + + public static void bitLength_pattern(QueryEngine queryEngine, String pattern) { + queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "bit_length", pattern ) + .setInvariantType( StandardBasicTypes.INTEGER ) + .setExactArgumentCount( 1 ) .register(); } @@ -1208,18 +1218,18 @@ public class CommonFunctionFactory { * ANSI-style */ public static void position(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder("position", "position(?1 in ?2)") + queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "position", "position(?1 in ?2)" ) .setInvariantType( StandardBasicTypes.INTEGER ) - .setExactArgumentCount(2) - .setArgumentListSignature("(pattern in string)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(pattern in string)" ) .register(); } public static void locate(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("locate") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "locate" ) .setInvariantType( StandardBasicTypes.INTEGER ) - .setArgumentCountBetween(2, 3) - .setArgumentListSignature("(pattern, string[, start])") + .setArgumentCountBetween( 2, 3 ) + .setArgumentListSignature( "(pattern, string[, start])" ) .register(); } @@ -1230,7 +1240,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "charindex" ) .setInvariantType( StandardBasicTypes.INTEGER ) .setArgumentCountBetween( 2, 3 ) - .setArgumentListSignature("(pattern, string[, start])") + .setArgumentListSignature( "(pattern, string[, start])" ) .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "locate", "charindex" ); } @@ -1239,29 +1249,33 @@ public class CommonFunctionFactory { * locate() in terms of ANSI position() and substring() */ public static void locate_positionSubstring(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern("locate", - StandardBasicTypes.INTEGER, - "position(?1 in ?2)", "(position(?1 in substring(?2 from ?3))+?3)") - .setArgumentListSignature("(pattern, string[, start])"); + queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( + "locate", + StandardBasicTypes.INTEGER, + "position(?1 in ?2)", "(position(?1 in substring(?2 from ?3))+?3)" + ) + .setArgumentListSignature( "(pattern, string[, start])" ); } /** * ANSI-style substring */ public static void substringFromFor(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern("substring", - StandardBasicTypes.STRING, - "substring(?1 from ?2)", "substring(?1 from ?2 for ?3)") - .setArgumentListSignature("(string{ from|,} start[{ for|,} length])"); + queryEngine.getSqmFunctionRegistry().registerBinaryTernaryPattern( + "substring", + StandardBasicTypes.STRING, + "substring(?1 from ?2)", "substring(?1 from ?2 for ?3)" + ) + .setArgumentListSignature( "(string{ from|,} start[{ for|,} length])" ); } /** * Not the same as ANSI-style substring! */ public static void substring(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("substring") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "substring" ) .setInvariantType( StandardBasicTypes.STRING ) - .setArgumentCountBetween(2, 3) - .setArgumentListSignature("(string{ from|,} start[{ for|,} length])") + .setArgumentCountBetween( 2, 3 ) + .setArgumentListSignature( "(string{ from|,} start[{ for|,} length])" ) .register(); } @@ -1276,7 +1290,7 @@ public class CommonFunctionFactory { "substring(?1,?2,len(?1)-?2+1)", "substring(?1,?2,?3)" ) - .setArgumentListSignature("(string{ from|,} start[{ for|,} length])"); + .setArgumentListSignature( "(string{ from|,} start[{ for|,} length])" ); } /** @@ -1284,17 +1298,17 @@ public class CommonFunctionFactory { */ public static void substring_substr(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "substring", "substr" ) - .setArgumentListSignature("(string{ from|,} start[{ for|,} length])") + .setArgumentListSignature( "(string{ from|,} start[{ for|,} length])" ) .setInvariantType( StandardBasicTypes.STRING ) .setArgumentCountBetween( 2, 3 ) .register(); } public static void insert(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("insert") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "insert" ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(4) - .setArgumentListSignature("(string, start, length, replacement)") + .setExactArgumentCount( 4 ) + .setArgumentListSignature( "(string, start, length, replacement)" ) .register(); } @@ -1302,10 +1316,13 @@ public class CommonFunctionFactory { * Postgres */ public static void insert_overlay(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder("insert", "overlay(?1 placing ?4 from ?2 for ?3)") + queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( + "insert", + "overlay(?1 placing ?4 from ?2 for ?3)" + ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(4) - .setArgumentListSignature("(string, start, length, replacement)") + .setExactArgumentCount( 4 ) + .setArgumentListSignature( "(string, start, length, replacement)" ) .register(); } @@ -1313,29 +1330,35 @@ public class CommonFunctionFactory { * ANSI SQL form, supported by Postgres, HSQL */ public static void overlay(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().registerTernaryQuaternaryPattern("overlay", StandardBasicTypes.STRING, - "overlay(?1 placing ?2 from ?3)", - "overlay(?1 placing ?2 from ?3 for ?4)") - .setArgumentListSignature("(string placing replacement from start[ for length])"); + queryEngine.getSqmFunctionRegistry().registerTernaryQuaternaryPattern( + "overlay", + StandardBasicTypes.STRING, + "overlay(?1 placing ?2 from ?3)", + "overlay(?1 placing ?2 from ?3 for ?4)" + ) + .setArgumentListSignature( "(string placing replacement from start[ for length])" ); } /** * For DB2 which has a broken implementation of overlay() */ public static void overlayCharacterLength_overlay(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().registerTernaryQuaternaryPattern("overlay", StandardBasicTypes.STRING, - //use character_length() here instead of length() - //because DB2 doesn't like "length(?)" - "overlay(?1 placing ?2 from ?3 for character_length(?2))", - "overlay(?1 placing ?2 from ?3 for ?4)") - .setArgumentListSignature("(string placing replacement from start[ for length])"); + queryEngine.getSqmFunctionRegistry().registerTernaryQuaternaryPattern( + "overlay", + StandardBasicTypes.STRING, + //use character_length() here instead of length() + //because DB2 doesn't like "length(?)" + "overlay(?1 placing ?2 from ?3 for character_length(?2))", + "overlay(?1 placing ?2 from ?3 for ?4)" + ) + .setArgumentListSignature( "(string placing replacement from start[ for length])" ); } public static void replace(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("replace") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "replace" ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(3) - .setArgumentListSignature("(string, pattern, replacement)") + .setExactArgumentCount( 3 ) + .setArgumentListSignature( "(string, pattern, replacement)" ) .register(); } @@ -1343,33 +1366,33 @@ public class CommonFunctionFactory { * Sybase */ public static void replace_strReplace(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("str_replace") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "str_replace" ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(3) - .setArgumentListSignature("(string, pattern, replacement)") + .setExactArgumentCount( 3 ) + .setArgumentListSignature( "(string, pattern, replacement)" ) .register(); - queryEngine.getSqmFunctionRegistry().registerAlternateKey("replace", "str_replace"); + queryEngine.getSqmFunctionRegistry().registerAlternateKey( "replace", "str_replace" ); } public static void concat(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("concat") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "concat" ) .setInvariantType( StandardBasicTypes.STRING ) - .setMinArgumentCount(1) - .setArgumentListSignature("(string0[, string1[, ...]])") + .setMinArgumentCount( 1 ) + .setArgumentListSignature( "(string0[, string1[, ...]])" ) .register(); } public static void lowerUpper(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("lower") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "lower" ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(1) - .setArgumentListSignature("(string)") + .setExactArgumentCount( 1 ) + .setArgumentListSignature( "(string)" ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("upper") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "upper" ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(1) - .setArgumentListSignature("(string)") + .setExactArgumentCount( 1 ) + .setArgumentListSignature( "(string)" ) .register(); } @@ -1402,14 +1425,14 @@ public class CommonFunctionFactory { public static void datepartDatename(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datepart" ) // .setInvariantType( StandardBasicTypes.INTEGER ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(field, arg)") + .setArgumentListSignature( "(field, arg)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datename" ) .setInvariantType( StandardBasicTypes.STRING ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(field, arg)") + .setArgumentListSignature( "(field, arg)" ) .register(); } @@ -1460,13 +1483,15 @@ public class CommonFunctionFactory { .register(); } - public static void aggregates(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("max") - .setExactArgumentCount(1) + public static void aggregates(QueryEngine queryEngine, SqlAstNodeRenderingMode inferenceArgumentRenderingMode) { + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "max" ) + .setArgumentRenderingMode( inferenceArgumentRenderingMode ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("min") - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "min" ) + .setArgumentRenderingMode( inferenceArgumentRenderingMode ) + .setExactArgumentCount( 1 ) .register(); final TypeConfiguration typeConfiguration = queryEngine.getTypeConfiguration(); @@ -1479,155 +1504,175 @@ public class CommonFunctionFactory { // Double when applied to state fields of floating point types; // BigInteger when applied to state fields of type BigInteger; // and BigDecimal when applied to state fields of type BigDecimal. - queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("sum") - .setReturnTypeResolver( new FunctionReturnTypeResolver() { - @Override - public AllowableFunctionReturnType resolveFunctionReturnType(AllowableFunctionReturnType impliedType, List> arguments, TypeConfiguration typeConfiguration) { - final AllowableFunctionReturnType argType = StandardFunctionReturnTypeResolvers.extractArgumentType( - arguments, - 1 - ); - final BasicType basicType; - if ( argType instanceof BasicType ) { - basicType = (BasicType) argType; - } - else { - basicType = typeConfiguration.getBasicTypeForJavaType( argType.getJavaType() ); - if ( basicType == null ) { - return impliedType; + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "sum" ) + .setArgumentRenderingMode( inferenceArgumentRenderingMode ) + .setReturnTypeResolver( + new FunctionReturnTypeResolver() { + @Override + public AllowableFunctionReturnType resolveFunctionReturnType( + AllowableFunctionReturnType impliedType, + List> arguments, + TypeConfiguration typeConfiguration) { + if ( impliedType != null ) { + return impliedType; + } + final AllowableFunctionReturnType argType = StandardFunctionReturnTypeResolvers.extractArgumentType( + arguments, + 1 + ); + final BasicType basicType; + if ( argType instanceof BasicType ) { + basicType = (BasicType) argType; + } + else { + basicType = typeConfiguration.getBasicTypeForJavaType( argType.getJavaType() ); + if ( basicType == null ) { + return impliedType; + } + } + switch ( basicType.getJdbcTypeDescriptor().getJdbcTypeCode() ) { + case Types.SMALLINT: + case Types.TINYINT: + case Types.INTEGER: + case Types.BIGINT: + return longType; + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + return doubleType; + case Types.DECIMAL: + case Types.NUMERIC: + if ( BigInteger.class.isAssignableFrom( basicType.getJavaType() ) ) { + return bigIntegerType; + } + else { + return bigDecimalType; + } + } + return bigDecimalType; } - } - switch ( basicType.getJdbcTypeDescriptor().getJdbcTypeCode() ) { - case Types.SMALLINT: - case Types.TINYINT: - case Types.INTEGER: - case Types.BIGINT: - return longType; - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - return doubleType; - case Types.DECIMAL: - case Types.NUMERIC: - if ( BigInteger.class.isAssignableFrom( basicType.getJavaType() ) ) { - return bigIntegerType; - } - else { - return bigDecimalType; - } - } - // Better use the implied type than throwing an exception - return impliedType; - } - @Override - public BasicValuedMapping resolveFunctionReturnType(Supplier impliedTypeAccess, List arguments) { - // Resolve according to JPA spec 4.8.5 - final BasicValuedMapping specifiedArgType = StandardFunctionReturnTypeResolvers.extractArgumentValuedMapping( - arguments, - 1 - ); - switch ( specifiedArgType.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode() ) { - case Types.SMALLINT: - case Types.TINYINT: - case Types.INTEGER: - case Types.BIGINT: - return longType; - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - return doubleType; - case Types.DECIMAL: - case Types.NUMERIC: - if ( BigInteger.class.isAssignableFrom( specifiedArgType.getJdbcMapping().getJavaTypeDescriptor().getJavaTypeClass() ) ) { - return bigIntegerType; + @Override + public BasicValuedMapping resolveFunctionReturnType( + Supplier impliedTypeAccess, + List arguments) { + if ( impliedTypeAccess != null ) { + final BasicValuedMapping basicValuedMapping = impliedTypeAccess.get(); + if ( basicValuedMapping != null ) { + return basicValuedMapping; + } } - else { - return bigDecimalType; + // Resolve according to JPA spec 4.8.5 + final BasicValuedMapping specifiedArgType = StandardFunctionReturnTypeResolvers.extractArgumentValuedMapping( + arguments, + 1 + ); + switch ( specifiedArgType.getJdbcMapping().getJdbcTypeDescriptor().getJdbcTypeCode() ) { + case Types.SMALLINT: + case Types.TINYINT: + case Types.INTEGER: + case Types.BIGINT: + return longType; + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + return doubleType; + case Types.DECIMAL: + case Types.NUMERIC: + final Class argTypeClass = specifiedArgType.getJdbcMapping() + .getJavaTypeDescriptor() + .getJavaTypeClass(); + if ( BigInteger.class.isAssignableFrom( argTypeClass ) ) { + return bigIntegerType; + } + else { + return bigDecimalType; + } } - } - return impliedTypeAccess.get(); - } + return bigDecimalType; + } - } ) - .setExactArgumentCount(1) + } + ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("avg") + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "avg" ) + .setArgumentRenderingMode( inferenceArgumentRenderingMode ) .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("count") + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "count" ) .setInvariantType( StandardBasicTypes.LONG ) - .setExactArgumentCount(1) - .setArgumentListSignature("([distinct ]{arg|*})") + .setExactArgumentCount( 1 ) + .setArgumentListSignature( "([distinct ]{arg|*})" ) .register(); } public static void math(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "round" ) // To avoid truncating to a specific data type, we default to using the argument type - .setReturnTypeResolver( useArgType(1) ) - .setExactArgumentCount(2) + .setReturnTypeResolver( useArgType( 1 ) ) + .setExactArgumentCount( 2 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("floor") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "floor" ) // To avoid truncating to a specific data type, we default to using the argument type - .setReturnTypeResolver( useArgType(1) ) - .setExactArgumentCount(1) + .setReturnTypeResolver( useArgType( 1 ) ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("ceiling") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ceiling" ) // To avoid truncating to a specific data type, we default to using the argument type - .setReturnTypeResolver( useArgType(1) ) - .setExactArgumentCount(1) + .setReturnTypeResolver( useArgType( 1 ) ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("mod") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "mod" ) // According to JPA spec 4.6.17.2.2. .setInvariantType( StandardBasicTypes.INTEGER ) - .setExactArgumentCount(2) + .setExactArgumentCount( 2 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("abs") - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "abs" ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("sign") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "sign" ) .setInvariantType( StandardBasicTypes.INTEGER ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("sqrt") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "sqrt" ) // According to JPA spec 4.6.17.2.2. .setInvariantType( StandardBasicTypes.DOUBLE ) - .setExactArgumentCount(1) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("ln") - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "ln" ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("exp") - .setExactArgumentCount(1) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "exp" ) + .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("power") - .setExactArgumentCount(2) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "power" ) + .setExactArgumentCount( 2 ) .setReturnTypeResolver( new PowerReturnTypeResolver() ) .register(); } public static void mod_operator(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "mod", "(?1 % ?2)" ) + queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "mod", "(?1%?2)" ) .setInvariantType( StandardBasicTypes.INTEGER ) .setExactArgumentCount( 2 ) .register(); } public static void power_expLn(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "power", "exp(ln(?1)*?2)") + queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "power", "exp(ln(?1)*?2)" ) .setExactArgumentCount( 2 ) .setReturnTypeResolver( new PowerReturnTypeResolver() ) .register(); @@ -1681,7 +1726,7 @@ public class CommonFunctionFactory { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "datediff" ) .setInvariantType( StandardBasicTypes.INTEGER ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(end, start)") + .setArgumentListSignature( "(end, start)" ) .register(); } @@ -1690,122 +1735,122 @@ public class CommonFunctionFactory { */ public static void adddateSubdateAddtimeSubtime(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "adddate" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, days)") + .setArgumentListSignature( "(datetime, days)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "subdate" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, days)") + .setArgumentListSignature( "(datetime, days)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "addtime" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, time)") + .setArgumentListSignature( "(datetime, time)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "subtime" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, time)") + .setArgumentListSignature( "(datetime, time)" ) .register(); } public static void addMonths(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("add_months") - .setReturnTypeResolver( useArgType(1) ) - .setArgumentListSignature("(datetime, months)") - .setExactArgumentCount(2) + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_months" ) + .setReturnTypeResolver( useArgType( 1 ) ) + .setArgumentListSignature( "(datetime, months)" ) + .setExactArgumentCount( 2 ) .register(); } public static void monthsBetween(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("months_between") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "months_between" ) .setInvariantType( StandardBasicTypes.INTEGER ) - .setExactArgumentCount(2) - .setArgumentListSignature("(end, start)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(end, start)" ) .register(); } public static void daysBetween(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("days_between") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "days_between" ) .setInvariantType( StandardBasicTypes.INTEGER ) - .setExactArgumentCount(2) - .setArgumentListSignature("(end, start)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(end, start)" ) .register(); } public static void secondsBetween(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("seconds_between") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "seconds_between" ) .setInvariantType( StandardBasicTypes.LONG ) - .setExactArgumentCount(2) - .setArgumentListSignature("(end, start)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(end, start)" ) .register(); } public static void yearsMonthsDaysHoursMinutesSecondsBetween(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("years_between") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "years_between" ) .setInvariantType( StandardBasicTypes.INTEGER ) - .setExactArgumentCount(2) - .setArgumentListSignature("(end, start)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(end, start)" ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("months_between") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "months_between" ) .setInvariantType( StandardBasicTypes.INTEGER ) - .setExactArgumentCount(2) - .setArgumentListSignature("(end, start)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(end, start)" ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("days_between") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "days_between" ) .setInvariantType( StandardBasicTypes.INTEGER ) - .setExactArgumentCount(2) - .setArgumentListSignature("(end, start)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(end, start)" ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("hours_between") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "hours_between" ) .setInvariantType( StandardBasicTypes.LONG ) - .setExactArgumentCount(2) - .setArgumentListSignature("(end, start)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(end, start)" ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("minutes_between") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "minutes_between" ) .setInvariantType( StandardBasicTypes.LONG ) - .setExactArgumentCount(2) - .setArgumentListSignature("(end, start)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(end, start)" ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("seconds_between") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "seconds_between" ) .setInvariantType( StandardBasicTypes.LONG ) - .setExactArgumentCount(2) - .setArgumentListSignature("(end, start)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(end, start)" ) .register(); } public static void addYearsMonthsDaysHoursMinutesSeconds(QueryEngine queryEngine) { queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_years" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, years)") + .setArgumentListSignature( "(datetime, years)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_months" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, months)") + .setArgumentListSignature( "(datetime, months)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_days" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, days)") + .setArgumentListSignature( "(datetime, days)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_hours" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, hours)") + .setArgumentListSignature( "(datetime, hours)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_minutes" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, minutes)") + .setArgumentListSignature( "(datetime, minutes)" ) .register(); queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "add_seconds" ) - .setReturnTypeResolver( useArgType(1) ) + .setReturnTypeResolver( useArgType( 1 ) ) .setExactArgumentCount( 2 ) - .setArgumentListSignature("(datetime, seconds)") + .setArgumentListSignature( "(datetime, seconds)" ) .register(); } @@ -1813,10 +1858,10 @@ public class CommonFunctionFactory { * H2-style (uses Java's SimpleDateFormat directly so no need to translate format) */ public static void format_formatdatetime(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "formatdatetime") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "format", "formatdatetime" ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(2) - .setArgumentListSignature("(datetime as pattern)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(datetime as pattern)" ) .register(); } @@ -1826,10 +1871,10 @@ public class CommonFunctionFactory { * @see org.hibernate.dialect.OracleDialect#datetimeFormat */ public static void format_toChar(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "to_char") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "format", "to_char" ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(2) - .setArgumentListSignature("(datetime as pattern)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(datetime as pattern)" ) .register(); } @@ -1839,10 +1884,10 @@ public class CommonFunctionFactory { * @see org.hibernate.dialect.MySQLDialect#datetimeFormat */ public static void format_dateFormat(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "date_format") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "format", "date_format" ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(2) - .setArgumentListSignature("(datetime as pattern)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(datetime as pattern)" ) .register(); } @@ -1852,18 +1897,18 @@ public class CommonFunctionFactory { * @see org.hibernate.dialect.OracleDialect#datetimeFormat */ public static void format_toVarchar(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("format", "to_varchar") + queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "format", "to_varchar" ) .setInvariantType( StandardBasicTypes.STRING ) - .setExactArgumentCount(2) - .setArgumentListSignature("(datetime as pattern)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(datetime as pattern)" ) .register(); } public static void dateTrunc(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder("date_trunc", "date_trunc('?1',?2)") + queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "date_trunc", "date_trunc('?1',?2)" ) .setInvariantType( StandardBasicTypes.TIMESTAMP ) - .setExactArgumentCount(2) - .setArgumentListSignature("(field, datetime)") + .setExactArgumentCount( 2 ) + .setArgumentListSignature( "(field, datetime)" ) .register(); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyConcatFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyConcatFunction.java new file mode 100644 index 0000000000..0703844ff5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DerbyConcatFunction.java @@ -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.dialect.function; + +import java.util.List; + +import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; +import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; +import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; +import org.hibernate.sql.ast.SqlAstNodeRenderingMode; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.spi.SqlAppender; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.type.StandardBasicTypes; + +public class DerbyConcatFunction extends AbstractSqmSelfRenderingFunctionDescriptor { + public DerbyConcatFunction() { + super( + "concat", + StandardArgumentsValidators.min( 1 ), + StandardFunctionReturnTypeResolvers.invariant( StandardBasicTypes.STRING ) + ); + } + + @Override + public void render(SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { + sqlAppender.appendSql( '(' ); + walker.render( sqlAstArguments.get( 0 ), SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + for ( int i = 1; i < sqlAstArguments.size(); i++ ) { + sqlAppender.appendSql( "||" ); + walker.render( sqlAstArguments.get( i ), SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); + } + sqlAppender.appendSql( ')' ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/FieldFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/FieldFunction.java index f699b3c7d9..9abf496a3a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/FieldFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/FieldFunction.java @@ -34,7 +34,7 @@ public class FieldFunction extends AbstractSqmSelfRenderingFunctionDescriptor { sqlAppender.appendSql( "field(" ); sqlAstArguments.get( 0 ).accept( walker ); for ( int i = 1; i < sqlAstArguments.size(); i++ ) { - sqlAppender.appendSql( ", " ); + sqlAppender.appendSql( ',' ); final SqlAstNode argument = sqlAstArguments.get( i ); final SqlTuple sqlTuple = SqlTupleContainer.getSqlTuple( argument ); @@ -42,7 +42,7 @@ public class FieldFunction extends AbstractSqmSelfRenderingFunctionDescriptor { final List expressions = sqlTuple.getExpressions(); for ( int j = 0; j < expressions.size(); j++ ) { if ( j != 0 ) { - sqlAppender.appendSql( ", " ); + sqlAppender.appendSql( ',' ); } expressions.get( j ).accept( walker ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/QuantifiedLeastGreatestEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/QuantifiedLeastGreatestEmulation.java index 035f196284..a1ede382dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/QuantifiedLeastGreatestEmulation.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/QuantifiedLeastGreatestEmulation.java @@ -46,12 +46,12 @@ public class QuantifiedLeastGreatestEmulation sqlAppender.appendSql( " when " ); arguments.get( i ).accept( walker ); sqlAppender.appendSql( operator ); - sqlAppender.appendSql( " all(" ); + sqlAppender.appendSql( "all(" ); String separator = ""; for ( int j = i + 1; j < numberOfArguments; j++ ) { sqlAppender.appendSql( separator ); arguments.get( j ).accept( walker ); - separator = ", "; + separator = ","; } sqlAppender.appendSql( ") then " ); arguments.get( i ).accept( walker ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java index 3381da032c..08157729d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TransactSQLStrFunction.java @@ -63,7 +63,7 @@ public class TransactSQLStrFunction extends CastStrEmulation implements Function sqlAppender.appendSql( "str(" ); arguments.get( 0 ).accept( walker ); for ( int i = 1; i < arguments.size(); i++ ) { - sqlAppender.appendSql( ", " ); + sqlAppender.appendSql( ',' ); arguments.get( i ).accept( walker ); } sqlAppender.appendSql( ')' ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyDB2LimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyDB2LimitHandler.java index 7ad039691e..51ceddc597 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyDB2LimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyDB2LimitHandler.java @@ -22,9 +22,9 @@ public class LegacyDB2LimitHandler extends AbstractLimitHandler { public String processSql(String sql, RowSelection selection) { if ( hasFirstRow( selection ) ) { //nest the main query in an outer select - return "select * from ( select row_.*, rownumber() over(order by order of row_) as rownumber_ from ( " + return "select * from (select row_.*,rownumber() over(order by order of row_) as rownumber_ from (" + sql + fetchFirstRows( selection ) - + " ) as row_ ) as query_ where rownumber_ > " + + ") as row_) as query_ where rownumber_>" + selection.getFirstRow() + " order by rownumber_"; } @@ -43,9 +43,9 @@ public class LegacyDB2LimitHandler extends AbstractLimitHandler { public String processSql(String sql, Limit limit) { if ( hasFirstRow( limit ) ) { //nest the main query in an outer select - return "select * from ( select row_.*, rownumber() over(order by order of row_) as rownumber_ from ( " + return "select * from (select row_.*,rownumber() over(order by order of row_) as rownumber_ from (" + sql + fetchFirstRows( limit ) - + " ) as row_ ) as query_ where rownumber_ > " + + ") as row_) as query_ where rownumber_>" + limit.getFirstRow() + " order by rownumber_"; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyOracleLimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyOracleLimitHandler.java index c5f8a9a154..ef50853465 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyOracleLimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyOracleLimitHandler.java @@ -38,16 +38,16 @@ public class LegacyOracleLimitHandler extends AbstractLimitHandler { final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 ); if ( hasOffset ) { - pagingSelect.append( "select * from (select row_.*, rownum rownum_ from (" ).append( sql ); + pagingSelect.append( "select * from (select row_.*,rownum rownum_ from (" ).append( sql ); if ( version < 900 ) { - pagingSelect.append( ") row_) where rownum_ <= ? and rownum_ > ?" ); + pagingSelect.append( ") row_) where rownum_<=? and rownum_>?" ); } else { - pagingSelect.append( ") row_ where rownum <= ?) where rownum_ > ?" ); + pagingSelect.append( ") row_ where rownum<=?) where rownum_>?" ); } } else { - pagingSelect.append( "select * from (" ).append( sql ).append( ") where rownum <= ?" ); + pagingSelect.append( "select * from (" ).append( sql ).append( ") where rownum<=?" ); } if ( forUpdateClause != null ) { @@ -73,16 +73,16 @@ public class LegacyOracleLimitHandler extends AbstractLimitHandler { final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 ); if ( hasOffset ) { - pagingSelect.append( "select * from (select row_.*, rownum rownum_ from (" ).append( sql ); + pagingSelect.append( "select * from (select row_.*,rownum rownum_ from (" ).append( sql ); if ( version < 900 ) { - pagingSelect.append( ") row_) where rownum_ <= ? and rownum_ > ?" ); + pagingSelect.append( ") row_) where rownum_<=? and rownum_>?" ); } else { - pagingSelect.append( ") row_ where rownum <= ?) where rownum_ > ?" ); + pagingSelect.append( ") row_ where rownum<=?) where rownum_>?" ); } } else { - pagingSelect.append( "select * from (" ).append( sql ).append( ") where rownum <= ?" ); + pagingSelect.append( "select * from (" ).append( sql ).append( ") where rownum<=?" ); } if ( forUpdateClause != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LimitLimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LimitLimitHandler.java index 2dfc372e41..883d88de25 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LimitLimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LimitLimitHandler.java @@ -25,7 +25,7 @@ public class LimitLimitHandler extends AbstractSimpleLimitHandler { @Override protected String limitClause(boolean hasFirstRow) { - return hasFirstRow ? " limit ?, ?" : " limit ?"; + return hasFirstRow ? " limit ?,?" : " limit ?"; } private static final Pattern FOR_UPDATE_PATTERN = diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java index 4214bf16ec..f20c920581 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java @@ -146,15 +146,15 @@ public class Oracle12LimitHandler extends AbstractLimitHandler { if ( hasFirstRow ) { pagingSelect = new StringBuilder( sql.length() + forUpdateClauseLength + 98 ); - pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " ); + pagingSelect.append( "select * from (select row_.*,rownum rownum_ from (" ); pagingSelect.append( sql ); - pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" ); + pagingSelect.append( ") row_ where rownum<=?) where rownum_>?" ); } else { pagingSelect = new StringBuilder( sql.length() + forUpdateClauseLength + 37 ); - pagingSelect.append( "select * from ( " ); + pagingSelect.append( "select * from (" ); pagingSelect.append( sql ); - pagingSelect.append( " ) where rownum <= ?" ); + pagingSelect.append( ") where rownum<=?" ); } if ( isForUpdate ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java index 76d5aae1f0..55c20e841c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java @@ -108,9 +108,9 @@ public class SQLServer2005LimitHandler extends AbstractLimitHandler { String aliases = selectAliases( sql, afterSelectOffset, fromOffset, result ); //warning: changes result by side-effect result.insert( selectOffset, ( hasCommonTables ? "," : "with" ) - + " query_ as (select row_.*, row_number() over (order by current_timestamp) as rownumber_ from (" ) + + " query_ as (select row_.*,row_number() over (order by current_timestamp) as rownumber_ from (" ) .append( ") row_) select " ).append( aliases ) - .append( " from query_ where rownumber_ >= ? and rownumber_ < ?" ); + .append( " from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?" ); + .append( " from query_ where rownumber_>=? and rownumber_ return DomainModelHelper.resolveSubType( this, subType, jpaMetamodel() ); } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Serialization + + protected Object writeReplace() throws ObjectStreamException { + return new SerialForm( jpaMetamodel(), getJavaType() ); + } + + private static class SerialForm implements Serializable { + private final JpaMetamodel jpaMetamodel; + private final Class typeClass; + + public SerialForm(JpaMetamodel jpaMetamodel, Class typeClass) { + this.jpaMetamodel = jpaMetamodel; + this.typeClass = typeClass; + } + + private Object readResolve() { + return jpaMetamodel.managedType( typeClass ); + } + + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Creation diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/MapPersistentAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/MapPersistentAttribute.java index d1cfafa972..46dd4928eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/MapPersistentAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/MapPersistentAttribute.java @@ -17,7 +17,7 @@ import org.hibernate.query.sqm.SqmPathSource; * @author Steve Ebersole */ public interface MapPersistentAttribute extends MapAttribute, PluralPersistentAttribute,V> { - SqmPathSource getKeyPathSource(); + SqmPathSource getKeyPathSource(); @Override SimpleDomainType getKeyType(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java index 78dbe8492a..4ba4e94651 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractAttribute.java @@ -9,11 +9,13 @@ package org.hibernate.metamodel.model.domain.internal; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; import java.io.Serializable; import java.lang.reflect.Member; import java.lang.reflect.Method; import javax.persistence.metamodel.Attribute; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.metamodel.AttributeClassification; import org.hibernate.metamodel.internal.MetadataContext; @@ -106,49 +108,25 @@ public abstract class AbstractAttribute implements PersistentAttribute declaringType; + private final String name; + + public SerialForm(ManagedDomainType declaringType, String name) { + this.declaringType = declaringType; + this.name = name; + } + + private Object readResolve() { + return declaringType.findAttribute( name ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java index f75c57e39e..947421b6c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AbstractPluralAttribute.java @@ -76,6 +76,9 @@ public abstract class AbstractPluralAttribute @Override public SqmPathSource findSubPathSource(String name) { + if ( CollectionPart.Nature.ELEMENT.getName().equals( name ) ) { + return elementPathSource; + } return elementPathSource.findSubPathSource( name ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/BasicSqmPathSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/BasicSqmPathSource.java index 651740e811..14080d60d9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/BasicSqmPathSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/BasicSqmPathSource.java @@ -10,7 +10,6 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.query.NavigablePath; -import org.hibernate.query.sqm.IllegalPathUsageException; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmPath; @@ -37,7 +36,7 @@ public class BasicSqmPathSource @Override public SqmPathSource findSubPathSource(String name) { - throw new IllegalPathUsageException( "Basic paths cannot be dereferenced" ); + throw new IllegalStateException( "Basic paths cannot be dereferenced" ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DiscriminatorSqmPath.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DiscriminatorSqmPath.java index 14647b4c41..1d28c856fa 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DiscriminatorSqmPath.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DiscriminatorSqmPath.java @@ -9,11 +9,12 @@ package org.hibernate.metamodel.model.domain.internal; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityValuedModelPart; +import org.hibernate.metamodel.mapping.ModelPartContainer; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.PathException; import org.hibernate.query.hql.spi.SemanticPathPart; import org.hibernate.query.hql.spi.SqmCreationState; -import org.hibernate.query.sqm.IllegalPathUsageException; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SqmPathSource; @@ -65,7 +66,14 @@ public class DiscriminatorSqmPath extends AbstractSqmPath implements SelfInterpr assert entityDescriptor.hasSubclasses(); final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup( getLhs().getNavigablePath() ); - final EntityMappingType entityMapping = ( (EntityValuedModelPart) tableGroup.getModelPart() ).getEntityMappingType(); + final ModelPartContainer modelPart = tableGroup.getModelPart(); + final EntityMappingType entityMapping; + if ( modelPart instanceof EntityValuedModelPart ) { + entityMapping = ( (EntityValuedModelPart) modelPart ).getEntityMappingType(); + } + else { + entityMapping = (EntityMappingType) ( (PluralAttributeMapping) modelPart ).getElementDescriptor().getPartMappingType(); + } return new DiscriminatorPathInterpretation( getNavigablePath(), entityMapping, tableGroup, sqlAstCreationState ); } @@ -79,7 +87,7 @@ public class DiscriminatorSqmPath extends AbstractSqmPath implements SelfInterpr @Override public SemanticPathPart resolvePathPart(String name, boolean isTerminal, SqmCreationState creationState) { - throw new IllegalPathUsageException( "Discriminator cannot be de-referenced" ); + throw new IllegalStateException( "Discriminator cannot be de-referenced" ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DiscriminatorSqmPathSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DiscriminatorSqmPathSource.java index fa11bef3a6..656f62cf64 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DiscriminatorSqmPathSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/DiscriminatorSqmPathSource.java @@ -10,7 +10,6 @@ import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; -import org.hibernate.query.sqm.IllegalPathUsageException; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.domain.SqmPath; @@ -38,7 +37,7 @@ public class DiscriminatorSqmPathSource extends AbstractSqmPathSource { } @Override - public SqmPathSource findSubPathSource(String name) throws IllegalPathUsageException { - throw new IllegalPathUsageException( "Entity discriminator cannot be de-referenced" ); + public SqmPathSource findSubPathSource(String name) { + throw new IllegalStateException( "Entity discriminator cannot be de-referenced" ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java index a98ffabf71..75d09bccb2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EntityTypeImpl.java @@ -6,6 +6,7 @@ */ package org.hibernate.metamodel.model.domain.internal; +import java.io.ObjectStreamException; import java.io.Serializable; import javax.persistence.metamodel.EntityType; @@ -13,6 +14,7 @@ import org.hibernate.graph.internal.SubGraphImpl; import org.hibernate.graph.spi.SubGraphImplementor; import org.hibernate.mapping.PersistentClass; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; +import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.model.domain.AbstractIdentifiableType; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; @@ -123,7 +125,7 @@ public class EntityTypeImpl return attribute; } - if ( "id".equalsIgnoreCase( name ) ) { + if ( "id".equalsIgnoreCase( name ) || EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( name ) ) { //noinspection unchecked final SingularPersistentAttribute idAttribute = findIdAttribute(); //noinspection RedundantIfStatement @@ -188,4 +190,26 @@ public class EntityTypeImpl "EntityType cannot be used to create an SqmPath - that would be an SqmFrom which are created directly" ); } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Serialization + + protected Object writeReplace() throws ObjectStreamException { + return new SerialForm( jpaMetamodel(), getHibernateEntityName() ); + } + + private static class SerialForm implements Serializable { + private final JpaMetamodel jpaMetamodel; + private final String hibernateEntityName; + + public SerialForm(JpaMetamodel jpaMetamodel, String hibernateEntityName) { + this.jpaMetamodel = jpaMetamodel; + this.hibernateEntityName = hibernateEntityName; + } + + private Object readResolve() { + return jpaMetamodel.entity( hibernateEntityName ); + } + + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java index c088946727..a66dc2b88e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/JpaMetamodelImpl.java @@ -6,6 +6,8 @@ */ package org.hibernate.metamodel.model.domain.internal; +import java.io.ObjectStreamException; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -24,10 +26,12 @@ import javax.persistence.metamodel.EmbeddableType; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.ManagedType; +import org.hibernate.SessionFactory; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.cfg.annotations.NamedEntityGraphDefinition; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.graph.internal.RootGraphImpl; import org.hibernate.graph.spi.AttributeNodeImplementor; import org.hibernate.graph.spi.GraphImplementor; @@ -58,7 +62,7 @@ import org.hibernate.type.spi.TypeConfiguration; /** * @author Steve Ebersole */ -public class JpaMetamodelImpl implements JpaMetamodel { +public class JpaMetamodelImpl implements JpaMetamodel, Serializable { private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( JpaMetamodel.class ); private static final ImportInfo INVALID_IMPORT = new ImportInfo<>( null, null ); @@ -655,4 +659,24 @@ public class JpaMetamodelImpl implements JpaMetamodel { context.registerMappedSuperclassType( mappedSuperclass, mappedSuperclassType ); return mappedSuperclassType; } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Serialization + + private Object writeReplace() throws ObjectStreamException { + return new SerialForm( typeConfiguration.getSessionFactory() ); + } + + private static class SerialForm implements Serializable { + private final SessionFactoryImplementor sessionFactory; + + public SerialForm(SessionFactoryImplementor sessionFactory) { + this.sessionFactory = sessionFactory; + } + + private Object readResolve() { + return sessionFactory.getJpaMetamodel(); + } + + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/ListAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/ListAttributeImpl.java index c30398c923..65763824c4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/ListAttributeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/ListAttributeImpl.java @@ -9,6 +9,7 @@ package org.hibernate.metamodel.model.domain.internal; import java.util.List; import org.hibernate.metamodel.internal.MetadataContext; +import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.model.domain.ListPersistentAttribute; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.hql.spi.SqmCreationState; @@ -44,6 +45,20 @@ class ListAttributeImpl extends AbstractPluralAttribute, E> imp return indexPathSource; } + @Override + public SqmPathSource findSubPathSource(String name) { + final CollectionPart.Nature nature = CollectionPart.Nature.fromNameExact( name ); + if ( nature != null ) { + switch ( nature ) { + case INDEX: + return indexPathSource; + case ELEMENT: + return getElementPathSource(); + } + } + return getElementPathSource().findSubPathSource( name ); + } + @Override public SqmAttributeJoin createSqmJoin( SqmFrom lhs, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MapAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MapAttributeImpl.java index ff69a31736..a1cc3ef6d7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MapAttributeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/MapAttributeImpl.java @@ -55,6 +55,20 @@ class MapAttributeImpl extends AbstractPluralAttribute, V> return getKeyPathSource(); } + @Override + public SqmPathSource findSubPathSource(String name) { + final CollectionPart.Nature nature = CollectionPart.Nature.fromNameExact( name ); + if ( nature != null ) { + switch ( nature ) { + case INDEX: + return keyPathSource; + case ELEMENT: + return getElementPathSource(); + } + } + return getElementPathSource().findSubPathSource( name ); + } + @Override public SimpleDomainType getKeyType() { return (SimpleDomainType) keyPathSource.getSqmPathType(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/NonAggregatedCompositeSqmPathSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/NonAggregatedCompositeSqmPathSource.java index 08212e9627..21698a2c52 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/NonAggregatedCompositeSqmPathSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/NonAggregatedCompositeSqmPathSource.java @@ -7,7 +7,6 @@ package org.hibernate.metamodel.model.domain.internal; import org.hibernate.metamodel.model.domain.ManagedDomainType; -import org.hibernate.query.sqm.IllegalPathUsageException; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath; import org.hibernate.query.sqm.tree.domain.SqmPath; @@ -31,7 +30,7 @@ public class NonAggregatedCompositeSqmPathSource extends AbstractSqmPathSource i } @Override - public SqmPathSource findSubPathSource(String name) throws IllegalPathUsageException { + public SqmPathSource findSubPathSource(String name) { return (SqmPathSource) getSqmPathType().findAttribute( name ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java index 05e50e7724..e56df6a82e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/SingularAttributeImpl.java @@ -221,7 +221,7 @@ public class SingularAttributeImpl } @Override - public SqmPath createSqmPath(SqmPath lhs) { + public SqmPath createSqmPath(SqmPath lhs) { return sqmPathSource.createSqmPath( lhs ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index e7046cb238..8c3f26c92b 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -1289,30 +1289,6 @@ public abstract class AbstractEntityPersister tableGroup, creationState ); - if ( discriminatorMapping != null ) { - discriminatorMapping.applySqlSelections( - navigablePath.append( discriminatorMapping.getPartName() ), - tableGroup, - creationState - ); - } - if ( versionMapping != null ) { - versionMapping.applySqlSelections( - navigablePath.append( versionMapping.getPartName() ), - tableGroup, - creationState - ); - } - for ( int i = 0; i < attributeMappings.size(); i++ ) { - final AttributeMapping attributeMapping = attributeMappings.get( i ); - if ( attributeMapping instanceof SingularAttributeMapping ) { - attributeMapping.applySqlSelections( - navigablePath.append( attributeMapping.getPartName() ), - tableGroup, - creationState - ); - } - } } @Override @@ -1327,33 +1303,6 @@ public abstract class AbstractEntityPersister creationState, selectionConsumer ); - if ( discriminatorMapping != null ) { - discriminatorMapping.applySqlSelections( - navigablePath.append( discriminatorMapping.getPartName() ), - tableGroup, - creationState, - selectionConsumer - ); - } - if ( versionMapping != null ) { - versionMapping.applySqlSelections( - navigablePath.append( versionMapping.getPartName() ), - tableGroup, - creationState, - selectionConsumer - ); - } - for ( int i = 0; i < attributeMappings.size(); i++ ) { - final AttributeMapping attributeMapping = attributeMappings.get( i ); - if ( attributeMapping instanceof SingularAttributeMapping ) { - attributeMapping.applySqlSelections( - navigablePath.append( attributeMapping.getPartName() ), - tableGroup, - creationState, - selectionConsumer - ); - } - } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/ComparisonOperator.java b/hibernate-core/src/main/java/org/hibernate/query/ComparisonOperator.java index 3284e3b8b3..65dc3d7219 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/ComparisonOperator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/ComparisonOperator.java @@ -87,7 +87,7 @@ public enum ComparisonOperator { @Override public String sqlText() { - return "is not distinct from"; + return " is not distinct from "; } }, @@ -114,7 +114,7 @@ public enum ComparisonOperator { @Override public String sqlText() { - return "is distinct from"; + return " is distinct from "; } }, diff --git a/hibernate-core/src/main/java/org/hibernate/query/NavigablePath.java b/hibernate-core/src/main/java/org/hibernate/query/NavigablePath.java index f507fbcdf3..aa6092eeb4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/NavigablePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/NavigablePath.java @@ -6,6 +6,8 @@ */ package org.hibernate.query; +import java.io.Serializable; + import org.hibernate.internal.util.StringHelper; /** @@ -14,7 +16,7 @@ import org.hibernate.internal.util.StringHelper; * * @author Steve Ebersole */ -public class NavigablePath implements DotIdentifierSequence { +public class NavigablePath implements DotIdentifierSequence, Serializable { public static final String IDENTIFIER_MAPPER_PROPERTY = "_identifierMapper"; private final NavigablePath parent; diff --git a/hibernate-core/src/main/java/org/hibernate/query/ParameterMetadata.java b/hibernate-core/src/main/java/org/hibernate/query/ParameterMetadata.java index 9163f57ff6..6566dd8514 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/ParameterMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/query/ParameterMetadata.java @@ -11,6 +11,7 @@ import java.util.function.Consumer; import javax.persistence.Parameter; import org.hibernate.Incubating; +import org.hibernate.metamodel.model.domain.AllowableParameterType; /** @@ -57,6 +58,10 @@ public interface ParameterMetadata { */ QueryParameter resolve(Parameter param); + default AllowableParameterType getInferredParameterType(QueryParameter parameter) { + return null; + } + /** * Is this parameter reference registered in this collection? */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java index a63977c072..1fa9426a7c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java @@ -145,6 +145,9 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder { JpaCompoundSelection array(Selection[] selections); JpaCompoundSelection array(List> selections); + JpaCompoundSelection array(Class resultClass, Selection[] selections); + JpaCompoundSelection array(Class resultClass, List> selections); + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Expressions @@ -272,6 +275,8 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder { @Override JpaParameterExpression parameter(Class paramClass, String name); + JpaParameterExpression parameter(Class paramClass, T value); + @Override JpaExpression concat(Expression x, Expression y); @@ -423,13 +428,12 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder { * @apiNote This is different from the purely JPA form * {@link CriteriaBuilder#tuple} which is intended only for use as * the selection in a root query. - * - * @param tupleType The Java type + *@param tupleType The Java type * @param expressions The individual expressions making up the tuple */ JpaCompoundSelection tuple( Class tupleType, - List> expressions); + List> expressions); /** * Create a tuple, as in a composite value, usable in any @@ -459,7 +463,7 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder { */ JpaCompoundSelection tuple( DomainType tupleType, - List> expressions); + List> expressions); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -671,7 +675,7 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder { @SuppressWarnings("unchecked") JpaInPredicate in(Expression expression, T... values); - JpaInPredicate in(Expression expression, List values); + JpaInPredicate in(Expression expression, Collection values); @Override JpaPredicate exists(Subquery subquery); @@ -724,7 +728,7 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder { * * @return size expression */ - > JpaExpression mapSize(M map); + > JpaExpression mapSize(M map); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaPath.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaPath.java index 28e1450a2b..3fbc91e7af 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/JpaPath.java @@ -6,7 +6,13 @@ */ package org.hibernate.query.criteria; +import java.util.Collection; +import java.util.Map; +import javax.persistence.criteria.Expression; import javax.persistence.criteria.Path; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.SingularAttribute; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.NavigablePath; @@ -46,4 +52,19 @@ public interface JpaPath extends JpaExpression, Path { default JpaPath getParentPath() { return getLhs(); } + + @Override + JpaPath get(SingularAttribute attribute); + + @Override + > JpaExpression get(PluralAttribute collection); + + @Override + > JpaExpression get(MapAttribute map); + + @Override + JpaExpression> type(); + + @Override + JpaPath get(String attributeName); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QuerySplitter.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QuerySplitter.java index 72fedc40fb..4bccc0a261 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QuerySplitter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/QuerySplitter.java @@ -289,6 +289,7 @@ public class QuerySplitter { final SqmRoot copy = new SqmRoot<>( pathSource, sqmRoot.getExplicitAlias(), + sqmRoot.isAllowJoins(), sqmRoot.nodeBuilder() ); return (SqmRoot) getProcessingStateStack().getCurrent().getPathRegistry().resolvePath( @@ -632,7 +633,7 @@ public class QuerySplitter { @Override - public SqmPositionalParameter visitPositionalParameterExpression(SqmPositionalParameter expression) { + public SqmPositionalParameter visitPositionalParameterExpression(SqmPositionalParameter expression) { return new SqmPositionalParameter( expression.getPosition(), expression.allowMultiValuedBinding(), @@ -641,7 +642,7 @@ public class QuerySplitter { } @Override - public SqmNamedParameter visitNamedParameterExpression(SqmNamedParameter expression) { + public SqmNamedParameter visitNamedParameterExpression(SqmNamedParameter expression) { return new SqmNamedParameter( expression.getName(), expression.allowMultiValuedBinding(), @@ -650,12 +651,12 @@ public class QuerySplitter { } @Override - public SqmLiteralEntityType visitEntityTypeLiteralExpression(SqmLiteralEntityType expression) { + public SqmLiteralEntityType visitEntityTypeLiteralExpression(SqmLiteralEntityType expression) { return new SqmLiteralEntityType( expression.getNodeType(), expression.nodeBuilder() ); } @Override - public SqmUnaryOperation visitUnaryOperationExpression(SqmUnaryOperation expression) { + public SqmUnaryOperation visitUnaryOperationExpression(SqmUnaryOperation expression) { return new SqmUnaryOperation( expression.getOperation(), (SqmExpression) expression.getOperand().accept( this ) @@ -672,7 +673,7 @@ public class QuerySplitter { } @Override - public SqmBinaryArithmetic visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) { + public SqmBinaryArithmetic visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) { return new SqmBinaryArithmetic( expression.getOperator(), (SqmExpression) expression.getLeftHandOperand().accept( this ), (SqmExpression) expression.getRightHandOperand().accept( this ), @@ -682,7 +683,7 @@ public class QuerySplitter { } @Override - public SqmSubQuery visitSubQueryExpression(SqmSubQuery expression) { + public SqmSubQuery visitSubQueryExpression(SqmSubQuery expression) { // its not supported for a SubQuery to define a dynamic instantiation, so // any "selectable node" will only ever be an SqmExpression return new SqmSubQuery( 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 08638590ea..5d09fbb733 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 @@ -43,6 +43,7 @@ import org.hibernate.grammars.hql.HqlParserBaseVisitor; import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.StandardStack; import org.hibernate.metamodel.CollectionClassification; +import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.DomainType; @@ -54,6 +55,7 @@ import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; import org.hibernate.query.BinaryArithmeticOperator; import org.hibernate.query.ComparisonOperator; import org.hibernate.query.FetchClauseType; +import org.hibernate.query.NavigablePath; import org.hibernate.query.NullPrecedence; import org.hibernate.query.PathException; import org.hibernate.query.SemanticException; @@ -403,6 +405,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem return new SqmRoot<>( (EntityDomainType) visitEntityName( entityNameContext ), identificationVariable, + false, creationContext.getNodeBuilder() ); } @@ -852,7 +855,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem fromClause.visitRoots( sqmRoot -> selectClause.addSelection( - new SqmSelection<>( sqmRoot, sqmRoot.getExplicitAlias(), creationContext.getNodeBuilder() ) + new SqmSelection<>( sqmRoot, sqmRoot.getAlias(), creationContext.getNodeBuilder() ) ) ); return selectClause; @@ -952,8 +955,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem ); } - final PluralPersistentAttribute pluralAttribute = (PluralPersistentAttribute) sqmPath.getReferencedPathSource(); - final SqmPath elementPath = pluralAttribute.getElementPathSource().createSqmPath( sqmPath ); + final SqmPath elementPath = (SqmPath) sqmPath.resolvePathPart( CollectionPart.Nature.ELEMENT.getName(), true, this ); processingStateStack.getCurrent().getPathRegistry().register( elementPath ); return elementPath; } @@ -1534,7 +1536,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem } } - final SqmRoot sqmRoot = new SqmRoot<>( entityDescriptor, alias, creationContext.getNodeBuilder() ); + final SqmRoot sqmRoot = new SqmRoot<>( entityDescriptor, alias, true, creationContext.getNodeBuilder() ); pathRegistry.register( sqmRoot ); @@ -1688,7 +1690,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem } else { if ( getCreationOptions().useStrictJpaCompliance() ) { - if ( join.getExplicitAlias() != null ){ + if ( join.getExplicitAlias() != null ) { //noinspection rawtypes if ( ( (SqmAttributeJoin) join ).isFetched() ) { throw new StrictJpaComplianceViolation( @@ -2158,13 +2160,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem @Override public SqmPath visitEntityIdReference(HqlParser.EntityIdReferenceContext ctx) { - final SqmPath sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); + final SqmPath sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); final DomainType sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType(); if ( sqmPathType instanceof IdentifiableDomainType ) { - //noinspection unchecked - final SqmPath idPath = ( (IdentifiableDomainType) sqmPathType ).getIdentifierDescriptor() - .createSqmPath( sqmPath ); + final SqmPathSource identifierDescriptor = ( (IdentifiableDomainType) sqmPathType ).getIdentifierDescriptor(); + final SqmPath idPath = sqmPath.get( identifierDescriptor.getPathName() ); if ( ctx.getChildCount() != 5 ) { return idPath; @@ -2184,12 +2185,13 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem @Override public SqmPath visitEntityVersionReference(HqlParser.EntityVersionReferenceContext ctx) { - final SqmPath sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); + final SqmPath sqmPath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); final DomainType sqmPathType = sqmPath.getReferencedPathSource().getSqmPathType(); if ( sqmPathType instanceof IdentifiableDomainType ) { - final IdentifiableDomainType identifiableType = (IdentifiableDomainType) sqmPathType; - final SingularPersistentAttribute versionAttribute = identifiableType.findVersionAttribute(); + @SuppressWarnings("unchecked") + final IdentifiableDomainType identifiableType = (IdentifiableDomainType) sqmPathType; + final SingularPersistentAttribute versionAttribute = identifiableType.findVersionAttribute(); if ( versionAttribute == null ) { throw new SemanticException( "`" + sqmPath.getNavigablePath().getFullPath() + "` resolved to an identifiable-type (`" + @@ -2197,7 +2199,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem ); } - return versionAttribute.createSqmPath( sqmPath ); + return sqmPath.get( versionAttribute ); } throw new SemanticException( "Path does not reference an identifiable-type : " + sqmPath.getNavigablePath().getFullPath() ); @@ -3614,19 +3616,20 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem selectClause.setSelection( literal ); } else { - final SqmPathSource pathSource; + final String partName; switch ( collectionReferenceCtx.getSymbol().getType() ) { case HqlParser.ELEMENTS: - pathSource = attribute.getElementPathSource(); + partName = CollectionPart.Nature.ELEMENT.getName(); break; case HqlParser.INDICES: - pathSource = attribute.getIndexPathSource(); + partName = CollectionPart.Nature.INDEX.getName(); break; default: throw new ParsingException( "Unexpected collection reference : " + collectionReferenceCtx.getText() ); } - subQuery.applyInferableType( pathSource.getSqmPathType() ); - selectClause.setSelection( pathSource.createSqmPath( collectionJoin ) ); + final SqmPath path = collectionJoin.resolvePathPart( partName, true, this ); + subQuery.applyInferableType( path.getNodeType() ); + selectClause.setSelection( path ); } final SqmQuerySpec querySpec = subQuery.getQuerySpec(); querySpec.setFromClause( fromClause ); @@ -3822,13 +3825,11 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem final SqmPathSource pluralAttribute = sqmFrom.getReferencedPathSource(); - if ( !( pluralAttribute instanceof PluralPersistentAttribute ) ) { + if ( !( pluralAttribute instanceof PluralPersistentAttribute ) ) { throw new ParsingException( "Could not resolve identification variable [" + alias + "] as plural-attribute" ); } - return ( (PluralPersistentAttribute) pluralAttribute ).getIndexPathSource().createSqmPath( - sqmFrom - ); + return sqmFrom.resolvePathPart( CollectionPart.Nature.INDEX.getName(), true, this ); } @SuppressWarnings("BooleanMethodIsAlwaysInverted") @@ -4020,6 +4021,17 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem final DotIdentifierConsumer consumer = dotIdentifierConsumerStack.pop(); final SqmExpression indexExpression = (SqmExpression) ctx.getChild( 1 ).accept( this ); final SqmAttributeJoin attributeJoin = (SqmAttributeJoin) consumer.getConsumedPart(); + final NavigablePath navigablePath = attributeJoin.getNavigablePath().getParent().append( + attributeJoin.getNavigablePath().getLocalName(), + indexExpression.toHqlString() + ); + // Reuse an existing indexed path join if possible + for ( SqmJoin sqmJoin : attributeJoin.getSqmJoins() ) { + if ( sqmJoin.getNavigablePath().getLocalName().equals( navigablePath.getLocalName() ) ) { + return sqmJoin; + } + } + final SqmExpression index; if ( attributeJoin instanceof SqmListJoin ) { index = ( (SqmListJoin) attributeJoin ).index(); @@ -4032,6 +4044,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem } attributeJoin.setJoinPredicate( creationContext.getNodeBuilder().equal( index, indexExpression ) ); final SqmIndexedCollectionAccessPath path = new SqmIndexedCollectionAccessPath<>( + navigablePath, attributeJoin, indexExpression ); @@ -4118,7 +4131,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem final SqmPath pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); final SqmPathSource referencedPathSource = pluralAttributePath.getReferencedPathSource(); - if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) { + if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) { throw new PathException( "Illegal attempt to treat non-plural path as a plural path : " + pluralAttributePath.getNavigablePath() ); @@ -4130,11 +4143,13 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem if ( attribute.getCollectionClassification() != CollectionClassification.MAP ) { throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.VALUE_FUNCTION_ON_NON_MAP ); } + final TerminalNode firstNode = (TerminalNode) ctx.getChild( 0 ); + if ( firstNode.getSymbol().getType() == HqlParser.ELEMENTS ) { + throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION ); + } } - SqmPath result = attribute.getElementPathSource().createSqmPath( - pluralAttributePath - ); + SqmPath result = (SqmPath) pluralAttributePath.resolvePathPart( CollectionPart.Nature.ELEMENT.getName(), true, this ); if ( ctx.getChildCount() == 5 ) { result = consumeDomainPath( (HqlParser.DotIdentifierSequenceContext) ctx.getChild( 4 ).getChild( 1 ) ); @@ -4146,26 +4161,19 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem @Override public SqmPath visitCollectionIndexNavigablePath(HqlParser.CollectionIndexNavigablePathContext ctx) { + if ( getCreationOptions().useStrictJpaCompliance() ) { + throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.HQL_COLLECTION_FUNCTION ); + } final SqmPath pluralAttributePath = consumeDomainPath( (HqlParser.PathContext) ctx.getChild( 2 ) ); final SqmPathSource referencedPathSource = pluralAttributePath.getReferencedPathSource(); - if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) { + if ( !(referencedPathSource instanceof PluralPersistentAttribute ) ) { throw new PathException( "Illegal attempt to treat non-plural path as a plural path : " + pluralAttributePath.getNavigablePath() ); } - final PluralPersistentAttribute attribute = (PluralPersistentAttribute) referencedPathSource; - - if ( getCreationOptions().useStrictJpaCompliance() ) { - if ( attribute.getCollectionClassification() != CollectionClassification.MAP ) { - throw new StrictJpaComplianceViolation( StrictJpaComplianceViolation.Type.VALUE_FUNCTION_ON_NON_MAP ); - } - } - - return attribute.getIndexPathSource().createSqmPath( - pluralAttributePath - ); + return (SqmPath) pluralAttributePath.resolvePathPart( CollectionPart.Nature.INDEX.getName(), true, this ); } @Override @@ -4176,16 +4184,12 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem SqmPath result; if ( sqmPath instanceof SqmMapJoin ) { final SqmMapJoin sqmMapJoin = (SqmMapJoin) sqmPath; - result = sqmMapJoin.getReferencedPathSource().getIndexPathSource().createSqmPath( sqmMapJoin ); + result = sqmMapJoin.key(); } else { assert sqmPath instanceof SqmPluralValuedSimplePath; final SqmPluralValuedSimplePath mapPath = (SqmPluralValuedSimplePath) sqmPath; - final SqmPath keyPath = mapPath.getReferencedPathSource() - .getIndexPathSource() - .createSqmPath( mapPath ); - mapPath.registerReusablePath( keyPath ); - result = keyPath; + result = mapPath.resolvePathPart( CollectionPart.Nature.INDEX.getName(), true, this ); } if ( ctx.getChildCount() == 5 ) { @@ -4195,10 +4199,11 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implem return result; } - private SqmPath consumeDomainPath(HqlParser.PathContext parserPath) { + private SqmPath consumeDomainPath(HqlParser.PathContext parserPath) { final SemanticPathPart consumedPart = (SemanticPathPart) parserPath.accept( this ); if ( consumedPart instanceof SqmPath ) { - return (SqmPath) consumedPart; + //noinspection unchecked + return (SqmPath) consumedPart; } throw new SemanticException( "Expecting domain-model path, but found : " + consumedPart ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmPathRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmPathRegistryImpl.java index 0cf4bf91b5..75c333b3f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmPathRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SqmPathRegistryImpl.java @@ -37,12 +37,12 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { private final SqmCreationProcessingState associatedProcessingState; private final JpaCompliance jpaCompliance; - private final Map sqmPathByPath = new HashMap<>(); - private final Map sqmFromByPath = new HashMap<>(); + private final Map> sqmPathByPath = new HashMap<>(); + private final Map> sqmFromByPath = new HashMap<>(); - private final Map sqmFromByAlias = new HashMap<>(); + private final Map> sqmFromByAlias = new HashMap<>(); - private final List simpleSelectionNodes = new ArrayList<>(); + private final List> simpleSelectionNodes = new ArrayList<>(); public SqmPathRegistryImpl(SqmCreationProcessingState associatedProcessingState) { this.associatedProcessingState = associatedProcessingState; @@ -50,7 +50,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { } @Override - public void register(SqmPath sqmPath) { + public void register(SqmPath sqmPath) { SqmTreeCreationLogger.LOGGER.tracef( "SqmProcessingIndex#register(SqmPath) : %s", sqmPath.getNavigablePath().getFullPath() ); // Generally we: @@ -61,8 +61,8 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { // Regarding part #1 (add to the path-by-path map), it is ok for a SqmFrom to replace a // non-SqmFrom. This should equate to, e.g., an implicit join. - if ( sqmPath instanceof SqmFrom ) { - final SqmFrom sqmFrom = (SqmFrom) sqmPath; + if ( sqmPath instanceof SqmFrom ) { + final SqmFrom sqmFrom = (SqmFrom) sqmPath; final String alias = sqmPath.getExplicitAlias(); if ( alias != null ) { @@ -70,7 +70,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { ? alias.toLowerCase( Locale.getDefault() ) : alias; - final SqmFrom previousFrom = sqmFromByAlias.put( aliasToUse, sqmFrom ); + final SqmFrom previousFrom = sqmFromByAlias.put( aliasToUse, sqmFrom ); if ( previousFrom != null ) { throw new AliasCollisionException( @@ -85,7 +85,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { } } - final SqmFrom previousFromByPath = sqmFromByPath.put( sqmPath.getNavigablePath(), sqmFrom ); + final SqmFrom previousFromByPath = sqmFromByPath.put( sqmPath.getNavigablePath(), sqmFrom ); if ( previousFromByPath != null ) { // this should never happen @@ -101,7 +101,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { } } - final SqmPath previousPath = sqmPathByPath.put( sqmPath.getNavigablePath(), sqmPath ); + final SqmPath previousPath = sqmPathByPath.put( sqmPath.getNavigablePath(), sqmPath ); if ( previousPath instanceof SqmFrom ) { // this should never happen @@ -118,14 +118,15 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { } @Override - public SqmPath findPath(NavigablePath path) { - final SqmPath found = sqmPathByPath.get( path ); + public SqmPath findPath(NavigablePath path) { + final SqmPath found = sqmPathByPath.get( path ); if ( found != null ) { - return found; + //noinspection unchecked + return (SqmPath) found; } if ( associatedProcessingState.getParentProcessingState() != null ) { - final SqmFrom containingQueryFrom = associatedProcessingState.getParentProcessingState() + final SqmFrom containingQueryFrom = associatedProcessingState.getParentProcessingState() .getPathRegistry() .findFromByPath( path ); if ( containingQueryFrom != null ) { @@ -138,14 +139,15 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { } @Override - public SqmFrom findFromByPath(NavigablePath navigablePath) { - final SqmFrom found = sqmFromByPath.get( navigablePath ); + public > X findFromByPath(NavigablePath navigablePath) { + final SqmFrom found = sqmFromByPath.get( navigablePath ); if ( found != null ) { - return found; + //noinspection unchecked + return (X) found; } if ( associatedProcessingState.getParentProcessingState() != null ) { - final SqmFrom containingQueryFrom = associatedProcessingState.getParentProcessingState() + final X containingQueryFrom = associatedProcessingState.getParentProcessingState() .getPathRegistry() .findFromByPath( navigablePath ); if ( containingQueryFrom != null ) { @@ -158,15 +160,16 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { } @Override - public SqmFrom findFromByAlias(String alias) { + public > X findFromByAlias(String alias) { final String localAlias = jpaCompliance.isJpaQueryComplianceEnabled() ? alias.toLowerCase( Locale.getDefault() ) : alias; - final SqmFrom registered = sqmFromByAlias.get( localAlias ); + final SqmFrom registered = sqmFromByAlias.get( localAlias ); if ( registered != null ) { - return registered; + //noinspection unchecked + return (X) registered; } if ( associatedProcessingState.getParentProcessingState() != null ) { @@ -177,14 +180,14 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { } @Override - public SqmFrom findFromExposing(String navigableName) { + public > X findFromExposing(String navigableName) { // todo (6.0) : atm this checks every from-element every time, the idea being to make sure there // is only one such element obviously that scales poorly across larger from-clauses. Another // (configurable?) option would be to simply pick the first one as a perf optimization - SqmFrom found = null; - for ( Map.Entry entry : sqmFromByPath.entrySet() ) { - final SqmFrom fromElement = entry.getValue(); + SqmFrom found = null; + for ( Map.Entry> entry : sqmFromByPath.entrySet() ) { + final SqmFrom fromElement = entry.getValue(); if ( definesAttribute( fromElement.getReferencedPathSource(), navigableName ) ) { if ( found != null ) { throw new IllegalStateException( "Multiple from-elements expose unqualified attribute : " + navigableName ); @@ -208,24 +211,26 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { navigableName ); - return found; + //noinspection unchecked + return (X) found; } @Override - public SqmPath resolvePath(NavigablePath navigablePath, Function creator) { + public SqmPath resolvePath(NavigablePath navigablePath, Function> creator) { SqmTreeCreationLogger.LOGGER.tracef( "SqmProcessingIndex#resolvePath(NavigablePath) : %s", navigablePath ); - final SqmPath existing = sqmPathByPath.get( navigablePath ); + final SqmPath existing = sqmPathByPath.get( navigablePath ); if ( existing != null ) { - return existing; + //noinspection unchecked + return (SqmPath) existing; } - final SqmPath sqmPath = creator.apply( navigablePath ); + final SqmPath sqmPath = creator.apply( navigablePath ); register( sqmPath ); return sqmPath; } - private boolean definesAttribute(SqmPathSource containerType, String name) { + private boolean definesAttribute(SqmPathSource containerType, String name) { return containerType.findSubPathSource( name ) != null; } @@ -282,7 +287,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { simpleSelectionNodes.add( node ); } - private void checkResultVariable(SqmAliasedNode selection) { + private void checkResultVariable(SqmAliasedNode selection) { final String alias = selection.getAlias(); if ( alias == null ) { return; @@ -300,7 +305,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry { ); } - final SqmFrom registeredFromElement = sqmFromByAlias.get( alias ); + final SqmFrom registeredFromElement = sqmFromByAlias.get( alias ); if ( registeredFromElement != null ) { if ( !registeredFromElement.equals( selection.getSelectableNode() ) ) { throw new AliasCollisionException( diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SemanticPathPart.java b/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SemanticPathPart.java index 00d5549880..3fe68e91fa 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SemanticPathPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SemanticPathPart.java @@ -29,8 +29,8 @@ public interface SemanticPathPart { boolean isTerminal, SqmCreationState creationState); - SqmPath resolveIndexedAccess( - SqmExpression selector, + SqmPath resolveIndexedAccess( + SqmExpression selector, boolean isTerminal, SqmCreationState creationState); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SqmPathRegistry.java b/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SqmPathRegistry.java index 1ff9f820bc..f9aabd5dd6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SqmPathRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/query/hql/spi/SqmPathRegistry.java @@ -30,7 +30,7 @@ public interface SqmPathRegistry { /** * Register an SqmPath */ - void register(SqmPath sqmPath); + void register(SqmPath sqmPath); /** * Find a SqmFrom by its identification variable (alias). Will search any @@ -38,14 +38,14 @@ public interface SqmPathRegistry { * * @return matching SqmFrom or {@code null} */ - SqmFrom findFromByAlias(String identificationVariable); + > X findFromByAlias(String identificationVariable); /** * Find a SqmFrom by its NavigablePath. Will search any parent contexts as well * * @return matching SqmFrom or {@code null} */ - SqmFrom findFromByPath(NavigablePath navigablePath); + > X findFromByPath(NavigablePath navigablePath); /** * Find a SqmFrom which exposes a Navigable by the given name. Will search any @@ -53,7 +53,7 @@ public interface SqmPathRegistry { * * @return matching SqmFrom or {@code null} */ - SqmFrom findFromExposing(String navigableName); + > X findFromExposing(String navigableName); /** * Find an SqmPath by its NavigablePath. Will return a SqmFrom if the NavigablePath @@ -61,7 +61,7 @@ public interface SqmPathRegistry { * * @return matching SqmPath or {@code null} */ - SqmPath findPath(NavigablePath path); + SqmPath findPath(NavigablePath path); /** * Similar to {@link #findPath}, but accepting a producer to be used @@ -69,7 +69,7 @@ public interface SqmPathRegistry { * * @return The existing or just-created SqmPath */ - SqmPath resolvePath(NavigablePath path, Function creator); + SqmPath resolvePath(NavigablePath path, Function> creator); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ParameterMetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ParameterMetadataImpl.java index 50a8c5e69e..f04537e17e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ParameterMetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ParameterMetadataImpl.java @@ -9,6 +9,7 @@ package org.hibernate.query.internal; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -22,9 +23,11 @@ import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.IdentitySet; import org.hibernate.internal.util.compare.ComparableComparator; +import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.query.QueryParameter; import org.hibernate.query.spi.ParameterMetadataImplementor; import org.hibernate.query.spi.QueryParameterImplementor; +import org.hibernate.query.sqm.tree.expression.SqmParameter; /** * Encapsulates metadata about parameters encountered within a query. @@ -37,19 +40,19 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor { */ public static final ParameterMetadataImpl EMPTY = new ParameterMetadataImpl(); - private final Set> queryParameters; + private final Map, List> queryParameters; private final Set names; private final Set labels; private ParameterMetadataImpl() { - this.queryParameters = Collections.emptySet(); + this.queryParameters = Collections.emptyMap(); this.names = Collections.emptySet(); this.labels = Collections.emptySet(); } - public ParameterMetadataImpl(Set> queryParameters) { + public ParameterMetadataImpl(Map, List> queryParameters) { this.queryParameters = queryParameters; // if we have any ordinal parameters, make sure the numbers @@ -58,7 +61,7 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor { Set names = null; Set labels = null; - for ( QueryParameterImplementor queryParameter : queryParameters ) { + for ( QueryParameterImplementor queryParameter : queryParameters.keySet() ) { if ( queryParameter.getPosition() != null ) { if ( labels == null ) { labels = new HashSet<>(); @@ -90,14 +93,16 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor { if ( CollectionHelper.isEmpty( positionalQueryParameters ) && CollectionHelper.isEmpty( namedQueryParameters ) ) { // no parameters - this.queryParameters = Collections.emptySet(); + this.queryParameters = Collections.emptyMap(); this.names = Collections.emptySet(); this.labels = Collections.emptySet(); } else { - this.queryParameters = new IdentitySet<>(); + this.queryParameters = new IdentityHashMap<>(); if ( positionalQueryParameters != null ) { - this.queryParameters.addAll( positionalQueryParameters.values() ); + for ( QueryParameterImplementor value : positionalQueryParameters.values() ) { + this.queryParameters.put( value, Collections.emptyList() ); + } this.labels = positionalQueryParameters.keySet(); verifyOrdinalParamLabels( labels ); } @@ -105,7 +110,9 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor { labels = null; } if ( namedQueryParameters != null ) { - this.queryParameters.addAll( namedQueryParameters.values() ); + for ( QueryParameterImplementor value : namedQueryParameters.values() ) { + this.queryParameters.put( value, Collections.emptyList() ); + } this.names = namedQueryParameters.keySet(); } else { @@ -160,25 +167,34 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor { return queryParameters.size(); } + @Override + public AllowableParameterType getInferredParameterType(QueryParameter parameter) { + final List sqmParameters = queryParameters.get( parameter ); + if ( sqmParameters == null || sqmParameters.isEmpty() ) { + return null; + } + return sqmParameters.get( 0 ).getNodeType(); + } + @Override public boolean containsReference(QueryParameter parameter) { //noinspection SuspiciousMethodCalls - return queryParameters.contains( parameter ); + return queryParameters.containsKey( parameter ); } @Override public void visitParameters(Consumer> consumer) { - queryParameters.forEach( consumer ); + queryParameters.keySet().forEach( consumer ); } @Override public Set> getRegistrations() { - return Collections.unmodifiableSet( queryParameters ); + return Collections.unmodifiableSet( queryParameters.keySet() ); } @Override public boolean hasAnyMatching(Predicate> filter) { - for ( QueryParameterImplementor queryParameter : queryParameters ) { + for ( QueryParameterImplementor queryParameter : queryParameters.keySet() ) { if ( filter.test( queryParameter ) ) { return true; } @@ -212,13 +228,20 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor { @Override public QueryParameterImplementor getQueryParameter(String name) { - for ( QueryParameterImplementor queryParameter : queryParameters ) { + for ( QueryParameterImplementor queryParameter : queryParameters.keySet() ) { if ( name.equals( queryParameter.getName() ) ) { return queryParameter; } } - return null; + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "Could not locate named parameter [%s], expecting one of [%s]", + name, + String.join( ", ", names ) + ) + ); } @@ -237,7 +260,7 @@ public class ParameterMetadataImpl implements ParameterMetadataImplementor { @Override public QueryParameterImplementor getQueryParameter(int positionLabel) { - for ( QueryParameterImplementor queryParameter : queryParameters ) { + for ( QueryParameterImplementor queryParameter : queryParameters.keySet() ) { if ( queryParameter.getPosition() != null && queryParameter.getPosition() == positionLabel ) { return queryParameter; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java index eac40a2eaf..757a56c40a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java @@ -20,6 +20,7 @@ import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterBindingTypeResolver; import org.hibernate.query.spi.QueryParameterBindingValidator; import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.CoercionException; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.spi.TypeConfiguration; @@ -128,19 +129,19 @@ public class QueryParameterBindingImpl implements QueryParameterBinding, J return false; } - if ( value instanceof Collection ) { - setBindValues( (Collection) value ); - return true; - } - - if ( value.getClass().isArray() ) { - setBindValues( (Collection) Arrays.asList( (Object[]) value ) ); + if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) { + //noinspection unchecked + setBindValues( (Collection) value ); return true; } return false; } + private boolean isRegisteredAsBasicType(Class valueClass) { + return getTypeConfiguration().getBasicTypeForJavaType( valueClass ) != null; + } + private void bindValue(T value) { this.isBound = true; this.bindValue = value; @@ -186,7 +187,20 @@ public class QueryParameterBindingImpl implements QueryParameterBinding, J } if ( bindType != null ) { - value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this ); + try { + value = bindType.getExpressableJavaTypeDescriptor().coerce( value, this ); + } + catch ( CoercionException ex ) { + throw new IllegalArgumentException( + String.format( + "Parameter value [%s] did not match expected type [%s (%s)]", + value, + bindType.getTypeName(), + temporalTypePrecision == null ? "n/a" : temporalTypePrecision.name() + ), + ex + ); + } } else if ( queryParameter.getHibernateType() != null ) { value = queryParameter.getHibernateType().getExpressableJavaTypeDescriptor().coerce( value, this ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java index c981299442..3a973e0b81 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java @@ -22,11 +22,13 @@ import org.hibernate.cache.spi.QueryKey; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.mapping.MappingModelExpressable; +import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.query.QueryParameter; import org.hibernate.query.spi.ParameterMetadataImplementor; import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.spi.QueryParameterImplementor; +import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypedExpressable; import org.hibernate.type.spi.TypeConfiguration; @@ -106,7 +108,12 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings { ); } - final QueryParameterBinding binding = new QueryParameterBindingImpl<>( queryParameter, sessionFactory, null, queryParametersValidationEnabled ); + final QueryParameterBinding binding = new QueryParameterBindingImpl<>( + queryParameter, + sessionFactory, + parameterMetadata.getInferredParameterType( queryParameter ), + queryParametersValidationEnabled + ); parameterBindingMap.put( queryParameter, binding ); return binding; diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java index c5fef69f9d..fe17a2f477 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryEngine.java @@ -73,6 +73,8 @@ public class QueryEngine { final SqmTranslatorFactory sqmTranslatorFactory = resolveSqmTranslatorFactory( queryEngineOptions, dialect ); return new QueryEngine( + sessionFactory.getUuid(), + sessionFactory.getName(), () -> sessionFactory.getRuntimeMetamodels().getJpaMetamodel(), sessionFactory.getSessionFactoryOptions().getCriteriaValueHandlingMode(), sessionFactory.getSessionFactoryOptions().getPreferredSqlTypeCodeForBoolean(), @@ -99,6 +101,8 @@ public class QueryEngine { private final int preferredSqlTypeCodeForBoolean; public QueryEngine( + String uuid, + String name, Supplier jpaMetamodelAccess, ValueHandlingMode criteriaValueHandlingMode, int preferredSqlTypeCodeForBoolean, @@ -118,6 +122,8 @@ public class QueryEngine { this.hqlTranslator = hqlTranslator; this.criteriaBuilder = new SqmCriteriaNodeBuilder( + uuid, + name, this, jpaMetamodelAccess, serviceRegistry, @@ -152,6 +158,8 @@ public class QueryEngine { * Simplified constructor mainly meant for Quarkus use */ public QueryEngine( + String uuid, + String name, JpaMetamodel jpaMetamodel, ValueHandlingMode criteriaValueHandlingMode, int preferredSqlTypeCodeForBoolean, @@ -170,6 +178,8 @@ public class QueryEngine { dialect.initializeFunctionRegistry( this ); this.criteriaBuilder = new SqmCriteriaNodeBuilder( + uuid, + name, this, () -> jpaMetamodel, serviceRegistry, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/IllegalPathUsageException.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/IllegalPathUsageException.java deleted file mode 100644 index 10f23a380d..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/IllegalPathUsageException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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; - -import org.hibernate.query.SemanticException; - -/** - * Indicates an attempt to use an SqmPath in an unsupported manner - e.g., an - * attempt to de-reference a basic value - * - * @author Steve Ebersole - */ -public class IllegalPathUsageException extends SemanticException { - public IllegalPathUsageException(String message) { - super( message ); - } - - public IllegalPathUsageException(String message, Exception cause) { - super( message, cause ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java index f23939b787..bece06c097 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/NodeBuilder.java @@ -409,7 +409,7 @@ public interface NodeBuilder extends HibernateCriteriaBuilder { @Override SqmTuple tuple( Class tupleType, - List> expressions); + List> expressions); @Override SqmTuple tuple( @@ -419,7 +419,7 @@ public interface NodeBuilder extends HibernateCriteriaBuilder { @Override SqmTuple tuple( DomainType tupleType, - List> expressions); + List> expressions); @Override SqmPredicate and(Expression x, Expression y); @@ -603,7 +603,7 @@ public interface NodeBuilder extends HibernateCriteriaBuilder { SqmInPredicate in(Expression expression, T... values); @Override - SqmInPredicate in(Expression expression, List values); + SqmInPredicate in(Expression expression, Collection values); SqmInPredicate in(Expression expression, SqmSubQuery subQuery); @@ -620,7 +620,7 @@ public interface NodeBuilder extends HibernateCriteriaBuilder { > SqmExpression mapSize(JpaExpression mapExpression); @Override - SqmExpression mapSize(Map map); + > SqmExpression mapSize(M map); @Override SqmSortSpecification sort( diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java index be15644460..982a4b5b98 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/SemanticQueryWalker.java @@ -141,15 +141,15 @@ public interface SemanticQueryWalker { T visitAnyValuedValuedPath(SqmAnyValuedSimplePath path); - T visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path); + T visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path); T visitEntityValuedPath(SqmEntityValuedSimplePath path); T visitPluralValuedPath(SqmPluralValuedSimplePath path); - T visitSelfInterpretingSqmPath(SelfInterpretingSqmPath sqmPath); + T visitSelfInterpretingSqmPath(SelfInterpretingSqmPath sqmPath); - T visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path); + T visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path); T visitMaxElementPath(SqmMaxElementPath path); @@ -161,7 +161,7 @@ public interface SemanticQueryWalker { T visitTreatedPath(SqmTreatedPath sqmTreatedPath); - T visitCorrelation(SqmCorrelation correlation); + T visitCorrelation(SqmCorrelation correlation); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -193,9 +193,9 @@ public interface SemanticQueryWalker { T visitLiteral(SqmLiteral literal); - T visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral); + T visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral); - T visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral); + T visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral); T visitTuple(SqmTuple sqmTuple); @@ -229,27 +229,27 @@ public interface SemanticQueryWalker { T visitUnaryOperationExpression(SqmUnaryOperation expression); - T visitFunction(SqmFunction tSqmFunction); + T visitFunction(SqmFunction tSqmFunction); - T visitExtractUnit(SqmExtractUnit extractUnit); + T visitExtractUnit(SqmExtractUnit extractUnit); T visitFormat(SqmFormat sqmFormat); - T visitCastTarget(SqmCastTarget sqmCastTarget); + T visitCastTarget(SqmCastTarget sqmCastTarget); T visitTrimSpecification(SqmTrimSpecification trimSpecification); - T visitDistinct(SqmDistinct distinct); + T visitDistinct(SqmDistinct distinct); T visitStar(SqmStar sqmStar); - T visitCoalesce(SqmCoalesce sqmCoalesce); + T visitCoalesce(SqmCoalesce sqmCoalesce); - T visitToDuration(SqmToDuration toDuration); + T visitToDuration(SqmToDuration toDuration); T visitByUnit(SqmByUnit sqmByUnit); - T visitDurationUnit(SqmDurationUnit durationUnit); + T visitDurationUnit(SqmDurationUnit durationUnit); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // predicates @@ -306,7 +306,7 @@ public interface SemanticQueryWalker { T visitPluralAttributeSizeFunction(SqmCollectionSize function); - T visitMapEntryFunction(SqmMapEntryReference function); + T visitMapEntryFunction(SqmMapEntryReference function); T visitFullyQualifiedClass(Class namedClass); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmPathSource.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmPathSource.java index a54752a019..d8caaa0ea5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmPathSource.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/SqmPathSource.java @@ -11,6 +11,7 @@ import javax.persistence.metamodel.Bindable; import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.query.hql.spi.SqmCreationState; +import org.hibernate.query.sqm.tree.SqmExpressableAccessor; import org.hibernate.query.sqm.tree.domain.SqmPath; /** @@ -22,7 +23,7 @@ import org.hibernate.query.sqm.tree.domain.SqmPath; * * @author Steve Ebersole */ -public interface SqmPathSource extends SqmExpressable, Bindable { +public interface SqmPathSource extends SqmExpressable, Bindable, SqmExpressableAccessor { /** * The name of this thing. Mainly used in logging and when creating a * {@link org.hibernate.query.NavigablePath} @@ -38,15 +39,20 @@ public interface SqmPathSource extends SqmExpressable, Bindable { /** * Find a SqmPathSource by name relative to this source. * - * @throws IllegalPathUsageException to indicate that this source cannot be de-referenced + * @throws IllegalStateException to indicate that this source cannot be de-referenced */ - SqmPathSource findSubPathSource(String name) throws IllegalPathUsageException; + SqmPathSource findSubPathSource(String name); /** * Create an SQM path for this source relative to the given left-hand side */ SqmPath createSqmPath(SqmPath lhs); + @Override + default SqmExpressable getExpressable() { + return (SqmExpressable) getSqmPathType(); + } + default X sqmAs(Class targetType) { if ( targetType.isInstance( this ) ) { //noinspection unchecked diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/NamedSqmFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/NamedSqmFunctionDescriptor.java index b1763ab162..d1dd002eb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/NamedSqmFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/NamedSqmFunctionDescriptor.java @@ -113,7 +113,7 @@ public class NamedSqmFunctionDescriptor boolean firstPass = true; for ( SqlAstNode arg : sqlAstArguments ) { if ( !firstPass ) { - sqlAppender.appendSql( ", " ); + sqlAppender.appendSql( "," ); } if ( caseWrapper && !( arg instanceof Distinct ) ) { sqlAppender.appendSql( "case when " ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java index 11e7665f3c..0431dbab42 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java @@ -14,6 +14,7 @@ import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.tree.SqmTypedNode; +import org.hibernate.query.sqm.tree.expression.SqmAggregateFunction; import org.hibernate.query.sqm.tree.expression.SqmDistinct; import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.select.SqmSelectableNode; @@ -22,7 +23,8 @@ import org.hibernate.sql.ast.tree.predicate.Predicate; /** * @author Christian Beikov */ -public class SelfRenderingSqmAggregateFunction extends SelfRenderingSqmFunction { +public class SelfRenderingSqmAggregateFunction extends SelfRenderingSqmFunction + implements SqmAggregateFunction { private final SqmPredicate filter; @@ -55,6 +57,11 @@ public class SelfRenderingSqmAggregateFunction extends SelfRenderingSqmFuncti ); } + @Override + public SqmPredicate getFilter() { + return filter; + } + @Override public void appendHqlString(StringBuilder sb) { final List> arguments = getArguments(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ConcreteSqmSelectQueryPlan.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ConcreteSqmSelectQueryPlan.java index 325b1f8196..df49538864 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ConcreteSqmSelectQueryPlan.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ConcreteSqmSelectQueryPlan.java @@ -12,6 +12,7 @@ import java.util.List; import java.util.Map; import javax.persistence.Tuple; import javax.persistence.TupleElement; +import javax.persistence.criteria.CompoundSelection; import org.hibernate.ScrollMode; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; @@ -22,6 +23,7 @@ import org.hibernate.internal.EmptyScrollableResults; import org.hibernate.internal.util.streams.StingArrayCollector; import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.query.IllegalQueryOperationException; +import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryParameterImplementor; @@ -32,6 +34,7 @@ import org.hibernate.query.sqm.sql.SqmTranslation; import org.hibernate.query.sqm.sql.SqmTranslator; import org.hibernate.query.sqm.sql.SqmTranslatorFactory; import org.hibernate.query.sqm.tree.expression.SqmParameter; +import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.query.sqm.tree.select.SqmSelection; import org.hibernate.sql.ast.SqlAstTranslator; @@ -140,10 +143,22 @@ public class ConcreteSqmSelectQueryPlan implements SelectQueryPlan { if ( Tuple.class.isAssignableFrom( resultType ) ) { // resultType is Tuple.. if ( queryOptions.getTupleTransformer() == null ) { - final Map, Integer> tupleElementMap = new IdentityHashMap<>( selections.size() ); - for ( int i = 0; i < selections.size(); i++ ) { - final SqmSelection selection = selections.get( i ); - tupleElementMap.put( selection.getSelectableNode(), i ); + final Map, Integer> tupleElementMap; + if ( selections.size() == 1 && selections.get( 0 ).getSelectableNode() instanceof CompoundSelection ) { + final List> selectionItems = selections.get( 0 ) + .getSelectableNode() + .getSelectionItems(); + tupleElementMap = new IdentityHashMap<>( selectionItems.size() ); + for ( int i = 0; i < selectionItems.size(); i++ ) { + tupleElementMap.put( selectionItems.get( i ), i ); + } + } + else { + tupleElementMap = new IdentityHashMap<>( selections.size() ); + for ( int i = 0; i < selections.size(); i++ ) { + final SqmSelection selection = selections.get( i ); + tupleElementMap.put( selection.getSelectableNode(), i ); + } } return (RowTransformer) new RowTransformerJpaTupleImpl( new TupleMetadata( tupleElementMap ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/DomainParameterXref.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/DomainParameterXref.java index d4b9f784bd..e8f97f9d49 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/DomainParameterXref.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/DomainParameterXref.java @@ -175,8 +175,8 @@ public class DomainParameterXref { /** * Get all of the QueryParameters mapped by this xref */ - public Set> getQueryParameters() { - return sqmParamsByQueryParam.keySet(); + public Map, List> getQueryParameters() { + return sqmParamsByQueryParam; } public int getQueryParameterCount() { @@ -216,6 +216,9 @@ public class DomainParameterXref { if ( sqmParameter instanceof SqmJpaCriteriaParameterWrapper ) { return ( (SqmJpaCriteriaParameterWrapper) sqmParameter ).getJpaCriteriaParameter(); } + else if ( sqmParameter instanceof QueryParameterImplementor ) { + return (QueryParameterImplementor) sqmParameter; + } return queryParamBySqmParam.get( sqmParameter ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ParameterCollector.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ParameterCollector.java index dde6619bd0..f3a02f0d0d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ParameterCollector.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ParameterCollector.java @@ -14,5 +14,5 @@ import org.hibernate.query.sqm.tree.expression.SqmParameter; * @author Steve Ebersole */ public interface ParameterCollector { - void addParameter(SqmParameter parameter); + void addParameter(SqmParameter parameter); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java index b4a5db35ea..9be41f7282 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/QuerySqmImpl.java @@ -6,9 +6,11 @@ */ package org.hibernate.query.sqm.internal; +import java.sql.Types; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -31,6 +33,8 @@ import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.collections.IdentitySet; +import org.hibernate.metamodel.model.domain.BasicDomainType; +import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Loadable; import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode; @@ -57,6 +61,7 @@ import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.query.spi.SelectQueryPlan; import org.hibernate.query.spi.SqlOmittingQueryOptions; import org.hibernate.query.sqm.SqmExpressable; +import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.query.sqm.tree.SqmDmlStatement; import org.hibernate.query.sqm.tree.SqmStatement; @@ -76,6 +81,7 @@ import org.hibernate.sql.exec.internal.CallbackImpl; import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.type.BasicType; +import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; /** * {@link Query} implementation based on an SQM @@ -218,7 +224,11 @@ public class QuerySqmImpl ); } else if ( sqmStatement instanceof SqmUpdateStatement ) { - verifyImmutableEntityUpdate( CRITERIA_HQL_STRING, (SqmUpdateStatement) sqmStatement, producer.getFactory() ); + final SqmUpdateStatement updateStatement = (SqmUpdateStatement) sqmStatement; + verifyImmutableEntityUpdate( CRITERIA_HQL_STRING, updateStatement, producer.getFactory() ); + if ( updateStatement.getSetClause() == null || updateStatement.getSetClause().getAssignments().isEmpty() ) { + throw new IllegalArgumentException( "No assignments specified as part of UPDATE criteria" ); + } } this.hqlString = CRITERIA_HQL_STRING; @@ -334,7 +344,41 @@ public class QuerySqmImpl assert sqmExpressable != null; assert sqmExpressable.getExpressableJavaTypeDescriptor() != null; - if ( ! resultClass.isAssignableFrom( sqmExpressable.getExpressableJavaTypeDescriptor().getJavaTypeClass() ) ) { + final Class javaTypeClass = sqmExpressable.getExpressableJavaTypeDescriptor().getJavaTypeClass(); + if ( ! resultClass.isAssignableFrom( javaTypeClass ) ) { + // Special case for date because we always report java.util.Date as expression type + // But the expected resultClass could be a subtype of that, so we need to check the JdbcTypeDescriptor + if ( javaTypeClass == Date.class ) { + JdbcTypeDescriptor jdbcTypeDescriptor = null; + if ( sqmExpressable instanceof BasicDomainType ) { + jdbcTypeDescriptor = ( (BasicDomainType) sqmExpressable ).getJdbcTypeDescriptor(); + } + else if ( sqmExpressable instanceof SqmPathSource ) { + final DomainType domainType = ( (SqmPathSource) sqmExpressable ).getSqmPathType(); + if ( domainType instanceof BasicDomainType ) { + jdbcTypeDescriptor = ( (BasicDomainType) domainType ).getJdbcTypeDescriptor(); + } + } + if ( jdbcTypeDescriptor != null ) { + switch ( jdbcTypeDescriptor.getJdbcTypeCode() ) { + case Types.DATE: + if ( resultClass.isAssignableFrom( java.sql.Date.class ) ) { + return; + } + break; + case Types.TIME: + if ( resultClass.isAssignableFrom( java.sql.Time.class ) ) { + return; + } + break; + case Types.TIMESTAMP: + if ( resultClass.isAssignableFrom( java.sql.Timestamp.class ) ) { + return; + } + break; + } + } + } final String errorMessage = String.format( "Specified result type [%s] did not match Query selection type [%s] - multiple selections: use Tuple or array", resultClass.getName(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java index f6567d8273..a71b21af01 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmCriteriaNodeBuilder.java @@ -6,6 +6,8 @@ */ package org.hibernate.query.sqm.internal; +import java.io.InvalidObjectException; +import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Date; @@ -13,8 +15,10 @@ import java.sql.Time; import java.sql.Timestamp; import java.time.Instant; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -34,12 +38,17 @@ import javax.persistence.criteria.SetJoin; import javax.persistence.criteria.Subquery; import org.hibernate.NotYetImplementedFor6Exception; +import org.hibernate.SessionFactory; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.SessionFactoryRegistry; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.query.NullPrecedence; import org.hibernate.QueryException; import org.hibernate.query.SetOperator; import org.hibernate.query.SortOrder; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.metamodel.model.domain.BasicDomainType; @@ -54,6 +63,7 @@ import org.hibernate.query.criteria.JpaCoalesce; import org.hibernate.query.criteria.JpaCompoundSelection; import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.query.criteria.JpaExpression; +import org.hibernate.query.criteria.JpaParameterExpression; import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.criteria.ValueHandlingMode; import org.hibernate.query.internal.QueryHelper; @@ -131,12 +141,17 @@ import static org.hibernate.query.internal.QueryHelper.highestPrecedenceType; * * @author Steve Ebersole */ -public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { +public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext, Serializable { + + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SqmCriteriaNodeBuilder.class ); + /** * Simplified creation from a SessionFactory */ public static SqmCriteriaNodeBuilder create(SessionFactoryImplementor sf) { - return new SqmCriteriaNodeBuilder( + return new SqmCriteriaNodeBuilder( + sf.getUuid(), + sf.getName(), sf.getQueryEngine(), () -> sf.getRuntimeMetamodels().getJpaMetamodel(), sf.getServiceRegistry(), @@ -144,16 +159,22 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { ); } - private final QueryEngine queryEngine; - private final Supplier domainModelAccess; - private final ServiceRegistry serviceRegistry; - private final ValueHandlingMode criteriaValueHandlingMode; + private final String uuid; + private final String name; + private final transient QueryEngine queryEngine; + private final transient Supplier domainModelAccess; + private final transient ServiceRegistry serviceRegistry; + private final transient ValueHandlingMode criteriaValueHandlingMode; public SqmCriteriaNodeBuilder( + String uuid, + String name, QueryEngine queryEngine, Supplier domainModelAccess, ServiceRegistry serviceRegistry, ValueHandlingMode criteriaValueHandlingMode) { + this.uuid = uuid; + this.name = name; this.queryEngine = queryEngine; this.domainModelAccess = domainModelAccess; this.serviceRegistry = serviceRegistry; @@ -229,6 +250,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { return setOperation( all ? SetOperator.EXCEPT_ALL : SetOperator.EXCEPT, query1, queries ); } + @SuppressWarnings("unchecked") private JpaCriteriaQuery setOperation( SetOperator operator, CriteriaQuery query1, @@ -270,130 +292,53 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { return new SqmBooleanExpressionPredicate( (SqmExpression) expression, this ); } - // todo (6.0) : wrapping a non-`SqmPredicate` `Expression` expression should be as easy as an impl @Override - public SqmPredicate wrap(Expression... expressions) { - SqmPredicate lhs = (SqmPredicate) expressions[0]; - SqmPredicate rhs = (SqmPredicate) expressions[0]; + @SafeVarargs + public final SqmPredicate wrap(Expression... expressions) { + final SqmPredicate lhs = wrap( expressions[0] ); + final SqmPredicate rhs = wrap( expressions[1] ); SqmPredicate predicate = new SqmAndPredicate( lhs, rhs, this ); - if ( expressions.length > 2 ) { - for ( Expression expression : expressions ) { - final SqmPredicate newRhs; - if ( expression instanceof SqmPredicate ) { - newRhs = (SqmPredicate) expression; - } - else { - //noinspection unchecked - return new SqmBooleanExpressionPredicate( (SqmExpression) expression, this ); - } - - predicate = new SqmAndPredicate( predicate, newRhs, this ); - } + for ( int i = 2; i < expressions.length; i++ ) { + predicate = new SqmAndPredicate( predicate, wrap( expressions[i] ), this ); } return predicate; } @Override public SqmPath treat(Path path, Class type) { - //noinspection unchecked - return ( (SqmPath) path ).treatAs( type ); + return ( (SqmPath) path ).treatAs( type ); } @Override public SqmRoot treat(Root root, Class type) { - //noinspection unchecked - return ( (SqmRoot) root ).treatAs( type ); + return ( (SqmRoot) root ).treatAs( type ); } @Override public SqmSingularJoin treat(Join join, Class type) { - //noinspection unchecked - return ( (SqmSingularJoin) join ).treatAs( type ); + return ( (SqmSingularJoin) join ).treatAs( type ); } @Override public SqmBagJoin treat(CollectionJoin join, Class type) { - //noinspection unchecked - return ( (SqmBagJoin) join ).treatAs( type ); + return ( (SqmBagJoin) join ).treatAs( type ); } @Override public SqmSetJoin treat(SetJoin join, Class type) { - //noinspection unchecked - return ( (SqmSetJoin) join ).treatAs( type ); + return ( (SqmSetJoin) join ).treatAs( type ); } @Override public SqmListJoin treat(ListJoin join, Class type) { - //noinspection unchecked - return ( (SqmListJoin) join ).treatAs( type ); + return ( (SqmListJoin) join ).treatAs( type ); } @Override public SqmMapJoin treat(MapJoin join, Class type) { - //noinspection unchecked - return ( (SqmMapJoin) join ).treatAs( type ); + return ( (SqmMapJoin) join ).treatAs( type ); } - @Override - public JpaCompoundSelection construct(Class resultClass, Selection[] arguments) { - final SqmDynamicInstantiation instantiation; - if ( List.class.equals( resultClass ) ) { - instantiation = SqmDynamicInstantiation.forListInstantiation( this ); - } - else if ( Map.class.equals( resultClass ) ) { - instantiation = SqmDynamicInstantiation.forMapInstantiation( this ); - } - else { - instantiation = SqmDynamicInstantiation.forClassInstantiation( resultClass, this ); - } - - for ( Selection argument : arguments ) { - //noinspection unchecked - instantiation.addArgument( - new SqmDynamicInstantiationArgument( - (SqmSelectableNode) argument, - argument.getAlias(), - this - ) - ); - } - - //noinspection unchecked - return instantiation; - } - - @Override - public JpaCompoundSelection construct(Class resultClass, List> arguments) { - final SqmDynamicInstantiation instantiation; - if ( List.class.equals( resultClass ) ) { - //noinspection unchecked - instantiation = (SqmDynamicInstantiation) SqmDynamicInstantiation.forListInstantiation( this ); - } - else if ( Map.class.equals( resultClass ) ) { - //noinspection unchecked - instantiation = (SqmDynamicInstantiation) SqmDynamicInstantiation.forMapInstantiation( this ); - } - else { - instantiation = SqmDynamicInstantiation.forClassInstantiation( resultClass, this ); - } - - for ( Selection argument : arguments ) { - instantiation.addArgument( - new SqmDynamicInstantiationArgument<>( - (SqmSelectableNode) argument, - argument.getAlias(), - this - ) - ); - } - - //noinspection unchecked - return instantiation; - } - - - @Override public SqmSortSpecification sort(JpaExpression sortExpression, SortOrder sortOrder, NullPrecedence nullPrecedence) { return new SqmSortSpecification( (SqmExpression) sortExpression, sortOrder, nullPrecedence ); @@ -421,15 +366,13 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public JpaCompoundSelection tuple(Selection[] selections) { - return new SqmJpaCompoundSelection<>( - ArrayHelper.toList( selections ), - getTypeConfiguration().getJavaTypeDescriptorRegistry().getDescriptor( Tuple.class ), - this - ); + //noinspection unchecked + return tuple( (List>) (List) Arrays.asList( selections ) ); } @Override public JpaCompoundSelection tuple(List> selections) { + checkMultiselect( selections ); //noinspection unchecked return new SqmJpaCompoundSelection<>( (List>) selections, @@ -441,38 +384,41 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmTuple tuple(Class tupleType, JpaExpression... expressions) { //noinspection unchecked - return new SqmTuple<>( - (List>) (List) asList( expressions ), -// getTypeConfiguration().standardExpressableTypeForJavaType( tupleType ), - this - ); + return tuple( tupleType, (List>) (List) asList( expressions ) ); } @Override - public SqmTuple tuple(Class tupleType, List> expressions) { - //noinspection unchecked - return new SqmTuple<>( - (List>) (List) expressions, -// getTypeConfiguration().standardExpressableTypeForJavaType( tupleType ), - this - ); + public SqmTuple tuple(Class tupleType, List> expressions) { + final TypeConfiguration typeConfiguration = getTypeConfiguration(); + @SuppressWarnings("unchecked") + final List> sqmExpressions = (List>) (List) expressions; + final DomainType domainType; + if ( tupleType == null || tupleType == Object[].class ) { + //noinspection unchecked + domainType = (DomainType) typeConfiguration.resolveTupleType( sqmExpressions ); + } + else { + domainType = typeConfiguration.getSessionFactory().getMetamodel().embeddable( tupleType ); + } + return tuple( domainType, sqmExpressions ); } @Override public SqmTuple tuple(DomainType tupleType, JpaExpression... expressions) { //noinspection unchecked - return new SqmTuple<>( - (List>) (List) asList( expressions ), - tupleType, - this - ); + return tuple( tupleType, (List>) (List) asList( expressions ) ); } @Override - public SqmTuple tuple(DomainType tupleType, List> expressions) { - //noinspection unchecked + public SqmTuple tuple(DomainType tupleType, List> expressions) { + @SuppressWarnings("unchecked") + final List> sqmExpressions = (List>) (List) expressions; + if ( tupleType == null ) { + //noinspection unchecked + tupleType = (DomainType) getTypeConfiguration().resolveTupleType( sqmExpressions ); + } return new SqmTuple<>( - new ArrayList<>( (List>) (List) expressions ), + new ArrayList<>( sqmExpressions ), tupleType, this ); @@ -480,36 +426,106 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public JpaCompoundSelection array(Selection[] selections) { - return new SqmJpaCompoundSelection<>( - ArrayHelper.toList( selections ), - getTypeConfiguration().getJavaTypeDescriptorRegistry().getDescriptor( Object[].class ), - this - ); + //noinspection unchecked + return array( (List>) (List) Arrays.asList( selections ) ); } @Override public JpaCompoundSelection array(List> selections) { + return array( Object[].class, selections ); + } + + @Override + public JpaCompoundSelection array(Class resultClass, Selection[] selections) { + //noinspection unchecked + return array( resultClass, (List>) (List) Arrays.asList( selections ) ); + } + + @Override + public JpaCompoundSelection array(Class resultClass, List> selections) { + checkMultiselect( selections ); //noinspection unchecked return new SqmJpaCompoundSelection<>( (List>) selections, - getTypeConfiguration().getJavaTypeDescriptorRegistry().getDescriptor( Object[].class ), + getTypeConfiguration().getJavaTypeDescriptorRegistry().getDescriptor( resultClass ), this ); } @Override - public SqmExpression avg(Expression argument) { - return getFunctionDescriptor("avg").generateSqmExpression( - (SqmTypedNode) argument, - StandardBasicTypes.DOUBLE, - queryEngine, - getJpaMetamodel().getTypeConfiguration() - ); + public JpaCompoundSelection construct(Class resultClass, Selection[] arguments) { + //noinspection unchecked + return construct( resultClass, (List>) (List) Arrays.asList( arguments ) ); } @Override - public SqmExpression sum(Expression argument) { - return getFunctionDescriptor("sum").generateSqmExpression( + public JpaCompoundSelection construct(Class resultClass, List> arguments) { + checkMultiselect( arguments ); + final SqmDynamicInstantiation instantiation; + if ( List.class.equals( resultClass ) ) { + //noinspection unchecked + instantiation = (SqmDynamicInstantiation) SqmDynamicInstantiation.forListInstantiation( this ); + } + else if ( Map.class.equals( resultClass ) ) { + //noinspection unchecked + instantiation = (SqmDynamicInstantiation) SqmDynamicInstantiation.forMapInstantiation( this ); + } + else { + instantiation = SqmDynamicInstantiation.forClassInstantiation( resultClass, this ); + } + + for ( Selection argument : arguments ) { + instantiation.addArgument( + new SqmDynamicInstantiationArgument<>( + (SqmSelectableNode) argument, + argument.getAlias(), + this + ) + ); + } + + return instantiation; + } + + /** + * Package-protected method to centralize checking of criteria query multi-selects as defined by the + * {@link CriteriaQuery#multiselect(List)} method. + * + * @param selections The selection varargs to check + * + * @throws IllegalArgumentException If the selection items are not valid per {@link CriteriaQuery#multiselect} + * documentation. + * "An argument to the multiselect method must not be a tuple- + * or array-valued compound selection item." + */ + void checkMultiselect(List> selections) { + final HashSet aliases = new HashSet<>( CollectionHelper.determineProperSizing( selections.size() ) ); + + for ( JpaSelection selection : selections ) { + if ( selection.isCompoundSelection() ) { + if ( selection.getJavaType().isArray() ) { + throw new IllegalArgumentException( + "Selection items in a multi-select cannot contain compound array-valued elements" + ); + } + if ( Tuple.class.isAssignableFrom( selection.getJavaType() ) ) { + throw new IllegalArgumentException( + "Selection items in a multi-select cannot contain compound tuple-valued elements" + ); + } + } + if ( StringHelper.isNotEmpty( selection.getAlias() ) ) { + boolean added = aliases.add( selection.getAlias() ); + if ( ! added ) { + throw new IllegalArgumentException( "Multi-select expressions defined duplicate alias : " + selection.getAlias() ); + } + } + } + } + + @Override + public SqmExpression avg(Expression argument) { + return getFunctionDescriptor( "avg" ).generateSqmExpression( (SqmTypedNode) argument, null, queryEngine, @@ -517,21 +533,43 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { ); } + @Override + @SuppressWarnings("unchecked") + public SqmExpression sum(Expression argument) { + final SqmTypedNode typedNode = (SqmTypedNode) argument; + return getFunctionDescriptor( "sum" ).generateSqmExpression( + typedNode, + (AllowableFunctionReturnType) typedNode.getNodeType(), + queryEngine, + getJpaMetamodel().getTypeConfiguration() + ); + } + @Override public SqmExpression sumAsLong(Expression argument) { - return cast( sum( argument ), Long.class ); + return getFunctionDescriptor( "sum" ).generateSqmExpression( + (SqmTypedNode) argument, + null, + queryEngine, + getJpaMetamodel().getTypeConfiguration() + ); } @Override public SqmExpression sumAsDouble(Expression argument) { - return cast( sum( argument ), Double.class ); + return getFunctionDescriptor( "sum" ).generateSqmExpression( + (SqmTypedNode) argument, + null, + queryEngine, + getJpaMetamodel().getTypeConfiguration() + ); } @Override public SqmExpression max(Expression argument) { - return getFunctionDescriptor("max").generateSqmExpression( + return getFunctionDescriptor( "max" ).generateSqmExpression( (SqmTypedNode) argument, - (AllowableFunctionReturnType) ((SqmExpression) argument).getNodeType(), + null, queryEngine, getJpaMetamodel().getTypeConfiguration() ); @@ -539,9 +577,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmExpression min(Expression argument) { - return getFunctionDescriptor("min").generateSqmExpression( + return getFunctionDescriptor( "min" ).generateSqmExpression( (SqmTypedNode) argument, - (AllowableFunctionReturnType) ((SqmExpression) argument).getNodeType(), + null, queryEngine, getJpaMetamodel().getTypeConfiguration() ); @@ -561,9 +599,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmExpression count(Expression argument) { - return getFunctionDescriptor("count").generateSqmExpression( + return getFunctionDescriptor( "count" ).generateSqmExpression( (SqmTypedNode) argument, - StandardBasicTypes.LONG, + null, queryEngine, getJpaMetamodel().getTypeConfiguration() ); @@ -571,9 +609,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmExpression countDistinct(Expression argument) { - return getFunctionDescriptor("count").generateSqmExpression( + return getFunctionDescriptor( "count" ).generateSqmExpression( new SqmDistinct<>( (SqmExpression) argument, getQueryEngine().getCriteriaBuilder() ), - StandardBasicTypes.LONG, + null, queryEngine, getJpaMetamodel().getTypeConfiguration() ); @@ -590,9 +628,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmExpression abs(Expression x) { - return getFunctionDescriptor("abs").generateSqmExpression( + return getFunctionDescriptor( "abs" ).generateSqmExpression( (SqmTypedNode) x, - (AllowableFunctionReturnType) ((SqmExpression) x).getNodeType(), + null, queryEngine, getJpaMetamodel().getTypeConfiguration() ); @@ -642,23 +680,30 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public SqmExpression prod(Expression x, Expression y) { return createSqmArithmeticNode( - BinaryArithmeticOperator.ADD, - value( x, (SqmExpression) y ), + BinaryArithmeticOperator.MULTIPLY, + (SqmExpression) x, (SqmExpression) y ); } @Override public SqmExpression prod(Expression x, N y) { - return sum( x, y ); + return createSqmArithmeticNode( + BinaryArithmeticOperator.MULTIPLY, + (SqmExpression) x, + value( y, (SqmExpression) x ) + ); } @Override public SqmExpression prod(N x, Expression y) { - return sum( x, y ); + return createSqmArithmeticNode( + BinaryArithmeticOperator.MULTIPLY, + value( x, (SqmExpression) y ), + (SqmExpression) y + ); } @Override @@ -681,12 +726,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public SqmExpression diff(N x, Expression y) { return createSqmArithmeticNode( BinaryArithmeticOperator.SUBTRACT, - value( x, (SqmExpression) y ), - (SqmExpression) y + value( x, (SqmExpression) y ), + (SqmExpression) y ); } @@ -700,17 +744,16 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public SqmExpression quot(Expression x, Number y) { return createSqmArithmeticNode( BinaryArithmeticOperator.QUOT, - (SqmExpression) x, - value( y, (SqmExpression) x ) + (SqmExpression) x, + value( y, (SqmExpression) x ) ); } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({ "unchecked" }) public SqmExpression quot(Number x, Expression y) { return createSqmArithmeticNode( BinaryArithmeticOperator.QUOT, @@ -748,7 +791,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmExpression sqrt(Expression x) { - return getFunctionDescriptor("sqrt").generateSqmExpression( + return getFunctionDescriptor( "sqrt" ).generateSqmExpression( (SqmTypedNode) x, null, queryEngine, @@ -860,7 +903,18 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmExpression nullLiteral(Class resultClass) { - return new SqmLiteralNull<>( getTypeConfiguration().standardBasicTypeForJavaType( resultClass ), this ); + final TypeConfiguration typeConfiguration = getTypeConfiguration(); + final BasicType basicTypeForJavaType = typeConfiguration.getBasicTypeForJavaType( resultClass ); + final SqmExpressable sqmExpressable; + if ( basicTypeForJavaType == null ) { + sqmExpressable = typeConfiguration.getSessionFactory() + .getMetamodel() + .managedType( resultClass ); + } + else { + sqmExpressable = basicTypeForJavaType; + } + return new SqmLiteralNull<>( sqmExpressable, this ); } class MultiValueParameterType implements AllowableParameterType { @@ -891,38 +945,41 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public JpaCriteriaParameter parameter(Class paramClass) { - return parameter( paramClass, null ); + return parameter( paramClass, (String) null ); } @Override - @SuppressWarnings("unchecked") public JpaCriteriaParameter parameter(Class paramClass, String name) { - if ( Collection.class.isAssignableFrom( paramClass ) ) { - // a Collection-valued, multi-valued parameter + return (JpaCriteriaParameter) parameter( paramClass, name, null ); + } + + @Override + public JpaParameterExpression parameter(Class paramClass, T value) { + return parameter( paramClass, null, value ); + } + + @SuppressWarnings("unchecked") + private JpaParameterExpression parameter(Class paramClass, String name, T value) { + final BasicType basicType = getTypeConfiguration().getBasicTypeForJavaType( paramClass ); + if ( basicType == null ) { + final AllowableParameterType parameterType; + if ( Collection.class.isAssignableFrom( paramClass ) ) { + // a Collection-valued, multi-valued parameter + parameterType = new MultiValueParameterType<>( (Class) Collection.class ); + } + else { + parameterType = null; + } return new JpaCriteriaParameter<>( name, - new MultiValueParameterType( (Class) Collection.class ), + parameterType, + value, true, this ); } - - if ( paramClass.isArray() ) { - // an array-valued, multi-valued parameter - return new JpaCriteriaParameter<>( - name, - new MultiValueParameterType( (Class) Object[].class ), - true, - this - ); - } - - try { - final BasicType basicType = getTypeConfiguration().standardBasicTypeForJavaType( paramClass ); - return new JpaCriteriaParameter<>( name, basicType, false, this ); - } - catch (JdbcTypeRecommendationException e) { - return new JpaCriteriaParameter<>( name, null, false, this ); + else { + return new JpaCriteriaParameter<>( name, basicType, value, false, this ); } } @@ -1060,19 +1117,19 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { TrimSpec trimSpecification, SqmExpression trimCharacter, SqmExpression source) { - - final ArrayList> arguments = new ArrayList<>(); - - if ( trimSpecification != null ) { - arguments.add( - new SqmTrimSpecification( trimSpecification, this ) + if ( trimSpecification == null ) { + trimSpecification = TrimSpec.BOTH; + } + if ( trimCharacter == null ) { + trimCharacter = new SqmLiteral<>( + ' ', + getTypeConfiguration().standardBasicTypeForJavaType( Character.class ), + this ); } - - if ( trimCharacter != null ) { - arguments.add( trimCharacter ); - } - + final ArrayList> arguments = new ArrayList<>( 3 ); + arguments.add( new SqmTrimSpecification( trimSpecification, this ) ); + arguments.add( trimCharacter ); arguments.add( source ); //noinspection unchecked @@ -1131,15 +1188,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmFunction lower(Expression x) { - //noinspection unchecked - final AllowableFunctionReturnType type = (AllowableFunctionReturnType) highestPrecedenceType( - ((SqmExpression) x).getNodeType(), - StandardBasicTypes.STRING - ); - return getFunctionDescriptor( "lower" ).generateSqmExpression( (SqmExpression) x, - type, + null, getQueryEngine(), getJpaMetamodel().getTypeConfiguration() ); @@ -1147,15 +1198,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmFunction upper(Expression x) { - //noinspection unchecked - final AllowableFunctionReturnType type = (AllowableFunctionReturnType) highestPrecedenceType( - ((SqmExpression) x).getNodeType(), - StandardBasicTypes.STRING - ); - return getFunctionDescriptor( "upper" ).generateSqmExpression( (SqmExpression) x, - type, + null, getQueryEngine(), getJpaMetamodel().getTypeConfiguration() ); @@ -1165,7 +1210,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { public SqmFunction length(Expression argument) { return getFunctionDescriptor( "length" ).generateSqmExpression( (SqmExpression) argument, - StandardBasicTypes.INTEGER, + null, getQueryEngine(), getJpaMetamodel().getTypeConfiguration() ); @@ -1279,7 +1324,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmFunction function(String name, Class type, Expression[] args) { - final SqmFunctionDescriptor functionTemplate = getFunctionDescriptor( name); + final SqmFunctionDescriptor functionTemplate = getFunctionDescriptor( name ); if ( functionTemplate == null ) { throw new SemanticException( "Could not resolve function named `" + name + "`" ); } @@ -1391,12 +1436,13 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { return literal( value ); } else { - final BasicType basicType; + final BasicType basicType; if ( value == null ) { basicType = null; } else { - basicType = getTypeConfiguration().getBasicTypeForJavaType( value.getClass() ); + //noinspection unchecked + basicType = getTypeConfiguration().getBasicTypeForJavaType( (Class) value.getClass() ); } return new JpaCriteriaParameter<>( basicType, @@ -1418,12 +1464,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public > SqmExpression size(Expression collection) { - return new SqmCollectionSize( (SqmPath) collection, this ); + return new SqmCollectionSize( (SqmPath) collection, this ); } @Override public > SqmExpression size(C collection) { - //noinspection unchecked return new SqmLiteral<>( collection.size(), StandardBasicTypes.INTEGER, @@ -1438,12 +1483,14 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public JpaCoalesce coalesce(Expression x, Expression y) { - //noinspection unchecked + @SuppressWarnings("unchecked") + final SqmExpressable sqmExpressable = (SqmExpressable) highestPrecedenceType( + ( (SqmExpression) x ).getNodeType(), + ( (SqmExpression) y ).getNodeType() + ); return new SqmCoalesce<>( - highestPrecedenceType( - ((SqmExpression) x).getNodeType(), - ((SqmExpression) y).getNodeType() - ), + sqmExpressable, + 2, this ) .value(x) @@ -1452,19 +1499,19 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public JpaCoalesce coalesce(Expression x, Y y) { - return coalesce( x, value( y, (SqmExpression) x ) ); + //noinspection unchecked + return coalesce( x, value( y, (SqmExpression) x ) ); } @Override public SqmExpression nullif(Expression x, Expression y) { //noinspection unchecked - return createNullifFunctionNode( (SqmExpression) x, (SqmExpression) y ); + return createNullifFunctionNode( (SqmExpression) x, (SqmExpression) y ); } @Override public SqmExpression nullif(Expression x, Y y) { - //noinspection unchecked - return createNullifFunctionNode( (SqmExpression) x, value( y, (SqmExpression) x ) ); + return createNullifFunctionNode( (SqmExpression) x, value( y, (SqmExpression) x ) ); } private SqmExpression createNullifFunctionNode(SqmExpression first, SqmExpression second) { @@ -1489,7 +1536,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmCaseSimple selectCase(Expression expression) { //noinspection unchecked - return new SqmCaseSimple<>( (SqmExpression) expression, this ); + return new SqmCaseSimple<>( (SqmExpression) expression, this ); } @Override @@ -1503,8 +1550,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - public SqmExpression mapSize(Map map) { - //noinspection unchecked + public > SqmExpression mapSize(M map) { return new SqmLiteral<>( map.size(), StandardBasicTypes.INTEGER, this ); } @@ -1569,22 +1615,20 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate conjunction() { - //noinspection unchecked return new SqmComparisonPredicate( - new SqmLiteral( 1, StandardBasicTypes.INTEGER, this ), + new SqmLiteral<>( 1, StandardBasicTypes.INTEGER, this ), ComparisonOperator.EQUAL, - new SqmLiteral( 1, StandardBasicTypes.INTEGER, this ), + new SqmLiteral<>( 1, StandardBasicTypes.INTEGER, this ), this ); } @Override public SqmPredicate disjunction() { - //noinspection unchecked return new SqmComparisonPredicate( - new SqmLiteral( 1, StandardBasicTypes.INTEGER, this ), + new SqmLiteral<>( 1, StandardBasicTypes.INTEGER, this ), ComparisonOperator.NOT_EQUAL, - new SqmLiteral( 1, StandardBasicTypes.INTEGER, this ), + new SqmLiteral<>( 1, StandardBasicTypes.INTEGER, this ), this ); } @@ -1601,29 +1645,30 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate isNull(Expression x) { - return new SqmNullnessPredicate( (SqmExpression) x, this ); + return new SqmNullnessPredicate( (SqmExpression) x, this ); } @Override public SqmPredicate isNotNull(Expression x) { - return new SqmNullnessPredicate( (SqmExpression) x, this ).not(); + return new SqmNullnessPredicate( (SqmExpression) x, this ).not(); } @Override public > SqmPredicate between(Expression value, Expression lower, Expression upper) { + //noinspection unchecked return new SqmBetweenPredicate( - (SqmExpression) value, - (SqmExpression) lower, - (SqmExpression) upper, + (SqmExpression) value, + (SqmExpression) lower, + (SqmExpression) upper, false, this ); } @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({ "unchecked" }) public > SqmPredicate between(Expression value, Y lower, Y upper) { - final SqmExpression valueExpression = (SqmExpression) value; + final SqmExpression valueExpression = (SqmExpression) value; return new SqmBetweenPredicate( valueExpression, value( lower, valueExpression ), @@ -1644,12 +1689,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public SqmPredicate equal(Expression x, Object y) { return new SqmComparisonPredicate( (SqmExpression) x, ComparisonOperator.EQUAL, - value( y, (SqmExpression) x ), + value( y, (SqmExpression) x ), this ); } @@ -1665,12 +1709,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) public SqmPredicate notEqual(Expression x, Object y) { return new SqmComparisonPredicate( - (SqmExpression) x, + (SqmExpression) x, ComparisonOperator.NOT_EQUAL, - value( y, (SqmExpression) x ), + value( y, (SqmExpression) x ), this ); } @@ -1690,7 +1733,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { return new SqmComparisonPredicate( (SqmExpression) x, ComparisonOperator.DISTINCT_FROM, - value( y ), + value( y, (SqmExpression) x ), this ); } @@ -1710,7 +1753,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { return new SqmComparisonPredicate( (SqmExpression) x, ComparisonOperator.NOT_DISTINCT_FROM, - value( y ), + value( y, (SqmExpression) x ), this ); } @@ -1768,12 +1811,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public > SqmPredicate lessThan(Expression x, Y y) { return new SqmComparisonPredicate( (SqmExpression) x, ComparisonOperator.LESS_THAN, - value( y, (SqmExpression) x ), + value( y, (SqmExpression) x ), this ); } @@ -1809,12 +1851,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public SqmPredicate gt(Expression x, Number y) { return new SqmComparisonPredicate( (SqmExpression) x, ComparisonOperator.GREATER_THAN, - value( y, (SqmExpression) x ), + value( y, (SqmExpression) x ), this ); } @@ -1830,12 +1871,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public SqmPredicate ge(Expression x, Number y) { return new SqmComparisonPredicate( (SqmExpression) x, ComparisonOperator.GREATER_THAN_OR_EQUAL, - value( y, (SqmExpression) x ), + value( y, (SqmExpression) x ), this ); } @@ -1851,12 +1891,11 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public SqmPredicate lt(Expression x, Number y) { return new SqmComparisonPredicate( (SqmExpression) x, ComparisonOperator.LESS_THAN, - value( y, (SqmExpression) x ), + value( y, (SqmExpression) x ), this ); } @@ -1872,24 +1911,23 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { } @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) public SqmPredicate le(Expression x, Number y) { return new SqmComparisonPredicate( (SqmExpression) x, ComparisonOperator.LESS_THAN_OR_EQUAL, - value( y, (SqmExpression) x ), + value( y, (SqmExpression) x ), this ); } @Override public > SqmPredicate isEmpty(Expression collection) { - return new SqmEmptinessPredicate( (SqmPluralValuedSimplePath) collection, false, this ); + return new SqmEmptinessPredicate( (SqmPluralValuedSimplePath) collection, false, this ); } @Override public > SqmPredicate isNotEmpty(Expression collection) { - return new SqmEmptinessPredicate( (SqmPluralValuedSimplePath) collection, true, this ); + return new SqmEmptinessPredicate( (SqmPluralValuedSimplePath) collection, true, this ); } @Override @@ -1915,8 +1953,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate like(Expression searchString, Expression pattern) { return new SqmLikePredicate( - (SqmExpression) searchString, - (SqmExpression) pattern, + (SqmExpression) searchString, + (SqmExpression) pattern, this ); } @@ -1924,8 +1962,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate like(Expression searchString, String pattern) { return new SqmLikePredicate( - (SqmExpression) searchString, - value( pattern, (SqmExpression) searchString ), + (SqmExpression) searchString, + value( pattern, (SqmExpression) searchString ), this ); } @@ -1933,9 +1971,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate like(Expression searchString, Expression pattern, Expression escapeChar) { return new SqmLikePredicate( - (SqmExpression) searchString, - (SqmExpression) pattern, - (SqmExpression) escapeChar, + (SqmExpression) searchString, + (SqmExpression) pattern, + (SqmExpression) escapeChar, this ); } @@ -1943,8 +1981,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate like(Expression searchString, Expression pattern, char escapeChar) { return new SqmLikePredicate( - (SqmExpression) searchString, - (SqmExpression) pattern, + (SqmExpression) searchString, + (SqmExpression) pattern, literal( escapeChar ), this ); @@ -1953,9 +1991,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate like(Expression searchString, String pattern, Expression escapeChar) { return new SqmLikePredicate( - (SqmExpression) searchString, - value( pattern, (SqmExpression) searchString ), - (SqmExpression) escapeChar, + (SqmExpression) searchString, + value( pattern, (SqmExpression) searchString ), + (SqmExpression) escapeChar, this ); } @@ -1963,8 +2001,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate like(Expression searchString, String pattern, char escapeChar) { return new SqmLikePredicate( - (SqmExpression) searchString, - value( pattern, (SqmExpression) searchString ), + (SqmExpression) searchString, + value( pattern, (SqmExpression) searchString ), literal( escapeChar ), this ); @@ -1973,8 +2011,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate ilike(Expression searchString, Expression pattern) { return new SqmLikePredicate( - (SqmExpression) searchString, - (SqmExpression) pattern, + (SqmExpression) searchString, + (SqmExpression) pattern, false, false, this @@ -1984,8 +2022,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate ilike(Expression searchString, String pattern) { return new SqmLikePredicate( - (SqmExpression) searchString, - value( pattern, (SqmExpression) searchString ), + (SqmExpression) searchString, + value( pattern, (SqmExpression) searchString ), false, false, this @@ -1998,9 +2036,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { Expression pattern, Expression escapeChar) { return new SqmLikePredicate( - (SqmExpression) searchString, - (SqmExpression) pattern, - (SqmExpression) escapeChar, + (SqmExpression) searchString, + (SqmExpression) pattern, + (SqmExpression) escapeChar, false, false, this @@ -2010,8 +2048,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate ilike(Expression searchString, Expression pattern, char escapeChar) { return new SqmLikePredicate( - (SqmExpression) searchString, - (SqmExpression) pattern, + (SqmExpression) searchString, + (SqmExpression) pattern, literal( escapeChar ), false, false, @@ -2022,9 +2060,9 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate ilike(Expression searchString, String pattern, Expression escapeChar) { return new SqmLikePredicate( - (SqmExpression) searchString, - value( pattern, (SqmExpression) searchString ), - (SqmExpression) escapeChar, + (SqmExpression) searchString, + value( pattern, (SqmExpression) searchString ), + (SqmExpression) escapeChar, false, false, this @@ -2034,8 +2072,8 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override public SqmPredicate ilike(Expression searchString, String pattern, char escapeChar) { return new SqmLikePredicate( - (SqmExpression) searchString, - value( pattern, (SqmExpression) searchString ), + (SqmExpression) searchString, + value( pattern, (SqmExpression) searchString ), literal( escapeChar ), false, false, @@ -2112,37 +2150,33 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { @Override @SuppressWarnings("unchecked") public SqmInPredicate in(Expression expression, Expression... values) { - final SqmInListPredicate predicate = new SqmInListPredicate<>( (SqmExpression) expression, this ); + final List> listExpressions = new ArrayList<>( values.length ); for ( Expression value : values ) { - predicate.addExpression( (SqmExpression) value ); + listExpressions.add( (SqmExpression) value ); } - return predicate; + return new SqmInListPredicate<>( (SqmExpression) expression, listExpressions, this ); } @Override @SuppressWarnings("unchecked") public SqmInPredicate in(Expression expression, T... values) { final SqmExpression sqmExpression = (SqmExpression) expression; - final SqmInListPredicate predicate = new SqmInListPredicate<>( sqmExpression, this ); + final List> listExpressions = new ArrayList<>( values.length ); for ( T value : values ) { - predicate.addExpression( - new SqmLiteral<>( value, sqmExpression.getNodeType(), this ) - ); + listExpressions.add( value( value, sqmExpression ) ); } - return predicate; + return new SqmInListPredicate<>( sqmExpression, listExpressions, this ); } @Override @SuppressWarnings("unchecked") - public SqmInPredicate in(Expression expression, List values) { + public SqmInPredicate in(Expression expression, Collection values) { final SqmExpression sqmExpression = (SqmExpression) expression; - final SqmInListPredicate predicate = new SqmInListPredicate<>( sqmExpression, this ); + final List> listExpressions = new ArrayList<>( values.size() ); for ( T value : values ) { - predicate.addExpression( - new SqmLiteral<>( value, sqmExpression.getNodeType(), this ) - ); + listExpressions.add( value( value, sqmExpression ) ); } - return predicate; + return new SqmInListPredicate<>( sqmExpression, listExpressions, this ); } @Override @@ -2165,4 +2199,38 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext { public > SqmPredicate isMapNotEmpty(JpaExpression mapExpression) { return new SqmEmptinessPredicate( (SqmPluralValuedSimplePath) mapExpression, true, this ); } + + /** + * Custom serialization hook defined by Java spec. Used when the node builder is directly deserialized. + * Here we resolve the uuid/name read from the stream previously to resolve the SessionFactory + * instance to use based on the registrations with the {@link SessionFactoryRegistry} + * + * @return The resolved node builder to use. + * + * @throws InvalidObjectException Thrown if we could not resolve the factory by uuid/name. + */ + private Object readResolve() throws InvalidObjectException { + LOG.trace( "Resolving serialized SqmCriteriaNodeBuilder" ); + return locateSessionFactoryOnDeserialization( uuid, name ).getCriteriaBuilder(); + } + + private static SessionFactory locateSessionFactoryOnDeserialization(String uuid, String name) throws InvalidObjectException{ + final SessionFactory uuidResult = SessionFactoryRegistry.INSTANCE.getSessionFactory( uuid ); + if ( uuidResult != null ) { + LOG.debugf( "Resolved SessionFactory by UUID [%s]", uuid ); + return uuidResult; + } + + // in case we were deserialized in a different JVM, look for an instance with the same name + // (provided we were given a name) + if ( name != null ) { + final SessionFactory namedResult = SessionFactoryRegistry.INSTANCE.getNamedSessionFactory( name ); + if ( namedResult != null ) { + LOG.debugf( "Resolved SessionFactory by name [%s]", name ); + return namedResult; + } + } + + throw new InvalidObjectException( "Could not find a SessionFactory [uuid=" + uuid + ",name=" + name + "]" ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmMappingModelHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmMappingModelHelper.java index 583aade88c..941c428af2 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmMappingModelHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmMappingModelHelper.java @@ -127,7 +127,7 @@ public class SqmMappingModelHelper { return ( (BasicType) nodeType ); } - throw new NotYetImplementedFor6Exception( DomainModelHelper.class ); + return null; } private static ModelPart resolveSqmPath( diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmTreePrinter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmTreePrinter.java index 6addf07336..c5dd1303a8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmTreePrinter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmTreePrinter.java @@ -579,14 +579,14 @@ public class SqmTreePrinter implements SemanticQueryWalker { } @Override - public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path) { + public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path) { logWithIndentation( "-> [non-aggregated-composite-path] - `%s`", path.getNavigablePath().getFullPath() ); return null; } @Override - public Object visitSelfInterpretingSqmPath(SelfInterpretingSqmPath sqmPath) { + public Object visitSelfInterpretingSqmPath(SelfInterpretingSqmPath sqmPath) { logWithIndentation( "-> [self-interpreting-path] - `%s`", sqmPath.getNavigablePath().getFullPath() ); return null; @@ -607,7 +607,7 @@ public class SqmTreePrinter implements SemanticQueryWalker { } @Override - public Object visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path) { + public Object visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path) { return null; } @@ -617,7 +617,7 @@ public class SqmTreePrinter implements SemanticQueryWalker { } @Override - public Object visitCorrelation(SqmCorrelation correlation) { + public Object visitCorrelation(SqmCorrelation correlation) { return null; } @@ -681,17 +681,17 @@ public class SqmTreePrinter implements SemanticQueryWalker { } @Override - public Object visitFunction(SqmFunction tSqmFunction) { + public Object visitFunction(SqmFunction tSqmFunction) { return null; } @Override - public Object visitCoalesce(SqmCoalesce sqmCoalesce) { + public Object visitCoalesce(SqmCoalesce sqmCoalesce) { return null; } @Override - public Object visitToDuration(SqmToDuration toDuration) { + public Object visitToDuration(SqmToDuration toDuration) { return null; } @@ -701,7 +701,7 @@ public class SqmTreePrinter implements SemanticQueryWalker { } @Override - public Object visitExtractUnit(SqmExtractUnit extractUnit) { + public Object visitExtractUnit(SqmExtractUnit extractUnit) { return null; } @@ -711,7 +711,7 @@ public class SqmTreePrinter implements SemanticQueryWalker { } @Override - public Object visitCastTarget(SqmCastTarget sqmCastTarget) { + public Object visitCastTarget(SqmCastTarget sqmCastTarget) { return null; } @@ -721,12 +721,12 @@ public class SqmTreePrinter implements SemanticQueryWalker { } @Override - public Object visitDistinct(SqmDistinct distinct) { + public Object visitDistinct(SqmDistinct distinct) { return null; } @Override - public Object visitDurationUnit(SqmDurationUnit durationUnit) { + public Object visitDurationUnit(SqmDurationUnit durationUnit) { return null; } @@ -914,7 +914,7 @@ public class SqmTreePrinter implements SemanticQueryWalker { } @Override - public Object visitMapEntryFunction(SqmMapEntryReference function) { + public Object visitMapEntryFunction(SqmMapEntryReference function) { return null; } @@ -1011,12 +1011,12 @@ public class SqmTreePrinter implements SemanticQueryWalker { } @Override - public Object visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral) { + public Object visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral) { throw new NotYetImplementedFor6Exception( getClass() ); } @Override - public Object visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral) { + public Object visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral) { throw new NotYetImplementedFor6Exception( getClass() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java index 210de27737..85f7c474ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java @@ -6,18 +6,23 @@ */ package org.hibernate.query.sqm.internal; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.function.Function; +import java.util.function.Supplier; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.MappingMetamodel; import org.hibernate.metamodel.mapping.Bindable; import org.hibernate.metamodel.mapping.CollectionPart; @@ -34,11 +39,15 @@ import org.hibernate.query.NavigablePath; import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.spi.QueryParameterImplementor; +import org.hibernate.query.sqm.SqmQuerySource; import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess; import org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess; import org.hibernate.query.sqm.tree.SqmDmlStatement; import org.hibernate.query.sqm.tree.SqmStatement; +import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter; +import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper; import org.hibernate.query.sqm.tree.expression.SqmParameter; +import org.hibernate.query.sqm.tree.jpa.ParameterCollector; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.SqlTreeCreationException; @@ -192,6 +201,11 @@ public class SqmUtil { ); final List> jdbcParamsBinds = jdbcParamMap.get( sqmParameter ); + if ( jdbcParamsBinds == null ) { + // This can happen when a group or order by item expression, that contains parameters, + // is replaced with an alias reference expression, which can happen for JPA Criteria queries + continue; + } if ( !domainParamBinding.isBound() ) { final MappingModelExpressable mappingExpressable = SqmMappingModelHelper.resolveMappingModelExpressable( sqmParameter, @@ -405,4 +419,132 @@ public class SqmUtil { BasicType basicType = typeConfiguration.standardBasicTypeForJavaType( parameter.getParameterType() ); return basicType; } + + public static SqmStatement.ParameterResolutions resolveParameters(SqmStatement statement) { + if ( statement.getQuerySource() == SqmQuerySource.CRITERIA ) { + final CriteriaParameterCollector parameterCollector = new CriteriaParameterCollector(); + + ParameterCollector.collectParameters( + statement, + parameterCollector::process, + statement.nodeBuilder().getServiceRegistry() + ); + + return parameterCollector.makeResolution(); + } + else { + return new SqmStatement.ParameterResolutions() { + @Override + public Set> getSqmParameters() { + return statement.getSqmParameters(); + } + + @Override + public Map, Supplier>> getJpaCriteriaParamResolutions() { + return Collections.emptyMap(); + } + }; + } + } + + private static class CriteriaParameterCollector { + private Set> sqmParameters; + private Map, List>> jpaCriteriaParamResolutions; + + public void process(SqmParameter parameter) { + if ( sqmParameters == null ) { + sqmParameters = new HashSet<>(); + } + + if ( parameter instanceof SqmJpaCriteriaParameterWrapper ) { + if ( jpaCriteriaParamResolutions == null ) { + jpaCriteriaParamResolutions = new IdentityHashMap<>(); + } + + final SqmJpaCriteriaParameterWrapper wrapper = (SqmJpaCriteriaParameterWrapper) parameter; + final JpaCriteriaParameter criteriaParameter = wrapper.getJpaCriteriaParameter(); + + final List> sqmParametersForCriteriaParameter = jpaCriteriaParamResolutions.computeIfAbsent( + criteriaParameter, + jcp -> new ArrayList<>() + ); + + sqmParametersForCriteriaParameter.add( wrapper ); + sqmParameters.add( wrapper ); + } + else if ( parameter instanceof JpaCriteriaParameter ) { + throw new UnsupportedOperationException(); +// final JpaCriteriaParameter criteriaParameter = (JpaCriteriaParameter) parameter; +// +// if ( jpaCriteriaParamResolutions == null ) { +// jpaCriteriaParamResolutions = new IdentityHashMap<>(); +// } +// +// final List> sqmParametersForCriteriaParameter = jpaCriteriaParamResolutions.computeIfAbsent( +// criteriaParameter, +// jcp -> new ArrayList<>() +// ); +// +// final SqmJpaCriteriaParameterWrapper wrapper = new SqmJpaCriteriaParameterWrapper( +// criteriaParameter.getHibernateType(), +// criteriaParameter, +// criteriaParameter.nodeBuilder() +// ); +// +// sqmParametersForCriteriaParameter.add( wrapper ); +// sqmParameters.add( wrapper ); + } + else { + sqmParameters.add( parameter ); + } + } + + private SqmStatement.ParameterResolutions makeResolution() { + return new ParameterResolutionsImpl( + sqmParameters == null ? Collections.emptySet() : sqmParameters, + jpaCriteriaParamResolutions == null ? Collections.emptyMap() : jpaCriteriaParamResolutions + ); + } + } + + private static class ParameterResolutionsImpl implements SqmStatement.ParameterResolutions { + private final Set> sqmParameters; + private final Map, Supplier>> jpaCriteriaParamResolutions; + + public ParameterResolutionsImpl( + Set> sqmParameters, + Map, List>> jpaCriteriaParamResolutions) { + this.sqmParameters = sqmParameters; + + if ( jpaCriteriaParamResolutions == null || jpaCriteriaParamResolutions.isEmpty() ) { + this.jpaCriteriaParamResolutions = Collections.emptyMap(); + } + else { + this.jpaCriteriaParamResolutions = new IdentityHashMap<>( CollectionHelper.determineProperSizing( jpaCriteriaParamResolutions ) ); + for ( Map.Entry, List>> entry : jpaCriteriaParamResolutions.entrySet() ) { + final Iterator> itr = entry.getValue().iterator(); + this.jpaCriteriaParamResolutions.put( + entry.getKey(), + () -> { + if ( itr.hasNext() ) { + return itr.next(); + } + throw new IllegalStateException( "SqmJpaCriteriaParameterWrapper references for JpaCriteriaParameter [" + entry.getKey() + "] already exhausted" ); + } + ); + + } + } + } + + @Override + public Set> getSqmParameters() { + return sqmParameters; + } + + @Override + public Map, Supplier>> getJpaCriteriaParamResolutions() { + return jpaCriteriaParamResolutions; + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java index d403e31a05..17b75c7755 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java @@ -251,7 +251,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter new SqmAliasedNodePositionTracker( r, - sqmSelectClause.getSelectionItems().size() + sqmSelectClause.getSelections() ), getCurrentClauseStack()::getCurrent ) { @@ -277,7 +277,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter domainResultProducer = (DomainResultProducer) sqmSelectClause.getSelectionItems() .get( i ) .accept( this ); domainResultProducer.applySqlSelections( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/AbstractCteMutationHandler.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/AbstractCteMutationHandler.java index 24c4081fac..00fd9b587f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/AbstractCteMutationHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/AbstractCteMutationHandler.java @@ -219,10 +219,9 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler MultiTableSqmMutationConverter sqmConverter) { final SqmExpression arg = new SqmStar( factory.getNodeBuilder() ); final TypeConfiguration typeConfiguration = factory.getJpaMetamodel().getTypeConfiguration(); - final BasicDomainType type = typeConfiguration.standardBasicTypeForJavaType( Long.class ); - return factory.getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor("count").generateSqmExpression( + return factory.getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor( "count" ).generateSqmExpression( arg, - type, + null, factory.getQueryEngine(), typeConfiguration ).convertToSqlAst( sqmConverter ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java index ecd7b6de96..42ed580216 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/BaseSemanticQueryWalker.java @@ -8,10 +8,10 @@ package org.hibernate.query.sqm.spi; import java.util.List; -import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.sql.internal.SelfInterpretingSqmPath; import org.hibernate.query.sqm.tree.SqmStatement; +import org.hibernate.query.sqm.tree.SqmVisitableNode; import org.hibernate.query.sqm.tree.cte.SqmCteContainer; import org.hibernate.query.sqm.tree.cte.SqmCteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; @@ -31,6 +31,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.SqmAggregateFunction; import org.hibernate.query.sqm.tree.expression.SqmAny; import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic; import org.hibernate.query.sqm.tree.expression.SqmByUnit; @@ -132,7 +133,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker statement) { visitCteContainer( statement ); - visitRootPath( statement.getTarget() ); + statement.getTarget().accept( this ); visitSetClause( statement.getSetClause() ); visitWhereClause( statement.getWhereClause() ); return statement; @@ -156,7 +157,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker statement) { visitCteContainer( statement ); - visitRootPath( statement.getTarget() ); + statement.getTarget().accept( this ); for ( SqmPath stateField : statement.getInsertionTargetPaths() ) { stateField.accept( this ); } @@ -167,7 +168,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker statement) { visitCteContainer( statement ); - visitRootPath( statement.getTarget() ); + statement.getTarget().accept( this ); for ( SqmPath stateField : statement.getInsertionTargetPaths() ) { stateField.accept( this ); } @@ -180,7 +181,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker statement) { visitCteContainer( statement ); - visitRootPath( statement.getTarget() ); + statement.getTarget().accept( this ); visitWhereClause( statement.getWhereClause() ); return statement; } @@ -236,25 +237,35 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker sqmRoot) { + sqmRoot.visitReusablePaths( path -> path.accept( this ) ); sqmRoot.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) ); return sqmRoot; } @Override public Object visitCrossJoin(SqmCrossJoin joinedFromElement) { + joinedFromElement.visitReusablePaths( path -> path.accept( this ) ); joinedFromElement.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) ); return joinedFromElement; } @Override public Object visitQualifiedEntityJoin(SqmEntityJoin joinedFromElement) { + joinedFromElement.visitReusablePaths( path -> path.accept( this ) ); joinedFromElement.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) ); + if ( joinedFromElement.getJoinPredicate() != null ) { + joinedFromElement.getJoinPredicate().accept( this ); + } return joinedFromElement; } @Override public Object visitQualifiedAttributeJoin(SqmAttributeJoin joinedFromElement) { + joinedFromElement.visitReusablePaths( path -> path.accept( this ) ); joinedFromElement.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) ); + if ( joinedFromElement.getJoinPredicate() != null ) { + joinedFromElement.getJoinPredicate().accept( this ); + } return joinedFromElement; } @@ -274,7 +285,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker path) { return path; } @@ -289,12 +300,12 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker path) { + return path; } @Override - public Object visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path) { + public Object visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path) { return path; } @@ -319,12 +330,18 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker correlation) { + correlation.visitReusablePaths( path -> path.accept( this ) ); + correlation.visitSqmJoins( sqmJoin -> sqmJoin.accept( this ) ); return correlation; } @Override public Object visitSelectClause(SqmSelectClause selectClause) { + if ( selectClause == null ) { + return null; + } + // todo (6.0) : add the ability for certain SqlSelections to be sort of "implicit"... // - they do not get rendered into the SQL, but do have a SqlReader // @@ -427,6 +444,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker expression) { return expression; } @Override - public Object visitNamedParameterExpression(SqmNamedParameter expression) { + public Object visitNamedParameterExpression(SqmNamedParameter expression) { return expression; } @@ -535,23 +553,37 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker expression) { return expression; } @Override public Object visitParameterizedEntityTypeExpression(SqmParameterizedEntityType expression) { + expression.getDiscriminatorSource().accept( this ); return expression; } @Override - public Object visitUnaryOperationExpression(SqmUnaryOperation sqmExpression) { + public Object visitUnaryOperationExpression(SqmUnaryOperation sqmExpression) { sqmExpression.getOperand().accept( this ); return sqmExpression; } @Override - public Object visitFunction(SqmFunction sqmFunction) { + public Object visitFunction(SqmFunction sqmFunction) { + sqmFunction.getArguments().forEach( + e -> { + if ( e instanceof SqmVisitableNode ) { + ( (SqmVisitableNode) e ).accept( this ); + } + } + ); + if ( sqmFunction instanceof SqmAggregateFunction ) { + final SqmPredicate filter = ( (SqmAggregateFunction) sqmFunction ).getFilter(); + if ( filter != null ) { + filter.accept( this ); + } + } return sqmFunction; } @@ -561,7 +593,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker extractUnit) { return extractUnit; } @@ -571,17 +603,20 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker castTarget) { return castTarget; } @Override - public Object visitCoalesce(SqmCoalesce sqmCoalesce) { + public Object visitCoalesce(SqmCoalesce sqmCoalesce) { + sqmCoalesce.getArguments().forEach( e -> e.accept( this ) ); return sqmCoalesce; } @Override - public Object visitToDuration(SqmToDuration toDuration) { + public Object visitToDuration(SqmToDuration toDuration) { + toDuration.getMagnitude().accept( this ); + toDuration.getUnit().accept( this ); return toDuration; } @@ -591,7 +626,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker distinct) { return distinct; } @@ -605,19 +640,19 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker sqmTreatedPath) { + return sqmTreatedPath; } @Override public Object visitPluralAttributeSizeFunction(SqmCollectionSize function) { + function.getPluralPath().accept( this ); return function; } @Override - public Object visitMapEntryFunction(SqmMapEntryReference binding) { + public Object visitMapEntryFunction(SqmMapEntryReference binding) { + binding.getMapPath().accept( this ); return binding; } @@ -628,6 +663,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker sqmTuple) { + sqmTuple.getGroupedExpressions().forEach( e -> e.accept( this ) ); return sqmTuple; } @@ -638,51 +674,75 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker expression) { + expression.getLeftHandOperand().accept( this ); + expression.getRightHandOperand().accept( this ); return expression; } public Object visitByUnit(SqmByUnit byUnit) { + byUnit.getDuration().accept( this ); + byUnit.getUnit().accept( this ); return byUnit; } @Override - public Object visitDurationUnit(SqmDurationUnit durationUnit) { + public Object visitDurationUnit(SqmDurationUnit durationUnit) { return durationUnit; } @Override - public Object visitSubQueryExpression(SqmSubQuery expression) { + public Object visitSubQueryExpression(SqmSubQuery expression) { + expression.getQueryPart().accept( this ); return expression; } @Override public Object visitSimpleCaseExpression(SqmCaseSimple expression) { + expression.getFixture().accept( this ); + for ( SqmCaseSimple.WhenFragment whenFragment : expression.getWhenFragments() ) { + whenFragment.getCheckValue().accept( this ); + whenFragment.getResult().accept( this ); + } + if ( expression.getOtherwise() != null ) { + expression.getOtherwise().accept( this ); + } return expression; } @Override public Object visitAny(SqmAny sqmAny) { + sqmAny.getSubquery().accept( this ); return sqmAny; } @Override public Object visitEvery(SqmEvery sqmEvery) { + sqmEvery.getSubquery().accept( this ); return sqmEvery; } @Override public Object visitSummarization(SqmSummarization sqmSummarization) { + sqmSummarization.getGroupings().forEach( e -> e.accept( this ) ); return sqmSummarization; } @Override public Object visitSearchedCaseExpression(SqmCaseSearched expression) { + for ( SqmCaseSearched.WhenFragment whenFragment : expression.getWhenFragments() ) { + whenFragment.getPredicate().accept( this ); + whenFragment.getResult().accept( this ); + } + if ( expression.getOtherwise() != null ) { + expression.getOtherwise().accept( this ); + } return expression; } @Override public Object visitDynamicInstantiation(SqmDynamicInstantiation sqmDynamicInstantiation) { + sqmDynamicInstantiation.getArguments().forEach( e -> e.getSelectableNode().accept( this ) ); return sqmDynamicInstantiation; } @@ -693,13 +753,13 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker sqmEnumLiteral) { + return sqmEnumLiteral; } @Override - public Object visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral) { - throw new UnsupportedOperationException( "Not supported" ); + public Object visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral) { + return sqmFieldLiteral; } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index cc97414482..ff670cbb5b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -6,6 +6,7 @@ */ package org.hibernate.query.sqm.sql; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; @@ -16,6 +17,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; @@ -72,7 +74,6 @@ import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource; -import org.hibernate.metamodel.model.domain.internal.DiscriminatorSqmPath; import org.hibernate.param.VersionTypeSeedParameterSpecification; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.EntityPersister; @@ -93,6 +94,7 @@ import org.hibernate.query.spi.QueryParameterImplementor; import org.hibernate.query.sqm.InterpretationException; import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmPathSource; +import org.hibernate.query.sqm.SqmQuerySource; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression; import org.hibernate.query.sqm.internal.DomainParameterXref; @@ -195,6 +197,7 @@ import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.predicate.SqmOrPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; +import org.hibernate.query.sqm.tree.select.SqmAliasedNode; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationArgument; import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiationTarget; @@ -270,6 +273,7 @@ import org.hibernate.sql.ast.tree.from.VirtualTableGroup; import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.ast.tree.insert.Values; import org.hibernate.sql.ast.tree.predicate.BetweenPredicate; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.ExistsPredicate; import org.hibernate.sql.ast.tree.predicate.FilterPredicate; @@ -789,12 +793,11 @@ public abstract class BaseSqmToSqlAstConverter extends Base ); try { - - if ( sqmAssignment.getValue() instanceof SqmParameter ) { - final SqmParameter sqmParameter = (SqmParameter) sqmAssignment.getValue(); - + final SqmExpression assignmentValue = sqmAssignment.getValue(); + final SqmParameter assignmentValueParameter = getSqmParameter( assignmentValue ); + if ( assignmentValueParameter != null ) { consumeSqmParameter( - sqmParameter, + assignmentValueParameter, (index, jdbcParameter) -> assignments.add( new Assignment( targetColumnReferences.get( index ), @@ -804,7 +807,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base ); } else { - final Expression valueExpression = (Expression) sqmAssignment.getValue().accept( this ); + final Expression valueExpression = (Expression) assignmentValue.accept( this ); final int valueExprJdbcCount = getKeyExpressable( valueExpression.getExpressionType() ).getJdbcTypeCount(); final int assignedPathJdbcCount = getKeyExpressable( assignedPathInterpretation.getExpressionType() ) @@ -929,8 +932,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base r, selectQueryPart.getFirstQuerySpec() .getSelectClause() - .getSelectionItems() - .size() + .getSelections() ), getCurrentClauseStack()::getCurrent ) @@ -1113,17 +1115,8 @@ public abstract class BaseSqmToSqlAstConverter extends Base ); for ( SqmDynamicInstantiationArgument sqmArgument : sqmDynamicInstantiation.getArguments() ) { - //noinspection StatementWithEmptyBody - if ( sqmArgument.getSelectableNode() instanceof SqmDynamicInstantiation ) { - // see discussion on `#visitSelection` wrt dynamic-instantiation - } - else { - currentSqlSelectionCollector().next(); - } - - final DomainResultProducer argumentResultProducer = (DomainResultProducer) sqmArgument - .getSelectableNode() - .accept( this ); + final SqmSelectableNode selectableNode = sqmArgument.getSelectableNode(); + final DomainResultProducer argumentResultProducer = (DomainResultProducer) selectableNode.accept( this ); dynamicInstantiation.addArgument( sqmArgument.getAlias(), argumentResultProducer, this ); } @@ -1378,7 +1371,11 @@ public abstract class BaseSqmToSqlAstConverter extends Base trackAliasedNodePositions = true; } else { - trackAliasedNodePositions = false; + // Since JPA Criteria queries can use the same expression object in order or group by items, + // we need to track the positions to be able to replace the expression in the items with alias references + // Also see #resolveGroupOrOrderByExpression for more details + trackAliasedNodePositions = statement.getQuerySource() == SqmQuerySource.CRITERIA + && ( sqmQuerySpec.getOrderByClause() != null || !sqmQuerySpec.getGroupByClauseExpressions().isEmpty() ); } final SqlAstProcessingState processingState; @@ -1389,7 +1386,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base this, r -> new SqmAliasedNodePositionTracker( r, - selectClause.getSelectionItems().size() + selectClause.getSelections() ), currentClauseStack::getCurrent ); @@ -1544,10 +1541,15 @@ public abstract class BaseSqmToSqlAstConverter extends Base public SelectClause visitSelectClause(SqmSelectClause selectClause) { currentClauseStack.push( Clause.SELECT ); try { - super.visitSelectClause( selectClause ); - final SelectClause sqlSelectClause = currentQuerySpec().getSelectClause(); - sqlSelectClause.makeDistinct( selectClause.isDistinct() ); + if ( selectClause == null ) { + final SqmFrom implicitSelection = determineImplicitSelection( (SqmQuerySpec) currentSqmQueryPart ); + visitSelection( new SqmSelection<>( implicitSelection, implicitSelection.nodeBuilder() ) ); + } + else { + super.visitSelectClause( selectClause ); + sqlSelectClause.makeDistinct( selectClause.isDistinct() ); + } return sqlSelectClause; } finally { @@ -1555,38 +1557,40 @@ public abstract class BaseSqmToSqlAstConverter extends Base } } + protected SqmFrom determineImplicitSelection(SqmQuerySpec querySpec) { + // Note that this is different from org.hibernate.query.hql.internal.SemanticQueryBuilder.buildInferredSelectClause + return querySpec.getFromClause().getRoots().get( 0 ); + } + @Override public Void visitSelection(SqmSelection sqmSelection) { - final Map> resultProducers; - - if ( sqmSelection.getSelectableNode() instanceof SqmJpaCompoundSelection ) { - SqmJpaCompoundSelection selectableNode = (SqmJpaCompoundSelection) sqmSelection.getSelectableNode(); - resultProducers = new HashMap<>( selectableNode.getSelectionItems().size() ); + final List>> resultProducers; + final SqmSelectableNode selectionNode = sqmSelection.getSelectableNode(); + if ( selectionNode instanceof SqmJpaCompoundSelection ) { + final SqmJpaCompoundSelection selectableNode = (SqmJpaCompoundSelection) selectionNode; + resultProducers = new ArrayList<>( selectableNode.getSelectionItems().size() ); for ( SqmSelectableNode selectionItem : selectableNode.getSelectionItems() ) { - currentSqlSelectionCollector().next(); - resultProducers.put( - selectionItem.getAlias(), - (DomainResultProducer) selectionItem.accept( this ) + if ( selectionItem instanceof SqmPath ) { + prepareForSelection( (SqmPath) selectionItem ); + } + resultProducers.add( + new AbstractMap.SimpleEntry<>( + selectionItem.getAlias(), + (DomainResultProducer) selectionItem.accept( this ) + ) ); } } else { - //noinspection StatementWithEmptyBody - if ( sqmSelection.getSelectableNode() instanceof SqmDynamicInstantiation ) { - // this `currentSqlSelectionCollector().next()` is meant solely for resolving - // literal reference to a selection-item in the order-by or group-by clause. - // in the case of `SqmDynamicInstantiation`, that ordering should ignore that - // level here. visiting the dynamic-instantiation will manage this for its - // arguments + if ( selectionNode instanceof SqmPath ) { + prepareForSelection( (SqmPath) selectionNode ); } - else { - // otherwise, position the collector at the next index in prep for visitation - currentSqlSelectionCollector().next(); - } - resultProducers = Collections.singletonMap( - sqmSelection.getAlias(), - (DomainResultProducer) sqmSelection.getSelectableNode().accept( this ) + resultProducers = Collections.singletonList( + new AbstractMap.SimpleEntry<>( + sqmSelection.getAlias(), + (DomainResultProducer) selectionNode.accept( this ) + ) ); } @@ -1619,16 +1623,42 @@ public abstract class BaseSqmToSqlAstConverter extends Base } ) == null; } + // this `currentSqlSelectionCollector().next()` is meant solely for resolving + // literal reference to a selection-item in the order-by or group-by clause. + // in the case of `DynamicInstantiation`, that ordering should ignore that + // level here. visiting the dynamic-instantiation will manage this for its + // arguments if ( collectDomainResults ) { - resultProducers.forEach( (alias, r) -> domainResults.add( r.createDomainResult( alias, this ) ) ); + resultProducers.forEach( + entry -> { + if ( !( entry.getValue() instanceof DynamicInstantiation ) ) { + currentSqlSelectionCollector().next(); + } + domainResults.add( entry.getValue().createDomainResult( entry.getKey(), this ) ); + } + ); } else if ( needsDomainResults ) { // We just create domain results for the purpose of creating selections // This is necessary for top-level query specs within query groups to avoid cycles - resultProducers.forEach( (alias, r) -> r.createDomainResult( alias, this ) ); + resultProducers.forEach( + entry -> { + if ( !( entry.getValue() instanceof DynamicInstantiation ) ) { + currentSqlSelectionCollector().next(); + } + entry.getValue().createDomainResult( entry.getKey(), this ); + } + ); } else { - resultProducers.forEach( (alias, r) -> r.applySqlSelections( this ) ); + resultProducers.forEach( + entry -> { + if ( !( entry.getValue() instanceof DynamicInstantiation ) ) { + currentSqlSelectionCollector().next(); + } + entry.getValue().applySqlSelections( this ); + } + ); } return null; } @@ -1639,9 +1669,28 @@ public abstract class BaseSqmToSqlAstConverter extends Base } protected Expression resolveGroupOrOrderByExpression(SqmExpression groupByClauseExpression) { + final int sqmPosition; if ( groupByClauseExpression instanceof SqmAliasedNodeRef ) { final int aliasedNodeOrdinal = ( (SqmAliasedNodeRef) groupByClauseExpression ).getPosition(); - final int sqmPosition = aliasedNodeOrdinal - 1; + sqmPosition = aliasedNodeOrdinal - 1; + } + else if ( statement.getQuerySource() == SqmQuerySource.CRITERIA ) { + // In JPA Criteria we could be using the same expression object for the group/order by and select item + // We try to find the select item position for this expression here which is not necessarily just an optimization. + // This is vital to enable the support for parameters in these expressions. + // Databases usually don't know if a parameter marker will have the same value as another parameter marker + // and due to that, a database usually complains when seeing something like + // `select ?, count(*) from dual group by ?` saying that there is a missing group by for the first `?` + // To avoid this issue, we determine the position and let the SqlAstTranslator handle the rest. + // Usually it will render `select ?, count(*) from dual group by 1` if supported + // or force rendering the parameter as literal instead so that the database can see the grouping is fine + final SqmQuerySpec querySpec = currentSqmQueryPart.getFirstQuerySpec(); + sqmPosition = indexOfExpression( querySpec.getSelectClause().getSelections(), groupByClauseExpression ); + } + else { + sqmPosition = -1; + } + if ( sqmPosition != -1 ) { final List selections = currentSqlSelectionCollector().getSelections( sqmPosition ); assert selections != null : String.format( Locale.ROOT, "No SqlSelections for SQM position `%s`", sqmPosition ); final List expressions = new ArrayList<>( selections.size() ); @@ -1726,9 +1775,56 @@ public abstract class BaseSqmToSqlAstConverter extends Base return expression; } + private int indexOfExpression(List> selections, SqmExpression node) { + final int result = indexOfExpression( 0, selections, node ); + if ( result < 1 ) { + return -result; + } + else { + return -1; + } + } + + private int indexOfExpression(int offset, List> selections, SqmExpression node) { + // The idea of this method is that we return the negated index of the position at which we found the node + // and if we didn't find the node, we return the offset + size to allow for recursive invocation + // Encoding this into the integer allows us to avoid some kind of mutable state to handle size/offset + for ( int i = 0; i < selections.size(); i++ ) { + final SqmSelectableNode selectableNode = selections.get( i ).getSelectableNode(); + if ( selectableNode instanceof SqmDynamicInstantiation ) { + final int subResult = indexOfExpression( + offset + i, + ( (SqmDynamicInstantiation) selectableNode ).getArguments(), + node + ); + if ( subResult < 0 ) { + return subResult; + } + offset = subResult - i; + } + else if ( selectableNode instanceof SqmJpaCompoundSelection ) { + final List> selectionItems = ( (SqmJpaCompoundSelection) selectableNode ).getSelectionItems(); + for ( int j = 0; j < selectionItems.size(); j++ ) { + if ( selectionItems.get( j ) == node ) { + return -( offset + i + j ); + } + } + offset += selectionItems.size(); + } + else { + if ( selectableNode == node ) { + return -( offset + i ); + } + } + } + return offset + selections.size(); + } + private boolean selectClauseContains(SqmFrom from) { final SqmQuerySpec sqmQuerySpec = (SqmQuerySpec) currentSqmQueryPart; - final List> selections = sqmQuerySpec.getSelectClause().getSelections(); + final List> selections = sqmQuerySpec.getSelectClause() == null + ? Collections.emptyList() + : sqmQuerySpec.getSelectClause().getSelections(); if ( selections.isEmpty() && from instanceof SqmRoot ) { return true; } @@ -1997,14 +2093,14 @@ public abstract class BaseSqmToSqlAstConverter extends Base @SuppressWarnings("WeakerAccess") protected void consumeExplicitJoin(SqmJoin sqmJoin, TableGroup lhsTableGroup) { - if ( sqmJoin instanceof SqmAttributeJoin ) { - consumeAttributeJoin( ( (SqmAttributeJoin) sqmJoin ), lhsTableGroup ); + if ( sqmJoin instanceof SqmAttributeJoin ) { + consumeAttributeJoin( ( (SqmAttributeJoin) sqmJoin ), lhsTableGroup ); } - else if ( sqmJoin instanceof SqmCrossJoin ) { - consumeCrossJoin( ( (SqmCrossJoin) sqmJoin ), lhsTableGroup ); + else if ( sqmJoin instanceof SqmCrossJoin ) { + consumeCrossJoin( ( (SqmCrossJoin) sqmJoin ), lhsTableGroup ); } - else if ( sqmJoin instanceof SqmEntityJoin ) { - consumeEntityJoin( ( (SqmEntityJoin) sqmJoin ), lhsTableGroup ); + else if ( sqmJoin instanceof SqmEntityJoin ) { + consumeEntityJoin( ( (SqmEntityJoin) sqmJoin ), lhsTableGroup ); } else { throw new InterpretationException( "Could not resolve SqmJoin [" + sqmJoin.getNavigablePath() + "] to TableGroupJoin" ); @@ -2198,35 +2294,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base return; } - final SqmPath lhsPath = joinedPath.getLhs(); - final FromClauseIndex fromClauseIndex = getFromClauseIndex(); - final ModelPart subPart = parentTableGroup.getModelPart().findSubPart( - joinedPath.getReferencedPathSource().getPathName(), - lhsPath instanceof SqmTreatedPath - ? resolveEntityPersister( ( (SqmTreatedPath) lhsPath ).getTreatTarget() ) - : null - ); - - final TableGroup tableGroup; - if ( subPart instanceof TableGroupJoinProducer ) { - final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart; - final SqlAstJoinType defaultSqlAstJoinType = joinProducer.getDefaultSqlAstJoinType( - parentTableGroup ); - final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin( - joinedPath.getNavigablePath(), - parentTableGroup, - null, - defaultSqlAstJoinType, - false, - this - ); - - fromClauseIndex.register( joinedPath, tableGroupJoin.getJoinedGroup() ); - tableGroup = tableGroupJoin.getJoinedGroup(); - } - else { - tableGroup = null; - } + final TableGroup tableGroup = createTableGroup( parentTableGroup, joinedPath ); consumeReusablePaths( joinedPath, tableGroup, implicitJoinChecker ); if ( tableGroup != null ) { implicitJoinChecker.accept( tableGroup ); @@ -2235,6 +2303,62 @@ public abstract class BaseSqmToSqlAstConverter extends Base ); } + private void prepareForSelection(SqmPath joinedPath) { + final SqmPath lhsPath = joinedPath.getLhs(); + final FromClauseIndex fromClauseIndex = getFromClauseIndex(); + final TableGroup tableGroup = fromClauseIndex.findTableGroup( joinedPath.getNavigablePath() ); + if ( tableGroup == null ) { + final NavigablePath navigablePath; + if ( CollectionPart.Nature.fromNameExact( joinedPath.getNavigablePath().getUnaliasedLocalName() ) != null ) { + navigablePath = lhsPath.getLhs().getNavigablePath(); + } + else { + navigablePath = lhsPath.getNavigablePath(); + } + createTableGroup( fromClauseIndex.getTableGroup( navigablePath ), joinedPath ); + } + // When we select a treated path, we must add the type restriction as where clause predicate + if ( joinedPath instanceof SqmTreatedPath ) { + final SqmTreatedPath treatedPath = (SqmTreatedPath) joinedPath; + // todo (6.0): the persister and the table group should participate so we can optimize the joins/selects + currentQuerySpec().applyPredicate( + createTreatTypeRestriction( treatedPath.getWrappedPath(), treatedPath.getTreatTarget() ) + ); + } + } + + private TableGroup createTableGroup(TableGroup parentTableGroup, SqmPath joinedPath) { + final SqmPath lhsPath = joinedPath.getLhs(); + final FromClauseIndex fromClauseIndex = getFromClauseIndex(); + final ModelPart subPart = parentTableGroup.getModelPart().findSubPart( + joinedPath.getReferencedPathSource().getPathName(), + lhsPath instanceof SqmTreatedPath + ? resolveEntityPersister( ( (SqmTreatedPath) lhsPath ).getTreatTarget() ) + : null + ); + + final TableGroup tableGroup; + if ( subPart instanceof TableGroupJoinProducer ) { + final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart; + final SqlAstJoinType defaultSqlAstJoinType = joinProducer.getDefaultSqlAstJoinType( parentTableGroup ); + final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin( + joinedPath.getNavigablePath(), + parentTableGroup, + null, + defaultSqlAstJoinType, + false, + this + ); + + fromClauseIndex.register( joinedPath, tableGroupJoin.getJoinedGroup() ); + tableGroup = tableGroupJoin.getJoinedGroup(); + } + else { + tableGroup = null; + } + return tableGroup; + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SqmPath handling // - Note that SqmFrom references defined in the FROM-clause are already @@ -2313,8 +2437,13 @@ public abstract class BaseSqmToSqlAstConverter extends Base @Override public Expression visitBasicValuedPath(SqmBasicValuedSimplePath sqmPath) { - BasicValuedPathInterpretation path = BasicValuedPathInterpretation.from( sqmPath, this, this, jpaQueryComplianceEnabled ); - + final BasicValuedPathInterpretation path = BasicValuedPathInterpretation.from( + sqmPath, + this, + this, + jpaQueryComplianceEnabled + ); + Expression result = path; if ( isDuration( sqmPath.getNodeType() ) ) { // Durations are stored (at least by default) @@ -2345,7 +2474,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base // we're adding this variable duration to the // given date or timestamp, producing an // adjusted date or timestamp - return timestampadd().expression( + result = timestampadd().expression( (AllowableFunctionReturnType) adjustedTimestampType, new DurationUnit( NANOSECOND, basicType( Long.class ) ), scaledExpression, @@ -2363,47 +2492,114 @@ public abstract class BaseSqmToSqlAstConverter extends Base TemporalUnit appliedUnit = appliedByUnit.getUnit().getUnit(); BasicValuedMapping scalarType = (BasicValuedMapping) appliedByUnit.getNodeType(); - return new Conversion( duration, appliedUnit, scalarType ); + result = new Conversion( duration, appliedUnit, scalarType ); } else { // a "bare" Duration value in nanoseconds - return scaledExpression; + result = scaledExpression; } } - return path; + return withTreatRestriction( result, sqmPath ); } @Override - public SqmPathInterpretation visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath sqmPath) { - return EmbeddableValuedPathInterpretation.from( sqmPath, this, this, jpaQueryComplianceEnabled ); + public Expression visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath sqmPath) { + return withTreatRestriction( + EmbeddableValuedPathInterpretation.from( sqmPath, this, this, jpaQueryComplianceEnabled ), + sqmPath + ); } @Override - public SqmPathInterpretation visitAnyValuedValuedPath(SqmAnyValuedSimplePath path) { - return DiscriminatedAssociationPathInterpretation.from( path, this ); + public Expression visitAnyValuedValuedPath(SqmAnyValuedSimplePath sqmPath) { + return withTreatRestriction( + DiscriminatedAssociationPathInterpretation.from( sqmPath, this ), + sqmPath + ); } @Override - public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath sqmPath) { - return NonAggregatedCompositeValuedPathInterpretation.from( sqmPath, this, this ); + public Expression visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath sqmPath) { + return withTreatRestriction( + NonAggregatedCompositeValuedPathInterpretation.from( sqmPath, this, this ), + sqmPath + ); } @Override - public SqmPathInterpretation visitEntityValuedPath(SqmEntityValuedSimplePath sqmPath) { - return EntityValuedPathInterpretation.from( sqmPath, this ); + public Expression visitEntityValuedPath(SqmEntityValuedSimplePath sqmPath) { + return withTreatRestriction( + EntityValuedPathInterpretation.from( sqmPath, this ), + sqmPath + ); } @Override - public SqmPathInterpretation visitPluralValuedPath(SqmPluralValuedSimplePath sqmPath) { - return PluralValuedSimplePathInterpretation.from( sqmPath, this ); + public Expression visitPluralValuedPath(SqmPluralValuedSimplePath sqmPath) { + return withTreatRestriction( + PluralValuedSimplePathInterpretation.from( sqmPath, this ), + sqmPath + ); } @Override - public Object visitSelfInterpretingSqmPath(SelfInterpretingSqmPath sqmPath) { + public Object visitSelfInterpretingSqmPath(SelfInterpretingSqmPath sqmPath) { return sqmPath.interpret( this, this, jpaQueryComplianceEnabled ); } + private Expression withTreatRestriction(Expression expression, SqmPath path) { + final SqmPath lhs = path.getLhs(); + if ( lhs instanceof SqmTreatedPath ) { + final SqmTreatedPath treatedPath = (SqmTreatedPath) lhs; + final Class treatTargetJavaType = treatedPath.getTreatTarget().getJavaType(); + final Class originalJavaType = treatedPath.getWrappedPath().getJavaType(); + if ( treatTargetJavaType.isAssignableFrom( originalJavaType ) ) { + // Treating a node to a super type can be ignored + return expression; + } + return createCaseExpression( treatedPath.getWrappedPath(), treatedPath.getTreatTarget(), expression ); + } + return expression; + } + + private Expression createCaseExpression(SqmPath lhs, EntityDomainType treatTarget, Expression expression) { + @SuppressWarnings("rawtypes") + final MappingModelExpressable mappingModelExpressable = (MappingModelExpressable) expression.getExpressionType(); + final List whenFragments = new ArrayList<>( 1 ); + whenFragments.add( + new CaseSearchedExpression.WhenFragment( + createTreatTypeRestriction( lhs, treatTarget ), + expression + ) + ); + return new CaseSearchedExpression( + mappingModelExpressable, + whenFragments, + new NullnessLiteral( mappingModelExpressable ) + ); + } + + private Predicate createTreatTypeRestriction(SqmPath lhs, EntityDomainType treatTarget) { + final MappingMetamodel domainModel = getCreationContext().getDomainModel(); + final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( treatTarget.getHibernateEntityName() ); + final Set subclassEntityNames = entityDescriptor.getEntityMetamodel().getSubclassEntityNames(); + final Expression typeExpression = (Expression) lhs.type().accept( this ); + if ( subclassEntityNames.size() == 1 ) { + return new ComparisonPredicate( + typeExpression, + ComparisonOperator.EQUAL, + new EntityTypeLiteral( entityDescriptor ) + ); + } + else { + final List typeLiterals = new ArrayList<>( subclassEntityNames.size() ); + for ( String subclassEntityName : subclassEntityNames ) { + typeLiterals.add( new EntityTypeLiteral( domainModel.findEntityDescriptor( subclassEntityName ) ) ); + } + return new InListPredicate( typeExpression, typeLiterals ); + } + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // General expressions @@ -2413,7 +2609,10 @@ public abstract class BaseSqmToSqlAstConverter extends Base final Supplier inferableTypeAccess = inferrableTypeAccessStack.getCurrent(); if ( literal instanceof SqmLiteralNull ) { - final MappingModelExpressable mappingModelExpressable = inferableTypeAccess.get(); + MappingModelExpressable mappingModelExpressable = inferableTypeAccess.get(); + if ( mappingModelExpressable == null ) { + mappingModelExpressable = determineCurrentExpressable( literal ); + } if ( mappingModelExpressable instanceof BasicValuedMapping ) { return new NullnessLiteral( mappingModelExpressable ); } @@ -2463,9 +2662,38 @@ public abstract class BaseSqmToSqlAstConverter extends Base sqlLiteralValue = literalValue; } - return new QueryLiteral<>( sqlLiteralValue, (BasicValuedMapping) inferableExpressable ); + return new QueryLiteral<>( sqlLiteralValue, convertibleModelPart ); } } + // Special case for when we create an entity literal through the JPA CriteriaBuilder.literal API + else if ( inferableExpressable instanceof EntityDiscriminatorMapping ) { + final EntityDiscriminatorMapping discriminatorMapping = (EntityDiscriminatorMapping) inferableExpressable; + final Object literalValue = literal.getLiteralValue(); + final EntityPersister mappingDescriptor; + if ( literalValue instanceof Class ) { + mappingDescriptor = getCreationContext().getDomainModel() + .getEntityDescriptor( (Class) literalValue ); + } + else { + final JavaTypeDescriptor javaTypeDescriptor = discriminatorMapping.getJdbcMapping().getJavaTypeDescriptor(); + final Object discriminatorValue; + if ( javaTypeDescriptor.getJavaTypeClass().isInstance( literalValue ) ) { + discriminatorValue = literalValue; + } + else if ( literalValue instanceof String ) { + discriminatorValue = javaTypeDescriptor.fromString( (String) literalValue ); + } + else { + discriminatorValue = javaTypeDescriptor.coerce( literalValue, null ); + } + final String entityName = discriminatorMapping.getConcreteEntityNameForDiscriminatorValue( + discriminatorValue + ); + mappingDescriptor = getCreationContext().getDomainModel() + .getEntityDescriptor( entityName ); + } + return new EntityTypeLiteral( mappingDescriptor ); + } final MappingModelExpressable expressable; final MappingModelExpressable localExpressable = SqmMappingModelHelper.resolveMappingModelExpressable( @@ -2473,21 +2701,90 @@ public abstract class BaseSqmToSqlAstConverter extends Base getCreationContext().getDomainModel(), getFromClauseAccess()::findTableGroup ); - if ( localExpressable instanceof BasicType ) { - expressable = InferredBasicValueResolver.resolveSqlTypeIndicators( - this, - (BasicType) localExpressable, - literal.getJavaTypeDescriptor() - ); + if ( localExpressable == null ) { + expressable = getElementExpressable( inferableExpressable ); } else { - expressable = localExpressable; + final MappingModelExpressable elementExpressable = getElementExpressable( localExpressable ); + if ( elementExpressable instanceof BasicType ) { + expressable = InferredBasicValueResolver.resolveSqlTypeIndicators( + this, + (BasicType) elementExpressable, + literal.getJavaTypeDescriptor() + ); + } + else { + expressable = elementExpressable; + } } - return new QueryLiteral<>( - literal.getLiteralValue(), - (BasicValuedMapping) expressable - ); + if ( expressable instanceof BasicValuedMapping ) { + return new QueryLiteral<>( + literal.getLiteralValue(), + (BasicValuedMapping) expressable + ); + } + // Handling other values might seem unnecessary, but with JPA Criteria it is totally possible to have such literals + else if ( expressable instanceof EmbeddableValuedModelPart ) { + final EmbeddableValuedModelPart embeddableValuedModelPart = (EmbeddableValuedModelPart) expressable; + final List list = new ArrayList<>( embeddableValuedModelPart.getJdbcTypeCount() ); + embeddableValuedModelPart.forEachJdbcValue( + literal.getLiteralValue(), + null, + (selectionIndex, value, jdbcMapping) -> { + list.add( new QueryLiteral<>( value, (BasicValuedMapping) jdbcMapping ) ); + }, + null + ); + return new SqlTuple( list, expressable ); + } + else if ( expressable instanceof EntityValuedModelPart ) { + final EntityValuedModelPart entityValuedModelPart = (EntityValuedModelPart) expressable; + final Object associationKey; + final ModelPart associationKeyPart; + if ( entityValuedModelPart instanceof Association ) { + final Association association = (Association) entityValuedModelPart; + final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor(); + associationKey = foreignKeyDescriptor.getAssociationKeyFromSide( + literal.getLiteralValue(), + association.getSideNature(), + null + ); + associationKeyPart = foreignKeyDescriptor.getPart( association.getSideNature() ); + } + else { + final EntityIdentifierMapping identifierMapping = entityValuedModelPart.getEntityMappingType() + .getIdentifierMapping(); + associationKeyPart = identifierMapping; + associationKey = identifierMapping.getIdentifier( + literal.getLiteralValue(), + null + ); + } + if ( associationKeyPart instanceof BasicValuedMapping ) { + return new QueryLiteral<>( + associationKey, + (BasicValuedMapping) associationKeyPart + ); + } + else { + final List list = new ArrayList<>( associationKeyPart.getJdbcTypeCount() ); + associationKeyPart.forEachJdbcValue( + associationKey, + null, + (selectionIndex, value, jdbcMapping) -> { + list.add( new QueryLiteral<>( value, (BasicValuedMapping) jdbcMapping ) ); + }, + null + ); + return new SqlTuple( list, associationKeyPart ); + } + } + else { + throw new NotYetImplementedFor6Exception( + expressable == null ? literal.getLiteralValue().getClass() : expressable.getClass() + ); + } } private MappingModelExpressable getKeyExpressable(JdbcMappingContainer mappingModelExpressable) { @@ -2499,6 +2796,15 @@ public abstract class BaseSqmToSqlAstConverter extends Base } } + private MappingModelExpressable getElementExpressable(MappingModelExpressable mappingModelExpressable) { + if ( mappingModelExpressable instanceof PluralAttributeMapping ) { + return ( (PluralAttributeMapping) mappingModelExpressable ).getElementDescriptor(); + } + else { + return mappingModelExpressable; + } + } + private final Map>> jdbcParamsBySqmParam = new IdentityHashMap<>(); private final JdbcParameters jdbcParameters = new JdbcParametersImpl(); @@ -2508,7 +2814,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Expression visitNamedParameterExpression(SqmNamedParameter expression) { + public Expression visitNamedParameterExpression(SqmNamedParameter expression) { return consumeSqmParameter( expression ); } @@ -2731,6 +3037,23 @@ public abstract class BaseSqmToSqlAstConverter extends Base return valueMapping; } + protected MappingModelExpressable getInferredValueMapping() { + final Supplier currentExpressableSupplier = inferrableTypeAccessStack.getCurrent(); + if ( currentExpressableSupplier != null ) { + final MappingModelExpressable inferredMapping = currentExpressableSupplier.get(); + if ( inferredMapping != null ) { + if ( inferredMapping instanceof PluralAttributeMapping ) { + return ( (PluralAttributeMapping) inferredMapping ).getElementDescriptor(); + } + else if ( !( inferredMapping instanceof JavaObjectType ) ) { + // Never report back the "object type" as inferred type and instead rely on the value type + return inferredMapping; + } + } + } + return null; + } + @SuppressWarnings("WeakerAccess") protected MappingModelExpressable determineValueMapping(SqmParameter sqmParameter) { log.debugf( "Determining mapping-model type for SqmParameter : %s", sqmParameter ); @@ -2742,18 +3065,9 @@ public abstract class BaseSqmToSqlAstConverter extends Base // this should indicate the condition that the user query did not define an // explicit type in regard to this parameter. Here we should prefer the // inferrable type and fallback to the binding type - final Supplier currentExpressableSupplier = inferrableTypeAccessStack.getCurrent(); - if ( currentExpressableSupplier != null ) { - final MappingModelExpressable inferredMapping = currentExpressableSupplier.get(); - if ( inferredMapping != null ) { - if ( inferredMapping instanceof PluralAttributeMapping ) { - return ( (PluralAttributeMapping) inferredMapping ).getElementDescriptor(); - } - else if ( !( inferredMapping instanceof JavaObjectType ) ) { - // Never report back the "object type" as inferred type and instead rely on the value type - return inferredMapping; - } - } + final MappingModelExpressable inferredValueMapping = getInferredValueMapping(); + if ( inferredValueMapping != null ) { + return inferredValueMapping; } } @@ -2785,6 +3099,14 @@ public abstract class BaseSqmToSqlAstConverter extends Base return (BasicValuedMapping) parameterSqmType; } + if ( parameterSqmType instanceof SqmPathSource ) { + // Try to infer the value mapping since the other side apparently is a path source + final MappingModelExpressable inferredValueMapping = getInferredValueMapping(); + if ( inferredValueMapping != null ) { + return inferredValueMapping; + } + } + if ( parameterSqmType instanceof CompositeSqmPathSource ) { throw new NotYetImplementedFor6Exception( "Support for embedded-valued parameters not yet implemented" ); } @@ -2817,12 +3139,26 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitPositionalParameterExpression(SqmPositionalParameter expression) { + public Object visitPositionalParameterExpression(SqmPositionalParameter expression) { return consumeSqmParameter( expression ); } @Override public Object visitJpaCriteriaParameter(JpaCriteriaParameter expression) { + return consumeSqmParameter( getSqmParameter( expression ) ); + } + + private SqmParameter getSqmParameter(SqmExpression parameter) { + if ( parameter instanceof JpaCriteriaParameter ) { + return getSqmParameter( (JpaCriteriaParameter) parameter ); + } + else if ( parameter instanceof SqmParameter ) { + return (SqmParameter) parameter; + } + return null; + } + + private SqmParameter getSqmParameter(JpaCriteriaParameter expression) { if ( jpaCriteriaParamResolutions == null ) { throw new IllegalStateException( "No JpaCriteriaParameter resolutions registered" ); } @@ -2831,8 +3167,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base if ( supplier == null ) { throw new IllegalStateException( "Criteria parameter [" + expression + "] not known to be a parameter of the processing tree" ); } - - return consumeSqmParameter( supplier.get() ); + return supplier.get(); } @Override @@ -2871,7 +3206,20 @@ public abstract class BaseSqmToSqlAstConverter extends Base } } } - return new SqlTuple( expressions, null ); + final MappingModelExpressable valueMapping; + if ( mappingModelExpressable != null ) { + valueMapping = mappingModelExpressable; + } + else { + final SqmExpressable expressable = sqmTuple.getExpressable(); + if ( expressable instanceof MappingModelExpressable ) { + valueMapping = (MappingModelExpressable) expressable; + } + else { + valueMapping = null; + } + } + return new SqlTuple( expressions, valueMapping ); } @Override @@ -2883,7 +3231,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Expression visitFunction(SqmFunction sqmFunction) { + public Expression visitFunction(SqmFunction sqmFunction) { inferrableTypeAccessStack.push( () -> null ); try { return sqmFunction.convertToSqlAst( this ); @@ -2899,12 +3247,9 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - @SuppressWarnings("rawtypes") - public Object visitMapEntryFunction(SqmMapEntryReference entryRef) { - final SqmPath mapPath = entryRef.getMapPath(); + public Object visitMapEntryFunction(SqmMapEntryReference entryRef) { + final SqmPath mapPath = entryRef.getMapPath(); final NavigablePath mapNavigablePath = mapPath.getNavigablePath(); - - final TableGroup tableGroup = getFromClauseAccess().resolveTableGroup( mapNavigablePath, (navigablePath) -> { @@ -2928,38 +3273,39 @@ public abstract class BaseSqmToSqlAstConverter extends Base final PluralAttributeMapping mapDescriptor = (PluralAttributeMapping) tableGroup.getModelPart(); - final ForeignKeyDescriptor keyDescriptor = mapDescriptor.getKeyDescriptor(); - final NavigablePath keyNavigablePath = mapNavigablePath.append( keyDescriptor.getPartName() ); - final DomainResult keyResult = keyDescriptor.createKeyDomainResult( - keyNavigablePath, + final CollectionPart indexDescriptor = mapDescriptor.getIndexDescriptor(); + final NavigablePath indexNavigablePath = mapNavigablePath.append( indexDescriptor.getPartName() ); + final DomainResult indexResult = indexDescriptor.createDomainResult( + indexNavigablePath, tableGroup, + null, this ); final CollectionPart valueDescriptor = mapDescriptor.getElementDescriptor(); final NavigablePath valueNavigablePath = mapNavigablePath.append( valueDescriptor.getPartName() ); - final DomainResult valueResult = valueDescriptor.createDomainResult( + final DomainResult valueResult = valueDescriptor.createDomainResult( valueNavigablePath, tableGroup, null, this ); - return new DomainResultProducer() { + return new DomainResultProducer>() { @Override - public DomainResult createDomainResult( + public DomainResult> createDomainResult( String resultVariable, DomainResultCreationState creationState) { - final JavaTypeDescriptor mapEntryDescriptor = getTypeConfiguration() + final JavaTypeDescriptor> mapEntryDescriptor = getTypeConfiguration() .getJavaTypeDescriptorRegistry() .resolveDescriptor( Map.Entry.class ); - return new SqmMapEntryResult( keyResult, valueResult, resultVariable, mapEntryDescriptor ); + return new SqmMapEntryResult<>( indexResult, valueResult, resultVariable, mapEntryDescriptor ); } }; } @Override - public Object visitDistinct(SqmDistinct sqmDistinct) { + public Object visitDistinct(SqmDistinct sqmDistinct) { return new Distinct( (Expression) sqmDistinct.getExpression().accept( this ) ); } @@ -2969,7 +3315,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitCastTarget(SqmCastTarget target) { + public Object visitCastTarget(SqmCastTarget target) { BasicValuedMapping targetType = (BasicValuedMapping) target.getType(); if ( targetType instanceof BasicType ) { targetType = InferredBasicValueResolver.resolveSqlTypeIndicators( @@ -2987,7 +3333,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitExtractUnit(SqmExtractUnit unit) { + public Object visitExtractUnit(SqmExtractUnit unit) { return new ExtractUnit( unit.getUnit(), (BasicValuedMapping) unit.getType() @@ -2995,7 +3341,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitDurationUnit(SqmDurationUnit unit) { + public Object visitDurationUnit(SqmDurationUnit unit) { return new DurationUnit( unit.getUnit(), (BasicValuedMapping) unit.getType() @@ -3389,7 +3735,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base // } @Override - public Object visitUnaryOperationExpression(SqmUnaryOperation expression) { + public Object visitUnaryOperationExpression(SqmUnaryOperation expression) { return new UnaryOperation( interpret( expression.getOperation() ), toSqlExpression( expression.getOperand().accept( this ) ), @@ -3402,7 +3748,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) { + public Object visitBinaryArithmeticExpression(SqmBinaryArithmetic expression) { SqmExpression leftOperand = expression.getLeftHandOperand(); SqmExpression rightOperand = expression.getRightHandOperand(); @@ -3445,13 +3791,20 @@ public abstract class BaseSqmToSqlAstConverter extends Base } } - private BasicValuedMapping getExpressionType(SqmBinaryArithmetic expression) { - SqmExpressable leftHandOperandType = expression.getLeftHandOperand().getNodeType(); + private BasicValuedMapping getExpressionType(SqmBinaryArithmetic expression) { + final SqmExpressable leftHandOperandType = expression.getLeftHandOperand().getNodeType(); if ( leftHandOperandType instanceof BasicValuedMapping ) { return (BasicValuedMapping) leftHandOperandType; } else { - return (BasicValuedMapping) expression.getRightHandOperand().getNodeType(); + final SqmExpressable rightHandOperandType = expression.getRightHandOperand().getNodeType(); + if ( rightHandOperandType instanceof BasicValuedMapping ) { + return (BasicValuedMapping) rightHandOperandType; + } + + return getTypeConfiguration().getBasicTypeForJavaType( + leftHandOperandType.getExpressableJavaTypeDescriptor().getJavaTypeClass() + ); } } @@ -3719,7 +4072,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitToDuration(SqmToDuration toDuration) { + public Object visitToDuration(SqmToDuration toDuration) { //TODO: do we need to temporarily set appliedByUnit // to null before we recurse down the tree? // and what about scale? @@ -3798,7 +4151,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public QueryPart visitSubQueryExpression(SqmSubQuery sqmSubQuery) { + public QueryPart visitSubQueryExpression(SqmSubQuery sqmSubQuery) { return visitQueryPart( sqmSubQuery.getQueryPart() ); // // final ExpressableType expressableType = determineExpressableType( sqmSubQuery ); @@ -3814,44 +4167,97 @@ public abstract class BaseSqmToSqlAstConverter extends Base @Override public CaseSimpleExpression visitSimpleCaseExpression(SqmCaseSimple expression) { - List whenFragments = new ArrayList<>( expression.getWhenFragments().size() ); - - final MappingModelExpressable alreadyKnown = determineCurrentExpressable( expression ); - MappingModelExpressable resolved = alreadyKnown; - - inferrableTypeAccessStack.push( () -> alreadyKnown ); - + final List whenFragments = new ArrayList<>( expression.getWhenFragments().size() ); + final Supplier inferenceSupplier = inferrableTypeAccessStack.getCurrent(); + inferrableTypeAccessStack.push( + () -> { + for ( SqmCaseSimple.WhenFragment whenFragment : expression.getWhenFragments() ) { + final MappingModelExpressable resolved = determineCurrentExpressable( whenFragment.getCheckValue() ); + if ( resolved != null ) { + return resolved; + } + } + return null; + } + ); + final Expression fixture = (Expression) expression.getFixture().accept( this ); + final MappingModelExpressable fixtureType = (MappingModelExpressable) fixture.getExpressionType(); + inferrableTypeAccessStack.pop(); + MappingModelExpressable resolved = determineCurrentExpressable( expression ); Expression otherwise = null; - try { - for ( SqmCaseSimple.WhenFragment whenFragment : expression.getWhenFragments() ) { - final Expression resultExpression = (Expression) whenFragment.getResult().accept( this ); - resolved = (MappingModelExpressable) TypeHelper.highestPrecedence( resolved, resultExpression.getExpressionType() ); - - whenFragments.add( - new CaseSimpleExpression.WhenFragment( - (Expression) whenFragment.getCheckValue().accept( this ), - resultExpression - ) - ); - } - - if ( expression.getOtherwise() != null ) { - otherwise = (Expression) expression.getOtherwise().accept( this ); - resolved = (MappingModelExpressable) TypeHelper.highestPrecedence( resolved, otherwise.getExpressionType() ); - } - } - finally { + for ( SqmCaseSimple.WhenFragment whenFragment : expression.getWhenFragments() ) { + inferrableTypeAccessStack.push( () -> fixtureType ); + final Expression checkValue = (Expression) whenFragment.getCheckValue().accept( this ); inferrableTypeAccessStack.pop(); + final MappingModelExpressable alreadyKnown = resolved; + inferrableTypeAccessStack.push( + () -> alreadyKnown == null && inferenceSupplier != null ? inferenceSupplier.get() : alreadyKnown + ); + final Expression resultExpression = (Expression) whenFragment.getResult().accept( this ); + inferrableTypeAccessStack.pop(); + resolved = (MappingModelExpressable) TypeHelper.highestPrecedence( resolved, resultExpression.getExpressionType() ); + + whenFragments.add( + new CaseSimpleExpression.WhenFragment( + checkValue, + resultExpression + ) + ); + } + + if ( expression.getOtherwise() != null ) { + final MappingModelExpressable alreadyKnown = resolved; + inferrableTypeAccessStack.push( + () -> alreadyKnown == null && inferenceSupplier != null ? inferenceSupplier.get() : alreadyKnown + ); + otherwise = (Expression) expression.getOtherwise().accept( this ); + inferrableTypeAccessStack.pop(); + resolved = (MappingModelExpressable) TypeHelper.highestPrecedence( resolved, otherwise.getExpressionType() ); } return new CaseSimpleExpression( resolved, - (Expression) expression.getFixture().accept( this ), + fixture, whenFragments, otherwise ); } + @Override + public CaseSearchedExpression visitSearchedCaseExpression(SqmCaseSearched expression) { + final List whenFragments = new ArrayList<>( expression.getWhenFragments().size() ); + final Supplier inferenceSupplier = inferrableTypeAccessStack.getCurrent(); + MappingModelExpressable resolved = determineCurrentExpressable( expression ); + + Expression otherwise = null; + for ( SqmCaseSearched.WhenFragment whenFragment : expression.getWhenFragments() ) { + inferrableTypeAccessStack.push( () -> null ); + final Predicate whenPredicate = (Predicate) whenFragment.getPredicate().accept( this ); + inferrableTypeAccessStack.pop(); + final MappingModelExpressable alreadyKnown = resolved; + inferrableTypeAccessStack.push( + () -> alreadyKnown == null && inferenceSupplier != null ? inferenceSupplier.get() : alreadyKnown + ); + final Expression resultExpression = (Expression) whenFragment.getResult().accept( this ); + inferrableTypeAccessStack.pop(); + resolved = (MappingModelExpressable) TypeHelper.highestPrecedence( resolved, resultExpression.getExpressionType() ); + + whenFragments.add( new CaseSearchedExpression.WhenFragment( whenPredicate, resultExpression ) ); + } + + if ( expression.getOtherwise() != null ) { + final MappingModelExpressable alreadyKnown = resolved; + inferrableTypeAccessStack.push( + () -> alreadyKnown == null && inferenceSupplier != null ? inferenceSupplier.get() : alreadyKnown + ); + otherwise = (Expression) expression.getOtherwise().accept( this ); + inferrableTypeAccessStack.pop(); + resolved = (MappingModelExpressable) TypeHelper.highestPrecedence( resolved, otherwise.getExpressionType() ); + } + + return new CaseSearchedExpression( resolved, whenFragments, otherwise ); + } + private MappingModelExpressable determineCurrentExpressable(SqmTypedNode expression) { try { return creationContext @@ -3863,37 +4269,6 @@ public abstract class BaseSqmToSqlAstConverter extends Base } } - @Override - public CaseSearchedExpression visitSearchedCaseExpression(SqmCaseSearched expression) { - final List whenFragments = new ArrayList<>( expression.getWhenFragments().size() ); - - final MappingModelExpressable alreadyKnown = determineCurrentExpressable( expression ); - MappingModelExpressable resolved = alreadyKnown; - - inferrableTypeAccessStack.push( () -> alreadyKnown ); - - Expression otherwise = null; - try { - for ( SqmCaseSearched.WhenFragment whenFragment : expression.getWhenFragments() ) { - final Predicate whenPredicate = (Predicate) whenFragment.getPredicate().accept( this ); - final Expression resultExpression = (Expression) whenFragment.getResult().accept( this ); - resolved = (MappingModelExpressable) TypeHelper.highestPrecedence( resolved, resultExpression.getExpressionType() ); - - whenFragments.add( new CaseSearchedExpression.WhenFragment( whenPredicate, resultExpression ) ); - } - - if ( expression.getOtherwise() != null ) { - otherwise = (Expression) expression.getOtherwise().accept( this ); - resolved = (MappingModelExpressable) TypeHelper.highestPrecedence( resolved, otherwise.getExpressionType() ); - } - } - finally { - inferrableTypeAccessStack.pop(); - } - - return new CaseSearchedExpression( resolved, whenFragments, otherwise ); - } - private X visitWithInferredType(SqmExpression expression, SqmExpression inferred) { inferrableTypeAccessStack.push( () -> determineValueMapping( inferred ) ); try { @@ -3984,7 +4359,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Expression visitEntityTypeLiteralExpression(SqmLiteralEntityType sqmExpression) { + public Expression visitEntityTypeLiteralExpression(SqmLiteralEntityType sqmExpression) { final EntityDomainType nodeType = sqmExpression.getNodeType(); final EntityPersister mappingDescriptor = getCreationContext().getDomainModel() .getEntityDescriptor( nodeType.getHibernateEntityName() ); @@ -3999,7 +4374,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral) { + public Object visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral) { final BasicValuedMapping inferrableType = (BasicValuedMapping) inferrableTypeAccessStack.getCurrent().get(); if ( inferrableType instanceof ConvertibleModelPart ) { final ConvertibleModelPart inferredPart = (ConvertibleModelPart) inferrableType; @@ -4015,7 +4390,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral) { + public Object visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral) { return new QueryLiteral<>( sqmFieldLiteral.getValue(), (BasicValuedMapping) determineValueMapping( sqmFieldLiteral ) @@ -4112,7 +4487,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path) { + public Object visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path) { // SemanticQueryBuilder applies the index expression to the generated join return path.getLhs().accept( this ); } @@ -4253,7 +4628,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base @Override public Junction visitAndPredicate(SqmAndPredicate predicate) { - final Junction conjunction = new Junction( Junction.Nature.CONJUNCTION ); + final Junction conjunction = new Junction( Junction.Nature.CONJUNCTION, getBooleanType() ); conjunction.add( (Predicate) predicate.getLeftHandPredicate().accept( this ) ); conjunction.add( (Predicate) predicate.getRightHandPredicate().accept( this ) ); return conjunction; @@ -4261,7 +4636,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base @Override public Junction visitOrPredicate(SqmOrPredicate predicate) { - final Junction disjunction = new Junction( Junction.Nature.DISJUNCTION ); + final Junction disjunction = new Junction( Junction.Nature.DISJUNCTION, getBooleanType() ); disjunction.add( (Predicate) predicate.getLeftHandPredicate().accept( this ) ); disjunction.add( (Predicate) predicate.getRightHandPredicate().accept( this ) ); return disjunction; @@ -4352,7 +4727,8 @@ public abstract class BaseSqmToSqlAstConverter extends Base return new InSubQueryPredicate( lhs, subQuerySpec, - predicate.isNegated() + predicate.isNegated(), + getBooleanType() ); } @@ -4385,7 +4761,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base inferrableTypeAccessStack.pop(); } - return new ComparisonPredicate( lhs, predicate.getSqmOperator(), rhs ); + return new ComparisonPredicate( lhs, predicate.getSqmOperator(), rhs, getBooleanType() ); } @Override @@ -4421,8 +4797,9 @@ public abstract class BaseSqmToSqlAstConverter extends Base tableGroup ); - final SqmPathInterpretation sqmPathInterpretation = visitPluralValuedPath( sqmPluralPath ); - final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) sqmPathInterpretation.getExpressionType(); + final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) visitPluralValuedPath( + sqmPluralPath + ).getExpressionType(); // The creation of the table group join against the correlated table group // has the side effect that the from and where clause of the sub-query are set pluralAttributeMapping.createTableGroupJoin( @@ -4445,7 +4822,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base new SqlSelectionImpl( 1, 0, jdbcLiteral ) ); - final ExistsPredicate existsPredicate = new ExistsPredicate( subQuerySpec ); + final ExistsPredicate existsPredicate = new ExistsPredicate( subQuerySpec, getBooleanType() ); if ( predicate.isNegated() ) { return existsPredicate; } @@ -4506,7 +4883,8 @@ public abstract class BaseSqmToSqlAstConverter extends Base expression, lowerBound, upperBound, - predicate.isNegated() + predicate.isNegated(), + getBooleanType() ); } @@ -4521,7 +4899,8 @@ public abstract class BaseSqmToSqlAstConverter extends Base (Expression) predicate.getPattern().accept( this ), escapeExpression, predicate.isNegated(), - predicate.isCaseSensitive() + predicate.isCaseSensitive(), + getBooleanType() ); } @@ -4529,7 +4908,8 @@ public abstract class BaseSqmToSqlAstConverter extends Base public NullnessPredicate visitIsNullPredicate(SqmNullnessPredicate predicate) { return new NullnessPredicate( (Expression) predicate.getExpression().accept( this ), - predicate.isNegated() + predicate.isNegated(), + getBooleanType() ); } @@ -4556,7 +4936,8 @@ public abstract class BaseSqmToSqlAstConverter extends Base final InListPredicate inPredicate = new InListPredicate( (Expression) predicate.getTestExpression().accept( this ), - predicate.isNegated() + predicate.isNegated(), + getBooleanType() ); inferrableTypeAccessStack.push( () -> determineValueMapping( predicate.getTestExpression() ) ); @@ -4595,7 +4976,9 @@ public abstract class BaseSqmToSqlAstConverter extends Base } final InListPredicate inListPredicate = new InListPredicate( - (Expression) sqmPredicate.getTestExpression().accept( this ) + (Expression) sqmPredicate.getTestExpression().accept( this ), + sqmPredicate.isNegated(), + getBooleanType() ); inferrableTypeAccessStack.push( @@ -4637,7 +5020,9 @@ public abstract class BaseSqmToSqlAstConverter extends Base } final InListPredicate inListPredicate = new InListPredicate( - (Expression) sqmPredicate.getTestExpression().accept( this ) + (Expression) sqmPredicate.getTestExpression().accept( this ), + sqmPredicate.isNegated(), + getBooleanType() ); inferrableTypeAccessStack.push( @@ -4676,13 +5061,18 @@ public abstract class BaseSqmToSqlAstConverter extends Base return new InSubQueryPredicate( visitWithInferredType( predicate.getTestExpression(), predicate.getSubQueryExpression() ), visitWithInferredType( predicate.getSubQueryExpression(), predicate.getTestExpression() ), - predicate.isNegated() + predicate.isNegated(), + getBooleanType() ); } + private JdbcMappingContainer getBooleanType() { + return getTypeConfiguration().getBasicTypeForJavaType( Boolean.class ); + } + @Override public Object visitBooleanExpressionPredicate(SqmBooleanExpressionPredicate predicate) { - final Object booleanExpression = predicate.getBooleanExpression().accept( this ); + final Expression booleanExpression = (Expression) predicate.getBooleanExpression().accept( this ); if ( booleanExpression instanceof SelfRenderingExpression ) { final Predicate sqlPredicate = new SelfRenderingPredicate( (SelfRenderingExpression) booleanExpression ); if ( predicate.isNegated() ) { @@ -4691,17 +5081,17 @@ public abstract class BaseSqmToSqlAstConverter extends Base return sqlPredicate; } else { - return new ComparisonPredicate( - (Expression) booleanExpression, - predicate.isNegated() ? ComparisonOperator.NOT_EQUAL : ComparisonOperator.EQUAL, - new QueryLiteral<>( true, basicType( Boolean.class ) ) + return new BooleanExpressionPredicate( + booleanExpression, + predicate.isNegated(), + getBooleanType() ); } } @Override public Object visitExistsPredicate(SqmExistsPredicate predicate) { - return new ExistsPredicate( (QueryPart) predicate.getExpression().accept( this ) ); + return new ExistsPredicate( (QueryPart) predicate.getExpression().accept( this ), getBooleanType() ); } @Override @@ -4710,7 +5100,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public Object visitFullyQualifiedClass(Class namedClass) { + public Object visitFullyQualifiedClass(Class namedClass) { throw new NotYetImplementedFor6Exception(); // what exactly is the expected end result here? @@ -5041,9 +5431,23 @@ public abstract class BaseSqmToSqlAstConverter extends Base private final List[] sqlSelectionsForSqmSelection; private int index = -1; - public SqmAliasedNodePositionTracker(SqlExpressionResolver delegate, int sqmSelectionCount) { + public SqmAliasedNodePositionTracker(SqlExpressionResolver delegate, List> selections) { this.delegate = delegate; - sqlSelectionsForSqmSelection = new List[sqmSelectionCount]; + this.sqlSelectionsForSqmSelection = new List[countIndividualSelections( selections )]; + } + + private static int countIndividualSelections(List> selections) { + int offset = 0; + for ( int i = 0; i < selections.size(); i++ ) { + final SqmSelectableNode selectableNode = selections.get( i ).getSelectableNode(); + if ( selectableNode instanceof SqmDynamicInstantiation ) { + offset = countIndividualSelections( ( (SqmDynamicInstantiation) selectableNode ).getArguments() ) - 1; + } + else if ( selectableNode instanceof SqmJpaCompoundSelection ) { + offset += ( (SqmJpaCompoundSelection) selectableNode ).getSelectionItems().size() - 1; + } + } + return offset + selections.size(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java index 3c1ddaffaf..217c0dd65b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java @@ -52,7 +52,7 @@ public class EntityValuedPathInterpretation extends AbstractSqmPathInterpreta SqmEntityValuedSimplePath sqmPath, SqmToSqlAstConverter sqlAstCreationState) { final SqmPath realPath; - if ( CollectionPart.Nature.ELEMENT.getName().equals( sqmPath.getNavigablePath().getUnaliasedLocalName() ) ) { + if ( CollectionPart.Nature.fromNameExact( sqmPath.getNavigablePath().getUnaliasedLocalName() ) != null ) { realPath = sqmPath.getLhs(); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/PluralValuedSimplePathInterpretation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/PluralValuedSimplePathInterpretation.java index fbf42ad70c..59524e6992 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/PluralValuedSimplePathInterpretation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/PluralValuedSimplePathInterpretation.java @@ -14,6 +14,8 @@ import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.from.TableGroup; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultCreationState; /** * @author Andrea Boriero @@ -53,6 +55,18 @@ public class PluralValuedSimplePathInterpretation extends AbstractSqmPathInte return sqlExpression; } + @Override + public DomainResult createDomainResult(String resultVariable, DomainResultCreationState creationState) { + // This is only invoked when a plural attribute is a top level select, order by or group by item + // in which case we have to produce results for the element + return ( (PluralAttributeMapping) getExpressionType() ).getElementDescriptor().createDomainResult( + getNavigablePath(), + getTableGroup(), + resultVariable, + creationState + ); + } + @Override public void accept(SqlAstWalker sqlTreeWalker) { throw new NotYetImplementedFor6Exception( getClass() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/SqlAstProcessingStateImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/SqlAstProcessingStateImpl.java index ab23afe8d2..cc3ab1faec 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/SqlAstProcessingStateImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/SqlAstProcessingStateImpl.java @@ -13,7 +13,6 @@ import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; -import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter; import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.SqmAliasedNodeCollector; import org.hibernate.query.sqm.sql.ConversionException; import org.hibernate.sql.ast.Clause; @@ -39,7 +38,7 @@ public class SqlAstProcessingStateImpl private final SqlExpressionResolver expressionResolver; private final Supplier currentClauseAccess; - private final Map expressionMap = new HashMap<>(); + private final Map expressionMap = new HashMap<>(); public SqlAstProcessingStateImpl( SqlAstProcessingState parentState, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmNode.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmNode.java index 54cbf2e02c..4118364e1d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmNode.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmNode.java @@ -6,6 +6,8 @@ */ package org.hibernate.query.sqm.tree; +import java.io.Serializable; + import org.hibernate.query.sqm.NodeBuilder; /** @@ -13,7 +15,7 @@ import org.hibernate.query.sqm.NodeBuilder; * * @author Steve Ebersole */ -public abstract class AbstractSqmNode implements SqmNode { +public abstract class AbstractSqmNode implements SqmNode, Serializable { private final NodeBuilder builder; protected AbstractSqmNode(NodeBuilder builder) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmRestrictedDmlStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmRestrictedDmlStatement.java new file mode 100644 index 0000000000..ca4566060a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmRestrictedDmlStatement.java @@ -0,0 +1,101 @@ +/* + * 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; + +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import javax.persistence.metamodel.EntityType; + +import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.query.criteria.JpaCriteriaBase; +import org.hibernate.query.criteria.JpaPredicate; +import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.SqmQuerySource; +import org.hibernate.query.sqm.tree.from.SqmRoot; +import org.hibernate.query.sqm.tree.predicate.SqmPredicate; +import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; + +/** + * @author Christian Beikov + */ +public abstract class AbstractSqmRestrictedDmlStatement extends AbstractSqmDmlStatement + implements JpaCriteriaBase { + + private SqmWhereClause whereClause; + + public AbstractSqmRestrictedDmlStatement(SqmQuerySource querySource, NodeBuilder nodeBuilder) { + super( querySource, nodeBuilder ); + } + + public AbstractSqmRestrictedDmlStatement(SqmRoot target, SqmQuerySource querySource, NodeBuilder nodeBuilder) { + super( target, querySource, nodeBuilder ); + } + + public Root from(Class entityClass) { + final EntityDomainType entity = nodeBuilder().getDomainModel().entity( entityClass ); + SqmRoot root = new SqmRoot<>( entity, null, false, nodeBuilder() ); + setTarget( root ); + return root; + } + + public Root from(EntityType entity) { + SqmRoot root = new SqmRoot<>( (EntityDomainType) entity, null, false, nodeBuilder() ); + setTarget( root ); + return root; + } + + public Root getRoot() { + return getTarget(); + } + + public SqmWhereClause getWhereClause() { + return whereClause; + } + + public void applyPredicate(SqmPredicate predicate) { + if ( predicate == null ) { + return; + } + + if ( whereClause == null ) { + whereClause = new SqmWhereClause( nodeBuilder() ); + } + + whereClause.applyPredicate( predicate ); + } + + public void setWhereClause(SqmWhereClause whereClause) { + this.whereClause = whereClause; + } + + @Override + public JpaPredicate getRestriction() { + return whereClause == null ? null : whereClause.getPredicate(); + } + + protected void setWhere(Expression restriction) { + applyPredicate( null ); + applyPredicate( (SqmPredicate) restriction ); + } + + protected void setWhere(Predicate... restrictions) { + applyPredicate( null ); + final SqmWhereClause whereClause = getWhereClause(); + for ( Predicate restriction : restrictions ) { + whereClause.applyPredicate( (SqmPredicate) restriction ); + } + } + + @Override + public void appendHqlString(StringBuilder sb) { + if ( whereClause != null && whereClause.getPredicate() != null ) { + sb.append( " where " ); + whereClause.getPredicate().appendHqlString( sb ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java index f27316f573..e50dd95b0e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/AbstractSqmStatement.java @@ -8,14 +8,11 @@ package org.hibernate.query.sqm.tree; import java.util.Collections; import java.util.HashSet; -import java.util.Map; import java.util.Set; -import java.util.function.Supplier; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmQuerySource; -import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter; -import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper; +import org.hibernate.query.sqm.internal.SqmUtil; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.internal.ParameterCollector; @@ -40,7 +37,7 @@ public abstract class AbstractSqmStatement extends AbstractSqmNode implements } @Override - public void addParameter(SqmParameter parameter) { + public void addParameter(SqmParameter parameter) { if ( parameters == null ) { parameters = new HashSet<>(); } @@ -50,21 +47,21 @@ public abstract class AbstractSqmStatement extends AbstractSqmNode implements @Override public Set> getSqmParameters() { + if ( querySource == SqmQuerySource.CRITERIA ) { + assert parameters == null : "SqmSelectStatement (as Criteria) should not have collected parameters"; + + return org.hibernate.query.sqm.tree.jpa.ParameterCollector.collectParameters( + this, + sqmParameter -> {}, + nodeBuilder().getServiceRegistry() + ); + } + return parameters == null ? Collections.emptySet() : Collections.unmodifiableSet( parameters ); } @Override public ParameterResolutions resolveParameters() { - return new ParameterResolutions() { - @Override - public Set> getSqmParameters() { - return AbstractSqmStatement.this.getSqmParameters(); - } - - @Override - public Map, Supplier>> getJpaCriteriaParamResolutions() { - return Collections.emptyMap(); - } - }; + return SqmUtil.resolveParameters( this ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmExpressableAccessor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmExpressableAccessor.java new file mode 100644 index 0000000000..3cd382ecfe --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmExpressableAccessor.java @@ -0,0 +1,27 @@ +/* + * 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; + +import org.hibernate.query.sqm.SqmExpressable; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; + +/** + * Accessor for {@link SqmExpressable}. + * + * @author Christian Beikov + */ +public interface SqmExpressableAccessor { + /** + * The Java type descriptor for this node. + */ + default JavaTypeDescriptor getNodeJavaTypeDescriptor() { + final SqmExpressable nodeType = getExpressable(); + return nodeType != null ? nodeType.getExpressableJavaTypeDescriptor() : null; + } + + SqmExpressable getExpressable(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmTypedNode.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmTypedNode.java index 1cc12ae66c..e3a598e2a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmTypedNode.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/SqmTypedNode.java @@ -15,7 +15,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; * * @author Steve Ebersole */ -public interface SqmTypedNode extends SqmNode { +public interface SqmTypedNode extends SqmNode, SqmExpressableAccessor { /** * The Java type descriptor for this node. */ @@ -24,5 +24,10 @@ public interface SqmTypedNode extends SqmNode { return nodeType != null ? nodeType.getExpressableJavaTypeDescriptor() : null; } + @Override + default SqmExpressable getExpressable() { + return getNodeType(); + } + SqmExpressable getNodeType(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTable.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTable.java index 60e76cc395..89a8c5c5fe 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTable.java @@ -6,6 +6,7 @@ */ package org.hibernate.query.sqm.tree.cte; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -20,7 +21,7 @@ import org.hibernate.sql.ast.tree.cte.CteColumn; * @author Steve Ebersole * @author Christian Beikov */ -public class SqmCteTable { +public class SqmCteTable implements Serializable { private final String cteName; private final List columns; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTableColumn.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTableColumn.java index a3a27cc686..598a7d6457 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTableColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteTableColumn.java @@ -6,13 +6,15 @@ */ package org.hibernate.query.sqm.tree.cte; +import java.io.Serializable; + import org.hibernate.metamodel.mapping.ModelPart; /** * @author Steve Ebersole * @author Christian Beikov */ -public class SqmCteTableColumn { +public class SqmCteTableColumn implements Serializable { private final SqmCteTable cteTable; private final String columnName; private final ModelPart typeExpressable; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmSearchClauseSpecification.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmSearchClauseSpecification.java index f3870a1c25..73fc28f641 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmSearchClauseSpecification.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmSearchClauseSpecification.java @@ -6,13 +6,15 @@ */ package org.hibernate.query.sqm.tree.cte; +import java.io.Serializable; + import org.hibernate.query.NullPrecedence; import org.hibernate.query.SortOrder; /** * @author Christian Beikov */ -public class SqmSearchClauseSpecification { +public class SqmSearchClauseSpecification implements Serializable { private final SqmCteTableColumn cteColumn; private final SortOrder sortOrder; private final NullPrecedence nullPrecedence; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/delete/SqmDeleteStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/delete/SqmDeleteStatement.java index 2579029615..d19d77c741 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/delete/SqmDeleteStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/delete/SqmDeleteStatement.java @@ -8,34 +8,24 @@ package org.hibernate.query.sqm.tree.delete; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import javax.persistence.metamodel.EntityType; -import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.criteria.JpaCriteriaDelete; -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.AbstractSqmDmlStatement; +import org.hibernate.query.sqm.tree.AbstractSqmRestrictedDmlStatement; import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement; import org.hibernate.query.sqm.tree.from.SqmRoot; -import org.hibernate.query.sqm.tree.predicate.SqmPredicate; -import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; /** * @author Steve Ebersole */ public class SqmDeleteStatement - extends AbstractSqmDmlStatement + extends AbstractSqmRestrictedDmlStatement implements SqmDeleteOrUpdateStatement, JpaCriteriaDelete { - private final SqmQuerySource querySource; - - private SqmWhereClause whereClause; public SqmDeleteStatement(SqmRoot target, SqmQuerySource querySource, NodeBuilder nodeBuilder) { super( target, querySource, nodeBuilder ); - this.querySource = SqmQuerySource.HQL; } public SqmDeleteStatement(Class targetEntity, SqmQuerySource querySource, NodeBuilder nodeBuilder) { @@ -43,80 +33,26 @@ public class SqmDeleteStatement new SqmRoot<>( nodeBuilder.getDomainModel().entity( targetEntity ), null, + false, nodeBuilder ), querySource, nodeBuilder ); - this.querySource = SqmQuerySource.CRITERIA; - } - - @Override - public SqmQuerySource getQuerySource() { - return querySource; - } - - @Override - public SqmWhereClause getWhereClause() { - return whereClause; - } - - @Override - public void applyPredicate(SqmPredicate predicate) { - if ( predicate == null ) { - return; - } - if ( whereClause == null ) { - whereClause = new SqmWhereClause( nodeBuilder() ); - } - - whereClause.applyPredicate( predicate ); - } - - public void setWhereClause(SqmWhereClause whereClause) { - this.whereClause = whereClause; - } - - @Override - public Root from(Class entityClass) { - final EntityDomainType entity = nodeBuilder().getDomainModel().entity( entityClass ); - SqmRoot root = new SqmRoot<>( entity, null, nodeBuilder() ); - setTarget( root ); - return root; - } - - @Override - public Root from(EntityType entity) { - SqmRoot root = new SqmRoot<>( (EntityDomainType) entity, null, nodeBuilder() ); - setTarget( root ); - return root; - } - - @Override - public Root getRoot() { - return getTarget(); } @Override public SqmDeleteStatement where(Expression restriction) { - getWhereClause().setPredicate( (SqmPredicate) restriction ); + setWhere( restriction ); return this; } @Override public SqmDeleteStatement where(Predicate... restrictions) { - getWhereClause().setPredicate( null ); - for ( Predicate restriction : restrictions ) { - getWhereClause().applyPredicate( (SqmPredicate) restriction ); - } + setWhere( restrictions ); return this; } - @Override - public JpaPredicate getRestriction() { - return whereClause == null ? null : whereClause.getPredicate(); - } - @Override public X accept(SemanticQueryWalker walker) { return walker.visitDeleteStatement( this ); @@ -126,12 +62,7 @@ public class SqmDeleteStatement 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 ); - } + sb.append( ' ' ).append( getTarget().resolveAlias() ); + super.appendHqlString( sb ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java index 24513c8935..d330430de0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmAttributeJoin.java @@ -21,7 +21,6 @@ import org.hibernate.query.sqm.spi.SqmCreationHelper; import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; import org.hibernate.query.sqm.tree.from.SqmFrom; -import org.hibernate.query.sqm.tree.from.SqmJoin; import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -62,9 +61,9 @@ public abstract class AbstractSqmAttributeJoin } @Override - public SqmFrom getLhs() { + public SqmFrom getLhs() { //noinspection unchecked - return (SqmFrom) super.getLhs(); + return (SqmFrom) super.getLhs(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java index 3c803962a8..7550f3d185 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmFrom.java @@ -59,7 +59,7 @@ public abstract class AbstractSqmFrom extends AbstractSqmPath implements protected AbstractSqmFrom( NavigablePath navigablePath, SqmPathSource referencedNavigable, - SqmFrom lhs, + SqmFrom lhs, String alias, NodeBuilder nodeBuilder) { super( navigablePath, referencedNavigable, lhs, nodeBuilder ); @@ -121,7 +121,7 @@ public abstract class AbstractSqmFrom extends AbstractSqmPath implements } @Override - public SemanticPathPart resolvePathPart( + public SqmPath resolvePathPart( String name, boolean isTerminal, SqmCreationState creationState) { @@ -170,7 +170,7 @@ public abstract class AbstractSqmFrom extends AbstractSqmPath implements @Override - public JpaPath getParentPath() { + public JpaPath getParentPath() { return getLhs(); } @@ -187,10 +187,10 @@ public abstract class AbstractSqmFrom extends AbstractSqmPath implements } @Override - @SuppressWarnings("unchecked") public Set> getJoins() { - return (Set) getSqmJoins().stream() - .filter( sqmJoin -> ! ( sqmJoin instanceof SqmAttributeJoin && ( (SqmAttributeJoin) sqmJoin ).isFetched() ) ) + //noinspection unchecked + return (Set>) (Set) getSqmJoins().stream() + .filter( sqmJoin -> ! ( sqmJoin instanceof SqmAttributeJoin && ( (SqmAttributeJoin) sqmJoin ).isFetched() ) ) .collect( Collectors.toSet() ); } @@ -408,10 +408,10 @@ public abstract class AbstractSqmFrom extends AbstractSqmPath implements } @Override - @SuppressWarnings("unchecked") public Set> getFetches() { - return (Set) getSqmJoins().stream() - .filter( sqmJoin -> sqmJoin instanceof SqmAttributeJoin && ( (SqmAttributeJoin) sqmJoin ).isFetched() ) + //noinspection unchecked + return (Set>) (Set) getSqmJoins().stream() + .filter( sqmJoin -> sqmJoin instanceof SqmAttributeJoin && ( (SqmAttributeJoin) sqmJoin ).isFetched() ) .collect( Collectors.toSet() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmJoin.java index 2ab4a3c8ca..ed2e2a67c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmJoin.java @@ -22,7 +22,7 @@ public abstract class AbstractSqmJoin extends AbstractSqmFrom implemen public AbstractSqmJoin( NavigablePath navigablePath, SqmPathSource referencedNavigable, - SqmFrom lhs, + SqmFrom lhs, String alias, SqmJoinType joinType, NodeBuilder nodeBuilder) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java index 96c6883195..93286e2537 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPath.java @@ -23,7 +23,6 @@ import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression; -import org.hibernate.type.BasicType; /** * @author Steve Ebersole @@ -152,10 +151,6 @@ public abstract class AbstractSqmPath extends AbstractSqmExpression implem // 1) add `Navigable#createCriteriaExpression` (ala, the exist `#createSqmExpression`) // 2) remove `Navigable#createSqmExpression` and use the approach used here instead. - if ( getReferencedPathSource().getSqmPathType() instanceof BasicType ) { - throw new IllegalStateException( "Cannot resolve path `" + attributeName + "` relative to a basic-valued path: `" + getNavigablePath() + "`" ); - } - final SqmPathSource subNavigable = getReferencedPathSource().findSubPathSource( attributeName ); if ( subNavigable == null ) { @@ -164,19 +159,21 @@ public abstract class AbstractSqmPath extends AbstractSqmExpression implem return resolvePath( attributeName, subNavigable ); } - private SqmPath resolvePath(PersistentAttribute attribute) { - return resolvePath( attribute.getName(), (SqmPathSource) attribute ); + protected SqmPath resolvePath(PersistentAttribute attribute) { + //noinspection unchecked + return resolvePath( attribute.getName(), (SqmPathSource) attribute ); } - private SqmPath resolvePath(String attributeName, SqmPathSource pathSource) { + protected SqmPath resolvePath(String attributeName, SqmPathSource pathSource) { if ( reusablePaths == null ) { reusablePaths = new HashMap<>(); - final SqmPath path = pathSource.createSqmPath( this ); + final SqmPath path = pathSource.createSqmPath( this ); reusablePaths.put( attributeName, path ); return path; } else { - return reusablePaths.computeIfAbsent( + //noinspection unchecked + return (SqmPath) reusablePaths.computeIfAbsent( attributeName, name -> pathSource.createSqmPath( this ) ); @@ -192,13 +189,13 @@ public abstract class AbstractSqmPath extends AbstractSqmExpression implem @Override @SuppressWarnings("unchecked") public > SqmPath get(PluralAttribute attribute) { - return (SqmPath) resolvePath( (PersistentAttribute) attribute ); + return resolvePath( (PersistentAttribute) attribute ); } @Override @SuppressWarnings("unchecked") public > SqmPath get(MapAttribute map) { - return (SqmPath) resolvePath( (PersistentAttribute) map ); + return resolvePath( (PersistentAttribute) map ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPluralJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPluralJoin.java index 75a73aeace..0e56083ccd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPluralJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmPluralJoin.java @@ -27,7 +27,6 @@ public abstract class AbstractSqmPluralJoin extends AbstractSqmAttributeJ SqmJoinType joinType, boolean fetched, NodeBuilder nodeBuilder) { - //noinspection unchecked super( lhs, joinedNavigable, @@ -39,12 +38,12 @@ public abstract class AbstractSqmPluralJoin extends AbstractSqmAttributeJ } @Override - public PluralPersistentAttribute getReferencedPathSource() { + public PluralPersistentAttribute getReferencedPathSource() { return (PluralPersistentAttribute) super.getReferencedPathSource(); } @Override - public PluralPersistentAttribute getModel() { + public PluralPersistentAttribute getModel() { return getReferencedPathSource(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSimplePath.java index de680e515d..7981da0d40 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSimplePath.java @@ -19,7 +19,7 @@ public abstract class AbstractSqmSimplePath extends AbstractSqmPath implem public AbstractSqmSimplePath( NavigablePath navigablePath, SqmPathSource referencedPathSource, - SqmPath lhs, + SqmPath lhs, NodeBuilder nodeBuilder) { this( navigablePath, referencedPathSource, lhs, null, nodeBuilder ); } @@ -28,7 +28,7 @@ public abstract class AbstractSqmSimplePath extends AbstractSqmPath implem public AbstractSqmSimplePath( NavigablePath navigablePath, SqmPathSource referencedPathSource, - SqmPath lhs, + SqmPath lhs, String explicitAlias, NodeBuilder nodeBuilder) { super( navigablePath, referencedPathSource, lhs, nodeBuilder ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSpecificPluralPartPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSpecificPluralPartPath.java index f30ad4b8a7..aecf2bd837 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSpecificPluralPartPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/AbstractSqmSpecificPluralPartPath.java @@ -16,8 +16,8 @@ import org.hibernate.query.PathException; * @author Steve Ebersole */ public abstract class AbstractSqmSpecificPluralPartPath extends AbstractSqmPath implements SqmPath { - private final SqmPath pluralDomainPath; - private final PluralPersistentAttribute pluralAttribute; + private final SqmPath pluralDomainPath; + private final PluralPersistentAttribute pluralAttribute; private String alias; @@ -25,7 +25,7 @@ public abstract class AbstractSqmSpecificPluralPartPath extends AbstractSqmPa public AbstractSqmSpecificPluralPartPath( NavigablePath navigablePath, SqmPath pluralDomainPath, - PluralPersistentAttribute referencedAttribute) { + PluralPersistentAttribute referencedAttribute) { super( navigablePath, referencedAttribute, @@ -37,17 +37,17 @@ public abstract class AbstractSqmSpecificPluralPartPath extends AbstractSqmPa } @SuppressWarnings("WeakerAccess") - public SqmPath getPluralDomainPath() { + public SqmPath getPluralDomainPath() { return pluralDomainPath; } @SuppressWarnings("WeakerAccess") - public PluralPersistentAttribute getPluralAttribute() { + public PluralPersistentAttribute getPluralAttribute() { return pluralAttribute; } @Override - public SqmPath getLhs() { + public SqmPath getLhs() { return pluralDomainPath; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/NonAggregatedCompositeSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/NonAggregatedCompositeSimplePath.java index 94033717fa..dd7fef2a1d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/NonAggregatedCompositeSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/NonAggregatedCompositeSimplePath.java @@ -26,7 +26,7 @@ public class NonAggregatedCompositeSimplePath extends SqmEntityValuedSimplePa public NonAggregatedCompositeSimplePath( NavigablePath navigablePath, SqmPathSource referencedPathSource, - SqmPath lhs, + SqmPath lhs, NodeBuilder nodeBuilder) { super( navigablePath, referencedPathSource, lhs, nodeBuilder ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBagJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBagJoin.java index 5cb6dec29f..ff8a2f10e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBagJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBagJoin.java @@ -42,11 +42,6 @@ public class SqmBagJoin extends AbstractSqmPluralJoin, E> return (BagPersistentAttribute) super.getReferencedPathSource(); } - @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - return getModel().getExpressableJavaTypeDescriptor(); - } - @Override public BagPersistentAttribute getModel() { return getReferencedPathSource(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBasicValuedEntityTypePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBasicValuedEntityTypePath.java index 74f571c4c1..d6de842681 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBasicValuedEntityTypePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBasicValuedEntityTypePath.java @@ -25,7 +25,7 @@ public class SqmBasicValuedEntityTypePath extends SqmBasicValuedSimplePath public SqmBasicValuedEntityTypePath( NavigablePath navigablePath, EntityDomainType referencedPathSource, - SqmPath lhs, + SqmPath lhs, NodeBuilder nodeBuilder) { this( navigablePath, referencedPathSource, lhs, null, nodeBuilder ); } @@ -33,7 +33,7 @@ public class SqmBasicValuedEntityTypePath extends SqmBasicValuedSimplePath public SqmBasicValuedEntityTypePath( NavigablePath navigablePath, EntityDomainType referencedPathSource, - SqmPath lhs, + SqmPath lhs, String explicitAlias, NodeBuilder nodeBuilder) { super( navigablePath, referencedPathSource, lhs, explicitAlias, nodeBuilder ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBasicValuedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBasicValuedSimplePath.java index efa6745a08..2400512089 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBasicValuedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmBasicValuedSimplePath.java @@ -28,7 +28,7 @@ public class SqmBasicValuedSimplePath public SqmBasicValuedSimplePath( NavigablePath navigablePath, SqmPathSource referencedPathSource, - SqmPath lhs, + SqmPath lhs, NodeBuilder nodeBuilder) { this( navigablePath, referencedPathSource, lhs, null, nodeBuilder ); } @@ -36,7 +36,7 @@ public class SqmBasicValuedSimplePath public SqmBasicValuedSimplePath( NavigablePath navigablePath, SqmPathSource referencedPathSource, - SqmPath lhs, + SqmPath lhs, String explicitAlias, NodeBuilder nodeBuilder) { super( navigablePath, referencedPathSource, lhs, explicitAlias, nodeBuilder ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedBagJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedBagJoin.java index 2b6bae0e20..35c8126473 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedBagJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedBagJoin.java @@ -72,7 +72,6 @@ public class SqmCorrelatedBagJoin extends SqmBagJoin implements SqmC @Override public SqmCorrelatedBagJoin makeCopy(SqmCreationProcessingState creationProcessingState) { final SqmPathRegistry pathRegistry = creationProcessingState.getPathRegistry(); - //noinspection unchecked return new SqmCorrelatedBagJoin<>( pathRegistry.findFromByPath( getLhs().getNavigablePath() ), getReferencedPathSource(), @@ -80,8 +79,8 @@ public class SqmCorrelatedBagJoin extends SqmBagJoin implements SqmC getSqmJoinType(), isFetched(), nodeBuilder(), - (SqmCorrelatedRootJoin) pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), - (SqmBagJoin) pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) + pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), + pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedCrossJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedCrossJoin.java index e376c6ae50..77c48c0623 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedCrossJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedCrossJoin.java @@ -33,7 +33,7 @@ public class SqmCorrelatedCrossJoin extends SqmCrossJoin implements SqmCor private SqmCorrelatedCrossJoin( EntityDomainType joinedEntityDescriptor, String alias, - SqmRoot sqmRoot, + SqmRoot sqmRoot, SqmCorrelatedRootJoin correlatedRootJoin, SqmCrossJoin correlationParent) { super( joinedEntityDescriptor, alias, sqmRoot ); @@ -64,13 +64,12 @@ public class SqmCorrelatedCrossJoin extends SqmCrossJoin implements SqmCor @Override public SqmCorrelatedCrossJoin makeCopy(SqmCreationProcessingState creationProcessingState) { final SqmPathRegistry pathRegistry = creationProcessingState.getPathRegistry(); - //noinspection unchecked return new SqmCorrelatedCrossJoin<>( getReferencedPathSource(), getExplicitAlias(), - (SqmRoot) pathRegistry.findFromByPath( getRoot().getNavigablePath() ), - (SqmCorrelatedRootJoin) pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), - (SqmCrossJoin) pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) + pathRegistry.findFromByPath( getRoot().getNavigablePath() ), + pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), + pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedEntityJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedEntityJoin.java index 5b59243fbe..ed9a9a0fd0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedEntityJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedEntityJoin.java @@ -36,7 +36,7 @@ public class SqmCorrelatedEntityJoin extends SqmEntityJoin implements SqmC EntityDomainType joinedEntityDescriptor, String alias, SqmJoinType joinType, - SqmRoot sqmRoot, + SqmRoot sqmRoot, SqmCorrelatedRootJoin correlatedRootJoin, SqmEntityJoin correlationParent) { super( joinedEntityDescriptor, alias, joinType, sqmRoot ); @@ -67,14 +67,13 @@ public class SqmCorrelatedEntityJoin extends SqmEntityJoin implements SqmC @Override public SqmCorrelatedEntityJoin makeCopy(SqmCreationProcessingState creationProcessingState) { final SqmPathRegistry pathRegistry = creationProcessingState.getPathRegistry(); - //noinspection unchecked return new SqmCorrelatedEntityJoin<>( getReferencedPathSource(), getExplicitAlias(), getSqmJoinType(), - (SqmRoot) pathRegistry.findFromByPath( getRoot().getNavigablePath() ), - (SqmCorrelatedRootJoin) pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), - (SqmEntityJoin) pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) + pathRegistry.findFromByPath( getRoot().getNavigablePath() ), + pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), + pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedListJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedListJoin.java index efbf429e1c..09a2e5dd58 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedListJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedListJoin.java @@ -72,7 +72,6 @@ public class SqmCorrelatedListJoin extends SqmListJoin implements Sq @Override public SqmCorrelatedListJoin makeCopy(SqmCreationProcessingState creationProcessingState) { final SqmPathRegistry pathRegistry = creationProcessingState.getPathRegistry(); - //noinspection unchecked return new SqmCorrelatedListJoin<>( pathRegistry.findFromByPath( getLhs().getNavigablePath() ), getReferencedPathSource(), @@ -80,8 +79,8 @@ public class SqmCorrelatedListJoin extends SqmListJoin implements Sq getSqmJoinType(), isFetched(), nodeBuilder(), - (SqmCorrelatedRootJoin) pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), - (SqmListJoin) pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) + pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), + pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedMapJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedMapJoin.java index 958606ab35..21273ddd02 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedMapJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedMapJoin.java @@ -72,7 +72,6 @@ public class SqmCorrelatedMapJoin extends SqmMapJoin implement @Override public SqmCorrelatedMapJoin makeCopy(SqmCreationProcessingState creationProcessingState) { final SqmPathRegistry pathRegistry = creationProcessingState.getPathRegistry(); - //noinspection unchecked return new SqmCorrelatedMapJoin<>( pathRegistry.findFromByPath( getLhs().getNavigablePath() ), getReferencedPathSource(), @@ -80,8 +79,8 @@ public class SqmCorrelatedMapJoin extends SqmMapJoin implement getSqmJoinType(), isFetched(), nodeBuilder(), - (SqmCorrelatedRootJoin) pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), - (SqmMapJoin) pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) + pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), + pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedRootJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedRootJoin.java index 6c42bd9a83..398d09a263 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedRootJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedRootJoin.java @@ -26,13 +26,14 @@ public class SqmCorrelatedRootJoin extends SqmRoot implements SqmCorrelati super( navigablePath, referencedNavigable, nodeBuilder ); } + @SuppressWarnings("unchecked") public static > SqmCorrelatedRootJoin create(J correlationParent, J correlatedJoin) { final SqmFrom parentPath = (SqmFrom) correlationParent.getParentPath(); final SqmCorrelatedRootJoin rootJoin; if ( parentPath == null ) { - rootJoin = new SqmCorrelatedRootJoin( + rootJoin = new SqmCorrelatedRootJoin<>( correlationParent.getNavigablePath(), - correlationParent.getReferencedPathSource(), + (SqmPathSource) correlationParent.getReferencedPathSource(), correlationParent.nodeBuilder() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedSetJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedSetJoin.java index b99e89a062..b1d6da5325 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedSetJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedSetJoin.java @@ -72,7 +72,6 @@ public class SqmCorrelatedSetJoin extends SqmSetJoin implements SqmC @Override public SqmCorrelatedSetJoin makeCopy(SqmCreationProcessingState creationProcessingState) { final SqmPathRegistry pathRegistry = creationProcessingState.getPathRegistry(); - //noinspection unchecked return new SqmCorrelatedSetJoin<>( pathRegistry.findFromByPath( getLhs().getNavigablePath() ), getReferencedPathSource(), @@ -80,8 +79,8 @@ public class SqmCorrelatedSetJoin extends SqmSetJoin implements SqmC getSqmJoinType(), isFetched(), nodeBuilder(), - (SqmCorrelatedRootJoin) pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), - (SqmSetJoin) pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) + pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), + pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedSingularJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedSingularJoin.java index d3ba4a4eb3..c11e05eb6a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedSingularJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmCorrelatedSingularJoin.java @@ -72,7 +72,6 @@ public class SqmCorrelatedSingularJoin extends SqmSingularJoin imple @Override public SqmCorrelatedSingularJoin makeCopy(SqmCreationProcessingState creationProcessingState) { final SqmPathRegistry pathRegistry = creationProcessingState.getPathRegistry(); - //noinspection unchecked return new SqmCorrelatedSingularJoin<>( pathRegistry.findFromByPath( getLhs().getNavigablePath() ), getReferencedPathSource(), @@ -80,8 +79,8 @@ public class SqmCorrelatedSingularJoin extends SqmSingularJoin imple getSqmJoinType(), isFetched(), nodeBuilder(), - (SqmCorrelatedRootJoin) pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), - (SqmSingularJoin) pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) + pathRegistry.findFromByPath( correlatedRootJoin.getNavigablePath() ), + pathRegistry.findFromByPath( correlationParent.getNavigablePath() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEmbeddedValuedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEmbeddedValuedSimplePath.java index ab01673cf6..b1f65e9ebe 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEmbeddedValuedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEmbeddedValuedSimplePath.java @@ -26,7 +26,7 @@ public class SqmEmbeddedValuedSimplePath extends AbstractSqmSimplePath imp public SqmEmbeddedValuedSimplePath( NavigablePath navigablePath, SqmPathSource referencedPathSource, - SqmPath lhs, + SqmPath lhs, NodeBuilder nodeBuilder) { super( navigablePath, referencedPathSource, lhs, nodeBuilder ); @@ -37,7 +37,7 @@ public class SqmEmbeddedValuedSimplePath extends AbstractSqmSimplePath imp public SqmEmbeddedValuedSimplePath( NavigablePath navigablePath, SqmPathSource referencedPathSource, - SqmPath lhs, + SqmPath lhs, String explicitAlias, NodeBuilder nodeBuilder) { super( navigablePath, referencedPathSource, lhs, explicitAlias, nodeBuilder ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEntityValuedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEntityValuedSimplePath.java index ae1d333b14..acda996eb5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEntityValuedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmEntityValuedSimplePath.java @@ -22,7 +22,7 @@ public class SqmEntityValuedSimplePath extends AbstractSqmSimplePath { public SqmEntityValuedSimplePath( NavigablePath navigablePath, SqmPathSource referencedPathSource, - SqmPath lhs, + SqmPath lhs, NodeBuilder nodeBuilder) { super( navigablePath, referencedPathSource, lhs, nodeBuilder ); } @@ -32,15 +32,14 @@ public class SqmEntityValuedSimplePath extends AbstractSqmSimplePath { String name, boolean isTerminal, SqmCreationState creationState) { - final SqmPathSource referencedPathSource = getReferencedPathSource(); - final SqmPathSource subPathSource = referencedPathSource.findSubPathSource( name ); + final SqmPathSource referencedPathSource = getReferencedPathSource(); + final SqmPathSource subPathSource = referencedPathSource.findSubPathSource( name ); assert getLhs() == null || creationState.getProcessingStateStack() .getCurrent() .getPathRegistry() .findPath( getLhs().getNavigablePath() ) != null; - //noinspection unchecked return subPathSource.createSqmPath( this ); } @@ -62,8 +61,7 @@ public class SqmEntityValuedSimplePath extends AbstractSqmSimplePath { @Override public SqmTreatedPath treatAs(EntityDomainType treatTarget) throws PathException { - //noinspection unchecked - return new SqmTreatedSimplePath( this, treatTarget, nodeBuilder() ); + return new SqmTreatedSimplePath<>( this, treatTarget, nodeBuilder() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexedCollectionAccessPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexedCollectionAccessPath.java index 29d08f6aaf..159e837a24 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexedCollectionAccessPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmIndexedCollectionAccessPath.java @@ -22,14 +22,14 @@ import org.hibernate.query.sqm.tree.expression.SqmExpression; public class SqmIndexedCollectionAccessPath extends AbstractSqmPath implements SqmPath { private final SqmExpression selectorExpression; - public SqmIndexedCollectionAccessPath( + NavigablePath navigablePath, SqmPath pluralDomainPath, SqmExpression selectorExpression) { //noinspection unchecked super( - pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), selectorExpression.toHqlString() ), - (PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource(), + navigablePath, + (PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource(), pluralDomainPath, pluralDomainPath.nodeBuilder() ); @@ -37,21 +37,13 @@ public class SqmIndexedCollectionAccessPath extends AbstractSqmPath implem } - public SqmExpression getSelectorExpression() { + public SqmExpression getSelectorExpression() { return selectorExpression; } @Override - public PluralPersistentAttribute getReferencedPathSource() { - //noinspection unchecked - return (PluralPersistentAttribute) super.getReferencedPathSource(); - } - - @Override - public NavigablePath getNavigablePath() { - // todo (6.0) : this would require some String-ified form of the selector -// return null; - return super.getNavigablePath(); + public PluralPersistentAttribute getReferencedPathSource() { + return (PluralPersistentAttribute) super.getReferencedPathSource(); } @Override @@ -59,8 +51,7 @@ public class SqmIndexedCollectionAccessPath extends AbstractSqmPath implem String name, boolean isTerminal, SqmCreationState creationState) { - final SqmPathSource subPathSource = getReferencedPathSource().getElementPathSource().findSubPathSource( name ); - //noinspection unchecked + final SqmPathSource subPathSource = getReferencedPathSource().getElementPathSource().findSubPathSource( name ); return subPathSource.createSqmPath( this ); } @@ -77,8 +68,7 @@ public class SqmIndexedCollectionAccessPath extends AbstractSqmPath implem @Override public SqmTreatedPath treatAs(EntityDomainType treatTarget) throws PathException { if ( getReferencedPathSource().getSqmPathType() instanceof EntityDomainType ) { - //noinspection unchecked - return new SqmTreatedSimplePath( this, treatTarget, nodeBuilder() ); + return new SqmTreatedSimplePath<>( this, treatTarget, nodeBuilder() ); } throw new UnsupportedOperationException( ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmListJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmListJoin.java index 33bd54c3e6..34249fb0d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmListJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmListJoin.java @@ -12,17 +12,16 @@ import javax.persistence.criteria.Predicate; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.ListPersistentAttribute; -import org.hibernate.query.NavigablePath; import org.hibernate.query.PathException; import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaListJoin; import org.hibernate.query.criteria.JpaPredicate; import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; import org.hibernate.query.sqm.tree.from.SqmFrom; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Steve Ebersole @@ -41,14 +40,8 @@ public class SqmListJoin } @Override - public ListPersistentAttribute getReferencedPathSource() { - //noinspection unchecked - return (ListPersistentAttribute) super.getReferencedPathSource(); - } - - @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - return getNodeJavaTypeDescriptor(); + public ListPersistentAttribute getReferencedPathSource() { + return (ListPersistentAttribute) super.getReferencedPathSource(); } @Override @@ -64,16 +57,8 @@ public class SqmListJoin @Override public SqmPath index() { - final String navigableName = "{index}"; - final NavigablePath navigablePath = getNavigablePath().append( navigableName ); - - //noinspection unchecked - return new SqmBasicValuedSimplePath<>( - navigablePath, - ( (ListPersistentAttribute) getReferencedPathSource() ).getIndexPathSource(), - this, - nodeBuilder() - ); + final SqmPathSource indexPathSource = getReferencedPathSource().getIndexPathSource(); + return resolvePath( indexPathSource.getPathName(), indexPathSource ); } @Override @@ -108,14 +93,12 @@ public class SqmListJoin @Override public SqmTreatedListJoin treatAs(EntityDomainType treatTarget) throws PathException { - //noinspection unchecked - return new SqmTreatedListJoin( this, treatTarget, null ); + return new SqmTreatedListJoin<>( this, treatTarget, null ); } @Override - public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { - //noinspection unchecked - return new SqmListJoin( + public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { + return new SqmListJoin<>( creationProcessingState.getPathRegistry().findFromByPath( getLhs().getNavigablePath() ), getReferencedPathSource(), getExplicitAlias(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapEntryReference.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapEntryReference.java index f5607d54ae..f426323b29 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapEntryReference.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapEntryReference.java @@ -30,7 +30,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; * @author Steve Ebersole */ public class SqmMapEntryReference - implements SqmSelectableNode>, Expression> { + implements SqmSelectableNode>, Expression>, SqmExpressable> { @SuppressWarnings({"FieldCanBeLocal", "unused"}) private final SqmPath mapPath; private final NodeBuilder nodeBuilder; @@ -77,6 +77,11 @@ public class SqmMapEntryReference return mapEntryTypeDescriptor; } + @Override + public JavaTypeDescriptor> getExpressableJavaTypeDescriptor() { + return mapEntryTypeDescriptor; + } + @Override public X accept(SemanticQueryWalker walker) { return walker.visitMapEntryFunction( this ); @@ -99,7 +104,7 @@ public class SqmMapEntryReference @Override public SqmExpressable> getNodeType() { - return null; + return this; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapJoin.java index b0f3d6c7cb..ccc62ecc8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMapJoin.java @@ -11,11 +11,8 @@ import javax.persistence.criteria.Expression; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; -import org.hibernate.metamodel.model.domain.BasicDomainType; -import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.MapPersistentAttribute; -import org.hibernate.query.NavigablePath; import org.hibernate.query.PathException; import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaMapJoin; @@ -26,7 +23,6 @@ import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; import org.hibernate.query.sqm.tree.from.SqmFrom; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Steve Ebersole @@ -46,13 +42,7 @@ public class SqmMapJoin @Override public MapPersistentAttribute getReferencedPathSource() { - //noinspection unchecked - return(MapPersistentAttribute) super.getReferencedPathSource(); - } - - @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - return getNodeJavaTypeDescriptor(); + return(MapPersistentAttribute) super.getReferencedPathSource(); } @Override @@ -71,81 +61,20 @@ public class SqmMapJoin // JPA @Override - @SuppressWarnings("unchecked") public SqmPath key() { - final SqmPathSource keyPathSource = getReferencedPathSource().getKeyPathSource(); - final NavigablePath navigablePath = getNavigablePath().append( keyPathSource.getPathName() ); - - if ( keyPathSource.getSqmPathType() instanceof BasicDomainType ) { - return new SqmBasicValuedSimplePath( - navigablePath, - keyPathSource, - this, - null - ); - } - - if ( keyPathSource.getSqmPathType() instanceof EmbeddableDomainType ) { - return new SqmEmbeddedValuedSimplePath( - navigablePath, - keyPathSource, - this, - null - ); - } - - if ( keyPathSource.getSqmPathType() instanceof EntityDomainType ) { - return new SqmEntityValuedSimplePath( - navigablePath, - keyPathSource, - this, - null - ); - } - - throw new UnsupportedOperationException( "Unrecognized Map key descriptor : " + keyPathSource ); + final SqmPathSource keyPathSource = getReferencedPathSource().getKeyPathSource(); + return resolvePath( keyPathSource.getPathName(), keyPathSource ); } @Override - @SuppressWarnings("unchecked") public Path value() { - final SqmPathSource elementPathSource = getReferencedPathSource().getElementPathSource(); - final NavigablePath navigablePath = getNavigablePath().append( elementPathSource.getPathName() ); - - if ( elementPathSource.getSqmPathType() instanceof BasicDomainType ) { - return new SqmBasicValuedSimplePath( - navigablePath, - elementPathSource, - this, - null - ); - } - - if ( elementPathSource.getSqmPathType() instanceof EmbeddableDomainType ) { - return new SqmEmbeddedValuedSimplePath( - navigablePath, - elementPathSource, - this, - null - ); - } - - if ( elementPathSource.getSqmPathType() instanceof EntityDomainType ) { - return new SqmEntityValuedSimplePath( - navigablePath, - elementPathSource, - this, - null - ); - } - - throw new UnsupportedOperationException( "Unrecognized Map value descriptor : " + elementPathSource ); + final SqmPathSource elementPathSource = getReferencedPathSource().getElementPathSource(); + return resolvePath( elementPathSource.getPathName(), elementPathSource ); } @Override - @SuppressWarnings("unchecked") public Expression> entry() { - return new SqmMapEntryReference( this, nodeBuilder() ); + return new SqmMapEntryReference<>( this, nodeBuilder() ); } @Override @@ -180,14 +109,12 @@ public class SqmMapJoin @Override public SqmTreatedMapJoin treatAs(EntityDomainType treatTarget) throws PathException { - //noinspection unchecked - return new SqmTreatedMapJoin( this, treatTarget, null ); + return new SqmTreatedMapJoin<>( this, treatTarget, null ); } @Override - public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { - //noinspection unchecked - return new SqmMapJoin( + public SqmMapJoin makeCopy(SqmCreationProcessingState creationProcessingState) { + return new SqmMapJoin<>( creationProcessingState.getPathRegistry().findFromByPath( getLhs().getNavigablePath() ), getReferencedPathSource(), getExplicitAlias(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMaxElementPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMaxElementPath.java index 2dab0129c2..71b7ee32b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMaxElementPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMaxElementPath.java @@ -25,7 +25,7 @@ public class SqmMaxElementPath extends AbstractSqmSpecificPluralPartPath { super( pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ), pluralDomainPath, - (PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource() + (PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource() ); } @@ -35,7 +35,6 @@ public class SqmMaxElementPath extends AbstractSqmSpecificPluralPartPath { boolean isTerminal, SqmCreationState creationState) { if ( getPluralAttribute().getElementPathSource().getSqmPathType() instanceof ManagedDomainType ) { - //noinspection unchecked return getPluralAttribute().getElementPathSource().createSqmPath( this ); } @@ -44,7 +43,6 @@ public class SqmMaxElementPath extends AbstractSqmSpecificPluralPartPath { @Override public SqmPathSource getReferencedPathSource() { - //noinspection unchecked return getPluralAttribute().getElementPathSource(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMaxIndexPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMaxIndexPath.java index 17e93cba08..29ef170bc3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMaxIndexPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMaxIndexPath.java @@ -36,7 +36,7 @@ public class SqmMaxIndexPath extends AbstractSqmSpecificPluralPartPath { } else if ( getPluralAttribute() instanceof MapPersistentAttribute ) { //noinspection unchecked - this.indexPathSource = ( (MapPersistentAttribute) getPluralAttribute() ).getKeyPathSource(); + this.indexPathSource = ( (MapPersistentAttribute) getPluralAttribute() ).getKeyPathSource(); } else { throw new UnsupportedOperationException( "Plural attribute [" + getPluralAttribute() + "] is not indexed" ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMinElementPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMinElementPath.java index 9a2d121ef4..bc831f1706 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMinElementPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMinElementPath.java @@ -25,7 +25,7 @@ public class SqmMinElementPath extends AbstractSqmSpecificPluralPartPath { super( pluralDomainPath.getNavigablePath().getParent().append( pluralDomainPath.getNavigablePath().getLocalName(), NAVIGABLE_NAME ), pluralDomainPath, - (PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource() + (PluralPersistentAttribute) pluralDomainPath.getReferencedPathSource() ); } @@ -35,7 +35,6 @@ public class SqmMinElementPath extends AbstractSqmSpecificPluralPartPath { boolean isTerminal, SqmCreationState creationState) { if ( getPluralAttribute().getElementPathSource().getSqmPathType() instanceof ManagedDomainType ) { - //noinspection unchecked return getPluralAttribute().getElementPathSource().createSqmPath( this ); } @@ -44,7 +43,6 @@ public class SqmMinElementPath extends AbstractSqmSpecificPluralPartPath { @Override public SqmPathSource getReferencedPathSource() { - //noinspection unchecked return getPluralAttribute().getElementPathSource(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMinIndexPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMinIndexPath.java index b68dbea815..14d0e9d8a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMinIndexPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmMinIndexPath.java @@ -36,7 +36,7 @@ public class SqmMinIndexPath extends AbstractSqmSpecificPluralPartPath { } else if ( getPluralAttribute() instanceof MapPersistentAttribute ) { //noinspection unchecked - this.indexPathSource = ( (MapPersistentAttribute) getPluralAttribute() ).getKeyPathSource(); + this.indexPathSource = ( (MapPersistentAttribute) getPluralAttribute() ).getKeyPathSource(); } else { throw new UnsupportedOperationException( "Plural attribute [" + getPluralAttribute() + "] is not indexed" ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPath.java index d20c57e09f..6e784e7618 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPath.java @@ -6,13 +6,20 @@ */ package org.hibernate.query.sqm.tree.domain; +import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.function.Consumer; +import javax.persistence.metamodel.MapAttribute; +import javax.persistence.metamodel.PluralAttribute; +import javax.persistence.metamodel.SingularAttribute; + import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.NavigablePath; import org.hibernate.query.PathException; import org.hibernate.query.SemanticException; +import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaPath; import org.hibernate.query.hql.spi.SemanticPathPart; import org.hibernate.query.hql.spi.SqmCreationState; @@ -55,6 +62,18 @@ public interface SqmPath extends SqmExpression, SemanticPathPart, JpaPath< */ void setExplicitAlias(String explicitAlias); + /** + * Retrieve the explicit alias, if one, otherwise return a generated one and set that as explicit alias. + */ + default String resolveAlias() { + final String explicitAlias = getExplicitAlias(); + if ( explicitAlias != null ) { + return explicitAlias; + } + final String generatedAlias = "alias_" + System.identityHashCode( this ); + setExplicitAlias( generatedAlias ); + return generatedAlias; + } /** * Get the left-hand side of this path - may be null, indicating a @@ -101,8 +120,8 @@ public interface SqmPath extends SqmExpression, SemanticPathPart, JpaPath< @Override SqmTreatedPath treatAs(EntityDomainType treatTarget) throws PathException; - default SqmRoot findRoot() { - final SqmPath lhs = getLhs(); + default SqmRoot findRoot() { + final SqmPath lhs = getLhs(); if ( lhs != null ) { return lhs.findRoot(); } @@ -111,10 +130,27 @@ public interface SqmPath extends SqmExpression, SemanticPathPart, JpaPath< } @Override - default SqmPath resolveIndexedAccess( - SqmExpression selector, + default SqmPath resolveIndexedAccess( + SqmExpression selector, boolean isTerminal, SqmCreationState creationState) { throw new SemanticException( "Non-plural path [" + getNavigablePath() + "] cannot be index-accessed" ); } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Covariant overrides + + @Override + SqmPath get(SingularAttribute attribute); + + @Override + > SqmExpression get(PluralAttribute collection); + + @Override + > SqmExpression get(MapAttribute map); + + @Override + SqmExpression> type(); + + @Override + SqmPath get(String attributeName); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPluralValuedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPluralValuedSimplePath.java index 9f9b3b7414..b5d48ce600 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPluralValuedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmPluralValuedSimplePath.java @@ -7,16 +7,12 @@ package org.hibernate.query.sqm.tree.domain; import org.hibernate.metamodel.model.domain.EntityDomainType; -import org.hibernate.metamodel.model.domain.ListPersistentAttribute; -import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; -import org.hibernate.persister.collection.CollectionPropertyNames; import org.hibernate.query.NavigablePath; import org.hibernate.query.PathException; +import org.hibernate.query.hql.spi.SqmCreationState; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; -import org.hibernate.query.hql.spi.SemanticPathPart; -import org.hibernate.query.hql.spi.SqmCreationState; /** * An SqmPath for plural attribute paths @@ -28,8 +24,8 @@ import org.hibernate.query.hql.spi.SqmCreationState; public class SqmPluralValuedSimplePath extends AbstractSqmSimplePath { public SqmPluralValuedSimplePath( NavigablePath navigablePath, - PluralPersistentAttribute referencedNavigable, - SqmPath lhs, + PluralPersistentAttribute referencedNavigable, + SqmPath lhs, NodeBuilder nodeBuilder) { this( navigablePath, referencedNavigable, lhs, null, nodeBuilder ); } @@ -37,18 +33,16 @@ public class SqmPluralValuedSimplePath extends AbstractSqmSimplePath { @SuppressWarnings("WeakerAccess") public SqmPluralValuedSimplePath( NavigablePath navigablePath, - PluralPersistentAttribute referencedNavigable, - SqmPath lhs, + PluralPersistentAttribute referencedNavigable, + SqmPath lhs, String explicitAlias, NodeBuilder nodeBuilder) { - //noinspection unchecked super( navigablePath, referencedNavigable, lhs, explicitAlias, nodeBuilder ); } @Override - public PluralPersistentAttribute getReferencedPathSource() { - //noinspection unchecked - return (PluralPersistentAttribute) super.getReferencedPathSource(); + public PluralPersistentAttribute getReferencedPathSource() { + return (PluralPersistentAttribute) super.getReferencedPathSource(); } @Override @@ -62,50 +56,15 @@ public class SqmPluralValuedSimplePath extends AbstractSqmSimplePath { } @Override - @SuppressWarnings("unchecked") - public SemanticPathPart resolvePathPart( + public SqmPath resolvePathPart( String name, boolean isTerminal, SqmCreationState creationState) { // this is a reference to a collection outside of the from-clause... - - // what "names" should be allowed here? - // 1) special names such as {id}, {index}, {element}, etc? - // 2) named Navigables relative to the Collection's element type? - // 3) named Navigables relative to the Collection's index (if one) type? - // ?) others? - // d) all of the above :) - // - // or probably some combination of. For now, - final NavigablePath navigablePath = getNavigablePath().append( name ); return creationState.getProcessingStateStack().getCurrent().getPathRegistry().resolvePath( navigablePath, - np -> { - final PluralPersistentAttribute referencedPathSource = getReferencedPathSource(); - - if ( CollectionPropertyNames.COLLECTION_ELEMENTS.equals( name ) ) { - return referencedPathSource.getElementPathSource().createSqmPath( - this - ); - } - - if ( CollectionPropertyNames.COLLECTION_INDEX.equals( name ) - || CollectionPropertyNames.COLLECTION_INDICES.equals( name ) ) { - if ( referencedPathSource instanceof MapPersistentAttribute ) { - return ( (MapPersistentAttribute) referencedPathSource ).getKeyPathSource().createSqmPath( this ); - } - else if ( referencedPathSource instanceof ListPersistentAttribute ) { - return referencedPathSource.getIndexPathSource().createSqmPath( this ); - } - - throw new UnsupportedOperationException( ); - } - - return referencedPathSource.getElementPathSource().createSqmPath( - this - ); - } + np -> get( np.getUnaliasedLocalName() ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSetJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSetJoin.java index 772930566a..64313199eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSetJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSetJoin.java @@ -22,7 +22,6 @@ import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; import org.hibernate.query.sqm.tree.from.SqmFrom; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Steve Ebersole @@ -42,13 +41,7 @@ public class SqmSetJoin @Override public SetPersistentAttribute getReferencedPathSource() { - //noinspection unchecked - return (SetPersistentAttribute) super.getReferencedPathSource(); - } - - @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - return getReferencedPathSource().getExpressableJavaTypeDescriptor(); + return (SetPersistentAttribute) super.getReferencedPathSource(); } @Override @@ -102,9 +95,8 @@ public class SqmSetJoin } @Override - public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { - //noinspection unchecked - return new SqmSetJoin( + public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { + return new SqmSetJoin<>( creationProcessingState.getPathRegistry().findFromByPath( getLhs().getNavigablePath() ), getReferencedPathSource(), getExplicitAlias(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSingularJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSingularJoin.java index fa0d61c969..013d37b2e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSingularJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmSingularJoin.java @@ -17,7 +17,6 @@ import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; import org.hibernate.query.sqm.tree.from.SqmFrom; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Steve Ebersole @@ -38,11 +37,6 @@ public class SqmSingularJoin extends AbstractSqmAttributeJoin implemen return (SingularPersistentAttribute) super.getReferencedPathSource(); } - @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - return getNodeJavaTypeDescriptor(); - } - @Override public SingularPersistentAttribute getModel() { return getReferencedPathSource(); @@ -61,8 +55,7 @@ public class SqmSingularJoin extends AbstractSqmAttributeJoin implemen @Override public SqmTreatedSingularJoin treatAs(EntityDomainType treatTarget) throws PathException { - //noinspection unchecked - return new SqmTreatedSingularJoin( this, treatTarget, null ); + return new SqmTreatedSingularJoin<>( this, treatTarget, null ); } @Override @@ -81,9 +74,8 @@ public class SqmSingularJoin extends AbstractSqmAttributeJoin implemen } @Override - public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { - //noinspection unchecked - return new SqmSingularJoin( + public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { + return new SqmSingularJoin<>( creationProcessingState.getPathRegistry().findFromByPath( getLhs().getNavigablePath() ), getReferencedPathSource(), getExplicitAlias(), diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java index f094d098a4..9c193b94be 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedBagJoin.java @@ -9,7 +9,9 @@ package org.hibernate.query.sqm.tree.domain; import org.hibernate.metamodel.model.domain.BagPersistentAttribute; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.hql.spi.SqmCreationProcessingState; +import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; +import org.hibernate.query.sqm.tree.from.SqmJoin; /** * @author Steve Ebersole @@ -20,13 +22,13 @@ public class SqmTreatedBagJoin extends SqmBagJoin impleme @SuppressWarnings("WeakerAccess") public SqmTreatedBagJoin( - SqmBagJoin wrappedPath, + SqmBagJoin wrappedPath, EntityDomainType treatTarget, String alias) { //noinspection unchecked super( wrappedPath.getLhs(), - (BagPersistentAttribute) wrappedPath.getAttribute(), + (BagPersistentAttribute) wrappedPath.getAttribute(), alias, wrappedPath.getSqmJoinType(), wrappedPath.isFetched(), @@ -36,6 +38,13 @@ public class SqmTreatedBagJoin extends SqmBagJoin impleme this.wrappedPath = wrappedPath; } + @Override + public void addSqmJoin(SqmJoin join) { + super.addSqmJoin( join ); + //noinspection unchecked + wrappedPath.addSqmJoin( (SqmJoin) join ); + } + @Override public SqmBagJoin getWrappedPath() { return wrappedPath; @@ -47,9 +56,13 @@ public class SqmTreatedBagJoin extends SqmBagJoin impleme } @Override - public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { - //noinspection unchecked - return new SqmTreatedBagJoin( wrappedPath, treatTarget, getAlias() ); + public SqmPathSource getNodeType() { + return treatTarget; + } + + @Override + public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { + return new SqmTreatedBagJoin<>( wrappedPath, treatTarget, getAlias() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java index 1cbcf9fc17..bf84bcafc4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedCrossJoin.java @@ -7,7 +7,9 @@ package org.hibernate.query.sqm.tree.domain; import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.from.SqmCrossJoin; +import org.hibernate.query.sqm.tree.from.SqmJoin; /** * @author Steve Ebersole @@ -22,7 +24,7 @@ public class SqmTreatedCrossJoin extends SqmCrossJoin impleme EntityDomainType treatTarget) { //noinspection unchecked super( - (EntityDomainType) wrappedPath.getReferencedPathSource().getSqmPathType(), + (EntityDomainType) wrappedPath.getReferencedPathSource().getSqmPathType(), alias, wrappedPath.getRoot() ); @@ -30,6 +32,13 @@ public class SqmTreatedCrossJoin extends SqmCrossJoin impleme this.treatTarget = treatTarget; } + @Override + public void addSqmJoin(SqmJoin join) { + super.addSqmJoin( join ); + //noinspection unchecked + wrappedPath.addSqmJoin( (SqmJoin) join ); + } + @Override public EntityDomainType getTreatTarget() { return treatTarget; @@ -45,10 +54,15 @@ public class SqmTreatedCrossJoin extends SqmCrossJoin impleme return wrappedPath; } + @Override + public SqmPathSource getNodeType() { + return treatTarget; + } + @Override public EntityDomainType getReferencedPathSource() { //noinspection unchecked - return (EntityDomainType) wrappedPath.getReferencedPathSource(); + return (EntityDomainType) wrappedPath.getReferencedPathSource(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java index 4b83af35cd..9482645ebe 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedEntityJoin.java @@ -7,8 +7,10 @@ package org.hibernate.query.sqm.tree.domain; import org.hibernate.metamodel.model.domain.EntityDomainType; +import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.SqmJoinType; import org.hibernate.query.sqm.tree.from.SqmEntityJoin; +import org.hibernate.query.sqm.tree.from.SqmJoin; /** * @author Steve Ebersole @@ -32,6 +34,13 @@ public class SqmTreatedEntityJoin extends SqmEntityJoin imple this.treatTarget = treatTarget; } + @Override + public void addSqmJoin(SqmJoin join) { + super.addSqmJoin( join ); + //noinspection unchecked + wrappedPath.addSqmJoin( (SqmJoin) join ); + } + @Override public EntityDomainType getTreatTarget() { return treatTarget; @@ -42,6 +51,11 @@ public class SqmTreatedEntityJoin extends SqmEntityJoin imple return wrappedPath; } + @Override + public SqmPathSource getNodeType() { + return treatTarget; + } + @Override public EntityDomainType getReferencedPathSource() { //noinspection unchecked diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java index 6a4a754da0..577fe3bee4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedListJoin.java @@ -10,8 +10,10 @@ import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.ListPersistentAttribute; import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.hql.spi.SqmCreationState; +import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; +import org.hibernate.query.sqm.tree.from.SqmJoin; /** * @author Steve Ebersole @@ -22,13 +24,13 @@ public class SqmTreatedListJoin extends SqmListJoin imple @SuppressWarnings("WeakerAccess") public SqmTreatedListJoin( - SqmListJoin wrappedPath, + SqmListJoin wrappedPath, EntityDomainType treatTarget, String alias) { //noinspection unchecked super( wrappedPath.getLhs(), - (ListPersistentAttribute) wrappedPath.getAttribute(), + (ListPersistentAttribute) wrappedPath.getAttribute(), alias, wrappedPath.getSqmJoinType(), wrappedPath.isFetched(), @@ -38,6 +40,13 @@ public class SqmTreatedListJoin extends SqmListJoin imple this.wrappedPath = wrappedPath; } + @Override + public void addSqmJoin(SqmJoin join) { + super.addSqmJoin( join ); + //noinspection unchecked + wrappedPath.addSqmJoin( (SqmJoin) join ); + } + @Override public SqmListJoin getWrappedPath() { return wrappedPath; @@ -54,17 +63,21 @@ public class SqmTreatedListJoin extends SqmListJoin imple } @Override - public SqmPath resolveIndexedAccess( - SqmExpression selector, + public SqmPathSource getNodeType() { + return treatTarget; + } + + @Override + public SqmPath resolveIndexedAccess( + SqmExpression selector, boolean isTerminal, SqmCreationState creationState) { return getWrappedPath().resolveIndexedAccess( selector, isTerminal, creationState ); } @Override - public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { - //noinspection unchecked - return new SqmTreatedListJoin( wrappedPath, treatTarget, getAlias() ); + public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { + return new SqmTreatedListJoin<>( wrappedPath, treatTarget, getAlias() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java index 7cbb35486c..0a9f907bb4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedMapJoin.java @@ -8,25 +8,25 @@ package org.hibernate.query.sqm.tree.domain; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.hql.spi.SqmCreationProcessingState; -import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.query.sqm.SqmPathSource; +import org.hibernate.query.sqm.tree.from.SqmJoin; /** * @author Steve Ebersole */ -public class SqmTreatedMapJoin extends SqmMapJoin implements SqmTreatedPath { - private final SqmMapJoin wrappedPath; +public class SqmTreatedMapJoin extends SqmMapJoin implements SqmTreatedPath { + private final SqmMapJoin wrappedPath; private final EntityDomainType treatTarget; @SuppressWarnings("WeakerAccess") public SqmTreatedMapJoin( - SqmMapJoin wrappedPath, + SqmMapJoin wrappedPath, EntityDomainType treatTarget, String alias) { //noinspection unchecked super( wrappedPath.getLhs(), - ( (SqmMapJoin) wrappedPath ).getModel(), + ( (SqmMapJoin) wrappedPath ).getModel(), alias, wrappedPath.getSqmJoinType(), wrappedPath.isFetched(), @@ -36,6 +36,13 @@ public class SqmTreatedMapJoin extends SqmMapJoin imp this.wrappedPath = wrappedPath; } + @Override + public void addSqmJoin(SqmJoin join) { + super.addSqmJoin( join ); + //noinspection unchecked + wrappedPath.addSqmJoin( (SqmJoin) join ); + } + @Override public SqmMapJoin getWrappedPath() { return wrappedPath; @@ -47,14 +54,13 @@ public class SqmTreatedMapJoin extends SqmMapJoin imp } @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - return null; + public SqmPathSource getNodeType() { + return treatTarget; } @Override - public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { - //noinspection unchecked - return new SqmTreatedMapJoin( + public SqmMapJoin makeCopy(SqmCreationProcessingState creationProcessingState) { + return new SqmTreatedMapJoin<>( wrappedPath, treatTarget, getAlias() diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPath.java index b2fa8649bf..a3db726157 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedPath.java @@ -15,11 +15,6 @@ import org.hibernate.query.sqm.SqmPathSource; public interface SqmTreatedPath extends SqmPathWrapper { EntityDomainType getTreatTarget(); - @Override - default SqmPathSource getNodeType() { - return getTreatTarget(); - } - @Override SqmPath getWrappedPath(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java index 63e859dbfb..d6faf74657 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedRoot.java @@ -14,6 +14,7 @@ import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.UnknownPathException; +import org.hibernate.query.sqm.tree.from.SqmJoin; import org.hibernate.query.sqm.tree.from.SqmRoot; /** @@ -38,6 +39,13 @@ public class SqmTreatedRoot extends SqmRoot implements SqmTre this.treatTarget = treatTarget; } + @Override + public void addSqmJoin(SqmJoin join) { + super.addSqmJoin( join ); + //noinspection unchecked + wrappedPath.addSqmJoin( (SqmJoin) join ); + } + @Override public EntityDomainType getTreatTarget() { return treatTarget; @@ -53,6 +61,11 @@ public class SqmTreatedRoot extends SqmRoot implements SqmTre return wrappedPath; } + @Override + public SqmPathSource getNodeType() { + return treatTarget; + } + @Override public EntityDomainType getReferencedPathSource() { return getManagedType(); @@ -69,7 +82,7 @@ public class SqmTreatedRoot extends SqmRoot implements SqmTre } @Override - public SemanticPathPart resolvePathPart( + public SqmPath resolvePathPart( String name, boolean isTerminal, SqmCreationState creationState) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java index 0ed4e2596f..de78ee4798 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSetJoin.java @@ -9,8 +9,9 @@ package org.hibernate.query.sqm.tree.domain; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.SetPersistentAttribute; import org.hibernate.query.hql.spi.SqmCreationProcessingState; +import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.query.sqm.tree.from.SqmJoin; /** * @author Steve Ebersole @@ -21,13 +22,13 @@ public class SqmTreatedSetJoin extends SqmSetJoin impleme @SuppressWarnings("WeakerAccess") public SqmTreatedSetJoin( - SqmSetJoin wrappedPath, + SqmSetJoin wrappedPath, EntityDomainType treatTarget, String alias) { //noinspection unchecked super( wrappedPath.getLhs(), - (SetPersistentAttribute) wrappedPath.getAttribute(), + (SetPersistentAttribute) wrappedPath.getAttribute(), alias, wrappedPath.getSqmJoinType(), wrappedPath.isFetched(), @@ -37,6 +38,13 @@ public class SqmTreatedSetJoin extends SqmSetJoin impleme this.wrappedPath = wrappedPath; } + @Override + public void addSqmJoin(SqmJoin join) { + super.addSqmJoin( join ); + //noinspection unchecked + wrappedPath.addSqmJoin( (SqmJoin) join ); + } + @Override public SqmSetJoin getWrappedPath() { return wrappedPath; @@ -52,21 +60,19 @@ public class SqmTreatedSetJoin extends SqmSetJoin impleme return treatTarget; } + @Override + public SqmPathSource getNodeType() { + return treatTarget; + } + @Override public SetPersistentAttribute getReferencedPathSource() { return super.getReferencedPathSource(); } @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - //noinspection unchecked - return (JavaTypeDescriptor) wrappedPath.getJavaTypeDescriptor(); - } - - @Override - public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { - //noinspection unchecked - return new SqmTreatedSetJoin( wrappedPath, treatTarget, getAlias() ); + public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { + return new SqmTreatedSetJoin<>( wrappedPath, treatTarget, getAlias() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java index e44b9aaada..0fa7416443 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSimplePath.java @@ -51,6 +51,12 @@ public class SqmTreatedSimplePath this.wrappedPath = wrappedPath; } + @Override + public void registerReusablePath(SqmPath path) { + super.registerReusablePath( path ); + wrappedPath.registerReusablePath( path ); + } + @Override public EntityDomainType getTreatTarget() { return treatTarget; @@ -61,6 +67,11 @@ public class SqmTreatedSimplePath return wrappedPath; } + @Override + public EntityDomainType getNodeType() { + return treatTarget; + } + @Override public SqmTreatedSimplePath treatAs(Class treatJavaType) throws PathException { return super.treatAs( treatJavaType ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java index 1a49010229..a44e7be728 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/domain/SqmTreatedSingularJoin.java @@ -9,8 +9,9 @@ package org.hibernate.query.sqm.tree.domain; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; import org.hibernate.query.hql.spi.SqmCreationProcessingState; +import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.query.sqm.tree.from.SqmJoin; /** * @author Steve Ebersole @@ -27,7 +28,7 @@ public class SqmTreatedSingularJoin extends SqmSingularJoin) wrappedPath.getAttribute(), alias, wrappedPath.getSqmJoinType(), wrappedPath.isFetched(), @@ -37,6 +38,13 @@ public class SqmTreatedSingularJoin extends SqmSingularJoin join) { + super.addSqmJoin( join ); + //noinspection unchecked + wrappedPath.addSqmJoin( (SqmJoin) join ); + } + @Override public SqmSingularJoin getWrappedPath() { return wrappedPath; @@ -48,20 +56,13 @@ public class SqmTreatedSingularJoin extends SqmSingularJoin getNodeType() { + return treatTarget; } @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - return treatTarget.getExpressableJavaTypeDescriptor(); - } - - @Override - public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { - //noinspection unchecked - return new SqmTreatedSingularJoin( wrappedPath, treatTarget, getAlias() ); + public SqmAttributeJoin makeCopy(SqmCreationProcessingState creationProcessingState) { + return new SqmTreatedSingularJoin<>( wrappedPath, treatTarget, getAlias() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java index efac8ecbd5..844f072a9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/AbstractSqmExpression.java @@ -11,11 +11,13 @@ import java.math.BigInteger; import java.util.Collection; import javax.persistence.criteria.Expression; +import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmTreeCreationLogger; import org.hibernate.query.sqm.tree.jpa.AbstractJpaSelection; +import org.hibernate.query.sqm.tree.predicate.SqmInPredicate; import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -58,43 +60,36 @@ public abstract class AbstractSqmExpression extends AbstractJpaSelection i @Override public SqmExpression asLong() { - //noinspection unchecked return castAs( StandardBasicTypes.LONG ); } @Override public SqmExpression asInteger() { - //noinspection unchecked return castAs( StandardBasicTypes.INTEGER ); } @Override public SqmExpression asFloat() { - //noinspection unchecked return castAs( StandardBasicTypes.FLOAT ); } @Override public SqmExpression asDouble() { - //noinspection unchecked return castAs( StandardBasicTypes.DOUBLE ); } @Override public SqmExpression asBigDecimal() { - //noinspection unchecked return castAs( StandardBasicTypes.BIG_DECIMAL ); } @Override public SqmExpression asBigInteger() { - //noinspection unchecked return castAs( StandardBasicTypes.BIG_INTEGER ); } @Override public SqmExpression asString() { - //noinspection unchecked return castAs( StandardBasicTypes.STRING ); } @@ -125,7 +120,19 @@ public abstract class AbstractSqmExpression extends AbstractJpaSelection i @Override public SqmPredicate in(Collection values) { - return nodeBuilder().in( this, values ); + final SqmInPredicate in = nodeBuilder().in( this ); + for ( Object value : values ) { + if ( value instanceof SqmExpression ) { + //noinspection unchecked + in.value( (JpaExpression) value ); + } + else { + //noinspection unchecked + in.value( (T) value ); + } + } + + return in; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java index 98bae493a2..1d5ff085e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/JpaCriteriaParameter.java @@ -33,6 +33,13 @@ public class JpaCriteriaParameter private final T value; private boolean allowsMultiValuedBinding; + public JpaCriteriaParameter( + AllowableParameterType type, + boolean allowsMultiValuedBinding, + NodeBuilder nodeBuilder) { + this( null, type, allowsMultiValuedBinding, nodeBuilder ); + } + public JpaCriteriaParameter( String name, AllowableParameterType type, @@ -43,11 +50,17 @@ public class JpaCriteriaParameter this.value = null; this.allowsMultiValuedBinding = allowsMultiValuedBinding; } + public JpaCriteriaParameter( + String name, AllowableParameterType type, + T value, boolean allowsMultiValuedBinding, NodeBuilder nodeBuilder) { - this( null, type, allowsMultiValuedBinding, nodeBuilder ); + super( type, nodeBuilder ); + this.name = name; + this.value = value; + this.allowsMultiValuedBinding = allowsMultiValuedBinding; } public JpaCriteriaParameter(AllowableParameterType type, T value, NodeBuilder criteriaBuilder) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAggregateFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAggregateFunction.java new file mode 100644 index 0000000000..3247c6038a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmAggregateFunction.java @@ -0,0 +1,22 @@ +/* + * 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.criteria.JpaFunction; +import org.hibernate.query.sqm.tree.predicate.SqmPredicate; + +/** + * A SQM aggregate function. + * + * @param The Java type of the expression + * + * @author Christian Beikov + */ +public interface SqmAggregateFunction extends JpaFunction, SqmExpression { + + SqmPredicate getFilter(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmBinaryArithmetic.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmBinaryArithmetic.java index a9fe438642..dcae9607a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmBinaryArithmetic.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmBinaryArithmetic.java @@ -71,7 +71,7 @@ public class SqmBinaryArithmetic extends AbstractSqmExpression implements * * @return The left-hand operand. */ - public SqmExpression getLeftHandOperand() { + public SqmExpression getLeftHandOperand() { return lhsOperand; } @@ -89,7 +89,7 @@ public class SqmBinaryArithmetic extends AbstractSqmExpression implements * * @return The right-hand operand. */ - public SqmExpression getRightHandOperand() { + public SqmExpression getRightHandOperand() { return rhsOperand; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEntityType.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEntityType.java index 3551273a1f..0a6623ec81 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEntityType.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmLiteralEntityType.java @@ -15,7 +15,6 @@ import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.select.SqmSelectableNode; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * Represents an reference to an entity type as a literal. This is the JPA @@ -36,11 +35,6 @@ public class SqmLiteralEntityType this.entityType = entityType; } - @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - return getNodeType().getExpressableJavaTypeDescriptor(); - } - @Override public EntityDomainType getNodeType() { return entityType; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCrossJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCrossJoin.java index 5e086e8950..b83d570170 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCrossJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmCrossJoin.java @@ -16,7 +16,6 @@ import org.hibernate.query.sqm.tree.domain.AbstractSqmFrom; import org.hibernate.query.sqm.tree.domain.SqmCorrelatedCrossJoin; import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.domain.SqmTreatedCrossJoin; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import static org.hibernate.query.sqm.spi.SqmCreationHelper.buildRootNavigablePath; @@ -24,12 +23,12 @@ import static org.hibernate.query.sqm.spi.SqmCreationHelper.buildRootNavigablePa * @author Steve Ebersole */ public class SqmCrossJoin extends AbstractSqmFrom implements SqmJoin { - private final SqmRoot sqmRoot; + private final SqmRoot sqmRoot; public SqmCrossJoin( EntityDomainType joinedEntityDescriptor, String alias, - SqmRoot sqmRoot) { + SqmRoot sqmRoot) { super( buildRootNavigablePath( alias, joinedEntityDescriptor.getHibernateEntityName() ), joinedEntityDescriptor, @@ -40,12 +39,12 @@ public class SqmCrossJoin extends AbstractSqmFrom implements SqmJoin getRoot() { return sqmRoot; } @Override - public SqmPath getLhs() { + public SqmPath getLhs() { // a cross-join has no LHS return null; } @@ -70,12 +69,7 @@ public class SqmCrossJoin extends AbstractSqmFrom implements SqmJoin getJavaTypeDescriptor() { - return getReferencedPathSource().getExpressableJavaTypeDescriptor(); - } - - @Override - public SqmRoot findRoot() { + public SqmRoot findRoot() { return getRoot(); } @@ -102,7 +96,7 @@ public class SqmCrossJoin extends AbstractSqmFrom implements SqmJoin( getReferencedPathSource(), getExplicitAlias(), - (SqmRoot) pathRegistry.findFromByPath( getRoot().getNavigablePath() ) + pathRegistry.findFromByPath( getRoot().getNavigablePath() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmEntityJoin.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmEntityJoin.java index 6e3d00b1d1..ebb3caa157 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmEntityJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmEntityJoin.java @@ -26,14 +26,14 @@ import org.hibernate.query.sqm.tree.predicate.SqmPredicate; * @author Steve Ebersole */ public class SqmEntityJoin extends AbstractSqmJoin implements SqmQualifiedJoin, JpaEntityJoin { - private final SqmRoot sqmRoot; + private final SqmRoot sqmRoot; private SqmPredicate joinPredicate; public SqmEntityJoin( EntityDomainType joinedEntityDescriptor, String alias, SqmJoinType joinType, - SqmRoot sqmRoot) { + SqmRoot sqmRoot) { super( SqmCreationHelper.buildRootNavigablePath( joinedEntityDescriptor.getHibernateEntityName(), alias ), joinedEntityDescriptor, @@ -45,18 +45,18 @@ public class SqmEntityJoin extends AbstractSqmJoin implements SqmQualif this.sqmRoot = sqmRoot; } - public SqmRoot getRoot() { + public SqmRoot getRoot() { return sqmRoot; } @Override - public SqmRoot findRoot() { + public SqmRoot findRoot() { return getRoot(); } @Override - public SqmPath resolveIndexedAccess( - SqmExpression selector, + public SqmPath resolveIndexedAccess( + SqmExpression selector, boolean isTerminal, SqmCreationState creationState) { return null; @@ -68,7 +68,7 @@ public class SqmEntityJoin extends AbstractSqmJoin implements SqmQualif } @Override - public SqmPath getLhs() { + public SqmPath getLhs() { // An entity-join has no LHS return null; } @@ -120,7 +120,7 @@ public class SqmEntityJoin extends AbstractSqmJoin implements SqmQualif getReferencedPathSource(), getExplicitAlias(), getSqmJoinType(), - (SqmRoot) pathRegistry.findFromByPath( getRoot().getNavigablePath() ) + pathRegistry.findFromByPath( getRoot().getNavigablePath() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java index 269045664b..ebc2fe2b35 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFrom.java @@ -20,6 +20,7 @@ import javax.persistence.metamodel.SetAttribute; import javax.persistence.metamodel.SingularAttribute; import org.hibernate.query.criteria.JpaFrom; +import org.hibernate.query.hql.spi.SqmCreationState; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.tree.SqmVisitableNode; import org.hibernate.query.sqm.tree.domain.SqmBagJoin; @@ -44,6 +45,9 @@ public interface SqmFrom extends SqmVisitableNode, SqmPath, JpaFrom getReferencedPathSource(); + @Override + SqmPath resolvePathPart(String name, boolean isTerminal, SqmCreationState creationState); + boolean hasJoins(); /** diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFromClause.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFromClause.java index 9b15998f05..55375e2e46 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFromClause.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmFromClause.java @@ -6,6 +6,7 @@ */ package org.hibernate.query.sqm.tree.from; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -21,7 +22,7 @@ import org.hibernate.internal.util.collections.CollectionHelper; * * @author Steve Ebersole */ -public class SqmFromClause { +public class SqmFromClause implements Serializable { private List> domainRoots; public SqmFromClause() { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmRoot.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmRoot.java index ffd07bbada..0193759faf 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/from/SqmRoot.java @@ -24,17 +24,21 @@ import org.hibernate.query.sqm.tree.domain.SqmTreatedPath; import org.hibernate.query.sqm.tree.domain.SqmTreatedRoot; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Steve Ebersole */ public class SqmRoot extends AbstractSqmFrom implements JpaRoot, DomainResultProducer { + + private final boolean allowJoins; + public SqmRoot( EntityDomainType entityType, String alias, + boolean allowJoins, NodeBuilder nodeBuilder) { super( entityType, alias, nodeBuilder ); + this.allowJoins = allowJoins; } protected SqmRoot( @@ -42,6 +46,7 @@ public class SqmRoot extends AbstractSqmFrom implements JpaRoot, Doma SqmPathSource referencedNavigable, NodeBuilder nodeBuilder) { super( navigablePath, referencedNavigable, nodeBuilder ); + this.allowJoins = true; } public SqmRoot( @@ -50,7 +55,7 @@ public class SqmRoot extends AbstractSqmFrom implements JpaRoot, Doma String alias, NodeBuilder nodeBuilder) { super( navigablePath, entityType, alias, nodeBuilder ); - + this.allowJoins = true; } @Override @@ -59,8 +64,22 @@ public class SqmRoot extends AbstractSqmFrom implements JpaRoot, Doma return null; } + public boolean isAllowJoins() { + return allowJoins; + } + @Override - public SqmRoot findRoot() { + public void addSqmJoin(SqmJoin join) { + if ( !allowJoins ) { + throw new IllegalArgumentException( + "The root node [" + this + "] does not allow join/fetch" + ); + } + super.addSqmJoin( join ); + } + + @Override + public SqmRoot findRoot() { return this; } @@ -73,11 +92,6 @@ public class SqmRoot extends AbstractSqmFrom implements JpaRoot, Doma return getReferencedPathSource().getHibernateEntityName(); } - @Override - public JavaTypeDescriptor getJavaTypeDescriptor() { - return getReferencedPathSource().getExpressableJavaTypeDescriptor(); - } - @Override public String toString() { return getExplicitAlias() == null @@ -132,7 +146,7 @@ public class SqmRoot extends AbstractSqmFrom implements JpaRoot, Doma public JpaEntityJoin join(EntityDomainType entity, SqmJoinType joinType) { final SqmEntityJoin join = new SqmEntityJoin<>( entity, null, joinType, this ); //noinspection unchecked - addSqmJoin( (SqmEntityJoin) join ); + addSqmJoin( (SqmJoin) join ); return join; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java index e55d5bc2a0..d352934537 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertSelectStatement.java @@ -31,6 +31,7 @@ public class SqmInsertSelectStatement extends AbstractSqmInsertStatement i new SqmRoot<>( nodeBuilder.getDomainModel().entity( targetEntity ), null, + false, nodeBuilder ), SqmQuerySource.CRITERIA, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java index f76f9d3eb9..0758bb7cbc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmInsertValuesStatement.java @@ -20,7 +20,7 @@ import java.util.List; * @author Gavin King */ public class SqmInsertValuesStatement extends AbstractSqmInsertStatement { - private List valuesList = new ArrayList<>(); + private final List valuesList = new ArrayList<>(); public SqmInsertValuesStatement(SqmRoot targetRoot, NodeBuilder nodeBuilder) { super( targetRoot, SqmQuerySource.HQL, nodeBuilder ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmValues.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmValues.java index 1df0591f98..3b7ed96111 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmValues.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/insert/SqmValues.java @@ -8,13 +8,14 @@ package org.hibernate.query.sqm.tree.insert; import org.hibernate.query.sqm.tree.expression.SqmExpression; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * @author Gavin King */ -public class SqmValues { +public class SqmValues implements Serializable { private final List> expressions = new ArrayList<>(); public List> getExpressions() { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/jpa/ParameterCollector.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/jpa/ParameterCollector.java index d0a600e1d4..490268faa0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/jpa/ParameterCollector.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/jpa/ParameterCollector.java @@ -11,13 +11,26 @@ import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; +import org.hibernate.metamodel.model.domain.AllowableParameterType; +import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker; +import org.hibernate.query.sqm.tree.SqmExpressableAccessor; import org.hibernate.query.sqm.tree.SqmStatement; +import org.hibernate.query.sqm.tree.domain.SqmIndexedCollectionAccessPath; import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter; +import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper; import org.hibernate.query.sqm.tree.expression.SqmNamedParameter; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.expression.SqmPositionalParameter; +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.SqmInListPredicate; +import org.hibernate.query.sqm.tree.predicate.SqmInSubQueryPredicate; +import org.hibernate.query.sqm.tree.predicate.SqmLikePredicate; +import org.hibernate.query.sqm.tree.predicate.SqmMemberOfPredicate; +import org.hibernate.query.sqm.tree.predicate.SqmNullnessPredicate; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.service.ServiceRegistry; @@ -50,12 +63,12 @@ public class ParameterCollector extends BaseSemanticQueryWalker { private final Consumer> consumer; @Override - public Object visitPositionalParameterExpression(SqmPositionalParameter expression) { + public Object visitPositionalParameterExpression(SqmPositionalParameter expression) { return visitParameter( expression ); } @Override - public Object visitNamedParameterExpression(SqmNamedParameter expression) { + public Object visitNamedParameterExpression(SqmNamedParameter expression) { return visitParameter( expression ); } @@ -71,26 +84,143 @@ public class ParameterCollector extends BaseSemanticQueryWalker { */ @Override public SqmJpaCriteriaParameterWrapper visitJpaCriteriaParameter(JpaCriteriaParameter expression) { - //noinspection unchecked - return (SqmJpaCriteriaParameterWrapper) visitParameter( - new SqmJpaCriteriaParameterWrapper( - expression.getHibernateType(), + return visitParameter( + new SqmJpaCriteriaParameterWrapper<>( + getInferredParameterType( expression ), expression, expression.nodeBuilder() ) ); } - private SqmParameter visitParameter(SqmParameter param) { + private AllowableParameterType getInferredParameterType(JpaCriteriaParameter expression) { + AllowableParameterType parameterType = null; + if ( inferenceBasis != null ) { + final SqmExpressable expressable = inferenceBasis.getExpressable(); + if ( expressable instanceof AllowableParameterType ) { + parameterType = (AllowableParameterType) expressable; + } + } + if ( parameterType == null ) { + parameterType = expression.getHibernateType(); + } + //noinspection unchecked + return (AllowableParameterType) parameterType; + } + + private > T visitParameter(T param) { if ( parameterExpressions == null ) { parameterExpressions = new HashSet<>(); } - parameterExpressions.add( param ); - consumer.accept( param ); - return param; } + private SqmJpaCriteriaParameterWrapper visitParameter(SqmJpaCriteriaParameterWrapper param) { + if ( parameterExpressions == null ) { + parameterExpressions = new HashSet<>(); + } + parameterExpressions.add( param.getJpaCriteriaParameter() ); + consumer.accept( param ); + return param; + } + + private SqmExpressableAccessor inferenceBasis; + + private void withTypeInference(SqmExpressableAccessor inferenceBasis, Runnable action) { + SqmExpressableAccessor original = this.inferenceBasis; + this.inferenceBasis = inferenceBasis; + try { + action.run(); + } + finally { + this.inferenceBasis = original; + } + } + + @Override + public Object visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath path) { + path.getLhs().accept( this ); + withTypeInference( path.getReferencedPathSource().getIndexPathSource(), () -> path.getSelectorExpression().accept( this ) ); + return path; + } + + @Override + public Object visitIsEmptyPredicate(SqmEmptinessPredicate predicate) { + withTypeInference( null, () -> super.visitIsEmptyPredicate( predicate ) ); + return predicate; + } + + @Override + public Object visitIsNullPredicate(SqmNullnessPredicate predicate) { + withTypeInference( null, () -> super.visitIsNullPredicate( predicate ) ); + return predicate; + } + + @Override + public Object visitComparisonPredicate(SqmComparisonPredicate predicate) { + withTypeInference( predicate.getRightHandExpression(), () -> predicate.getLeftHandExpression().accept( this ) ); + withTypeInference( predicate.getLeftHandExpression(), () -> predicate.getRightHandExpression().accept( this ) ); + return predicate; + } + + @Override + public Object visitBetweenPredicate(SqmBetweenPredicate predicate) { + withTypeInference( predicate.getLowerBound(), () -> predicate.getExpression().accept( this ) ); + withTypeInference( + predicate.getExpression(), + () -> { + predicate.getLowerBound().accept( this ); + predicate.getUpperBound().accept( this ); + } + ); + return predicate; + } + + @Override + public Object visitLikePredicate(SqmLikePredicate predicate) { + withTypeInference( predicate.getPattern(), () -> predicate.getMatchExpression().accept( this ) ); + withTypeInference( + predicate.getMatchExpression(), + () -> { + predicate.getPattern().accept( this ); + if ( predicate.getEscapeCharacter() != null ) { + predicate.getEscapeCharacter().accept( this ); + } + } + ); + return predicate; + } + + @Override + public Object visitMemberOfPredicate(SqmMemberOfPredicate predicate) { + withTypeInference( predicate.getPluralPath(), () -> predicate.getLeftHandExpression().accept( this ) ); + predicate.getPluralPath().accept( this ); + return predicate; + } + + @Override + public Object visitInListPredicate(SqmInListPredicate predicate) { + final SqmExpression firstListElement = predicate.getListExpressions().isEmpty() + ? null + : predicate.getListExpressions().get( 0 ); + withTypeInference( firstListElement, () -> predicate.getTestExpression().accept( this ) ); + withTypeInference( + predicate.getTestExpression(), + () -> { + for ( SqmExpression expression : predicate.getListExpressions() ) { + expression.accept( this ); + } + } + ); + return predicate; + } + + @Override + public Object visitInSubQueryPredicate(SqmInSubQueryPredicate predicate) { + withTypeInference( predicate.getSubQueryExpression(), () -> predicate.getTestExpression().accept( this ) ); + withTypeInference( predicate.getTestExpression(), () -> predicate.getSubQueryExpression().accept( this ) ); + return predicate; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractSqmPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractSqmPredicate.java index e206d2e543..0afead45ab 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractSqmPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/AbstractSqmPredicate.java @@ -6,18 +6,12 @@ */ package org.hibernate.query.sqm.tree.predicate; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Collection; import java.util.Collections; import java.util.List; import javax.persistence.criteria.Expression; -import org.hibernate.NotYetImplementedFor6Exception; -import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.tree.expression.AbstractSqmExpression; -import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.type.StandardBasicTypes; /** @@ -42,97 +36,4 @@ public abstract class AbstractSqmPredicate extends AbstractSqmExpression... values) { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmPredicate in(Collection values) { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmPredicate in(Expression> values) { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmExpression asLong() { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmExpression asInteger() { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmExpression asFloat() { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmExpression asDouble() { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmExpression asBigDecimal() { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmExpression asBigInteger() { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmExpression asString() { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public SqmExpression as(Class type) { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public List> getSelectionItems() { - return Collections.emptyList(); - } - - @Override - public JpaSelection alias(String name) { - throw new NotYetImplementedFor6Exception(); - } - - @Override - public boolean isCompoundSelection() { - return false; - } - - @Override - public String getAlias() { - throw new NotYetImplementedFor6Exception(); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java index b37c0d7776..2d24b141c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmBooleanExpressionPredicate.java @@ -10,7 +10,6 @@ import java.util.Collections; import java.util.List; import javax.persistence.criteria.Expression; -import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.tree.expression.SqmExpression; @@ -27,13 +26,13 @@ public class SqmBooleanExpressionPredicate extends AbstractNegatableSqmPredicate super( nodeBuilder ); assert booleanExpression.getNodeType() != null; - final Class expressionJavaType = ( ( BasicDomainType) booleanExpression.getNodeType() ).getJavaType(); + final Class expressionJavaType = booleanExpression.getNodeType().getExpressableJavaTypeDescriptor().getJavaTypeClass(); assert boolean.class.equals( expressionJavaType ) || Boolean.class.equals( expressionJavaType ); this.booleanExpression = booleanExpression; } - public SqmExpression getBooleanExpression() { + public SqmExpression getBooleanExpression() { return booleanExpression; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java index 009824e930..5515638487 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmComparisonPredicate.java @@ -31,7 +31,7 @@ public class SqmComparisonPredicate extends AbstractNegatableSqmPredicate { this.rightHandExpression = rightHandExpression; this.operator = operator; - final SqmExpressable expressableType = QueryHelper.highestPrecedenceType( + final SqmExpressable expressableType = QueryHelper.highestPrecedenceType( leftHandExpression.getNodeType(), rightHandExpression.getNodeType() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmPredicate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmPredicate.java index 207ed5392d..274ff1bd11 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/predicate/SqmPredicate.java @@ -17,7 +17,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; * @author Steve Ebersole */ public interface SqmPredicate - extends SqmVisitableNode, JpaPredicate, SqmExpression, DomainResultProducer { + extends SqmVisitableNode, JpaPredicate, SqmExpression { @Override default JavaTypeDescriptor getJavaTypeDescriptor(){ return BooleanTypeDescriptor.INSTANCE; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java index 96cae76263..924540656d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/AbstractSqmSelectQuery.java @@ -112,6 +112,7 @@ public abstract class AbstractSqmSelectQuery new SqmRoot<>( nodeBuilder().getDomainModel().entity( entityClass ), null, + true, nodeBuilder() ) ); @@ -125,7 +126,7 @@ public abstract class AbstractSqmSelectQuery @Override public SqmRoot from(EntityType entityType) { - return addRoot( new SqmRoot<>( (EntityDomainType) entityType, null, nodeBuilder() ) ); + return addRoot( new SqmRoot<>( (EntityDomainType) entityType, null, true, nodeBuilder() ) ); } @@ -250,6 +251,5 @@ public abstract class AbstractSqmSelectQuery sb.setLength( sb.length() - 2 ); } sqmQueryPart.appendHqlString( sb ); - sb.append( ')' ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmOrderByClause.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmOrderByClause.java index 66b94b9bc5..314410a9a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmOrderByClause.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmOrderByClause.java @@ -6,6 +6,7 @@ */ package org.hibernate.query.sqm.tree.select; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -16,7 +17,7 @@ import org.hibernate.query.sqm.tree.expression.SqmExpression; /** * @author Steve Ebersole */ -public class SqmOrderByClause { +public class SqmOrderByClause implements Serializable { private boolean hasPositionalSortItem; private List sortSpecifications; @@ -38,7 +39,7 @@ public class SqmOrderByClause { } sortSpecifications.add( sortSpecification ); if ( sortSpecification.getExpression() instanceof SqmAliasedNodeRef ) { - hasPositionalSortItem = true; + this.hasPositionalSortItem = true; } return this; } @@ -62,10 +63,11 @@ public class SqmOrderByClause { public void setSortSpecifications(List sortSpecifications) { this.sortSpecifications = new ArrayList<>(); this.sortSpecifications.addAll( sortSpecifications ); + this.hasPositionalSortItem = false; for ( int i = 0; i < sortSpecifications.size(); i++ ) { final SqmSortSpecification sortSpecification = sortSpecifications.get( i ); if ( sortSpecification.getExpression() instanceof SqmAliasedNodeRef ) { - hasPositionalSortItem = true; + this.hasPositionalSortItem = true; } } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java index de4560767e..d10c045d5c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java @@ -142,14 +142,18 @@ public class SqmQuerySpec extends SqmQueryPart } public void setGroupByClauseExpressions(List> groupByClauseExpressions) { - this.groupByClauseExpressions = groupByClauseExpressions == null - ? Collections.emptyList() - : groupByClauseExpressions; - - for ( int i = 0; i < groupByClauseExpressions.size(); i++ ) { - final SqmExpression groupItem = groupByClauseExpressions.get( i ); - if ( groupItem instanceof SqmAliasedNodeRef ) { - hasPositionalGroupItem = true; + this.hasPositionalGroupItem = false; + if ( groupByClauseExpressions == null ) { + this.groupByClauseExpressions = Collections.emptyList(); + } + else { + this.groupByClauseExpressions = groupByClauseExpressions; + for ( int i = 0; i < groupByClauseExpressions.size(); i++ ) { + final SqmExpression groupItem = groupByClauseExpressions.get( i ); + if ( groupItem instanceof SqmAliasedNodeRef ) { + this.hasPositionalGroupItem = true; + break; + } } } } @@ -191,12 +195,11 @@ public class SqmQuerySpec extends SqmQueryPart assert getSelectClause() != null; // NOTE : this call comes from JPA which inherently supports just a // single (possibly "compound") selection - getSelectClause().setSelection( (SqmSelectableNode) selection ); + getSelectClause().setSelection( (SqmSelectableNode) selection ); return this; } @Override - @SuppressWarnings("unchecked") public Set> getRoots() { assert getFromClause() != null; return new HashSet<>( getFromClause().getRoots() ); @@ -207,7 +210,7 @@ public class SqmQuerySpec extends SqmQueryPart if ( getFromClause() == null ) { setFromClause( new SqmFromClause() ); } - getFromClause().addRoot( (SqmRoot) root ); + getFromClause().addRoot( (SqmRoot) root ); return this; } @@ -221,29 +224,34 @@ public class SqmQuerySpec extends SqmQueryPart @Override public SqmQuerySpec setRestriction(JpaPredicate restriction) { - if ( getWhereClause() == null ) { - setWhereClause( new SqmWhereClause( nodeBuilder() ) ); + SqmWhereClause whereClause = getWhereClause(); + if ( whereClause == null ) { + setWhereClause( whereClause = new SqmWhereClause( nodeBuilder() ) ); } - getWhereClause().setPredicate( (SqmPredicate) restriction ); + whereClause.setPredicate( (SqmPredicate) restriction ); return this; } @Override public SqmQuerySpec setRestriction(Expression restriction) { - if ( getWhereClause() == null ) { - setWhereClause( new SqmWhereClause( nodeBuilder() ) ); + SqmWhereClause whereClause = getWhereClause(); + if ( whereClause == null ) { + setWhereClause( whereClause = new SqmWhereClause( nodeBuilder() ) ); } - getWhereClause().setPredicate( nodeBuilder().wrap( restriction ) ); + whereClause.setPredicate( nodeBuilder().wrap( restriction ) ); return this; } @Override public SqmQuerySpec setRestriction(Predicate... restrictions) { - if ( getWhereClause() == null ) { - setWhereClause( new SqmWhereClause( nodeBuilder() ) ); + SqmWhereClause whereClause = getWhereClause(); + if ( whereClause == null ) { + setWhereClause( whereClause = new SqmWhereClause( nodeBuilder() ) ); } - getWhereClause().applyPredicates( (SqmPredicate[]) restrictions ); - return null; + for ( Predicate restriction : restrictions ) { + whereClause.applyPredicate( (SqmPredicate) restriction ); + } + return this; } @Override @@ -253,8 +261,12 @@ public class SqmQuerySpec extends SqmQueryPart @Override public SqmQuerySpec setGroupingExpressions(List> groupExpressions) { + this.hasPositionalGroupItem = false; this.groupByClauseExpressions = new ArrayList<>( groupExpressions.size() ); for ( JpaExpression groupExpression : groupExpressions ) { + if ( groupExpression instanceof SqmAliasedNodeRef ) { + this.hasPositionalGroupItem = true; + } this.groupByClauseExpressions.add( (SqmExpression) groupExpression ); } return this; @@ -262,8 +274,12 @@ public class SqmQuerySpec extends SqmQueryPart @Override public SqmQuerySpec setGroupingExpressions(JpaExpression... groupExpressions) { + this.hasPositionalGroupItem = false; this.groupByClauseExpressions = new ArrayList<>( groupExpressions.length ); for ( JpaExpression groupExpression : groupExpressions ) { + if ( groupExpression instanceof SqmAliasedNodeRef ) { + this.hasPositionalGroupItem = true; + } this.groupByClauseExpressions.add( (SqmExpression) groupExpression ); } return this; @@ -354,21 +370,17 @@ public class SqmQuerySpec extends SqmQueryPart sb.append( separator ); if ( root.isCorrelated() ) { if ( root.containsOnlyInnerJoins() ) { - appendJoins( root, root.getCorrelationParent().getExplicitAlias(), sb ); + appendJoins( root, root.getCorrelationParent().resolveAlias(), sb ); } else { - sb.append( root.getCorrelationParent().getExplicitAlias() ); - if ( root.getExplicitAlias() != null ) { - sb.append( ' ' ).append( root.getExplicitAlias() ); - } + sb.append( root.getCorrelationParent().resolveAlias() ); + sb.append( ' ' ).append( root.resolveAlias() ); appendJoins( root, sb ); } } else { sb.append( root.getEntityName() ); - if ( root.getExplicitAlias() != null ) { - sb.append( ' ' ).append( root.getExplicitAlias() ); - } + sb.append( ' ' ).append( root.resolveAlias() ); appendJoins( root, sb ); } separator = ", "; @@ -415,11 +427,9 @@ public class SqmQuerySpec extends SqmQueryPart } if ( sqmJoin instanceof SqmAttributeJoin ) { final SqmAttributeJoin attributeJoin = (SqmAttributeJoin) sqmJoin; - sb.append( sqmFrom.getExplicitAlias() ).append( '.' ); + sb.append( sqmFrom.resolveAlias() ).append( '.' ); sb.append( (attributeJoin).getAttribute().getName() ); - if ( sqmJoin.getExplicitAlias() != null ) { - sb.append( ' ' ).append( sqmJoin.getExplicitAlias() ); - } + sb.append( ' ' ).append( sqmJoin.resolveAlias() ); if ( attributeJoin.getJoinPredicate() != null ) { sb.append( " on " ); attributeJoin.getJoinPredicate().appendHqlString( sb ); @@ -428,17 +438,13 @@ public class SqmQuerySpec extends SqmQueryPart } else if ( sqmJoin instanceof SqmCrossJoin ) { sb.append( ( (SqmCrossJoin) sqmJoin ).getEntityName() ); - if ( sqmJoin.getExplicitAlias() != null ) { - sb.append( ' ' ).append( sqmJoin.getExplicitAlias() ); - } + sb.append( ' ' ).append( sqmJoin.resolveAlias() ); 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() ); - } + sb.append( ' ' ).append( sqmJoin.resolveAlias() ); if ( sqmEntityJoin.getJoinPredicate() != null ) { sb.append( " on " ); sqmEntityJoin.getJoinPredicate().appendHqlString( sb ); @@ -458,9 +464,7 @@ public class SqmQuerySpec extends SqmQueryPart sb.append( separator ); sb.append( correlationPrefix ).append( '.' ); sb.append( ( (SqmAttributeJoin) sqmJoin ).getAttribute().getName() ); - if ( sqmJoin.getExplicitAlias() != null ) { - sb.append( ' ' ).append( sqmJoin.getExplicitAlias() ); - } + sb.append( ' ' ).append( sqmJoin.resolveAlias() ); appendJoins( sqmJoin, sb ); separator = ", "; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java index 3f0fa03d01..aa691d81bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSelectStatement.java @@ -6,15 +6,11 @@ */ package org.hibernate.query.sqm.tree.select; -import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.function.Supplier; +import javax.persistence.Tuple; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Order; import javax.persistence.criteria.ParameterExpression; @@ -22,17 +18,15 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Selection; import org.hibernate.query.FetchClauseType; -import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.query.criteria.JpaCriteriaQuery; import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaSelection; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SqmQuerySource; +import org.hibernate.query.sqm.internal.SqmUtil; import org.hibernate.query.sqm.tree.SqmStatement; -import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter; import org.hibernate.query.sqm.tree.expression.SqmExpression; -import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.from.SqmFromClause; import org.hibernate.query.sqm.tree.jpa.ParameterCollector; @@ -51,7 +45,7 @@ public class SqmSelectStatement extends AbstractSqmSelectQuery implements } public SqmSelectStatement(SqmQuerySource querySource, NodeBuilder nodeBuilder) { - super( (Class) null, nodeBuilder ); + super( null, nodeBuilder ); this.querySource = querySource; } @@ -149,131 +143,7 @@ public class SqmSelectStatement extends AbstractSqmSelectQuery implements @Override public ParameterResolutions resolveParameters() { - if ( querySource == SqmQuerySource.CRITERIA ) { - final CriteriaParameterCollector parameterCollector = new CriteriaParameterCollector(); - - ParameterCollector.collectParameters( - this, - parameterCollector::process, - nodeBuilder().getServiceRegistry() - ); - - return parameterCollector.makeResolution(); - } - else { - return new ParameterResolutions() { - @Override - public Set> getSqmParameters() { - return parameters == null ? Collections.emptySet() : Collections.unmodifiableSet( parameters ); - } - - @Override - public Map, Supplier>> getJpaCriteriaParamResolutions() { - return Collections.emptyMap(); - } - }; - } - } - - private static class CriteriaParameterCollector { - private Set> sqmParameters; - private Map, List>> jpaCriteriaParamResolutions; - - public void process(SqmParameter parameter) { - if ( sqmParameters == null ) { - sqmParameters = new HashSet<>(); - } - - if ( parameter instanceof SqmJpaCriteriaParameterWrapper ) { - if ( jpaCriteriaParamResolutions == null ) { - jpaCriteriaParamResolutions = new IdentityHashMap<>(); - } - - final SqmJpaCriteriaParameterWrapper wrapper = (SqmJpaCriteriaParameterWrapper) parameter; - final JpaCriteriaParameter criteriaParameter = wrapper.getJpaCriteriaParameter(); - - final List> sqmParametersForCriteriaParameter = jpaCriteriaParamResolutions.computeIfAbsent( - criteriaParameter, - jcp -> new ArrayList<>() - ); - - sqmParametersForCriteriaParameter.add( wrapper ); - sqmParameters.add( wrapper ); - } - else if ( parameter instanceof JpaCriteriaParameter ) { - throw new UnsupportedOperationException(); -// final JpaCriteriaParameter criteriaParameter = (JpaCriteriaParameter) parameter; -// -// if ( jpaCriteriaParamResolutions == null ) { -// jpaCriteriaParamResolutions = new IdentityHashMap<>(); -// } -// -// final List> sqmParametersForCriteriaParameter = jpaCriteriaParamResolutions.computeIfAbsent( -// criteriaParameter, -// jcp -> new ArrayList<>() -// ); -// -// final SqmJpaCriteriaParameterWrapper wrapper = new SqmJpaCriteriaParameterWrapper( -// criteriaParameter.getHibernateType(), -// criteriaParameter, -// criteriaParameter.nodeBuilder() -// ); -// -// sqmParametersForCriteriaParameter.add( wrapper ); -// sqmParameters.add( wrapper ); - } - else { - sqmParameters.add( parameter ); - } - } - - private ParameterResolutions makeResolution() { - return new ParameterResolutionsImpl( - sqmParameters == null ? Collections.emptySet() : sqmParameters, - jpaCriteriaParamResolutions == null ? Collections.emptyMap() : jpaCriteriaParamResolutions - ); - } - } - - private static class ParameterResolutionsImpl implements ParameterResolutions { - private final Set> sqmParameters; - private final Map, Supplier>> jpaCriteriaParamResolutions; - - public ParameterResolutionsImpl( - Set> sqmParameters, - Map, List>> jpaCriteriaParamResolutions) { - this.sqmParameters = sqmParameters; - - if ( jpaCriteriaParamResolutions == null || jpaCriteriaParamResolutions.isEmpty() ) { - this.jpaCriteriaParamResolutions = Collections.emptyMap(); - } - else { - this.jpaCriteriaParamResolutions = new IdentityHashMap<>( CollectionHelper.determineProperSizing( jpaCriteriaParamResolutions ) ); - for ( Map.Entry, List>> entry : jpaCriteriaParamResolutions.entrySet() ) { - final Iterator> itr = entry.getValue().iterator(); - this.jpaCriteriaParamResolutions.put( - entry.getKey(), - () -> { - if ( itr.hasNext() ) { - return itr.next(); - } - throw new IllegalStateException( "SqmJpaCriteriaParameterWrapper references for JpaCriteriaParameter [" + entry.getKey() + "] already exhausted" ); - } - ); - - } - } - } - - @Override - public Set> getSqmParameters() { - return sqmParameters; - } - - @Override - public Map, Supplier>> getJpaCriteriaParamResolutions() { - return jpaCriteriaParamResolutions; - } + return SqmUtil.resolveParameters( this ); } @Override @@ -282,7 +152,7 @@ public class SqmSelectStatement extends AbstractSqmSelectQuery implements } @Override - public void addParameter(SqmParameter parameter) { + public void addParameter(SqmParameter parameter) { if ( parameters == null ) { parameters = new HashSet<>(); } @@ -308,12 +178,15 @@ public class SqmSelectStatement extends AbstractSqmSelectQuery implements // // for a "finalized" set of parameters, use `#resolveParameters` instead assert querySource == SqmQuerySource.CRITERIA; - return (Set) getSqmParameters(); + return (Set>) (Set) getSqmParameters(); } @Override @SuppressWarnings("unchecked") public SqmSelectStatement select(Selection selection) { + if ( nodeBuilder().getDomainModel().getJpaCompliance().isJpaQueryComplianceEnabled() ) { + checkSelectionIsJpaCompliant( selection ); + } getQuerySpec().setSelection( (JpaSelection) selection ); if ( getResultType() == null ) { setResultType( (Class) selection.getJavaType() ); @@ -322,46 +195,115 @@ public class SqmSelectStatement extends AbstractSqmSelectQuery implements } @Override + @SuppressWarnings("unchecked") public SqmSelectStatement multiselect(Selection... selections) { - for ( Selection selection : selections ) { - getQuerySpec().getSelectClause().add( (SqmExpression) selection, selection.getAlias() ); + if ( nodeBuilder().getDomainModel().getJpaCompliance().isJpaQueryComplianceEnabled() ) { + for ( Selection selection : selections ) { + checkSelectionIsJpaCompliant( selection ); + } } - if ( getResultType() == null ) { - setResultType( (Class) Object[].class ); + final Selection resultSelection; + Class resultType = getResultType(); + if ( resultType == null ) { + setResultType( resultType = (Class) Object[].class ); } + if ( Tuple.class.isAssignableFrom( resultType ) ) { + resultSelection = ( Selection ) nodeBuilder().tuple( selections ); + } + else if ( resultType.isArray() ) { + resultSelection = nodeBuilder().array( resultType, selections ); + } + else if ( Object.class.equals( resultType ) ) { + switch ( selections.length ) { + case 0: { + throw new IllegalArgumentException( + "empty selections passed to criteria query typed as Object" + ); + } + case 1: { + resultSelection = ( Selection ) selections[0]; + break; + } + default: { + resultSelection = ( Selection ) nodeBuilder().array( selections ); + } + } + } + else { + resultSelection = nodeBuilder().construct( resultType, selections ); + } + getQuerySpec().getSelectClause().setSelection( (SqmSelectableNode) resultSelection ); return this; } @Override + @SuppressWarnings("unchecked") public SqmSelectStatement multiselect(List> selectionList) { - for ( Selection selection : selectionList ) { - getQuerySpec().getSelectClause().add( (SqmExpression) selection, selection.getAlias() ); + if ( nodeBuilder().getDomainModel().getJpaCompliance().isJpaQueryComplianceEnabled() ) { + for ( Selection selection : selectionList ) { + checkSelectionIsJpaCompliant( selection ); + } } - if ( getResultType() == null ) { - setResultType( (Class) Object[].class ); + final Selection resultSelection; + Class resultType = getResultType(); + if ( resultType == null ) { + setResultType( resultType = (Class) Object[].class ); } + final List> jpaSelectionList = (List>) (List) selectionList; + if ( Tuple.class.isAssignableFrom( resultType ) ) { + resultSelection = ( Selection ) nodeBuilder().tuple( jpaSelectionList ); + } + else if ( resultType.isArray() ) { + resultSelection = nodeBuilder().array( resultType, jpaSelectionList ); + } + else if ( Object.class.equals( resultType ) ) { + switch ( selectionList.size() ) { + case 0: { + throw new IllegalArgumentException( + "empty selections passed to criteria query typed as Object" + ); + } + case 1: { + resultSelection = ( Selection ) selectionList.get( 0 ); + break; + } + default: { + resultSelection = ( Selection ) nodeBuilder().array( jpaSelectionList ); + } + } + } + else { + resultSelection = nodeBuilder().construct( resultType, jpaSelectionList ); + } + getQuerySpec().getSelectClause().setSelection( (SqmSelectableNode) resultSelection ); return this; } + private void checkSelectionIsJpaCompliant(Selection selection) { + if ( selection instanceof SqmSubQuery ) { + throw new IllegalStateException( + "The JPA specification does not support subqueries in select clauses. " + + "Please disable the JPA query compliance if you want to use this feature." ); + } + } + @Override public SqmSelectStatement orderBy(Order... orders) { - if ( getQueryPart().getOrderByClause() == null ) { - getQueryPart().setOrderByClause( new SqmOrderByClause() ); - } + final SqmOrderByClause sqmOrderByClause = new SqmOrderByClause( orders.length ); for ( Order order : orders ) { - getQueryPart().getOrderByClause().addSortSpecification( (SqmSortSpecification) order ); + sqmOrderByClause.addSortSpecification( (SqmSortSpecification) order ); } + getQueryPart().setOrderByClause( sqmOrderByClause ); return this; } @Override public SqmSelectStatement orderBy(List orders) { - if ( getQueryPart().getOrderByClause() == null ) { - getQueryPart().setOrderByClause( new SqmOrderByClause() ); - } + final SqmOrderByClause sqmOrderByClause = new SqmOrderByClause( orders.size() ); for ( Order order : orders ) { - getQueryPart().getOrderByClause().addSortSpecification( (SqmSortSpecification) order ); + sqmOrderByClause.addSortSpecification( (SqmSortSpecification) order ); } + getQueryPart().setOrderByClause( sqmOrderByClause ); return this; } @@ -402,6 +344,7 @@ public class SqmSelectStatement extends AbstractSqmSelectQuery implements @Override public JpaExpression getOffset() { + //noinspection unchecked return (JpaExpression) getQueryPart().getOffset(); } @@ -419,6 +362,7 @@ public class SqmSelectStatement extends AbstractSqmSelectQuery implements @Override public JpaExpression getFetch() { + //noinspection unchecked return (JpaExpression) getQueryPart().getFetch(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSubQuery.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSubQuery.java index 7eab038a17..18b8cef45a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSubQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmSubQuery.java @@ -12,6 +12,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import javax.persistence.criteria.AbstractQuery; import javax.persistence.criteria.CollectionJoin; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Join; @@ -83,7 +84,7 @@ public class SqmSubQuery extends AbstractSqmSelectQuery implements SqmSele public SqmSubQuery( SqmQuery parent, NodeBuilder builder) { - super( (Class) null, builder ); + super( null, builder ); this.parent = parent; } @@ -94,8 +95,12 @@ public class SqmSubQuery extends AbstractSqmSelectQuery implements SqmSele @Override public SqmSelectQuery getParent() { + final SqmQuery containingQuery = getContainingQuery(); // JPA only allows sub-queries on select queries - return (SqmSelectQuery) getContainingQuery(); + if ( !(containingQuery instanceof AbstractQuery) ) { + throw new IllegalStateException( "Cannot call getParent on update/delete criterias" ); + } + return (SqmSelectQuery) containingQuery; } @Override @@ -110,15 +115,19 @@ public class SqmSubQuery extends AbstractSqmSelectQuery implements SqmSele } @Override - @SuppressWarnings("unchecked") public SqmSubQuery select(Expression expression) { - getQuerySpec().setSelection( (JpaSelection) expression ); + final SqmQuerySpec querySpec = getQuerySpec(); + if ( querySpec.getSelectClause() == null ) { + querySpec.setSelectClause( new SqmSelectClause( false, 1, nodeBuilder() ) ); + } + //noinspection unchecked + querySpec.setSelection( (JpaSelection) expression ); return this; } @Override public SqmExpression getSelection() { - return (SqmExpression) super.getSelection(); + return this; } @Override @@ -177,9 +186,7 @@ public class SqmSubQuery extends AbstractSqmSelectQuery implements SqmSele @Override public SqmRoot correlate(Root parentRoot) { final SqmCorrelatedRoot correlated = ( (SqmRoot) parentRoot ).createCorrelation(); - if ( getQuerySpec().getFromClause() != null ) { - getQuerySpec().getFromClause().addRoot( correlated ); - } + getQuerySpec().addRoot( correlated ); return correlated; } @@ -199,63 +206,49 @@ public class SqmSubQuery extends AbstractSqmSelectQuery implements SqmSele } } final SqmCorrelatedSingularJoin correlated = ( (SqmSingularJoin) join ).createCorrelation(); - if ( getQuerySpec().getFromClause() != null ) { - getQuerySpec().getFromClause().addRoot( correlated.getCorrelatedRoot() ); - } + getQuerySpec().addRoot( correlated.getCorrelatedRoot() ); return correlated; } @Override public SqmBagJoin correlate(CollectionJoin parentCollection) { final SqmCorrelatedBagJoin correlated = ( (SqmBagJoin) parentCollection ).createCorrelation(); - if ( getQuerySpec().getFromClause() != null ) { - getQuerySpec().getFromClause().addRoot( correlated.getCorrelatedRoot() ); - } + getQuerySpec().addRoot( correlated.getCorrelatedRoot() ); return correlated; } @Override public SqmSetJoin correlate(SetJoin parentSet) { final SqmCorrelatedSetJoin correlated = ( (SqmSetJoin) parentSet ).createCorrelation(); - if ( getQuerySpec().getFromClause() != null ) { - getQuerySpec().getFromClause().addRoot( correlated.getCorrelatedRoot() ); - } + getQuerySpec().addRoot( correlated.getCorrelatedRoot() ); return correlated; } @Override public SqmListJoin correlate(ListJoin parentList) { final SqmCorrelatedListJoin correlated = ( (SqmListJoin) parentList ).createCorrelation(); - if ( getQuerySpec().getFromClause() != null ) { - getQuerySpec().getFromClause().addRoot( correlated.getCorrelatedRoot() ); - } + getQuerySpec().addRoot( correlated.getCorrelatedRoot() ); return correlated; } @Override public SqmMapJoin correlate(MapJoin parentMap) { final SqmCorrelatedMapJoin correlated = ( (SqmMapJoin) parentMap ).createCorrelation(); - if ( getQuerySpec().getFromClause() != null ) { - getQuerySpec().getFromClause().addRoot( correlated.getCorrelatedRoot() ); - } + getQuerySpec().addRoot( correlated.getCorrelatedRoot() ); return correlated; } @Override public SqmCrossJoin correlate(SqmCrossJoin parentCrossJoin) { final SqmCorrelatedCrossJoin correlated = parentCrossJoin.createCorrelation(); - if ( getQuerySpec().getFromClause() != null ) { - getQuerySpec().getFromClause().addRoot( correlated.getCorrelatedRoot() ); - } + getQuerySpec().addRoot( correlated.getCorrelatedRoot() ); return correlated; } @Override public SqmEntityJoin correlate(SqmEntityJoin parentEntityJoin) { final SqmCorrelatedEntityJoin correlated = parentEntityJoin.createCorrelation(); - if ( getQuerySpec().getFromClause() != null ) { - getQuerySpec().getFromClause().addRoot( correlated.getCorrelatedRoot() ); - } + getQuerySpec().addRoot( correlated.getCorrelatedRoot() ); return correlated; } @@ -300,22 +293,22 @@ public class SqmSubQuery extends AbstractSqmSelectQuery implements SqmSele } @Override - public SqmInPredicate in(Object... values) { + public SqmInPredicate in(Object... values) { return nodeBuilder().in( this, values ); } @Override - public SqmInPredicate in(Expression... values) { + public SqmInPredicate in(Expression... values) { return nodeBuilder().in( this, values ); } @Override - public SqmInPredicate in(Collection values) { + public SqmInPredicate in(Collection values) { return nodeBuilder().in( this, values ); } @Override - public SqmInPredicate in(Expression> values) { + public SqmInPredicate in(Expression> values) { return nodeBuilder().in( this, values ); } @@ -333,43 +326,36 @@ public class SqmSubQuery extends AbstractSqmSelectQuery implements SqmSele @Override public SqmExpression asLong() { - //noinspection unchecked return castAs( StandardBasicTypes.LONG ); } @Override public SqmExpression asInteger() { - //noinspection unchecked return castAs( StandardBasicTypes.INTEGER ); } @Override public SqmExpression asFloat() { - //noinspection unchecked return castAs( StandardBasicTypes.FLOAT ); } @Override public SqmExpression asDouble() { - //noinspection unchecked return castAs( StandardBasicTypes.DOUBLE ); } @Override public SqmExpression asBigDecimal() { - //noinspection unchecked return castAs( StandardBasicTypes.BIG_DECIMAL ); } @Override public SqmExpression asBigInteger() { - //noinspection unchecked return castAs( StandardBasicTypes.BIG_INTEGER ); } @Override public SqmExpression asString() { - //noinspection unchecked return castAs( StandardBasicTypes.STRING ); } @@ -388,7 +374,6 @@ public class SqmSubQuery extends AbstractSqmSelectQuery implements SqmSele @Override public Class getJavaType() { - //noinspection unchecked return getResultType(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/update/SqmUpdateStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/update/SqmUpdateStatement.java index 41adb1d9d5..bd60960907 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/update/SqmUpdateStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/update/SqmUpdateStatement.java @@ -10,35 +10,27 @@ import java.util.List; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.SingularAttribute; -import org.hibernate.NotYetImplementedFor6Exception; -import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.query.criteria.JpaCriteriaUpdate; -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.internal.SqmCriteriaNodeBuilder; -import org.hibernate.query.sqm.tree.AbstractSqmDmlStatement; +import org.hibernate.query.sqm.tree.AbstractSqmRestrictedDmlStatement; import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement; import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.from.SqmRoot; -import org.hibernate.query.sqm.tree.predicate.SqmPredicate; -import org.hibernate.query.sqm.tree.predicate.SqmWhereClause; /** * @author Steve Ebersole */ public class SqmUpdateStatement - extends AbstractSqmDmlStatement + extends AbstractSqmRestrictedDmlStatement implements SqmDeleteOrUpdateStatement, JpaCriteriaUpdate { private boolean versioned; private SqmSetClause setClause; - private SqmWhereClause whereClause; public SqmUpdateStatement(SqmRoot target, NodeBuilder nodeBuilder) { this( target, SqmQuerySource.HQL, nodeBuilder ); @@ -53,6 +45,7 @@ public class SqmUpdateStatement new SqmRoot<>( nodeBuilder.getDomainModel().entity( targetEntity ), null, + false, nodeBuilder ), SqmQuerySource.CRITERIA, @@ -68,71 +61,34 @@ public class SqmUpdateStatement this.setClause = setClause; } - @Override - public SqmWhereClause getWhereClause() { - return whereClause; - } - - @Override - public void applyPredicate(SqmPredicate predicate) { - if ( predicate == null ) { - return; - } - - if ( whereClause == null ) { - whereClause = new SqmWhereClause( nodeBuilder() ); - } - - whereClause.applyPredicate( predicate ); - } - - public void setWhereClause(SqmWhereClause whereClause) { - this.whereClause = whereClause; - } - - @Override - public Root from(Class entityClass) { - final EntityDomainType entity = nodeBuilder().getDomainModel().entity( entityClass ); - SqmRoot root = new SqmRoot<>( entity, null, nodeBuilder() ); - setTarget( root ); - return root; - } - - @Override - public Root from(EntityType entity) { - SqmRoot root = new SqmRoot<>( (EntityDomainType) entity, null, nodeBuilder() ); - setTarget( root ); - return root; - } - - @Override - public Root getRoot() { - return getTarget(); - } - @Override public SqmUpdateStatement set(SingularAttribute attribute, X value) { - throw new NotYetImplementedFor6Exception(); + applyAssignment( getTarget().get( attribute ), nodeBuilder().value( value ) ); + return this; } @Override public SqmUpdateStatement set(SingularAttribute attribute, Expression value) { - throw new NotYetImplementedFor6Exception(); + applyAssignment( getTarget().get( attribute ), (SqmExpression) value ); + return this; } @Override public SqmUpdateStatement set(Path attribute, X value) { - throw new NotYetImplementedFor6Exception(); + applyAssignment( (SqmPath) attribute, nodeBuilder().value( value ) ); + return this; } @Override public SqmUpdateStatement set(Path attribute, Expression value) { - throw new NotYetImplementedFor6Exception(); + applyAssignment( (SqmPath) attribute, (SqmExpression) value ); + return this; } @Override public SqmUpdateStatement set(String attributeName, Object value) { - throw new NotYetImplementedFor6Exception(); + applyAssignment( getTarget().get( attributeName ), nodeBuilder().value( value ) ); + return this; } @Override @@ -154,24 +110,16 @@ public class SqmUpdateStatement @Override public SqmUpdateStatement where(Expression restriction) { - getWhereClause().setPredicate( (SqmPredicate) restriction ); + setWhere( restriction ); return this; } @Override public SqmUpdateStatement where(Predicate... restrictions) { - getWhereClause().setPredicate( null ); - for ( Predicate restriction : restrictions ) { - getWhereClause().applyPredicate( (SqmPredicate) restriction ); - } + setWhere( restrictions ); return this; } - @Override - public JpaPredicate getRestriction() { - return whereClause == null ? null : whereClause.getPredicate(); - } - @Override public X accept(SemanticQueryWalker walker) { return walker.visitUpdateStatement( this ); @@ -191,9 +139,7 @@ public class SqmUpdateStatement sb.append( "versioned " ); } sb.append( getTarget().getEntityName() ); - if ( getTarget().getExplicitAlias() != null ) { - sb.append( ' ' ).append( getTarget().getExplicitAlias() ); - } + sb.append( ' ' ).append( getTarget().resolveAlias() ); sb.append( " set " ); final List assignments = setClause.getAssignments(); appendAssignment( assignments.get( 0 ), sb ); @@ -202,10 +148,7 @@ public class SqmUpdateStatement appendAssignment( assignments.get( i ), sb ); } - if ( whereClause != null && whereClause.getPredicate() != null ) { - sb.append( " where " ); - whereClause.getPredicate().appendHqlString( sb ); - } + super.appendHqlString( sb ); } private static void appendAssignment(SqmAssignment sqmAssignment, StringBuilder sb) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstNodeRenderingMode.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstNodeRenderingMode.java index c6e0ef47db..1ecfabea41 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstNodeRenderingMode.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstNodeRenderingMode.java @@ -33,6 +33,12 @@ public enum SqlAstNodeRenderingMode { */ INLINE_PARAMETERS, + /** + * Render all nested parameters as literals. + * All parameters within the {@link org.hibernate.sql.ast.tree.SqlAstNode} are rendered as literals. + */ + INLINE_ALL_PARAMETERS, + /** * Don't render plain parameters. Render it as literal or as expression. * If the {@link org.hibernate.sql.ast.tree.SqlAstNode} to render is a parameter, diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstWalker.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstWalker.java index 16931f9b86..2876b28d16 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/SqlAstWalker.java @@ -42,6 +42,7 @@ import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReferenceJoin; import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.ast.tree.predicate.BetweenPredicate; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.ExistsPredicate; import org.hibernate.sql.ast.tree.predicate.FilterPredicate; @@ -147,6 +148,8 @@ public interface SqlAstWalker { void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression); + void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate); + void visitBetweenPredicate(BetweenPredicate betweenPredicate); void visitFilterPredicate(FilterPredicate filterPredicate); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java index 2bb591032b..964a23405b 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java @@ -9,6 +9,7 @@ package org.hibernate.sql.ast.spi; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; +import java.util.BitSet; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -19,6 +20,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.TimeZone; +import java.util.function.Consumer; import java.util.function.Function; import org.hibernate.LockMode; @@ -66,7 +68,6 @@ import org.hibernate.query.SortOrder; import org.hibernate.query.UnaryArithmeticOperator; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; -import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation; import org.hibernate.query.sqm.tree.expression.Conversion; import org.hibernate.sql.ast.Clause; @@ -97,7 +98,6 @@ 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; -import org.hibernate.sql.ast.tree.expression.FunctionExpression; import org.hibernate.sql.ast.tree.expression.JdbcLiteral; import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.expression.Literal; @@ -122,6 +122,7 @@ import org.hibernate.sql.ast.tree.from.VirtualTableGroup; import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.ast.tree.insert.Values; import org.hibernate.sql.ast.tree.predicate.BetweenPredicate; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.ExistsPredicate; import org.hibernate.sql.ast.tree.predicate.FilterPredicate; @@ -161,7 +162,6 @@ import org.hibernate.sql.results.jdbc.internal.JdbcValuesMappingProducerStandard import org.hibernate.type.BasicType; import org.hibernate.type.IntegerType; import org.hibernate.type.StandardBasicTypes; -import org.hibernate.type.StringType; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; @@ -207,7 +207,7 @@ public abstract class AbstractSqlAstTranslator implemen private transient AbstractSqmSelfRenderingFunctionDescriptor castFunction; private transient LazySessionWrapperOptions lazySessionWrapperOptions; - private boolean inlineParameters; + private SqlAstNodeRenderingMode parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT; private Map appliedParameterBindings = Collections.emptyMap(); private JdbcParameterBindings jdbcParameterBindings; @@ -350,6 +350,10 @@ public abstract class AbstractSqlAstTranslator implemen return statement; } + protected SqlAstNodeRenderingMode getParameterRenderingMode() { + return parameterRenderingMode; + } + @Override public boolean supportsFilterClause() { // By default we report false because not many dialects support this @@ -506,9 +510,12 @@ public abstract class AbstractSqlAstTranslator implemen return binding.getBindValue(); } - protected boolean isCurrentlyInPredicate() { - return clauseStack.getCurrent() == Clause.WHERE - || clauseStack.getCurrent() == Clause.HAVING; + protected Expression getLeftHandExpression(Predicate predicate) { + if ( predicate instanceof NullnessPredicate ) { + return ( (NullnessPredicate) predicate ).getExpression(); + } + assert predicate instanceof ComparisonPredicate; + return ( (ComparisonPredicate) predicate ).getLeftHandExpression(); } protected boolean inOverClause() { @@ -835,13 +842,13 @@ public abstract class AbstractSqlAstTranslator implemen firstPass = false; } else { - appendSql( ", " ); + appendSql( COMA_SEPARATOR_CHAR ); } final List columnReferences = assignment.getAssignable().getColumnReferences(); if ( columnReferences.size() == 1 ) { columnReferences.get( 0 ).accept( this ); - appendSql( " = " ); + appendSql( '=' ); final Expression assignedValue = assignment.getAssignedValue(); final SqlTuple sqlTuple = SqlTupleContainer.getSqlTuple( assignedValue ); if ( sqlTuple != null ) { @@ -855,12 +862,11 @@ public abstract class AbstractSqlAstTranslator implemen } } else { - appendSql( " (" ); + appendSql( OPEN_PARENTHESIS ); for ( ColumnReference columnReference : columnReferences ) { columnReference.accept( this ); } - appendSql( ") " ); - appendSql( " = " ); + appendSql( ")=" ); assignment.getAssignedValue().accept( this ); } } @@ -886,7 +892,7 @@ public abstract class AbstractSqlAstTranslator implemen appendSql( "insert into " ); appendSql( statement.getTargetTable().getTableExpression() ); - appendSql( " (" ); + appendSql( OPEN_PARENTHESIS ); boolean firstPass = true; final List targetColumnReferences = statement.getTargetColumnReferences(); @@ -899,7 +905,7 @@ public abstract class AbstractSqlAstTranslator implemen firstPass = false; } else { - appendSql( ", " ); + appendSql( COMA_SEPARATOR_CHAR ); } appendSql( targetColumnReference.getColumnExpression() ); @@ -931,7 +937,7 @@ public abstract class AbstractSqlAstTranslator implemen firstTuple = false; } else { - appendSql( ", " ); + appendSql( COMA_SEPARATOR_CHAR ); } appendSql( " (" ); boolean firstExpr = true; @@ -940,11 +946,11 @@ public abstract class AbstractSqlAstTranslator implemen firstExpr = false; } else { - appendSql( ", " ); + appendSql( COMA_SEPARATOR_CHAR ); } expression.accept( this ); } - appendSql( ")" ); + appendSql( ')' ); } } finally { @@ -1244,7 +1250,7 @@ public abstract class AbstractSqlAstTranslator implemen for ( int i = 0; i < size; i++ ) { appendSql( separator ); appendSql( returningColumns.get( i ).getColumnExpression() ); - separator = ", "; + separator = COMA_SEPARATOR; } } @@ -1271,7 +1277,7 @@ public abstract class AbstractSqlAstTranslator implemen for ( CteColumn cteColumn : cte.getCteTable().getCteColumns() ) { appendSql( separator ); appendSql( cteColumn.getColumnExpression() ); - separator = ", "; + separator = COMA_SEPARATOR; } appendSql( ") as " ); @@ -1280,7 +1286,7 @@ public abstract class AbstractSqlAstTranslator implemen renderMaterializationHint( cte.getMaterialization() ); } - appendSql( '(' ); + appendSql( OPEN_PARENTHESIS ); cte.getCteDefinition().accept( this ); appendSql( ')' ); @@ -1288,9 +1294,9 @@ public abstract class AbstractSqlAstTranslator implemen renderSearchClause( cte ); renderCycleClause( cte ); - mainSeparator = ", "; + mainSeparator = COMA_SEPARATOR; } - appendSql( ' ' ); + appendSql( WHITESPACE ); } protected void renderMaterializationHint(CteMaterialization materialization) { @@ -1328,7 +1334,7 @@ public abstract class AbstractSqlAstTranslator implemen } } } - separator = ", "; + separator = COMA_SEPARATOR; } } } @@ -1341,7 +1347,7 @@ public abstract class AbstractSqlAstTranslator implemen for ( CteColumn cycleColumn : cte.getCycleColumns() ) { appendSql( separator ); appendSql( cycleColumn.getColumnExpression() ); - separator = ", "; + separator = COMA_SEPARATOR; } appendSql( " set " ); appendSql( cte.getCycleMarkColumn().getColumnExpression() ); @@ -1349,7 +1355,7 @@ public abstract class AbstractSqlAstTranslator implemen appendSql( cte.getCycleValue() ); appendSql( "' default '" ); appendSql( cte.getNoCycleValue() ); - appendSql( "'" ); + appendSql( '\'' ); } } @@ -1379,7 +1385,7 @@ public abstract class AbstractSqlAstTranslator implemen // order by and offset fetch clause, so we must do row counting on the query group level if ( queryPartForRowNumbering == queryGroup ) { this.needsSelectAliases = true; - queryGroupAlias = "grp_" + queryGroupAliasCounter + "_"; + queryGroupAlias = "grp_" + queryGroupAliasCounter + '_'; queryGroupAliasCounter++; appendSql( "select " ); appendSql( queryGroupAlias ); @@ -1412,7 +1418,7 @@ public abstract class AbstractSqlAstTranslator implemen } queryPartStack.push( queryGroup ); final List queryParts = queryGroup.getQueryParts(); - final String setOperatorString = " " + queryGroup.getSetOperator().sqlString() + " "; + final String setOperatorString = ' ' + queryGroup.getSetOperator().sqlString() + ' '; String separator = ""; for ( int i = 0; i < queryParts.size(); i++ ) { appendSql( separator ); @@ -1463,7 +1469,7 @@ public abstract class AbstractSqlAstTranslator implemen // If the parent is a query group with a fetch clause, // or if the database does not support simple query grouping, we must use a select wrapper if ( !supportsSimpleQueryGrouping() || currentQueryPart.hasOffsetOrFetchClause() ) { - queryGroupAlias = " grp_" + queryGroupAliasCounter + "_"; + queryGroupAlias = " grp_" + queryGroupAliasCounter + '_'; queryGroupAliasCounter++; appendSql( "select" ); appendSql( queryGroupAlias ); @@ -1476,7 +1482,7 @@ public abstract class AbstractSqlAstTranslator implemen } queryPartStack.push( querySpec ); if ( needsParenthesis ) { - appendSql( '(' ); + appendSql( OPEN_PARENTHESIS ); } visitSelectClause( querySpec.getSelectClause() ); visitFromClause( querySpec.getFromClause() ); @@ -1491,7 +1497,7 @@ public abstract class AbstractSqlAstTranslator implemen } if ( needsParenthesis ) { - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); appendSql( queryGroupAlias ); } } @@ -1613,37 +1619,60 @@ public abstract class AbstractSqlAstTranslator implemen List partitionExpressions, SelectItemReferenceStrategy referenceStrategy) { final Function resolveAliasExpression; + final boolean inlineParametersOfAliasedExpressions; switch ( referenceStrategy ) { case POSITION: resolveAliasExpression = Function.identity(); + inlineParametersOfAliasedExpressions = false; break; case ALIAS: resolveAliasExpression = this::resolveExpressionToAlias; + inlineParametersOfAliasedExpressions = false; break; case EXPRESSION: default: resolveAliasExpression = this::resolveAliasedExpression; + inlineParametersOfAliasedExpressions = true; break; } - visitPartitionExpressions( partitionExpressions, resolveAliasExpression ); + visitPartitionExpressions( partitionExpressions, resolveAliasExpression, inlineParametersOfAliasedExpressions ); } protected final void visitPartitionExpressions( List partitionExpressions, - Function resolveAliasExpression) { + Function resolveAliasExpression, + boolean inlineParametersOfAliasedExpressions) { String separator = ""; for ( Expression partitionExpression : partitionExpressions ) { final SqlTuple sqlTuple = SqlTupleContainer.getSqlTuple( partitionExpression ); if ( sqlTuple != null ) { for ( Expression e : sqlTuple.getExpressions() ) { appendSql( separator ); - renderPartitionItem( resolveAliasExpression.apply( e ) ); + final Expression resolved = resolveAliasExpression.apply( e ); + if ( inlineParametersOfAliasedExpressions && resolved != e ) { + final SqlAstNodeRenderingMode original = parameterRenderingMode; + parameterRenderingMode = SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS; + renderPartitionItem( resolved ); + parameterRenderingMode = original; + } + else { + renderPartitionItem( resolved ); + } separator = COMA_SEPARATOR; } } else { appendSql( separator ); - renderPartitionItem( resolveAliasExpression.apply( partitionExpression ) ); + final Expression resolved = resolveAliasExpression.apply( partitionExpression ); + if ( inlineParametersOfAliasedExpressions && resolved != partitionExpression ) { + final SqlAstNodeRenderingMode original = parameterRenderingMode; + parameterRenderingMode = SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS; + renderPartitionItem( resolved ); + parameterRenderingMode = original; + } + else { + renderPartitionItem( resolved ); + } } separator = COMA_SEPARATOR; } @@ -1691,7 +1720,7 @@ public abstract class AbstractSqlAstTranslator implemen protected void renderOrderBy(boolean addWhitespace, List sortSpecifications) { if ( sortSpecifications != null && !sortSpecifications.isEmpty() ) { if ( addWhitespace ) { - appendSql( ' ' ); + appendSql( WHITESPACE ); } appendSql( "order by " ); @@ -1743,7 +1772,7 @@ public abstract class AbstractSqlAstTranslator implemen appendSql( " intersect select " ); renderCommaSeparatedSelectExpression( rhsExpressions ); appendSql( getFromDualForSelectOnly() ); - appendSql( ")" ); + appendSql( CLOSE_PARENTHESIS ); } else { appendSql( "exists (select 1" ); @@ -1753,7 +1782,7 @@ public abstract class AbstractSqlAstTranslator implemen for ( int i = 0; i < size; i++ ) { appendSql( separator ); lhsExpressions.get( i ).accept( this ); - appendSql( " = " ); + appendSql( '=' ); rhsExpressions.get( i ).accept( this ); appendSql( " or " ); lhsExpressions.get( i ).accept( this ); @@ -1920,9 +1949,7 @@ public abstract class AbstractSqlAstTranslator implemen separator = COMA_SEPARATOR; } appendSql( CLOSE_PARENTHESIS ); - appendSql( " " ); appendSql( operator.sqlText() ); - appendSql( " " ); tuple.accept( this ); } @@ -1932,9 +1959,7 @@ public abstract class AbstractSqlAstTranslator implemen protected void renderComparisonStandard(Expression lhs, ComparisonOperator operator, Expression rhs) { lhs.accept( this ); - appendSql( " " ); appendSql( operator.sqlText() ); - appendSql( " " ); rhs.accept( this ); } @@ -1959,12 +1984,10 @@ public abstract class AbstractSqlAstTranslator implemen appendSql( "not(" ); } lhs.accept( this ); - appendSql( ' ' ); appendSql( operatorText ); - appendSql( ' ' ); rhs.accept( this ); if ( notWrapper ) { - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } } @@ -1986,9 +2009,7 @@ public abstract class AbstractSqlAstTranslator implemen break; default: lhs.accept( this ); - appendSql( ' ' ); appendSql( operator.sqlText() ); - appendSql( ' ' ); rhs.accept( this ); break; } @@ -1999,30 +2020,28 @@ public abstract class AbstractSqlAstTranslator implemen case DISTINCT_FROM: appendSql( "case when " ); lhs.accept( this ); - appendSql( " = " ); + appendSql( '=' ); rhs.accept( this ); appendSql( " or " ); lhs.accept( this ); appendSql( " is null and " ); rhs.accept( this ); - appendSql( " is null then 0 else 1 end = 1" ); + appendSql( " is null then 0 else 1 end=1" ); break; case NOT_DISTINCT_FROM: appendSql( "case when " ); lhs.accept( this ); - appendSql( " = " ); + appendSql( '=' ); rhs.accept( this ); appendSql( " or " ); lhs.accept( this ); appendSql( " is null and " ); rhs.accept( this ); - appendSql( " is null then 0 else 1 end = 0" ); + appendSql( " is null then 0 else 1 end=0" ); break; default: lhs.accept( this ); - appendSql( ' ' ); appendSql( operator.sqlText() ); - appendSql( ' ' ); rhs.accept( this ); break; } @@ -2041,14 +2060,12 @@ public abstract class AbstractSqlAstTranslator implemen visitSqlSelectExpression( rhs ); appendSql( getFromDualForSelectOnly() ); clauseStack.pop(); - appendSql( ")" ); + appendSql( CLOSE_PARENTHESIS ); return; } } lhs.accept( this ); - appendSql( " " ); appendSql( operator.sqlText() ); - appendSql( " " ); rhs.accept( this ); } @@ -2116,7 +2133,7 @@ public abstract class AbstractSqlAstTranslator implemen appendSql( "1 else 0" ); } appendSql( " end" ); - appendSql( COMA_SEPARATOR ); + appendSql( COMA_SEPARATOR_CHAR ); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2251,7 +2268,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( fetchExpression != null ) { appendSql( "top " ); if ( needsParenthesis ) { - appendSql( '(' ); + appendSql( OPEN_PARENTHESIS ); } final Stack clauseStack = getClauseStack(); clauseStack.push( Clause.FETCH ); @@ -2267,9 +2284,9 @@ public abstract class AbstractSqlAstTranslator implemen clauseStack.pop(); } if ( needsParenthesis ) { - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } - appendSql( ' ' ); + appendSql( WHITESPACE ); switch ( fetchClauseType ) { case ROWS_WITH_TIES: appendSql( "with ties " ); @@ -2322,7 +2339,7 @@ public abstract class AbstractSqlAstTranslator implemen clauseStack.pop(); } } - appendSql( ' ' ); + appendSql( WHITESPACE ); switch ( fetchClauseType ) { case ROWS_WITH_TIES: appendSql( "with ties " ); @@ -2370,7 +2387,7 @@ public abstract class AbstractSqlAstTranslator implemen clauseStack.pop(); } } - appendSql( ' ' ); + appendSql( WHITESPACE ); } } @@ -2528,7 +2545,7 @@ public abstract class AbstractSqlAstTranslator implemen finally { clauseStack.pop(); } - appendSql( ' ' ); + appendSql( WHITESPACE ); } if ( offsetExpression != null ) { appendSql( "skip " ); @@ -2539,7 +2556,7 @@ public abstract class AbstractSqlAstTranslator implemen finally { clauseStack.pop(); } - appendSql( ' ' ); + appendSql( WHITESPACE ); } } @@ -2565,7 +2582,7 @@ public abstract class AbstractSqlAstTranslator implemen finally { clauseStack.pop(); } - appendSql( ' ' ); + appendSql( WHITESPACE ); } if ( fetchExpression != null ) { appendSql( "first " ); @@ -2576,7 +2593,7 @@ public abstract class AbstractSqlAstTranslator implemen finally { clauseStack.pop(); } - appendSql( ' ' ); + appendSql( WHITESPACE ); } } @@ -2602,7 +2619,7 @@ public abstract class AbstractSqlAstTranslator implemen finally { clauseStack.pop(); } - appendSql( ' ' ); + appendSql( WHITESPACE ); } } @@ -2628,7 +2645,7 @@ public abstract class AbstractSqlAstTranslator implemen finally { clauseStack.pop(); } - appendSql( COMA_SEPARATOR ); + appendSql( COMA_SEPARATOR_CHAR ); if ( fetchExpression != null ) { clauseStack.push( Clause.FETCH ); try { @@ -2746,7 +2763,7 @@ public abstract class AbstractSqlAstTranslator implemen this.queryPartForRowNumbering = queryPart; this.queryPartForRowNumberingClauseDepth = clauseStack.depth(); this.needsSelectAliases = true; - final String alias = "r_" + queryPartForRowNumberingAliasCounter + "_"; + final String alias = "r_" + queryPartForRowNumberingAliasCounter + '_'; queryPartForRowNumberingAliasCounter++; final boolean needsParenthesis; if ( queryPart instanceof QueryGroup ) { @@ -2757,11 +2774,11 @@ public abstract class AbstractSqlAstTranslator implemen needsParenthesis = !queryPart.isRoot(); } if ( needsParenthesis && !queryPart.isRoot() ) { - appendSql( '(' ); + appendSql( OPEN_PARENTHESIS ); } appendSql( "select " ); if ( getClauseStack().isEmpty() ) { - appendSql( "*" ); + appendSql( '*' ); } else { final int size = queryPart.getFirstQuerySpec().getSelectClause().getSqlSelections().size(); @@ -2776,13 +2793,13 @@ public abstract class AbstractSqlAstTranslator implemen } appendSql( " from " ); if ( !needsParenthesis || queryPart.isRoot() ) { - appendSql( '(' ); + appendSql( OPEN_PARENTHESIS ); } queryPart.accept( this ); if ( !needsParenthesis || queryPart.isRoot() ) { - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } - appendSql( ' '); + appendSql( WHITESPACE); appendSql( alias ); appendSql( " where " ); final Stack clauseStack = getClauseStack(); @@ -2792,45 +2809,45 @@ public abstract class AbstractSqlAstTranslator implemen switch ( fetchClauseType ) { case PERCENT_ONLY: appendSql( alias ); - appendSql( ".rn <= " ); + appendSql( ".rn<=" ); if ( offsetExpression != null ) { offsetExpression.accept( this ); - appendSql( " + " ); + appendSql( '+' ); } appendSql( "ceil("); appendSql( alias ); - appendSql( ".cnt * " ); + appendSql( ".cnt*" ); fetchExpression.accept( this ); - appendSql( " / 100)" ); + appendSql( "/100)" ); break; case ROWS_ONLY: appendSql( alias ); - appendSql( ".rn <= " ); + appendSql( ".rn<=" ); if ( offsetExpression != null ) { offsetExpression.accept( this ); - appendSql( " + " ); + appendSql( '+' ); } fetchExpression.accept( this ); break; case PERCENT_WITH_TIES: appendSql( alias ); - appendSql( ".rnk <= " ); + appendSql( ".rnk<=" ); if ( offsetExpression != null ) { offsetExpression.accept( this ); - appendSql( " + " ); + appendSql( '+' ); } appendSql( "ceil("); appendSql( alias ); - appendSql( ".cnt * " ); + appendSql( ".cnt*" ); fetchExpression.accept( this ); - appendSql( " / 100)" ); + appendSql( "/100)" ); break; case ROWS_WITH_TIES: appendSql( alias ); - appendSql( ".rnk <= " ); + appendSql( ".rnk<=" ); if ( offsetExpression != null ) { offsetExpression.accept( this ); - appendSql( " + " ); + appendSql( '+' ); } fetchExpression.accept( this ); break; @@ -2860,7 +2877,7 @@ public abstract class AbstractSqlAstTranslator implemen appendSql( " and " ); } appendSql( alias ); - appendSql( ".rn > " ); + appendSql( ".rn>" ); offsetExpression.accept( this ); if ( queryPart.isRoot() ) { appendSql( " order by " ); @@ -2880,7 +2897,7 @@ public abstract class AbstractSqlAstTranslator implemen clauseStack.pop(); } if ( needsParenthesis && !queryPart.isRoot() ) { - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } } finally { @@ -2930,12 +2947,28 @@ public abstract class AbstractSqlAstTranslator implemen protected void visitSqlSelections(SelectClause selectClause) { final List sqlSelections = selectClause.getSqlSelections(); final int size = sqlSelections.size(); - if ( needsSelectAliases || needsSelectAliasesForGroupOrOrderByClause() ) { + final SelectItemReferenceStrategy referenceStrategy = dialect.getGroupBySelectItemReferenceStrategy(); + // When the dialect needs to render the aliased expression and there are aliased group by items, + // we need to inline parameters as the database would otherwise not be able to match the group by item + // to the select item, ultimately leading to a query error + final BitSet selectItemsToInline; + if ( referenceStrategy == SelectItemReferenceStrategy.EXPRESSION ) { + selectItemsToInline = getSelectItemsToInline(); + } + else { + selectItemsToInline = null; + } + final SqlAstNodeRenderingMode original = parameterRenderingMode; + if ( needsSelectAliases || referenceStrategy == SelectItemReferenceStrategy.ALIAS && hasSelectAliasInGroupByClause() ) { String separator = NO_SEPARATOR; for ( int i = 0; i < size; i++ ) { final SqlSelection sqlSelection = sqlSelections.get( i ); appendSql( separator ); + if ( selectItemsToInline != null && selectItemsToInline.get( i ) ) { + parameterRenderingMode = SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS; + } visitSqlSelection( sqlSelection ); + parameterRenderingMode = original; appendSql( " c" ); appendSql( Integer.toString( i ) ); separator = COMA_SEPARATOR; @@ -2949,50 +2982,58 @@ public abstract class AbstractSqlAstTranslator implemen for ( int i = 0; i < size; i++ ) { final SqlSelection sqlSelection = sqlSelections.get( i ); appendSql( separator ); + if ( selectItemsToInline != null && selectItemsToInline.get( i ) ) { + parameterRenderingMode = SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS; + } visitSqlSelection( sqlSelection ); + parameterRenderingMode = original; separator = COMA_SEPARATOR; } } } - private boolean needsSelectAliasesForGroupOrOrderByClause() { - if ( dialect.getGroupBySelectItemReferenceStrategy() == SelectItemReferenceStrategy.ALIAS ) { - final QuerySpec querySpec = (QuerySpec) getQueryPartStack().getCurrent(); - for ( Expression groupByClauseExpression : querySpec.getGroupByClauseExpressions() ) { - if ( isSelectItemReference( groupByClauseExpression ) ) { - return true; - } + private BitSet getSelectItemsToInline() { + final QuerySpec querySpec = (QuerySpec) getQueryPartStack().getCurrent(); + final List sqlSelections = querySpec.getSelectClause().getSqlSelections(); + final BitSet bitSet = new BitSet( sqlSelections.size() ); + for ( Expression groupByClauseExpression : querySpec.getGroupByClauseExpressions() ) { + final SqlSelectionExpression selectItemReference = getSelectItemReference( groupByClauseExpression ); + if ( selectItemReference != null ) { + bitSet.set( sqlSelections.indexOf( selectItemReference.getSelection() ) ); } - if ( querySpec.hasSortSpecifications() ) { - for ( SortSpecification sortSpecification : querySpec.getSortSpecifications() ) { - if ( isSelectItemReference( sortSpecification.getSortExpression() ) ) { - return true; - } - } + } + return bitSet; + } + + private boolean hasSelectAliasInGroupByClause() { + final QuerySpec querySpec = (QuerySpec) getQueryPartStack().getCurrent(); + for ( Expression groupByClauseExpression : querySpec.getGroupByClauseExpressions() ) { + if ( getSelectItemReference( groupByClauseExpression ) != null ) { + return true; } } return false; } - protected final boolean isSelectItemReference(Expression expression) { + protected final SqlSelectionExpression getSelectItemReference(Expression expression) { final SqlTuple sqlTuple = SqlTupleContainer.getSqlTuple( expression ); if ( sqlTuple != null ) { for ( Expression e : sqlTuple.getExpressions() ) { if ( e instanceof SqlSelectionExpression ) { - return true; + return (SqlSelectionExpression) e; } } } else if ( expression instanceof SqlSelectionExpression ) { - return true; + return (SqlSelectionExpression) expression; } - return false; + return null; } protected void renderRowNumberingSelectItems(SelectClause selectClause, QueryPart queryPart) { final FetchClauseType fetchClauseType = getFetchClauseTypeForRowNumbering( queryPart ); if ( fetchClauseType != null ) { - appendSql( COMA_SEPARATOR ); + appendSql( COMA_SEPARATOR_CHAR ); switch ( fetchClauseType ) { case PERCENT_ONLY: appendSql( "count(*) over () cnt," ); @@ -3005,7 +3046,7 @@ public abstract class AbstractSqlAstTranslator implemen case ROWS_WITH_TIES: if ( queryPart.getOffsetClauseExpression() != null ) { renderRowNumber( selectClause, queryPart ); - appendSql( " rn, " ); + appendSql( " rn," ); } if ( selectClause.isDistinct() ) { appendSql( "dense_rank()" ); @@ -3040,7 +3081,7 @@ public abstract class AbstractSqlAstTranslator implemen appendSql( " over (" ); visitPartitionByClause( partitionExpressions ); renderOrderBy( !partitionExpressions.isEmpty(), sortSpecifications ); - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } finally { clauseStack.pop(); @@ -3057,6 +3098,10 @@ public abstract class AbstractSqlAstTranslator implemen visitOverClause( Collections.emptyList(), getSortSpecificationsRowNumbering( selectClause, queryPart ) ); } + protected final boolean isParameter(Expression expression) { + return expression instanceof JdbcParameter || expression instanceof SqmParameterInterpretation; + } + protected List getSortSpecificationsRowNumbering( SelectClause selectClause, QueryPart queryPart) { @@ -3156,7 +3201,7 @@ public abstract class AbstractSqlAstTranslator implemen isFirst = false; } else { - appendSql( ", " ); + appendSql( ',' ); } renderSelectExpression( e ); } @@ -3167,7 +3212,23 @@ public abstract class AbstractSqlAstTranslator implemen } protected void renderSelectExpression(Expression expression) { - expression.accept( this ); + renderExpressionAsClauseItem( expression ); + } + + protected void renderExpressionAsClauseItem(Expression expression) { + // Most databases do not support predicates as top level items + if ( expression instanceof Predicate ) { + appendSql( "case when " ); + expression.accept( this ); + appendSql( " then " ); + appendSql( getDialect().toBooleanValueString( true ) ); + appendSql( " else " ); + appendSql( getDialect().toBooleanValueString( false ) ); + appendSql( " end" ); + } + else { + expression.accept( this ); + } } protected void renderSelectExpressionWithCastedOrInlinedPlainParameters(Expression expression) { @@ -3181,8 +3242,13 @@ public abstract class AbstractSqlAstTranslator implemen renderLiteral( literal, true ); } } - else if ( expression instanceof NullnessLiteral || expression instanceof JdbcParameter || expression instanceof SqmParameterInterpretation ) { - renderCasted( expression ); + else if ( expression instanceof NullnessLiteral || isParameter( expression ) ) { + if ( parameterRenderingMode == SqlAstNodeRenderingMode.INLINE_PARAMETERS || parameterRenderingMode == SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS ) { + renderExpressionAsLiteral( expression, getJdbcParameterBindings() ); + } + else { + renderCasted( expression ); + } } else if ( expression instanceof CaseSimpleExpression ) { visitCaseSimpleExpression( (CaseSimpleExpression) expression, true ); @@ -3191,7 +3257,7 @@ public abstract class AbstractSqlAstTranslator implemen visitCaseSearchedExpression( (CaseSearchedExpression) expression, true ); } else { - expression.accept( this ); + renderExpressionAsClauseItem( expression ); } } @@ -3306,7 +3372,7 @@ public abstract class AbstractSqlAstTranslator implemen final boolean realTableGroup = tableGroup.isRealTableGroup() && CollectionHelper.isNotEmpty( tableGroup.getTableReferenceJoins() ); if ( realTableGroup ) { - appendSql( '(' ); + appendSql( OPEN_PARENTHESIS ); } final LockMode effectiveLockMode = getEffectiveLockMode( tableGroup.getSourceAlias() ); @@ -3314,7 +3380,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( realTableGroup ) { renderTableReferenceJoins( tableGroup ); - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } appendSql( " on " ); @@ -3351,7 +3417,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( rendersTableReferenceAlias( currentClause ) ) { final String identificationVariable = tableReference.getIdentificationVariable(); if ( identificationVariable != null ) { - appendSql( getDialect().getTableAliasSeparator() ); + appendSql( WHITESPACE ); appendSql( identificationVariable ); } } @@ -3385,7 +3451,7 @@ public abstract class AbstractSqlAstTranslator implemen } for ( TableReferenceJoin tableJoin : joins ) { - appendSql( EMPTY_STRING ); + appendSql( WHITESPACE ); renderJoinType( tableJoin.getJoinType() ); renderTableReference( tableJoin.getJoinedTableReference(), LockMode.NONE ); @@ -3410,7 +3476,7 @@ public abstract class AbstractSqlAstTranslator implemen processTableGroupJoins( tableGroupJoin.getJoinedGroup() ); } else if ( !( joinedGroup instanceof LazyTableGroup ) || ( (LazyTableGroup) joinedGroup ).getUnderlyingTableGroup() != null ) { - appendSql( EMPTY_STRING ); + appendSql( WHITESPACE ); SqlAstJoinType joinType = tableGroupJoin.getJoinType(); if ( !joinedGroup.isRealTableGroup() && joinType == SqlAstJoinType.INNER && !joinedGroup.getTableReferenceJoins().isEmpty() ) { joinType = SqlAstJoinType.LEFT; @@ -3535,21 +3601,21 @@ public abstract class AbstractSqlAstTranslator implemen @Override public void visitFormat(Format format) { final String dialectFormat = getDialect().translateDatetimeFormat( format.getFormat() ); - appendSql( "'" ); + appendSql( '\'' ); appendSql( dialectFormat ); - appendSql( "'" ); + appendSql( '\'' ); } @Override public void visitStar(Star star) { - appendSql( "*" ); + appendSql( '*' ); } @Override public void visitTrimSpecification(TrimSpecification trimSpecification) { - appendSql( " " ); + appendSql( WHITESPACE ); appendSql( trimSpecification.getSpecification().toSqlText() ); - appendSql( " " ); + appendSql( WHITESPACE ); } @Override @@ -3572,73 +3638,38 @@ public abstract class AbstractSqlAstTranslator implemen @Override public void visitParameter(JdbcParameter jdbcParameter) { - if ( inlineParameters ) { - renderExpressionAsLiteral( jdbcParameter, jdbcParameterBindings ); - } - else { - appendSql( PARAM_MARKER ); + switch ( parameterRenderingMode ) { + case NO_PLAIN_PARAMETER: + final List arguments = new ArrayList<>( 2 ); + arguments.add( jdbcParameter ); + arguments.add( new CastTarget( jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ) ) ); + castFunction().render( this, arguments, this ); + break; + case INLINE_PARAMETERS: + case INLINE_ALL_PARAMETERS: + renderExpressionAsLiteral( jdbcParameter, jdbcParameterBindings ); + break; + case DEFAULT: + default: + appendSql( PARAM_MARKER ); - parameterBinders.add( jdbcParameter.getParameterBinder() ); - jdbcParameters.addParameter( jdbcParameter ); + parameterBinders.add( jdbcParameter.getParameterBinder() ); + jdbcParameters.addParameter( jdbcParameter ); + break; } } @Override public void render(SqlAstNode sqlAstNode, SqlAstNodeRenderingMode renderingMode) { - switch ( renderingMode ) { - case NO_PLAIN_PARAMETER: { - if ( sqlAstNode instanceof SqmParameterInterpretation ) { - sqlAstNode = ( (SqmParameterInterpretation) sqlAstNode ).getResolvedExpression(); - } - if ( sqlAstNode instanceof JdbcParameter ) { - final JdbcParameter jdbcParameter = (JdbcParameter) sqlAstNode; - final JdbcMapping jdbcMapping = jdbcParameter.getExpressionType().getJdbcMappings().get( 0 ); - // We try to avoid inlining parameters if possible which can be done by wrapping the parameter - // in an expression that is semantically unnecessary e.g. numeric + 0 or concat with an empty string - if ( jdbcMapping.getJdbcTypeDescriptor().isNumber() ) { - appendSql( '(' ); - sqlAstNode.accept( this ); - appendSql( "+0)" ); - break; - } - else if ( jdbcMapping.getJdbcTypeDescriptor().isString() ) { - final SqmFunctionDescriptor sqmFunctionDescriptor = getSessionFactory().getQueryEngine() - .getSqmFunctionRegistry() - .findFunctionDescriptor( "concat" ); - if ( sqmFunctionDescriptor instanceof AbstractSqmSelfRenderingFunctionDescriptor ) { - final List list = new ArrayList<>( 2 ); - list.add( sqlAstNode ); - list.add( new QueryLiteral<>( "", StringType.INSTANCE ) ); - ( (AbstractSqmSelfRenderingFunctionDescriptor) sqmFunctionDescriptor ) - .render( this, list, this ); - break; - } - } - final List arguments = new ArrayList<>( 2 ); - arguments.add( jdbcParameter ); - arguments.add( new CastTarget( jdbcMapping ) ); - castFunction().render( this, arguments, this ); - } - else { - sqlAstNode.accept( this ); - } - break; - } - case INLINE_PARAMETERS: { - boolean inlineParameters = this.inlineParameters; - this.inlineParameters = true; - try { - sqlAstNode.accept( this ); - } - finally { - this.inlineParameters = inlineParameters; - } - break; - } - case DEFAULT: - default: { - sqlAstNode.accept( this ); - } + SqlAstNodeRenderingMode original = this.parameterRenderingMode; + if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS ) { + this.parameterRenderingMode = renderingMode; + } + try { + sqlAstNode.accept( this ); + } + finally { + this.parameterRenderingMode = original; } } @@ -3991,11 +4022,11 @@ public abstract class AbstractSqlAstTranslator implemen @Override public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) { - appendSql( "(" ); + appendSql( OPEN_PARENTHESIS ); arithmeticExpression.getLeftHandOperand().accept( this ); appendSql( arithmeticExpression.getOperator().getOperatorSqlTextString() ); arithmeticExpression.getRightHandOperand().accept( this ); - appendSql( ")" ); + appendSql( CLOSE_PARENTHESIS ); } @Override @@ -4023,46 +4054,33 @@ public abstract class AbstractSqlAstTranslator implemen protected void visitCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression, boolean inSelect) { if ( inSelect ) { - visitAnsiCaseSearchedExpressionInSelect( caseSearchedExpression ); + visitAnsiCaseSearchedExpression( caseSearchedExpression, this::renderSelectExpression ); } else { - visitAnsiCaseSearchedExpression( caseSearchedExpression ); + visitAnsiCaseSearchedExpression( caseSearchedExpression, e -> e.accept( this ) ); } } - protected void visitAnsiCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression){ + protected void visitAnsiCaseSearchedExpression( + CaseSearchedExpression caseSearchedExpression, + Consumer resultRenderer) { appendSql( "case" ); - + final SqlAstNodeRenderingMode original = this.parameterRenderingMode; for ( CaseSearchedExpression.WhenFragment whenFragment : caseSearchedExpression.getWhenFragments() ) { + if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS ) { + this.parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT; + } appendSql( " when " ); whenFragment.getPredicate().accept( this ); + this.parameterRenderingMode = original; appendSql( " then " ); - whenFragment.getResult().accept( this ); + resultRenderer.accept( whenFragment.getResult() ); } - Expression otherwise = caseSearchedExpression.getOtherwise(); + final Expression otherwise = caseSearchedExpression.getOtherwise(); if ( otherwise != null ) { appendSql( " else " ); - otherwise.accept( this ); - } - - appendSql( " end" ); - } - - protected void visitAnsiCaseSearchedExpressionInSelect(CaseSearchedExpression caseSearchedExpression) { - appendSql( "case" ); - - for ( CaseSearchedExpression.WhenFragment whenFragment : caseSearchedExpression.getWhenFragments() ) { - appendSql( " when " ); - whenFragment.getPredicate().accept( this ); - appendSql( " then " ); - renderSelectExpression( whenFragment.getResult() ); - } - - Expression otherwise = caseSearchedExpression.getOtherwise(); - if ( otherwise != null ) { - appendSql( " else " ); - renderSelectExpression( otherwise ); + resultRenderer.accept( otherwise ); } appendSql( " end" ); @@ -4070,17 +4088,21 @@ public abstract class AbstractSqlAstTranslator implemen protected void visitDecodeCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression) { appendSql( "decode( " ); - - List whenFragments = caseSearchedExpression.getWhenFragments(); - int caseNumber = whenFragments.size(); + final SqlAstNodeRenderingMode original = this.parameterRenderingMode; + final List whenFragments = caseSearchedExpression.getWhenFragments(); + final int caseNumber = whenFragments.size(); CaseSearchedExpression.WhenFragment firstWhenFragment = null; for ( int i = 0; i < caseNumber; i++ ) { final CaseSearchedExpression.WhenFragment whenFragment = whenFragments.get( i ); Predicate predicate = whenFragment.getPredicate(); + if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS ) { + this.parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT; + } if ( i != 0 ) { - appendSql( ", " ); + appendSql( ',' ); getLeftHandExpression( predicate ).accept( this ); - appendSql( ", " ); + this.parameterRenderingMode = original; + appendSql( ',' ); whenFragment.getResult().accept( this ); } else { @@ -4088,83 +4110,98 @@ public abstract class AbstractSqlAstTranslator implemen firstWhenFragment = whenFragment; } } - appendSql( ", " ); + this.parameterRenderingMode = original; + appendSql( ',' ); firstWhenFragment.getResult().accept( this ); - Expression otherwise = caseSearchedExpression.getOtherwise(); + final Expression otherwise = caseSearchedExpression.getOtherwise(); if ( otherwise != null ) { - appendSql( ", " ); + appendSql( ',' ); otherwise.accept( this ); } - appendSql( ')' ); - } - - protected Expression getLeftHandExpression(Predicate predicate) { - if ( predicate instanceof NullnessPredicate ) { - return ( (NullnessPredicate) predicate ).getExpression(); - } - assert predicate instanceof ComparisonPredicate; - return ( (ComparisonPredicate) predicate ).getLeftHandExpression(); + appendSql( CLOSE_PARENTHESIS ); } @Override public final void visitCaseSimpleExpression(CaseSimpleExpression caseSimpleExpression) { - visitCaseSimpleExpression( caseSimpleExpression, false ); + visitAnsiCaseSimpleExpression( caseSimpleExpression, e -> e.accept( this ) ); } protected void visitCaseSimpleExpression(CaseSimpleExpression caseSimpleExpression, boolean inSelect) { if ( inSelect ) { - visitAnsiCaseSimpleExpressionInSelect( caseSimpleExpression ); + visitAnsiCaseSimpleExpression( caseSimpleExpression, this::renderSelectExpression ); } else { - visitAnsiCaseSimpleExpression( caseSimpleExpression ); + visitAnsiCaseSimpleExpression( caseSimpleExpression, e -> e.accept( this ) ); } } - protected void visitAnsiCaseSimpleExpression(CaseSimpleExpression caseSimpleExpression) { + protected void visitAnsiCaseSimpleExpression( + CaseSimpleExpression caseSimpleExpression, + Consumer resultRenderer) { appendSql( "case " ); + final SqlAstNodeRenderingMode original = this.parameterRenderingMode; + if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS ) { + this.parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT; + } caseSimpleExpression.getFixture().accept( this ); for ( CaseSimpleExpression.WhenFragment whenFragment : caseSimpleExpression.getWhenFragments() ) { + if ( original != SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS ) { + this.parameterRenderingMode = SqlAstNodeRenderingMode.DEFAULT; + } appendSql( " when " ); whenFragment.getCheckValue().accept( this ); + this.parameterRenderingMode = original; appendSql( " then " ); - whenFragment.getResult().accept( this ); + resultRenderer.accept( whenFragment.getResult() ); } + this.parameterRenderingMode = original; final Expression otherwise = caseSimpleExpression.getOtherwise(); if ( otherwise != null ) { appendSql( " else " ); - otherwise.accept( this ); + resultRenderer.accept( otherwise ); } appendSql( " end" ); } - protected void visitAnsiCaseSimpleExpressionInSelect(CaseSimpleExpression caseSimpleExpression) { - appendSql( "case " ); - caseSimpleExpression.getFixture().accept( this ); - for ( CaseSimpleExpression.WhenFragment whenFragment : caseSimpleExpression.getWhenFragments() ) { - appendSql( " when " ); - whenFragment.getCheckValue().accept( this ); - appendSql( " then " ); - renderSelectExpression( whenFragment.getResult() ); + protected boolean areAllResultsParameters(CaseSearchedExpression caseSearchedExpression) { + final List whenFragments = caseSearchedExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + if ( isParameter( firstResult ) ) { + for ( int i = 1; i < whenFragments.size(); i++ ) { + if ( !isParameter( whenFragments.get( i ).getResult() ) ) { + return false; + } + } + return true; } - final Expression otherwise = caseSimpleExpression.getOtherwise(); - if ( otherwise != null ) { - appendSql( " else " ); - renderSelectExpression( otherwise ); + return false; + } + + protected boolean areAllResultsParameters(CaseSimpleExpression caseSimpleExpression) { + final List whenFragments = caseSimpleExpression.getWhenFragments(); + final Expression firstResult = whenFragments.get( 0 ).getResult(); + if ( isParameter( firstResult ) ) { + for ( int i = 1; i < whenFragments.size(); i++ ) { + if ( !isParameter( whenFragments.get( i ).getResult() ) ) { + return false; + } + } + return true; } - appendSql( " end" ); + return false; } @Override public void visitAny(Any any) { - appendSql( "some " ); + appendSql( "any" ); any.getSubquery().accept( this ); } @Override public void visitEvery(Every every) { - appendSql( "all " ); + appendSql( "all" ); every.getSubquery().accept( this ); } @@ -4255,6 +4292,14 @@ public abstract class AbstractSqlAstTranslator implemen // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Predicates + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + // Most databases do not support boolean expressions in a predicate context, so we render `expr=true` + booleanExpressionPredicate.getExpression().accept( this ); + appendSql( '=' ); + appendSql( getDialect().toBooleanValueString( true ) ); + } + @Override public void visitBetweenPredicate(BetweenPredicate betweenPredicate) { betweenPredicate.getExpression().accept( this ); @@ -4293,7 +4338,7 @@ public abstract class AbstractSqlAstTranslator implemen public void visitInListPredicate(InListPredicate inListPredicate) { final List listExpressions = inListPredicate.getListExpressions(); if ( listExpressions.isEmpty() ) { - appendSql( "false" ); + appendSql( "1=0" ); return; } final SqlTuple lhsTuple; @@ -4304,7 +4349,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( inListPredicate.isNegated() ) { appendSql( " not" ); } - appendSql( " in (" ); + appendSql( " in(" ); String separator = NO_SEPARATOR; for ( Expression expression : listExpressions ) { appendSql( separator ); @@ -4323,7 +4368,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( inListPredicate.isNegated() ) { appendSql( " not" ); } - appendSql( " in (" ); + appendSql( " in(" ); String separator = NO_SEPARATOR; for ( Expression expression : listExpressions ) { appendSql( separator ); @@ -4353,7 +4398,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( inListPredicate.isNegated() ) { appendSql( " not" ); } - appendSql( " in (" ); + appendSql( " in(" ); renderCommaSeparated( listExpressions ); appendSql( CLOSE_PARENTHESIS ); } @@ -4363,7 +4408,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( inListPredicate.isNegated() ) { appendSql( " not" ); } - appendSql( " in (" ); + appendSql( " in(" ); renderCommaSeparated( listExpressions ); appendSql( CLOSE_PARENTHESIS ); } @@ -4379,7 +4424,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( inSubQueryPredicate.isNegated() ) { appendSql( " not" ); } - appendSql( " in " ); + appendSql( " in" ); inSubQueryPredicate.getSubQuery().accept( this ); } else if ( !supportsRowValueConstructorSyntaxInInSubQuery() ) { @@ -4397,7 +4442,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( inSubQueryPredicate.isNegated() ) { appendSql( " not" ); } - appendSql( " in " ); + appendSql( " in" ); inSubQueryPredicate.getSubQuery().accept( this ); } } @@ -4406,7 +4451,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( inSubQueryPredicate.isNegated() ) { appendSql( " not" ); } - appendSql( " in " ); + appendSql( " in" ); inSubQueryPredicate.getSubQuery().accept( this ); } } @@ -4455,7 +4500,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( havingClauseRestrictions != null ) { appendSql( " and (" ); havingClauseRestrictions.accept( this ); - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } } finally { @@ -4476,7 +4521,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( whereClauseRestrictions != null ) { appendSql( " and (" ); whereClauseRestrictions.accept( this ); - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } } finally { @@ -4484,7 +4529,7 @@ public abstract class AbstractSqlAstTranslator implemen } } - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } finally { queryPartStack.pop(); @@ -4517,9 +4562,7 @@ public abstract class AbstractSqlAstTranslator implemen subQuery = (QuerySpec) queryPart; // We can only emulate the tuple sub query predicate comparing against the top element when there are no limit/offsets lhsTuple.accept( this ); - appendSql( " " ); appendSql( tupleComparisonOperator.sqlText() ); - appendSql( " " ); final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering; final int queryPartForRowNumberingClauseDepth = this.queryPartForRowNumberingClauseDepth; @@ -4529,7 +4572,7 @@ public abstract class AbstractSqlAstTranslator implemen this.queryPartForRowNumberingClauseDepth = -1; this.needsSelectAliases = false; queryPartStack.push( subQuery ); - appendSql( '(' ); + appendSql( OPEN_PARENTHESIS ); visitSelectClause( subQuery.getSelectClause() ); visitFromClause( subQuery.getFromClause() ); visitWhereClause( subQuery ); @@ -4546,15 +4589,15 @@ public abstract class AbstractSqlAstTranslator implemen else { order = " desc"; } - appendSql( "1" ); + appendSql( '1' ); appendSql( order ); for ( int i = 1; i < sqlSelections.size(); i++ ) { - appendSql( COMA_SEPARATOR ); + appendSql( COMA_SEPARATOR_CHAR ); appendSql( Integer.toString( i + 1 ) ); appendSql( order ); } renderFetch( ONE_LITERAL, null, FetchClauseType.ROWS_ONLY ); - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } finally { queryPartStack.pop(); @@ -4571,7 +4614,7 @@ public abstract class AbstractSqlAstTranslator implemen @Override public void visitExistsPredicate(ExistsPredicate existsPredicate) { - appendSql( "exists " ); + appendSql( "exists" ); existsPredicate.getExpression().accept( this ); } @@ -4595,9 +4638,9 @@ public abstract class AbstractSqlAstTranslator implemen private void visitJunctionPredicate(Junction.Nature nature, Predicate p) { if ( p instanceof Junction && nature != ( (Junction) p ).getNature() ) { - appendSql( '(' ); + appendSql( OPEN_PARENTHESIS ); p.accept( this ); - appendSql( ')' ); + appendSql( CLOSE_PARENTHESIS ); } else { p.accept( this ); @@ -4607,7 +4650,6 @@ public abstract class AbstractSqlAstTranslator implemen @Override public void visitLikePredicate(LikePredicate likePredicate) { if ( likePredicate.isCaseSensitive() ) { - likePredicate.getMatchExpression().accept( this ); if ( likePredicate.isNegated() ) { appendSql( " not" ); @@ -4618,18 +4660,16 @@ public abstract class AbstractSqlAstTranslator implemen appendSql( " escape " ); likePredicate.getEscapeCharacter().accept( this ); } - } else { if (dialect.supportsCaseInsensitiveLike()) { - likePredicate.getMatchExpression().accept( this ); if ( likePredicate.isNegated() ) { appendSql( " not" ); } - appendSql( " " ); + appendSql( WHITESPACE ); appendSql( dialect.getCaseInsensitiveLike() ); - appendSql( " " ); + appendSql( WHITESPACE ); likePredicate.getPattern().accept( this ); if ( likePredicate.getEscapeCharacter() != null ) { appendSql( " escape " ); @@ -4646,17 +4686,18 @@ public abstract class AbstractSqlAstTranslator implemen protected void renderCaseInsensitiveLikeEmulation(Expression lhs, Expression rhs, Expression escapeCharacter, boolean negated) { //LOWER(lhs) operator LOWER(rhs) - appendSql( " " ); appendSql( dialect.getLowercaseFunction() ); - appendSql( "( "); + appendSql( OPEN_PARENTHESIS ); lhs.accept( this ); - appendSql( " )" ); - appendSql( negated ? " not" : "" ); + appendSql( CLOSE_PARENTHESIS ); + if ( negated ) { + appendSql( " not" ); + } appendSql( " like " ); appendSql( dialect.getLowercaseFunction() ); - appendSql( "( " ); + appendSql( OPEN_PARENTHESIS ); rhs.accept( this ); - appendSql( " ) " ); + appendSql( CLOSE_PARENTHESIS ); if ( escapeCharacter != null ) { appendSql( " escape " ); escapeCharacter.accept( this ); @@ -4669,9 +4710,9 @@ public abstract class AbstractSqlAstTranslator implemen return; } - appendSql( "not (" ); + appendSql( "not(" ); negatedPredicate.getPredicate().accept( this ); - appendSql( ")" ); + appendSql( CLOSE_PARENTHESIS ); } @Override @@ -4787,7 +4828,7 @@ public abstract class AbstractSqlAstTranslator implemen if ( operator == ComparisonOperator.NOT_EQUAL ) { appendSql( " not" ); } - appendSql( " in (" ); + appendSql( " in(" ); renderExpressionsAsSubquery( rhsTuple.getExpressions() ); appendSql( CLOSE_PARENTHESIS ); } @@ -4937,7 +4978,7 @@ public abstract class AbstractSqlAstTranslator implemen * @return the SQL equivalent to Oracle's {@code from dual}. */ protected String getFromDual() { - return " from (values (0)) as dual"; + return " from (values (0)) dual"; } protected String getFromDualForSelectOnly() { @@ -5060,7 +5101,7 @@ public abstract class AbstractSqlAstTranslator implemen first = false; } else { - appender.appendSql( ", " ); + appender.appendSql( ',' ); } appender.appendSql( tableAlias ); appender.appendSql( '.' ); @@ -5075,7 +5116,7 @@ public abstract class AbstractSqlAstTranslator implemen first = false; } else { - appender.appendSql( ", " ); + appender.appendSql( ',' ); } appender.appendSql( tableAlias ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AggregateFunctionChecker.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AggregateFunctionChecker.java index 66603a5ce7..d16747b7eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AggregateFunctionChecker.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AggregateFunctionChecker.java @@ -46,6 +46,7 @@ import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReferenceJoin; import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.ast.tree.predicate.BetweenPredicate; +import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.ExistsPredicate; import org.hibernate.sql.ast.tree.predicate.FilterPredicate; @@ -174,6 +175,11 @@ class AggregateFunctionChecker implements SqlAstWalker { unaryOperationExpression.getOperand().accept( this ); } + @Override + public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { + booleanExpressionPredicate.getExpression().accept( this ); + } + @Override public void visitBetweenPredicate(BetweenPredicate betweenPredicate) { betweenPredicate.getExpression().accept( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAppender.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAppender.java index bd2a6dcdd1..3b4ef757d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAppender.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAppender.java @@ -13,13 +13,14 @@ package org.hibernate.sql.ast.spi; */ public interface SqlAppender { String NO_SEPARATOR = ""; - String COMA_SEPARATOR = ", "; - String EMPTY_STRING = " "; + String COMA_SEPARATOR = ","; + char COMA_SEPARATOR_CHAR = ','; + char WHITESPACE = ' '; - String OPEN_PARENTHESIS = "("; - String CLOSE_PARENTHESIS = ")"; + char OPEN_PARENTHESIS = '('; + char CLOSE_PARENTHESIS = ')'; - String PARAM_MARKER = "?"; + char PARAM_MARKER = '?'; String NULL_KEYWORD = "null"; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Any.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Any.java index aed3728aa8..6064f5ca96 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Any.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Any.java @@ -7,18 +7,23 @@ package org.hibernate.sql.ast.tree.expression; import org.hibernate.metamodel.mapping.MappingModelExpressable; +import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.basic.BasicResult; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Gavin King */ -public class Any implements Expression { +public class Any implements Expression, DomainResultProducer { - private QueryPart subquery; - private MappingModelExpressable type; + private final QueryPart subquery; + private final MappingModelExpressable type; public Any(QueryPart subquery, MappingModelExpressable type) { this.subquery = subquery; @@ -38,4 +43,20 @@ public class Any implements Expression { public void accept(SqlAstWalker walker) { walker.visitAny( this ); } + + @Override + public DomainResult createDomainResult( + String resultVariable, + DomainResultCreationState creationState) { + final JavaTypeDescriptor javaTypeDescriptor = type.getJdbcMappings().get( 0 ).getJavaTypeDescriptor(); + return new BasicResult( + creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection( + this, + javaTypeDescriptor, + creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration() + ).getValuesArrayPosition(), + resultVariable, + javaTypeDescriptor + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/CaseSearchedExpression.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/CaseSearchedExpression.java index c36e933bbc..f6ba1f95e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/CaseSearchedExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/CaseSearchedExpression.java @@ -7,6 +7,7 @@ package org.hibernate.sql.ast.tree.expression; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -92,7 +93,7 @@ public class CaseSearchedExpression implements Expression, DomainResultProducer return type; } - public static class WhenFragment { + public static class WhenFragment implements Serializable { private final Predicate predicate; private final Expression result; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/CaseSimpleExpression.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/CaseSimpleExpression.java index a59c865fb0..5f0870dd35 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/CaseSimpleExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/CaseSimpleExpression.java @@ -7,6 +7,7 @@ package org.hibernate.sql.ast.tree.expression; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -87,7 +88,7 @@ public class CaseSimpleExpression implements Expression, DomainResultProducer { whenFragments.add( new WhenFragment( test, result ) ); } - public static class WhenFragment { + public static class WhenFragment implements Serializable { private final Expression checkValue; private final Expression result; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Collate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Collate.java index 7d2a54f253..9fa7900696 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Collate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Collate.java @@ -9,13 +9,18 @@ package org.hibernate.sql.ast.tree.expression; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.metamodel.mapping.SqlExpressable; +import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.basic.BasicResult; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Christian Beikov */ -public class Collate implements Expression, SqlExpressable, SqlAstNode { +public class Collate implements Expression, SqlExpressable, SqlAstNode, DomainResultProducer { private final Expression expression; private final String collation; @@ -61,4 +66,20 @@ public class Collate implements Expression, SqlExpressable, SqlAstNode { public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitCollate( this ); } + + @Override + public DomainResult createDomainResult( + String resultVariable, + DomainResultCreationState creationState) { + final JavaTypeDescriptor javaTypeDescriptor = expression.getExpressionType().getJdbcMappings().get( 0 ).getJavaTypeDescriptor(); + return new BasicResult( + creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection( + this, + javaTypeDescriptor, + creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration() + ).getValuesArrayPosition(), + resultVariable, + javaTypeDescriptor + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Every.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Every.java index 1489116bac..9a54826090 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Every.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Every.java @@ -7,18 +7,23 @@ package org.hibernate.sql.ast.tree.expression; import org.hibernate.metamodel.mapping.MappingModelExpressable; +import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.basic.BasicResult; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Gavin King */ -public class Every implements Expression { +public class Every implements Expression, DomainResultProducer { - private QueryPart subquery; - private MappingModelExpressable type; + private final QueryPart subquery; + private final MappingModelExpressable type; public Every(QueryPart subquery, MappingModelExpressable type) { this.subquery = subquery; @@ -38,4 +43,20 @@ public class Every implements Expression { public void accept(SqlAstWalker walker) { walker.visitEvery( this ); } + + @Override + public DomainResult createDomainResult( + String resultVariable, + DomainResultCreationState creationState) { + final JavaTypeDescriptor javaTypeDescriptor = type.getJdbcMappings().get( 0 ).getJavaTypeDescriptor(); + return new BasicResult( + creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection( + this, + javaTypeDescriptor, + creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration() + ).getValuesArrayPosition(), + resultVariable, + javaTypeDescriptor + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/NullnessLiteral.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/NullnessLiteral.java index 5278dcd566..9362fb1def 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/NullnessLiteral.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/NullnessLiteral.java @@ -7,12 +7,17 @@ package org.hibernate.sql.ast.tree.expression; import org.hibernate.metamodel.mapping.MappingModelExpressable; +import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.sql.ast.SqlAstWalker; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.basic.BasicResult; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * Assertion that the SQL state of a "mapping model expressable" is null */ -public class NullnessLiteral implements Expression { +public class NullnessLiteral implements Expression, DomainResultProducer { private final MappingModelExpressable valueMapping; public NullnessLiteral(MappingModelExpressable valueMapping) { @@ -28,4 +33,20 @@ public class NullnessLiteral implements Expression { public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitNullnessLiteral( this ); } + + @Override + public DomainResult createDomainResult( + String resultVariable, + DomainResultCreationState creationState) { + final JavaTypeDescriptor javaTypeDescriptor = valueMapping.getJdbcMappings().get( 0 ).getJavaTypeDescriptor(); + return new BasicResult( + creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection( + this, + javaTypeDescriptor, + creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration() + ).getValuesArrayPosition(), + resultVariable, + javaTypeDescriptor + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTuple.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTuple.java index cb4c8416b2..28f1466509 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTuple.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTuple.java @@ -11,13 +11,19 @@ import java.util.Collections; import java.util.List; import org.hibernate.metamodel.mapping.MappingModelExpressable; +import org.hibernate.query.sqm.SqmExpressable; +import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.SqlTreeCreationLogger; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.tuple.TupleResult; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Steve Ebersole */ -public class SqlTuple implements Expression, SqlTupleContainer { +public class SqlTuple implements Expression, SqlTupleContainer, DomainResultProducer { private final List expressions; private final MappingModelExpressable valueMapping; @@ -52,6 +58,27 @@ public class SqlTuple implements Expression, SqlTupleContainer { return this; } + @Override + public DomainResult createDomainResult( + String resultVariable, + DomainResultCreationState creationState) { + final JavaTypeDescriptor javaTypeDescriptor = ( (SqmExpressable) valueMapping ).getExpressableJavaTypeDescriptor(); + final int[] valuesArrayPositions = new int[expressions.size()]; + for ( int i = 0; i < expressions.size(); i++ ) { + valuesArrayPositions[i] = creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection( + expressions.get( i ), + javaTypeDescriptor, + creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration() + ).getValuesArrayPosition(); + } + + return new TupleResult( + valuesArrayPositions, + resultVariable, + javaTypeDescriptor + ); + } + public static class Builder { private final MappingModelExpressable valueMapping; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/AbstractPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/AbstractPredicate.java new file mode 100644 index 0000000000..06ff894b24 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/AbstractPredicate.java @@ -0,0 +1,40 @@ +/* + * 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.metamodel.mapping.JdbcMappingContainer; + +/** + * @author Christian Beikov + */ +public abstract class AbstractPredicate implements Predicate { + private final JdbcMappingContainer expressionType; + private final boolean negated; + + public AbstractPredicate(JdbcMappingContainer expressionType) { + this( expressionType, false ); + } + + public AbstractPredicate(JdbcMappingContainer expressionType, boolean negated) { + this.expressionType = expressionType; + this.negated = negated; + } + + public boolean isNegated() { + return negated; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public JdbcMappingContainer getExpressionType() { + return expressionType; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/BetweenPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/BetweenPredicate.java index d962c717b9..0b86baf0dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/BetweenPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/BetweenPredicate.java @@ -6,27 +6,28 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.Expression; /** * @author Steve Ebersole */ -public class BetweenPredicate implements Predicate { +public class BetweenPredicate extends AbstractPredicate { private final Expression expression; private final Expression lowerBound; private final Expression upperBound; - private final boolean negated; public BetweenPredicate( Expression expression, Expression lowerBound, Expression upperBound, - boolean negated) { + boolean negated, + JdbcMappingContainer expressionType) { + super( expressionType, negated ); this.expression = expression; this.lowerBound = lowerBound; this.upperBound = upperBound; - this.negated = negated; } public Expression getExpression() { @@ -41,15 +42,6 @@ public class BetweenPredicate implements Predicate { return upperBound; } - public boolean isNegated() { - return negated; - } - - @Override - public boolean isEmpty() { - return false; - } - @Override public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitBetweenPredicate( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/BooleanExpressionPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/BooleanExpressionPredicate.java new file mode 100644 index 0000000000..f2b56d78e0 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/BooleanExpressionPredicate.java @@ -0,0 +1,32 @@ +/* + * 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.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.sql.ast.SqlAstWalker; +import org.hibernate.sql.ast.tree.expression.Expression; + +/** + * @author Christian Beikov + */ +public class BooleanExpressionPredicate extends AbstractPredicate { + private final Expression expression; + + public BooleanExpressionPredicate(Expression expression, boolean negated, JdbcMappingContainer expressionType) { + super( expressionType, negated ); + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + @Override + public void accept(SqlAstWalker sqlTreeWalker) { + sqlTreeWalker.visitBooleanExpressionPredicate( this ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/ComparisonPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/ComparisonPredicate.java index 258522b666..bb13736631 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/ComparisonPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/ComparisonPredicate.java @@ -6,6 +6,7 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.query.ComparisonOperator; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.Expression; @@ -17,14 +18,24 @@ public class ComparisonPredicate implements Predicate { private final Expression leftHandExpression; private final ComparisonOperator operator; private final Expression rightHandExpression; + private final JdbcMappingContainer expressionType; public ComparisonPredicate( Expression leftHandExpression, ComparisonOperator operator, Expression rightHandExpression) { + this( leftHandExpression, operator, rightHandExpression, null ); + } + + public ComparisonPredicate( + Expression leftHandExpression, + ComparisonOperator operator, + Expression rightHandExpression, + JdbcMappingContainer expressionType) { this.leftHandExpression = leftHandExpression; this.operator = operator; this.rightHandExpression = rightHandExpression; + this.expressionType = expressionType; } public Expression getLeftHandExpression() { @@ -48,4 +59,9 @@ public class ComparisonPredicate implements Predicate { public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitRelationalPredicate( this ); } + + @Override + public JdbcMappingContainer getExpressionType() { + return expressionType; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/ExistsPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/ExistsPredicate.java index 45e9210d70..104333d357 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/ExistsPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/ExistsPredicate.java @@ -6,8 +6,8 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; -import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.select.QueryPart; /** @@ -16,9 +16,11 @@ import org.hibernate.sql.ast.tree.select.QueryPart; public class ExistsPredicate implements Predicate { private final QueryPart expression; + private final JdbcMappingContainer expressionType; - public ExistsPredicate(QueryPart expression) { + public ExistsPredicate(QueryPart expression, JdbcMappingContainer expressionType) { this.expression = expression; + this.expressionType = expressionType; } public QueryPart getExpression() { @@ -34,4 +36,9 @@ public class ExistsPredicate implements Predicate { public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitExistsPredicate( this ); } + + @Override + public JdbcMappingContainer getExpressionType() { + return expressionType; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/FilterPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/FilterPredicate.java index 9168ef836c..aa4c9fccb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/FilterPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/FilterPredicate.java @@ -9,6 +9,7 @@ package org.hibernate.sql.ast.tree.predicate; import java.util.List; import org.hibernate.internal.FilterJdbcParameter; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; /** @@ -45,4 +46,9 @@ public class FilterPredicate implements Predicate { public List getFilterJdbcParameters() { return filterJdbcParameters; } + + @Override + public JdbcMappingContainer getExpressionType() { + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/GroupedPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/GroupedPredicate.java index 7157a75e90..7ee4590c12 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/GroupedPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/GroupedPredicate.java @@ -6,6 +6,7 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; /** @@ -31,4 +32,9 @@ public class GroupedPredicate implements Predicate { public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitGroupedPredicate( this ); } + + @Override + public JdbcMappingContainer getExpressionType() { + return subPredicate.getExpressionType(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/InListPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/InListPredicate.java index cbef5496f2..cfa00a0ab4 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/InListPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/InListPredicate.java @@ -10,23 +10,23 @@ import java.util.ArrayList; import java.util.List; import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.Expression; /** * @author Steve Ebersole */ -public class InListPredicate implements Predicate { +public class InListPredicate extends AbstractPredicate { private final Expression testExpression; private final List listExpressions; - private final boolean negated; public InListPredicate(Expression testExpression) { this( testExpression, new ArrayList<>() ); } - public InListPredicate(Expression testExpression, boolean negated) { - this( testExpression, new ArrayList<>(), negated ); + public InListPredicate(Expression testExpression, boolean negated, JdbcMappingContainer expressionType) { + this( testExpression, new ArrayList<>(), negated, expressionType ); } public InListPredicate(Expression testExpression, Expression... listExpressions) { @@ -36,16 +36,17 @@ public class InListPredicate implements Predicate { public InListPredicate( Expression testExpression, List listExpressions) { - this( testExpression, listExpressions, false ); + this( testExpression, listExpressions, false, null ); } public InListPredicate( Expression testExpression, List listExpressions, - boolean negated) { + boolean negated, + JdbcMappingContainer expressionType) { + super( expressionType, negated ); this.testExpression = testExpression; this.listExpressions = listExpressions; - this.negated = negated; } public Expression getTestExpression() { @@ -60,15 +61,6 @@ public class InListPredicate implements Predicate { listExpressions.add( expression ); } - public boolean isNegated() { - return negated; - } - - @Override - public boolean isEmpty() { - return false; - } - @Override public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitInListPredicate( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/InSubQueryPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/InSubQueryPredicate.java index 7f0e49dfc6..b9480f6780 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/InSubQueryPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/InSubQueryPredicate.java @@ -6,6 +6,7 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.select.QueryPart; @@ -13,15 +14,18 @@ import org.hibernate.sql.ast.tree.select.QueryPart; /** * @author Steve Ebersole */ -public class InSubQueryPredicate implements Predicate { +public class InSubQueryPredicate extends AbstractPredicate { private final Expression testExpression; private final QueryPart subQuery; - private final boolean negated; public InSubQueryPredicate(Expression testExpression, QueryPart subQuery, boolean negated) { + this( testExpression, subQuery, negated, null ); + } + + public InSubQueryPredicate(Expression testExpression, QueryPart subQuery, boolean negated, JdbcMappingContainer expressionType) { + super( expressionType, negated ); this.testExpression = testExpression; this.subQuery = subQuery; - this.negated = negated; } public Expression getTestExpression() { @@ -32,15 +36,6 @@ public class InSubQueryPredicate implements Predicate { return subQuery; } - public boolean isNegated() { - return negated; - } - - @Override - public boolean isEmpty() { - return false; - } - @Override public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitInSubQueryPredicate( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/Junction.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/Junction.java index f6ad8c5275..b7b32505e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/Junction.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/Junction.java @@ -9,6 +9,7 @@ package org.hibernate.sql.ast.tree.predicate; import java.util.ArrayList; import java.util.List; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; /** @@ -27,10 +28,16 @@ public class Junction implements Predicate { } private final Nature nature; + private final JdbcMappingContainer expressionType; private final List predicates = new ArrayList<>(); public Junction(Nature nature) { + this( nature, null ); + } + + public Junction(Nature nature, JdbcMappingContainer expressionType) { this.nature = nature; + this.expressionType = expressionType; } public void add(Predicate predicate) { @@ -54,4 +61,9 @@ public class Junction implements Predicate { public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitJunction( this ); } + + @Override + public JdbcMappingContainer getExpressionType() { + return expressionType; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/LikePredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/LikePredicate.java index 47d4f4b80f..b86e7eb2de 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/LikePredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/LikePredicate.java @@ -6,19 +6,23 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.Expression; /** * @author Steve Ebersole */ -public class LikePredicate implements Predicate { +public class LikePredicate extends AbstractPredicate { private final Expression matchExpression; private final Expression pattern; private final Expression escapeCharacter; - private final boolean negated; private final boolean isCaseSensitive; + public LikePredicate(Expression matchExpression, Expression pattern) { + this( matchExpression, pattern, null ); + } + public LikePredicate( Expression matchExpression, Expression pattern, @@ -31,7 +35,7 @@ public class LikePredicate implements Predicate { Expression pattern, Expression escapeCharacter, boolean negated) { - this( matchExpression, pattern, escapeCharacter, negated, true ); + this( matchExpression, pattern, escapeCharacter, negated, true, null ); } public LikePredicate( @@ -39,18 +43,15 @@ public class LikePredicate implements Predicate { Expression pattern, Expression escapeCharacter, boolean negated, - boolean isCaseSensitive) { + boolean isCaseSensitive, + JdbcMappingContainer expressionType) { + super( expressionType, negated ); this.matchExpression = matchExpression; this.pattern = pattern; this.escapeCharacter = escapeCharacter; - this.negated = negated; this.isCaseSensitive = isCaseSensitive; } - public LikePredicate(Expression matchExpression, Expression pattern) { - this( matchExpression, pattern, null ); - } - public Expression getMatchExpression() { return matchExpression; } @@ -63,19 +64,10 @@ public class LikePredicate implements Predicate { return escapeCharacter; } - public boolean isNegated() { - return negated; - } - public boolean isCaseSensitive() { return isCaseSensitive; } - @Override - public boolean isEmpty() { - return false; - } - @Override public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitLikePredicate( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/NegatedPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/NegatedPredicate.java index 5553e06e3b..60211b3e71 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/NegatedPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/NegatedPredicate.java @@ -6,6 +6,7 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; /** @@ -31,4 +32,9 @@ public class NegatedPredicate implements Predicate { public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitNegatedPredicate( this ); } + + @Override + public JdbcMappingContainer getExpressionType() { + return predicate.getExpressionType(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/NullnessPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/NullnessPredicate.java index b5556126f9..0fc9f71a6c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/NullnessPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/NullnessPredicate.java @@ -6,38 +6,33 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.Expression; /** * @author Steve Ebersole */ -public class NullnessPredicate implements Predicate { +public class NullnessPredicate extends AbstractPredicate { private final Expression expression; - private final boolean negated; public NullnessPredicate(Expression expression) { - this( expression, false ); + this( expression, false, null ); } public NullnessPredicate(Expression expression, boolean negated) { + this( expression, negated, null ); + } + + public NullnessPredicate(Expression expression, boolean negated, JdbcMappingContainer expressionType) { + super( expressionType, negated ); this.expression = expression; - this.negated = negated; } public Expression getExpression() { return expression; } - public boolean isNegated() { - return negated; - } - - @Override - public boolean isEmpty() { - return false; - } - @Override public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitNullnessPredicate( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/Predicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/Predicate.java index 6e9901a50c..78dcb344a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/Predicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/Predicate.java @@ -6,15 +6,25 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.query.sqm.sql.internal.DomainResultProducer; +import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstTreeHelper; +import org.hibernate.sql.ast.spi.SqlExpressionResolver; +import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.basic.BasicResult; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.spi.TypeConfiguration; /** * Models a predicate in the SQL AST * * @author Steve Ebersole */ -public interface Predicate extends SqlAstNode { +public interface Predicate extends Expression, DomainResultProducer { /** * Short-cut for {@link SqlAstTreeHelper#combinePredicates} */ @@ -23,4 +33,19 @@ public interface Predicate extends SqlAstNode { } boolean isEmpty(); + + @Override + default DomainResult createDomainResult(String resultVariable, DomainResultCreationState creationState) { + final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState(); + final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver(); + final JavaTypeDescriptor javaTypeDescriptor = getExpressionType().getJdbcMappings().get( 0 ).getJavaTypeDescriptor(); + final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection( + this, + javaTypeDescriptor, + sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration() + ); + + //noinspection unchecked + return new BasicResult( sqlSelection.getValuesArrayPosition(), resultVariable, javaTypeDescriptor ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/SelfRenderingPredicate.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/SelfRenderingPredicate.java index 0bfe8a515b..dd5a7fe9e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/SelfRenderingPredicate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/predicate/SelfRenderingPredicate.java @@ -6,6 +6,7 @@ */ package org.hibernate.sql.ast.tree.predicate; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression; @@ -33,4 +34,9 @@ public class SelfRenderingPredicate implements Predicate { public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitSelfRenderingPredicate( this ); } + + @Override + public JdbcMappingContainer getExpressionType() { + return selfRenderingExpression.getExpressionType(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QuerySpec.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QuerySpec.java index 1978f1a81f..2bb062646d 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QuerySpec.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QuerySpec.java @@ -122,12 +122,14 @@ public class QuerySpec extends QueryPart implements SqlAstNode, PredicateContain @Override public JdbcMappingContainer getExpressionType() { - if ( selectClause.getSqlSelections().size() == 1 ) { - SqlSelection first = selectClause.getSqlSelections().get( 0 ); - return first.getExpressionType(); - } - else { - return null; + final List sqlSelections = selectClause.getSqlSelections(); + switch ( sqlSelections.size() ) { + case 1: + return sqlSelections.get( 0 ).getExpressionType(); + default: + // todo (6.0): At some point we should create an ArrayTupleType and return that + case 0: + return null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java index a90ce8e211..716aaf4162 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java @@ -212,6 +212,7 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA compositeInstance = null; } else { + notifyParentResolutionListeners( compositeInstance ); if ( compositeInstance instanceof HibernateProxy ) { Object target = embeddedModelPartDescriptor.getEmbeddableTypeDescriptor() .getRepresentationStrategy() diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiation.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiation.java index b057929f51..7cf2286839 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiation.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiation.java @@ -90,7 +90,7 @@ public class DynamicInstantiation implements DomainResultProducer { arguments = new ArrayList<>(); } - arguments.add( new DynamicInstantiationArgument<>( alias, argumentResultProducer, creationState ) ); + arguments.add( new DynamicInstantiationArgument<>( argumentResultProducer, alias ) ); } public void complete() { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiationArgument.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiationArgument.java index e2b3a52d9d..417d19df56 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiationArgument.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/instantiation/internal/DynamicInstantiationArgument.java @@ -6,23 +6,21 @@ */ package org.hibernate.sql.results.graph.instantiation.internal; +import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter; import org.hibernate.query.sqm.sql.internal.DomainResultProducer; -import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.results.graph.DomainResultCreationState; /** * @author Steve Ebersole */ public class DynamicInstantiationArgument { - private final ArgumentDomainResult argumentResult; + private final DomainResultProducer argumentResultProducer; private final String alias; @SuppressWarnings("WeakerAccess") - public DynamicInstantiationArgument( - String alias, - DomainResultProducer argumentResultProducer, - DomainResultCreationState creationState) { - this.argumentResult = new ArgumentDomainResult<>( argumentResultProducer.createDomainResult( alias, creationState ) ); + public DynamicInstantiationArgument(DomainResultProducer argumentResultProducer, String alias) { + this.argumentResultProducer = argumentResultProducer; this.alias = alias; } @@ -31,6 +29,12 @@ public class DynamicInstantiationArgument { } public ArgumentDomainResult buildArgumentDomainResult(DomainResultCreationState creationState) { - return argumentResult; + final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlAstCreationState() + .getCurrentProcessingState() + .getSqlExpressionResolver(); + if ( sqlExpressionResolver instanceof BaseSqmToSqlAstConverter.SqmAliasedNodeCollector ) { + ( (BaseSqmToSqlAstConverter.SqmAliasedNodeCollector) sqlExpressionResolver ).next(); + } + return new ArgumentDomainResult<>( argumentResultProducer.createDomainResult( alias, creationState ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/tuple/TupleResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/tuple/TupleResult.java new file mode 100644 index 0000000000..025eb0858c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/tuple/TupleResult.java @@ -0,0 +1,75 @@ +/* + * 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.results.graph.tuple; + +import org.hibernate.Internal; +import org.hibernate.query.NavigablePath; +import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.DomainResultAssembler; +import org.hibernate.sql.results.graph.basic.BasicResultGraphNode; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; + +/** + * @author Christian Beikov + */ +public class TupleResult implements DomainResult, BasicResultGraphNode { + private final String resultVariable; + private final JavaTypeDescriptor javaTypeDescriptor; + + private final NavigablePath navigablePath; + + private final DomainResultAssembler assembler; + + public TupleResult( + int[] jdbcValuesArrayPositions, + String resultVariable, + JavaTypeDescriptor javaTypeDescriptor) { + this( jdbcValuesArrayPositions, resultVariable, javaTypeDescriptor, (NavigablePath) null ); + } + + public TupleResult( + int[] jdbcValuesArrayPositions, + String resultVariable, + JavaTypeDescriptor javaTypeDescriptor, + NavigablePath navigablePath) { + this.resultVariable = resultVariable; + this.javaTypeDescriptor = javaTypeDescriptor; + + this.navigablePath = navigablePath; + + this.assembler = new TupleResultAssembler<>( jdbcValuesArrayPositions, javaTypeDescriptor ); + } + + @Override + public String getResultVariable() { + return resultVariable; + } + + @Override + public JavaTypeDescriptor getResultJavaTypeDescriptor() { + return javaTypeDescriptor; + } + + @Override + public NavigablePath getNavigablePath() { + return navigablePath; + } + + /** + * For testing purposes only + */ + @Internal + public DomainResultAssembler getAssembler() { + return assembler; + } + + @Override + public DomainResultAssembler createResultAssembler(AssemblerCreationState creationState) { + return assembler; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/tuple/TupleResultAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/tuple/TupleResultAssembler.java new file mode 100644 index 0000000000..26df4b6fc7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/tuple/TupleResultAssembler.java @@ -0,0 +1,66 @@ +/* + * 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.results.graph.tuple; + +import org.hibernate.sql.results.ResultsLogger; +import org.hibernate.sql.results.graph.DomainResultAssembler; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; +import org.hibernate.sql.results.jdbc.spi.RowProcessingState; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; + +/** + * @author Christian Beikov + */ +public class TupleResultAssembler implements DomainResultAssembler { + + private final int[] valuesArrayPositions; + private final JavaTypeDescriptor assembledJavaTypeDescriptor; + + public TupleResultAssembler( + int[] valuesArrayPositions, + JavaTypeDescriptor assembledJavaTypeDescriptor) { + this.valuesArrayPositions = valuesArrayPositions; + this.assembledJavaTypeDescriptor = assembledJavaTypeDescriptor; + } + + /** + * Access to the raw value (unconverted, if a converter applied) + */ + public Object[] extractRawValue(RowProcessingState rowProcessingState) { + final Object[] values = new Object[valuesArrayPositions.length]; + for ( int i = 0; i < valuesArrayPositions.length; i++ ) { + values[i] = rowProcessingState.getJdbcValue( valuesArrayPositions[i] ); + } + return values; + } + + @Override + public J assemble( + RowProcessingState rowProcessingState, + JdbcValuesSourceProcessingOptions options) { + final Object[] jdbcValues = extractRawValue( rowProcessingState ); + + if ( ResultsLogger.LOGGER.isDebugEnabled() ) { + for ( int i = 0; i < valuesArrayPositions.length; i++ ) { + ResultsLogger.LOGGER.debugf( + "Extracted JDBC value [%d] - [%s]", + valuesArrayPositions[i], + jdbcValues[i] + ); + } + } + + //noinspection unchecked + return (J) jdbcValues; + } + + @Override + public JavaTypeDescriptor getAssembledJavaTypeDescriptor() { + return assembledJavaTypeDescriptor; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralWithSingleQuoteTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralWithSingleQuoteTest.java deleted file mode 100644 index 987144359a..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralWithSingleQuoteTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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 . - */ -package org.hibernate.jpa.test.criteria.literal; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; - -import org.hibernate.dialect.CockroachDialect; -import org.hibernate.dialect.PostgreSQL81Dialect; -import org.hibernate.dialect.SQLServerDialect; -import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; - -import org.hibernate.testing.SkipForDialect; -import org.hibernate.testing.SkipForDialects; -import org.hibernate.testing.TestForIssue; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertEquals; - -@TestForIssue( jiraKey = "HHH-14077") -public class CriteriaLiteralWithSingleQuoteTest extends BaseEntityManagerFunctionalTestCase { - - @Test - public void literalSingleQuoteTest() throws Exception { - - doInJPA( - this::entityManagerFactory, - entityManager -> { - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery(); - query.select( cb.literal( '\'' ) ).from( Student.class ); - Object object = entityManager.createQuery( query ).getSingleResult(); - assertEquals( "'", object ); - } - ); - } - - @Test - public void literalProjectionTest() throws Exception { - - doInJPA( - this::entityManagerFactory, - entityManager -> { - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery(); - query.multiselect( cb.literal( "' || aValue || '" ) ).from( Student.class ); - Object object = entityManager.createQuery( query ).getSingleResult(); - assertEquals( "' || aValue || '", object ); - } - ); - } - - @Test - @SkipForDialects( - value = { - @SkipForDialect(value = SQLServerDialect.class, comment = "SQLServer does not support literals in group by statement"), - @SkipForDialect(value = PostgreSQL81Dialect.class, comment = "PostgreSQL does not support literals in group by statement"), - @SkipForDialect( value = CockroachDialect.class, comment = "CockroachDB does not support literals in group by statement") - } - ) - public void testLiteralProjectionAndGroupBy() throws Exception { - doInJPA( - this::entityManagerFactory, - entityManager -> { - - final String literal = "' || aValue || '"; - - CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery(); - query.multiselect( cb.literal( literal ) ) - .from( Student.class ); - query.groupBy( cb.literal( literal ) ); - - Object object = entityManager.createQuery( query ).getSingleResult(); - assertEquals( literal, object ); - } - ); - } - - @Before - public void setupData() { - doInJPA( - this::entityManagerFactory, - entityManager -> { - Student student = new Student(); - student.setAValue( "A Value" ); - entityManager.persist( student ); - } - ); - } - - @After - public void cleanupData() { - doInJPA( - this::entityManagerFactory, - entityManager -> { - entityManager.createQuery( "delete from Student" ); - } - ); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Student.class }; - } - - @Entity(name = "Student") - @Table(name = "Students") - public static class Student { - - @Id - @GeneratedValue - private Long id; - - @Column - private String aValue; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - this.id = id; - } - - public String getAValue() { - return aValue; - } - - public void setAValue(String value) { - this.aValue = value; - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/mapping/NestedEmbeddableTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/mapping/NestedEmbeddableTest.java index dfba5e9e5c..7c054c02d8 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/mapping/NestedEmbeddableTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/mapping/NestedEmbeddableTest.java @@ -14,13 +14,11 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import javax.persistence.AssociationOverride; -import javax.persistence.Basic; import javax.persistence.Column; import javax.persistence.ElementCollection; import javax.persistence.Embeddable; import javax.persistence.Embedded; import javax.persistence.Entity; -import javax.persistence.EntityManager; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; @@ -35,21 +33,10 @@ import javax.persistence.MapKeyColumn; import javax.persistence.OneToMany; import javax.persistence.OrderBy; import javax.persistence.Table; -import javax.persistence.TypedQuery; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Root; -import org.hibernate.Hibernate; import org.hibernate.annotations.Type; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; -import org.hibernate.jpa.test.criteria.components.Alias; -import org.hibernate.jpa.test.criteria.components.Client; -import org.hibernate.jpa.test.criteria.components.Client_; -import org.hibernate.jpa.test.criteria.components.Name_; -import org.hibernate.testing.TestForIssue; -import org.junit.Assert; import org.junit.Test; import static org.junit.Assert.assertTrue; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/Oracle12LimitHandlerTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/Oracle12LimitHandlerTest.java index 6be5f81ed0..46d72fca11 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/Oracle12LimitHandlerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/Oracle12LimitHandlerTest.java @@ -22,7 +22,7 @@ public class Oracle12LimitHandlerTest { @Test public void testSqlWithSpace() { final String sql = "select p.name from Person p where p.id = 1 for update"; - final String expected = "select * from ( select p.name from Person p where p.id = 1 ) where rownum <= ? for update"; + final String expected = "select * from (select p.name from Person p where p.id = 1) where rownum<=? for update"; final QueryParameters queryParameters = getQueryParameters( 0, 5 ); final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); @@ -33,7 +33,7 @@ public class Oracle12LimitHandlerTest { @Test public void testSqlWithSpaceInsideQuotedString() { final String sql = "select p.name from Person p where p.name = ' this is a string with spaces ' for update"; - final String expected = "select * from ( select p.name from Person p where p.name = ' this is a string with spaces ' ) where rownum <= ? for update"; + final String expected = "select * from (select p.name from Person p where p.name = ' this is a string with spaces ') where rownum<=? for update"; final QueryParameters queryParameters = getQueryParameters( 0, 5 ); final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); @@ -55,7 +55,7 @@ public class Oracle12LimitHandlerTest { @Test public void testSqlWithForUpdateInsideAndOutsideQuotedStringA() { final String sql = "select a.prop from A a where a.name = 'this is for update ' for update"; - final String expected = "select * from ( select a.prop from A a where a.name = 'this is for update ' ) where rownum <= ? for update"; + final String expected = "select * from (select a.prop from A a where a.name = 'this is for update ') where rownum<=? for update"; final QueryParameters queryParameters = getQueryParameters( 0, 5 ); final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/SQLServer2005DialectTestCase.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/SQLServer2005DialectTestCase.java index 4cd71a5f23..02b200d019 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/SQLServer2005DialectTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/SQLServer2005DialectTestCase.java @@ -47,9 +47,9 @@ public class SQLServer2005DialectTestCase extends BaseUnitTestCase { String input = "select distinct f1 as f53245 from table849752 order by f234, f67 desc"; assertEquals( - "with query_ as (select row_.*, row_number() over (order by current_timestamp) as rownumber_ from (" + + "with query_ as (select row_.*,row_number() over (order by current_timestamp) as rownumber_ from (" + "select distinct top(?) f1 as f53245 from table849752 order by f234, f67 desc) row_)" + - " select f53245 from query_ where rownumber_ >= ? and rownumber_ < ?", + " select f53245 from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "with query_ as (select row_.*,row_number() over (order by current_timestamp) as rownumber_ from (" + + query + ") row_) select * from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "with query_ as (select row_.*,row_number() over (order by current_timestamp) as rownumber_ from (" + + query + ") row_) select * from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "FROM Employee E WHERE E.firstName = :firstName) row_) select col0_,col1_ from query_ " + + "where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select rid1688_,deviati16_1688_,sortindex1688_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select col0_,col1_,col2_,col3_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select c1,c2,c3,c4 from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select c1,c2 from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select col_0_0_,col_1_0_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select CONTENT1_12_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "row_) select col0_,tmp1,col1_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select f1 from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select col0_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select f1 from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select col_0_0_,col_1_0_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select f1,f2 from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select col0_,col1_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select * from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select * from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select col0_,col1_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select c1,col0_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "select c1,col0_ from query_ where rownumber_>=? and rownumber_0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC"; assertEquals( - "with query_ as (select row_.*, row_number() over (order by current_timestamp) as rownumber_ from (" + + "with query_ as (select row_.*,row_number() over (order by current_timestamp) as rownumber_ from (" + "select top(?) t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC) row_) " + - "select col_0_0, col_1_0 from query_ where rownumber_ >= ? and rownumber_ < ?", + "select col_0_0,col_1_0 from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + "with query_ as (select row_.*,row_number() over (order by current_timestamp) as rownumber_ from (" + + "select top(?) t1.c1 as col_0_0 FROM table1 t1 where t1.c1 = '(123' ORDER BY t1.c1 ASC) row_) select col_0_0 from query_ where rownumber_>=? and rownumber_= ? " + - "and rownumber_ < ?", + "FROM a) row_) select col0_,col1_ from query_ where rownumber_>=? " + + "and rownumber_= " + - "? and rownumber_ < ?", + "as col1_ FROM a) row_) select col0_,col1_ from query_ where rownumber_>=" + + "? and rownumber_= ? and rownumber_ < ?", + " select col0_,col1_,col2_,col3_ from query_ where rownumber_>=? and rownumber_= ? and rownumber_ < ?", + " select col0_,col1_,col2_,col3_ from query_ where rownumber_>=? and rownumber_ criteria = detachedCriteriaBuilder.createQuery( Student.class ); @@ -133,7 +131,6 @@ public class CriteriaQueryWithAppliedFilterTest { } @Test - @FailureExpected(reason = "subquery not fully implemented in v6 yet") void testSubqueryWithRestrictionsOnComponentTypes(SessionFactoryScope scope) { final CriteriaBuilder detachedCriteriaBuilder = scope.getSessionFactory().getCriteriaBuilder(); final CriteriaQuery criteria = detachedCriteriaBuilder.createQuery( Student.class ); @@ -172,7 +169,6 @@ public class CriteriaQueryWithAppliedFilterTest { } @Test - @FailureExpected(reason = "subquery not fully implemented in v6 yet") void testSubqueryWithRestrictionsOnComponentTypes2(SessionFactoryScope scope) { final CriteriaBuilder detachedCriteriaBuilder = scope.getSessionFactory().getCriteriaBuilder(); final CriteriaQuery criteria = detachedCriteriaBuilder.createQuery( Student.class ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/intg/sqm/HqlTranslationNoFactoryTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/intg/sqm/HqlTranslationNoFactoryTests.java index 2d926addbf..4d8d4a18e2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/intg/sqm/HqlTranslationNoFactoryTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/intg/sqm/HqlTranslationNoFactoryTests.java @@ -116,6 +116,8 @@ public class HqlTranslationNoFactoryTests { final SqmCreationOptions sqmCreationOptions = () -> false; final QueryEngine queryEngine = new QueryEngine( + null, + null, jpaMetamodel, ValueHandlingMode.BIND, ConfigurationHelper.getPreferredSqlTypeCodeForBoolean( registryScope.getRegistry() ), diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/CallbackAndDirtyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/CallbackAndDirtyTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/CallbackAndDirtyTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/CallbackAndDirtyTest.java index 9d8dbd81b0..e8a5cbb336 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/CallbackAndDirtyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/CallbackAndDirtyTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.callbacks; +package org.hibernate.orm.test.jpa.callbacks; import java.util.Iterator; import java.util.List; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/Customer.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/Customer.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/Customer.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/Customer.java index 870e07c679..3ddd42613b 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/Customer.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/Customer.java @@ -6,7 +6,7 @@ */ //$Id$ -package org.hibernate.jpa.test.callbacks; +package org.hibernate.orm.test.jpa.callbacks; import javax.persistence.Entity; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/Employee.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/Employee.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/Employee.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/Employee.java index 0c9509bffa..0a60f31a33 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/Employee.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/Employee.java @@ -6,7 +6,7 @@ */ //$Id$ -package org.hibernate.jpa.test.callbacks; +package org.hibernate.orm.test.jpa.callbacks; import java.math.BigDecimal; import javax.persistence.Entity; import javax.persistence.Inheritance; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/Person.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/Person.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/Person.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/Person.java index 1e139c2c43..5dc504f7ec 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/Person.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/Person.java @@ -6,7 +6,7 @@ */ //$Id$ -package org.hibernate.jpa.test.callbacks; +package org.hibernate.orm.test.jpa.callbacks; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PreUpdateBytecodeEnhancementTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/PreUpdateBytecodeEnhancementTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PreUpdateBytecodeEnhancementTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/PreUpdateBytecodeEnhancementTest.java index 0e9ab1b321..85ba1ef2bd 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PreUpdateBytecodeEnhancementTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/PreUpdateBytecodeEnhancementTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.callbacks; +package org.hibernate.orm.test.jpa.callbacks; import java.nio.ByteBuffer; import java.time.Instant; @@ -112,7 +112,7 @@ public class PreUpdateBytecodeEnhancementTest extends BaseEntityManagerFunctiona @Lob @Basic(fetch = FetchType.LAZY) - private ByteBuffer image; + private byte[] image; @PrePersist void beforeCreate() { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PreUpdateCustomEntityDirtinessStrategyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/PreUpdateCustomEntityDirtinessStrategyTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PreUpdateCustomEntityDirtinessStrategyTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/PreUpdateCustomEntityDirtinessStrategyTest.java index bb45944c81..39e189bde7 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PreUpdateCustomEntityDirtinessStrategyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/PreUpdateCustomEntityDirtinessStrategyTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.callbacks; +package org.hibernate.orm.test.jpa.callbacks; import java.nio.ByteBuffer; import java.time.Instant; @@ -165,7 +165,7 @@ public class PreUpdateCustomEntityDirtinessStrategyTest @Lob @Basic(fetch = FetchType.LAZY) - private ByteBuffer image; + private byte[] image; @PrePersist void beforeCreate() { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PreUpdateDirtyCheckingInterceptorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/PreUpdateDirtyCheckingInterceptorTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PreUpdateDirtyCheckingInterceptorTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/PreUpdateDirtyCheckingInterceptorTest.java index 93a3f80697..c5158c0cbb 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PreUpdateDirtyCheckingInterceptorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/callbacks/PreUpdateDirtyCheckingInterceptorTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.callbacks; +package org.hibernate.orm.test.jpa.callbacks; import java.io.Serializable; import java.nio.ByteBuffer; @@ -140,7 +140,7 @@ public class PreUpdateDirtyCheckingInterceptorTest @Lob @Basic(fetch = FetchType.LAZY) - private ByteBuffer image; + private byte[] image; @PrePersist void beforeCreate() { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Animal.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Animal.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Animal.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Animal.java index 2301bb86fd..f136836115 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Animal.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Animal.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import java.util.Date; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Attribute.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Attribute.java similarity index 87% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Attribute.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Attribute.java index 17d9a09d36..3d378e1e5c 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Attribute.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Attribute.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; /** * @author Chris Cranford diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Book.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Book.java similarity index 93% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Book.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Book.java index 3d9a67243a..a2bbd3d590 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Book.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Book.java @@ -4,9 +4,8 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; -import java.util.List; import java.util.Set; import javax.persistence.Entity; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Color.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Color.java similarity index 91% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Color.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Color.java index c10eb15e68..a4a7dbbc38 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Color.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Color.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import javax.persistence.Embeddable; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/CriteriaCompilingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaCompilingTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/CriteriaCompilingTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaCompilingTest.java index e3494c77b4..783be5e3ab 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/CriteriaCompilingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaCompilingTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/CriteriaQueryTypeQueryAdapterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaQueryTypeQueryAdapterTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/CriteriaQueryTypeQueryAdapterTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaQueryTypeQueryAdapterTest.java index 9c727fc221..1db4f873fb 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/CriteriaQueryTypeQueryAdapterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/CriteriaQueryTypeQueryAdapterTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ElementCollectionConverterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ElementCollectionConverterTest.java index 477a7561b3..3eba903f78 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ElementCollectionConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ElementCollectionConverterTest.java @@ -12,9 +12,6 @@ import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; -import org.hibernate.jpa.test.criteria.Color; -import org.hibernate.jpa.test.criteria.Industry; - import org.hibernate.testing.TestForIssue; import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; import org.hibernate.testing.orm.junit.Jpa; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Elephant.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Elephant.java similarity index 89% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Elephant.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Elephant.java index 040420bdcc..efbbad81c8 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Elephant.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Elephant.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/EntitySuperclassCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/EntitySuperclassCollectionTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/EntitySuperclassCollectionTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/EntitySuperclassCollectionTest.java index 265fd55b0c..8814789423 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/EntitySuperclassCollectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/EntitySuperclassCollectionTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import java.util.ArrayList; import java.util.List; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Human.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Human.java similarity index 89% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Human.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Human.java index 30904edcff..bcd054ea6b 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Human.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Human.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import javax.persistence.Entity; import javax.persistence.Table; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/HumanDTO.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/HumanDTO.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/HumanDTO.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/HumanDTO.java index e36b590c73..2ce4284884 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/HumanDTO.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/HumanDTO.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; public class HumanDTO { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Industry.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Industry.java similarity index 91% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Industry.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Industry.java index 220439f736..c7bc1fa8a6 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Industry.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Industry.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import javax.persistence.Embeddable; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Item.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Item.java index c61093785e..6199e78a52 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Item.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Item.java @@ -16,9 +16,6 @@ import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; -import org.hibernate.jpa.test.criteria.Attribute; -import org.hibernate.jpa.test.criteria.ItemAttributeConverter; - /** * @author Chris Cranford */ diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/ItemAttributeConverter.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ItemAttributeConverter.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/ItemAttributeConverter.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ItemAttributeConverter.java index c029ff96e3..cf19fb3145 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/ItemAttributeConverter.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ItemAttributeConverter.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import java.util.HashMap; import java.util.Map; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/ManipulationCriteriaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ManipulationCriteriaTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/ManipulationCriteriaTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ManipulationCriteriaTest.java index 86ac13f318..f8e066aad4 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/ManipulationCriteriaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ManipulationCriteriaTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/MultiTypedBasicAttributesEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/MultiTypedBasicAttributesEntity.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/MultiTypedBasicAttributesEntity.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/MultiTypedBasicAttributesEntity.java index a8ece15d23..051ef0062d 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/MultiTypedBasicAttributesEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/MultiTypedBasicAttributesEntity.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/ParameterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ParameterTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/ParameterTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ParameterTest.java index 7a201372b9..ec4c14c937 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/ParameterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/ParameterTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import javax.persistence.EntityManager; import javax.persistence.Parameter; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/QueryBuilderTest.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/QueryBuilderTest.java index 9b95742af4..10d0e473d8 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/QueryBuilderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/QueryBuilderTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import java.util.ArrayList; import java.util.Arrays; @@ -12,6 +12,7 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import javax.persistence.EntityManager; +import javax.persistence.Tuple; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; @@ -20,7 +21,6 @@ import javax.persistence.criteria.Root; import javax.persistence.criteria.SetJoin; import javax.persistence.metamodel.EntityType; import org.hibernate.dialect.CockroachDialect; -import org.hibernate.dialect.H2Dialect; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.jpa.test.metamodel.Address; import org.hibernate.jpa.test.metamodel.Alias; @@ -39,7 +39,6 @@ import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl; import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate; import org.hibernate.testing.FailureExpected; -import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.junit.Test; @@ -212,20 +211,19 @@ public class QueryBuilderTest extends BaseEntityManagerFunctionalTestCase { @Test @TestForIssue(jiraKey = "HHH-8699") - // For now, restrict to H2. Selecting w/ predicate functions cause issues for too many dialects. - @RequiresDialect(value = H2Dialect.class, jiraKey = "HHH-9092") public void testMultiselectWithPredicates() { EntityManager em = getOrCreateEntityManager(); em.getTransaction().begin(); + em.createQuery( "select (c.id, c.name), c.age from Customer c" ).getResultList(); CriteriaBuilder cb = em.getCriteriaBuilder(); - CriteriaQuery cq = cb.createQuery( Customer.class ); + CriteriaQuery cq = cb.createTupleQuery(); Root r = cq.from( Customer.class ); cq.multiselect( r.get( Customer_.id ), r.get( Customer_.name ), cb.concat( "Hello ", r.get( Customer_.name ) ), cb.isNotNull( r.get( Customer_.age ) ) ); - TypedQuery tq = em.createQuery( cq ); + TypedQuery tq = em.createQuery( cq ); tq.getResultList(); em.getTransaction().commit(); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Store.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Store.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Store.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Store.java index 6b8bb1dd8f..85e3337932 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/Store.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/Store.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/SuperclassCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/SuperclassCollectionTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/SuperclassCollectionTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/SuperclassCollectionTest.java index 72de902cf0..b3e99f5f65 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/SuperclassCollectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/SuperclassCollectionTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import java.util.ArrayList; import java.util.List; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/TreatJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatJoinTest.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/TreatJoinTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatJoinTest.java index ad8d942e9c..c05f2c0c3f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/TreatJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatJoinTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import java.util.List; import javax.persistence.CascadeType; @@ -62,13 +62,13 @@ public class TreatJoinTest extends BaseEntityManagerFunctionalTestCase { public void testTreatJoin() { doInJPA( this::entityManagerFactory, entityManager -> { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery( Bid.class ); + CriteriaQuery query = cb.createQuery( String.class ); Root bid = query.from( Bid.class ); Join book = cb.treat( bid.join( "item" ), Book.class ); query.select( book.get( "title" ) ); - final List resultList = entityManager.createQuery( query ).getResultList(); + final List resultList = entityManager.createQuery( query ).getResultList(); assertThat(resultList.size(),is(2)); } ); } @@ -96,7 +96,7 @@ public class TreatJoinTest extends BaseEntityManagerFunctionalTestCase { public void testJoinMethodOnATreatedJoin() { doInJPA( this::entityManagerFactory, entityManager -> { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery( Bid.class ); + CriteriaQuery query = cb.createQuery( String.class ); Root bid = query.from( Bid.class ); final Join item = bid.join( "item" ); @@ -108,7 +108,7 @@ public class TreatJoinTest extends BaseEntityManagerFunctionalTestCase { query.where( cb.equal( price.get("amount"), 10 ) ); - final List resultList = entityManager.createQuery( query ).getResultList(); + final List resultList = entityManager.createQuery( query ).getResultList(); assertThat(resultList.size(),is(2)); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/TreatKeywordTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/TreatKeywordTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java index 422ddc7e89..f351bffb63 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/TreatKeywordTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatKeywordTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import java.util.Arrays; import java.util.List; @@ -100,7 +100,7 @@ public class TreatKeywordTest extends BaseEntityManagerFunctionalTestCase { EntityType Animal_ = em.getMetamodel().entity(Animal.class); criteria.select(root.get(Animal_.getSingularAttribute("name", String.class))); - criteria.where(builder.like(builder.treat(root, Human.class).get( org.hibernate.jpa.test.criteria.Human_.name ), "2%")); + criteria.where(builder.like(builder.treat(root, Human.class).get( Human_.name ), "2%")); List animalList = em.createQuery( criteria ).getResultList(); Assert.assertEquals("treat(Animal as Human) was ignored",1, animalList.size()); @@ -111,7 +111,7 @@ public class TreatKeywordTest extends BaseEntityManagerFunctionalTestCase { idCriteria.where( builder.like( builder.treat( idRoot, Human.class ) - .get( org.hibernate.jpa.test.criteria.Human_.name ), "2%" + .get( Human_.name ), "2%" ) ); List animalIdList = em.createQuery( idCriteria ).getResultList(); @@ -269,9 +269,13 @@ public class TreatKeywordTest extends BaseEntityManagerFunctionalTestCase { this.fast = fast; } - public final boolean isFast() { + public boolean isFast() { return fast; } + + public void setFast(boolean fast) { + this.fast = fast; + } } @Entity(name = "Dachshund") diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/TreatListJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatListJoinTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/TreatListJoinTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatListJoinTest.java index 6a67266268..85fcd3bb2a 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/TreatListJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/TreatListJoinTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria; +package org.hibernate.orm.test.jpa.criteria; import javax.persistence.CascadeType; import javax.persistence.Entity; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/alias/CriteriaMultiselectAliasTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/alias/CriteriaMultiselectAliasTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/alias/CriteriaMultiselectAliasTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/alias/CriteriaMultiselectAliasTest.java index 933f97c83b..6bd9d480b3 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/alias/CriteriaMultiselectAliasTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/alias/CriteriaMultiselectAliasTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.alias; +package org.hibernate.orm.test.jpa.criteria.alias; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/AggregationResultTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/AggregationResultTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/AggregationResultTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/AggregationResultTest.java index 063ba43b3d..5746b16f04 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/AggregationResultTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/AggregationResultTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.basic; +package org.hibernate.orm.test.jpa.criteria.basic; import java.math.BigDecimal; import java.math.BigInteger; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/BasicCriteriaUsageTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/BasicCriteriaUsageTest.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/BasicCriteriaUsageTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/BasicCriteriaUsageTest.java index 1fa9ffefb1..6c84272318 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/BasicCriteriaUsageTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/BasicCriteriaUsageTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.basic; +package org.hibernate.orm.test.jpa.criteria.basic; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -24,6 +24,7 @@ import javax.persistence.metamodel.SingularAttribute; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.testing.TestForIssue; +import org.junit.Ignore; import org.junit.Test; /** @@ -65,6 +66,8 @@ public class BasicCriteriaUsageTest extends BaseEntityManagerFunctionalTestCase @Test @TestForIssue(jiraKey = "HHH-8283") + // todo (6.0): needs a composite user type mechanism e.g. by providing a custom ComponentTuplizer/Instantiator + @Ignore( "Missing support for composite user types" ) public void testDateCompositeCustomType() { Payment payment = new Payment(); payment.setAmount( new BigDecimal( 1000 ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/ConcatTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/ConcatTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/ConcatTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/ConcatTest.java index 8837182208..7a6e853ebf 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/ConcatTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/ConcatTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.basic; +package org.hibernate.orm.test.jpa.criteria.basic; import javax.persistence.Entity; import javax.persistence.EntityManager; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/ExpressionsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/ExpressionsTest.java similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/ExpressionsTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/ExpressionsTest.java index 97dfedddb0..3a06c4af68 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/ExpressionsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/ExpressionsTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.basic; +package org.hibernate.orm.test.jpa.criteria.basic; import java.math.BigDecimal; import java.math.BigInteger; @@ -18,14 +18,15 @@ import javax.persistence.criteria.ParameterExpression; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; +import org.hibernate.dialect.DB2Dialect; +import org.hibernate.dialect.DerbyDialect; import org.hibernate.query.Query; -import org.hibernate.dialect.H2Dialect; import org.hibernate.jpa.test.metamodel.AbstractMetamodelSpecificTest; import org.hibernate.jpa.test.metamodel.Phone; import org.hibernate.jpa.test.metamodel.Product; import org.hibernate.jpa.test.metamodel.Product_; -import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.junit.After; import org.junit.Before; @@ -84,7 +85,6 @@ public class ExpressionsTest extends AbstractMetamodelSpecificTest { @Test @TestForIssue( jiraKey = "HHH-6876" ) - @RequiresDialect( H2Dialect.class ) public void testEmptyInList() { EntityManager em = getOrCreateEntityManager(); em.getTransaction().begin(); @@ -218,6 +218,11 @@ public class ExpressionsTest extends AbstractMetamodelSpecificTest { } @Test + @SkipForDialect(value = DerbyDialect.class, comment = "By default, unless some kind of context enables inference," + + "a numeric/decimal parameter has the type DECIMAL(31,31) which might cause an overflow on certain arithmetics." + + "Fixing this would require a custom SqmToSqlAstConverter that creates a special JdbcParameter " + + "that is always rendered as literal. Since numeric literal + parameter arithmetic is rare, we skip this for now.") + @SkipForDialect(value = DB2Dialect.class, comment = "Same reason as for Derby") public void testQuotientAndMultiply() { EntityManager em = getOrCreateEntityManager(); em.getTransaction().begin(); @@ -270,8 +275,8 @@ public class ExpressionsTest extends AbstractMetamodelSpecificTest { em.close(); } - private int countGeneratedParameters(Query query) { - return query.getParameterMetadata().getNamedParameterNames().size(); + private int countGeneratedParameters(Query query) { + return query.getParameterMetadata().getParameterCount(); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/InWithHeterogeneousCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/InWithHeterogeneousCollectionTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/InWithHeterogeneousCollectionTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/InWithHeterogeneousCollectionTest.java index a0b9abe8dd..8ceb8b006e 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/InWithHeterogeneousCollectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/InWithHeterogeneousCollectionTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.basic; +package org.hibernate.orm.test.jpa.criteria.basic; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/ListIndexTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/ListIndexTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/ListIndexTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/ListIndexTest.java index e0b3ec62d7..a4e72c9352 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/ListIndexTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/ListIndexTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.basic; +package org.hibernate.orm.test.jpa.criteria.basic; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/Payment.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/Payment.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/Payment.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/Payment.java index 4f97a28954..b7fb19d252 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/Payment.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/Payment.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.basic; +package org.hibernate.orm.test.jpa.criteria.basic; import java.math.BigDecimal; import java.util.Date; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/PredicateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/PredicateTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/PredicateTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/PredicateTest.java index e0f08b7643..5f7e8b86d6 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/PredicateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/PredicateTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.basic; +package org.hibernate.orm.test.jpa.criteria.basic; import java.util.List; import javax.persistence.EntityManager; @@ -195,8 +195,6 @@ public class PredicateTest extends AbstractMetamodelSpecificTest { Predicate p1 = builder.equal( orderRoot.get( "id" ), "order-1" ); Predicate p2 = builder.equal( orderRoot.get( "id" ), "order-2" ); Predicate compoundPredicate = builder.and( p1, p2 ).not(); - // a negated AND should become an OR - assertEquals( Predicate.BooleanOperator.OR, compoundPredicate.getOperator() ); orderCriteria.where( compoundPredicate ); List orders = em.createQuery( orderCriteria ).getResultList(); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/Wall.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/Wall.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/Wall.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/Wall.java index f29165f489..321ff92c81 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/basic/Wall.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/basic/Wall.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.basic; +package org.hibernate.orm.test.jpa.criteria.basic; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/components/ComponentInWhereClauseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/components/ComponentInWhereClauseTest.java index 2c83c085ce..59624121a5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/components/ComponentInWhereClauseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/components/ComponentInWhereClauseTest.java @@ -191,7 +191,6 @@ public class ComponentInWhereClauseTest { } @Test - @NotImplementedYet public void testInExpressionForAComponent(EntityManagerFactoryScope scope) { scope.inTransaction( entityManager -> { @@ -208,7 +207,6 @@ public class ComponentInWhereClauseTest { } @Test - @NotImplementedYet public void testInExpressionForTheManyToOnePropertyOfAComponent(EntityManagerFactoryScope scope) { scope.inTransaction( entityManager -> { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/enumcollection/EnumIsMemberTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/enumcollection/EnumIsMemberTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/enumcollection/EnumIsMemberTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/enumcollection/EnumIsMemberTest.java index 1687942a7e..7f170a114d 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/enumcollection/EnumIsMemberTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/enumcollection/EnumIsMemberTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.enumcollection; +package org.hibernate.orm.test.jpa.criteria.enumcollection; import java.util.List; import java.util.Set; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/enumcollection/User.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/enumcollection/User.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/enumcollection/User.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/enumcollection/User.java index 898d8077e8..322c48b36e 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/enumcollection/User.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/enumcollection/User.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.enumcollection; +package org.hibernate.orm.test.jpa.criteria.enumcollection; import javax.persistence.Column; import javax.persistence.ElementCollection; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/CriteriaToScrollableResultsFetchTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/CriteriaToScrollableResultsFetchTest.java old mode 100755 new mode 100644 similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/CriteriaToScrollableResultsFetchTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/CriteriaToScrollableResultsFetchTest.java index 3e0b3836d8..315b295385 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/CriteriaToScrollableResultsFetchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/CriteriaToScrollableResultsFetchTest.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import java.util.ArrayList; import java.util.Arrays; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Customer.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Customer.java old mode 100755 new mode 100644 similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Customer.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Customer.java index 0dc695caa6..a2832fa02b --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Customer.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Customer.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import java.io.Serializable; import javax.persistence.*; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Facility.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Facility.java old mode 100755 new mode 100644 similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Facility.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Facility.java index 4b2dd933fc..96e096e486 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Facility.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Facility.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import java.io.Serializable; import javax.persistence.*; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Order.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Order.java old mode 100755 new mode 100644 similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Order.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Order.java index 889dbcff56..adaadcf6f1 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Order.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Order.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import java.util.*; import javax.persistence.*; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/OrderId.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/OrderId.java old mode 100755 new mode 100644 similarity index 91% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/OrderId.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/OrderId.java index 5b9716e6a5..279941c1c3 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/OrderId.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/OrderId.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import java.io.Serializable; import javax.persistence.*; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/OrderLine.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/OrderLine.java old mode 100755 new mode 100644 similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/OrderLine.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/OrderLine.java index 7defb4847c..23668ad970 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/OrderLine.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/OrderLine.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import javax.persistence.*; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/OrderLineId.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/OrderLineId.java old mode 100755 new mode 100644 similarity index 85% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/OrderLineId.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/OrderLineId.java index 9df05d911b..6e7dadf560 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/OrderLineId.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/OrderLineId.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import javax.persistence.*; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Product.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Product.java old mode 100755 new mode 100644 similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Product.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Product.java index 67db0b2386..2aaa6f4d78 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Product.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Product.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import javax.persistence.*; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/ProductId.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/ProductId.java old mode 100755 new mode 100644 similarity index 90% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/ProductId.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/ProductId.java index 3af7bf3a1b..e1ec025105 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/ProductId.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/ProductId.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import java.io.Serializable; import javax.persistence.*; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/PurchaseOrg.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/PurchaseOrg.java old mode 100755 new mode 100644 similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/PurchaseOrg.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/PurchaseOrg.java index 50eb000460..91c634938e --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/PurchaseOrg.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/PurchaseOrg.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import java.util.List; import java.io.Serializable; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Site.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Site.java old mode 100755 new mode 100644 similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Site.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Site.java index 694b9fd109..a094351e8a --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/fetchscroll/Site.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/fetchscroll/Site.java @@ -1,5 +1,5 @@ -package org.hibernate.jpa.test.criteria.fetchscroll; +package org.hibernate.orm.test.jpa.criteria.fetchscroll; import java.io.Serializable; import javax.persistence.*; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/Helper.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/Helper.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/Helper.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/Helper.java index fd94ed3fcc..95de2aba1a 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/Helper.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/Helper.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.idclass; +package org.hibernate.orm.test.jpa.criteria.idclass; import javax.persistence.Id; import javax.persistence.IdClass; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/HelperId.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/HelperId.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/HelperId.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/HelperId.java index 0cb21cc818..b7ae9b6c98 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/HelperId.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/HelperId.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.idclass; +package org.hibernate.orm.test.jpa.criteria.idclass; import java.io.Serializable; import javax.persistence.Column; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/IdClassPredicateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/IdClassPredicateTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/IdClassPredicateTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/IdClassPredicateTest.java index bef428ca04..91b22f50d0 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/IdClassPredicateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/IdClassPredicateTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.idclass; +package org.hibernate.orm.test.jpa.criteria.idclass; import java.util.ArrayList; import java.util.List; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/Tool.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/Tool.java similarity index 93% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/Tool.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/Tool.java index 762dc2417b..a4882476ee 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/Tool.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/Tool.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.idclass; +package org.hibernate.orm.test.jpa.criteria.idclass; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/Widget.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/Widget.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/Widget.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/Widget.java index dc96695023..86a5c530e1 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/Widget.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/Widget.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.idclass; +package org.hibernate.orm.test.jpa.criteria.idclass; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/WidgetId.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/WidgetId.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/WidgetId.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/WidgetId.java index 193677a818..88397b8e78 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/idclass/WidgetId.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/idclass/WidgetId.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.idclass; +package org.hibernate.orm.test.jpa.criteria.idclass; import java.io.Serializable; import javax.persistence.Column; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/AbstractCriteriaLiteralHandlingModeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/AbstractCriteriaLiteralHandlingModeTest.java similarity index 90% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/AbstractCriteriaLiteralHandlingModeTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/AbstractCriteriaLiteralHandlingModeTest.java index 6274982323..3eb62c1d0f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/AbstractCriteriaLiteralHandlingModeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/AbstractCriteriaLiteralHandlingModeTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.literal; +package org.hibernate.orm.test.jpa.criteria.literal; import java.util.List; import java.util.Map; @@ -16,6 +16,7 @@ import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Root; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.junit.Before; @@ -60,8 +61,7 @@ public abstract class AbstractCriteriaLiteralHandlingModeTest extends BaseEntity @Test public void testLiteralHandlingMode() throws Exception { doInJPA( this::entityManagerFactory, entityManager -> { - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - + final HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) entityManager.getCriteriaBuilder(); final CriteriaQuery query = cb.createQuery( Tuple.class ); final Root entity = query.from( Book.class ); @@ -69,17 +69,17 @@ public abstract class AbstractCriteriaLiteralHandlingModeTest extends BaseEntity cb.and( cb.equal( entity.get( "id" ), - cb.literal( 1 ) + 1 ), cb.equal( entity.get( "name" ), - cb.literal( bookName() ) + bookName() ) ) ); query.multiselect( - cb.literal( "abc" ), + cb.value( "abc" ), entity.get( "name" ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeAutoTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeAutoTest.java similarity index 78% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeAutoTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeAutoTest.java index f9b8133277..e2c546746a 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeAutoTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeAutoTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.literal; +package org.hibernate.orm.test.jpa.criteria.literal; import org.hibernate.dialect.H2Dialect; @@ -21,6 +21,6 @@ import static org.junit.Assert.assertNotNull; public class CriteriaLiteralHandlingModeAutoTest extends AbstractCriteriaLiteralHandlingModeTest { protected String expectedSQL() { - return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=1 and abstractcr0_.name=?"; + return "select ?,b1_0.name from Book b1_0 where b1_0.id=? and b1_0.name=?"; } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeBindTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeBindTest.java similarity index 81% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeBindTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeBindTest.java index b8ff9ae71c..c095c4058f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeBindTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeBindTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.literal; +package org.hibernate.orm.test.jpa.criteria.literal; import java.util.Map; @@ -31,6 +31,6 @@ public class CriteriaLiteralHandlingModeBindTest extends AbstractCriteriaLiteral } protected String expectedSQL() { - return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=? and abstractcr0_.name=?"; + return "select ?,b1_0.name from Book b1_0 where b1_0.id=? and b1_0.name=?"; } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameLowercaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameLowercaseTest.java similarity index 77% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameLowercaseTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameLowercaseTest.java index cdf0742592..fd422c4b4c 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameLowercaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameLowercaseTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.literal; +package org.hibernate.orm.test.jpa.criteria.literal; import java.util.Map; @@ -30,6 +30,6 @@ public class CriteriaLiteralHandlingModeInlineShortNameLowercaseTest extends Abs } protected String expectedSQL() { - return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=1 and abstractcr0_.name='Vlad''s High-Performance Java Persistence'"; + return "select 'abc',b1_0.name from Book b1_0 where b1_0.id=1 and b1_0.name='Vlad''s High-Performance Java Persistence'"; } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameUppercaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameUppercaseTest.java similarity index 77% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameUppercaseTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameUppercaseTest.java index a80f6a901a..1bc824c8c8 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameUppercaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeInlineShortNameUppercaseTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.literal; +package org.hibernate.orm.test.jpa.criteria.literal; import java.util.Map; @@ -30,6 +30,6 @@ public class CriteriaLiteralHandlingModeInlineShortNameUppercaseTest extends Abs } protected String expectedSQL() { - return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=1 and abstractcr0_.name='Vlad''s High-Performance Java Persistence'"; + return "select 'abc',b1_0.name from Book b1_0 where b1_0.id=1 and b1_0.name='Vlad''s High-Performance Java Persistence'"; } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeInlineTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeInlineTest.java similarity index 78% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeInlineTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeInlineTest.java index 2b11abb9e9..22a915b08f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralHandlingModeInlineTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/CriteriaLiteralHandlingModeInlineTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.literal; +package org.hibernate.orm.test.jpa.criteria.literal; import java.util.Map; @@ -31,6 +31,6 @@ public class CriteriaLiteralHandlingModeInlineTest extends AbstractCriteriaLiter } protected String expectedSQL() { - return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=1 and abstractcr0_.name='Vlad''s High-Performance Java Persistence'"; + return "select 'abc',b1_0.name from Book b1_0 where b1_0.id=1 and b1_0.name='Vlad''s High-Performance Java Persistence'"; } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/MySQLCriteriaLiteralHandlingModeInlineTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/MySQLCriteriaLiteralHandlingModeInlineTest.java similarity index 80% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/MySQLCriteriaLiteralHandlingModeInlineTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/MySQLCriteriaLiteralHandlingModeInlineTest.java index ca8480992e..a2d0786baa 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/MySQLCriteriaLiteralHandlingModeInlineTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/literal/MySQLCriteriaLiteralHandlingModeInlineTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.literal; +package org.hibernate.orm.test.jpa.criteria.literal; import java.util.Map; @@ -31,7 +31,7 @@ public class MySQLCriteriaLiteralHandlingModeInlineTest extends AbstractCriteria } protected String expectedSQL() { - return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=1 and abstractcr0_.name='Vlad\\\\''s High-Performance Java Persistence'"; + return "select 'abc',b1_0.name from Book b1_0 where b1_0.id=1 and b1_0.name='Vlad\\\\''s High-Performance Java Persistence'"; } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/Customer.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/Customer.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/Customer.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/Customer.java index 6213ec62bd..fc3b5b5aa2 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/Customer.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/Customer.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.mapjoin; +package org.hibernate.orm.test.jpa.criteria.mapjoin; import java.util.HashMap; import java.util.Map; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/CustomerOrder.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/CustomerOrder.java similarity index 93% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/CustomerOrder.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/CustomerOrder.java index 7b5a6e8e8a..d9fd99f519 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/CustomerOrder.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/CustomerOrder.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.mapjoin; +package org.hibernate.orm.test.jpa.criteria.mapjoin; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/MapJoinEntryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/MapJoinEntryTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/MapJoinEntryTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/MapJoinEntryTest.java index f4cb85cd00..d809d7f507 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/MapJoinEntryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/MapJoinEntryTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.mapjoin; +package org.hibernate.orm.test.jpa.criteria.mapjoin; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/MapJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/MapJoinTest.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/MapJoinTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/MapJoinTest.java index 199ebca627..af019ccad8 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/MapJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/MapJoinTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.mapjoin; +package org.hibernate.orm.test.jpa.criteria.mapjoin; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/MapJoinTestWithEmbeddable.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/MapJoinTestWithEmbeddable.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/MapJoinTestWithEmbeddable.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/MapJoinTestWithEmbeddable.java index 36ab3f51c0..c77f7330e5 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/mapjoin/MapJoinTestWithEmbeddable.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/mapjoin/MapJoinTestWithEmbeddable.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.mapjoin; +package org.hibernate.orm.test.jpa.criteria.mapjoin; import java.io.Serializable; import java.util.HashMap; @@ -65,7 +65,7 @@ public class MapJoinTestWithEmbeddable extends BaseEntityManagerFunctionalTestCa public void testSelectingValueOfMapJoin() { doInJPA( this::entityManagerFactory, entityManager -> { CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery( Node.class ); + CriteriaQuery query = cb.createQuery( BatchNodeMetadata.class ); Root root = query.from( Batch.class ); MapJoin nodes = (MapJoin) root.join( "batchNodeMetadata" ); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/CriteriaLiteralInSelectExpressionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/CriteriaLiteralInSelectExpressionTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/CriteriaLiteralInSelectExpressionTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/CriteriaLiteralInSelectExpressionTest.java index 9e63f67972..786e351c5d 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/CriteriaLiteralInSelectExpressionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/CriteriaLiteralInSelectExpressionTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.nulliteral; +package org.hibernate.orm.test.jpa.criteria.nulliteral; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/CriteriaLiteralsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/CriteriaLiteralsTest.java similarity index 81% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/CriteriaLiteralsTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/CriteriaLiteralsTest.java index 51613b4c5b..1587e46263 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/CriteriaLiteralsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/CriteriaLiteralsTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.nulliteral; +package org.hibernate.orm.test.jpa.criteria.nulliteral; import java.util.ArrayList; import java.util.List; @@ -119,7 +119,7 @@ public class CriteriaLiteralsTest extends BaseEntityManagerFunctionalTestCase { 1, sqlStatementInterceptor.getSqlQueries().size() ); - sqlStatementInterceptor.assertExecuted("select 'abc' as col_0_0_, criteriali0_.name as col_1_0_ from Book criteriali0_ where criteriali0_.name=?"); + sqlStatementInterceptor.assertExecuted("select 'abc',b1_0.name from Book b1_0 where b1_0.name='( SELECT REPEAT(''abc'' || '' '', 10000000000 FROM MY_ENTITY )'"); assertTrue( tuples.isEmpty() ); } ); } @@ -129,7 +129,7 @@ public class CriteriaLiteralsTest extends BaseEntityManagerFunctionalTestCase { doInJPA( this::entityManagerFactory, entityManager -> { testNumericLiterals( entityManager, - "select 'abc' as col_0_0_, criteriali0_.name as col_1_0_ from Book criteriali0_ where criteriali0_.id=1" + "select 'abc',b1_0.name from Book b1_0 where b1_0.id=1" ); } ); } @@ -139,7 +139,7 @@ public class CriteriaLiteralsTest extends BaseEntityManagerFunctionalTestCase { doInJPA( this::entityManagerFactory, entityManager -> { testNumericLiterals( entityManager, - "select 'abc' as col_0_0_, criteriali0_.name as col_1_0_ from Book criteriali0_ where criteriali0_.id=1" + "select 'abc',b1_0.name from Book b1_0 where b1_0.id=1" ); } ); } @@ -188,34 +188,26 @@ public class CriteriaLiteralsTest extends BaseEntityManagerFunctionalTestCase { 1, sqlStatementInterceptor.getSqlQueries().size() ); - sqlStatementInterceptor.assertExecuted( "select authors1_.name as col_0_0_ from Book criteriali0_ inner join Author authors1_ on criteriali0_.id=authors1_.book_id where criteriali0_.name=? and authors1_.index_id=0" ); + sqlStatementInterceptor.assertExecuted( "select a1_0.name from Book b1_0 inner join Author a1_0 on a1_0.book_id=b1_0.id where b1_0.name=? and a1_0.index_id=?" ); } ); } @Test public void testLiteralsInSelectClause() throws Exception { - try { - doInJPA( this::entityManagerFactory, entityManager -> { - final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); - CriteriaQuery query = cb.createQuery( String.class ); - Root root = query.from( Book.class ); - ListJoin authors = root.joinList( "authors" ); + doInJPA( this::entityManagerFactory, entityManager -> { + final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery( String.class ); + Root root = query.from( Book.class ); + ListJoin authors = root.joinList( "authors" ); - query.where( cb.equal( - root.get( "name" ), - "Java Persistence with Hibernate" - )) - .select( cb.literal( "( SELECT REPEAT('abc' || ' ', 10000000000 FROM MY_ENTITY )" ) ); + query.where( cb.equal( + root.get( "name" ), + "Java Persistence with Hibernate" + )) + .select( cb.literal( "( SELECT REPEAT('abc' || ' ', 10000000000 FROM MY_ENTITY )" ) ); - entityManager.createQuery( query ).getResultList(); - } ); - } - catch ( Exception expected ) { - assertEquals( - SemanticException.class, - expected.getCause().getClass() - ); - } + entityManager.createQuery( query ).getResultList(); + } ); } @Entity(name = "Book") diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/NullLiteralExpression.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/NullLiteralExpression.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/NullLiteralExpression.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/NullLiteralExpression.java index bc42de81ca..02e82e96ad 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/NullLiteralExpression.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/NullLiteralExpression.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.nulliteral; +package org.hibernate.orm.test.jpa.criteria.nulliteral; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/Person.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/Person.java similarity index 90% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/Person.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/Person.java index be3a0377df..900e3fc644 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/Person.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/Person.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.nulliteral; +package org.hibernate.orm.test.jpa.criteria.nulliteral; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/Subject.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/Subject.java similarity index 89% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/Subject.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/Subject.java index c9da16c612..9e7ae02937 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/nulliteral/Subject.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/Subject.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.nulliteral; +package org.hibernate.orm.test.jpa.criteria.nulliteral; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/AbstractPathImplTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/AbstractPathImplTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/AbstractPathImplTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/AbstractPathImplTest.java index 79187075ac..665af19dc8 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/AbstractPathImplTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/AbstractPathImplTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.paths; +package org.hibernate.orm.test.jpa.criteria.paths; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/FetchAndJoinTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/FetchAndJoinTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/FetchAndJoinTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/FetchAndJoinTest.java index a71f330e65..44840a6300 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/FetchAndJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/FetchAndJoinTest.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.test.criteria.paths; +package org.hibernate.orm.test.jpa.criteria.paths; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/PluralAttributeExpressionsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/PluralAttributeExpressionsTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/PluralAttributeExpressionsTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/PluralAttributeExpressionsTest.java index 18bd743b97..9444f5612b 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/paths/PluralAttributeExpressionsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/paths/PluralAttributeExpressionsTest.java @@ -4,7 +4,7 @@ * 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.jpa.test.criteria.paths; +package org.hibernate.orm.test.jpa.criteria.paths; import java.util.ArrayList; import java.util.Collections; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/selectcase/GroupBySelectCaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/GroupBySelectCaseTest.java similarity index 83% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/selectcase/GroupBySelectCaseTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/GroupBySelectCaseTest.java index 211ef39111..1156bcce1c 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/selectcase/GroupBySelectCaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/GroupBySelectCaseTest.java @@ -4,11 +4,10 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.selectcase; +package org.hibernate.orm.test.jpa.criteria.selectcase; import java.util.List; import javax.persistence.Entity; -import javax.persistence.EntityManager; import javax.persistence.Id; import javax.persistence.Tuple; import javax.persistence.criteria.CriteriaBuilder; @@ -16,14 +15,9 @@ import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; -import org.hibernate.dialect.DB2Dialect; -import org.hibernate.dialect.DerbyDialect; -import org.hibernate.dialect.PostgreSQL95Dialect; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.orm.test.jpa.metadata.Person_; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.junit.Test; @@ -32,8 +26,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @TestForIssue(jiraKey = "HHH-12230") -@SkipForDialect(value = DB2Dialect.class, comment = "We would need casts in the case clauses. See HHH-12822.") -@SkipForDialect(value = DerbyDialect.class, comment = "Derby requires either casted parameters or literals in the result arms of CASE expressions") public class GroupBySelectCaseTest extends BaseEntityManagerFunctionalTestCase { @Override diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/selectcase/SelectCaseLiteralHandlingBindTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/SelectCaseLiteralHandlingBindTest.java similarity index 88% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/selectcase/SelectCaseLiteralHandlingBindTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/SelectCaseLiteralHandlingBindTest.java index 3d1a926f43..614c062571 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/selectcase/SelectCaseLiteralHandlingBindTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/SelectCaseLiteralHandlingBindTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.selectcase; +package org.hibernate.orm.test.jpa.criteria.selectcase; import java.util.List; import java.util.Map; @@ -17,12 +17,9 @@ import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.hibernate.cfg.AvailableSettings; -import org.hibernate.dialect.DB2Dialect; -import org.hibernate.dialect.DerbyDialect; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.query.criteria.ValueHandlingMode; -import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.junit.Test; @@ -88,10 +85,10 @@ public class SelectCaseLiteralHandlingBindTest extends BaseEntityManagerFunction Predicate junior = cb.between( programmer.get( "commits" ), 0, 10 ); Predicate senior = cb.between( programmer.get( "commits" ), 11, 20 ); - CriteriaBuilder.Case selectCase = cb.selectCase(); - selectCase.when( junior, 1 ) - .when( senior, 2 ) - .otherwise( 3 ); + CriteriaBuilder.Case selectCase = cb.selectCase(); + selectCase.when( junior, 1.1 ) + .when( senior, 2.2 ) + .otherwise( 3.3 ); query.multiselect( programmer.get( "team" ), cb.sum( selectCase ) ) .groupBy( programmer.get( "team" ) ) @@ -104,8 +101,6 @@ public class SelectCaseLiteralHandlingBindTest extends BaseEntityManagerFunction } @Test - @SkipForDialect(value = DB2Dialect.class, comment = "We would need casts in the case clauses. See HHH-12822.") - @SkipForDialect(value = DerbyDialect.class, comment = "Derby requires either casted parameters or literals in the result arms of CASE expressions") public void whereCaseExpression() { doInJPA( this::entityManagerFactory, entityManager -> { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/selectcase/SelectCaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/SelectCaseTest.java similarity index 89% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/selectcase/SelectCaseTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/SelectCaseTest.java index 6537ad7b5e..d368b91f62 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/selectcase/SelectCaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/selectcase/SelectCaseTest.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.jpa.test.criteria.selectcase; +package org.hibernate.orm.test.jpa.criteria.selectcase; import java.util.List; import javax.persistence.EntityManager; @@ -34,19 +34,12 @@ import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; -import org.hibernate.dialect.DB2Dialect; -import org.hibernate.dialect.DerbyDialect; -import org.hibernate.dialect.H2Dialect; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.junit.Test; @TestForIssue( jiraKey = "HHH-9731" ) -@SkipForDialect(value = DB2Dialect.class, comment = "We would need casts in the case clauses. See HHH-12822.") -@SkipForDialect(value = DerbyDialect.class, comment = "Derby requires either casted parameters or literals in the result arms of CASE expressions") public class SelectCaseTest extends BaseEntityManagerFunctionalTestCase { @Override diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/simplecase/BasicSimpleCaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/simplecase/BasicSimpleCaseTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/simplecase/BasicSimpleCaseTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/simplecase/BasicSimpleCaseTest.java index 111fc4aff1..015cc0b812 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/simplecase/BasicSimpleCaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/simplecase/BasicSimpleCaseTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.simplecase; +package org.hibernate.orm.test.jpa.criteria.simplecase; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/AbstractSubqueryInSelectClauseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/AbstractSubqueryInSelectClauseTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/AbstractSubqueryInSelectClauseTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/AbstractSubqueryInSelectClauseTest.java index 79d322b3e0..852a955795 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/AbstractSubqueryInSelectClauseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/AbstractSubqueryInSelectClauseTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.subquery; +package org.hibernate.orm.test.jpa.criteria.subquery; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/CorrelatedSubqueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/CorrelatedSubqueryTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/CorrelatedSubqueryTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/CorrelatedSubqueryTest.java index f26ed0d34a..dd63069c27 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/CorrelatedSubqueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/CorrelatedSubqueryTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.subquery; +package org.hibernate.orm.test.jpa.criteria.subquery; import static org.junit.Assert.assertEquals; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/SubqueryInSelectClauseJpaComplianceTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/SubqueryInSelectClauseJpaComplianceTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/SubqueryInSelectClauseJpaComplianceTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/SubqueryInSelectClauseJpaComplianceTest.java index e07e594ba2..a9e4f2efbc 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/SubqueryInSelectClauseJpaComplianceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/SubqueryInSelectClauseJpaComplianceTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.subquery; +package org.hibernate.orm.test.jpa.criteria.subquery; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/SubqueryInSelectClauseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/SubqueryInSelectClauseTest.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/SubqueryInSelectClauseTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/SubqueryInSelectClauseTest.java index 0077c9e4e2..138dea8928 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/SubqueryInSelectClauseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/SubqueryInSelectClauseTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.subquery; +package org.hibernate.orm.test.jpa.criteria.subquery; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/UncorrelatedSubqueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/UncorrelatedSubqueryTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/UncorrelatedSubqueryTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/UncorrelatedSubqueryTest.java index 2a967625ac..ca9efce02c 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/subquery/UncorrelatedSubqueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/subquery/UncorrelatedSubqueryTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.subquery; +package org.hibernate.orm.test.jpa.criteria.subquery; import javax.persistence.EntityManager; import javax.persistence.criteria.CriteriaBuilder; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/tuple/TupleCriteriaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/tuple/TupleCriteriaTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/tuple/TupleCriteriaTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/tuple/TupleCriteriaTest.java index 0ddfde31bb..94eb01e921 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/tuple/TupleCriteriaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/tuple/TupleCriteriaTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.tuple; +package org.hibernate.orm.test.jpa.criteria.tuple; import java.util.Date; import java.util.List; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/Alias.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/Alias.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/Alias.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/Alias.java index 9bb602033b..0f258dbe9f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/Alias.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/Alias.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.components; +package org.hibernate.orm.test.jpa.test.components; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/Client.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/Client.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/Client.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/Client.java index 5e938e388b..227184da6e 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/Client.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/Client.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.components; +package org.hibernate.orm.test.jpa.test.components; import java.io.Serializable; import javax.persistence.Embedded; import javax.persistence.Entity; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/ComponentCriteriaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/ComponentCriteriaTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/ComponentCriteriaTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/ComponentCriteriaTest.java index 99f8eb268f..bab86a7177 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/ComponentCriteriaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/ComponentCriteriaTest.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.components; +package org.hibernate.orm.test.jpa.test.components; import java.util.ArrayList; import java.util.List; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/Name.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/Name.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/Name.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/Name.java index 301f0ab465..7873df65c4 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/components/Name.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/test/components/Name.java @@ -4,14 +4,13 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.jpa.test.criteria.components; +package org.hibernate.orm.test.jpa.test.components; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Embeddable; -import javax.persistence.JoinColumn; import javax.persistence.OneToMany; /** diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/transaction/SynchronizationTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/transaction/SynchronizationTypeTest.java index 0a41d5fa7b..3c6f16a8f0 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/transaction/SynchronizationTypeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/transaction/SynchronizationTypeTest.java @@ -27,7 +27,6 @@ import org.hibernate.testing.jta.TestingJtaPlatformImpl; import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; import org.hibernate.testing.orm.junit.ExtraAssertions; import org.hibernate.testing.orm.junit.Jpa; -import org.hibernate.testing.orm.junit.NotImplementedYet; import org.hibernate.testing.orm.junit.Setting; import org.junit.jupiter.api.Test; @@ -146,7 +145,6 @@ public class SynchronizationTypeTest { } @Test - @NotImplementedYet(reason = "SqmUpdateStatement#set method has not yet been emplemented") public void testDisallowedOperations(EntityManagerFactoryScope scope) throws Exception { // test calling operations that are disallowed while a UNSYNCHRONIZED persistence context is not // yet joined/enlisted diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/QueryTimeOutTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/QueryTimeOutTest.java index f8921e700b..5114300623 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/QueryTimeOutTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/QueryTimeOutTest.java @@ -42,7 +42,7 @@ public class QueryTimeOutTest extends BaseNonConfigCoreFunctionalTestCase { true, false ); - private static final String QUERY = "update AnEntity set name = 'abc'"; + private static final String QUERY = "update AnEntity set name='abc'"; @Override protected Class[] getAnnotatedClasses() { @@ -73,7 +73,7 @@ public class QueryTimeOutTest extends BaseNonConfigCoreFunctionalTestCase { if ( getDialect() instanceof SybaseDialect ) { verify( CONNECTION_PROVIDER.getPreparedStatement( - "update AnEntity set AnEntity.name = 'abc'" ), + "update AnEntity set AnEntity.name='abc'" ), times( 1 ) ).setQueryTimeout( 123 ); } @@ -104,7 +104,7 @@ public class QueryTimeOutTest extends BaseNonConfigCoreFunctionalTestCase { if ( getDialect() instanceof SybaseDialect ) { verify( CONNECTION_PROVIDER.getPreparedStatement( - "update AnEntity set AnEntity.name = 'abc'" ), + "update AnEntity set AnEntity.name='abc'" ), times( 1 ) ).setQueryTimeout( 123 ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/TupleTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/TupleTest.java new file mode 100644 index 0000000000..5ea00d965a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/TupleTest.java @@ -0,0 +1,75 @@ +/* + * 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 java.util.Calendar; +import java.util.List; + +import org.hibernate.testing.orm.domain.gambit.SimpleEntity; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Christian Beikov + */ +@DomainModel( annotatedClasses = SimpleEntity.class ) +@SessionFactory +public class TupleTest { + + @Test + public void testSelectTuple(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + List results = session.createQuery( + "select o.id, (o.someString, o.someInteger), o.someLong from SimpleEntity o" ) + .list(); + assertThat( results.size(), is( 1 ) ); + Object[] result = (Object[]) results.get( 0 ); + assertThat( result[0], is( 1 ) ); + assertThat( result[1], instanceOf( Object[].class ) ); + Object[] tuple = (Object[]) result[1]; + assertThat( tuple[0], is( "aaa" ) ); + assertThat( tuple[1], is( Integer.MAX_VALUE ) ); + assertThat( result[2], is( Long.MAX_VALUE ) ); + } + ); + } + + @BeforeEach + public void setUp(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + SimpleEntity entity = new SimpleEntity( + 1, + Calendar.getInstance().getTime(), + null, + Integer.MAX_VALUE, + Long.MAX_VALUE, + "aaa" + ); + session.save( entity ); + } + ); + } + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + session.createQuery( "delete SimpleEntity" ).executeUpdate(); + } + ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/ast/SmokeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/ast/SmokeTests.java index 2a871ef36c..60eb95325f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/ast/SmokeTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/ast/SmokeTests.java @@ -118,13 +118,9 @@ public class SmokeTests { sqlAst ).translate( null, QueryOptions.NONE ); - final String separator = session.getSessionFactory() - .getJdbcServices() - .getDialect() - .getTableAliasSeparator(); assertThat( jdbcSelectOperation.getSql(), - is( "select s1_0.name from mapping_simple_entity" + separator + "s1_0" ) + is( "select s1_0.name from mapping_simple_entity s1_0" ) ); } ); @@ -217,13 +213,9 @@ public class SmokeTests { sqlAst ).translate( null, QueryOptions.NONE ); - final String separator = session.getSessionFactory() - .getJdbcServices() - .getDialect() - .getTableAliasSeparator(); assertThat( jdbcSelectOperation.getSql(), - is( "select s1_0.gender from mapping_simple_entity" + separator + "s1_0" ) + is( "select s1_0.gender from mapping_simple_entity s1_0" ) ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/expression/SearchedCaseExpressionTest.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/expression/SearchedCaseExpressionTest.java index 0590ecdea8..f3bb936ad8 100644 --- a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/expression/SearchedCaseExpressionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/expression/SearchedCaseExpressionTest.java @@ -18,13 +18,7 @@ import javax.persistence.criteria.Expression; import javax.persistence.criteria.Path; import javax.persistence.criteria.Root; -import org.hibernate.dialect.DB2Dialect; -import org.hibernate.dialect.DerbyDialect; -import org.hibernate.dialect.H2Dialect; -import org.hibernate.dialect.PostgreSQL81Dialect; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Assert; @@ -40,7 +34,6 @@ import static org.junit.Assert.assertEquals; public class SearchedCaseExpressionTest extends BaseCoreFunctionalTestCase { @Test - @RequiresDialect(H2Dialect.class) public void testCaseClause() { doInHibernate( this::sessionFactory, session -> { CriteriaBuilder cb = session.getCriteriaBuilder(); @@ -65,8 +58,6 @@ public class SearchedCaseExpressionTest extends BaseCoreFunctionalTestCase { } @Test - @SkipForDialect(value = DB2Dialect.class, comment = "We would need casts in the case clauses. See HHH-12822.") - @SkipForDialect(value = DerbyDialect.class, comment = "Derby requires either casted parameters or literals in the result arms of CASE expressions") public void testEqualClause() { doInHibernate( this::sessionFactory, session -> { CriteriaBuilder cb = session.getCriteriaBuilder(); @@ -91,8 +82,6 @@ public class SearchedCaseExpressionTest extends BaseCoreFunctionalTestCase { @Test @TestForIssue(jiraKey = "HHH-13167") - @SkipForDialect(value = DB2Dialect.class, comment = "We would need casts in the case clauses. See HHH-12822.") - @SkipForDialect(value = DerbyDialect.class, comment = "Derby requires either casted parameters or literals in the result arms of CASE expressions") public void testMissingElseClause() { doInHibernate( this::sessionFactory, session -> { Event event = new Event();