From 5f4b0978d94881d3256adfd4626015dc5c64c1eb Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 25 May 2021 15:29:55 +0200 Subject: [PATCH] Update H2 to 1.4.200. Replace LockMode in Fetch and DomainResult with the source alias to resolve lock mode during initializer creation. Introduce notion of aggregate function with an optional filter clause. Implement support for rendering locks into SQL. Move locking tests to orm package --- gradle/libraries.gradle | 2 +- .../main/java/org/hibernate/LockOptions.java | 30 +- .../internal/AbstractBagSemantics.java | 7 - .../internal/AbstractMapSemantics.java | 7 - .../internal/AbstractSetSemantics.java | 5 - .../internal/StandardArraySemantics.java | 7 - .../internal/StandardListSemantics.java | 7 - .../collection/spi/CollectionSemantics.java | 2 - .../dialect/AbstractHANADialect.java | 5 + .../dialect/AbstractTransactSQLDialect.java | 5 + .../dialect/CacheSqlAstTranslator.java | 13 + .../hibernate/dialect/CockroachDialect.java | 155 +++- .../dialect/CockroachSqlAstTranslator.java | 26 + .../org/hibernate/dialect/DB2Dialect.java | 47 +- .../dialect/DB2SqlAstTranslator.java | 21 +- .../org/hibernate/dialect/DB2iDialect.java | 11 +- .../org/hibernate/dialect/DB2zDialect.java | 16 +- .../org/hibernate/dialect/DerbyDialect.java | 15 +- .../dialect/DerbySqlAstTranslator.java | 15 + .../java/org/hibernate/dialect/Dialect.java | 45 ++ .../dialect/FirebirdSqlAstTranslator.java | 7 +- .../java/org/hibernate/dialect/H2Dialect.java | 14 +- .../dialect/HSQLSqlAstTranslator.java | 28 +- .../dialect/IngresSqlAstTranslator.java | 13 + .../dialect/MariaDBSqlAstTranslator.java | 5 + .../org/hibernate/dialect/MySQLDialect.java | 6 + .../dialect/MySQLSqlAstTranslator.java | 5 + .../org/hibernate/dialect/OracleDialect.java | 7 +- .../dialect/OracleSqlAstTranslator.java | 139 +++- .../hibernate/dialect/PostgreSQLDialect.java | 10 + .../dialect/PostgreSQLSqlAstTranslator.java | 21 + .../hibernate/dialect/RDMSOS2200Dialect.java | 2 +- ...r.java => RDMSOS2200SqlAstTranslator.java} | 19 +- .../hibernate/dialect/RowLockStrategy.java | 27 + .../hibernate/dialect/SQLServerDialect.java | 5 + .../dialect/SQLServerSqlAstTranslator.java | 92 +++ .../org/hibernate/dialect/SpannerDialect.java | 12 +- .../dialect/SpannerSqlAstTranslator.java | 14 + .../hibernate/dialect/SybaseASEDialect.java | 11 +- .../dialect/SybaseASESqlAstTranslator.java | 22 + .../dialect/SybaseAnywhereDialect.java | 40 +- .../SybaseAnywhereSqlAstTranslator.java | 22 + .../org/hibernate/dialect/SybaseDialect.java | 2 +- .../dialect/SybaseSqlAstTranslator.java | 17 + .../hibernate/dialect/TeradataDialect.java | 11 +- .../dialect/TeradataSqlAstTranslator.java | 40 + .../hibernate/dialect/TimesTenDialect.java | 49 ++ .../dialect/TimesTenSqlAstTranslator.java | 20 + .../function/CommonFunctionFactory.java | 68 +- .../AbstractSharedSessionContract.java | 3 + .../ast/internal/AbstractNaturalIdLoader.java | 9 +- .../internal/DatabaseSnapshotExecutor.java | 2 - .../ast/internal/LoaderSelectBuilder.java | 4 - .../internal/LoaderSqlAstCreationState.java | 4 +- .../ast/internal/SimpleNaturalIdLoader.java | 3 +- .../SingleIdEntityLoaderStandardImpl.java | 11 +- .../loader/ast/internal/SingleIdLoadPlan.java | 21 +- .../SingleUniqueKeyEntityLoaderStandard.java | 6 +- .../hibernate/loader/ast/spi/Loadable.java | 2 - .../AbstractCompositeIdentifierMapping.java | 3 - .../metamodel/mapping/EntityMappingType.java | 3 - .../AbstractEntityDiscriminatorMapping.java | 3 - .../internal/AnyDiscriminatorPart.java | 2 - .../mapping/internal/AnyKeyPart.java | 2 - .../internal/BasicAttributeMapping.java | 2 - .../BasicEntityIdentifierMappingImpl.java | 2 - .../internal/BasicValuedCollectionPart.java | 2 - .../CollectionIdentifierDescriptorImpl.java | 2 - ...criminatedAssociationAttributeMapping.java | 3 - .../DiscriminatedAssociationMapping.java | 1 - .../internal/DiscriminatedCollectionPart.java | 3 - .../internal/EmbeddedAttributeMapping.java | 3 - .../internal/EmbeddedCollectionPart.java | 3 - .../EmbeddedForeignKeyDescriptor.java | 2 - .../internal/EntityCollectionPart.java | 6 +- .../internal/EntityVersionMappingImpl.java | 2 - .../internal/PluralAttributeMappingImpl.java | 25 +- .../internal/SimpleForeignKeyDescriptor.java | 2 - .../internal/ToOneAttributeMapping.java | 23 +- .../entity/AbstractEntityPersister.java | 5 +- .../entity/SingleTableEntityPersister.java | 6 +- .../entity/UnionSubclassEntityPersister.java | 5 +- .../QueryInterpretationCacheStandardImpl.java | 2 +- .../query/internal/SimpleQueryOptions.java | 34 + .../org/hibernate/query/results/Builders.java | 3 - .../DomainResultCreationStateImpl.java | 12 +- .../ImplicitAttributeFetchBuilder.java | 2 - .../query/results/JdbcValuesMappingImpl.java | 49 +- .../query/results/ResultSetMappingImpl.java | 5 +- .../query/results/TableGroupImpl.java | 12 +- .../CompleteFetchBuilderBasicPart.java | 2 - .../CompleteResultBuilderEntityJpa.java | 1 - .../CompleteResultBuilderEntityStandard.java | 1 - .../dynamic/DynamicFetchBuilderLegacy.java | 1 - .../dynamic/DynamicFetchBuilderStandard.java | 3 - .../DynamicResultBuilderEntityCalculated.java | 5 +- .../DynamicResultBuilderEntityStandard.java | 7 +- .../ImplicitFetchBuilderEmbeddable.java | 3 - .../implicit/ImplicitFetchBuilderEntity.java | 5 - .../implicit/ImplicitFetchBuilderPlural.java | 2 - ...licitModelPartResultBuilderEmbeddable.java | 2 - .../ImplicitModelPartResultBuilderEntity.java | 2 - .../hibernate/query/spi/AbstractQuery.java | 15 +- .../query/spi/QueryInterpretationCache.java | 6 + .../query/spi/SqlOmittingQueryOptions.java | 2 +- .../query/sql/internal/NativeQueryImpl.java | 26 +- .../query/sqm/SemanticQueryWalker.java | 1 - .../AbstractSqmFunctionDescriptor.java | 23 + ...actSqmSelfRenderingFunctionDescriptor.java | 43 ++ .../function/FunctionRenderingSupport.java | 10 + .../function/NamedSqmFunctionDescriptor.java | 40 +- .../PatternBasedSqmFunctionDescriptor.java | 12 +- ...ringAggregateFunctionSqlAstExpression.java | 54 ++ ...SelfRenderingFunctionSqlAstExpression.java | 4 + .../SelfRenderingSqmAggregateFunction.java | 54 ++ .../sqm/function/SqmFunctionDescriptor.java | 14 + .../sqm/function/SqmFunctionRegistry.java | 41 +- .../internal/ConcreteSqmSelectQueryPlan.java | 6 +- .../query/sqm/internal/QuerySqmImpl.java | 26 +- .../sqm/internal/SqmInterpretationsKey.java | 56 +- .../internal/MatchingIdSelectionHelper.java | 26 +- .../MultiTableSqmMutationConverter.java | 26 +- .../cte/AbstractCteMutationHandler.java | 22 +- .../idtable/ExecuteWithIdTableHelper.java | 21 +- .../idtable/ExecuteWithoutIdTableHelper.java | 2 +- .../DisjunctionRestrictionProducer.java | 128 --- .../internal/inline/InlineStrategy.java | 2 +- ...leValueConstructorRestrictionProducer.java | 57 -- .../NamedFunctionDescriptorBuilder.java | 9 +- .../PatternFunctionDescriptorBuilder.java | 5 +- .../function/internal/PatternRenderer.java | 44 +- .../sqm/spi/BaseSemanticQueryWalker.java | 1 - .../sqm/sql/BaseSqmToSqlAstConverter.java | 39 +- .../EntityValuedPathInterpretation.java | 2 - .../query/sqm/tree/cte/SqmCteStatement.java | 10 + .../query/sqm/tree/expression/Conversion.java | 2 +- .../sqm/tree/expression/SqmFunction.java | 23 +- .../org/hibernate/sql/ForUpdateFragment.java | 61 +- .../java/org/hibernate/sql/ast/Clause.java | 1 + .../hibernate/sql/ast/SqlAstTranslator.java | 5 + .../sql/ast/spi/AbstractSqlAstTranslator.java | 726 +++++++++++++++--- .../sql/ast/spi/AggregateFunctionChecker.java | 363 +++++++++ .../sql/ast/spi/SqlAstCreationState.java | 2 +- .../sql/ast/tree/cte/CteMaterialization.java | 28 + .../sql/ast/tree/cte/CteStatement.java | 12 + .../hibernate/sql/ast/tree/cte/CteTable.java | 2 +- .../sql/ast/tree/cte/CteTableGroup.java | 4 +- .../AggregateFunctionExpression.java | 19 + .../sql/ast/tree/expression/Distinct.java | 2 +- .../sql/ast/tree/expression/Duration.java | 2 +- .../sql/ast/tree/expression/DurationUnit.java | 4 +- .../sql/ast/tree/from/AbstractTableGroup.java | 14 +- .../ast/tree/from/CompositeTableGroup.java | 4 +- .../ast/tree/from/CorrelatedTableGroup.java | 2 +- .../sql/ast/tree/from/FromClause.java | 71 ++ .../sql/ast/tree/from/LazyTableGroup.java | 10 +- .../MutatingTableReferenceGroupWrapper.java | 4 +- .../ast/tree/from/RootTableGroupProducer.java | 1 - .../sql/ast/tree/from/StandardTableGroup.java | 12 +- .../sql/ast/tree/from/TableGroup.java | 2 +- .../sql/ast/tree/from/TableGroupJoin.java | 9 +- .../ast/tree/from/TableGroupJoinProducer.java | 3 - .../sql/ast/tree/from/TableJoin.java | 22 + .../sql/ast/tree/from/TableReferenceJoin.java | 11 +- .../sql/ast/tree/from/UnionTableGroup.java | 9 +- .../sql/ast/tree/select/QueryPart.java | 2 +- .../sql/exec/internal/CallbackImpl.java | 40 + .../JdbcSelectExecutorStandardImpl.java | 34 +- .../sql/exec/spi/AbstractJdbcOperation.java | 100 +++ .../org/hibernate/sql/exec/spi/Callback.java | 4 + .../sql/exec/spi/ExecutionContext.java | 5 + .../hibernate/sql/exec/spi/JdbcDelete.java | 19 +- .../hibernate/sql/exec/spi/JdbcInsert.java | 19 +- .../sql/exec/spi/JdbcLockStrategy.java | 28 + .../hibernate/sql/exec/spi/JdbcOperation.java | 10 +- .../hibernate/sql/exec/spi/JdbcSelect.java | 81 +- .../hibernate/sql/exec/spi/JdbcUpdate.java | 19 +- .../sql/exec/spi/NativeJdbcMutation.java | 10 + .../results/graph/AssemblerCreationState.java | 3 + .../sql/results/graph/FetchParent.java | 2 - .../sql/results/graph/Fetchable.java | 1 - .../internal/CollectionDomainResult.java | 1 - .../internal/EagerCollectionFetch.java | 5 - .../EntityCollectionPartTableGroup.java | 4 +- .../internal/EmbeddableFetchImpl.java | 2 - .../EmbeddableForeignKeyResultImpl.java | 3 - .../internal/EmbeddableResultImpl.java | 2 - .../entity/AbstractEntityInitializer.java | 53 +- .../entity/AbstractEntityResultGraphNode.java | 10 +- .../graph/entity/EntityValuedFetchable.java | 2 - .../internal/EntityFetchJoinedImpl.java | 13 +- .../entity/internal/EntityResultImpl.java | 8 +- .../EntityResultJoinedSubclassImpl.java | 2 +- .../sql/results/internal/ResultsHelper.java | 17 +- .../RowProcessingStateStandardImpl.java | 2 +- .../results/internal/StandardRowReader.java | 5 +- .../CircularBiDirectionalFetchImpl.java | 1 - .../internal/domain/CircularFetchImpl.java | 2 - .../internal/DeferredResultSetAccess.java | 135 +++- ...luesSourceProcessingStateStandardImpl.java | 6 + ...oaderInitializationWithNoLockModeTest.java | 2 +- .../functional/OracleFollowOnLockingTest.java | 52 +- .../unit/lockhint/AbstractLockHintTest.java | 2 +- .../unit/lockhint/MySQLStorageEngineTest.java | 2 +- .../lockhint/SQLServer2005LockHintsTest.java | 2 +- .../unit/lockhint/SQLServerLockHintsTest.java | 2 +- .../lockhint/SybaseASE15LockHintsTest.java | 2 +- .../unit/lockhint/SybaseLockHintsTest.java | 2 +- .../unit/locktimeout/DB2LockTimeoutTest.java | 4 +- .../unit/locktimeout/HANALockTimeoutTest.java | 2 +- .../locktimeout/OracleLockTimeoutTest.java | 2 +- .../PostgreSQLLockTimeoutTest.java | 2 +- ...tractSequenceInformationExtractorTest.java | 2 +- ...B2390SequenceInformationExtractorTest.java | 2 +- ...B2400SequenceInformationExtractorTest.java | 2 +- ...alectSequenceInformationExtractorTest.java | 6 +- ...alectSequenceInformationExtractorTest.java | 6 +- ...alectSequenceInformationExtractorTest.java | 6 +- .../test}/engine/spi/EntityEntryTest.java | 9 +- .../test/jpa}/EntityManagerClosedTest.java | 4 +- .../{ => orm}/test/jpa/lock/JPALockTest.java | 2 +- .../{jpa/test => orm/test/jpa}/lock/Lock.java | 2 +- .../test/jpa/lock/LockExceptionTests.java | 2 +- .../test => orm/test/jpa}/lock/LockTest.java | 19 +- .../jpa}/lock/LockTimeoutPropertyTest.java | 2 +- .../test => orm/test/jpa}/lock/Lockable.java | 2 +- .../jpa}/lock/NativeSQLQueryTimeoutTest.java | 2 +- .../test => orm/test/jpa}/lock/Person.java | 2 +- .../test/jpa}/lock/QueryLockingTest.java | 2 +- .../test/jpa/lock/RepeatableReadTest.java | 2 +- ...tementIsClosedAfterALockExceptionTest.java | 2 +- .../test/jpa}/lock/UnversionedLock.java | 2 +- .../orm/test/jpa/lock/UpgradeLockTest.java | 2 - .../jpa/schemagen/JpaSchemaGeneratorTest.java | 2 +- .../{ => orm}/test/lob/BlobLocatorTest.java | 7 +- .../{ => orm}/test/lob/ClobLocatorTest.java | 7 +- .../{ => orm}/test/lob/LobHolder.java | 2 +- .../{ => orm}/test/lob/LobMappings.hbm.xml | 2 +- .../{ => orm}/test/lob/LobMergeTest.java | 7 +- .../hibernate/{ => orm}/test/locking/A.java | 2 +- .../test/locking/AbstractSkipLockedTest.java | 26 +- .../locking/HANAOptimisticLockingTest.java | 2 +- ...heritanceOptimisticForceIncrementTest.java | 2 +- .../{ => orm}/test/locking/LockModeTest.java | 17 +- .../test/locking/LockRefreshTest.java | 2 +- .../PessimisticReadSkipLockedTest.java | 2 +- .../PessimisticWriteLockTimeoutTest.java | 15 +- .../PessimisticWriteSkipLockedTest.java | 2 +- .../test/locking/UpgradeSkipLockedTest.java | 2 +- .../{ => orm}/test/locking/paging/Door.java | 2 +- .../locking/paging/PagingAndLockingTest.java | 6 +- .../genericApi/BasicGetLoadAccessTest.java | 2 +- .../genericApi/ProxiedGetLoadAccessTest.java | 2 +- .../QueryParametersValidationArrayTest.java | 2 +- .../orm/test/query/sqm/BaseSqmUnitTest.java | 6 + .../mutation/multitable/IdSelectionTests.java | 3 +- .../org/hibernate/testing/DialectChecks.java | 12 + .../junit4/BaseCoreFunctionalTestCase.java | 3 +- .../orm/junit/DialectFeatureChecks.java | 6 + 259 files changed, 3581 insertions(+), 1122 deletions(-) rename hibernate-core/src/main/java/org/hibernate/dialect/{RDBMSOS2200SqlAstTranslator.java => RDMSOS2200SqlAstTranslator.java} (86%) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/RowLockStrategy.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/internal/SimpleQueryOptions.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingAggregateFunctionSqlAstExpression.java create mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/DisjunctionRestrictionProducer.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/TableValueConstructorRestrictionProducer.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AggregateFunctionChecker.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteMaterialization.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/AggregateFunctionExpression.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableJoin.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/exec/internal/CallbackImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/exec/spi/AbstractJdbcOperation.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcLockStrategy.java rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/batchfetch/BatchingEntityLoaderInitializationWithNoLockModeTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/functional/OracleFollowOnLockingTest.java (91%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/lockhint/AbstractLockHintTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/lockhint/MySQLStorageEngineTest.java (96%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/lockhint/SQLServer2005LockHintsTest.java (94%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/lockhint/SQLServerLockHintsTest.java (92%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/lockhint/SybaseASE15LockHintsTest.java (92%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/lockhint/SybaseLockHintsTest.java (91%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/locktimeout/DB2LockTimeoutTest.java (92%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/locktimeout/HANALockTimeoutTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/locktimeout/OracleLockTimeoutTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/locktimeout/PostgreSQLLockTimeoutTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/sequence/AbstractSequenceInformationExtractorTest.java (96%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java (94%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java (94%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java (87%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java (89%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java (89%) rename hibernate-core/src/test/java/org/hibernate/{ => orm/test}/engine/spi/EntityEntryTest.java (92%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/EntityManagerClosedTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/jpa/lock/JPALockTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/lock/Lock.java (96%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/jpa/lock/LockExceptionTests.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/lock/LockTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/lock/LockTimeoutPropertyTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/lock/Lockable.java (95%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/lock/NativeSQLQueryTimeoutTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/lock/Person.java (95%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/lock/QueryLockingTest.java (99%) mode change 100755 => 100644 rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/jpa/lock/RepeatableReadTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/lock/StatementIsClosedAfterALockExceptionTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{jpa/test => orm/test/jpa}/lock/UnversionedLock.java (95%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/lob/BlobLocatorTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/lob/ClobLocatorTest.java (97%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/lob/LobHolder.java (97%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/lob/LobMappings.hbm.xml (92%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/lob/LobMergeTest.java (96%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/A.java (96%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/AbstractSkipLockedTest.java (88%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/HANAOptimisticLockingTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/JoinedInheritanceOptimisticForceIncrementTest.java (98%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/LockModeTest.java (94%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/LockRefreshTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/PessimisticReadSkipLockedTest.java (85%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/PessimisticWriteLockTimeoutTest.java (85%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/PessimisticWriteSkipLockedTest.java (85%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/UpgradeSkipLockedTest.java (91%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/paging/Door.java (94%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/locking/paging/PagingAndLockingTest.java (94%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/ops/genericApi/BasicGetLoadAccessTest.java (99%) rename hibernate-core/src/test/java/org/hibernate/{ => orm}/test/ops/genericApi/ProxiedGetLoadAccessTest.java (98%) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 6506f316044a..a1ee800174b3 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -13,7 +13,7 @@ ext { junitVintageVersion = '5.7.1' junit5Version = '5.7.1' - h2Version = '1.4.199' + h2Version = '1.4.200' bytemanVersion = '4.0.13' //Compatible with JDK16 jnpVersion = '5.0.6.CR1' diff --git a/hibernate-core/src/main/java/org/hibernate/LockOptions.java b/hibernate-core/src/main/java/org/hibernate/LockOptions.java index b77774d368b0..0448f0e3e220 100644 --- a/hibernate-core/src/main/java/org/hibernate/LockOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/LockOptions.java @@ -124,7 +124,12 @@ public LockOptions setAliasSpecificLockMode(String alias, LockMode lockMode) { if ( aliasSpecificLockModes == null ) { aliasSpecificLockModes = new LinkedHashMap<>(); } - aliasSpecificLockModes.put( alias, lockMode ); + if ( lockMode == null ) { + aliasSpecificLockModes.remove( alias ); + } + else { + aliasSpecificLockModes.put( alias, lockMode ); + } return this; } @@ -338,13 +343,16 @@ public static LockOptions copy(LockOptions source, LockOptions destination) { return destination; } - public boolean isCompatible(LockOptions that) { - if ( that == null ) { - return isEmpty(); - } - else if ( this == that ) { + @Override + public boolean equals(Object o) { + if ( this == o ) { return true; } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + + LockOptions that = (LockOptions) o; if ( timeout != that.timeout ) { return false; @@ -363,4 +371,14 @@ else if ( this == that ) { return followOnLocking != null ? followOnLocking.equals( that.followOnLocking ) : that.followOnLocking == null; } + @Override + public int hashCode() { + int result = lockMode != null ? lockMode.hashCode() : 0; + result = 31 * result + timeout; + result = 31 * result + ( aliasSpecificLockModes != null ? aliasSpecificLockModes.hashCode() : 0 ); + result = 31 * result + ( followOnLocking != null ? followOnLocking.hashCode() : 0 ); + result = 31 * result + ( scope ? 1 : 0 ); + return result; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractBagSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractBagSemantics.java index 8082d76e0e3f..e0313a74bd08 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractBagSemantics.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractBagSemantics.java @@ -11,7 +11,6 @@ import java.util.Iterator; import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.collection.spi.BagSemantics; import org.hibernate.collection.spi.CollectionInitializerProducer; import org.hibernate.engine.FetchTiming; @@ -68,7 +67,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, DomainResultCreationState creationState) { return new BagInitializerProducer( attributeMapping, @@ -77,7 +75,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ID.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ), @@ -86,7 +83,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ) @@ -100,7 +96,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, Fetch indexFetch, Fetch elementFetch, DomainResultCreationState creationState){ @@ -110,7 +105,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ID.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ); @@ -121,7 +115,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractMapSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractMapSemantics.java index bb4a67b79619..ef50e24f56c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractMapSemantics.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractMapSemantics.java @@ -12,7 +12,6 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.collection.spi.CollectionInitializerProducer; import org.hibernate.collection.spi.MapSemantics; import org.hibernate.engine.FetchTiming; @@ -80,7 +79,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, DomainResultCreationState creationState) { return new MapInitializerProducer( attributeMapping, @@ -89,7 +87,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.INDEX.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ), @@ -98,7 +95,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ) @@ -112,7 +108,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, Fetch indexFetch, Fetch elementFetch, DomainResultCreationState creationState){ @@ -122,7 +117,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.INDEX.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ); @@ -133,7 +127,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractSetSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractSetSemantics.java index 2d9a4e348621..b4f565dac961 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractSetSemantics.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractSetSemantics.java @@ -10,7 +10,6 @@ import java.util.Set; import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.collection.spi.CollectionInitializerProducer; import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.engine.FetchTiming; @@ -53,7 +52,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, DomainResultCreationState creationState) { return new SetInitializerProducer( attributeMapping, @@ -62,7 +60,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ) @@ -76,7 +73,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, Fetch indexFetch, Fetch elementFetch, DomainResultCreationState creationState){ @@ -87,7 +83,6 @@ public CollectionInitializerProducer createInitializerProducer( fetchParent, selected, resultVariable, - lockMode, creationState ); } diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardArraySemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardArraySemantics.java index a607c556a989..e280d471cb2a 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardArraySemantics.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardArraySemantics.java @@ -10,7 +10,6 @@ import java.util.Iterator; import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.collection.spi.CollectionInitializerProducer; import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.collection.spi.PersistentCollection; @@ -101,7 +100,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, DomainResultCreationState creationState) { return new ArrayInitializerProducer( attributeMapping, @@ -110,7 +108,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.INDEX.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ), @@ -119,7 +116,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ) @@ -133,7 +129,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, Fetch indexFetch, Fetch elementFetch, DomainResultCreationState creationState){ @@ -143,7 +138,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.INDEX.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ); @@ -154,7 +148,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardListSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardListSemantics.java index ba6ee267dcf1..9804c6829343 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardListSemantics.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/StandardListSemantics.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.collection.spi.CollectionInitializerProducer; import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.collection.spi.PersistentCollection; @@ -75,7 +74,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, DomainResultCreationState creationState) { return new ListInitializerProducer( attributeMapping, @@ -84,7 +82,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.INDEX.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ), @@ -93,7 +90,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ) @@ -107,7 +103,6 @@ public CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, Fetch indexFetch, Fetch elementFetch, DomainResultCreationState creationState) { @@ -117,7 +112,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.INDEX.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ); @@ -128,7 +122,6 @@ public CollectionInitializerProducer createInitializerProducer( navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ), FetchTiming.IMMEDIATE, selected, - lockMode, null, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemantics.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemantics.java index 95512479b122..55a6bef25af0 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemantics.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/CollectionSemantics.java @@ -65,7 +65,6 @@ CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, DomainResultCreationState creationState); CollectionInitializerProducer createInitializerProducer( @@ -74,7 +73,6 @@ CollectionInitializerProducer createInitializerProducer( FetchParent fetchParent, boolean selected, String resultVariable, - LockMode lockMode, Fetch indexFetch, Fetch elementFetch, DomainResultCreationState creationState); 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 0e350a6388d5..2b77bb459b5a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java @@ -923,6 +923,11 @@ public boolean forUpdateOfColumns() { return true; } + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return RowLockStrategy.COLUMN; + } + @Override public String getAddColumnString() { return "add ("; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java index 6cae7c7fde88..e0240b4b53b6 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java @@ -158,6 +158,11 @@ public String getForUpdateString() { return ""; } + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return RowLockStrategy.TABLE; + } + @Override public String appendLockHint(LockOptions lockOptions, String tableName) { return lockOptions.getLockMode().greaterThan( LockMode.READ ) ? tableName + " holdlock" : tableName; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CacheSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/CacheSqlAstTranslator.java index 5c05f26ed650..b61360f9dcb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CacheSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CacheSqlAstTranslator.java @@ -34,6 +34,19 @@ public CacheSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement super( sessionFactory, statement ); } + @Override + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + return LockStrategy.NONE; + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + // Cache does not support the FOR UPDATE clause + } + @Override protected boolean needsRowsToSkip() { return true; 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 a0fb506047af..adaae56a7234 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java @@ -6,6 +6,8 @@ */ package org.hibernate.dialect; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.OffsetFetchLimitHandler; @@ -24,6 +26,8 @@ import org.hibernate.type.StandardBasicTypes; import java.sql.Types; +import java.util.Iterator; +import java.util.Map; import javax.persistence.TemporalType; @@ -43,10 +47,10 @@ public class CockroachDialect extends Dialect { // * no support for java.sql.Clob - private int version; + private final int version; public CockroachDialect() { - this(192); + this( 1920 ); } public CockroachDialect(DialectResolutionInfo info) { @@ -354,4 +358,151 @@ public LimitHandler getLimitHandler() { return OffsetFetchLimitHandler.INSTANCE; } + @Override + public String getForUpdateString(String aliases) { + return getForUpdateString() + " of " + aliases; + } + + @Override + public String getForUpdateString(LockOptions lockOptions) { + // Support was added in 20.1: https://www.cockroachlabs.com/docs/v20.1/select-for-update.html + if ( getVersion() < 2010 ) { + return ""; + } + return super.getForUpdateString( lockOptions ); + } + + @Override + public String getForUpdateString(String aliases, LockOptions lockOptions) { + // Support was added in 20.1: https://www.cockroachlabs.com/docs/v20.1/select-for-update.html + if ( getVersion() < 2010 ) { + return ""; + } + /* + * Parent's implementation for (aliases, lockOptions) ignores aliases. + */ + if ( aliases.isEmpty() ) { + LockMode lockMode = lockOptions.getLockMode(); + final Iterator> itr = lockOptions.getAliasLockIterator(); + while ( itr.hasNext() ) { + // seek the highest lock mode + final Map.Entry entry = itr.next(); + final LockMode lm = entry.getValue(); + if ( lm.greaterThan( lockMode ) ) { + aliases = entry.getKey(); + } + } + } + LockMode lockMode = lockOptions.getAliasSpecificLockMode( aliases ); + if (lockMode == null ) { + lockMode = lockOptions.getLockMode(); + } + switch ( lockMode ) { + //noinspection deprecation + case UPGRADE: + return getForUpdateString(aliases); + case PESSIMISTIC_READ: + return getReadLockString( aliases, lockOptions.getTimeOut() ); + case PESSIMISTIC_WRITE: + return getWriteLockString( aliases, lockOptions.getTimeOut() ); + case UPGRADE_NOWAIT: + //noinspection deprecation + case FORCE: + case PESSIMISTIC_FORCE_INCREMENT: + return getForUpdateNowaitString(aliases); + case UPGRADE_SKIPLOCKED: + return getForUpdateSkipLockedString(aliases); + default: + return ""; + } + } + + private String withTimeout(String lockString, int timeout) { + switch (timeout) { + case LockOptions.NO_WAIT: + return supportsNoWait() ? lockString + " nowait" : lockString; + case LockOptions.SKIP_LOCKED: + return supportsSkipLocked() ? lockString + " skip locked" : lockString; + default: + return lockString; + } + } + + @Override + public String getWriteLockString(int timeout) { + return withTimeout( getForUpdateString(), timeout ); + } + + @Override + public String getWriteLockString(String aliases, int timeout) { + return withTimeout( getForUpdateString( aliases ), timeout ); + } + + @Override + public String getReadLockString(int timeout) { + return withTimeout(" for share", timeout ); + } + + @Override + public String getReadLockString(String aliases, int timeout) { + return withTimeout(" for share of " + aliases, timeout ); + } + + @Override + public String getForUpdateNowaitString() { + return supportsNoWait() + ? " for update nowait" + : getForUpdateString(); + } + + @Override + public String getForUpdateNowaitString(String aliases) { + return supportsNoWait() + ? " for update of " + aliases + " nowait" + : getForUpdateString(aliases); + } + + @Override + public String getForUpdateSkipLockedString() { + return supportsSkipLocked() + ? " for update skip locked" + : getForUpdateString(); + } + + @Override + public String getForUpdateSkipLockedString(String aliases) { + return supportsSkipLocked() + ? " for update of " + aliases + " skip locked" + : getForUpdateString( aliases ); + } + + @Override + public boolean supportsOuterJoinForUpdate() { + return false; + } + + @Override + public boolean supportsNoWait() { + return getVersion() >= 2010; + } + + @Override + public boolean supportsWait() { + return false; + } + + @Override + public boolean supportsSkipLocked() { + return getVersion() >= 2010; + } + + @Override + public boolean forUpdateOfColumns() { + return getVersion() >= 2010; + } + + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return getVersion() >= 2010 ? RowLockStrategy.TABLE : RowLockStrategy.NONE; + } } 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 f52b68d0c72c..56298fd57c2f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachSqlAstTranslator.java @@ -29,6 +29,32 @@ public CockroachSqlAstTranslator(SessionFactoryImplementor sessionFactory, State super( sessionFactory, statement ); } + @Override + protected String getForShare() { + return " for share"; + } + + @Override + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + // Support was added in 20.1: https://www.cockroachlabs.com/docs/v20.1/select-for-update.html + if ( getDialect().getVersion() < 2010 ) { + return LockStrategy.NONE; + } + return super.determineLockingStrategy( querySpec, forUpdateClause, followOnLocking ); + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + // Support was added in 20.1: https://www.cockroachlabs.com/docs/v20.1/select-for-update.html + if ( getDialect().getVersion() < 2010 ) { + return; + } + super.renderForUpdateClause( querySpec, forUpdateClause ); + } + protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Check if current query part is already row numbering to avoid infinite recursion return useOffsetFetchClause( queryPart ) && getQueryPartForRowNumbering() != queryPart 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 96b8e2a26635..24df29875251 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -57,11 +57,6 @@ */ public class DB2Dialect extends Dialect { - // KNOWN LIMITATIONS: - - // * can't select a parameter unless wrapped - // in a cast or function call - private static final String FOR_READ_ONLY_SQL = " for read only with rs"; private static final String FOR_SHARE_SQL = FOR_READ_ONLY_SQL + " use and keep share locks"; private static final String FOR_UPDATE_SQL = FOR_READ_ONLY_SQL + " use and keep update locks"; @@ -71,8 +66,7 @@ public class DB2Dialect extends Dialect { private final int version; - private LimitHandler limitHandler; - + private final LimitHandler limitHandler; private final UniqueDelegate uniqueDelegate; public DB2Dialect(DialectResolutionInfo info) { @@ -80,7 +74,7 @@ public DB2Dialect(DialectResolutionInfo info) { } public DB2Dialect() { - this(900); + this( 900 ); } public DB2Dialect(int version) { @@ -292,6 +286,10 @@ public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) pattern.append("+("); // DB2 supports temporal arithmetic. See https://www.ibm.com/support/knowledgecenter/en/SSEPGG_9.7.0/com.ibm.db2.luw.sql.ref.doc/doc/r0023457.html switch (unit) { + case NATIVE: + // AFAICT the native format is seconds with fractional parts after the decimal point + pattern.append("?2) seconds"); + break; case NANOSECOND: pattern.append("(?2)/1e9) seconds"); break; @@ -340,33 +338,42 @@ public SequenceInformationExtractor getSequenceInformationExtractor() { } @Override - public String getReadLockString(int timeout) { - return timeout==LockOptions.SKIP_LOCKED - ? FOR_SHARE_SKIP_LOCKED_SQL - : FOR_SHARE_SQL; + public String getForUpdateString() { + return FOR_UPDATE_SQL; } @Override - public String getWriteLockString(int timeout) { - return timeout==LockOptions.SKIP_LOCKED + public boolean supportsSkipLocked() { + // Introduced in 11.5: https://www.ibm.com/docs/en/db2/11.5?topic=statement-concurrent-access-resolution-clause + return getVersion() >= 1150; + } + + @Override + public String getForUpdateSkipLockedString() { + return supportsSkipLocked() ? FOR_UPDATE_SKIP_LOCKED_SQL : FOR_UPDATE_SQL; } @Override - public String getForUpdateString() { - return FOR_UPDATE_SQL; + public String getForUpdateSkipLockedString(String aliases) { + return getForUpdateSkipLockedString(); } @Override - public boolean supportsSkipLocked() { - return true; + public String getWriteLockString(int timeout) { + return timeout == LockOptions.SKIP_LOCKED && supportsSkipLocked() + ? FOR_UPDATE_SKIP_LOCKED_SQL + : FOR_UPDATE_SQL; } @Override - public String getForUpdateSkipLockedString() { - return FOR_UPDATE_SKIP_LOCKED_SQL; + public String getReadLockString(int timeout) { + return timeout == LockOptions.SKIP_LOCKED && supportsSkipLocked() + ? FOR_SHARE_SKIP_LOCKED_SQL + : FOR_SHARE_SQL; } + @Override public boolean supportsOuterJoinForUpdate() { return false; 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 9a64c960ec71..cb68147cd0dd 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2SqlAstTranslator.java @@ -42,6 +42,21 @@ public DB2SqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement s super( sessionFactory, statement ); } + @Override + protected String getForUpdate() { + return " for read only with rs use and keep update locks"; + } + + @Override + protected String getForShare() { + return " for read only with rs use and keep share locks"; + } + + @Override + protected String getSkipLocked() { + return " skip locked data"; + } + protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Percent fetches or ties fetches aren't supported in DB2 // According to LegacyDB2LimitHandler, variable limit also isn't supported before 11.1 @@ -59,7 +74,7 @@ protected boolean supportsOffsetClause() { @Override public void visitQueryGroup(QueryGroup queryGroup) { final boolean emulateFetchClause = shouldEmulateFetchClause( queryGroup ); - if ( emulateFetchClause || hasOffset( queryGroup ) && !supportsOffsetClause() ) { + if ( emulateFetchClause || !supportsOffsetClause() && hasOffset( queryGroup ) ) { emulateFetchOffsetWithWindowFunctions( queryGroup, emulateFetchClause ); } else { @@ -70,7 +85,7 @@ public void visitQueryGroup(QueryGroup queryGroup) { @Override public void visitQuerySpec(QuerySpec querySpec) { final boolean emulateFetchClause = shouldEmulateFetchClause( querySpec ); - if ( emulateFetchClause || hasOffset( querySpec ) && !supportsOffsetClause() ) { + if ( emulateFetchClause || !supportsOffsetClause() && hasOffset( querySpec ) ) { emulateFetchOffsetWithWindowFunctions( querySpec, emulateFetchClause ); } else { @@ -81,7 +96,7 @@ public void visitQuerySpec(QuerySpec querySpec) { @Override public void visitOffsetFetchClause(QueryPart queryPart) { if ( !isRowNumberingCurrentQueryPart() ) { - if ( !hasOffset( queryPart ) || supportsOffsetClause() ) { + if ( supportsOffsetClause() || !hasOffset( queryPart ) ) { renderOffsetFetchClause( queryPart, true ); } else if ( queryPart.isRoot() && hasLimit() ) { 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 0eec2ae8f697..7a71e0d9d5be 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2iDialect.java @@ -6,6 +6,7 @@ */ package org.hibernate.dialect; +import org.hibernate.LockOptions; import org.hibernate.dialect.identity.DB2390IdentityColumnSupport; import org.hibernate.dialect.identity.DB2IdentityColumnSupport; import org.hibernate.dialect.identity.IdentityColumnSupport; @@ -87,11 +88,6 @@ public String getQuerySequencesString() { } } - @Override - public String getForUpdateString() { - return " for update with rs"; - } - @Override public LimitHandler getLimitHandler() { if ( getIVersion() >= 730) { @@ -112,6 +108,11 @@ public IdentityColumnSupport getIdentityColumnSupport() { } } + @Override + public boolean supportsSkipLocked() { + return true; + } + @Override public SqlAstTranslatorFactory getSqlAstTranslatorFactory() { return new StandardSqlAstTranslatorFactory() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2zDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2zDialect.java index c01ddce3fbb6..b63da2ec8fc7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2zDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2zDialect.java @@ -10,6 +10,7 @@ import javax.persistence.TemporalType; +import org.hibernate.LockOptions; import org.hibernate.dialect.identity.DB2390IdentityColumnSupport; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.pagination.FetchLimitHandler; @@ -36,11 +37,11 @@ public class DB2zDialect extends DB2Dialect { private final int version; public DB2zDialect(DialectResolutionInfo info) { - this( info.getDatabaseMajorVersion() ); + this( info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10 ); } public DB2zDialect() { - this(7); + this( 700 ); } public DB2zDialect(int version) { @@ -55,7 +56,7 @@ public DB2zDialect(int version) { @Override public boolean supportsTimezoneTypes() { - return getVersion() > 1000; + return getZVersion() > 1000; } int getZVersion() { @@ -64,14 +65,14 @@ int getZVersion() { @Override public SequenceSupport getSequenceSupport() { - return getZVersion() < 8 + return getZVersion() < 800 ? NoSequenceSupport.INSTANCE : DB2390SequenceSupport.INSTANCE; } @Override public String getQuerySequencesString() { - return getZVersion() < 8 ? null : "select * from sysibm.syssequences"; + return getZVersion() < 800 ? null : "select * from sysibm.syssequences"; } @Override @@ -84,6 +85,11 @@ public IdentityColumnSupport getIdentityColumnSupport() { return new DB2390IdentityColumnSupport(); } + @Override + public boolean supportsSkipLocked() { + return true; + } + @Override public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType) { StringBuilder pattern = new StringBuilder(); 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 073b73e20ea4..4d3d3ed87049 100755 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java @@ -401,6 +401,16 @@ public boolean supportsCommentOn() { return false; } + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return RowLockStrategy.NONE; + } + + @Override + public RowLockStrategy getReadRowLockStrategy() { + return RowLockStrategy.NONE; + } + @Override public String getForUpdateString() { return " for update with rs"; @@ -416,11 +426,6 @@ public String getReadLockString(int timeout) { return " for read only with rs"; } - @Override - public String getWriteLockString(String aliases, int timeout) { - return " for update of " + aliases + " with rs"; - } - @Override public boolean supportsOuterJoinForUpdate() { //TODO: check this! 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 e0a64a2dc3b8..43f9b92c165e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DerbySqlAstTranslator.java @@ -39,6 +39,21 @@ public DerbySqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement super( sessionFactory, statement ); } + @Override + protected String getForUpdate() { + return " for update"; + } + + @Override + protected String getForShare() { + return " for read only"; + } + + @Override + protected String getForUpdateWithClause() { + return " with rs"; + } + @Override public void visitCteContainer(CteContainer cteContainer) { if ( cteContainer.isWithRecursive() ) { 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 4f999a22747c..c008e9c3787e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -1725,12 +1725,29 @@ public String getReadLockString(String aliases, int timeout) { * * @return True if the database supports FOR UPDATE OF syntax; * false otherwise. + * @deprecated Use {@link #getWriteRowLockStrategy()} instead */ + @Deprecated public boolean forUpdateOfColumns() { // by default we report no support return false; } + /** + * The row lock strategy to use for write locks. + */ + public RowLockStrategy getWriteRowLockStrategy() { + // by default we report no support + return RowLockStrategy.NONE; + } + + /** + * The row lock strategy to use for read locks. + */ + public RowLockStrategy getReadRowLockStrategy() { + return getWriteRowLockStrategy(); + } + /** * Does this dialect support FOR UPDATE in conjunction with * outer joined rows? @@ -1843,7 +1860,9 @@ public String appendLockHint(LockMode mode, String tableName) { * @param lockOptions The lock options to apply * @param tableName The name of the table to which to apply the lock hint. * @return The table with any required lock hints. + * @deprecated This was moved to {@link AbstractSqlAstTranslator} */ + @Deprecated public String appendLockHint(LockOptions lockOptions, String tableName){ return tableName; } @@ -3515,6 +3534,15 @@ public boolean supportsNoWait() { return false; } + /** + * Does this dialect/database support WAIT timeout. + * + * @return {@code true} if WAIT is supported + */ + public boolean supportsWait() { + return supportsNoWait(); + } + /** * Inline String literal. * @@ -3732,6 +3760,23 @@ public String formatBinaryLiteral(byte[] bytes) { return "X'" + StandardBasicTypes.BINARY.toString( bytes ) + "'"; } + public RowLockStrategy getLockRowIdentifier(LockMode lockMode) { + switch ( lockMode ) { + case PESSIMISTIC_READ: + return getReadRowLockStrategy(); + case WRITE: + case FORCE: + case PESSIMISTIC_FORCE_INCREMENT: + case PESSIMISTIC_WRITE: + case UPGRADE: + case UPGRADE_SKIPLOCKED: + case UPGRADE_NOWAIT: + return getWriteRowLockStrategy(); + default: + return RowLockStrategy.NONE; + } + } + /** * Pluggable strategy for determining the Size to use for columns of * a given SQL type. diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/FirebirdSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/FirebirdSqlAstTranslator.java index e6fbaa166cc2..74ff31fbde41 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/FirebirdSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/FirebirdSqlAstTranslator.java @@ -13,7 +13,6 @@ import org.hibernate.internal.util.collections.Stack; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.query.ComparisonOperator; -import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation; import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; @@ -27,7 +26,6 @@ import org.hibernate.sql.ast.tree.expression.JdbcLiteral; 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.SelfRenderingExpression; import org.hibernate.sql.ast.tree.expression.SqlTuple; @@ -52,6 +50,11 @@ public FirebirdSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statem super( sessionFactory, statement ); } + @Override + protected String getForUpdate() { + return " with lock"; + } + protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Percent fetches or ties fetches aren't supported in Firebird // Before 3.0 there was also no support for window functions 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 1ca9752e7b03..69a37e5195f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -101,7 +101,7 @@ public H2Dialect(int version) { // Prior to 1.4.200 the 'cascade' in 'drop table' was implicit cascadeConstraints = version >= 104200; // 1.4.200 introduced changes in current_time and current_timestamp - useLocalTime = version >= 140199; + useLocalTime = version >= 104199; getDefaultProperties().setProperty( AvailableSettings.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE ); // http://code.google.com/p/h2database/issues/detail?id=235 @@ -193,7 +193,13 @@ public void initializeFunctionRegistry(QueryEngine queryEngine) { CommonFunctionFactory.median( queryEngine ); CommonFunctionFactory.stddevPopSamp( queryEngine ); CommonFunctionFactory.varPopSamp( queryEngine ); - CommonFunctionFactory.format_formatdatetime( queryEngine ); + if ( version == 104200 ) { + // See https://github.com/h2database/h2database/issues/2518 + CommonFunctionFactory.format_toChar( queryEngine ); + } + else { + CommonFunctionFactory.format_formatdatetime( queryEngine ); + } CommonFunctionFactory.rownum( queryEngine ); } @@ -432,6 +438,10 @@ public String getQueryHintString(String query, String hints) { @Override public String translateDatetimeFormat(String format) { + if ( version == 104200 ) { + // See https://github.com/h2database/h2database/issues/2518 + return OracleDialect.datetimeFormat( format, true, true ).result(); + } return new Replacer( format, "'", "''" ) .replace("e", "u") .replace( "xxx", "XXX" ) 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 bd1b7915f8f8..b5bb7601dd57 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java @@ -10,18 +10,16 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; -import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation; 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.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.SqlTuple; import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.select.QueryPart; +import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.exec.spi.JdbcOperation; /** @@ -35,6 +33,30 @@ public HSQLSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement super( sessionFactory, statement ); } + @Override + public boolean supportsFilterClause() { + return true; + } + + @Override + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + if ( getDialect().getVersion() < 200 ) { + return LockStrategy.NONE; + } + return super.determineLockingStrategy( querySpec, forUpdateClause, followOnLocking ); + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + if ( getDialect().getVersion() < 200 ) { + return; + } + super.renderForUpdateClause( querySpec, forUpdateClause ); + } + @Override public void visitOffsetFetchClause(QueryPart queryPart) { if ( supportsOffsetFetchClause() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/IngresSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/IngresSqlAstTranslator.java index be6995182699..eb3f53702ebf 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/IngresSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/IngresSqlAstTranslator.java @@ -34,6 +34,19 @@ public IngresSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statemen super( sessionFactory, statement ); } + @Override + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + return LockStrategy.NONE; + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + // Ingres does not support the FOR UPDATE clause + } + @Override protected void renderFetchPlusOffsetExpression( Expression fetchClauseExpression, 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 22fbf9d23c02..01d7e30ce585 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBSqlAstTranslator.java @@ -30,6 +30,11 @@ public MariaDBSqlAstTranslator(SessionFactoryImplementor sessionFactory, Stateme super( sessionFactory, statement ); } + @Override + protected String getForShare() { + return " lock in share mode"; + } + protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Check if current query part is already row numbering to avoid infinite recursion return useOffsetFetchClause( queryPart ) && getQueryPartForRowNumbering() != queryPart && supportsWindowFunctions() && !isRowsOnlyFetchClauseType( queryPart ); 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 1b97fe85e9ff..d639d77517eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -956,11 +956,17 @@ public boolean supportsNoWait() { return getMySQLVersion() >= 800; } + @Override public boolean supportsWait() { //only supported on MariaDB return false; } + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return supportsAliasLocks() ? RowLockStrategy.TABLE : RowLockStrategy.NONE; + } + boolean supportsForShare() { return getMySQLVersion() >= 800; } 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 6a4ab95881eb..7ab190c3d99c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLSqlAstTranslator.java @@ -30,6 +30,11 @@ public MySQLSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement super( sessionFactory, statement ); } + @Override + protected String getForShare() { + return getDialect().getVersion() >= 800 ? " for share" : " lock in share mode"; + } + protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Check if current query part is already row numbering to avoid infinite recursion return useOffsetFetchClause( queryPart ) && getQueryPartForRowNumbering() != queryPart 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 fdc2451459d6..061b7a40bca7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -1058,6 +1058,11 @@ public boolean forUpdateOfColumns() { return true; } + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return RowLockStrategy.COLUMN; + } + @Override public String getForUpdateNowaitString() { return " for update nowait"; @@ -1092,7 +1097,7 @@ private String withTimeout(String lockString, int timeout) { case LockOptions.WAIT_FOREVER: return lockString; default: - return supportsNoWait() ? lockString + " wait " + Math.round(timeout / 1e3f) : lockString; + return supportsWait() ? lockString + " wait " + Math.round(timeout / 1e3f) : lockString; } } 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 fea474aeda83..78dff7e9ec9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleSqlAstTranslator.java @@ -6,11 +6,14 @@ */ package org.hibernate.dialect; +import java.util.Collections; import java.util.List; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.collections.Stack; import org.hibernate.query.ComparisonOperator; +import org.hibernate.query.FetchClauseType; +import org.hibernate.query.IllegalQueryOperationException; import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; @@ -20,11 +23,13 @@ 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.from.UnionTableGroup; import org.hibernate.sql.ast.tree.insert.Values; 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.ast.tree.select.SelectClause; +import org.hibernate.sql.ast.tree.select.SortSpecification; import org.hibernate.sql.exec.spi.JdbcOperation; /** @@ -38,11 +43,126 @@ public OracleSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statemen super( sessionFactory, statement ); } + @Override + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + LockStrategy strategy = super.determineLockingStrategy( querySpec, forUpdateClause, followOnLocking ); + final boolean followOnLockingDisabled = Boolean.FALSE.equals( followOnLocking ); + if ( strategy != LockStrategy.FOLLOW_ON && querySpec.hasSortSpecifications() ) { + if ( followOnLockingDisabled ) { + throw new IllegalQueryOperationException( "Locking with ORDER BY is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + // Oracle also doesn't support locks with set operators + // See https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_10002.htm#i2066346 + if ( strategy != LockStrategy.FOLLOW_ON && isPartOfQueryGroup() ) { + if ( followOnLockingDisabled ) { + throw new IllegalQueryOperationException( "Locking with set operators is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + if ( strategy != LockStrategy.FOLLOW_ON && hasSetOperations( querySpec ) ) { + if ( followOnLockingDisabled ) { + throw new IllegalQueryOperationException( "Locking with set operators is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + if ( strategy != LockStrategy.FOLLOW_ON && useOffsetFetchClause( querySpec ) && !isRowsOnlyFetchClauseType( querySpec ) ) { + if ( followOnLockingDisabled ) { + throw new IllegalQueryOperationException( "Locking with FETCH is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + if ( strategy != LockStrategy.FOLLOW_ON ) { + final boolean hasOffset; + if ( querySpec.isRoot() && hasLimit() && getLimit().getFirstRowJpa() != 0 ) { + hasOffset = true; + // We must record that the generated SQL depends on the fact that there is an offset + addAppliedParameterBinding( getOffsetParameter(), null ); + } + else { + hasOffset = querySpec.getOffsetClauseExpression() != null; + } + if ( hasOffset ) { + if ( followOnLockingDisabled ) { + throw new IllegalQueryOperationException( "Locking with OFFSET is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + } + return strategy; + } + + private boolean hasSetOperations(QuerySpec querySpec) { + return querySpec.getFromClause().queryTableGroups( group -> group instanceof UnionTableGroup ? group : null ) != null; + } + + private boolean isPartOfQueryGroup() { + return getQueryPartStack().findCurrentFirst( part -> part instanceof QueryGroup ? part : null ) != null; + } + protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Check if current query part is already row numbering to avoid infinite recursion - return getQueryPartForRowNumbering() != queryPart && !supportsOffsetFetchClause() && ( - queryPart.isRoot() && hasLimit() || queryPart.getFetchClauseExpression() != null || queryPart.getOffsetClauseExpression() != null - ); + if (getQueryPartForRowNumbering() == queryPart) { + return false; + } + final boolean hasLimit = queryPart.isRoot() && hasLimit() || queryPart.getFetchClauseExpression() != null + || queryPart.getOffsetClauseExpression() != null; + if ( !hasLimit ) { + return false; + } + // Even if Oracle supports the OFFSET/FETCH clause, there are conditions where we still want to use the ROWNUM pagination + if ( supportsOffsetFetchClause() ) { + // When the query has no sort specifications and offset, we want to use the ROWNUM pagination as that is a special locking case + return !queryPart.hasSortSpecifications() && !hasOffset( queryPart ); + } + return true; + } + + @Override + protected void emulateFetchOffsetWithWindowFunctions( + QueryPart queryPart, + Expression offsetExpression, + Expression fetchExpression, + FetchClauseType fetchClauseType, + boolean emulateFetchClause) { + if ( queryPart instanceof QuerySpec && !queryPart.hasSortSpecifications() && offsetExpression == null && fetchClauseType == FetchClauseType.ROWS_ONLY ) { + // Special case for Oracle to support locking along with simple max results paging + final QuerySpec querySpec = (QuerySpec) queryPart; + withRowNumbering( + querySpec, + () -> { + appendSql( "select * from (" ); + super.visitQuerySpec( querySpec ); + appendSql( ") where rownum <= " ); + final Stack clauseStack = getClauseStack(); + clauseStack.push( Clause.WHERE ); + try { + fetchExpression.accept( this ); + + // We render the FOR UPDATE clause in the outer query + clauseStack.pop(); + clauseStack.push( Clause.FOR_UPDATE ); + visitForUpdateClause( querySpec ); + } + finally { + clauseStack.pop(); + } + } + ); + } + else { + super.emulateFetchOffsetWithWindowFunctions( + queryPart, + offsetExpression, + fetchExpression, + fetchClauseType, + emulateFetchClause + ); + } } @Override @@ -104,7 +224,18 @@ public void visitOffsetFetchClause(QueryPart queryPart) { @Override protected void renderRowNumber(SelectClause selectClause, QueryPart queryPart) { if ( supportsOffsetFetchClause() || selectClause.isDistinct() ) { - super.renderRowNumber( selectClause, queryPart ); + final List sortSpecifications = getSortSpecificationsRowNumbering( selectClause, queryPart ); + if ( selectClause.isDistinct() ) { + appendSql( "dense_rank()" ); + } + else { + if ( sortSpecifications.isEmpty() ) { + appendSql( "rownum" ); + return; + } + appendSql( "row_number()" ); + } + visitOverClause( Collections.emptyList(), sortSpecifications ); } else { appendSql( "rownum" ); 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 7061d6287052..adff3353c886 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -784,11 +784,21 @@ public boolean supportsNoWait() { return getVersion() >= 810; } + @Override + public boolean supportsWait() { + return false; + } + @Override public boolean supportsSkipLocked() { return getVersion() >= 950; } + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return RowLockStrategy.TABLE; + } + @Override public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() { return getVersion() >= 950 ? GroupBySummarizationRenderingStrategy.FUNCTION : GroupBySummarizationRenderingStrategy.NONE; 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 996673ea8751..d1155175dd3b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLSqlAstTranslator.java @@ -10,6 +10,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.tree.Statement; +import org.hibernate.sql.ast.tree.cte.CteMaterialization; import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; @@ -30,6 +31,26 @@ public PostgreSQLSqlAstTranslator(SessionFactoryImplementor sessionFactory, Stat super( sessionFactory, statement ); } + @Override + protected void renderMaterializationHint(CteMaterialization materialization) { + if ( getDialect().getVersion() >= 1200 ) { + if ( materialization == CteMaterialization.NOT_MATERIALIZED ) { + appendSql( "not " ); + } + appendSql( "materialized " ); + } + } + + @Override + public boolean supportsFilterClause() { + return getDialect().getVersion() >= 940; + } + + @Override + protected String getForShare() { + return " for share"; + } + protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Check if current query part is already row numbering to avoid infinite recursion if ( getQueryPartForRowNumbering() == queryPart || isRowsOnlyFetchClauseType( queryPart ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java index f56face4f63e..6d702308029b 100755 --- a/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200Dialect.java @@ -176,7 +176,7 @@ public SqlAstTranslatorFactory getSqlAstTranslatorFactory() { @Override protected SqlAstTranslator buildTranslator( SessionFactoryImplementor sessionFactory, Statement statement) { - return new RDBMSOS2200SqlAstTranslator<>( sessionFactory, statement ); + return new RDMSOS2200SqlAstTranslator<>( sessionFactory, statement ); } }; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/RDBMSOS2200SqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200SqlAstTranslator.java similarity index 86% rename from hibernate-core/src/main/java/org/hibernate/dialect/RDBMSOS2200SqlAstTranslator.java rename to hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200SqlAstTranslator.java index c24b908b3d53..00294c531df2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/RDBMSOS2200SqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/RDMSOS2200SqlAstTranslator.java @@ -11,7 +11,6 @@ import org.hibernate.query.FetchClauseType; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; -import org.hibernate.query.Limit; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.Statement; @@ -22,6 +21,7 @@ import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.select.QueryPart; +import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.exec.spi.JdbcOperation; /** @@ -29,12 +29,25 @@ * * @author Christian Beikov */ -public class RDBMSOS2200SqlAstTranslator extends AbstractSqlAstTranslator { +public class RDMSOS2200SqlAstTranslator extends AbstractSqlAstTranslator { - public RDBMSOS2200SqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { + public RDMSOS2200SqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { super( sessionFactory, statement ); } + @Override + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + return LockStrategy.NONE; + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + // Unisys 2200 does not support the FOR UPDATE clause + } + @Override public void visitOffsetFetchClause(QueryPart queryPart) { if ( queryPart.isRoot() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/RowLockStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/RowLockStrategy.java new file mode 100644 index 000000000000..d4d87b515894 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/RowLockStrategy.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 . + */ +package org.hibernate.dialect; + +/** + * The strategy for rendering which row to lock with the FOR UPDATE OF clause. + * + * @author Christian Beikov + */ +public enum RowLockStrategy { + /** + * Use a column name. + */ + COLUMN, + /** + * Use a table alias. + */ + TABLE, + /** + * No support for specifying rows to lock. + */ + NONE; +} 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 012e55d03f27..a82a1b8309f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -394,6 +394,11 @@ public boolean supportsNoWait() { return getVersion() >= 9; } + @Override + public boolean supportsWait() { + return false; + } + @Override public GroupBySummarizationRenderingStrategy getGroupBySummarizationRenderingStrategy() { return GroupBySummarizationRenderingStrategy.CLAUSE; 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 2b1783a34b01..bf2ac41f8a67 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerSqlAstTranslator.java @@ -8,6 +8,8 @@ import java.util.List; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; import org.hibernate.query.FetchClauseType; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; @@ -20,6 +22,8 @@ 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.from.TableReference; +import org.hibernate.sql.ast.tree.from.UnionTableReference; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; @@ -34,10 +38,98 @@ */ public class SQLServerSqlAstTranslator extends AbstractSqlAstTranslator { + private static final String UNION_ALL = " union all "; + public SQLServerSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { super( sessionFactory, statement ); } + @Override + protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) { + final String tableExpression = tableReference.getTableExpression(); + if ( tableReference instanceof UnionTableReference && lockMode != LockMode.NONE && tableExpression.charAt( 0 ) == '(' ) { + // SQL Server requires to push down the lock hint to the actual table names + int searchIndex = 0; + int unionIndex; + while ( ( unionIndex = tableExpression.indexOf( UNION_ALL, searchIndex ) ) != -1 ) { + appendSql( tableExpression.substring( searchIndex, unionIndex ) ); + renderLockHint( lockMode ); + appendSql( UNION_ALL ); + searchIndex = unionIndex + UNION_ALL.length(); + } + appendSql( tableExpression.substring( searchIndex, tableExpression.length() - 2 ) ); + renderLockHint( lockMode ); + appendSql( " )" ); + + registerAffectedTable( tableReference ); + final Clause currentClause = getClauseStack().getCurrent(); + if ( rendersTableReferenceAlias( currentClause ) ) { + final String identificationVariable = tableReference.getIdentificationVariable(); + if ( identificationVariable != null ) { + appendSql( getDialect().getTableAliasSeparator() ); + appendSql( identificationVariable ); + } + } + } + else { + super.renderTableReference( tableReference, lockMode ); + renderLockHint( lockMode ); + } + // Just always return true because SQL Server doesn't support the FOR UPDATE clause + return true; + } + + 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 readLockStr = effectiveLockTimeout == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock"; + + 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 + ")" ); + break; + case PESSIMISTIC_READ: + appendSql( " with (" + readLockStr + ", rowlock" + noWaitStr + skipLockStr + ")" ); + break; + case UPGRADE_SKIPLOCKED: + appendSql( " with (updlock, rowlock, readpast" + noWaitStr + ")" ); + break; + case UPGRADE_NOWAIT: + appendSql( " with (updlock, holdlock, rowlock, nowait)" ); + break; + } + } + else { + switch ( lockMode ) { + //noinspection deprecation + case UPGRADE: + case UPGRADE_NOWAIT: + case PESSIMISTIC_WRITE: + case WRITE: + appendSql( " with (updlock, rowlock)" ); + break; + case PESSIMISTIC_READ: + appendSql(" with (holdlock, rowlock)" ); + break; + case UPGRADE_SKIPLOCKED: + appendSql( " with (updlock, rowlock, readpast)" ); + break; + } + } + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + // SQL Server does not support the FOR UPDATE clause + } + protected OffsetFetchClauseMode getOffsetFetchClauseMode(QueryPart queryPart) { final int version = getDialect().getVersion(); final boolean hasLimit; 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 8aee479c55bd..abcc7752e571 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java @@ -109,25 +109,25 @@ public void initializeFunctionRegistry(QueryEngine queryEngine) { super.initializeFunctionRegistry( queryEngine ); // Aggregate Functions - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "any_value" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "any_value" ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "array_agg" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "array_agg" ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "countif" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "countif" ) .setInvariantType( StandardBasicTypes.LONG ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "logical_and" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "logical_and" ) .setInvariantType( StandardBasicTypes.BOOLEAN ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "logical_or" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "logical_or" ) .setInvariantType( StandardBasicTypes.BOOLEAN ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "string_agg" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "string_agg" ) .setInvariantType( StandardBasicTypes.STRING ) .setArgumentCountBetween( 1, 2 ) .register(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerSqlAstTranslator.java index ae49cd2860de..c53905aaa623 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerSqlAstTranslator.java @@ -19,6 +19,7 @@ import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.select.QueryPart; +import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.exec.spi.JdbcOperation; /** @@ -32,6 +33,19 @@ public SpannerSqlAstTranslator(SessionFactoryImplementor sessionFactory, Stateme super( sessionFactory, statement ); } + @Override + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + return LockStrategy.NONE; + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + // Spanner does not support the FOR UPDATE clause + } + @Override public void visitOffsetFetchClause(QueryPart queryPart) { renderLimitOffsetClause( queryPart ); 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 87bbb629b66e..4cca3d944b97 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASEDialect.java @@ -47,7 +47,7 @@ public SybaseASEDialect() { } public SybaseASEDialect(int version) { - super(version); + super( version ); //On Sybase ASE, the 'bit' type cannot be null, //and cannot have indexes (while we don't use @@ -421,15 +421,20 @@ public boolean forUpdateOfColumns() { return getVersion() >= 1570; } + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return getVersion() >= 1570 ? RowLockStrategy.COLUMN : RowLockStrategy.TABLE; + } + @Override public String getForUpdateString() { - return getVersion() < 1570 ? super.getForUpdateString() : " for update"; + return getVersion() < 1570 ? "" : " for update"; } @Override public String getForUpdateString(String aliases) { return getVersion() < 1570 - ? super.getForUpdateString( aliases ) + ? "" : getForUpdateString() + " of " + aliases; } 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 e2cc4f724342..34fa53948e3d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASESqlAstTranslator.java @@ -8,6 +8,7 @@ import java.util.List; +import org.hibernate.LockMode; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; @@ -18,6 +19,7 @@ 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.from.TableReference; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectClause; @@ -34,6 +36,26 @@ public SybaseASESqlAstTranslator(SessionFactoryImplementor sessionFactory, State super( sessionFactory, statement ); } + @Override + protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) { + super.renderTableReference( tableReference, lockMode ); + if ( getDialect().getVersion() < 1570 ) { + if ( LockMode.READ.lessThan( lockMode ) ) { + appendSql( " holdlock" ); + } + return true; + } + return false; + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + if ( getDialect().getVersion() < 1570 ) { + return; + } + super.renderForUpdateClause( querySpec, forUpdateClause ); + } + @Override protected void renderSearchClause(CteStatement cte) { // Sybase ASE does not support this, but it's just a hint anyway diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseAnywhereDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseAnywhereDialect.java index 10e9dd626b58..59781d541f3e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseAnywhereDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseAnywhereDialect.java @@ -7,12 +7,14 @@ package org.hibernate.dialect; +import org.hibernate.LockOptions; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.identity.SybaseAnywhereIdentityColumnSupport; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.TopLimitHandler; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.sql.ForUpdateFragment; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory; @@ -20,6 +22,7 @@ import org.hibernate.sql.exec.spi.JdbcOperation; import java.sql.Types; +import java.util.Map; /** * SQL Dialect for Sybase Anywhere @@ -28,7 +31,7 @@ public class SybaseAnywhereDialect extends SybaseDialect { public SybaseAnywhereDialect() { - this(8); + this( 800 ); } public SybaseAnywhereDialect(DialectResolutionInfo info){ @@ -130,6 +133,41 @@ public IdentityColumnSupport getIdentityColumnSupport() { return new SybaseAnywhereIdentityColumnSupport(); } + @Override + public boolean forUpdateOfColumns() { + return getVersion() >= 1000; + } + + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return getVersion() >= 1000 ? RowLockStrategy.COLUMN : RowLockStrategy.TABLE; + } + + @Override + public String getForUpdateString() { + return getVersion() < 1000 ? "" : " for update"; + } + + @Override + public String getForUpdateString(String aliases) { + return getVersion() < 1000 + ? "" + : getForUpdateString() + " of " + aliases; + } + + @Override + public String appendLockHint(LockOptions mode, String tableName) { + return getVersion() < 1000 ? super.appendLockHint( mode, tableName ) : tableName; + } + + @Override + @SuppressWarnings("deprecation") + public String applyLocksToSql(String sql, LockOptions aliasedLockOptions, Map keyColumnNames) { + return getVersion() < 1000 + ? super.applyLocksToSql( sql, aliasedLockOptions, keyColumnNames ) + : sql + new ForUpdateFragment( this, aliasedLockOptions, keyColumnNames ).toFragmentString(); + } + @Override public LimitHandler getLimitHandler() { //TODO: support 'TOP ? START AT ?' diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseAnywhereSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseAnywhereSqlAstTranslator.java index 6f9b14a959e5..002024d8cf8b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseAnywhereSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseAnywhereSqlAstTranslator.java @@ -8,6 +8,7 @@ import java.util.List; +import org.hibernate.LockMode; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; @@ -18,6 +19,7 @@ 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.from.TableReference; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectClause; @@ -34,6 +36,26 @@ public SybaseAnywhereSqlAstTranslator(SessionFactoryImplementor sessionFactory, super( sessionFactory, statement ); } + @Override + protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) { + super.renderTableReference( tableReference, lockMode ); + if ( getDialect().getVersion() < 1000 ) { + if ( LockMode.READ.lessThan( lockMode ) ) { + appendSql( " holdlock" ); + } + return true; + } + return false; + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + if ( getDialect().getVersion() < 1000 ) { + return; + } + super.renderForUpdateClause( querySpec, forUpdateClause ); + } + @Override protected boolean needsRowsToSkip() { return getDialect().getVersion() < 900; 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 f8e5b255b9c6..29f208a1fdbf 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java @@ -38,7 +38,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect { private static final int PARAM_LIST_SIZE_LIMIT = 250000; public SybaseDialect(){ - this(1100); + this( 1100 ); } public SybaseDialect(DialectResolutionInfo info){ 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 b7df4ee23f12..3897fc4ea510 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseSqlAstTranslator.java @@ -8,6 +8,7 @@ import java.util.List; +import org.hibernate.LockMode; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; @@ -18,7 +19,9 @@ 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.from.TableReference; import org.hibernate.sql.ast.tree.select.QueryPart; +import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.exec.spi.JdbcOperation; /** @@ -32,6 +35,20 @@ public SybaseSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statemen super( sessionFactory, statement ); } + @Override + protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) { + super.renderTableReference( tableReference, lockMode ); + if ( LockMode.READ.lessThan( lockMode ) ) { + appendSql( " holdlock" ); + } + return true; + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + // Sybase does not support the FOR UPDATE clause + } + @Override protected void renderSearchClause(CteStatement cte) { // Sybase does not support this, but it's just a hint anyway diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TeradataDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/TeradataDialect.java index 2a812eb37db7..467c670066e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TeradataDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TeradataDialect.java @@ -482,6 +482,16 @@ public boolean supportsLockTimeouts() { return false; } + @Override + public boolean supportsNoWait() { + return true; + } + + @Override + public boolean supportsWait() { + return false; + } + @Override public boolean useFollowOnLocking(String sql, QueryOptions queryOptions) { return getVersion() >= 14; @@ -581,7 +591,6 @@ public String applyLocksToSql(String sql, LockOptions aliasedLockOptions, Map= 14 ) { + final ForUpdateClause forUpdateClause = new ForUpdateClause(); + forUpdateClause.merge( getLockOptions() ); + super.renderForUpdateClause( querySpec, forUpdateClause ); + } + else { + super.visitQuerySpec( querySpec ); + } + } + + @Override + protected String getForUpdate() { + return "locking row for write "; + } + + @Override + protected String getForShare() { + return "locking row for read "; + } + + @Override + protected String getNoWait() { + return "nowait "; + } + + @Override + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + return LockStrategy.NONE; + } + + @Override + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + // Teradata does not support the FOR UPDATE clause but has a proprietary LOCKING clause + } + @Override protected boolean needsRowsToSkip() { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java index f932ba0d9a75..c1a0c2f77b54 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenDialect.java @@ -7,6 +7,7 @@ package org.hibernate.dialect; import org.hibernate.LockMode; +import org.hibernate.LockOptions; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.lock.*; @@ -215,11 +216,59 @@ public boolean supportsNoWait() { return true; } + @Override + public boolean forUpdateOfColumns() { + return true; + } + + @Override + public RowLockStrategy getWriteRowLockStrategy() { + return RowLockStrategy.COLUMN; + } + + @Override + public String getForUpdateString(String aliases) { + return " for update of " + aliases; + } + @Override public String getForUpdateNowaitString() { return " for update nowait"; } + @Override + public String getWriteLockString(int timeout) { + return withTimeout( getForUpdateString(), timeout ); + } + + @Override + public String getWriteLockString(String aliases, int timeout) { + return withTimeout( getForUpdateString(aliases), timeout ); + } + + @Override + public String getReadLockString(int timeout) { + return getWriteLockString( timeout ); + } + + @Override + public String getReadLockString(String aliases, int timeout) { + return getWriteLockString( aliases, timeout ); + } + + + private String withTimeout(String lockString, int timeout) { + switch (timeout) { + case LockOptions.NO_WAIT: + return supportsNoWait() ? lockString + " nowait" : lockString; + case LockOptions.SKIP_LOCKED: + case LockOptions.WAIT_FOREVER: + return lockString; + default: + return supportsWait() ? lockString + " wait " + Math.round( timeout / 1e3f ) : lockString; + } + } + @Override public boolean supportsColumnCheck() { return false; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenSqlAstTranslator.java index ef5ba975ec90..de916a75a858 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TimesTenSqlAstTranslator.java @@ -10,6 +10,8 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.query.ComparisonOperator; +import org.hibernate.query.IllegalQueryOperationException; +import org.hibernate.query.SemanticException; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.Statement; @@ -18,6 +20,7 @@ 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.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectClause; @@ -34,6 +37,23 @@ public TimesTenSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statem super( sessionFactory, statement ); } + @Override + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + // TimesTen supports locks with aggregates but not with set operators + // See https://docs.oracle.com/cd/E11882_01/timesten.112/e21642/state.htm#TTSQL329 + LockStrategy strategy = LockStrategy.CLAUSE; + if ( getQueryPartStack().findCurrentFirst( part -> part instanceof QueryGroup ? part : null ) != null ) { + if ( Boolean.FALSE.equals( followOnLocking ) ) { + throw new IllegalQueryOperationException( "Locking with set operators is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + return strategy; + } + @Override protected void renderSearchClause(CteStatement cte) { // TimesTen does not support this, but it's just a hint anyway 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 1891b0fa023a..c3df974ed4b6 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 @@ -167,7 +167,7 @@ public static void rand(QueryEngine queryEngine) { } public static void median(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "median" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "median" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); @@ -189,7 +189,7 @@ public static void median_percentileCont(QueryEngine queryEngine, boolean over) * - On Oracle, DB2, MySQL it means stdev_pop() */ public static void stddev(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "stddev" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stddev" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); @@ -202,47 +202,47 @@ public static void stddev(QueryEngine queryEngine) { * - On Oracle, DB2, MySQL it means var_pop() */ public static void variance(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "variance" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "variance" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); } public static void stddevPopSamp(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "stddev_pop" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stddev_pop" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "stddev_samp" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stddev_samp" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); } public static void varPopSamp(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "var_pop" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "var_pop" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "var_samp" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "var_samp" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); } public static void covarPopSamp(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "covar_pop" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "covar_pop" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 2 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "covar_samp" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "covar_samp" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 2 ) .register(); } public static void corr(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "corr" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "corr" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 2 ) .register(); @@ -254,7 +254,7 @@ public static void regrLinearRegressionAggregates(QueryEngine queryEngine) { "regr_slope", "regr_sxx", "regr_sxy", "regr_syy" ) .forEach( fnName -> - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( fnName ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( fnName ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 2 ) .register() @@ -265,11 +265,11 @@ public static void regrLinearRegressionAggregates(QueryEngine queryEngine) { * DB2 */ public static void stdevVarianceSamp(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "stddev_samp" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stddev_samp" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "variance_samp" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "variance_samp" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); @@ -279,11 +279,11 @@ public static void stdevVarianceSamp(QueryEngine queryEngine) { * SQL Server-style */ public static void stddevPopSamp_stdevp(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "stdev" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stdev" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "stdevp" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "stdevp" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); @@ -295,11 +295,11 @@ public static void stddevPopSamp_stdevp(QueryEngine queryEngine) { * SQL Server-style */ public static void varPopSamp_varp(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "var" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "var" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "varp" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "varp" ) .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount( 1 ) .register(); @@ -638,11 +638,11 @@ public static void bitandorxornot_operator(QueryEngine queryEngine) { * These are aggregate functions taking one argument! */ public static void bitAndOr(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_and" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "bit_and" ) .setExactArgumentCount( 1 ) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bit_or" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "bit_or" ) .setExactArgumentCount( 1 ) .register(); @@ -656,13 +656,13 @@ public static void bitAndOr(QueryEngine queryEngine) { * These are aggregate functions taking one argument! */ public static void everyAny(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "every" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "every" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) .setArgumentListSignature("(predicate)") .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "any" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "any" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) .setArgumentListSignature("(predicate)") @@ -675,14 +675,14 @@ public static void everyAny(QueryEngine queryEngine) { * and predicates! */ public static void everyAny_boolAndOr(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bool_and" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "bool_and" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) .setArgumentListSignature("(predicate)") .register(); queryEngine.getSqmFunctionRegistry().registerAlternateKey( "every", "bool_and" ); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder( "bool_or" ) + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder( "bool_or" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) .setArgumentListSignature("(predicate)") @@ -696,14 +696,14 @@ public static void everyAny_boolAndOr(QueryEngine queryEngine) { * aggregation functions using sum() and case. */ public static void everyAny_sumCase(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "every", + queryEngine.getSqmFunctionRegistry().patternAggregateDescriptorBuilder( "every", "(sum(case when ?1 then 0 else 1 end)=0)" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) .setArgumentListSignature("(predicate)") .register(); - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "any", + queryEngine.getSqmFunctionRegistry().patternAggregateDescriptorBuilder( "any", "(sum(case when ?1 then 1 else 0 end)>0)" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) @@ -716,14 +716,14 @@ public static void everyAny_sumCase(QueryEngine queryEngine) { * for SQL Server. */ public static void everyAny_sumIif(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "every", + queryEngine.getSqmFunctionRegistry().patternAggregateDescriptorBuilder( "every", "min(iif(?1,1,0))" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) .setArgumentListSignature("(predicate)") .register(); - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "any", + queryEngine.getSqmFunctionRegistry().patternAggregateDescriptorBuilder( "any", "max(iif(?1,1,0))" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) @@ -736,14 +736,14 @@ public static void everyAny_sumIif(QueryEngine queryEngine) { * for Oracle. */ public static void everyAny_sumCaseCase(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "every", + queryEngine.getSqmFunctionRegistry().patternAggregateDescriptorBuilder( "every", "min(case when ?1 then 1 else 0 end)" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) .setArgumentListSignature("(predicate)") .register(); - queryEngine.getSqmFunctionRegistry().patternDescriptorBuilder( "any", + queryEngine.getSqmFunctionRegistry().patternAggregateDescriptorBuilder( "any", "max(case when ?1 then 1 else 0 end)" ) .setExactArgumentCount( 1 ) .setInvariantType( StandardBasicTypes.BOOLEAN ) @@ -1482,11 +1482,11 @@ public static void leastGreatest_minMaxValue(QueryEngine queryEngine) { } public static void aggregates(QueryEngine queryEngine) { - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("max") + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("max") .setExactArgumentCount(1) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("min") + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("min") .setExactArgumentCount(1) .register(); @@ -1500,7 +1500,7 @@ public static void aggregates(QueryEngine queryEngine) { // 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().namedDescriptorBuilder("sum") + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("sum") .setReturnTypeResolver( new FunctionReturnTypeResolver() { @Override public AllowableFunctionReturnType resolveFunctionReturnType(AllowableFunctionReturnType impliedType, List> arguments, TypeConfiguration typeConfiguration) { @@ -1574,12 +1574,12 @@ public BasicValuedMapping resolveFunctionReturnType(Supplier .setExactArgumentCount(1) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("avg") + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("avg") .setInvariantType( StandardBasicTypes.DOUBLE ) .setExactArgumentCount(1) .register(); - queryEngine.getSqmFunctionRegistry().namedDescriptorBuilder("count") + queryEngine.getSqmFunctionRegistry().namedAggregateDescriptorBuilder("count") .setInvariantType( StandardBasicTypes.LONG ) .setExactArgumentCount(1) .setArgumentListSignature("([distinct ]{arg|*})") diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index eddf2ca4f1be..bdd52a34893e 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -801,6 +801,9 @@ protected QueryImplementor buildNamedQuery(String queryName, Class res HqlQueryImplementor query = namedHqlDescriptor.toQuery( this, resultType ); query.setComment( "dynamic HQL query" ); applyQuerySettingsAndHints( query ); + if ( namedHqlDescriptor.getLockOptions() != null ) { + query.setLockOptions( namedHqlDescriptor.getLockOptions() ); + } return query; } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractNaturalIdLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractNaturalIdLoader.java index 4ca9ff592989..426dc5905fd6 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractNaturalIdLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractNaturalIdLoader.java @@ -107,7 +107,6 @@ public T load(Object naturalIdValue, NaturalIdLoadOptions options, SharedSession navigablePath, fetchable.getMappedFetchOptions().getTiming(), true, - options.getLockOptions() != null ? options.getLockOptions().getLockMode() : LockMode.READ, null, creationState ); @@ -158,7 +157,6 @@ protected L selectByNaturalId( else { lockOptions = LockOptions.READ; } - final LockMode lockMode = lockOptions.getLockMode(); final NavigablePath entityPath = new NavigablePath( entityDescriptor.getRootPathName() ); final QuerySpec rootQuerySpec = new QuerySpec( true ); @@ -176,7 +174,6 @@ protected L selectByNaturalId( final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup( entityPath, null, - lockMode, () -> rootQuerySpec::applyPredicate, sqlAstCreationState, sessionFactory @@ -232,7 +229,7 @@ public QueryParameterBindings getQueryParameterBindings() { @Override public Callback getCallback() { - return afterLoadAction -> {}; + throw new UnsupportedOperationException( "Follow-on locking not supported yet" ); } }, row -> (L) row[0], @@ -327,7 +324,6 @@ public Object resolveNaturalIdToId(Object naturalIdValue, SharedSessionContractI navigablePath, fetchable.getMappedFetchOptions().getTiming(), true, - LockMode.READ, null, creationState ); @@ -410,8 +406,7 @@ public QueryParameterBindings getQueryParameterBindings() { @Override public Callback getCallback() { - return afterLoadAction -> { - }; + throw new UnsupportedOperationException( "Follow-on locking not supported yet" ); } }, (row) -> { diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java index 2d6cebbe00a7..06247fa94ab8 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java @@ -10,7 +10,6 @@ import java.util.Collections; import java.util.List; -import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; @@ -91,7 +90,6 @@ class DatabaseSnapshotExecutor { final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup( rootPath, null, - LockMode.NONE, () -> rootQuerySpec::applyPredicate, state, sessionFactory diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java index 239a41190f37..9f45d37ed572 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java @@ -380,7 +380,6 @@ private SelectStatement generateSelect() { final TableGroup rootTableGroup = loadable.createRootTableGroup( rootNavigablePath, null, - lockOptions.getLockMode(), () -> rootQuerySpec::applyPredicate, sqlAstCreationState, creationContext @@ -705,7 +704,6 @@ private BiConsumer createFetchableBiConsumer( } } - final LockMode lockMode = LockMode.READ; FetchTiming fetchTiming = fetchable.getMappedFetchOptions().getTiming(); boolean joined = fetchable.getMappedFetchOptions().getStyle() == FetchStyle.JOIN; @@ -779,7 +777,6 @@ else if ( fetchDepth > maximumFetchDepth ) { fetchablePath, fetchTiming, joined, - lockMode, null, creationState ); @@ -865,7 +862,6 @@ private SelectStatement generateSelect(SubselectFetch subselect) { final TableGroup rootTableGroup = loadable.createRootTableGroup( rootNavigablePath, null, - lockOptions.getLockMode(), () -> rootQuerySpec::applyPredicate, sqlAstCreationState, creationContext diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java index 41073c3a8e5e..89ca0d223b78 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java @@ -108,8 +108,8 @@ public SqlAliasBaseGenerator getSqlAliasBaseGenerator() { } @Override - public LockMode determineLockMode(String identificationVariable) { - return lockOptions.getEffectiveLockMode( identificationVariable ); + public void registerLockMode(String identificationVariable, LockMode explicitLockMode) { + throw new UnsupportedOperationException( "Registering lock modes should only be done for result set mappings!" ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SimpleNaturalIdLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SimpleNaturalIdLoader.java index dbce7617aa70..91b9dec308cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SimpleNaturalIdLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SimpleNaturalIdLoader.java @@ -177,8 +177,7 @@ public QueryParameterBindings getQueryParameterBindings() { @Override public Callback getCallback() { - return afterLoadAction -> { - }; + throw new UnsupportedOperationException( "Follow-on locking not supported yet" ); } }, row -> row[0], diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdEntityLoaderStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdEntityLoaderStandardImpl.java index 802cdec794fd..a604bea7dc83 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdEntityLoaderStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdEntityLoaderStandardImpl.java @@ -84,7 +84,16 @@ public T load( session.getFactory() ); - return loadPlan.load( key, lockOptions, entityInstance, readOnly, session ); + // It seems lock options were ignored in Hibernate 5.x + final LockOptions lockOptionsToUse; + if ( session.getLoadQueryInfluencers().getEnabledCascadingFetchProfile() != null + && LockMode.UPGRADE.greaterThan( lockOptions.getLockMode() ) ) { + lockOptionsToUse = lockOptions.makeCopy().setLockMode( LockMode.NONE ); + } + else { + lockOptionsToUse = lockOptions; + } + return loadPlan.load( key, lockOptionsToUse, entityInstance, readOnly, session ); } @Internal diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdLoadPlan.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdLoadPlan.java index 6ab071a37b04..a15a49a0069e 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdLoadPlan.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdLoadPlan.java @@ -15,6 +15,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.loader.ast.spi.Loadable; import org.hibernate.metamodel.mapping.ModelPart; +import org.hibernate.query.internal.SimpleQueryOptions; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryOptionsAdapter; import org.hibernate.query.spi.QueryParameterBindings; @@ -22,6 +23,7 @@ import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.select.SelectStatement; +import org.hibernate.sql.exec.internal.CallbackImpl; import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl; import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl; import org.hibernate.sql.exec.spi.Callback; @@ -111,10 +113,12 @@ T load( ); } assert offset == jdbcParameters.size(); + final QueryOptions queryOptions = new SimpleQueryOptions( lockOptions, readOnly ); + final Callback callback = new CallbackImpl(); final JdbcSelect jdbcSelect = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory, sqlAst ) - .translate( jdbcParameterBindings, QueryOptions.NONE ); + .translate( jdbcParameterBindings, queryOptions ); - final List list = JdbcSelectExecutorStandardImpl.INSTANCE.list( + final List list = JdbcSelectExecutorStandardImpl.INSTANCE.list( jdbcSelect, jdbcParameterBindings, new ExecutionContext() { @@ -135,12 +139,7 @@ public Object getEntityId() { @Override public QueryOptions getQueryOptions() { - return new QueryOptionsAdapter() { - @Override - public Boolean isReadOnly() { - return readOnly; - } - }; + return queryOptions; } @Override @@ -150,8 +149,7 @@ public QueryParameterBindings getQueryParameterBindings() { @Override public Callback getCallback() { - return afterLoadAction -> { - }; + return callback; } }, RowTransformerPassThruImpl.instance(), @@ -162,7 +160,6 @@ public Callback getCallback() { return null; } - //noinspection unchecked - return (T) list.get( 0 ); + return list.get( 0 ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleUniqueKeyEntityLoaderStandard.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleUniqueKeyEntityLoaderStandard.java index c93c08202e75..d27461c49139 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleUniqueKeyEntityLoaderStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleUniqueKeyEntityLoaderStandard.java @@ -123,8 +123,7 @@ public QueryParameterBindings getQueryParameterBindings() { @Override public Callback getCallback() { - return afterLoadAction -> { - }; + throw new UnsupportedOperationException( "Follow-on locking not supported yet" ); } }, row -> row[0], @@ -201,8 +200,7 @@ public QueryParameterBindings getQueryParameterBindings() { @Override public Callback getCallback() { - return afterLoadAction -> { - }; + throw new UnsupportedOperationException( "Follow-on locking not supported yet" ); } }, row -> row[0], diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/spi/Loadable.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/spi/Loadable.java index 6a98dca770c7..5dbe465b9958 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/spi/Loadable.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/spi/Loadable.java @@ -9,7 +9,6 @@ import java.util.function.Consumer; import java.util.function.Supplier; -import org.hibernate.LockMode; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.metamodel.mapping.ModelPart; @@ -40,7 +39,6 @@ public interface Loadable extends ModelPart, RootTableGroupProducer { default TableGroup createRootTableGroup( NavigablePath navigablePath, String explicitSourceAlias, - LockMode lockMode, Supplier> additionalPredicateCollectorAccess, SqlAstCreationState creationState, SqlAstCreationContext creationContext) { throw new NotYetImplementedFor6Exception( getClass() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java index 164f71227b53..f0775bc1f2c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java @@ -9,7 +9,6 @@ import java.util.List; import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -151,7 +150,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { return new EmbeddableFetchImpl( @@ -172,7 +170,6 @@ public TableGroupJoin createTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java index faa35a1454c3..f74bd207cf43 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityMappingType.java @@ -12,7 +12,6 @@ import java.util.function.Consumer; import java.util.function.Supplier; -import org.hibernate.LockMode; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.loader.ast.spi.Loadable; @@ -273,14 +272,12 @@ default boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencer default TableGroup createRootTableGroup( NavigablePath navigablePath, String explicitSourceAlias, - LockMode lockMode, Supplier> additionalPredicateCollectorAccess, SqlAstCreationState creationState, SqlAstCreationContext creationContext) { return getEntityPersister().createRootTableGroup( navigablePath, explicitSourceAlias, - lockMode, additionalPredicateCollectorAccess, creationState, creationContext diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityDiscriminatorMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityDiscriminatorMapping.java index 322ed48ac63c..8e5bc2e9c231 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityDiscriminatorMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityDiscriminatorMapping.java @@ -6,12 +6,10 @@ */ package org.hibernate.metamodel.mapping.internal; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.JdbcMapping; -import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.persister.entity.DiscriminatorType; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.query.NavigablePath; @@ -138,7 +136,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java index 3183ea623965..a47684dd6d9a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java @@ -8,7 +8,6 @@ import java.io.Serializable; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -181,7 +180,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java index 619eddeaa79b..9c5ded47d9e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java @@ -9,7 +9,6 @@ import java.util.Collections; import java.util.List; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -138,7 +137,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { final FromClauseAccess fromClauseAccess = creationState diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java index 0b07b9f49412..a030a899c8f0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java @@ -8,7 +8,6 @@ import java.util.function.BiConsumer; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -270,7 +269,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java index 62821b1261b7..df1ab71fe64e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java @@ -8,7 +8,6 @@ import java.util.Locale; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -292,7 +291,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { return new BasicFetch<>( diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java index fda4d9d92258..140b758b743e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.function.BiConsumer; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -208,7 +207,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { ResultsLogger.LOGGER.debugf( diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java index 7254d710e7ad..b05a60198ab5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java @@ -6,7 +6,6 @@ */ package org.hibernate.metamodel.mapping.internal; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -145,7 +144,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { // get the collection TableGroup diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java index 40c6e1d262d5..e01636130698 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java @@ -10,7 +10,6 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.SharedSessionContract; import org.hibernate.engine.FetchStyle; @@ -120,7 +119,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { return discriminatorMapping.generateFetch( @@ -128,7 +126,6 @@ public Fetch generateFetch( fetchablePath, fetchTiming, selected, - lockMode, resultVariable, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java index ec95a724f226..781f414d3350 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java @@ -315,7 +315,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { return new AnyValuedFetch( diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java index 81ed021c37e1..1963d9d32c8a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java @@ -8,7 +8,6 @@ import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.mapping.Any; @@ -106,7 +105,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { return discriminatorMapping.generateFetch( @@ -114,7 +112,6 @@ public Fetch generateFetch( fetchablePath, fetchTiming, selected, - lockMode, resultVariable, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java index 76cf4423db64..98975c478312 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java @@ -10,7 +10,6 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -209,7 +208,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { return new EmbeddableFetchImpl( @@ -277,7 +275,6 @@ public TableGroupJoin createTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java index 5996f301c412..0d0572e76f54 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java @@ -11,7 +11,6 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -151,7 +150,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { return new EmbeddableFetchImpl( @@ -203,7 +201,6 @@ public TableGroupJoin createTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedForeignKeyDescriptor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedForeignKeyDescriptor.java index 61ae42db3f18..cdfda4a661bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedForeignKeyDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedForeignKeyDescriptor.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.function.IntFunction; -import org.hibernate.LockMode; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.mapping.IndexedConsumer; import org.hibernate.metamodel.mapping.AssociationKey; @@ -303,7 +302,6 @@ private DomainResult createDomainResult( null, SqlAstJoinType.INNER, true, - LockMode.NONE, creationState.getSqlAstCreationState() ); return tableGroupJoin.getJoinedGroup(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java index f00a20534cf5..d4549adf4151 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java @@ -8,7 +8,6 @@ import java.util.function.BiConsumer; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -144,7 +143,6 @@ public EntityFetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { // find or create the TableGroup associated with this `fetchablePath` @@ -166,7 +164,7 @@ public EntityFetch generateFetch( } ); - return new EntityFetchJoinedImpl( fetchParent, this, tableGroup, lockMode, selected, fetchablePath, creationState ); + return new EntityFetchJoinedImpl( fetchParent, this, tableGroup, selected, fetchablePath, creationState ); } @Override @@ -353,7 +351,6 @@ public TableGroupJoin createTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { @@ -363,7 +360,6 @@ public TableGroupJoin createTableGroupJoin( explicitSourceAlias, sqlAstJoinType, fetched, - lockMode, aliasBaseGenerator, sqlExpressionResolver, creationContext diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java index 41f7573bc6a8..278b84474184 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java @@ -8,7 +8,6 @@ import java.util.function.BiConsumer; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -142,7 +141,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java index 2f56e4b16cc8..df7417d69cc6 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java @@ -12,7 +12,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import org.hibernate.LockMode; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.dialect.Dialect; import org.hibernate.engine.FetchStyle; @@ -478,7 +477,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState(); @@ -499,7 +497,6 @@ public Fetch generateFetch( null, SqlAstJoinType.LEFT, true, - lockMode, creationState.getSqlAstCreationState() ); return tableGroupJoin.getJoinedGroup(); @@ -556,7 +553,6 @@ public TableGroupJoin createTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { @@ -568,7 +564,6 @@ public TableGroupJoin createTableGroupJoin( explicitSourceAlias, sqlAstJoinType, fetched, - lockMode, aliasBaseGenerator, sqlExpressionResolver, creationContext @@ -581,7 +576,6 @@ public TableGroupJoin createTableGroupJoin( explicitSourceAlias, sqlAstJoinType, fetched, - lockMode, aliasBaseGenerator, sqlExpressionResolver, creationContext @@ -600,14 +594,13 @@ private TableGroupJoin createOneToManyTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { final TableGroup tableGroup = createOneToManyTableGroup( navigablePath, fetched, - lockMode, + explicitSourceAlias, aliasBaseGenerator, sqlExpressionResolver, creationContext @@ -634,7 +627,7 @@ private TableGroupJoin createOneToManyTableGroupJoin( private TableGroup createOneToManyTableGroup( NavigablePath navigablePath, boolean fetched, - LockMode lockMode, + String sourceAlias, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { @@ -661,7 +654,7 @@ private TableGroup createOneToManyTableGroup( navigablePath, this, fetched, - lockMode, + sourceAlias, primaryTableReference, true, sqlAliasBase, @@ -684,14 +677,13 @@ private TableGroupJoin createCollectionTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { final TableGroup tableGroup = createCollectionTableGroup( navigablePath, fetched, - lockMode, + explicitSourceAlias, aliasBaseGenerator, sqlExpressionResolver, creationContext @@ -718,7 +710,7 @@ private TableGroupJoin createCollectionTableGroupJoin( private TableGroup createCollectionTableGroup( NavigablePath navigablePath, boolean fetched, - LockMode lockMode, + String sourceAlias, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { @@ -847,7 +839,7 @@ else if ( indexDescriptorEntityMappingType != null navigablePath, this, fetched, - lockMode, + sourceAlias, collectionTableReference, true, sqlAliasBase, @@ -931,7 +923,6 @@ private java.util.function.Predicate createTableReferenceJoinNameChecker public TableGroup createRootTableGroup( NavigablePath navigablePath, String explicitSourceAlias, - LockMode lockMode, Supplier> additionalPredicateCollectorAccess, SqlAstCreationState creationState, SqlAstCreationContext creationContext) { @@ -939,7 +930,7 @@ public TableGroup createRootTableGroup( return createOneToManyTableGroup( navigablePath, false, - lockMode, + explicitSourceAlias, creationState.getSqlAliasBaseGenerator(), creationState.getSqlExpressionResolver(), creationContext @@ -949,7 +940,7 @@ public TableGroup createRootTableGroup( return createCollectionTableGroup( navigablePath, false, - lockMode, + explicitSourceAlias, creationState.getSqlAliasBaseGenerator(), creationState.getSqlExpressionResolver(), creationContext diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java index bcccc22dabed..fd4d34dd93e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java @@ -11,7 +11,6 @@ import java.util.function.Function; import java.util.function.IntFunction; -import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -491,7 +490,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java index 1a71ac339238..fae8f1dc77ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java @@ -600,7 +600,6 @@ public EntityFetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { @@ -622,7 +621,7 @@ public EntityFetch generateFetch( fetchablePath, true, getJoinType( fetchablePath, parentTableGroup ), - lockMode, + resultVariable, creationState, parentTableGroup ); @@ -632,7 +631,7 @@ public EntityFetch generateFetch( tableGroup = fromClauseAccess.resolveTableGroup( fetchablePath, np -> - createTableGroupJoin( fetchablePath, true, lockMode, creationState, parentTableGroup ) + createTableGroupJoin( fetchablePath, true, resultVariable, creationState, parentTableGroup ) ); } @@ -641,7 +640,6 @@ public EntityFetch generateFetch( fetchParent, this, tableGroup, - lockMode, true, fetchablePath, creationState @@ -733,7 +731,6 @@ public DomainResult createDelayedDomainResult( null, tableGroup.isInnerJoinPossible() ? SqlAstJoinType.INNER : SqlAstJoinType.LEFT, true, - null, creationState.getSqlAstCreationState() ); @@ -764,14 +761,14 @@ public DomainResult createDelayedDomainResult( private TableGroup createTableGroupJoin( NavigablePath fetchablePath, boolean fetched, - LockMode lockMode, + String sourceAlias, DomainResultCreationState creationState, TableGroup parentTableGroup) { return createTableGroupJoin( fetchablePath, fetched, getDefaultSqlAstJoinType( parentTableGroup ), - lockMode, + sourceAlias, creationState, parentTableGroup ); @@ -793,16 +790,15 @@ private TableGroup createTableGroupJoin( NavigablePath fetchablePath, boolean fetched, SqlAstJoinType sqlAstJoinType, - LockMode lockMode, + String sourceAlias, DomainResultCreationState creationState, TableGroup parentTableGroup) { final TableGroupJoin tableGroupJoin = createTableGroupJoin( fetchablePath, parentTableGroup, - null, + sourceAlias, sqlAstJoinType, fetched, - lockMode, creationState.getSqlAstCreationState() ); @@ -821,7 +817,6 @@ public TableGroupJoin createTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { @@ -862,7 +857,7 @@ public TableGroupJoin createTableGroupJoin( ); }, this, - null, + explicitSourceAlias, sqlAliasBase, creationContext.getSessionFactory(), lhs @@ -910,7 +905,7 @@ private SqlAstJoinType getJoinType(NavigablePath navigablePath, TableGroup table public TableGroup createTableGroupJoinInternal( NavigablePath navigablePath, boolean fetched, - LockMode lockMode, + String sourceAlias, final SqlAliasBase sqlAliasBase, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext) { @@ -924,7 +919,7 @@ public TableGroup createTableGroupJoinInternal( navigablePath, this, fetched, - lockMode, + sourceAlias, primaryTableReference, false, sqlAliasBase, 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 b2cd1506c2f3..6f3c82e39842 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 @@ -1362,7 +1362,6 @@ public EntityMappingType getEntityMappingType() { public TableGroup createRootTableGroup( NavigablePath navigablePath, String explicitSourceAlias, - LockMode lockMode, Supplier> additionalPredicateCollectorAccess, SqlAstCreationState creationState, SqlAstCreationContext creationContext) { @@ -1379,7 +1378,7 @@ public TableGroup createRootTableGroup( return new StandardTableGroup( navigablePath, this, - lockMode, + explicitSourceAlias, primaryTableReference, true, sqlAliasBase, @@ -2245,7 +2244,7 @@ public Object getCurrentVersion(Object id, SharedSessionContractImplementor sess if ( !isVersioned() ) { return this; } - return getVersionType().nullSafeGet( rs, VERSION_COLUMN_ALIAS, session, null ); + return getVersionMapping().getJdbcMapping().getJdbcValueExtractor().extract( rs, 1, session ); } finally { session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( rs, st ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index 81b6b31df261..0049a3943c90 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -18,7 +18,6 @@ import java.util.function.Supplier; import org.hibernate.HibernateException; -import org.hibernate.LockMode; import org.hibernate.MappingException; import org.hibernate.boot.model.relational.Database; import org.hibernate.cache.spi.access.EntityDataAccess; @@ -924,16 +923,15 @@ public FilterAliasGenerator getFilterAliasGenerator(String rootAlias) { public TableGroup createRootTableGroup( NavigablePath navigablePath, String explicitSourceAlias, - LockMode lockMode, Supplier> additionalPredicateCollectorAccess, SqlAstCreationState creationState, SqlAstCreationContext creationContext) { final TableGroup tableGroup = super.createRootTableGroup( navigablePath, explicitSourceAlias, - lockMode, additionalPredicateCollectorAccess, - creationState, creationContext + creationState, + creationContext ); if ( needsDiscriminator() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java index 148ac3595b09..8bc46bfd8684 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java @@ -21,7 +21,6 @@ import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; -import org.hibernate.LockMode; import org.hibernate.MappingException; import org.hibernate.boot.model.relational.Database; import org.hibernate.cache.spi.access.EntityDataAccess; @@ -54,7 +53,6 @@ import org.hibernate.sql.ast.tree.from.UnionTableGroup; import org.hibernate.sql.ast.tree.from.UnionTableReference; import org.hibernate.sql.ast.tree.predicate.Predicate; -import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.Type; @@ -245,7 +243,6 @@ public boolean containsTableReference(String tableExpression) { public TableGroup createRootTableGroup( NavigablePath navigablePath, String explicitSourceAlias, - LockMode lockMode, Supplier> additionalPredicateCollectorAccess, SqlAstCreationState creationState, SqlAstCreationContext creationContext) { @@ -253,7 +250,7 @@ public TableGroup createRootTableGroup( final TableReference tableReference = resolvePrimaryTableReference(sqlAliasBase); - return new UnionTableGroup( navigablePath, tableReference, this ); + return new UnionTableGroup( navigablePath, tableReference, this, explicitSourceAlias ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheStandardImpl.java index 7ae94b920690..3e6d844becb3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheStandardImpl.java @@ -87,7 +87,7 @@ public SelectQueryPlan resolveSelectQueryPlan( } final SelectQueryPlan plan = creator.get(); - queryPlanCache.put( key, plan ); + queryPlanCache.put( key.prepareForStore(), plan ); return plan; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/SimpleQueryOptions.java b/hibernate-core/src/main/java/org/hibernate/query/internal/SimpleQueryOptions.java new file mode 100644 index 000000000000..9af32abf3684 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/SimpleQueryOptions.java @@ -0,0 +1,34 @@ +/* + * 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.internal; + +import org.hibernate.LockOptions; +import org.hibernate.query.spi.QueryOptionsAdapter; + +/** + * @author Christian Beikov + */ +public class SimpleQueryOptions extends QueryOptionsAdapter { + + private final LockOptions lockOptions; + private final Boolean readOnlyEnabled; + + public SimpleQueryOptions(LockOptions lockOptions, Boolean readOnlyEnabled) { + this.lockOptions = lockOptions; + this.readOnlyEnabled = readOnlyEnabled; + } + + @Override + public LockOptions getLockOptions() { + return lockOptions; + } + + @Override + public Boolean isReadOnly() { + return readOnlyEnabled; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/Builders.java b/hibernate-core/src/main/java/org/hibernate/query/results/Builders.java index 173c3738c422..708b24784137 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/Builders.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/Builders.java @@ -43,11 +43,9 @@ import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.collection.internal.EntityCollectionPartTableGroup; import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; -import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -292,7 +290,6 @@ public static ImplicitFetchBuilder implicitFetchBuilder( fetchablePath, FetchTiming.IMMEDIATE, true, - LockMode.NONE, null, domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java index 2e972a90f460..4fbd27c9cc12 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java @@ -75,6 +75,7 @@ public class DomainResultCreationStateImpl private final Stack> fetchBuilderResolverStack = new StandardStack<>( fetchableName -> null ); private final Stack relativePathStack = new StandardStack<>(); + private Map registeredLockModes; private boolean processingKeyFetches = false; private boolean resolvingCircularFetch; private ForeignKeyDescriptor.Nature currentlyResolvingForeignKeySide; @@ -209,8 +210,15 @@ public DomainResultCreationStateImpl getSqlExpressionResolver() { } @Override - public LockMode determineLockMode(String identificationVariable) { - return LockMode.READ; + public void registerLockMode(String identificationVariable, LockMode explicitLockMode) { + if (registeredLockModes == null ) { + registeredLockModes = new HashMap<>(); + } + registeredLockModes.put( identificationVariable, explicitLockMode ); + } + + public Map getRegisteredLockModes() { + return registeredLockModes; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ImplicitAttributeFetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/ImplicitAttributeFetchBuilder.java index deaab5a4809b..43fa5d2ea91a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ImplicitAttributeFetchBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ImplicitAttributeFetchBuilder.java @@ -8,7 +8,6 @@ import java.util.function.BiFunction; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.query.NavigablePath; @@ -47,7 +46,6 @@ public Fetch buildFetch( fetchPath, FetchTiming.IMMEDIATE, true, - LockMode.READ, null, domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/JdbcValuesMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/JdbcValuesMappingImpl.java index d8c8b302a03b..d279aaa1bdea 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/JdbcValuesMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/JdbcValuesMappingImpl.java @@ -7,9 +7,18 @@ package org.hibernate.query.results; import java.util.List; +import java.util.Map; +import java.util.function.Supplier; +import org.hibernate.LockMode; +import org.hibernate.metamodel.mapping.ModelPart; +import org.hibernate.query.NavigablePath; +import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.ast.spi.SqlSelection; +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.Initializer; import org.hibernate.sql.results.jdbc.internal.StandardJdbcValuesMapping; /** @@ -20,16 +29,54 @@ public class JdbcValuesMappingImpl extends StandardJdbcValuesMapping { private final int rowSize; + private final Map registeredLockModes; public JdbcValuesMappingImpl( List sqlSelections, - List> domainResults, int rowSize) { + List> domainResults, + int rowSize, + Map registeredLockModes) { super( sqlSelections, domainResults ); this.rowSize = rowSize; + this.registeredLockModes = registeredLockModes; } @Override public int getRowSize() { return rowSize; } + + @Override + public List> resolveAssemblers(AssemblerCreationState creationState) { + final AssemblerCreationState finalCreationState; + if ( registeredLockModes == null ) { + finalCreationState = creationState; + } + else { + finalCreationState = new AssemblerCreationState() { + @Override + public LockMode determineEffectiveLockMode(String identificationVariable) { + final LockMode lockMode = registeredLockModes.get( identificationVariable ); + if ( lockMode == null ) { + return creationState.determineEffectiveLockMode( identificationVariable ); + } + return lockMode; + } + + @Override + public Initializer resolveInitializer( + NavigablePath navigablePath, + ModelPart fetchedModelPart, + Supplier producer) { + return creationState.resolveInitializer( navigablePath, fetchedModelPart, producer ); + } + + @Override + public SqlAstCreationContext getSqlAstCreationContext() { + return creationState.getSqlAstCreationContext(); + } + }; + } + return super.resolveAssemblers( finalCreationState ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java index b7111a3df79a..6289c69e6f71 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java @@ -17,6 +17,7 @@ import org.hibernate.Incubating; import org.hibernate.Internal; +import org.hibernate.LockMode; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.StringHelper; @@ -182,8 +183,8 @@ public JdbcValuesMapping resolve( domainResults.add( domainResult ); } - - return new JdbcValuesMappingImpl( sqlSelections, domainResults, rowSize ); + final Map registeredLockModes = creationState.getRegisteredLockModes(); + return new JdbcValuesMappingImpl( sqlSelections, domainResults, rowSize, registeredLockModes ); } private DomainResult makeImplicitDomainResult( diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/TableGroupImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/TableGroupImpl.java index 2e063cc58da8..a923569b34b6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/TableGroupImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/TableGroupImpl.java @@ -11,8 +11,6 @@ import java.util.List; import java.util.function.Consumer; -import org.hibernate.LockMode; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.ModelPartContainer; import org.hibernate.query.NavigablePath; import org.hibernate.sql.ast.tree.from.TableGroup; @@ -33,7 +31,7 @@ public class TableGroupImpl implements TableGroup { private List tableGroupJoins; private final ModelPartContainer container; - private final LockMode lockMode; + private final String sourceAlias; public TableGroupImpl( @@ -41,12 +39,12 @@ public TableGroupImpl( String alias, TableReference primaryTableReference, ModelPartContainer container, - LockMode lockMode) { + String sourceAlias) { this.navigablePath = navigablePath; this.alias = alias; this.primaryTableReference = primaryTableReference; this.container = container; - this.lockMode = lockMode; + this.sourceAlias = sourceAlias; } @Override @@ -70,8 +68,8 @@ public ModelPartContainer getExpressionType() { } @Override - public LockMode getLockMode() { - return lockMode; + public String getSourceAlias() { + return sourceAlias; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java index df99fc2afcfc..a9a584876920 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java @@ -8,7 +8,6 @@ import java.util.function.BiFunction; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.query.NavigablePath; @@ -109,7 +108,6 @@ public Fetch buildFetch( fetchPath, FetchTiming.IMMEDIATE, true, - LockMode.READ, selectedAlias, domainResultCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java index a3ca18ffde44..f09d4301d48e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java @@ -81,7 +81,6 @@ public EntityResult buildResult( np -> entityDescriptor.createRootTableGroup( navigablePath, null, - lockMode, () -> predicate -> {}, impl.getSqlAstCreationState(), impl.getSqlAstCreationState().getCreationContext() diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java index 73fcc4d5ff15..489a01170fbf 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java @@ -73,7 +73,6 @@ public EntityResult buildResult( np -> entityDescriptor.createRootTableGroup( navigablePath, null, - lockMode, () -> predicate -> {}, impl, impl.getCreationContext() diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java index 69b3ba133373..d2692af49fea 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java @@ -109,7 +109,6 @@ public Fetch buildFetch( tableAlias, SqlAstJoinType.INNER, true, - LockMode.NONE, s -> sqlAliasBase, creationState.getSqlExpressionResolver(), creationState.getCreationContext() diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java index f5a930c8e245..6709c94b5572 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.function.BiFunction; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.SelectableConsumer; @@ -93,7 +92,6 @@ public Fetch buildFetch( fetchPath, FetchTiming.IMMEDIATE, true, - LockMode.NONE, null, creationStateImpl ); @@ -109,7 +107,6 @@ public Fetch buildFetch( fetchPath, FetchTiming.DELAYED, false, - LockMode.NONE, null, creationStateImpl ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityCalculated.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityCalculated.java index c2d98eba0d77..0671d99e9e63 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityCalculated.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityCalculated.java @@ -114,10 +114,13 @@ public EntityResult buildResult( tableAlias, tableReference, entityMapping, - explicitLockMode + tableAlias ); creationStateImpl.getFromClauseAccess().registerTableGroup( navigablePath, tableGroup ); + if ( explicitLockMode != null ) { + domainResultCreationState.getSqlAstCreationState().registerLockMode( tableAlias, explicitLockMode ); + } return (EntityResult) entityMapping.createDomainResult( navigablePath, diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java index 12a1dc5045db..fc7e36d19ec3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java @@ -134,7 +134,6 @@ public Fetch buildFetch( navigablePath, FetchTiming.IMMEDIATE, true, - lockMode, null, domainResultCreationState ), @@ -157,7 +156,11 @@ private T buildResultOrFetch( creationState.getSqlExpressionResolver(), creationState.getCreationContext() ); - return new TableGroupImpl( navigablePath, tableAlias, tableReference, entityMapping, lockMode ); + + if ( lockMode != null ) { + domainResultCreationState.getSqlAstCreationState().registerLockMode( tableAlias, lockMode ); + } + return new TableGroupImpl( navigablePath, tableAlias, tableReference, entityMapping, tableAlias ); } ); final TableReference tableReference = tableGroup.getPrimaryTableReference(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java index 518f3c4d751b..829eed989d7c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java @@ -11,7 +11,6 @@ import java.util.function.BiFunction; import java.util.function.Function; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.query.NavigablePath; import org.hibernate.query.results.Builders; @@ -89,7 +88,6 @@ public Fetch buildFetch( null, SqlAstJoinType.INNER, true, - LockMode.READ, creationStateImpl ); return tableGroupJoin.getJoinedGroup(); @@ -101,7 +99,6 @@ public Fetch buildFetch( fetchPath, FetchTiming.IMMEDIATE, true, - LockMode.READ, null, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java index fc054cf7e492..ad685a5913f5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java @@ -12,7 +12,6 @@ import java.util.function.BiFunction; import java.util.function.Function; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; @@ -23,9 +22,6 @@ import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.FetchBuilder; import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; -import org.hibernate.sql.ast.SqlAstJoinType; -import org.hibernate.sql.ast.tree.from.TableGroup; -import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; @@ -107,7 +103,6 @@ public Fetch buildFetch( fetchPath, FetchTiming.DELAYED, false, - LockMode.READ, null, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderPlural.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderPlural.java index a8ab3bacf2d9..03b1f103f8d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderPlural.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderPlural.java @@ -8,7 +8,6 @@ import java.util.function.BiFunction; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.query.NavigablePath; @@ -50,7 +49,6 @@ public Fetch buildFetch( fetchPath, FetchTiming.DELAYED, false, - LockMode.READ, null, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEmbeddable.java index f2b611aec764..ae7e60984b96 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEmbeddable.java @@ -8,7 +8,6 @@ import java.util.function.BiFunction; -import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.query.NavigablePath; import org.hibernate.query.results.DomainResultCreationStateImpl; @@ -66,7 +65,6 @@ public EmbeddableResult buildResult( null, SqlAstJoinType.INNER, true, - LockMode.READ, creationStateImpl ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEntity.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEntity.java index 4cb6d7e2a42f..e9a4858fe716 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitModelPartResultBuilderEntity.java @@ -8,7 +8,6 @@ import java.util.function.BiFunction; -import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityValuedModelPart; import org.hibernate.query.NavigablePath; @@ -60,7 +59,6 @@ public EntityResult buildResult( return modelPart.getEntityMappingType().createRootTableGroup( navigablePath, null, - LockMode.READ, () -> predicate -> { }, creationStateImpl, diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java index 4d73c29cf1ca..31c6605f9c52 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/AbstractQuery.java @@ -1184,6 +1184,8 @@ public QueryImplementor setParameter(int position, Date value, TemporalType t public T getParameterValue(Parameter param) { QueryLogging.QUERY_LOGGER.tracef( "#getParameterValue(%s)", param ); + getSession().checkOpen( false ); + final QueryParameterImplementor qp = getParameterMetadata().resolve( param ); if ( qp == null ) { throw new IllegalArgumentException( "The parameter [" + param + "] is not part of this Query" ); @@ -1204,6 +1206,8 @@ public T getParameterValue(Parameter param) { @Override public Object getParameterValue(String name) { + getSession().checkOpen( false ); + final QueryParameterImplementor parameter = getParameterMetadata().getQueryParameter( name ); if ( parameter == null ) { throw new IllegalArgumentException( "Could not resolve parameter by name - " + name ); @@ -1369,7 +1373,7 @@ public List list() { throw new IllegalArgumentException( e ); } catch (HibernateException he) { - throw getSession().getExceptionConverter().convert( he ); + throw getSession().getExceptionConverter().convert( he, getLockOptions() ); } finally { afterQuery(); @@ -1394,7 +1398,7 @@ public R getSingleResult() { } catch ( HibernateException e ) { if ( getSession().getFactory().getSessionFactoryOptions().isJpaBootstrap() ) { - throw getSession().getExceptionConverter().convert( e ); + throw getSession().getExceptionConverter().convert( e, getLockOptions() ); } else { throw e; @@ -1459,12 +1463,7 @@ public int executeUpdate() throws HibernateException { throw new IllegalArgumentException( e ); } catch ( HibernateException e) { - if ( getSession().getFactory().getSessionFactoryOptions().isJpaBootstrap() ) { - throw getSession().getExceptionConverter().convert( e ); - } - else { - throw e; - } + throw getSession().getExceptionConverter().convert( e ); } finally { afterQuery(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryInterpretationCache.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryInterpretationCache.java index b4f8c3b81176..8792538fb1d9 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryInterpretationCache.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryInterpretationCache.java @@ -21,6 +21,12 @@ @Incubating public interface QueryInterpretationCache { interface Key { + /** + * The possibility for a cache key to do defensive copying in case it has mutable state. + */ + default Key prepareForStore() { + return this; + } } int getNumberOfCachedHqlInterpretations(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/SqlOmittingQueryOptions.java b/hibernate-core/src/main/java/org/hibernate/query/spi/SqlOmittingQueryOptions.java index 311634ae06d7..78ea425b0ac3 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/SqlOmittingQueryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/SqlOmittingQueryOptions.java @@ -31,7 +31,7 @@ public static ExecutionContext omitSqlQueryOptions(ExecutionContext context) { } public static ExecutionContext omitSqlQueryOptions(ExecutionContext context, JdbcSelect select) { - return omitSqlQueryOptions( context, !select.usesLimitParameters(), true ); + return omitSqlQueryOptions( context, !select.usesLimitParameters(), false ); } public static ExecutionContext omitSqlQueryOptions(ExecutionContext context, boolean omitLimit, boolean omitLocks) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java index 20914d330a63..6e0e0d6a6182 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sql/internal/NativeQueryImpl.java @@ -51,6 +51,7 @@ import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.metamodel.model.domain.BasicDomainType; +import org.hibernate.persister.entity.Loadable; import org.hibernate.query.Limit; import org.hibernate.query.ParameterMetadata; import org.hibernate.query.Query; @@ -86,6 +87,7 @@ import org.hibernate.query.sql.spi.NonSelectInterpretationsKey; import org.hibernate.query.sql.spi.ParameterInterpretation; import org.hibernate.query.sql.spi.SelectInterpretationsKey; +import org.hibernate.sql.exec.internal.CallbackImpl; import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer; @@ -114,6 +116,7 @@ public class NativeQueryImpl private final QueryOptionsImpl queryOptions = new QueryOptionsImpl(); private Set querySpaces; + private Callback callback; private Object collectionKey; private NativeQueryInterpreter nativeQueryInterpreter; @@ -345,7 +348,17 @@ public MutableQueryOptions getQueryOptions() { @Override public Callback getCallback() { - throw new NotYetImplementedFor6Exception(); + if ( callback == null ) { + callback = new CallbackImpl(); + } + return callback; + } + + @Override + public void invokeAfterLoadActions(SharedSessionContractImplementor session, Object entity, Loadable persister) { + if ( callback != null ) { + callback.invokeAfterLoadActions( session, entity, persister ); + } } public SessionFactoryImplementor getSessionFactory() { @@ -438,6 +451,8 @@ protected void prepareForExecution() { if ( shouldFlush() ) { getSession().flush(); } + // Reset the callback before every execution + callback = null; } private boolean shouldFlush() { @@ -536,9 +551,12 @@ private SelectInterpretationsKey generateSelectInterpretationsKey(JdbcValuesMapp @SuppressWarnings("RedundantIfStatement") private static boolean isCacheable(NativeQueryImpl query) { - if ( hasLimit( query.getQueryOptions().getLimit() ) ) { - return false; - } + // todo (6.0): unless we move the limit rendering from DeferredResultSetAccess to NativeSelectQueryPlanImpl + // we don't need to consider the limit here at all because that is applied on demand. + // It certainly is better for performance to include the limit early, but then we might trash the cache +// if ( hasLimit( query.getQueryOptions().getLimit() ) ) { +// return false; +// } return true; } 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 5e569f42c128..c21e0844affc 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 @@ -85,7 +85,6 @@ import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection; import org.hibernate.query.sqm.tree.select.SqmOrderByClause; import org.hibernate.query.sqm.tree.select.SqmQueryGroup; -import org.hibernate.query.sqm.tree.select.SqmQueryPart; import org.hibernate.query.sqm.tree.select.SqmQuerySpec; import org.hibernate.query.sqm.tree.select.SqmSelectClause; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmFunctionDescriptor.java index b739384def3c..f0651e65ee41 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmFunctionDescriptor.java @@ -15,6 +15,7 @@ import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.tree.SqmTypedNode; import org.hibernate.query.sqm.tree.SqmVisitableNode; +import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.sql.ast.tree.SqlAstNode; import org.hibernate.type.spi.TypeConfiguration; @@ -120,5 +121,27 @@ protected abstract SelfRenderingSqmFunction generateSqmFunctionExpression AllowableFunctionReturnType impliedResultType, QueryEngine queryEngine, TypeConfiguration typeConfiguration); + + /** + * Return an SQM node or subtree representing an invocation of this aggregate function + * with the given arguments. This method may be overridden in the case of + * function descriptors that wish to customize creation of the node. + * + * @param arguments the arguments of the function invocation + * @param impliedResultType the function return type as inferred from its usage + */ + protected SelfRenderingSqmAggregateFunction generateSqmAggregateFunctionExpression( + List> arguments, + SqmPredicate filter, + AllowableFunctionReturnType impliedResultType, + QueryEngine queryEngine, + TypeConfiguration typeConfiguration) { + return (SelfRenderingSqmAggregateFunction) generateSqmExpression( + arguments, + impliedResultType, + queryEngine, + typeConfiguration + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java index c7d9069ca29a..94aabba09582 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/AbstractSqmSelfRenderingFunctionDescriptor.java @@ -11,9 +11,11 @@ import org.hibernate.query.sqm.produce.function.ArgumentsValidator; import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; import org.hibernate.query.sqm.tree.SqmTypedNode; +import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.type.spi.TypeConfiguration; import java.util.List; @@ -24,8 +26,16 @@ public abstract class AbstractSqmSelfRenderingFunctionDescriptor extends AbstractSqmFunctionDescriptor { + private final boolean isAggregate; + public AbstractSqmSelfRenderingFunctionDescriptor(String name, ArgumentsValidator argumentsValidator, FunctionReturnTypeResolver returnTypeResolver) { super( name, argumentsValidator, returnTypeResolver ); + this.isAggregate = false; + } + + public AbstractSqmSelfRenderingFunctionDescriptor(String name, boolean isAggregate, ArgumentsValidator argumentsValidator, FunctionReturnTypeResolver returnTypeResolver) { + super( name, argumentsValidator, returnTypeResolver ); + this.isAggregate = isAggregate; } @Override @@ -34,6 +44,9 @@ protected SelfRenderingSqmFunction generateSqmFunctionExpression( AllowableFunctionReturnType impliedResultType, QueryEngine queryEngine, TypeConfiguration typeConfiguration) { + if ( isAggregate ) { + return generateAggregateSqmExpression( arguments, null, impliedResultType, queryEngine, typeConfiguration ); + } return new SelfRenderingSqmFunction<>( this, this::render, @@ -45,6 +58,28 @@ protected SelfRenderingSqmFunction generateSqmFunctionExpression( ); } + @Override + public SelfRenderingSqmFunction generateAggregateSqmExpression( + List> arguments, + SqmPredicate filter, + AllowableFunctionReturnType impliedResultType, + QueryEngine queryEngine, + TypeConfiguration typeConfiguration) { + if ( !isAggregate ) { + throw new UnsupportedOperationException( "The function " + getName() + " is not an aggregate function!" ); + } + return new SelfRenderingSqmAggregateFunction<>( + this, + this::render, + arguments, + filter, + impliedResultType, + getReturnTypeResolver(), + queryEngine.getCriteriaBuilder(), + getName() + ); + } + /** * Must be overridden by subclasses */ @@ -53,4 +88,12 @@ public abstract void render( List sqlAstArguments, SqlAstTranslator walker); + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + Predicate filter, + SqlAstTranslator walker) { + render( sqlAppender, sqlAstArguments, walker ); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderingSupport.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderingSupport.java index c28970d0880d..5e22200789ae 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderingSupport.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/FunctionRenderingSupport.java @@ -10,6 +10,7 @@ import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.predicate.Predicate; import java.util.List; @@ -29,4 +30,13 @@ void render( SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker); + + default void render( + SqlAppender sqlAppender, + List sqlAstArguments, + Predicate filter, + SqlAstTranslator walker) { + // Ignore the filter by default. Subclasses will override this + render( sqlAppender, sqlAstArguments, walker ); + } } 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 5697e343acf2..acf1c7cc7d19 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 @@ -12,6 +12,9 @@ import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.expression.Distinct; +import org.hibernate.sql.ast.tree.expression.Star; +import org.hibernate.sql.ast.tree.predicate.Predicate; import java.util.List; import java.util.Locale; @@ -43,6 +46,7 @@ public NamedSqmFunctionDescriptor( argumentsValidator, returnTypeResolver, functionName, + false, null, SqlAstNodeRenderingMode.DEFAULT ); @@ -54,9 +58,10 @@ public NamedSqmFunctionDescriptor( ArgumentsValidator argumentsValidator, FunctionReturnTypeResolver returnTypeResolver, String name, + boolean isAggregate, String argumentListSignature, SqlAstNodeRenderingMode argumentRenderingMode) { - super( name, argumentsValidator, returnTypeResolver ); + super( name, isAggregate, argumentsValidator, returnTypeResolver ); this.functionName = functionName; this.useParenthesesWhenNoArgs = useParenthesesWhenNoArgs; @@ -75,7 +80,7 @@ public String getName() { @Override public String getArgumentListSignature() { - return argumentListSignature==null ? super.getArgumentListSignature() : argumentListSignature; + return argumentListSignature == null ? super.getArgumentListSignature() : argumentListSignature; } @Override @@ -87,8 +92,18 @@ public boolean alwaysIncludesParentheses() { public void render( SqlAppender sqlAppender, List sqlAstArguments, - SqlAstTranslator walker) { + SqlAstTranslator translator) { + render( sqlAppender, sqlAstArguments, null, translator ); + } + + @Override + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + Predicate filter, + SqlAstTranslator translator) { final boolean useParens = useParenthesesWhenNoArgs || !sqlAstArguments.isEmpty(); + final boolean caseWrapper = filter != null && !translator.supportsFilterClause(); sqlAppender.appendSql( functionName ); if ( useParens ) { @@ -96,17 +111,32 @@ public void render( } boolean firstPass = true; - for ( SqlAstNode sqlAstArgument : sqlAstArguments ) { + for ( SqlAstNode arg : sqlAstArguments ) { if ( !firstPass ) { sqlAppender.appendSql( ", " ); } - walker.render( sqlAstArgument, argumentRenderingMode ); + if ( caseWrapper && !( arg instanceof Distinct ) && !( arg instanceof Star ) ) { + sqlAppender.appendSql( "case when " ); + filter.accept( translator ); + sqlAppender.appendSql( " then " ); + translator.render( arg, argumentRenderingMode ); + sqlAppender.appendSql( " else null end" ); + } + else { + translator.render( arg, argumentRenderingMode ); + } firstPass = false; } if ( useParens ) { sqlAppender.appendSql( ")" ); } + + if ( filter != null && !caseWrapper ) { + sqlAppender.appendSql( " filter (where " ); + filter.accept( translator ); + sqlAppender.appendSql( ')' ); + } } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/PatternBasedSqmFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/PatternBasedSqmFunctionDescriptor.java index f13d8f060941..161144b3c5de 100755 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/PatternBasedSqmFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/PatternBasedSqmFunctionDescriptor.java @@ -13,6 +13,7 @@ import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.predicate.Predicate; import java.util.List; @@ -47,9 +48,11 @@ public PatternBasedSqmFunctionDescriptor( ArgumentsValidator argumentsValidator, FunctionReturnTypeResolver returnTypeResolver, String name, + boolean isAggregate, String argumentListSignature) { super( name, + isAggregate, argumentsValidator != null ? argumentsValidator // If no validator is given, it's still better to @@ -70,11 +73,16 @@ public void render( SqlAppender sqlAppender, List sqlAstArguments, SqlAstTranslator walker) { - renderer.render( sqlAppender, sqlAstArguments, walker ); + renderer.render( sqlAppender, sqlAstArguments, null, walker ); + } + + @Override + public void render(SqlAppender sqlAppender, List sqlAstArguments, Predicate filter, SqlAstTranslator walker) { + renderer.render( sqlAppender, sqlAstArguments, filter, walker ); } @Override public String getArgumentListSignature() { - return argumentListSignature==null ? super.getArgumentListSignature() : argumentListSignature; + return argumentListSignature == null ? super.getArgumentListSignature() : argumentListSignature; } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingAggregateFunctionSqlAstExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingAggregateFunctionSqlAstExpression.java new file mode 100644 index 000000000000..be31e403ef39 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingAggregateFunctionSqlAstExpression.java @@ -0,0 +1,54 @@ +/* + * 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.function; + +import java.util.List; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.mapping.JdbcMappingContainer; +import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.spi.SqlAppender; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.expression.AggregateFunctionExpression; +import org.hibernate.sql.ast.tree.predicate.Predicate; + +/** + * Representation of an aggregate function call in the SQL AST for impls that know how to + * render themselves. + * + * @author Christian Beikov + */ +public class SelfRenderingAggregateFunctionSqlAstExpression extends SelfRenderingFunctionSqlAstExpression + implements AggregateFunctionExpression { + + private final Predicate filter; + + public SelfRenderingAggregateFunctionSqlAstExpression( + String functionName, + FunctionRenderingSupport renderer, + List sqlAstArguments, + Predicate filter, + AllowableFunctionReturnType type, + JdbcMappingContainer expressable) { + super( functionName, renderer, sqlAstArguments, type, expressable ); + this.filter = filter; + } + + @Override + public Predicate getFilter() { + return filter; + } + + @Override + public void renderToSql( + SqlAppender sqlAppender, + SqlAstTranslator walker, + SessionFactoryImplementor sessionFactory) { + getRenderer().render( sqlAppender, getArguments(), filter, walker ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java index 0696f9ac235f..d75a2fad0b2c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingFunctionSqlAstExpression.java @@ -77,6 +77,10 @@ public JdbcMappingContainer getExpressionType() { return expressable; } + protected FunctionRenderingSupport getRenderer() { + return renderer; + } + @Override public SqlSelection createSqlSelection( int jdbcPosition, 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 new file mode 100644 index 000000000000..8ecb401c9961 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java @@ -0,0 +1,54 @@ +/* + * 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.function; + +import java.util.List; + +import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; +import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.produce.function.FunctionReturnTypeResolver; +import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; +import org.hibernate.query.sqm.tree.SqmTypedNode; +import org.hibernate.query.sqm.tree.predicate.SqmPredicate; +import org.hibernate.sql.ast.tree.predicate.Predicate; + +/** + * @author Christian Beikov + */ +public class SelfRenderingSqmAggregateFunction extends SelfRenderingSqmFunction { + + private final SqmPredicate filter; + + public SelfRenderingSqmAggregateFunction( + SqmFunctionDescriptor descriptor, + FunctionRenderingSupport renderingSupport, + List> arguments, + SqmPredicate filter, + AllowableFunctionReturnType impliedResultType, + FunctionReturnTypeResolver returnTypeResolver, + NodeBuilder nodeBuilder, + String name) { + super( descriptor, renderingSupport, arguments, impliedResultType, returnTypeResolver, nodeBuilder, name ); + this.filter = filter; + } + + @Override + public SelfRenderingFunctionSqlAstExpression convertToSqlAst(SqmToSqlAstConverter walker) { + final AllowableFunctionReturnType resultType = resolveResultType( + walker.getCreationContext().getDomainModel().getTypeConfiguration() + ); + + return new SelfRenderingAggregateFunctionSqlAstExpression( + getFunctionName(), + getRenderingSupport(), + resolveSqlAstArguments( getArguments(), walker ), + filter == null ? null : (Predicate) filter.accept( walker ), + resultType, + getMappingModelExpressable( walker, resultType ) + ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionDescriptor.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionDescriptor.java index 15aa7737328f..fefb382ee613 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionDescriptor.java @@ -9,6 +9,7 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.sqm.tree.SqmTypedNode; +import org.hibernate.query.sqm.tree.predicate.SqmPredicate; import org.hibernate.type.spi.TypeConfiguration; import java.util.List; @@ -45,6 +46,19 @@ SelfRenderingSqmFunction generateSqmExpression( QueryEngine queryEngine, TypeConfiguration typeConfiguration); + /** + * Like {@link #generateSqmExpression(List, AllowableFunctionReturnType, QueryEngine, TypeConfiguration)} + * but also accepts a filter predicate. This method is intended for aggregate functions. + */ + default SelfRenderingSqmFunction generateAggregateSqmExpression( + List> arguments, + SqmPredicate filter, + AllowableFunctionReturnType impliedResultType, + QueryEngine queryEngine, + TypeConfiguration typeConfiguration) { + throw new UnsupportedOperationException( "Not an aggregate function!" ); + } + /** * Convenience for single argument */ diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionRegistry.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionRegistry.java index 4c97c2de947d..192f979b575d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/function/SqmFunctionRegistry.java @@ -112,7 +112,19 @@ public SqmFunctionDescriptor registerPattern(String name, String pattern, BasicT * @return The builder */ public PatternFunctionDescriptorBuilder patternDescriptorBuilder(String registrationKey, String pattern) { - return new PatternFunctionDescriptorBuilder( this, registrationKey, pattern ); + return new PatternFunctionDescriptorBuilder( this, registrationKey, false, pattern ); + } + + /** + * Get a builder for creating and registering a pattern-based aggregate function descriptor. + * + * @param registrationKey The name under which the descriptor will get registered + * @param pattern The pattern defining the the underlying function call + * + * @return The builder + */ + public PatternFunctionDescriptorBuilder patternAggregateDescriptorBuilder(String registrationKey, String pattern) { + return new PatternFunctionDescriptorBuilder( this, registrationKey, true, pattern ); } /** @@ -150,6 +162,19 @@ public NamedFunctionDescriptorBuilder namedDescriptorBuilder(String name) { return namedDescriptorBuilder( name, name ); } + /** + * Get a builder for creating and registering a name-based aggregate function descriptor + * using the passed name as both the registration key and underlying SQL + * function name + * + * @param name The function name (and registration key) + * + * @return The builder + */ + public NamedFunctionDescriptorBuilder namedAggregateDescriptorBuilder(String name) { + return namedAggregateDescriptorBuilder( name, name ); + } + /** * Get a builder for creating and registering a name-based function descriptor. * @@ -159,7 +184,19 @@ public NamedFunctionDescriptorBuilder namedDescriptorBuilder(String name) { * @return The builder */ public NamedFunctionDescriptorBuilder namedDescriptorBuilder(String registrationKey, String name) { - return new NamedFunctionDescriptorBuilder( this, registrationKey, name ); + return new NamedFunctionDescriptorBuilder( this, registrationKey, false, name ); + } + + /** + * Get a builder for creating and registering a name-based aggregate function descriptor. + * + * @param registrationKey The name under which the descriptor will get registered + * @param name The underlying SQL function name to use + * + * @return The builder + */ + public NamedFunctionDescriptorBuilder namedAggregateDescriptorBuilder(String registrationKey, String name) { + return new NamedFunctionDescriptorBuilder( this, registrationKey, true, name ); } public NamedFunctionDescriptorBuilder noArgsBuilder(String name) { 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 fa83636bcc11..9fe09a00581a 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 @@ -63,6 +63,8 @@ public class ConcreteSqmSelectQueryPlan implements SelectQueryPlan { private final SqmInterpreter, Void> listInterpreter; private final SqmInterpreter, ScrollMode> scrollInterpreter; + private volatile CacheableSqmInterpretation cacheableSqmInterpretation; + @SuppressWarnings("WeakerAccess") public ConcreteSqmSelectQueryPlan( SqmSelectStatement sqm, @@ -195,8 +197,6 @@ public ScrollableResultsImplementor performScroll(ScrollMode scrollMode, Exec return withCacheableSqmInterpretation( executionContext, scrollMode, scrollInterpreter ); } - private volatile CacheableSqmInterpretation cacheableSqmInterpretation; - private T withCacheableSqmInterpretation(ExecutionContext executionContext, X context, SqmInterpreter interpreter) { // NOTE : VERY IMPORTANT - intentional double-lock checking // The other option would be to leverage `java.util.concurrent.locks.ReadWriteLock` @@ -227,6 +227,8 @@ private T withCacheableSqmInterpretation(ExecutionContext executionContex if ( localCopy.jdbcSelect.dependsOnParameterBindings() ) { jdbcParameterBindings = createJdbcParameterBindings( localCopy, executionContext ); } + // If the translation depends on the limit or lock options, we have to rebuild the JdbcSelect + // We could avoid this by putting the lock options into the cache key if ( !localCopy.jdbcSelect.isCompatibleWith( jdbcParameterBindings, executionContext.getQueryOptions() ) ) { localCopy = buildCacheableSqmInterpretation( sqm, 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 0b5e10566fdb..f40f466b09ea 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 @@ -31,6 +31,7 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.collections.IdentitySet; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.entity.Loadable; import org.hibernate.query.Query; import org.hibernate.query.QueryTypeMismatchException; import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl; @@ -69,6 +70,7 @@ import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.query.sqm.tree.select.SqmSelection; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; +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; @@ -98,6 +100,7 @@ public class QuerySqmImpl private final QueryParameterBindingsImpl parameterBindings; private final QueryOptionsImpl queryOptions = new QueryOptionsImpl(); + private Callback callback; /** * Creates a Query instance from a named HQL memento @@ -145,10 +148,6 @@ protected void applyOptions(NamedHqlQueryMemento memento) { setMaxResults( memento.getMaxResults() ); } - if ( memento.getLockOptions() != null ) { - setLockOptions( memento.getLockOptions() ); - } - if ( memento.getParameterTypes() != null ) { for ( Map.Entry entry : memento.getParameterTypes().entrySet() ) { final QueryParameterImplementor parameter = parameterMetadata.getQueryParameter( entry.getKey() ); @@ -400,6 +399,7 @@ public QueryParameterBindings getQueryParameterBindings() { @Override public Set> getParameters() { + getSession().checkOpen( false ); Set> parameters = new HashSet<>(); parameterMetadata.collectAllParameters( parameters::add ); return parameters; @@ -712,11 +712,27 @@ private NonSelectQueryPlan buildInsertQueryPlan() { // } } + @Override + protected void prepareForExecution() { + super.prepareForExecution(); + // Reset the callback before every execution + callback = null; + } + @Override public Callback getCallback() { - return afterLoadAction -> {}; + if ( callback == null ) { + callback = new CallbackImpl(); + } + return callback; } + @Override + public void invokeAfterLoadActions(SharedSessionContractImplementor session, Object entity, Loadable persister) { + if ( callback != null ) { + callback.invokeAfterLoadActions( session, entity, persister ); + } + } @Override public NamedHqlQueryMemento toMemento(String name) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmInterpretationsKey.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmInterpretationsKey.java index 8a77bad1f70f..988d7512bd42 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmInterpretationsKey.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmInterpretationsKey.java @@ -6,13 +6,10 @@ */ package org.hibernate.query.sqm.internal; -import org.hibernate.LockMode; import org.hibernate.LockOptions; -import org.hibernate.query.Limit; import org.hibernate.query.QueryParameter; import org.hibernate.query.ResultListTransformer; import org.hibernate.query.TupleTransformer; -import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryInterpretationCache; /** @@ -20,7 +17,7 @@ */ public class SqmInterpretationsKey implements QueryInterpretationCache.Key { @SuppressWarnings("WeakerAccess") - public static SqmInterpretationsKey generateFrom(QuerySqmImpl query) { + public static SqmInterpretationsKey generateFrom(QuerySqmImpl query) { if ( ! isCacheable( query ) ) { return null; } @@ -28,12 +25,14 @@ public static SqmInterpretationsKey generateFrom(QuerySqmImpl query) { return new SqmInterpretationsKey( query.getQueryString(), query.getResultType(), - query.getQueryOptions() + query.getLockOptions(), + query.getQueryOptions().getTupleTransformer(), + query.getQueryOptions().getResultListTransformer() ); } @SuppressWarnings("WeakerAccess") - public static QueryInterpretationCache.Key generateNonSelectKey(QuerySqmImpl query) { + public static QueryInterpretationCache.Key generateNonSelectKey(QuerySqmImpl query) { // todo (6.0) : do we want to cache non-select plans? If so, what requirements? // - very minimum is that it be a "simple" (non-multi-table) statement // @@ -73,37 +72,38 @@ private static boolean isCacheable(QuerySqmImpl query) { return false; } - if ( definesLocking( query.getQueryOptions().getLockOptions() ) ) { - // cannot cache query plans if it defines locking - return false; - } - return true; } - private static boolean hasLimit(Limit limit) { - return limit.getFirstRow() != null || limit.getMaxRows() != null; - } - - private static boolean definesLocking(LockOptions lockOptions) { - final LockMode mostRestrictiveLockMode = lockOptions.findGreatestLockMode(); - return mostRestrictiveLockMode.greaterThan( LockMode.READ ); - } - - private final String query; - private final Class resultType; - private final TupleTransformer tupleTransformer; + private final Class resultType; + private final LockOptions lockOptions; + private final TupleTransformer tupleTransformer; private final ResultListTransformer resultListTransformer; private SqmInterpretationsKey( String query, - Class resultType, - QueryOptions queryOptions) { + Class resultType, + LockOptions lockOptions, + TupleTransformer tupleTransformer, + ResultListTransformer resultListTransformer) { this.query = query; this.resultType = resultType; - this.tupleTransformer = queryOptions.getTupleTransformer(); - this.resultListTransformer = queryOptions.getResultListTransformer(); + this.lockOptions = lockOptions; + this.tupleTransformer = tupleTransformer; + this.resultListTransformer = resultListTransformer; + } + + @Override + public QueryInterpretationCache.Key prepareForStore() { + return new SqmInterpretationsKey( + query, + resultType, + // Since lock options are mutable, we need a copy for the cache key + lockOptions.makeCopy(), + tupleTransformer, + resultListTransformer + ); } @Override @@ -118,6 +118,7 @@ public boolean equals(Object o) { final SqmInterpretationsKey that = (SqmInterpretationsKey) o; return query.equals( that.query ) && areEqual( resultType, that.resultType ) + && areEqual( lockOptions, that.lockOptions ) && areEqual( tupleTransformer, that.tupleTransformer ) && areEqual( resultListTransformer, that.resultListTransformer ); } @@ -135,6 +136,7 @@ private boolean areEqual(T o1, T o2) { public int hashCode() { int result = query.hashCode(); result = 31 * result + ( resultType != null ? resultType.hashCode() : 0 ); + result = 31 * result + ( lockOptions != null ? lockOptions.hashCode() : 0 ); result = 31 * result + ( tupleTransformer != null ? tupleTransformer.hashCode() : 0 ); result = 31 * result + ( resultListTransformer != null ? resultListTransformer.hashCode() : 0 ); return result; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java index 11c293d72cfe..261c1b181243 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java @@ -12,6 +12,9 @@ import java.util.List; import java.util.Map; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.FilterHelper; @@ -23,6 +26,7 @@ import org.hibernate.query.sqm.internal.SqmUtil; import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement; import org.hibernate.query.sqm.tree.expression.SqmParameter; +import org.hibernate.sql.ast.SqlAstJoinType; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAstTreeHelper; import org.hibernate.sql.ast.spi.SqlExpressionResolver; @@ -65,6 +69,7 @@ public class MatchingIdSelectionHelper { public static SelectStatement generateMatchingIdSelectStatement( EntityMappingType targetEntityDescriptor, SqmDeleteOrUpdateStatement sqmStatement, + boolean queryRoot, Predicate restriction, MultiTableSqmMutationConverter sqmConverter, ExecutionContext executionContext, @@ -77,7 +82,7 @@ public static SelectStatement generateMatchingIdSelectStatement( ); } - final QuerySpec idSelectionQuery = new QuerySpec( true, 1 ); + final QuerySpec idSelectionQuery = new QuerySpec( queryRoot, 1 ); final TableGroup mutatingTableGroup = sqmConverter.getMutatingTableGroup(); idSelectionQuery.getFromClause().addRoot( mutatingTableGroup ); @@ -224,6 +229,7 @@ public static List selectMatchingIds( final SelectStatement matchingIdSelection = generateMatchingIdSelectStatement( entityDescriptor, sqmMutationStatement, + true, restriction, sqmConverter, executionContext, @@ -231,7 +237,8 @@ public static List selectMatchingIds( ); final JdbcServices jdbcServices = factory.getJdbcServices(); - final SqlAstTranslator sqlAstSelectTranslator = jdbcServices.getJdbcEnvironment() + final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment(); + final SqlAstTranslator sqlAstSelectTranslator = jdbcEnvironment .getSqlAstTranslatorFactory() .buildSelectTranslator( factory, matchingIdSelection ); @@ -244,10 +251,25 @@ public static List selectMatchingIds( sqmConverter.getSqmParameterMappingModelExpressableResolutions()::get, executionContext.getSession() ); + final LockOptions lockOptions = executionContext.getQueryOptions().getLockOptions(); + final LockMode lockMode = lockOptions.getLockMode(); + // Acquire a WRITE lock for the rows that are about to be modified + lockOptions.setLockMode( LockMode.WRITE ); + // Visit the table joins and reset the lock mode if we encounter OUTER joins that are not supported + if ( !jdbcEnvironment.getDialect().supportsOuterJoinForUpdate() ) { + matchingIdSelection.getQuerySpec().getFromClause().visitTableJoins( + tableJoin -> { + if ( tableJoin.getJoinType() != SqlAstJoinType.INNER ) { + lockOptions.setLockMode( lockMode ); + } + } + ); + } final JdbcSelect idSelectJdbcOperation = sqlAstSelectTranslator.translate( jdbcParameterBindings, executionContext.getQueryOptions() ); + lockOptions.setLockMode( lockMode ); return jdbcServices.getJdbcSelectExecutor().list( idSelectJdbcOperation, 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 35a2077f6b4d..f02a2e91f79a 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 @@ -7,11 +7,9 @@ package org.hibernate.query.sqm.mutation.internal; import java.util.List; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; -import org.hibernate.LockMode; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.internal.util.collections.Stack; import org.hibernate.metamodel.mapping.EntityMappingType; @@ -71,6 +69,27 @@ public MultiTableSqmMutationConverter( LoadQueryInfluencers loadQueryInfluencers, QueryParameterBindings domainParameterBindings, SqlAstCreationContext creationContext) { + this( + mutatingEntityDescriptor, + mutatingEntityExplicitAlias, + mutatingEntityExplicitAlias, + domainParameterXref, + queryOptions, + loadQueryInfluencers, + domainParameterBindings, + creationContext + ); + } + + public MultiTableSqmMutationConverter( + EntityMappingType mutatingEntityDescriptor, + String mutatingEntityExplicitAlias, + String sourceAlias, + DomainParameterXref domainParameterXref, + QueryOptions queryOptions, + LoadQueryInfluencers loadQueryInfluencers, + QueryParameterBindings domainParameterBindings, + SqlAstCreationContext creationContext) { super( creationContext, null, queryOptions, loadQueryInfluencers, domainParameterXref, domainParameterBindings ); this.mutatingEntityDescriptor = mutatingEntityDescriptor; @@ -85,8 +104,7 @@ public MultiTableSqmMutationConverter( final NavigablePath navigablePath = new NavigablePath( mutatingEntityDescriptor.getEntityName(), mutatingEntityExplicitAlias ); this.mutatingTableGroup = mutatingEntityDescriptor.createRootTableGroup( navigablePath, - mutatingEntityExplicitAlias, - LockMode.PESSIMISTIC_WRITE, + sourceAlias, () -> predicate -> { }, 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 a237e9cb53c0..2577432b95e6 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 @@ -13,6 +13,8 @@ import java.util.List; import java.util.Map; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.EntityMappingType; @@ -34,6 +36,7 @@ import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.tree.cte.CteColumn; import org.hibernate.sql.ast.tree.cte.CteContainer; +import org.hibernate.sql.ast.tree.cte.CteMaterialization; import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.cte.CteTableGroup; import org.hibernate.sql.ast.tree.expression.ColumnReference; @@ -101,10 +104,19 @@ public int execute(ExecutionContext executionContext) { final SqmDeleteOrUpdateStatement sqmMutationStatement = getSqmDeleteOrUpdateStatement(); final SessionFactoryImplementor factory = executionContext.getSession().getFactory(); final EntityMappingType entityDescriptor = getEntityDescriptor(); + final String explicitDmlTargetAlias; + // We need an alias because we try to acquire a WRITE lock for these rows in the CTE + if ( sqmMutationStatement.getTarget().getExplicitAlias() == null ) { + explicitDmlTargetAlias = "dml_target"; + } + else { + explicitDmlTargetAlias = sqmMutationStatement.getTarget().getExplicitAlias(); + } final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter( entityDescriptor, sqmMutationStatement.getTarget().getExplicitAlias(), + explicitDmlTargetAlias, domainParameterXref, executionContext.getQueryOptions(), executionContext.getLoadQueryInfluencers(), @@ -132,11 +144,14 @@ public int execute(ExecutionContext executionContext) { MatchingIdSelectionHelper.generateMatchingIdSelectStatement( entityDescriptor, sqmMutationStatement, + false, restriction, sqmConverter, executionContext, factory - ) + ), + // The id-select cte will be reused multiple times + CteMaterialization.MATERIALIZED ); // Create the main query spec that will return the count of @@ -181,7 +196,12 @@ public int execute(ExecutionContext executionContext) { paramTypeResolutions::get, executionContext.getSession() ); + final LockOptions lockOptions = executionContext.getQueryOptions().getLockOptions(); + final LockMode lockMode = lockOptions.getAliasSpecificLockMode( explicitDmlTargetAlias ); + // Acquire a WRITE lock for the rows that are about to be modified + lockOptions.setAliasSpecificLockMode( explicitDmlTargetAlias, LockMode.WRITE ); final JdbcSelect select = translator.translate( jdbcParameterBindings, executionContext.getQueryOptions() ); + lockOptions.setAliasSpecificLockMode( explicitDmlTargetAlias, lockMode ); List list = jdbcServices.getJdbcSelectExecutor().list( select, jdbcParameterBindings, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithIdTableHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithIdTableHelper.java index d3d0b39ab666..f99d24418810 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithIdTableHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithIdTableHelper.java @@ -10,6 +10,7 @@ import java.util.function.Supplier; import org.hibernate.LockMode; +import org.hibernate.LockOptions; import org.hibernate.boot.TempTableDdlTransactionHandling; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; @@ -21,6 +22,7 @@ import org.hibernate.query.NavigablePath; import org.hibernate.query.spi.SqlOmittingQueryOptions; import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter; +import org.hibernate.sql.ast.SqlAstJoinType; import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.tree.expression.ColumnReference; @@ -127,8 +129,23 @@ public static int saveMatchingIdsIntoIdTable( final JdbcServices jdbcServices = factory.getJdbcServices(); final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment(); final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory(); + final LockOptions lockOptions = executionContext.getQueryOptions().getLockOptions(); + final LockMode lockMode = lockOptions.getLockMode(); + // Acquire a WRITE lock for the rows that are about to be modified + lockOptions.setLockMode( LockMode.WRITE ); + // Visit the table joins and reset the lock mode if we encounter OUTER joins that are not supported + if ( !jdbcEnvironment.getDialect().supportsOuterJoinForUpdate() ) { + matchingIdSelection.getFromClause().visitTableJoins( + tableJoin -> { + if ( tableJoin.getJoinType() != SqlAstJoinType.INNER ) { + lockOptions.setLockMode( lockMode ); + } + } + ); + } final JdbcInsert jdbcInsert = sqlAstTranslatorFactory.buildInsertTranslator( factory, idTableInsert ) .translate( jdbcParameterBindings, executionContext.getQueryOptions() ); + lockOptions.setLockMode( lockMode ); return jdbcServices.getJdbcMutationExecutor().execute( jdbcInsert, @@ -158,7 +175,7 @@ public static QuerySpec createIdTableSelectQuerySpec( final TableGroup idTableGroup = new StandardTableGroup( new NavigablePath( idTableReference.getTableExpression() ), entityDescriptor, - LockMode.NONE, + null, idTableReference, null, executionContext.getSession().getFactory() @@ -182,7 +199,7 @@ private static void applyIdTableSelections( if ( idTableColumn != idTable.getSessionUidColumn() ) { querySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( - i+1, + i + 1, i, new ColumnReference( tableReference, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithoutIdTableHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithoutIdTableHelper.java index 2f2f81807671..f8f53d038dee 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithoutIdTableHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/ExecuteWithoutIdTableHelper.java @@ -41,7 +41,7 @@ public static QuerySpec createIdMatchingSubQuerySpec( final StandardTableGroup matchingIdSelectTableGroup = new StandardTableGroup( navigablePath, rootEntityPersister, - LockMode.PESSIMISTIC_WRITE, + rootTableReference.getIdentificationVariable(), rootTableReference, null, sessionFactory diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/DisjunctionRestrictionProducer.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/DisjunctionRestrictionProducer.java deleted file mode 100644 index 0ad6e4a792ec..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/DisjunctionRestrictionProducer.java +++ /dev/null @@ -1,128 +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.mutation.internal.inline; - -import java.util.ArrayList; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.mapping.BasicValuedModelPart; -import org.hibernate.metamodel.mapping.SelectableConsumer; -import org.hibernate.metamodel.mapping.EntityIdentifierMapping; -import org.hibernate.metamodel.mapping.EntityMappingType; -import org.hibernate.metamodel.mapping.JdbcMapping; -import org.hibernate.query.ComparisonOperator; -import org.hibernate.sql.ast.tree.expression.ColumnReference; -import org.hibernate.sql.ast.tree.expression.JdbcLiteral; -import org.hibernate.sql.ast.tree.from.TableReference; -import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; -import org.hibernate.sql.ast.tree.predicate.Junction; -import org.hibernate.sql.exec.spi.ExecutionContext; - -/** - * MatchingIdRestrictionProducer producing a restriction based on a disjunction (OR) predicate. E.g.: - * - * ```` - * delete - * from - * entity-table - * where - * ( id = 1 ) - * or ( id = 2 ) - * or ( id = 3 ) - * or ( id = 4 ) - * ```` - * - * @author Steve Ebersole - */ -public class DisjunctionRestrictionProducer implements MatchingIdRestrictionProducer { - @Override - public Junction produceRestriction( - List matchingIdValues, - EntityMappingType entityDescriptor, - TableReference mutatingTableReference, - Supplier> columnsToMatchVisitationSupplier, - ExecutionContext executionContext) { - assert matchingIdValues != null; - assert ! matchingIdValues.isEmpty(); - - final SessionFactoryImplementor sessionFactory = executionContext.getSession().getFactory(); - - final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping(); - final int idColumnCount = identifierMapping.getJdbcTypeCount(); - assert idColumnCount > 0; - - final Junction predicate = new Junction( Junction.Nature.DISJUNCTION ); - - if ( idColumnCount == 1 ) { - final BasicValuedModelPart basicIdMapping = (BasicValuedModelPart) identifierMapping; - final String idColumn = basicIdMapping.getSelectionExpression(); - final ColumnReference idColumnReference = new ColumnReference( - mutatingTableReference, - idColumn, - // id columns cannot be formulas and cannot have custom read and write expressions - false, - null, - null, - basicIdMapping.getJdbcMapping(), - sessionFactory - ); - - matchingIdValues.forEach( - matchingId -> predicate.add( - new ComparisonPredicate( - idColumnReference, - ComparisonOperator.EQUAL, - new JdbcLiteral<>( matchingId, basicIdMapping.getJdbcMapping() ) - ) - ) - ); - } - else { - final List columnReferences = new ArrayList<>( idColumnCount ); - final List jdbcMappings = new ArrayList<>( idColumnCount ); - identifierMapping.forEachSelectable( - (columnIndex, selection) -> { - columnReferences.add( - new ColumnReference( - mutatingTableReference, - selection, - sessionFactory - ) - ); - jdbcMappings.add( selection.getJdbcMapping() ); - } - ); - - matchingIdValues.forEach( - matchingId -> { - final Junction idMatch = new Junction( Junction.Nature.CONJUNCTION ); - - assert matchingId instanceof Object[]; - - final Object[] matchingIdParts = (Object[]) matchingId; - - for ( int p = 0; p < matchingIdParts.length; p++ ) { - idMatch.add( - new ComparisonPredicate( - columnReferences.get( p ), - ComparisonOperator.EQUAL, - new JdbcLiteral<>( matchingIdParts[ p ], jdbcMappings.get( p ) ) - ) - ); - } - - predicate.add( idMatch ); - } - ); - } - - return predicate; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/InlineStrategy.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/InlineStrategy.java index 92c22132a6b4..be3528af5b96 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/InlineStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/InlineStrategy.java @@ -34,7 +34,7 @@ public InlineStrategy(Dialect dialect) { } private static Function determinePredicateProducer(Dialect dialect) { - throw new NotYetImplementedFor6Exception(); + return statement -> new InPredicateRestrictionProducer(); } public InlineStrategy(Function matchingIdsStrategy) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/TableValueConstructorRestrictionProducer.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/TableValueConstructorRestrictionProducer.java deleted file mode 100644 index 2e5c79540ea5..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/inline/TableValueConstructorRestrictionProducer.java +++ /dev/null @@ -1,57 +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.mutation.internal.inline; - -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Supplier; - -import org.hibernate.NotYetImplementedFor6Exception; -import org.hibernate.metamodel.mapping.SelectableConsumer; -import org.hibernate.metamodel.mapping.EntityMappingType; -import org.hibernate.sql.ast.tree.from.TableReference; -import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; -import org.hibernate.sql.exec.spi.ExecutionContext; - -/** - * MatchingIdRestrictionProducer producing a restriction based on a SQL table-value-constructor. E.g.: - * - * ```` - * delete - * from - * entity-table - * where - * ( id ) in ( - * select - * id - * from ( - * values - * ( 1 ), - * ( 2 ), - * ( 3 ), - * ( 4 ) - * ) as HT (id) - * ) - * ```` - * - * @author Vlad Mihalcea - * @author Steve Ebersole - */ -@SuppressWarnings("unused") -public class TableValueConstructorRestrictionProducer implements MatchingIdRestrictionProducer { - @Override - public InSubQueryPredicate produceRestriction( - List matchingIdValues, - EntityMappingType entityDescriptor, - TableReference mutatingTableReference, - Supplier> columnsToMatchVisitationSupplier, - ExecutionContext executionContext) { - // Not "yet" implemented. Not sure we will. This requires the ability to define - // "in-line views" with a table-ctor which the SQL AST does not yet define support for - throw new NotYetImplementedFor6Exception( getClass() ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/NamedFunctionDescriptorBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/NamedFunctionDescriptorBuilder.java index 637fd374905d..c683265c062f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/NamedFunctionDescriptorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/NamedFunctionDescriptorBuilder.java @@ -19,6 +19,7 @@ public class NamedFunctionDescriptorBuilder { private final SqmFunctionRegistry registry; private final String registrationKey; + private final boolean isAggregate; private final String functionName; @@ -29,9 +30,14 @@ public class NamedFunctionDescriptorBuilder { private String argumentListSignature; private SqlAstNodeRenderingMode argumentRenderingMode = SqlAstNodeRenderingMode.DEFAULT; - public NamedFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, String functionName) { + public NamedFunctionDescriptorBuilder( + SqmFunctionRegistry registry, + String registrationKey, + boolean isAggregate, + String functionName) { this.registry = registry; this.registrationKey = registrationKey; + this.isAggregate = isAggregate; this.functionName = functionName; } @@ -88,6 +94,7 @@ public SqmFunctionDescriptor descriptor() { argumentsValidator, returnTypeResolver, registrationKey, + isAggregate, argumentListSignature, argumentRenderingMode ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/PatternFunctionDescriptorBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/PatternFunctionDescriptorBuilder.java index f277b2a69e42..4b4884b3dc1a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/PatternFunctionDescriptorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/PatternFunctionDescriptorBuilder.java @@ -19,6 +19,7 @@ public class PatternFunctionDescriptorBuilder { private final SqmFunctionRegistry registry; private final String registrationKey; + private final boolean isAggregate; private final String pattern; private String argumentListSignature; @@ -26,9 +27,10 @@ public class PatternFunctionDescriptorBuilder { private FunctionReturnTypeResolver returnTypeResolver; private SqlAstNodeRenderingMode argumentRenderingMode = SqlAstNodeRenderingMode.DEFAULT; - public PatternFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, String pattern) { + public PatternFunctionDescriptorBuilder(SqmFunctionRegistry registry, String registrationKey, boolean isAggregate, String pattern) { this.registry = registry; this.registrationKey = registrationKey; + this.isAggregate = isAggregate; this.pattern = pattern; } @@ -71,6 +73,7 @@ public SqmFunctionDescriptor descriptor() { argumentsValidator, returnTypeResolver, registrationKey, + isAggregate, argumentListSignature ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java index 48bc9e1e8386..3b66d47ea66d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java @@ -12,6 +12,9 @@ import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.expression.Distinct; +import org.hibernate.sql.ast.tree.expression.Star; +import org.hibernate.sql.ast.tree.predicate.Predicate; import java.util.ArrayList; import java.util.HashSet; @@ -132,19 +135,37 @@ public int getParamCount() { public void render( SqlAppender sqlAppender, List args, - SqlAstTranslator walker) { + SqlAstTranslator translator) { + render( sqlAppender, args, null, translator ); + } + + public void render( + SqlAppender sqlAppender, + List args, + Predicate filter, + SqlAstTranslator translator) { final int numberOfArguments = args.size(); + final boolean caseWrapper = filter != null && !translator.supportsFilterClause(); if ( numberOfArguments < maxParamIndex ) { LOG.missingArguments( maxParamIndex, numberOfArguments ); } for ( int i = 0; i < chunks.length; i++ ) { - if ( i==varargParam ) { + if ( i == varargParam ) { for ( int j = i; j < numberOfArguments; j++ ) { final SqlAstNode arg = args.get( j ); if ( arg != null ) { sqlAppender.appendSql( chunks[i] ); - walker.render( arg, argumentRenderingMode ); + if ( caseWrapper && !( arg instanceof Distinct ) && !( arg instanceof Star ) ) { + sqlAppender.appendSql( "case when " ); + filter.accept( translator ); + sqlAppender.appendSql( " then " ); + translator.render( arg, argumentRenderingMode ); + sqlAppender.appendSql( " else null end" ); + } + else { + translator.render( arg, argumentRenderingMode ); + } } } } @@ -155,12 +176,27 @@ else if ( i < paramIndexes.length ) { sqlAppender.appendSql( chunks[i] ); } if ( arg != null ) { - walker.render( arg, argumentRenderingMode ); + if ( caseWrapper && !( arg instanceof Distinct ) && !( arg instanceof Star ) ) { + sqlAppender.appendSql( "case when " ); + filter.accept( translator ); + sqlAppender.appendSql( " then " ); + translator.render( arg, argumentRenderingMode ); + sqlAppender.appendSql( " else null end" ); + } + else { + translator.render( arg, argumentRenderingMode ); + } } } else { sqlAppender.appendSql( chunks[i] ); } } + + if ( filter != null && !caseWrapper ) { + sqlAppender.appendSql( " filter (where " ); + filter.accept( translator ); + sqlAppender.appendSql( ')' ); + } } } 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 31985709233e..a664a983f29b 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 @@ -100,7 +100,6 @@ import org.hibernate.query.sqm.tree.update.SqmSetClause; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.service.ServiceRegistry; -import org.hibernate.sql.ast.tree.Statement; /** * Base support for an SQM walker 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 3495603b4f34..1d1d7ffc40d2 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 @@ -25,7 +25,6 @@ import org.hibernate.HibernateException; import org.hibernate.Internal; import org.hibernate.LockMode; -import org.hibernate.LockOptions; import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.QueryException; import org.hibernate.boot.model.process.internal.InferredBasicValueResolver; @@ -89,7 +88,7 @@ import org.hibernate.query.sqm.SqmExpressable; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; -import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression; +import org.hibernate.query.sqm.function.SelfRenderingAggregateFunctionSqlAstExpression; import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.internal.SqmMappingModelHelper; import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker; @@ -505,11 +504,8 @@ public SqlAliasBaseGenerator getSqlAliasBaseGenerator() { } @Override - public LockMode determineLockMode(String identificationVariable) { - final LockOptions lockOptions = getQueryOptions().getLockOptions(); - return lockOptions.getScope() || identificationVariable == null - ? lockOptions.getLockMode() - : lockOptions.getEffectiveLockMode( identificationVariable ); + public void registerLockMode(String identificationVariable, LockMode explicitLockMode) { + throw new UnsupportedOperationException( "Registering lock modes should only be done for result set mappings!" ); } public QueryOptions getQueryOptions() { @@ -589,7 +585,6 @@ public UpdateStatement visitUpdateStatement(SqmUpdateStatement sqmStatement) { final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup( rootPath, sqmStatement.getRoot().getAlias(), - LockMode.WRITE, () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate ), this, getCreationContext() @@ -847,7 +842,6 @@ public DeleteStatement visitDeleteStatement(SqmDeleteStatement statement) { final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup( rootPath, statement.getRoot().getAlias(), - LockMode.WRITE, () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate ), this, getCreationContext() @@ -930,7 +924,6 @@ public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement sq final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup( rootPath, sqmStatement.getTarget().getExplicitAlias(), - LockMode.WRITE, () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate ), this, getCreationContext() @@ -1029,7 +1022,6 @@ public InsertStatement visitInsertValuesStatement(SqmInsertValuesStatement sq final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup( rootPath, sqmStatement.getTarget().getExplicitAlias(), - LockMode.WRITE, () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate ), this, getCreationContext() @@ -1083,6 +1075,7 @@ public Values visitValues(SqmValues sqmValues) { public SelectStatement visitSelectStatement(SqmSelectStatement statement) { Map cteStatements = this.visitCteContainer( statement ); final QueryPart queryPart = visitQueryPart( statement.getQueryPart() ); + final List> domainResults = queryPart.isRoot() ? this.domainResults : Collections.emptyList(); return new SelectStatement( statement.isWithRecursive(), cteStatements, queryPart, domainResults ); } @@ -1147,6 +1140,7 @@ public CteStatement visitCteStatement(SqmCteStatement sqmCteStatement) { return new CteStatement( cteTable, visitStatement( sqmCteStatement.getCteDefinition() ), + sqmCteStatement.getMaterialization(), sqmCteStatement.getSearchClauseKind(), visitSearchBySpecifications( cteTable, sqmCteStatement.getSearchBySpecifications() ), visitCycleColumns( cteTable, sqmCteStatement.getCycleColumns() ), @@ -1751,7 +1745,6 @@ protected void consumeFromClauseRoot(SqmRoot sqmRoot) { if ( fromClauseIndex.isResolved( sqmRoot ) ) { log.tracef( "Already resolved SqmRoot [%s] to TableGroup", sqmRoot ); } - final SqlExpressionResolver sqlExpressionResolver = getSqlExpressionResolver(); final TableGroup tableGroup; if ( sqmRoot.isCorrelated() ) { final SessionFactoryImplementor sessionFactory = creationContext.getSessionFactory(); @@ -1784,7 +1777,6 @@ protected void consumeFromClauseRoot(SqmRoot sqmRoot) { tableGroup = entityDescriptor.createRootTableGroup( sqmRoot.getNavigablePath(), sqmRoot.getExplicitAlias(), - LockMode.NONE, () -> predicate -> {}, this, creationContext @@ -1849,7 +1841,6 @@ protected void consumeFromClauseRoot(SqmRoot sqmRoot) { tableGroup = entityDescriptor.createRootTableGroup( sqmRoot.getNavigablePath(), sqmRoot.getExplicitAlias(), - LockMode.NONE, () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate @@ -1935,7 +1926,6 @@ private void consumeAttributeJoin(SqmAttributeJoin sqmJoin, TableGroup lhs sqmJoin.getExplicitAlias(), sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(), sqmJoin.isFetched(), - determineLockMode( sqmJoin.getExplicitAlias() ), this ); } @@ -1950,7 +1940,6 @@ private void consumeAttributeJoin(SqmAttributeJoin sqmJoin, TableGroup lhs sqmJoin.getExplicitAlias(), sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(), sqmJoin.isFetched(), - determineLockMode( sqmJoin.getExplicitAlias() ), this ); } @@ -2002,7 +1991,6 @@ private void consumeCrossJoin(SqmCrossJoin sqmJoin, TableGroup lhsTableGroup) { final TableGroup tableGroup = entityDescriptor.createRootTableGroup( sqmJoin.getNavigablePath(), sqmJoin.getExplicitAlias(), - determineLockMode( sqmJoin.getExplicitAlias() ), () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate @@ -2031,7 +2019,6 @@ private void consumeEntityJoin(SqmEntityJoin sqmJoin, TableGroup lhsTableGroup) final TableGroup tableGroup = entityDescriptor.createRootTableGroup( sqmJoin.getNavigablePath(), sqmJoin.getExplicitAlias(), - determineLockMode( sqmJoin.getExplicitAlias() ), () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates( additionalRestrictions, predicate @@ -2102,7 +2089,6 @@ private void consumeReusablePaths( null, parentTableGroup.isInnerJoinPossible() ? SqlAstJoinType.INNER : SqlAstJoinType.LEFT, false, - null, this ); @@ -2709,7 +2695,6 @@ public Object visitMapEntryFunction(SqmMapEntryReference entryRef) { null, SqlAstJoinType.INNER, false, - LockMode.READ, sqlAliasBaseManager, getSqlExpressionResolver(), creationContext @@ -3834,7 +3819,6 @@ public Expression visitPluralAttributeSizeFunction(SqmCollectionSize function) { final TableGroup tableGroup = collectionPart.createRootTableGroup( pluralPath.getNavigablePath(), null, - LockOptions.NONE.getLockMode(), () -> subQuerySpec::applyPredicate, this, creationContext @@ -3851,10 +3835,11 @@ public Expression visitPluralAttributeSizeFunction(SqmCollectionSize function) { final BasicType integerType = creationContext.getDomainModel() .getTypeConfiguration() .getBasicTypeForJavaType( Integer.class ); - final Expression expression = new SelfRenderingFunctionSqlAstExpression( + final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression( functionDescriptor.getName(), functionDescriptor::render, Collections.singletonList( new QueryLiteral<>( 1, integerType ) ), + null, integerType, integerType ); @@ -3902,7 +3887,6 @@ protected Expression createCorrelatedAggregateSubQuery( final TableGroup tableGroup = mappingModelExpressable.createRootTableGroup( pluralPartPath.getNavigablePath(), null, - LockOptions.NONE.getLockMode(), () -> subQuerySpec::applyPredicate, this, creationContext @@ -3932,10 +3916,11 @@ protected Expression createCorrelatedAggregateSubQuery( ); } ); - final Expression expression = new SelfRenderingFunctionSqlAstExpression( + final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression( functionDescriptor.getName(), functionDescriptor::render, arguments, + null, (AllowableFunctionReturnType) collectionPart.getJdbcMappings().get( 0 ), collectionPart ); @@ -4050,7 +4035,6 @@ else if ( mappingModelExpressable.getElementDescriptor() instanceof EmbeddedColl final TableGroup tableGroup = mappingModelExpressable.createRootTableGroup( pluralPath.getNavigablePath(), null, - LockOptions.NONE.getLockMode(), () -> subQuerySpec::applyPredicate, this, creationContext @@ -4164,7 +4148,6 @@ public Object visitIsEmptyPredicate(SqmEmptinessPredicate predicate) { sqmPluralPath.getExplicitAlias(), SqlAstJoinType.INNER, false, - LockMode.NONE, sqlAliasBaseManager, subQueryState, creationContext @@ -4527,7 +4510,6 @@ private Fetch buildFetch(NavigablePath fetchablePath, FetchParent fetchParent, F // "initializing" state as part of AfterLoadAction final String alias; - LockMode lockMode = LockMode.READ; FetchTiming fetchTiming = fetchable.getMappedFetchOptions().getTiming(); boolean joined = false; @@ -4547,7 +4529,6 @@ private Fetch buildFetch(NavigablePath fetchablePath, FetchParent fetchParent, F } joined = true; alias = fetchedJoin.getExplicitAlias(); - lockMode = determineLockMode( alias ); } else { // there was not an explicit fetch in the SQM @@ -4611,7 +4592,6 @@ else if ( getLoadQueryInfluencers().hasEnabledFetchProfiles() ) { alias, SqlAstJoinType.LEFT, true, - LockMode.NONE, this ); return tableGroupJoin.getJoinedGroup(); @@ -4627,7 +4607,6 @@ else if ( getLoadQueryInfluencers().hasEnabledFetchProfiles() ) { fetchablePath, fetchTiming, joined, - lockMode, alias, this ); 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 f45dc3d2b200..3cc4b1b294fc 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 @@ -9,7 +9,6 @@ import java.util.ArrayList; import java.util.List; -import org.hibernate.LockMode; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; import org.hibernate.metamodel.mapping.BasicValuedModelPart; @@ -220,7 +219,6 @@ public DomainResult createDomainResult(String resultVariable, DomainResultCre null, SqlAstJoinType.INNER, false, - LockMode.READ, sqlAstCreationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteStatement.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteStatement.java index e00631ae0b1e..96c70ba369a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/cte/SqmCteStatement.java @@ -8,6 +8,7 @@ import java.util.List; +import org.hibernate.sql.ast.tree.cte.CteMaterialization; import org.hibernate.sql.ast.tree.cte.CteSearchClauseKind; import org.hibernate.query.sqm.NodeBuilder; import org.hibernate.query.sqm.SemanticQueryWalker; @@ -22,6 +23,7 @@ public class SqmCteStatement extends AbstractSqmNode implements SqmVisitableNode { private final SqmCteContainer cteContainer; private final SqmCteTable cteTable; + private final CteMaterialization materialization; private final SqmStatement cteDefinition; private final CteSearchClauseKind searchClauseKind; private final List searchBySpecifications; @@ -33,10 +35,12 @@ public class SqmCteStatement extends AbstractSqmNode implements SqmVisitableN public SqmCteStatement( SqmCteTable cteTable, SqmStatement cteDefinition, + CteMaterialization materialization, NodeBuilder nodeBuilder) { super( nodeBuilder ); this.cteTable = cteTable; this.cteDefinition = cteDefinition; + this.materialization = materialization; this.cteContainer = null; this.searchClauseKind = null; this.searchBySpecifications = null; @@ -49,10 +53,12 @@ public SqmCteStatement( public SqmCteStatement( SqmCteTable cteTable, SqmStatement cteDefinition, + CteMaterialization materialization, SqmCteContainer cteContainer) { super( cteContainer.nodeBuilder() ); this.cteTable = cteTable; this.cteDefinition = cteDefinition; + this.materialization = materialization; this.cteContainer = cteContainer; this.searchClauseKind = null; this.searchBySpecifications = null; @@ -74,6 +80,10 @@ public SqmCteContainer getCteContainer() { return cteContainer; } + public CteMaterialization getMaterialization() { + return materialization; + } + public CteSearchClauseKind getSearchClauseKind() { return searchClauseKind; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/Conversion.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/Conversion.java index c1bd032af4bc..d59a23f74ef5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/Conversion.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/Conversion.java @@ -27,7 +27,7 @@ */ public class Conversion implements Expression, DomainResultProducer { - private Duration duration; + private final Duration duration; private final TemporalUnit unit; private final BasicValuedMapping type; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFunction.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFunction.java index 0875a9abdfd0..3ac79bcddaba 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/expression/SqmFunction.java @@ -23,7 +23,7 @@ import java.util.List; /** - * An SQM function + * A SQM function * * @author Steve Ebersole */ @@ -34,17 +34,7 @@ public abstract class SqmFunction extends AbstractSqmExpression private final String functionName; private final SqmFunctionDescriptor functionDescriptor; - private List> arguments; - - public SqmFunction( - String functionName, - SqmFunctionDescriptor functionDescriptor, - SqmExpressable type, - NodeBuilder criteriaBuilder) { - super( type, criteriaBuilder ); - this.functionName = functionName; - this.functionDescriptor = functionDescriptor; - } + private final List> arguments; public SqmFunction( String functionName, @@ -71,15 +61,6 @@ public List> getArguments() { return arguments; } - public void addArgument(SqmTypedNode argument) { - assert argument != null; - - if ( arguments == null ) { - arguments = new ArrayList<>(); - } - arguments.add( argument ); - } - public abstract Expression convertToSqlAst(SqmToSqlAstConverter walker); @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ForUpdateFragment.java b/hibernate-core/src/main/java/org/hibernate/sql/ForUpdateFragment.java index aa16a7fe8624..ffe7e1f0f480 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ForUpdateFragment.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ForUpdateFragment.java @@ -20,35 +20,27 @@ */ public class ForUpdateFragment { private final StringBuilder aliases = new StringBuilder(); - private boolean isNowaitEnabled; - private boolean isSkipLockedEnabled; private final Dialect dialect; - private LockMode lockMode; - private LockOptions lockOptions; - - public ForUpdateFragment(Dialect dialect) { - this.dialect = dialect; - } + private final LockOptions lockOptions; public ForUpdateFragment(Dialect dialect, LockOptions lockOptions, Map keyColumnNames) throws QueryException { - this( dialect ); + this.dialect = dialect; LockMode upgradeType = null; - Iterator iter = lockOptions.getAliasLockIterator(); + Iterator> iter = lockOptions.getAliasLockIterator(); this.lockOptions = lockOptions; if ( !iter.hasNext()) { // no tables referenced final LockMode lockMode = lockOptions.getLockMode(); if ( LockMode.READ.lessThan( lockMode ) ) { upgradeType = lockMode; - this.lockMode = lockMode; } } while ( iter.hasNext() ) { - final Map.Entry me = ( Map.Entry ) iter.next(); - final LockMode lockMode = ( LockMode ) me.getValue(); + final Map.Entry me = iter.next(); + final LockMode lockMode = me.getValue(); if ( LockMode.READ.lessThan( lockMode ) ) { - final String tableAlias = ( String ) me.getKey(); + final String tableAlias = me.getKey(); if ( dialect.forUpdateOfColumns() ) { String[] keyColumns = keyColumnNames.get( tableAlias ); //use the id column alias if ( keyColumns == null ) { @@ -68,14 +60,6 @@ public ForUpdateFragment(Dialect dialect, LockOptions lockOptions, Map extends SqlAstWalker */ void render(SqlAstNode sqlAstNode, SqlAstNodeRenderingMode renderingMode); + /** + * Whether the FILTER clause for aggregate functions is supported. + */ + boolean supportsFilterClause(); + /** * Not the best spot for this. Its the table names collected while walking the SQL AST. * Its ok here because the translator is consider a one-time-use. It just needs to be called 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 dafeed8b0fb7..c9e8b5373121 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 @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.List; @@ -19,8 +20,15 @@ import java.util.Set; import java.util.TimeZone; +import org.hibernate.LockMode; +import org.hibernate.QueryException; +import org.hibernate.dialect.RowLockStrategy; +import org.hibernate.metamodel.mapping.EntityAssociationMapping; +import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Queryable; +import org.hibernate.query.IllegalQueryOperationException; +import org.hibernate.sql.ast.tree.cte.CteMaterialization; import org.hibernate.sql.ast.tree.cte.CteSearchClauseKind; import org.hibernate.query.FetchClauseType; import org.hibernate.LockOptions; @@ -137,6 +145,7 @@ import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.exec.spi.JdbcDelete; import org.hibernate.sql.exec.spi.JdbcInsert; +import org.hibernate.sql.exec.spi.JdbcLockStrategy; import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.sql.exec.spi.JdbcParameterBinder; import org.hibernate.sql.exec.spi.JdbcParameterBinding; @@ -144,6 +153,7 @@ import org.hibernate.sql.exec.spi.JdbcSelect; import org.hibernate.sql.exec.spi.JdbcUpdate; import org.hibernate.sql.results.jdbc.internal.JdbcValuesMappingProducerStandard; +import org.hibernate.type.BasicType; import org.hibernate.type.IntegerType; import org.hibernate.type.StringType; import org.hibernate.type.descriptor.WrapperOptions; @@ -194,6 +204,7 @@ public abstract class AbstractSqlAstTranslator implemen private Limit limit; private JdbcParameter offsetParameter; private JdbcParameter limitParameter; + private ForUpdateClause forUpdate; public Dialect getDialect() { return dialect; @@ -320,6 +331,12 @@ public Set getAffectedTableNames() { return affectedTableNames; } + @Override + public boolean supportsFilterClause() { + // By default we report false because not many dialects support this + return false; + } + @Override public void appendSql(String fragment) { sqlBuffer.append( fragment ); @@ -354,6 +371,10 @@ protected Map getAppliedParameterBindings() return appliedParameterBindings; } + protected JdbcLockStrategy getJdbcLockStrategy() { + return lockOptions == null ? JdbcLockStrategy.FOLLOW_ON : JdbcLockStrategy.NONE; + } + protected JdbcParameterBindings getJdbcParameterBindings() { return jdbcParameterBindings; } @@ -371,8 +392,8 @@ protected boolean hasLimit() { } protected boolean hasOffset(QueryPart queryPart) { - if ( queryPart.isRoot() && hasLimit() ) { - return limit.getFirstRowJpa() != 0; + if ( queryPart.isRoot() && hasLimit() && limit.getFirstRowJpa() != 0 ) { + return true; } else { return queryPart.getOffsetClauseExpression() != null; @@ -532,79 +553,37 @@ else if ( statement instanceof SelectStatement ) { protected JdbcDelete translateDelete(DeleteStatement sqlAst) { visitDeleteStatement( sqlAst ); - return new JdbcDelete() { - @Override - public String getSql() { - return AbstractSqlAstTranslator.this.getSql(); - } - - @Override - public List getParameterBinders() { - return AbstractSqlAstTranslator.this.getParameterBinders(); - } - - @Override - public Set getAffectedTableNames() { - return AbstractSqlAstTranslator.this.getAffectedTableNames(); - } - - @Override - public Set getFilterJdbcParameters() { - return AbstractSqlAstTranslator.this.getFilterJdbcParameters(); - } - }; + return new JdbcDelete( + getSql(), + getParameterBinders(), + getAffectedTableNames(), + getFilterJdbcParameters(), + getAppliedParameterBindings() + ); } protected JdbcUpdate translateUpdate(UpdateStatement sqlAst) { visitUpdateStatement( sqlAst ); - return new JdbcUpdate() { - @Override - public String getSql() { - return AbstractSqlAstTranslator.this.getSql(); - } - - @Override - public List getParameterBinders() { - return AbstractSqlAstTranslator.this.getParameterBinders(); - } - - @Override - public Set getFilterJdbcParameters() { - return AbstractSqlAstTranslator.this.getFilterJdbcParameters(); - } - - @Override - public Set getAffectedTableNames() { - return AbstractSqlAstTranslator.this.getAffectedTableNames(); - } - }; + return new JdbcUpdate( + getSql(), + getParameterBinders(), + getAffectedTableNames(), + getFilterJdbcParameters(), + getAppliedParameterBindings() + ); } protected JdbcInsert translateInsert(InsertStatement sqlAst) { visitInsertStatement( sqlAst ); - return new JdbcInsert() { - @Override - public String getSql() { - return AbstractSqlAstTranslator.this.getSql(); - } - - @Override - public List getParameterBinders() { - return AbstractSqlAstTranslator.this.getParameterBinders(); - } - - @Override - public Set getAffectedTableNames() { - return AbstractSqlAstTranslator.this.getAffectedTableNames(); - } - - @Override - public Set getFilterJdbcParameters() { - return AbstractSqlAstTranslator.this.getFilterJdbcParameters(); - } - }; + return new JdbcInsert( + getSql(), + getParameterBinders(), + getAffectedTableNames(), + getFilterJdbcParameters(), + getAppliedParameterBindings() + ); } protected JdbcSelect translateSelect(SelectStatement sqlAstSelect) { @@ -626,7 +605,7 @@ protected JdbcSelect translateSelect(SelectStatement sqlAstSelect) { rowsToSkip = getRowsToSkip( sqlAstSelect, getJdbcParameterBindings() ), getMaxRows( sqlAstSelect, getJdbcParameterBindings(), rowsToSkip ), getAppliedParameterBindings(), - getLockOptions(), + getJdbcLockStrategy(), getOffsetParameter(), getLimitParameter() ); @@ -676,40 +655,58 @@ protected void prepareLimitOffsetParameters() { final Limit limit = getLimit(); if ( limit.getFirstRow() != null ) { setOffsetParameter( - new JdbcParameterImpl( IntegerType.INSTANCE ) { - @Override - public void bindParameterValue( - PreparedStatement statement, - int startPosition, - JdbcParameterBindings jdbcParamBindings, - ExecutionContext executionContext) throws SQLException { - IntegerType.INSTANCE.getJdbcValueBinder().bind( - statement, - executionContext.getQueryOptions().getLimit().getFirstRow(), - startPosition, - executionContext.getSession() - ); - } - } + new OffsetJdbcParameter( + sessionFactory.getTypeConfiguration().getBasicTypeForJavaType( Integer.class ) + ) ); } if ( limit.getMaxRows() != null ) { setLimitParameter( - new JdbcParameterImpl( IntegerType.INSTANCE ) { - @Override - public void bindParameterValue( - PreparedStatement statement, - int startPosition, - JdbcParameterBindings jdbcParamBindings, - ExecutionContext executionContext) throws SQLException { - IntegerType.INSTANCE.getJdbcValueBinder().bind( - statement, - executionContext.getQueryOptions().getLimit().getMaxRows(), - startPosition, - executionContext.getSession() - ); - } - } + new LimitJdbcParameter( + sessionFactory.getTypeConfiguration().getBasicTypeForJavaType( Integer.class ) + ) + ); + } + } + + private static class OffsetJdbcParameter extends JdbcParameterImpl { + + public OffsetJdbcParameter(BasicType type) { + super( type ); + } + + @Override + public void bindParameterValue( + PreparedStatement statement, + int startPosition, + JdbcParameterBindings jdbcParamBindings, + ExecutionContext executionContext) throws SQLException { + getJdbcMapping().getJdbcValueBinder().bind( + statement, + executionContext.getQueryOptions().getLimit().getFirstRow(), + startPosition, + executionContext.getSession() + ); + } + } + + private static class LimitJdbcParameter extends JdbcParameterImpl { + + public LimitJdbcParameter(BasicType type) { + super( type ); + } + + @Override + public void bindParameterValue( + PreparedStatement statement, + int startPosition, + JdbcParameterBindings jdbcParamBindings, + ExecutionContext executionContext) throws SQLException { + getJdbcMapping().getJdbcValueBinder().bind( + statement, + executionContext.getQueryOptions().getLimit().getMaxRows(), + startPosition, + executionContext.getSession() ); } } @@ -779,7 +776,7 @@ protected void visitDeleteStatementOnly(DeleteStatement statement) { final Stack clauseStack = getClauseStack(); try { clauseStack.push( Clause.DELETE ); - renderTableReference( statement.getTargetTable() ); + renderTableReference( statement.getTargetTable(), LockMode.NONE ); } finally { clauseStack.pop(); @@ -804,7 +801,7 @@ protected void visitUpdateStatementOnly(UpdateStatement statement) { final Stack clauseStack = getClauseStack(); try { clauseStack.push( Clause.UPDATE ); - renderTableReference( statement.getTargetTable() ); + renderTableReference( statement.getTargetTable(), LockMode.NONE ); } finally { clauseStack.pop(); @@ -924,6 +921,262 @@ protected void visitValuesList(List valuesList) { } } + protected void visitForUpdateClause(QuerySpec querySpec) { + if ( querySpec.isRoot() ) { + if ( forUpdate != null ) { + final Boolean followOnLocking = getLockOptions().getFollowOnLocking(); + if ( Boolean.TRUE.equals( followOnLocking ) ) { + lockOptions = null; + } + else { + forUpdate.merge( getLockOptions() ); + forUpdate.applyAliases( dialect.getWriteRowLockStrategy(), querySpec ); + final LockStrategy lockStrategy = determineLockingStrategy( querySpec, forUpdate, followOnLocking ); + switch ( lockStrategy ) { + case CLAUSE: + renderForUpdateClause( querySpec, forUpdate ); + break; + case FOLLOW_ON: + lockOptions = null; + break; + } + } + forUpdate = null; + } + else { + // Since we get here, we know that no alias locks were applied. + // We only apply locking on the root query though if there is a global lock mode + final LockOptions lockOptions = getLockOptions(); + final Boolean followOnLocking = lockOptions.getFollowOnLocking(); + if ( Boolean.TRUE.equals( followOnLocking )) { + this.lockOptions = null; + } + else if ( lockOptions.getLockMode() != LockMode.NONE ) { + final ForUpdateClause forUpdateClause = new ForUpdateClause(); + forUpdateClause.merge( getLockOptions() ); + forUpdateClause.applyAliases( dialect.getWriteRowLockStrategy(), querySpec ); + final LockStrategy lockStrategy = determineLockingStrategy( + querySpec, + forUpdateClause, + followOnLocking + ); + switch ( lockStrategy ) { + case CLAUSE: + renderForUpdateClause( + querySpec, + forUpdateClause + ); + break; + case FOLLOW_ON: + if ( Boolean.FALSE.equals( followOnLocking ) ) { + throw new UnsupportedOperationException( "" ); + } + this.lockOptions = null; + break; + } + } + } + } + else if ( forUpdate != null ) { + forUpdate.merge( getLockOptions() ); + forUpdate.applyAliases( dialect.getWriteRowLockStrategy(), querySpec ); + final LockStrategy lockStrategy = determineLockingStrategy( querySpec, forUpdate, null ); + switch ( lockStrategy ) { + case CLAUSE: + renderForUpdateClause( querySpec, forUpdate ); + break; + case FOLLOW_ON: + throw new UnsupportedOperationException( "Follow-on locking for subqueries is not supported" ); + } + forUpdate = null; + } + } + + protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { + int timeoutMillis = forUpdateClause.getTimeoutMillis(); + LockKind lockKind = LockKind.NONE; + switch ( forUpdateClause.getLockMode() ) { + //noinspection deprecation + case UPGRADE: + timeoutMillis = LockOptions.WAIT_FOREVER; + case PESSIMISTIC_WRITE: + lockKind = LockKind.UPDATE; + break; + case PESSIMISTIC_READ: + lockKind = LockKind.SHARE; + break; + case UPGRADE_NOWAIT: + //noinspection deprecation + case FORCE: + case PESSIMISTIC_FORCE_INCREMENT: + timeoutMillis = LockOptions.NO_WAIT; + lockKind = LockKind.UPDATE; + break; + case UPGRADE_SKIPLOCKED: + timeoutMillis = LockOptions.SKIP_LOCKED; + lockKind = LockKind.UPDATE; + break; + default: + break; + } + if ( lockKind != LockKind.NONE ) { + if ( lockKind == LockKind.SHARE ) { + appendSql( getForShare() ); + if ( forUpdateClause.hasAliases() && getDialect().getReadRowLockStrategy() != RowLockStrategy.NONE ) { + appendSql( " of " ); + forUpdateClause.appendAliases( this ); + } + } + else { + appendSql( getForUpdate() ); + if ( forUpdateClause.hasAliases() && getDialect().getWriteRowLockStrategy() != RowLockStrategy.NONE ) { + appendSql( " of " ); + forUpdateClause.appendAliases( this ); + } + } + appendSql( getForUpdateWithClause() ); + switch ( timeoutMillis ) { + case LockOptions.NO_WAIT: + if ( getDialect().supportsNoWait() ) { + appendSql( getNoWait() ); + } + break; + case LockOptions.SKIP_LOCKED: + if ( getDialect().supportsSkipLocked() ) { + appendSql( getSkipLocked() ); + } + break; + case LockOptions.WAIT_FOREVER: + break; + default: + if ( getDialect().supportsWait() ) { + appendSql( " wait " ); + appendSql( Integer.toString( Math.round( timeoutMillis / 1e3f ) ) ); + } + break; + } + } + } + + private enum LockKind { + NONE, + SHARE, + UPDATE; + } + + protected String getForUpdate() { + return " for update"; + } + + protected String getForShare() { + return " for update"; + } + + protected String getForUpdateWithClause() { + // This is a clause to specify the lock isolation for e.g. Derby + return ""; + } + + protected String getNoWait() { + return " nowait"; + } + + protected String getSkipLocked() { + return " skip locked"; + } + + protected LockMode getEffectiveLockMode(String alias) { + final QueryPart currentQueryPart = getQueryPartStack().getCurrent(); + LockMode lockMode = getLockOptions().getAliasSpecificLockMode( alias ); + if ( currentQueryPart.isRoot() && lockMode == null ) { + lockMode = getLockOptions().getLockMode(); + } + return lockMode == null ? LockMode.NONE : lockMode; + } + + protected int getEffectiveLockTimeout(LockMode lockMode) { + int timeoutMillis = getLockOptions().getTimeOut(); + switch ( lockMode ) { + //noinspection deprecation + case UPGRADE: + timeoutMillis = LockOptions.WAIT_FOREVER; + break; + case UPGRADE_NOWAIT: + //noinspection deprecation + case FORCE: + case PESSIMISTIC_FORCE_INCREMENT: + timeoutMillis = LockOptions.NO_WAIT; + break; + case UPGRADE_SKIPLOCKED: + timeoutMillis = LockOptions.SKIP_LOCKED; + break; + default: + break; + } + return timeoutMillis; + } + + protected boolean hasAggregateFunctions(QuerySpec querySpec) { + return AggregateFunctionChecker.hasAggregateFunctions( querySpec ); + } + + protected LockStrategy determineLockingStrategy( + QuerySpec querySpec, + ForUpdateClause forUpdateClause, + Boolean followOnLocking) { + LockStrategy strategy = LockStrategy.CLAUSE; + if ( !querySpec.getGroupByClauseExpressions().isEmpty() ) { + if ( Boolean.FALSE.equals( followOnLocking ) ) { + throw new IllegalQueryOperationException( "Locking with GROUP BY is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + if ( querySpec.getHavingClauseRestrictions() != null ) { + if ( Boolean.FALSE.equals( followOnLocking ) ) { + throw new IllegalQueryOperationException( "Locking with HAVING is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + if ( querySpec.getSelectClause().isDistinct() ) { + if ( Boolean.FALSE.equals( followOnLocking ) ) { + throw new IllegalQueryOperationException( "Locking with DISTINCT is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + if ( !getDialect().supportsOuterJoinForUpdate() ) { + if ( forUpdateClause.hasAliases() ) { + // Only need to visit the TableGroupJoins for which the alias is registered + querySpec.getFromClause().visitTableGroupJoins( + tableGroupJoin -> { + final TableGroup group = tableGroupJoin.getJoinedGroup(); + if ( forUpdateClause.hasAlias( group.getSourceAlias() ) ) { + if ( tableGroupJoin.getJoinType() != SqlAstJoinType.INNER && !( group instanceof VirtualTableGroup ) ) { + throw new IllegalQueryOperationException( "Locking with OUTER joins is not supported!" ); + } + } + } + ); + } + else { + // Visit TableReferenceJoin and TableGroupJoin to see if all use INNER + querySpec.getFromClause().visitTableJoins( + tableJoin -> { + if ( tableJoin.getJoinType() != SqlAstJoinType.INNER && !( tableJoin.getJoinedNode() instanceof VirtualTableGroup ) ) { + throw new IllegalQueryOperationException( "Locking with OUTER joins is not supported!" ); + } + } + ); + } + } + if ( hasAggregateFunctions( querySpec ) ) { + if ( Boolean.FALSE.equals( followOnLocking ) ) { + throw new IllegalQueryOperationException( "Locking with aggregate functions is not supported!" ); + } + strategy = LockStrategy.FOLLOW_ON; + } + return strategy; + } + protected void visitReturningColumns(MutationStatement mutationStatement) { final List returningColumns = mutationStatement.getReturningColumns(); final int size = returningColumns.size(); @@ -966,8 +1219,13 @@ public void visitCteContainer(CteContainer cteContainer) { separator = ", "; } - appendSql( ") as (" ); + appendSql( ") as " ); + + if ( cte.getMaterialization() != CteMaterialization.UNDEFINED ) { + renderMaterializationHint( cte.getMaterialization() ); + } + appendSql( '(' ); cte.getCteDefinition().accept( this ); appendSql( ')' ); @@ -980,6 +1238,10 @@ public void visitCteContainer(CteContainer cteContainer) { appendSql( ' ' ); } + protected void renderMaterializationHint(CteMaterialization materialization) { + // No-op by default + } + protected void renderSearchClause(CteStatement cte) { String separator; if ( cte.getSearchClauseKind() != null ) { @@ -1088,7 +1350,9 @@ public void visitQueryGroup(QueryGroup queryGroup) { public void visitQuerySpec(QuerySpec querySpec) { final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering; final boolean needsSelectAliases = this.needsSelectAliases; + final ForUpdateClause forUpdate = this.forUpdate; try { + this.forUpdate = null; final QueryPart currentQueryPart = queryPartStack.getCurrent(); if ( currentQueryPart != null && queryPartForRowNumbering != currentQueryPart ) { this.queryPartForRowNumbering = null; @@ -1124,6 +1388,10 @@ public void visitQuerySpec(QuerySpec querySpec) { visitHavingClause( querySpec ); visitOrderBy( querySpec.getSortSpecifications() ); visitOffsetFetchClause( querySpec ); + // We render the FOR UPDATE clause in the parent query + if ( queryPartForRowNumbering == null ) { + visitForUpdateClause( querySpec ); + } if ( needsParenthesis ) { appendSql( ")" ); @@ -1131,9 +1399,12 @@ public void visitQuerySpec(QuerySpec querySpec) { } } finally { - queryPartStack.pop(); + this.queryPartStack.pop(); this.queryPartForRowNumbering = queryPartForRowNumbering; this.needsSelectAliases = needsSelectAliases; + if ( queryPartForRowNumbering == null ) { + this.forUpdate = forUpdate; + } } } @@ -2252,7 +2523,7 @@ protected void emulateFetchOffsetWithWindowFunctions( } appendSql( " from (" ); queryPart.accept( this ); - appendSql( " ) "); + appendSql( ") "); appendSql( alias ); appendSql( " where " ); final Stack clauseStack = getClauseStack(); @@ -2271,7 +2542,7 @@ protected void emulateFetchOffsetWithWindowFunctions( appendSql( alias ); appendSql( ".cnt * " ); fetchExpression.accept( this ); - appendSql( " / 100 )" ); + appendSql( " / 100)" ); break; case ROWS_ONLY: appendSql( alias ); @@ -2289,7 +2560,7 @@ protected void emulateFetchOffsetWithWindowFunctions( appendSql( alias ); appendSql( ".cnt * " ); fetchExpression.accept( this ); - appendSql( " / 100 )" ); + appendSql( " / 100)" ); break; case ROWS_WITH_TIES: appendSql( alias ); @@ -2326,6 +2597,13 @@ protected void emulateFetchOffsetWithWindowFunctions( appendSql( alias ); appendSql( ".rn" ); } + + // We render the FOR UPDATE clause in the outer query + if ( queryPart instanceof QuerySpec ) { + clauseStack.pop(); + clauseStack.push( Clause.FOR_UPDATE ); + visitForUpdateClause( (QuerySpec) queryPart ); + } } finally { clauseStack.pop(); @@ -2337,6 +2615,21 @@ protected void emulateFetchOffsetWithWindowFunctions( } } + protected final void withRowNumbering(QueryPart queryPart, Runnable r) { + final QueryPart queryPartForRowNumbering = this.queryPartForRowNumbering; + final boolean needsSelectAliases = this.needsSelectAliases; + try { + this.queryPartForRowNumbering = queryPart; + this.needsSelectAliases = false; + r.run(); + } + finally { + this.queryPartForRowNumbering = queryPartForRowNumbering; + this.needsSelectAliases = needsSelectAliases; + } + } + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SELECT clause @@ -2378,7 +2671,7 @@ protected void visitSqlSelections(SelectClause selectClause) { appendSql( "count(*) over () cnt," ); case ROWS_ONLY: renderRowNumber( selectClause, queryPartForRowNumbering ); - appendSql( " rn " ); + appendSql( " rn" ); break; case PERCENT_WITH_TIES: appendSql( "count(*) over () cnt," ); @@ -2451,7 +2744,13 @@ protected void renderRowNumber(SelectClause selectClause, QueryPart queryPart) { protected List getSortSpecificationsRowNumbering( SelectClause selectClause, QueryPart queryPart) { - final List sortSpecifications = queryPart.getSortSpecifications(); + final List sortSpecifications; + if ( queryPart.hasSortSpecifications() ) { + sortSpecifications = queryPart.getSortSpecifications(); + } + else { + sortSpecifications = Collections.emptyList(); + } if ( selectClause.isDistinct() ) { // When select distinct is used, we need to add all select items to the order by clause final List sqlSelections = new ArrayList<>( selectClause.getSqlSelections() ); @@ -2477,7 +2776,7 @@ protected List getSortSpecificationsRowNumbering( final List sortSpecificationsRowNumbering = new ArrayList<>( sqlSelectionsSize + specificationsSize ); sortSpecificationsRowNumbering.addAll( sortSpecifications ); for ( int i = 0; i < sqlSelectionsSize; i++ ) { - sortSpecifications.add( + sortSpecificationsRowNumbering.add( new SortSpecification( new SqlSelectionExpression( sqlSelections.get( i ) ), null, @@ -2604,7 +2903,8 @@ protected void renderTableGroup(TableGroup tableGroup) { // sqlAppender.appendSql( OPEN_PARENTHESIS ); // } - renderTableReference( tableGroup.getPrimaryTableReference() ); + final LockMode effectiveLockMode = getEffectiveLockMode( tableGroup.getSourceAlias() ); + final boolean usesLockHint = renderTableReference( tableGroup.getPrimaryTableReference(), effectiveLockMode ); renderTableReferenceJoins( tableGroup ); @@ -2622,6 +2922,15 @@ protected void renderTableGroup(TableGroup tableGroup) { registerAffectedTable( querySpaces[i] ); } } + if ( !usesLockHint && tableGroup.getSourceAlias() != null && LockMode.READ.lessThan( effectiveLockMode ) ) { + if ( forUpdate == null ) { + forUpdate = new ForUpdateClause( effectiveLockMode ); + } + else { + forUpdate.setLockMode( effectiveLockMode ); + } + forUpdate.applyAliases( getDialect().getLockRowIdentifier( effectiveLockMode ), tableGroup ); + } } protected void renderTableGroup(TableGroup tableGroup, Predicate predicate) { @@ -2632,7 +2941,8 @@ protected void renderTableGroup(TableGroup tableGroup, Predicate predicate) { appendSql( '(' ); } - renderTableReference( tableGroup.getPrimaryTableReference() ); + final LockMode effectiveLockMode = getEffectiveLockMode( tableGroup.getSourceAlias() ); + final boolean usesLockHint = renderTableReference( tableGroup.getPrimaryTableReference(), effectiveLockMode ); if ( realTableGroup ) { renderTableReferenceJoins( tableGroup ); @@ -2654,21 +2964,30 @@ protected void renderTableGroup(TableGroup tableGroup, Predicate predicate) { registerAffectedTable( querySpaces[i] ); } } + if ( !usesLockHint && tableGroup.getSourceAlias() != null && LockMode.READ.lessThan( effectiveLockMode ) ) { + if ( forUpdate == null ) { + forUpdate = new ForUpdateClause( effectiveLockMode ); + } + else { + forUpdate.setLockMode( effectiveLockMode ); + } + forUpdate.applyAliases( getDialect().getLockRowIdentifier( effectiveLockMode ), tableGroup ); + } } @SuppressWarnings("WeakerAccess") - protected void renderTableReference(TableReference tableReference) { + protected boolean renderTableReference(TableReference tableReference, LockMode lockMode) { appendSql( tableReference.getTableExpression() ); registerAffectedTable( tableReference ); final Clause currentClause = clauseStack.getCurrent(); - if ( !rendersTableReferenceAlias( currentClause ) ) { - return; - } - final String identificationVariable = tableReference.getIdentificationVariable(); - if ( identificationVariable != null ) { - appendSql( getDialect().getTableAliasSeparator() ); - appendSql( identificationVariable ); + if ( rendersTableReferenceAlias( currentClause ) ) { + final String identificationVariable = tableReference.getIdentificationVariable(); + if ( identificationVariable != null ) { + appendSql( getDialect().getTableAliasSeparator() ); + appendSql( identificationVariable ); + } } + return false; } public static boolean rendersTableReferenceAlias(Clause clause) { @@ -2702,11 +3021,11 @@ protected void renderTableReferenceJoins(TableGroup tableGroup) { appendSql( tableJoin.getJoinType().getText() ); appendSql( " join " ); - renderTableReference( tableJoin.getJoinedTableReference() ); + renderTableReference( tableJoin.getJoinedTableReference(), LockMode.NONE ); - if ( tableJoin.getJoinPredicate() != null && !tableJoin.getJoinPredicate().isEmpty() ) { + if ( tableJoin.getPredicate() != null && !tableJoin.getPredicate().isEmpty() ) { appendSql( " on " ); - tableJoin.getJoinPredicate().accept( this ); + tableJoin.getPredicate().accept( this ); } } } @@ -4164,4 +4483,173 @@ protected String getFromDualForSelectOnly() { return ""; } + protected enum LockStrategy { + CLAUSE, + FOLLOW_ON, + NONE; + } + + protected static class ForUpdateClause { + private LockMode lockMode; + private int timeoutMillis = LockOptions.WAIT_FOREVER; + private Map keyColumnNames; + private Map aliases; + + public ForUpdateClause(LockMode lockMode) { + this.lockMode = lockMode; + } + + public ForUpdateClause() { + this.lockMode = LockMode.NONE; + } + + public void applyAliases(RowLockStrategy lockIdentifier, QuerySpec querySpec) { + if ( lockIdentifier != RowLockStrategy.NONE ) { + querySpec.getFromClause().visitTableGroups( tableGroup -> applyAliases( lockIdentifier, tableGroup ) ); + } + } + + public void applyAliases(RowLockStrategy lockIdentifier, TableGroup tableGroup) { + if ( aliases != null && lockIdentifier != RowLockStrategy.NONE ) { + final String tableAlias = tableGroup.getPrimaryTableReference().getIdentificationVariable(); + if ( aliases.containsKey( tableGroup.getSourceAlias() ) ) { + addAlias( tableGroup.getSourceAlias(), tableAlias ); + if ( lockIdentifier == RowLockStrategy.COLUMN ) { + addKeyColumnNames( tableGroup ); + } + } + } + } + + public LockMode getLockMode() { + return lockMode; + } + + public void setLockMode(LockMode lockMode) { + if ( this.lockMode != LockMode.NONE && lockMode != this.lockMode ) { + throw new QueryException( "mixed LockModes" ); + } + this.lockMode = lockMode; + } + + public void addKeyColumnNames(TableGroup tableGroup) { + final String[] keyColumnNames = determineKeyColumnNames( tableGroup.getModelPart() ); + if ( keyColumnNames == null ) { + throw new IllegalArgumentException( "Can't lock table group: " + tableGroup ); + } + addKeyColumnNames( + tableGroup.getSourceAlias(), + tableGroup.getPrimaryTableReference().getIdentificationVariable(), + keyColumnNames + ); + } + + private String[] determineKeyColumnNames(ModelPart modelPart) { + if ( modelPart instanceof Loadable ) { + return ( (Loadable) modelPart ).getIdentifierColumnNames(); + } + else if ( modelPart instanceof PluralAttributeMapping ) { + return ((PluralAttributeMapping) modelPart).getCollectionDescriptor().getKeyColumnAliases( null ); + } + else if ( modelPart instanceof EntityAssociationMapping ) { + return determineKeyColumnNames( ( (EntityAssociationMapping) modelPart ).getAssociatedEntityMappingType() ); + } + return null; + } + + private void addKeyColumnNames(String alias, String tableAlias, String[] keyColumnNames) { + if ( this.keyColumnNames == null ) { + this.keyColumnNames = new HashMap<>(); + } + this.keyColumnNames.put( tableAlias, keyColumnNames ); + } + + public boolean hasAlias(String alias) { + return aliases != null && aliases.containsKey( alias ); + } + + private void addAlias(String alias, String tableAlias) { + if ( aliases == null ) { + aliases = new HashMap<>(); + } + aliases.put( alias, tableAlias ); + } + + public int getTimeoutMillis() { + return timeoutMillis; + } + + public boolean hasAliases() { + return aliases != null; + } + + public void appendAliases(SqlAppender appender) { + if ( aliases == null ) { + return; + } + if ( keyColumnNames != null ) { + boolean first = true; + for ( String tableAlias : aliases.values() ) { + final String[] keyColumns = keyColumnNames.get( tableAlias ); //use the id column alias + if ( keyColumns == null ) { + throw new IllegalArgumentException( "alias not found: " + tableAlias ); + } + for ( String keyColumn : keyColumns ) { + if ( first ) { + first = false; + } + else { + appender.appendSql( ", " ); + } + appender.appendSql( tableAlias ); + appender.appendSql( '.' ); + appender.appendSql( keyColumn ); + } + } + } + else { + boolean first = true; + for ( String tableAlias : aliases.values() ) { + if ( first ) { + first = false; + } + else { + appender.appendSql( ", " ); + } + appender.appendSql( tableAlias ); + } + } + } + + public String getAliases() { + if ( aliases == null ) { + return null; + } + return aliases.toString(); + } + + public void merge(LockOptions lockOptions) { + if ( lockOptions != null ) { + LockMode upgradeType = LockMode.NONE; + if ( lockOptions.getAliasLockCount() == 0 ) { + upgradeType = lockOptions.getLockMode(); + } + else { + for ( Map.Entry entry : lockOptions.getAliasSpecificLocks() ) { + final LockMode lockMode = entry.getValue(); + if ( LockMode.READ.lessThan( lockMode ) ) { + addAlias( entry.getKey(), null ); + if ( upgradeType != LockMode.NONE && lockMode != upgradeType ) { + throw new QueryException( "mixed LockModes" ); + } + upgradeType = lockMode; + } + } + } + lockMode = upgradeType; + timeoutMillis = lockOptions.getTimeOut(); + } + } + } + } 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 new file mode 100644 index 000000000000..66603a5ce75e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AggregateFunctionChecker.java @@ -0,0 +1,363 @@ +/* + * 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.spi; + +import org.hibernate.query.sqm.tree.expression.Conversion; +import org.hibernate.sql.ast.SqlAstWalker; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.delete.DeleteStatement; +import org.hibernate.sql.ast.tree.expression.AggregateFunctionExpression; +import org.hibernate.sql.ast.tree.expression.Any; +import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression; +import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; +import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; +import org.hibernate.sql.ast.tree.expression.CastTarget; +import org.hibernate.sql.ast.tree.expression.Collate; +import org.hibernate.sql.ast.tree.expression.ColumnReference; +import org.hibernate.sql.ast.tree.expression.Distinct; +import org.hibernate.sql.ast.tree.expression.Duration; +import org.hibernate.sql.ast.tree.expression.DurationUnit; +import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral; +import org.hibernate.sql.ast.tree.expression.Every; +import org.hibernate.sql.ast.tree.expression.Expression; +import org.hibernate.sql.ast.tree.expression.ExtractUnit; +import org.hibernate.sql.ast.tree.expression.Format; +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.NullnessLiteral; +import org.hibernate.sql.ast.tree.expression.QueryLiteral; +import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression; +import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression; +import org.hibernate.sql.ast.tree.expression.SqlTuple; +import org.hibernate.sql.ast.tree.expression.Star; +import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.expression.TrimSpecification; +import org.hibernate.sql.ast.tree.expression.UnaryOperation; +import org.hibernate.sql.ast.tree.from.FromClause; +import org.hibernate.sql.ast.tree.from.TableGroup; +import org.hibernate.sql.ast.tree.from.TableGroupJoin; +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.ComparisonPredicate; +import org.hibernate.sql.ast.tree.predicate.ExistsPredicate; +import org.hibernate.sql.ast.tree.predicate.FilterPredicate; +import org.hibernate.sql.ast.tree.predicate.GroupedPredicate; +import org.hibernate.sql.ast.tree.predicate.InListPredicate; +import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; +import org.hibernate.sql.ast.tree.predicate.Junction; +import org.hibernate.sql.ast.tree.predicate.LikePredicate; +import org.hibernate.sql.ast.tree.predicate.NegatedPredicate; +import org.hibernate.sql.ast.tree.predicate.NullnessPredicate; +import org.hibernate.sql.ast.tree.predicate.Predicate; +import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate; +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.ast.tree.select.SelectClause; +import org.hibernate.sql.ast.tree.select.SelectStatement; +import org.hibernate.sql.ast.tree.select.SortSpecification; +import org.hibernate.sql.ast.tree.update.Assignment; +import org.hibernate.sql.ast.tree.update.UpdateStatement; + +/** + * A simple walker that checks for aggregate functions. + * + * @author Christian Beikov + */ +class AggregateFunctionChecker implements SqlAstWalker { + + private static final AggregateFunctionChecker INSTANCE = new AggregateFunctionChecker(); + + private static class AggregateFunctionException extends RuntimeException {} + + public static boolean hasAggregateFunctions(QuerySpec querySpec) { + try { + querySpec.getSelectClause().accept( INSTANCE ); + querySpec.visitSortSpecifications( INSTANCE::visitSortSpecification ); + return false; + } + catch (AggregateFunctionException ex) { + return true; + } + } + + @Override + public void visitAny(Any any) { + throw new AggregateFunctionException(); + } + + @Override + public void visitEvery(Every every) { + throw new AggregateFunctionException(); + } + + @Override + public void visitSelfRenderingExpression(SelfRenderingExpression expression) { + if ( expression instanceof AggregateFunctionExpression ) { + throw new AggregateFunctionException(); + } + else if ( expression instanceof FunctionExpression ) { + for ( SqlAstNode argument : ( (FunctionExpression) expression ).getArguments() ) { + argument.accept( this ); + } + } + } + + @Override + public void visitSortSpecification(SortSpecification sortSpecification) { + sortSpecification.getSortExpression().accept( this ); + } + + @Override + public void visitSelectClause(SelectClause selectClause) { + for ( SqlSelection sqlSelection : selectClause.getSqlSelections() ) { + sqlSelection.accept( this ); + } + } + + @Override + public void visitSqlSelection(SqlSelection sqlSelection) { + sqlSelection.getExpression().accept( this ); + } + + @Override + public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) { + arithmeticExpression.getLeftHandOperand().accept( this ); + arithmeticExpression.getRightHandOperand().accept( this ); + } + + @Override + public void visitCaseSearchedExpression(CaseSearchedExpression caseSearchedExpression) { + for ( CaseSearchedExpression.WhenFragment whenFragment : caseSearchedExpression.getWhenFragments() ) { + whenFragment.getPredicate().accept( this ); + whenFragment.getResult().accept( this ); + } + if ( caseSearchedExpression.getOtherwise() != null ) { + caseSearchedExpression.getOtherwise().accept( this ); + } + } + + @Override + public void visitCaseSimpleExpression(CaseSimpleExpression caseSimpleExpression) { + caseSimpleExpression.getFixture().accept( this ); + for ( CaseSimpleExpression.WhenFragment whenFragment : caseSimpleExpression.getWhenFragments() ) { + whenFragment.getCheckValue().accept( this ); + whenFragment.getResult().accept( this ); + } + if ( caseSimpleExpression.getOtherwise() != null ) { + caseSimpleExpression.getOtherwise().accept( this ); + } + } + + @Override + public void visitTuple(SqlTuple tuple) { + for ( Expression expression : tuple.getExpressions() ) { + expression.accept( this ); + } + } + + @Override + public void visitCollate(Collate collate) { + collate.getExpression().accept( this ); + } + + @Override + public void visitUnaryOperationExpression(UnaryOperation unaryOperationExpression) { + unaryOperationExpression.getOperand().accept( this ); + } + + @Override + public void visitBetweenPredicate(BetweenPredicate betweenPredicate) { + betweenPredicate.getExpression().accept( this ); + betweenPredicate.getLowerBound().accept( this ); + betweenPredicate.getUpperBound().accept( this ); + } + + @Override + public void visitGroupedPredicate(GroupedPredicate groupedPredicate) { + groupedPredicate.getSubPredicate().accept( this ); + } + + @Override + public void visitJunction(Junction junction) { + for ( Predicate predicate : junction.getPredicates() ) { + predicate.accept( this ); + } + } + + @Override + public void visitLikePredicate(LikePredicate likePredicate) { + likePredicate.getMatchExpression().accept( this ); + if ( likePredicate.getEscapeCharacter() != null ) { + likePredicate.getEscapeCharacter().accept( this ); + } + likePredicate.getPattern().accept( this ); + } + + @Override + public void visitNegatedPredicate(NegatedPredicate negatedPredicate) { + negatedPredicate.getPredicate().accept( this ); + } + + @Override + public void visitNullnessPredicate(NullnessPredicate nullnessPredicate) { + nullnessPredicate.getExpression().accept( this ); + } + + @Override + public void visitRelationalPredicate(ComparisonPredicate comparisonPredicate) { + comparisonPredicate.getLeftHandExpression().accept( this ); + comparisonPredicate.getRightHandExpression().accept( this ); + } + + @Override + public void visitSelfRenderingPredicate(SelfRenderingPredicate selfRenderingPredicate) { + selfRenderingPredicate.getSelfRenderingExpression().accept( this ); + } + + // --- to ignore --- + + @Override + public void visitSelectStatement(SelectStatement statement) { + } + + @Override + public void visitDeleteStatement(DeleteStatement statement) { + } + + @Override + public void visitUpdateStatement(UpdateStatement statement) { + } + + @Override + public void visitInsertStatement(InsertStatement statement) { + } + + @Override + public void visitAssignment(Assignment assignment) { + } + + @Override + public void visitQueryGroup(QueryGroup queryGroup) { + } + + @Override + public void visitQuerySpec(QuerySpec querySpec) { + } + + @Override + public void visitColumnReference(ColumnReference columnReference) { + } + + @Override + public void visitExtractUnit(ExtractUnit extractUnit) { + } + + @Override + public void visitFormat(Format format) { + } + + @Override + public void visitDistinct(Distinct distinct) { + } + + @Override + public void visitStar(Star star) { + } + + @Override + public void visitOffsetFetchClause(QueryPart querySpec) { + } + + @Override + public void visitTrimSpecification(TrimSpecification trimSpecification) { + } + + @Override + public void visitCastTarget(CastTarget castTarget) { + } + + @Override + public void visitDurationUnit(DurationUnit durationUnit) { + } + + @Override + public void visitDuration(Duration duration) { + } + + @Override + public void visitConversion(Conversion conversion) { + } + + @Override + public void visitInListPredicate(InListPredicate inListPredicate) { + } + + @Override + public void visitInSubQueryPredicate(InSubQueryPredicate inSubQueryPredicate) { + } + + @Override + public void visitExistsPredicate(ExistsPredicate existsPredicate) { + } + + @Override + public void visitFilterPredicate(FilterPredicate filterPredicate) { + } + + @Override + public void visitParameter(JdbcParameter jdbcParameter) { + } + + @Override + public void visitJdbcLiteral(JdbcLiteral jdbcLiteral) { + } + + @Override + public void visitQueryLiteral(QueryLiteral queryLiteral) { + } + + @Override + public void visitNullnessLiteral(NullnessLiteral nullnessLiteral) { + } + + @Override + public void visitSummarization(Summarization every) { + } + + @Override + public void visitEntityTypeLiteral(EntityTypeLiteral expression) { + } + + @Override + public void visitSqlSelectionExpression(SqlSelectionExpression expression) { + } + + @Override + public void visitTableReference(TableReference tableReference) { + } + + @Override + public void visitTableReferenceJoin(TableReferenceJoin tableReferenceJoin) { + } + + @Override + public void visitFromClause(FromClause fromClause) { + } + + @Override + public void visitTableGroup(TableGroup tableGroup) { + } + + @Override + public void visitTableGroupJoin(TableGroupJoin tableGroupJoin) { + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAstCreationState.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAstCreationState.java index 2470c0be8c39..2426a7103d04 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAstCreationState.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/SqlAstCreationState.java @@ -24,5 +24,5 @@ public interface SqlAstCreationState { SqlAliasBaseGenerator getSqlAliasBaseGenerator(); - LockMode determineLockMode(String identificationVariable); + void registerLockMode(String identificationVariable, LockMode explicitLockMode); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteMaterialization.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteMaterialization.java new file mode 100644 index 000000000000..45c48cfdb77e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteMaterialization.java @@ -0,0 +1,28 @@ +/* + * 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.cte; + +/** + * The kind of materialization that should be used for a CTE. + * This is a hint that like e.g. for PostgreSQL which allows to control this. + * + * @author Christian Beikov + */ +public enum CteMaterialization { + /** + * It is undefined if the CTE should be materialized. + */ + UNDEFINED, + /** + * Materialize the CTE if possible. + */ + MATERIALIZED, + /** + * Do not materialize the CTE if possible. + */ + NOT_MATERIALIZED; +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteStatement.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteStatement.java index dce03b55ed4d..8e5499a21cae 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteStatement.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteStatement.java @@ -19,6 +19,7 @@ public class CteStatement { private final CteTable cteTable; private final Statement cteDefinition; + private final CteMaterialization materialization; private final CteSearchClauseKind searchClauseKind; private final List searchBySpecifications; private final List cycleColumns; @@ -27,8 +28,13 @@ public class CteStatement { private final char noCycleValue; public CteStatement(CteTable cteTable, Statement cteDefinition) { + this( cteTable, cteDefinition, CteMaterialization.UNDEFINED ); + } + + public CteStatement(CteTable cteTable, Statement cteDefinition, CteMaterialization materialization) { this.cteDefinition = cteDefinition; this.cteTable = cteTable; + this.materialization = materialization; this.searchClauseKind = null; this.searchBySpecifications = null; this.cycleColumns = null; @@ -40,6 +46,7 @@ public CteStatement(CteTable cteTable, Statement cteDefinition) { public CteStatement( CteTable cteTable, Statement cteDefinition, + CteMaterialization materialization, CteSearchClauseKind searchClauseKind, List searchBySpecifications, List cycleColumns, @@ -48,6 +55,7 @@ public CteStatement( char noCycleValue) { this.cteTable = cteTable; this.cteDefinition = cteDefinition; + this.materialization = materialization; this.searchClauseKind = searchClauseKind; this.searchBySpecifications = searchBySpecifications; this.cycleColumns = cycleColumns; @@ -64,6 +72,10 @@ public Statement getCteDefinition() { return cteDefinition; } + public CteMaterialization getMaterialization() { + return materialization; + } + public CteSearchClauseKind getSearchClauseKind() { return searchClauseKind; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteTable.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteTable.java index 052decf8757c..b1d137a4987a 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteTable.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteTable.java @@ -80,7 +80,7 @@ public QuerySpec createCteDefinition( final StandardTableGroup tableValueCtorGroup = new StandardTableGroup( new NavigablePath( "cte" ), null, - LockMode.NONE, + null, tableValueConstructorReference, null, sessionFactory diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteTableGroup.java index da0911937e56..9bd7fa50c304 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/cte/CteTableGroup.java @@ -41,8 +41,8 @@ public NavigablePath getNavigablePath() { } @Override - public LockMode getLockMode() { - return LockMode.NONE; + public String getSourceAlias() { + return null; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/AggregateFunctionExpression.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/AggregateFunctionExpression.java new file mode 100644 index 000000000000..1e7b83099244 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/AggregateFunctionExpression.java @@ -0,0 +1,19 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.ast.tree.expression; + +import org.hibernate.sql.ast.tree.predicate.Predicate; + +/** + * Models an aggregate function expression at the SQL AST level. + * + * @author Christian Beikov + */ +public interface AggregateFunctionExpression extends FunctionExpression { + + Predicate getFilter(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Distinct.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Distinct.java index f822a8f5a112..9aca54648d8f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Distinct.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Distinct.java @@ -16,7 +16,7 @@ * @author Gavin King */ public class Distinct implements Expression, SqlExpressable, SqlAstNode { - private Expression expression; + private final Expression expression; public Distinct(Expression expression) { this.expression = expression; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Duration.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Duration.java index 55d071a0b8e8..4177bf6dea1a 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Duration.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/Duration.java @@ -24,7 +24,7 @@ * @author Gavin King */ public class Duration implements Expression, DomainResultProducer { - private Expression magnitude; + private final Expression magnitude; private final TemporalUnit unit; private final BasicValuedMapping type; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/DurationUnit.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/DurationUnit.java index 26da7ec3c4b9..036432b3914f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/DurationUnit.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/DurationUnit.java @@ -22,8 +22,8 @@ * @author Gavin King */ public class DurationUnit implements Expression, SqlAstNode { - private TemporalUnit unit; - private BasicValuedMapping type; + private final TemporalUnit unit; + private final BasicValuedMapping type; public DurationUnit(TemporalUnit unit, BasicValuedMapping type) { this.unit = unit; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/AbstractTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/AbstractTableGroup.java index bb2dc697a243..310a2aebd390 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/AbstractTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/AbstractTableGroup.java @@ -23,7 +23,7 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifier implements TableGroup { private final NavigablePath navigablePath; private final TableGroupProducer producer; - private final LockMode lockMode; + private final String sourceAlias; private final SqlAliasBase sqlAliasBase; private List tableGroupJoins; @@ -35,24 +35,24 @@ public abstract class AbstractTableGroup extends AbstractColumnReferenceQualifie public AbstractTableGroup( NavigablePath navigablePath, TableGroupProducer producer, - LockMode lockMode, + String sourceAlias, SqlAliasBase sqlAliasBase, SessionFactoryImplementor sessionFactory) { - this( navigablePath, producer, lockMode, sqlAliasBase, false, sessionFactory ); + this( navigablePath, producer, sourceAlias, sqlAliasBase, false, sessionFactory ); } @SuppressWarnings("WeakerAccess") public AbstractTableGroup( NavigablePath navigablePath, TableGroupProducer producer, - LockMode lockMode, + String sourceAlias, SqlAliasBase sqlAliasBase, boolean isInnerJoinPossible, SessionFactoryImplementor sessionFactory) { super(); this.navigablePath = navigablePath; this.producer = producer; - this.lockMode = lockMode; + this.sourceAlias = sourceAlias; this.sqlAliasBase = sqlAliasBase; this.isInnerJoinPossible = isInnerJoinPossible; this.sessionFactory = sessionFactory; @@ -83,8 +83,8 @@ public ModelPart getExpressionType() { } @Override - public LockMode getLockMode() { - return lockMode; + public String getSourceAlias() { + return sourceAlias; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CompositeTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CompositeTableGroup.java index 13d63df79cb2..bf010f21d8d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CompositeTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CompositeTableGroup.java @@ -57,8 +57,8 @@ public EmbeddableValuedModelPart getModelPart() { } @Override - public LockMode getLockMode() { - return underlyingTableGroup.getLockMode(); + public String getSourceAlias() { + return underlyingTableGroup.getSourceAlias(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CorrelatedTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CorrelatedTableGroup.java index 176993e98276..e756fb46f491 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CorrelatedTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/CorrelatedTableGroup.java @@ -39,7 +39,7 @@ public CorrelatedTableGroup( super( correlatedTableGroup.getNavigablePath(), (TableGroupProducer) correlatedTableGroup.getExpressionType(), - LockMode.NONE, + null, sqlAliasBase, sessionFactory ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/FromClause.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/FromClause.java index b689d5c2914b..a8f98ecb4b81 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/FromClause.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/FromClause.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; +import java.util.function.Function; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.sql.ast.SqlAstWalker; @@ -42,6 +43,76 @@ public void visitRoots(Consumer action) { roots.forEach( action ); } + public void visitTableGroups(Consumer action) { + for ( int i = 0; i < roots.size(); i++ ) { + visitTableGroups( roots.get( i ), action ); + } + } + + private void visitTableGroups(TableGroup tableGroup, Consumer action) { + action.accept( tableGroup ); + final List tableGroupJoins = tableGroup.getTableGroupJoins(); + for ( int i = 0; i < tableGroupJoins.size(); i++ ) { + visitTableGroups( tableGroupJoins.get( i ).getJoinedGroup(), action ); + } + } + + public T queryTableGroups(Function action) { + for ( int i = 0; i < roots.size(); i++ ) { + final T result = queryTableGroups( roots.get( i ), action ); + if ( result != null ) { + return result; + } + } + return null; + } + + private T queryTableGroups(TableGroup tableGroup, Function action) { + final T result = action.apply( tableGroup ); + if ( result != null ) { + return result; + } + final List tableGroupJoins = tableGroup.getTableGroupJoins(); + for ( int i = 0; i < tableGroupJoins.size(); i++ ) { + final T nestedResult = queryTableGroups( tableGroupJoins.get( i ).getJoinedGroup(), action ); + if ( nestedResult != null ) { + return nestedResult; + } + } + return null; + } + + public void visitTableJoins(Consumer action) { + for ( int i = 0; i < roots.size(); i++ ) { + visitTableJoins( roots.get( i ), action ); + } + } + + private void visitTableJoins(TableGroup tableGroup, Consumer action) { + tableGroup.getTableReferenceJoins().forEach( action ); + final List tableGroupJoins = tableGroup.getTableGroupJoins(); + for ( int i = 0; i < tableGroupJoins.size(); i++ ) { + final TableGroupJoin tableGroupJoin = tableGroupJoins.get( i ); + action.accept( tableGroupJoin ); + visitTableJoins( tableGroupJoin.getJoinedGroup(), action ); + } + } + + public void visitTableGroupJoins(Consumer action) { + for ( int i = 0; i < roots.size(); i++ ) { + visitTableGroupJoins( roots.get( i ), action ); + } + } + + private void visitTableGroupJoins(TableGroup tableGroup, Consumer action) { + final List tableGroupJoins = tableGroup.getTableGroupJoins(); + for ( int i = 0; i < tableGroupJoins.size(); i++ ) { + final TableGroupJoin tableGroupJoin = tableGroupJoins.get( i ); + action.accept( tableGroupJoin ); + visitTableGroupJoins( tableGroupJoin.getJoinedGroup(), action ); + } + } + @Override public void accept(SqlAstWalker sqlTreeWalker) { sqlTreeWalker.visitFromClause( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/LazyTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/LazyTableGroup.java index 81cdaa384a66..c3fde913be33 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/LazyTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/LazyTableGroup.java @@ -25,7 +25,7 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements private final NavigablePath navigablePath; private final TableGroupProducer producer; - private final LockMode lockMode; + private final String sourceAlias; private final SqlAliasBase sqlAliasBase; private final SessionFactoryImplementor sessionFactory; private final Supplier tableGroupSupplier; @@ -39,13 +39,13 @@ public LazyTableGroup( Supplier tableGroupSupplier, Predicate navigablePathChecker, TableGroupProducer tableGroupProducer, - LockMode lockMode, + String sourceAlias, SqlAliasBase sqlAliasBase, SessionFactoryImplementor sessionFactory, TableGroup parentTableGroup) { this.navigablePath = navigablePath; this.producer = tableGroupProducer; - this.lockMode = lockMode; + this.sourceAlias = sourceAlias; this.sqlAliasBase = sqlAliasBase; this.tableGroupSupplier = tableGroupSupplier; this.navigablePathChecker = navigablePathChecker; @@ -133,8 +133,8 @@ public ModelPart getExpressionType() { } @Override - public LockMode getLockMode() { - return lockMode; + public String getSourceAlias() { + return sourceAlias; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/MutatingTableReferenceGroupWrapper.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/MutatingTableReferenceGroupWrapper.java index bb0c190c9d2b..ca31241de106 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/MutatingTableReferenceGroupWrapper.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/MutatingTableReferenceGroupWrapper.java @@ -78,8 +78,8 @@ public void applyAffectedTableNames(Consumer nameCollector) { } @Override - public LockMode getLockMode() { - return LockMode.WRITE; + public String getSourceAlias() { + return null; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/RootTableGroupProducer.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/RootTableGroupProducer.java index c43f54b970f7..a4d720ab3564 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/RootTableGroupProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/RootTableGroupProducer.java @@ -29,7 +29,6 @@ public interface RootTableGroupProducer extends TableGroupProducer, ModelPartCon TableGroup createRootTableGroup( NavigablePath navigablePath, String explicitSourceAlias, - LockMode lockMode, Supplier> additionalPredicateCollectorAccess, SqlAstCreationState creationState, SqlAstCreationContext creationContext); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/StandardTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/StandardTableGroup.java index 0ead9b5dbbc0..f124124d4dd8 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/StandardTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/StandardTableGroup.java @@ -33,11 +33,11 @@ public class StandardTableGroup extends AbstractTableGroup { public StandardTableGroup( NavigablePath navigablePath, TableGroupProducer tableGroupProducer, - LockMode lockMode, + String sourceAlias, TableReference primaryTableReference, SqlAliasBase sqlAliasBase, SessionFactoryImplementor sessionFactory) { - super( navigablePath, tableGroupProducer, lockMode, sqlAliasBase, sessionFactory ); + super( navigablePath, tableGroupProducer, sourceAlias, sqlAliasBase, sessionFactory ); this.primaryTableReference = primaryTableReference; this.realTableGroup = false; this.fetched = false; @@ -56,14 +56,14 @@ public StandardTableGroup( public StandardTableGroup( NavigablePath navigablePath, TableGroupProducer tableGroupProducer, - LockMode lockMode, + String sourceAlias, TableReference primaryTableReference, boolean realTableGroup, SqlAliasBase sqlAliasBase, Predicate tableReferenceJoinNameChecker, BiFunction tableReferenceJoinCreator, SessionFactoryImplementor sessionFactory) { - super( navigablePath, tableGroupProducer, lockMode, sqlAliasBase, sessionFactory ); + super( navigablePath, tableGroupProducer, sourceAlias, sqlAliasBase, sessionFactory ); this.primaryTableReference = primaryTableReference; this.realTableGroup = realTableGroup; this.fetched = false; @@ -76,14 +76,14 @@ public StandardTableGroup( NavigablePath navigablePath, TableGroupProducer tableGroupProducer, boolean fetched, - LockMode lockMode, + String sourceAlias, TableReference primaryTableReference, boolean realTableGroup, SqlAliasBase sqlAliasBase, Predicate tableReferenceJoinNameChecker, BiFunction tableReferenceJoinCreator, SessionFactoryImplementor sessionFactory) { - super( navigablePath, tableGroupProducer, lockMode, sqlAliasBase, sessionFactory ); + super( navigablePath, tableGroupProducer, sourceAlias, sqlAliasBase, sessionFactory ); this.primaryTableReference = primaryTableReference; this.realTableGroup = realTableGroup; this.fetched = fetched; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroup.java index bb6709bf1795..ed598da0c28b 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroup.java @@ -38,7 +38,7 @@ public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, SqmPat ModelPartContainer getModelPart(); - LockMode getLockMode(); + String getSourceAlias(); List getTableGroupJoins(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroupJoin.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroupJoin.java index 20042fbfef07..82f72800d0fc 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroupJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroupJoin.java @@ -19,7 +19,7 @@ /** * @author Steve Ebersole */ -public class TableGroupJoin implements SqlAstNode, DomainResultProducer { +public class TableGroupJoin implements TableJoin, DomainResultProducer { private final NavigablePath navigablePath; private final SqlAstJoinType sqlAstJoinType; private final TableGroup joinedGroup; @@ -44,6 +44,7 @@ public TableGroupJoin( this( navigablePath, sqlAstJoinType, joinedGroup, null ); } + @Override public SqlAstJoinType getJoinType() { return sqlAstJoinType; } @@ -52,6 +53,12 @@ public TableGroup getJoinedGroup() { return joinedGroup; } + @Override + public SqlAstNode getJoinedNode() { + return joinedGroup; + } + + @Override public Predicate getPredicate() { return predicate; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroupJoinProducer.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroupJoinProducer.java index 9940b0e9a2bf..31cc09198383 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroupJoinProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableGroupJoinProducer.java @@ -27,7 +27,6 @@ default TableGroupJoin createTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAstCreationState creationState) { return createTableGroupJoin( navigablePath, @@ -35,7 +34,6 @@ default TableGroupJoin createTableGroupJoin( explicitSourceAlias, sqlAstJoinType, fetched, - lockMode, creationState.getSqlAliasBaseGenerator(), creationState.getSqlExpressionResolver(), creationState.getCreationContext() @@ -51,7 +49,6 @@ TableGroupJoin createTableGroupJoin( String explicitSourceAlias, SqlAstJoinType sqlAstJoinType, boolean fetched, - LockMode lockMode, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, SqlAstCreationContext creationContext); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableJoin.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableJoin.java new file mode 100644 index 000000000000..a28b9793fa8a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableJoin.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.sql.ast.tree.from; + +import org.hibernate.sql.ast.SqlAstJoinType; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.sql.ast.tree.predicate.Predicate; + +/** + * The commonalities between {@link TableGroupJoin} and {@link TableReferenceJoin}. + * + * @author Christian Beikov + */ +public interface TableJoin extends SqlAstNode { + SqlAstJoinType getJoinType(); + Predicate getPredicate(); + SqlAstNode getJoinedNode(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableReferenceJoin.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableReferenceJoin.java index 87c5aee60012..22488ed6b4d3 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableReferenceJoin.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/TableReferenceJoin.java @@ -18,7 +18,7 @@ * * @author Steve Ebersole */ -public class TableReferenceJoin implements SqlAstNode, PredicateContainer { +public class TableReferenceJoin implements TableJoin, PredicateContainer { private final SqlAstJoinType sqlAstJoinType; private final TableReference joinedTableBinding; private Predicate predicate; @@ -35,6 +35,7 @@ public TableReferenceJoin(SqlAstJoinType sqlAstJoinType, TableReference joinedTa // } } + @Override public SqlAstJoinType getJoinType() { return sqlAstJoinType; } @@ -43,7 +44,13 @@ public TableReference getJoinedTableReference() { return joinedTableBinding; } - public Predicate getJoinPredicate() { + @Override + public SqlAstNode getJoinedNode() { + return joinedTableBinding; + } + + @Override + public Predicate getPredicate() { return predicate; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/UnionTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/UnionTableGroup.java index 2380441738ab..15d6f8a1df24 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/UnionTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/from/UnionTableGroup.java @@ -25,15 +25,18 @@ public class UnionTableGroup implements VirtualTableGroup { private List tableGroupJoins; private final UnionSubclassEntityPersister modelPart; + private final String sourceAlias; private final TableReference tableReference; public UnionTableGroup( NavigablePath navigablePath, TableReference tableReference, - UnionSubclassEntityPersister modelPart) { + UnionSubclassEntityPersister modelPart, + String sourceAlias) { this.navigablePath = navigablePath; this.tableReference = tableReference; this.modelPart = modelPart; + this.sourceAlias = sourceAlias; } @Override @@ -57,8 +60,8 @@ public ModelPartContainer getModelPart() { } @Override - public LockMode getLockMode() { - return LockMode.NONE; + public String getSourceAlias() { + return sourceAlias; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QueryPart.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QueryPart.java index 30b92d2d2b76..1d4ad7cabf3b 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QueryPart.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/select/QueryPart.java @@ -59,7 +59,7 @@ public List getSortSpecifications() { return sortSpecifications; } - void visitSortSpecifications(Consumer consumer) { + public void visitSortSpecifications(Consumer consumer) { if ( sortSpecifications != null ) { sortSpecifications.forEach( consumer ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/CallbackImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/CallbackImpl.java new file mode 100644 index 000000000000..da9b8e9b4578 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/CallbackImpl.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.exec.internal; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.loader.ast.spi.AfterLoadAction; +import org.hibernate.persister.entity.Loadable; +import org.hibernate.sql.exec.spi.Callback; + +/** + * @author Christian Beikov + */ +public class CallbackImpl implements Callback { + + private final List afterLoadActions; + + public CallbackImpl() { + this.afterLoadActions = new ArrayList<>( 1 ); + } + + @Override + public void registerAfterLoadAction(AfterLoadAction afterLoadAction) { + afterLoadActions.add( afterLoadAction ); + } + + @Override + public void invokeAfterLoadActions(SharedSessionContractImplementor session, Object entity, Loadable persister) { + for ( int i = 0; i < afterLoadActions.size(); i++ ) { + afterLoadActions.get( i ).afterLoad( session, entity, persister ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcSelectExecutorStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcSelectExecutorStandardImpl.java index 834e49e1bbfe..ca8918cd7b5e 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcSelectExecutorStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/internal/JdbcSelectExecutorStandardImpl.java @@ -7,7 +7,6 @@ package org.hibernate.sql.exec.internal; import java.sql.PreparedStatement; -import java.util.ArrayList; import java.util.List; import java.util.Spliterator; import java.util.Spliterators; @@ -16,17 +15,18 @@ import java.util.stream.StreamSupport; import org.hibernate.CacheMode; +import org.hibernate.LockOptions; import org.hibernate.ScrollMode; import org.hibernate.cache.spi.QueryKey; import org.hibernate.cache.spi.QueryResultsCache; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.loader.ast.spi.AfterLoadAction; import org.hibernate.query.internal.ScrollableResultsIterator; import org.hibernate.query.spi.ScrollableResultsImplementor; import org.hibernate.sql.exec.SqlExecLogger; import org.hibernate.sql.exec.spi.ExecutionContext; +import org.hibernate.sql.exec.spi.JdbcLockStrategy; import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcSelect; import org.hibernate.sql.exec.spi.JdbcSelectExecutor; @@ -166,16 +166,17 @@ private T doExecuteQuery( Function statementCreator, ResultsConsumer resultsConsumer) { + final DeferredResultSetAccess deferredResultSetAccess = new DeferredResultSetAccess( + jdbcSelect, + jdbcParameterBindings, + executionContext, + statementCreator + ); final JdbcValues jdbcValues = resolveJdbcValuesSource( jdbcSelect, resultsConsumer.canResultsBeCached(), executionContext, - new DeferredResultSetAccess( - jdbcSelect, - jdbcParameterBindings, - executionContext, - statementCreator - ) + deferredResultSetAccess ); /* @@ -209,11 +210,15 @@ public boolean shouldReturnProxies() { executionContext::registerLoadingEntityEntry ); - final List afterLoadActions = new ArrayList<>(); - final RowReader rowReader = ResultsHelper.createRowReader( - executionContext.getSession().getFactory(), - afterLoadActions::add, + executionContext, + // If follow on locking is used, we must omit the lock options here, + // because these lock options are only for Initializers. + // If we wouldn't omit this, the follow on lock requests would be no-ops, + // because the EntityEntrys would already have the desired lock mode + deferredResultSetAccess.usesFollowOnLocking() + ? LockOptions.NONE + : executionContext.getQueryOptions().getLockOptions(), rowTransformer, jdbcValues ); @@ -234,11 +239,6 @@ public boolean shouldReturnProxies() { rowReader ); - for ( AfterLoadAction afterLoadAction : afterLoadActions ) { - // todo (6.0) : see notes on - afterLoadAction.afterLoad( executionContext.getSession(), null, null ); - } - return result; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/AbstractJdbcOperation.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/AbstractJdbcOperation.java new file mode 100644 index 000000000000..6811aed571a2 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/AbstractJdbcOperation.java @@ -0,0 +1,100 @@ +/* + * 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.exec.spi; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.hibernate.internal.FilterJdbcParameter; +import org.hibernate.query.spi.QueryOptions; +import org.hibernate.sql.ast.tree.expression.JdbcParameter; + +/** + * Executable JDBC command + * + * @author Steve Ebersole + */ +public class AbstractJdbcOperation implements JdbcOperation { + protected final String sql; + protected final List parameterBinders; + protected final Set affectedTableNames; + protected final Set filterJdbcParameters; + protected final Map appliedParameters; + + public AbstractJdbcOperation( + String sql, + List parameterBinders, + Set affectedTableNames, + Set filterJdbcParameters) { + this( + sql, + parameterBinders, + affectedTableNames, + filterJdbcParameters, + Collections.emptyMap() + ); + } + + public AbstractJdbcOperation( + String sql, + List parameterBinders, + Set affectedTableNames, + Set filterJdbcParameters, + Map appliedParameters) { + this.sql = sql; + this.parameterBinders = parameterBinders; + this.affectedTableNames = affectedTableNames; + this.filterJdbcParameters = filterJdbcParameters; + this.appliedParameters = appliedParameters; + } + + @Override + public String getSql() { + return sql; + } + + @Override + public List getParameterBinders() { + return parameterBinders; + } + + @Override + public Set getAffectedTableNames() { + return affectedTableNames; + } + + @Override + public Set getFilterJdbcParameters() { + return filterJdbcParameters; + } + + @Override + public boolean dependsOnParameterBindings() { + return !appliedParameters.isEmpty(); + } + + @Override + public boolean isCompatibleWith(JdbcParameterBindings jdbcParameterBindings, QueryOptions queryOptions) { + if ( !appliedParameters.isEmpty() ) { + if ( jdbcParameterBindings == null ) { + return false; + } + for ( Map.Entry entry : appliedParameters.entrySet() ) { + final JdbcParameterBinding binding = jdbcParameterBindings.getBinding( entry.getKey() ); + final JdbcParameterBinding appliedBinding = entry.getValue(); + if ( binding == null || !appliedBinding.getBindType() + .getJavaTypeDescriptor() + .areEqual( binding.getBindValue(), appliedBinding.getBindValue() ) ) { + return false; + } + } + } + return true; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/Callback.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/Callback.java index c34106e414da..d1b960658fac 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/Callback.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/Callback.java @@ -7,7 +7,9 @@ package org.hibernate.sql.exec.spi; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.loader.ast.spi.AfterLoadAction; +import org.hibernate.persister.entity.Loadable; /** * Callback to allow SQM interpretation to trigger certain things within ORM. See the current @@ -18,4 +20,6 @@ */ public interface Callback { void registerAfterLoadAction(AfterLoadAction afterLoadAction); + + void invokeAfterLoadActions(SharedSessionContractImplementor session, Object entity, Loadable persister); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/ExecutionContext.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/ExecutionContext.java index 61794b1c0c90..7955d4803fbf 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/ExecutionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/ExecutionContext.java @@ -10,6 +10,7 @@ import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.entity.Loadable; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor; @@ -32,6 +33,10 @@ default LoadQueryInfluencers getLoadQueryInfluencers() { Callback getCallback(); + default void invokeAfterLoadActions(SharedSessionContractImplementor session, Object entity, Loadable persister) { + // No-op because by default there is callback + } + /** * Get the collection key for the collection which is to be loaded immediately. */ diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcDelete.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcDelete.java index 7ba05bb84ee4..ca20e59b08de 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcDelete.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcDelete.java @@ -6,8 +6,25 @@ */ package org.hibernate.sql.exec.spi; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.hibernate.LockOptions; +import org.hibernate.internal.FilterJdbcParameter; +import org.hibernate.sql.ast.tree.expression.JdbcParameter; + /** * @author Steve Ebersole */ -public interface JdbcDelete extends JdbcMutation { +public class JdbcDelete extends AbstractJdbcOperation implements JdbcMutation { + + public JdbcDelete( + String sql, + List parameterBinders, + Set affectedTableNames, + Set filterJdbcParameters, + Map appliedParameters) { + super( sql, parameterBinders, affectedTableNames, filterJdbcParameters, appliedParameters ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcInsert.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcInsert.java index ea01d9081cdd..24bcbc2ed881 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcInsert.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcInsert.java @@ -6,8 +6,25 @@ */ package org.hibernate.sql.exec.spi; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.hibernate.LockOptions; +import org.hibernate.internal.FilterJdbcParameter; +import org.hibernate.sql.ast.tree.expression.JdbcParameter; + /** * @author Steve Ebersole */ -public interface JdbcInsert extends JdbcMutation { +public class JdbcInsert extends AbstractJdbcOperation implements JdbcMutation { + + public JdbcInsert( + String sql, + List parameterBinders, + Set affectedTableNames, + Set filterJdbcParameters, + Map appliedParameters) { + super( sql, parameterBinders, affectedTableNames, filterJdbcParameters, appliedParameters ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcLockStrategy.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcLockStrategy.java new file mode 100644 index 000000000000..f6aee4ef8ef7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcLockStrategy.java @@ -0,0 +1,28 @@ +/* + * 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.exec.spi; + +/** + * The strategy to use for applying locks to a {@link JdbcSelect}. + * + * @author Christian Beikov + */ +public enum JdbcLockStrategy { + + /** + * Use a dialect specific check to determine how to apply locks. + */ + AUTO, + /** + * Use follow on locking. + */ + FOLLOW_ON, + /** + * Do not apply locks. + */ + NONE; +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcOperation.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcOperation.java index 917db07f1fa2..4186efd15a45 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcOperation.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcOperation.java @@ -38,15 +38,9 @@ public interface JdbcOperation { * Signals that the SQL depends on the parameter bindings e.g. due to the need for inlining * of parameter values or multiValued parameters. */ - default boolean dependsOnParameterBindings() { - return false; - } + boolean dependsOnParameterBindings(); - default boolean isCompatibleWith( - JdbcParameterBindings jdbcParameterBindings, - QueryOptions queryOptions) { - return true; - } + boolean isCompatibleWith(JdbcParameterBindings jdbcParameterBindings, QueryOptions queryOptions); default void bindFilterJdbcParameters(JdbcParameterBindings jdbcParameterBindings) { if ( CollectionHelper.isNotEmpty( getFilterJdbcParameters() ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcSelect.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcSelect.java index 48c5b885b794..03e006e32d67 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcSelect.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcSelect.java @@ -11,31 +11,24 @@ import java.util.Map; import java.util.Set; -import org.hibernate.LockOptions; import org.hibernate.internal.FilterJdbcParameter; import org.hibernate.query.Limit; import org.hibernate.query.spi.QueryOptions; import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * Executable JDBC command * * @author Steve Ebersole */ -public class JdbcSelect implements JdbcOperation { - private final String sql; - private final List parameterBinders; +public class JdbcSelect extends AbstractJdbcOperation { private final JdbcValuesMappingProducer jdbcValuesMappingProducer; - private final Set affectedTableNames; - private final Set filterJdbcParameters; private final int rowsToSkip; private final int maxRows; - private final Map appliedParameters; - private final LockOptions appliedLockOptions; private final JdbcParameter offsetParameter; private final JdbcParameter limitParameter; + private final JdbcLockStrategy jdbcLockStrategy; public JdbcSelect( String sql, @@ -52,7 +45,7 @@ public JdbcSelect( 0, Integer.MAX_VALUE, Collections.emptyMap(), - null, + JdbcLockStrategy.AUTO, null, null ); @@ -67,42 +60,18 @@ public JdbcSelect( int rowsToSkip, int maxRows, Map appliedParameters, - LockOptions appliedLockOptions, + JdbcLockStrategy jdbcLockStrategy, JdbcParameter offsetParameter, JdbcParameter limitParameter) { - this.sql = sql; - this.parameterBinders = parameterBinders; + super( sql, parameterBinders, affectedTableNames, filterJdbcParameters, appliedParameters ); this.jdbcValuesMappingProducer = jdbcValuesMappingProducer; - this.affectedTableNames = affectedTableNames; - this.filterJdbcParameters = filterJdbcParameters; this.rowsToSkip = rowsToSkip; this.maxRows = maxRows; - this.appliedParameters = appliedParameters; - this.appliedLockOptions = appliedLockOptions; + this.jdbcLockStrategy = jdbcLockStrategy; this.offsetParameter = offsetParameter; this.limitParameter = limitParameter; } - @Override - public String getSql() { - return sql; - } - - @Override - public List getParameterBinders() { - return parameterBinders; - } - - @Override - public Set getAffectedTableNames() { - return affectedTableNames; - } - - @Override - public Set getFilterJdbcParameters() { - return filterJdbcParameters; - } - public JdbcValuesMappingProducer getJdbcValuesMappingProducer() { return jdbcValuesMappingProducer; } @@ -119,9 +88,8 @@ public boolean usesLimitParameters() { return offsetParameter != null || limitParameter != null; } - @Override - public boolean dependsOnParameterBindings() { - return !appliedParameters.isEmpty(); + public JdbcLockStrategy getLockStrategy() { + return jdbcLockStrategy; } @Override @@ -132,10 +100,30 @@ public boolean isCompatibleWith(JdbcParameterBindings jdbcParameterBindings, Que } for ( Map.Entry entry : appliedParameters.entrySet() ) { final JdbcParameter parameter = entry.getKey(); + final JdbcParameterBinding appliedBinding = entry.getValue(); + // This is a special case where the rendered SQL depends on the presence of the parameter, + // but not specifically on the value. In this case we have to re-generate the SQL if we can't find a binding + // The need for this can be tested with the OracleFollowOnLockingTest#testPessimisticLockWithMaxResultsThenNoFollowOnLocking + // Since the Limit is not part of the query plan cache key, but this has an effect on follow on locking, + // we must treat the absence of Limit parameters, when they were considered for locking, as incompatible + if ( appliedBinding == null ) { + if ( parameter == offsetParameter ) { + if ( queryOptions.getLimit() == null || queryOptions.getLimit().getFirstRowJpa() == 0 ) { + return false; + } + } + else if ( parameter == limitParameter ) { + if ( queryOptions.getLimit() == null || queryOptions.getLimit().getMaxRowsJpa() == Integer.MAX_VALUE ) { + return false; + } + } + else if ( jdbcParameterBindings.getBinding( parameter ) == null ) { + return false; + } + } // We handle limit and offset parameters below if ( parameter != offsetParameter && parameter != limitParameter ) { - final JdbcParameterBinding binding = jdbcParameterBindings.getBinding( entry.getKey() ); - final JdbcParameterBinding appliedBinding = entry.getValue(); + final JdbcParameterBinding binding = jdbcParameterBindings.getBinding( parameter ); if ( binding == null || !appliedBinding.getBindType() .getJavaTypeDescriptor() .areEqual( binding.getBindValue(), appliedBinding.getBindValue() ) ) { @@ -144,15 +132,6 @@ public boolean isCompatibleWith(JdbcParameterBindings jdbcParameterBindings, Que } } } - final LockOptions lockOptions = queryOptions.getLockOptions(); - if ( appliedLockOptions == null ) { - if ( lockOptions != null && !lockOptions.isEmpty() ) { - return false; - } - } - else if ( !appliedLockOptions.isCompatible( lockOptions ) ) { - return false; - } final Limit limit = queryOptions.getLimit(); if ( offsetParameter == null && limitParameter == null ) { if ( limit != null && !limit.isEmpty() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcUpdate.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcUpdate.java index 2e8d3cedbd32..14318edcf4ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcUpdate.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/JdbcUpdate.java @@ -6,8 +6,25 @@ */ package org.hibernate.sql.exec.spi; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.hibernate.LockOptions; +import org.hibernate.internal.FilterJdbcParameter; +import org.hibernate.sql.ast.tree.expression.JdbcParameter; + /** * @author Steve Ebersole */ -public interface JdbcUpdate extends JdbcMutation { +public class JdbcUpdate extends AbstractJdbcOperation implements JdbcMutation { + + public JdbcUpdate( + String sql, + List parameterBinders, + Set affectedTableNames, + Set filterJdbcParameters, + Map appliedParameters) { + super( sql, parameterBinders, affectedTableNames, filterJdbcParameters, appliedParameters ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/NativeJdbcMutation.java b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/NativeJdbcMutation.java index 1faab969132e..72608491d190 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/NativeJdbcMutation.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/exec/spi/NativeJdbcMutation.java @@ -11,6 +11,7 @@ import java.util.Set; import org.hibernate.internal.FilterJdbcParameter; +import org.hibernate.query.spi.QueryOptions; /** * Executable JDBC command @@ -51,4 +52,13 @@ public Set getFilterJdbcParameters() { return Collections.EMPTY_SET; } + @Override + public boolean dependsOnParameterBindings() { + return false; + } + + @Override + public boolean isCompatibleWith(JdbcParameterBindings jdbcParameterBindings, QueryOptions queryOptions) { + return true; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/AssemblerCreationState.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/AssemblerCreationState.java index 4e129e89d647..6f500f7675de 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/AssemblerCreationState.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/AssemblerCreationState.java @@ -8,6 +8,7 @@ import java.util.function.Supplier; +import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.query.NavigablePath; import org.hibernate.sql.ast.spi.SqlAstCreationContext; @@ -17,6 +18,8 @@ */ public interface AssemblerCreationState { + LockMode determineEffectiveLockMode(String identificationVariable); + Initializer resolveInitializer( NavigablePath navigablePath, ModelPart fetchedModelPart, diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchParent.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchParent.java index d3ebc1523aeb..34097a1131c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchParent.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchParent.java @@ -76,7 +76,6 @@ default Fetch generateFetchableFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { return fetchable.generateFetch( @@ -84,7 +83,6 @@ default Fetch generateFetchableFetch( fetchablePath, fetchTiming, selected, - lockMode, resultVariable, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/Fetchable.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/Fetchable.java index 32011e75cad1..089d4857981c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/Fetchable.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/Fetchable.java @@ -31,7 +31,6 @@ Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/CollectionDomainResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/CollectionDomainResult.java index e6c115175588..9564efb03f3a 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/CollectionDomainResult.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/CollectionDomainResult.java @@ -63,7 +63,6 @@ public CollectionDomainResult( this, true, null, - LockMode.READ, creationState ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EagerCollectionFetch.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EagerCollectionFetch.java index 4afde5012cc1..a61061783223 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EagerCollectionFetch.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EagerCollectionFetch.java @@ -8,14 +8,12 @@ import java.util.List; -import org.hibernate.LockMode; import org.hibernate.collection.spi.CollectionInitializerProducer; import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.metamodel.mapping.internal.EntityCollectionPart; import org.hibernate.query.NavigablePath; import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.tree.from.TableGroup; @@ -29,7 +27,6 @@ import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.collection.CollectionInitializer; -import org.hibernate.sql.results.graph.entity.EntityFetch; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** @@ -136,8 +133,6 @@ public EagerCollectionFetch( fetchParent, true, null, - // todo (6.0) : we need to propagate these lock modes - LockMode.READ, indexFetch, elementFetch, creationState diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EntityCollectionPartTableGroup.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EntityCollectionPartTableGroup.java index 8ce35e9e8cab..5f12b617172e 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EntityCollectionPartTableGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EntityCollectionPartTableGroup.java @@ -57,8 +57,8 @@ public EntityCollectionPart getModelPart() { } @Override - public LockMode getLockMode() { - return collectionTableGroup.getLockMode(); + public String getSourceAlias() { + return collectionTableGroup.getSourceAlias(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableFetchImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableFetchImpl.java index 6d43bbf855b8..9ff2aba1e876 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableFetchImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableFetchImpl.java @@ -6,7 +6,6 @@ */ package org.hibernate.sql.results.graph.embeddable.internal; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; @@ -67,7 +66,6 @@ public EmbeddableFetchImpl( null, nullable ? SqlAstJoinType.LEFT : SqlAstJoinType.INNER, true, - LockMode.NONE, creationState.getSqlAstCreationState() ); return tableGroupJoin.getJoinedGroup(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableForeignKeyResultImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableForeignKeyResultImpl.java index 7198f80f57d2..6025d66c1bfe 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableForeignKeyResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableForeignKeyResultImpl.java @@ -6,7 +6,6 @@ */ package org.hibernate.sql.results.graph.embeddable.internal; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; @@ -59,7 +58,6 @@ public Fetch generateFetchableFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { final boolean shouldSelect; @@ -78,7 +76,6 @@ public Fetch generateFetchableFetch( fetchablePath, fetchTiming, shouldSelect, - lockMode, resultVariable, creationState ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableResultImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableResultImpl.java index 93716d34c849..c79ab22a5f74 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableResultImpl.java @@ -8,7 +8,6 @@ import java.util.List; -import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.query.NavigablePath; @@ -53,7 +52,6 @@ public EmbeddableResultImpl( resultVariable, SqlAstJoinType.INNER, true, - LockMode.NONE, creationState.getSqlAstCreationState() ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java index 4e1b024b7c70..265ecdb59494 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java @@ -12,7 +12,9 @@ import java.util.Map; import java.util.function.Supplier; +import org.hibernate.HibernateException; import org.hibernate.LockMode; +import org.hibernate.StaleObjectStateException; import org.hibernate.WrongClassException; import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cache.spi.entry.CacheEntry; @@ -48,7 +50,9 @@ import org.hibernate.sql.results.internal.NullValueAssembler; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; +import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.type.TypeHelper; +import org.hibernate.type.VersionType; import static org.hibernate.internal.log.LoggingHelper.toLoggableString; @@ -114,10 +118,16 @@ protected AbstractEntityInitializer( this.navigablePath = navigablePath; this.lockMode = lockMode; + assert lockMode != null; if ( identifierResult != null ) { this.identifierAssembler = identifierResult.createResultAssembler( new AssemblerCreationState() { + @Override + public LockMode determineEffectiveLockMode(String identificationVariable) { + return creationState.determineEffectiveLockMode( identificationVariable ); + } + @Override public Initializer resolveInitializer( NavigablePath navigablePath, @@ -468,7 +478,6 @@ public void resolveInstance(RowProcessingState rowProcessingState) { entityInstance = existingEntity; } else { - // look to see if another initializer from a parent load context or an earlier // initializer is already loading the entity if ( entityInstance == null ) { @@ -481,12 +490,47 @@ public void resolveInstance(RowProcessingState rowProcessingState) { } } + + if ( LockMode.NONE != lockMode ) { + final EntityEntry entry = session.getPersistenceContextInternal().getEntry( entityInstance ); + if ( entry != null && entry.getLockMode().lessThan( lockMode ) ) { + //we only check the version when _upgrading_ lock modes + if ( versionAssembler != null ) { + checkVersion( entry, rowProcessingState ); + } + //we need to upgrade the lock mode to the mode requested + entry.setLockMode( lockMode ); + } + } } notifyParentResolutionListeners( entityInstance ); preLoad( rowProcessingState ); } + /** + * Check the version of the object in the RowProcessingState against + * the object version in the session cache, throwing an exception + * if the version numbers are different + */ + private void checkVersion(EntityEntry entry, final RowProcessingState rowProcessingState) throws HibernateException { + final Object version = entry.getVersion(); + + if ( version != null ) { + // null version means the object is in the process of being loaded somewhere else in the ResultSet + final VersionType versionType = concreteDescriptor.getVersionType(); + final Object currentVersion = versionAssembler.assemble( rowProcessingState ); + if ( !versionType.isEqual( version, currentVersion ) ) { + final StatisticsImplementor statistics = rowProcessingState.getSession().getFactory().getStatistics(); + if ( statistics.isStatisticsEnabled() ) { + statistics.optimisticFailure( concreteDescriptor.getEntityName() ); + } + throw new StaleObjectStateException( concreteDescriptor.getEntityName(), entry.getId() ); + } + } + + } + protected Object getProxy(PersistenceContext persistenceContext) { return persistenceContext.getProxy( entityKey ); } @@ -666,6 +710,11 @@ private void initializeEntity( else { rowId = null; } + // from the perspective of Hibernate, an entity is read locked as soon as it is read + // so regardless of the requested lock mode, we upgrade to at least the read level + final LockMode lockModeToAcquire = lockMode == LockMode.NONE + ? LockMode.READ + : lockMode; final EntityEntry entityEntry = persistenceContext.addEntry( toInitialize, @@ -674,7 +723,7 @@ private void initializeEntity( rowId, entityKey.getIdentifier(), version, - lockMode, + lockModeToAcquire, true, concreteDescriptor, false diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java index e018f9295577..e74f94770589 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java @@ -39,28 +39,24 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent private final DomainResult discriminatorResult; private final DomainResult versionResult; private final DomainResult rowIdResult; - private final LockMode lockMode; private final EntityMappingType targetType; public AbstractEntityResultGraphNode( EntityValuedModelPart referencedModelPart, - LockMode lockMode, NavigablePath navigablePath, DomainResultCreationState creationState) { - this( referencedModelPart, lockMode, navigablePath, null, creationState ); + this( referencedModelPart, navigablePath, null, creationState ); } @SuppressWarnings("WeakerAccess") public AbstractEntityResultGraphNode( EntityValuedModelPart referencedModelPart, - LockMode lockMode, NavigablePath navigablePath, EntityMappingType targetType, DomainResultCreationState creationState) { super( referencedModelPart.getEntityMappingType(), navigablePath ); this.referencedModelPart = referencedModelPart; - this.lockMode = lockMode; this.targetType = targetType; final EntityMappingType entityDescriptor = referencedModelPart.getEntityMappingType(); @@ -205,10 +201,6 @@ public JavaTypeDescriptor getResultJavaTypeDescriptor() { return getEntityValuedModelPart().getEntityMappingType().getMappedJavaTypeDescriptor(); } - public LockMode getLockMode() { - return lockMode; - } - public DomainResult getIdentifierResult() { return identifierResult; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/EntityValuedFetchable.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/EntityValuedFetchable.java index df8d5d284db0..630f4bd9f64c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/EntityValuedFetchable.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/EntityValuedFetchable.java @@ -6,7 +6,6 @@ */ package org.hibernate.sql.results.graph.entity; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.FetchParent; @@ -24,7 +23,6 @@ EntityFetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchJoinedImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchJoinedImpl.java index 1b2395633d64..891316887b77 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchJoinedImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchJoinedImpl.java @@ -6,7 +6,6 @@ */ package org.hibernate.sql.results.graph.entity.internal; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.query.NavigablePath; import org.hibernate.sql.ast.tree.from.TableGroup; @@ -25,19 +24,18 @@ public class EntityFetchJoinedImpl extends AbstractNonLazyEntityFetch { private final EntityResultImpl entityResult; - private final LockMode lockMode; + private final String sourceAlias; public EntityFetchJoinedImpl( FetchParent fetchParent, EntityValuedFetchable fetchedAttribute, TableGroup tableGroup, - LockMode lockMode, boolean nullable, NavigablePath navigablePath, DomainResultCreationState creationState) { super( fetchParent, fetchedAttribute, navigablePath, nullable ); - this.lockMode = lockMode; - entityResult = new EntityResultImpl( + this.sourceAlias = tableGroup.getSourceAlias(); + this.entityResult = new EntityResultImpl( navigablePath, fetchedAttribute, tableGroup, @@ -57,7 +55,7 @@ protected EntityInitializer getEntityInitializer( entityResult, getReferencedModePart(), getNavigablePath(), - lockMode, + creationState.determineEffectiveLockMode( sourceAlias ), entityResult.getIdentifierResult(), entityResult.getDiscriminatorResult(), entityResult.getVersionResult(), @@ -80,7 +78,4 @@ public EntityResultImpl getEntityResult() { return entityResult; } - public LockMode getLockMode() { - return lockMode; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultImpl.java index ab232028fe0d..e86e266c3fdf 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultImpl.java @@ -6,6 +6,7 @@ */ package org.hibernate.sql.results.graph.entity.internal; +import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityValuedModelPart; import org.hibernate.query.NavigablePath; @@ -49,7 +50,6 @@ public EntityResultImpl( DomainResultCreationState creationState) { super( entityValuedModelPart, - creationState.getSqlAstCreationState().determineLockMode( resultVariable ), navigablePath, creationState ); @@ -89,6 +89,10 @@ public String getResultVariable() { return resultVariable; } + protected LockMode getLockMode(AssemblerCreationState creationState) { + return creationState.determineEffectiveLockMode( tableGroup.getSourceAlias() ); + } + @Override public DomainResultAssembler createResultAssembler(AssemblerCreationState creationState) { final EntityInitializer initializer = (EntityInitializer) creationState.resolveInitializer( @@ -97,7 +101,7 @@ public DomainResultAssembler createResultAssembler(AssemblerCreationState creati () -> new EntityResultInitializer( this, getNavigablePath(), - getLockMode(), + getLockMode( creationState ), getIdentifierResult(), getDiscriminatorResult(), getVersionResult(), diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultJoinedSubclassImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultJoinedSubclassImpl.java index ae89166fbb78..86509f3d0335 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultJoinedSubclassImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultJoinedSubclassImpl.java @@ -38,7 +38,7 @@ public DomainResultAssembler createResultAssembler(AssemblerCreationState creati () -> new EntityResultInitializer( this, getNavigablePath(), - getLockMode(), + getLockMode( creationState ), getIdentifierResult(), getDiscriminatorResult(), getVersionResult(), diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/ResultsHelper.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/ResultsHelper.java index 88c87aec9056..fdf9940bcb1d 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/ResultsHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/ResultsHelper.java @@ -12,6 +12,8 @@ import java.util.Map; import java.util.function.Supplier; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.BatchFetchQueue; import org.hibernate.engine.spi.CollectionEntry; @@ -22,6 +24,7 @@ import org.hibernate.query.NavigablePath; import org.hibernate.sql.ast.spi.SqlAstCreationContext; import org.hibernate.sql.exec.spi.Callback; +import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.results.ResultsLogger; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResultAssembler; @@ -36,15 +39,20 @@ */ public class ResultsHelper { public static RowReader createRowReader( - SessionFactoryImplementor sessionFactory, - Callback callback, + ExecutionContext executionContext, + LockOptions lockOptions, RowTransformer rowTransformer, JdbcValues jdbcValues) { - final Map initializerMap = new LinkedHashMap<>(); + final Map initializerMap = new LinkedHashMap<>(); final List initializers = new ArrayList<>(); + final SessionFactoryImplementor sessionFactory = executionContext.getSession().getFactory(); final List> assemblers = jdbcValues.getValuesMapping().resolveAssemblers( new AssemblerCreationState() { + @Override + public LockMode determineEffectiveLockMode(String identificationVariable) { + return lockOptions.getEffectiveLockMode( identificationVariable ); + } @Override public Initializer resolveInitializer( @@ -86,8 +94,7 @@ public SqlAstCreationContext getSqlAstCreationContext() { return new StandardRowReader<>( (List) assemblers, initializers, - rowTransformer, - callback + rowTransformer ); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/RowProcessingStateStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/RowProcessingStateStandardImpl.java index b9d4f5d57208..c610808813e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/RowProcessingStateStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/RowProcessingStateStandardImpl.java @@ -149,7 +149,7 @@ public QueryParameterBindings getQueryParameterBindings() { @Override public Callback getCallback() { - return afterLoadAction -> {}; + return executionContext.getCallback(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java index 792a8aa1ef06..8e579908b34b 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java @@ -33,21 +33,18 @@ public class StandardRowReader implements RowReader { private final RowTransformer rowTransformer; private final int assemblerCount; - private final Callback callback; @SuppressWarnings("WeakerAccess") public StandardRowReader( List resultAssemblers, List initializers, - RowTransformer rowTransformer, - Callback callback) { + RowTransformer rowTransformer) { this.resultAssemblers = resultAssemblers; this.initializers = initializers; this.rowTransformer = rowTransformer; this.assemblerCount = resultAssemblers.size(); - this.callback = callback; logDebugInfo(); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularBiDirectionalFetchImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularBiDirectionalFetchImpl.java index 1f297845cbe7..f6b466e2c861 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularBiDirectionalFetchImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularBiDirectionalFetchImpl.java @@ -166,7 +166,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { throw new UnsupportedOperationException(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularFetchImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularFetchImpl.java index c9225350fa71..c42e7a856de8 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularFetchImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/domain/CircularFetchImpl.java @@ -6,7 +6,6 @@ */ package org.hibernate.sql.results.internal.domain; -import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.mapping.Association; @@ -195,7 +194,6 @@ public Fetch generateFetch( NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, - LockMode lockMode, String resultVariable, DomainResultCreationState creationState) { throw new UnsupportedOperationException(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java index a5b9810605b8..23c9812b3d86 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/DeferredResultSetAccess.java @@ -9,8 +9,10 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Collections; import java.util.function.Function; +import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.Session; import org.hibernate.dialect.Dialect; @@ -19,26 +21,32 @@ import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; import org.hibernate.query.Limit; import org.hibernate.query.spi.QueryOptions; import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor; import org.hibernate.sql.exec.spi.ExecutionContext; +import org.hibernate.sql.exec.spi.JdbcLockStrategy; import org.hibernate.sql.exec.spi.JdbcParameterBinder; import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcSelect; -import org.jboss.logging.Logger; - /** * @author Steve Ebersole */ public class DeferredResultSetAccess extends AbstractResultSetAccess { - private static final Logger log = CoreLogging.logger( DeferredResultSetAccess.class ); + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( + DeferredResultSetAccess.class + ); private final JdbcSelect jdbcSelect; private final JdbcParameterBindings jdbcParameterBindings; private final ExecutionContext executionContext; private final Function statementCreator; + private final String finalSql; + private final Limit limit; + private final LimitHandler limitHandler; + private final boolean usesFollowOnLocking; private PreparedStatement preparedStatement; private ResultSet resultSet; @@ -53,38 +61,18 @@ public DeferredResultSetAccess( this.executionContext = executionContext; this.jdbcSelect = jdbcSelect; this.statementCreator = statementCreator; - } - - @Override - public ResultSet getResultSet() { - if ( resultSet == null ) { - executeQuery(); - } - return resultSet; - } - - @Override - public SessionFactoryImplementor getFactory() { - return executionContext.getSession().getFactory(); - } - - private void executeQuery() { - final LogicalConnectionImplementor logicalConnection = getPersistenceContext().getJdbcCoordinator().getLogicalConnection(); - final JdbcServices jdbcServices = getPersistenceContext().getFactory().getServiceRegistry().getService( JdbcServices.class ); final QueryOptions queryOptions = executionContext.getQueryOptions(); - final String finalSql; - final Limit limit; - final LimitHandler limitHandler; if ( queryOptions == null ) { finalSql = jdbcSelect.getSql(); limit = null; limitHandler = NoopLimitHandler.NO_LIMIT; + usesFollowOnLocking = false; } else { // Note that limit and lock aren't set for SQM as that is applied during SQL rendering // But for native queries, we have to adapt the SQL string final Dialect dialect = executionContext.getSession().getJdbcServices().getDialect(); - final String sql; + String sql = jdbcSelect.getSql(); limit = queryOptions.getLimit(); if ( limit == null || limit.isEmpty() || jdbcSelect.usesLimitParameters() ) { sql = jdbcSelect.getSql(); @@ -99,15 +87,82 @@ private void executeQuery() { ); } + final LockOptions lockOptions = queryOptions.getLockOptions(); + boolean followOnLocking = false; + if ( lockOptions != null && !lockOptions.isEmpty() && jdbcSelect.getLockStrategy() != JdbcLockStrategy.NONE ) { + switch ( jdbcSelect.getLockStrategy() ) { + case FOLLOW_ON: + followOnLocking = true; + break; + case AUTO: + if ( lockOptions.getFollowOnLocking() == null && dialect.useFollowOnLocking( sql, queryOptions ) + || Boolean.TRUE.equals( lockOptions.getFollowOnLocking() ) ) { + followOnLocking = true; + } + break; + } + if ( followOnLocking ) { + final LockMode lockMode = determineFollowOnLockMode( lockOptions ); + if ( lockMode != LockMode.UPGRADE_SKIPLOCKED ) { + // Dialect prefers to perform locking in a separate step + if ( lockOptions.getLockMode() != LockMode.NONE ) { + LOG.usingFollowOnLocking(); + } + + final LockOptions lockOptionsToUse = new LockOptions( lockMode ); + lockOptionsToUse.setTimeOut( lockOptions.getTimeOut() ); + lockOptionsToUse.setScope( lockOptions.getScope() ); + + executionContext.getCallback().registerAfterLoadAction( + (session, entity, persister) -> { + ( (Session) session ).buildLockRequest( lockOptionsToUse ).lock( + persister.getEntityName(), + entity + ); + } + ); + } + } + else { + sql = dialect.applyLocksToSql( sql, lockOptions, Collections.emptyMap() ); + } + } + usesFollowOnLocking = followOnLocking; finalSql = dialect.addSqlHintOrComment( - applyLocks( sql, queryOptions.getLockOptions() ), + sql, queryOptions, executionContext.getSession().getFactory().getSessionFactoryOptions().isCommentsEnabled() ); } + } + + @Override + public ResultSet getResultSet() { + if ( resultSet == null ) { + executeQuery(); + } + return resultSet; + } + + @Override + public SessionFactoryImplementor getFactory() { + return executionContext.getSession().getFactory(); + } + + public String getFinalSql() { + return finalSql; + } + + public boolean usesFollowOnLocking() { + return usesFollowOnLocking; + } + + private void executeQuery() { + final LogicalConnectionImplementor logicalConnection = getPersistenceContext().getJdbcCoordinator().getLogicalConnection(); + final QueryOptions queryOptions = executionContext.getQueryOptions(); try { - log.tracef( "Executing query to retrieve ResultSet : %s", finalSql ); + LOG.tracef( "Executing query to retrieve ResultSet : %s", finalSql ); // prepare the query preparedStatement = statementCreator.apply( finalSql ); @@ -169,7 +224,7 @@ private void executeQuery() { } catch (SQLException e) { - throw jdbcServices.getSqlExceptionHelper().convert( + throw executionContext.getSession().getJdbcServices().getSqlExceptionHelper().convert( e, "JDBC exception executing SQL [" + finalSql + "]" ); @@ -179,20 +234,18 @@ private void executeQuery() { } } - private String applyLocks(String sql, LockOptions lockOptions) { - if ( lockOptions != null && !lockOptions.isEmpty() ) { - // Locks are applied during SQL rendering, but for native queries, we apply locks separately - final LockOptions originalLockOptions = lockOptions.makeCopy(); - executionContext.getCallback().registerAfterLoadAction( - (session, entity, persister) -> { - ( (Session) session ).buildLockRequest( originalLockOptions ).lock( - persister.getEntityName(), - entity - ); - } - ); + protected LockMode determineFollowOnLockMode(LockOptions lockOptions) { + final LockMode lockModeToUse = lockOptions.findGreatestLockMode(); + + if ( lockOptions.hasAliasSpecificLockModes() ) { + if ( lockOptions.getLockMode() == LockMode.NONE && lockModeToUse == LockMode.NONE ) { + return lockModeToUse; + } + else { + LOG.aliasSpecificLockingWithFollowOnLocking( lockModeToUse ); + } } - return sql; + return lockModeToUse; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java index 92a20692d8e9..54bd383fa2e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/jdbc/internal/JdbcValuesSourceProcessingStateStandardImpl.java @@ -22,6 +22,7 @@ import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PostLoadEventListener; import org.hibernate.event.spi.PreLoadEvent; +import org.hibernate.persister.entity.Loadable; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.collection.internal.ArrayInitializer; import org.hibernate.query.spi.QueryOptions; @@ -199,6 +200,11 @@ private void postLoad() { for ( PostLoadEventListener listener : listenerGroup.listeners() ) { listener.onPostLoad( postLoadEvent ); } + executionContext.invokeAfterLoadActions( + getSession(), + loadingEntityEntry.getEntityInstance(), + (Loadable) loadingEntityEntry.getDescriptor() + ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/batchfetch/BatchingEntityLoaderInitializationWithNoLockModeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/batchfetch/BatchingEntityLoaderInitializationWithNoLockModeTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/test/batchfetch/BatchingEntityLoaderInitializationWithNoLockModeTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/batchfetch/BatchingEntityLoaderInitializationWithNoLockModeTest.java index 461e57c7a831..e43de735bda3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/batchfetch/BatchingEntityLoaderInitializationWithNoLockModeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/batchfetch/BatchingEntityLoaderInitializationWithNoLockModeTest.java @@ -1,4 +1,4 @@ -package org.hibernate.test.batchfetch; +package org.hibernate.orm.test.batchfetch; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertNotNull; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleFollowOnLockingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleFollowOnLockingTest.java similarity index 91% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleFollowOnLockingTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleFollowOnLockingTest.java index f19539eee743..41d1b8eea9b4 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleFollowOnLockingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/functional/OracleFollowOnLockingTest.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.test.dialect.functional; +package org.hibernate.orm.test.dialect.functional; import java.util.List; import javax.persistence.Entity; @@ -23,7 +23,9 @@ import org.hibernate.annotations.QueryHints; import org.hibernate.boot.SessionFactoryBuilder; import org.hibernate.dialect.Oracle8iDialect; +import org.hibernate.dialect.OracleDialect; import org.hibernate.exception.SQLGrammarException; +import org.hibernate.query.IllegalQueryOperationException; import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.TestForIssue; @@ -33,12 +35,13 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * @author Vlad Mihalcea */ -@RequiresDialect(value = { Oracle8iDialect.class }) +@RequiresDialect(value = { OracleDialect.class }) @TestForIssue(jiraKey = "HHH-9486") public class OracleFollowOnLockingTest extends BaseNonConfigCoreFunctionalTestCase { @@ -190,11 +193,16 @@ public void testPessimisticLockWithFirstResultsWhileExplicitlyDisablingFollowOnL .getResultList(); fail( "Should throw exception since Oracle does not support ORDER BY if follow on locking is disabled" ); } - catch ( PersistenceException expected ) { + catch ( IllegalStateException expected ) { assertEquals( - SQLGrammarException.class, + IllegalQueryOperationException.class, expected.getCause().getClass() ); + assertTrue( + expected.getCause().getMessage().contains( + "Locking with OFFSET is not supported!" + ) + ); } } @@ -265,11 +273,16 @@ public void testPessimisticLockWithMaxResultsAndOrderByWhileExplicitlyDisablingF .getResultList(); fail( "Should throw exception since Oracle does not support ORDER BY if follow on locking is disabled" ); } - catch ( PersistenceException expected ) { + catch ( IllegalStateException expected ) { assertEquals( - SQLGrammarException.class, + IllegalQueryOperationException.class, expected.getCause().getClass() ); + assertTrue( + expected.getCause().getMessage().contains( + "Locking with ORDER BY is not supported!" + ) + ); } } @@ -338,11 +351,16 @@ public void testPessimisticLockWithDistinctWhileExplicitlyDisablingFollowOnLocki .getResultList(); fail( "Should throw exception since Oracle does not support DISTINCT if follow on locking is disabled" ); } - catch ( PersistenceException expected ) { + catch ( IllegalStateException expected ) { assertEquals( - SQLGrammarException.class, + IllegalQueryOperationException.class, expected.getCause().getClass() ); + assertTrue( + expected.getCause().getMessage().contains( + "Locking with DISTINCT is not supported!" + ) + ); } } @@ -411,11 +429,16 @@ public void testPessimisticLockWithGroupByWhileExplicitlyDisablingFollowOnLockin .getResultList(); fail( "Should throw exception since Oracle does not support GROUP BY if follow on locking is disabled" ); } - catch ( PersistenceException expected ) { + catch ( IllegalStateException expected ) { assertEquals( - SQLGrammarException.class, + IllegalQueryOperationException.class, expected.getCause().getClass() ); + assertTrue( + expected.getCause().getMessage().contains( + "Locking with GROUP BY is not supported!" + ) + ); } } @@ -477,11 +500,16 @@ public void testPessimisticLockWithUnionWhileExplicitlyDisablingFollowOnLockingT .getResultList(); fail( "Should throw exception since Oracle does not support UNION if follow on locking is disabled" ); } - catch ( PersistenceException expected ) { + catch ( IllegalStateException expected ) { assertEquals( - SQLGrammarException.class, + IllegalQueryOperationException.class, expected.getCause().getClass() ); + assertTrue( + expected.getCause().getMessage().contains( + "Locking with set operators is not supported!" + ) + ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/AbstractLockHintTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/AbstractLockHintTest.java index 92617adc8552..b262d4f46090 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/AbstractLockHintTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/AbstractLockHintTest.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.test.dialect.unit.lockhint; +package org.hibernate.orm.test.dialect.unit.lockhint; import java.util.Collections; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/MySQLStorageEngineTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/MySQLStorageEngineTest.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/MySQLStorageEngineTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/MySQLStorageEngineTest.java index 36346e313b58..b7e6846a62d9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/MySQLStorageEngineTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/MySQLStorageEngineTest.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.test.dialect.unit.lockhint; +package org.hibernate.orm.test.dialect.unit.lockhint; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServer2005LockHintsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SQLServer2005LockHintsTest.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServer2005LockHintsTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SQLServer2005LockHintsTest.java index f87422629375..6936c18036af 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServer2005LockHintsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SQLServer2005LockHintsTest.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.test.dialect.unit.lockhint; +package org.hibernate.orm.test.dialect.unit.lockhint; import org.hibernate.LockMode; import org.hibernate.LockOptions; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SQLServerLockHintsTest.java similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SQLServerLockHintsTest.java index 5ba1d03089e4..589c9940afb5 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SQLServerLockHintsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SQLServerLockHintsTest.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.test.dialect.unit.lockhint; +package org.hibernate.orm.test.dialect.unit.lockhint; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.SQLServerDialect; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseASE15LockHintsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SybaseASE15LockHintsTest.java similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseASE15LockHintsTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SybaseASE15LockHintsTest.java index 656544304203..f64da376e57b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseASE15LockHintsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SybaseASE15LockHintsTest.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.test.dialect.unit.lockhint; +package org.hibernate.orm.test.dialect.unit.lockhint; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.SybaseASE15Dialect; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SybaseLockHintsTest.java similarity index 91% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SybaseLockHintsTest.java index a493a87ac746..594e144098e8 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/lockhint/SybaseLockHintsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/lockhint/SybaseLockHintsTest.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.test.dialect.unit.lockhint; +package org.hibernate.orm.test.dialect.unit.lockhint; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.SybaseDialect; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/DB2LockTimeoutTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/DB2LockTimeoutTest.java similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/DB2LockTimeoutTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/DB2LockTimeoutTest.java index 24b725d0e613..0f9909e09a2f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/DB2LockTimeoutTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/DB2LockTimeoutTest.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.test.dialect.unit.locktimeout; +package org.hibernate.orm.test.dialect.unit.locktimeout; import org.hibernate.LockMode; import org.hibernate.LockOptions; @@ -20,7 +20,7 @@ */ public class DB2LockTimeoutTest extends BaseUnitTestCase { - private final Dialect dialect = new DB2Dialect(); + private final Dialect dialect = new DB2Dialect( 1150 ); @Test public void testLockTimeoutNoAliasNoTimeout() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/HANALockTimeoutTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/HANALockTimeoutTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/HANALockTimeoutTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/HANALockTimeoutTest.java index 455345ea3540..5176390ee32f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/HANALockTimeoutTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/HANALockTimeoutTest.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.test.dialect.unit.locktimeout; +package org.hibernate.orm.test.dialect.unit.locktimeout; import org.hibernate.LockMode; import org.hibernate.LockOptions; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/OracleLockTimeoutTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/OracleLockTimeoutTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/OracleLockTimeoutTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/OracleLockTimeoutTest.java index b1a3d150d4f9..36f4b6e21ca4 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/OracleLockTimeoutTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/OracleLockTimeoutTest.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.test.dialect.unit.locktimeout; +package org.hibernate.orm.test.dialect.unit.locktimeout; import org.hibernate.LockMode; import org.hibernate.LockOptions; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/PostgreSQLLockTimeoutTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/PostgreSQLLockTimeoutTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/PostgreSQLLockTimeoutTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/PostgreSQLLockTimeoutTest.java index 07bef0918327..8f4de8fd4de2 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/locktimeout/PostgreSQLLockTimeoutTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/locktimeout/PostgreSQLLockTimeoutTest.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.test.dialect.unit.locktimeout; +package org.hibernate.orm.test.dialect.unit.locktimeout; import org.hibernate.LockMode; import org.hibernate.LockOptions; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/AbstractSequenceInformationExtractorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/AbstractSequenceInformationExtractorTest.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/AbstractSequenceInformationExtractorTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/AbstractSequenceInformationExtractorTest.java index 8d804fddd8b6..5c726f280b27 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/AbstractSequenceInformationExtractorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/AbstractSequenceInformationExtractorTest.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.test.dialect.unit.sequence; +package org.hibernate.orm.test.dialect.unit.sequence; import javax.persistence.Entity; import javax.persistence.Id; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java index 1f93aec43804..13f0e8a53c7a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.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.test.dialect.unit.sequence; +package org.hibernate.orm.test.dialect.unit.sequence; import org.hibernate.dialect.DB2390Dialect; import org.hibernate.dialect.Dialect; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java index a3fc3b45d44a..c0bcb93a2aa5 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.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.test.dialect.unit.sequence; +package org.hibernate.orm.test.dialect.unit.sequence; import org.hibernate.dialect.DB2400Dialect; import org.hibernate.dialect.Dialect; diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java similarity index 87% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java index 868a43e7f021..75463a4990b8 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java @@ -4,9 +4,9 @@ * 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.test.dialect.unit.sequence; +package org.hibernate.orm.test.dialect.unit.sequence; -import org.hibernate.dialect.DerbyTenFiveDialect; +import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.Dialect; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; @@ -21,7 +21,7 @@ public class DerbyTenFiveDialectSequenceInformationExtractorTest extends Abstrac @Override public Dialect getDialect() { - return new DerbyTenFiveDialect(); + return new DerbyDialect( 1050 ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java similarity index 89% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java index 166544245eef..b93c6d9a651f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java @@ -4,9 +4,9 @@ * 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.test.dialect.unit.sequence; +package org.hibernate.orm.test.dialect.unit.sequence; -import org.hibernate.dialect.DerbyTenSevenDialect; +import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.Dialect; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; @@ -20,7 +20,7 @@ public class DerbyTenSevenDialectSequenceInformationExtractorTest extends AbstractSequenceInformationExtractorTest { @Override public Dialect getDialect() { - return new DerbyTenSevenDialect(); + return new DerbyDialect( 1070 ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java similarity index 89% rename from hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java index a3835bddf534..e2aa3be84eed 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java @@ -4,9 +4,9 @@ * 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.test.dialect.unit.sequence; +package org.hibernate.orm.test.dialect.unit.sequence; -import org.hibernate.dialect.DerbyTenSixDialect; +import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.Dialect; import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl; import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; @@ -20,7 +20,7 @@ public class DerbyTenSixDialectSequenceInformationExtractorTest extends AbstractSequenceInformationExtractorTest { @Override public Dialect getDialect() { - return new DerbyTenSixDialect(); + return new DerbyDialect( 1060 ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/engine/spi/EntityEntryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/engine/spi/EntityEntryTest.java similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/engine/spi/EntityEntryTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/engine/spi/EntityEntryTest.java index 6da291c62bb4..1bb3a62b0ce9 100644 --- a/hibernate-core/src/test/java/org/hibernate/engine/spi/EntityEntryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/engine/spi/EntityEntryTest.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.engine.spi; +package org.hibernate.orm.test.engine.spi; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -14,7 +14,12 @@ import org.hibernate.LockMode; import org.hibernate.engine.internal.MutableEntityEntry; +import org.hibernate.engine.spi.EntityEntry; +import org.hibernate.engine.spi.PersistenceContext; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.Status; +import org.junit.Assert; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -33,7 +38,7 @@ public void packedAttributesAreSetByConstructor() { EntityEntry entityEntry = createEntityEntry(); assertEquals( LockMode.OPTIMISTIC, entityEntry.getLockMode() ); - assertEquals( Status.MANAGED, entityEntry.getStatus() ); + Assert.assertEquals( Status.MANAGED, entityEntry.getStatus() ); assertEquals( true, entityEntry.isExistsInDatabase() ); assertEquals( true, entityEntry.isBeingReplicated() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerClosedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/EntityManagerClosedTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerClosedTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/EntityManagerClosedTest.java index 015723d14afd..8cdc72d7284d 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerClosedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/EntityManagerClosedTest.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; +package org.hibernate.orm.test.jpa; import java.util.Date; import java.util.GregorianCalendar; @@ -17,6 +17,8 @@ import javax.persistence.Query; import javax.persistence.TemporalType; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + import org.hibernate.testing.TestForIssue; import org.junit.Test; diff --git a/hibernate-core/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/JPALockTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/JPALockTest.java index d32f896869ed..6ff351d11daf 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jpa/lock/JPALockTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/JPALockTest.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.test.jpa.lock; +package org.hibernate.orm.test.jpa.lock; import org.hibernate.LockMode; import org.hibernate.Session; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/Lock.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lock.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/lock/Lock.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lock.java index ee50e511f558..46373bd03d38 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/Lock.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lock.java @@ -6,7 +6,7 @@ */ //$Id$ -package org.hibernate.jpa.test.lock; +package org.hibernate.orm.test.jpa.lock; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; diff --git a/hibernate-core/src/test/java/org/hibernate/test/jpa/lock/LockExceptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/LockExceptionTests.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/test/jpa/lock/LockExceptionTests.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/LockExceptionTests.java index 6f1a38fb7f6c..a20d7ad77871 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jpa/lock/LockExceptionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/LockExceptionTests.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.test.jpa.lock; +package org.hibernate.orm.test.jpa.lock; import java.util.Collections; import javax.persistence.LockModeType; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/LockTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/LockTest.java index 79e48d8a5b8e..a168ffa05f29 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/LockTest.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.lock; +package org.hibernate.orm.test.jpa.lock; import java.util.HashMap; import java.util.List; @@ -28,8 +28,8 @@ import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.HSQLDialect; -import org.hibernate.dialect.Oracle10gDialect; -import org.hibernate.dialect.PostgreSQL81Dialect; +import org.hibernate.dialect.OracleDialect; +import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.QueryHints; @@ -39,7 +39,6 @@ import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.jdbc.SharedDriverManagerConnectionProviderImpl; import org.hibernate.testing.transaction.TransactionUtil; import org.hibernate.testing.util.ExceptionUtil; import org.jboss.logging.Logger; @@ -661,7 +660,7 @@ public void testContendedPessimisticLock() throws Exception { } @Test - @RequiresDialect( Oracle10gDialect.class ) + @RequiresDialect( OracleDialect.class ) @RequiresDialectFeature( DialectChecks.SupportsLockTimeouts.class ) public void testContendedPessimisticReadLockTimeout() throws Exception { final CountDownLatch latch = new CountDownLatch( 1 ); @@ -743,7 +742,7 @@ public void testContendedPessimisticReadLockTimeout() throws Exception { } @Test - @RequiresDialect( Oracle10gDialect.class ) + @RequiresDialect( OracleDialect.class ) @RequiresDialectFeature( DialectChecks.SupportsLockTimeouts.class ) public void testContendedPessimisticWriteLockTimeout() throws Exception { @@ -823,7 +822,7 @@ public void testContendedPessimisticWriteLockTimeout() throws Exception { } @Test - @RequiresDialect( { Oracle10gDialect.class, PostgreSQL81Dialect.class }) + @RequiresDialect( { OracleDialect.class, PostgreSQLDialect.class }) @RequiresDialectFeature( DialectChecks.SupportsLockTimeouts.class ) public void testContendedPessimisticWriteLockNoWait() throws Exception { @@ -903,7 +902,7 @@ public void testContendedPessimisticWriteLockNoWait() throws Exception { } @Test - @RequiresDialect( Oracle10gDialect.class ) + @RequiresDialect( OracleDialect.class ) @RequiresDialectFeature( DialectChecks.SupportsLockTimeouts.class ) public void testQueryTimeout() throws Exception { @@ -988,7 +987,7 @@ public void testQueryTimeout() throws Exception { } @Test - @RequiresDialect( Oracle10gDialect.class ) + @RequiresDialect( OracleDialect.class ) @RequiresDialectFeature( DialectChecks.SupportsLockTimeouts.class ) public void testQueryTimeoutEMProps() throws Exception { final CountDownLatch latch = new CountDownLatch( 1 ); @@ -1074,7 +1073,7 @@ public void testQueryTimeoutEMProps() throws Exception { } @Test - @RequiresDialect( Oracle10gDialect.class ) + @RequiresDialect( OracleDialect.class ) @RequiresDialectFeature( DialectChecks.SupportsLockTimeouts.class ) public void testLockTimeoutEMProps() throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTimeoutPropertyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/LockTimeoutPropertyTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTimeoutPropertyTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/LockTimeoutPropertyTest.java index cfc744343645..a369dfdd8cde 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTimeoutPropertyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/LockTimeoutPropertyTest.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.lock; +package org.hibernate.orm.test.jpa.lock; import java.util.Map; import javax.persistence.EntityManager; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/Lockable.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lockable.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/lock/Lockable.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lockable.java index 3302e90f3730..67ddb3aaf601 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/Lockable.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Lockable.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.lock; +package org.hibernate.orm.test.jpa.lock; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/NativeSQLQueryTimeoutTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/NativeSQLQueryTimeoutTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/lock/NativeSQLQueryTimeoutTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/NativeSQLQueryTimeoutTest.java index 4d816387e71e..6938803fb37f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/NativeSQLQueryTimeoutTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/NativeSQLQueryTimeoutTest.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.lock; +package org.hibernate.orm.test.jpa.lock; import org.hibernate.dialect.CockroachDialect; import org.hibernate.dialect.PostgreSQLDialect; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/Person.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Person.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/lock/Person.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/Person.java index 558fc68d6e25..188f06b5a4ea 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/Person.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/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.lock; +package org.hibernate.orm.test.jpa.lock; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/QueryLockingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/QueryLockingTest.java old mode 100755 new mode 100644 similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/lock/QueryLockingTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/QueryLockingTest.java index d683156c794e..8b98ae3bbce6 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/QueryLockingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/QueryLockingTest.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.lock; +package org.hibernate.orm.test.jpa.lock; import java.util.List; import java.util.Map; diff --git a/hibernate-core/src/test/java/org/hibernate/test/jpa/lock/RepeatableReadTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/RepeatableReadTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/test/jpa/lock/RepeatableReadTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/RepeatableReadTest.java index b210e8f53f36..5e01cc6eea70 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jpa/lock/RepeatableReadTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/RepeatableReadTest.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.test.jpa.lock; +package org.hibernate.orm.test.jpa.lock; import java.math.BigDecimal; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/StatementIsClosedAfterALockExceptionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/StatementIsClosedAfterALockExceptionTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/lock/StatementIsClosedAfterALockExceptionTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/StatementIsClosedAfterALockExceptionTest.java index bb35f9b4a5e7..26cdb8e6d12c 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/StatementIsClosedAfterALockExceptionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/StatementIsClosedAfterALockExceptionTest.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.lock; +package org.hibernate.orm.test.jpa.lock; import java.sql.PreparedStatement; import java.sql.SQLException; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/UnversionedLock.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/UnversionedLock.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/jpa/test/lock/UnversionedLock.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/UnversionedLock.java index 28d91aed36cc..68438ef8f73e 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/UnversionedLock.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/UnversionedLock.java @@ -6,7 +6,7 @@ */ //$Id$ -package org.hibernate.jpa.test.lock; +package org.hibernate.orm.test.jpa.lock; 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/lock/UpgradeLockTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/UpgradeLockTest.java index 605ffda520ae..7dc9d2b3f69a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/UpgradeLockTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/lock/UpgradeLockTest.java @@ -11,8 +11,6 @@ import javax.persistence.EntityManager; import javax.persistence.LockModeType; -import org.hibernate.jpa.test.lock.Lock; - import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; import org.hibernate.testing.orm.junit.Jpa; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/schemagen/JpaSchemaGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/schemagen/JpaSchemaGeneratorTest.java index 425609e831f4..02086d19c9d3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/schemagen/JpaSchemaGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/schemagen/JpaSchemaGeneratorTest.java @@ -150,7 +150,7 @@ private void doTest(Map settings) { // We want a fresh db after emf close // Unfortunately we have to use this dirty hack because the db seems not to be closed otherwise settings.put( "hibernate.connection.url", "jdbc:h2:mem:db-schemagen" + schemagenNumber++ - + ";MVCC=TRUE;LOCK_TIMEOUT=10000" ); + + ";LOCK_TIMEOUT=10000" ); EntityManagerFactoryBuilder emfb = Bootstrap.getEntityManagerFactoryBuilder( buildPersistenceUnitDescriptor(), settings diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/BlobLocatorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/BlobLocatorTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/test/lob/BlobLocatorTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/BlobLocatorTest.java index b7010a9ceb0c..1e94680b196c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/BlobLocatorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/BlobLocatorTest.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.test.lob; +package org.hibernate.orm.test.lob; import java.sql.Blob; import java.util.Arrays; @@ -35,6 +35,11 @@ public class BlobLocatorTest extends BaseCoreFunctionalTestCase { private static final long BLOB_SIZE = 10000L; + @Override + protected String getBaseForMappings() { + return "org/hibernate/orm/test/"; + } + public String[] getMappings() { return new String[] { "lob/LobMappings.hbm.xml" }; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/ClobLocatorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ClobLocatorTest.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/test/lob/ClobLocatorTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/ClobLocatorTest.java index 4d41358977bc..5883b0c21a8e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/ClobLocatorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ClobLocatorTest.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.test.lob; +package org.hibernate.orm.test.lob; import java.sql.Clob; @@ -37,6 +37,11 @@ public class ClobLocatorTest extends BaseCoreFunctionalTestCase { private static final int CLOB_SIZE = 10000; + @Override + protected String getBaseForMappings() { + return "org/hibernate/orm/test/"; + } + public String[] getMappings() { return new String[] { "lob/LobMappings.hbm.xml" }; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LobHolder.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobHolder.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/test/lob/LobHolder.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobHolder.java index 4b10200b7e90..3b8d84c69453 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LobHolder.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobHolder.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.test.lob; +package org.hibernate.orm.test.lob; import java.sql.Blob; import java.sql.Clob; diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LobMappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobMappings.hbm.xml similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/test/lob/LobMappings.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobMappings.hbm.xml index 4ad93cd21aec..8f25efb5a3ac 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LobMappings.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobMappings.hbm.xml @@ -9,7 +9,7 @@ "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - + diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LobMergeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobMergeTest.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/test/lob/LobMergeTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobMergeTest.java index 36c23c3523a9..d24cedd7a946 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LobMergeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobMergeTest.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.test.lob; +package org.hibernate.orm.test.lob; import java.util.Arrays; @@ -27,6 +27,11 @@ public class LobMergeTest extends BaseCoreFunctionalTestCase { private static final int LOB_SIZE = 10000; + @Override + protected String getBaseForMappings() { + return "org/hibernate/orm/test/"; + } + public String[] getMappings() { return new String[] { "lob/LobMappings.hbm.xml" }; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/A.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/A.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/test/locking/A.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/A.java index 243c4982b4b2..da734a2d9bc1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/A.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/A.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.test.locking; +package org.hibernate.orm.test.locking; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/AbstractSkipLockedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/AbstractSkipLockedTest.java similarity index 88% rename from hibernate-core/src/test/java/org/hibernate/test/locking/AbstractSkipLockedTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/AbstractSkipLockedTest.java index 522756e98777..11c3bc2f371c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/AbstractSkipLockedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/AbstractSkipLockedTest.java @@ -1,19 +1,23 @@ -package org.hibernate.test.locking; +package org.hibernate.orm.test.locking; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import javax.persistence.Entity; import javax.persistence.Id; + import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.Session; -import org.hibernate.dialect.MySQL8Dialect; -import org.hibernate.dialect.Oracle8iDialect; -import org.hibernate.dialect.PostgreSQL95Dialect; -import org.hibernate.dialect.SQLServer2005Dialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.OracleDialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.dialect.SQLServerDialect; import org.hibernate.query.Query; + +import org.hibernate.testing.DialectChecks; import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.Test; @@ -34,7 +38,8 @@ protected Class[] getAnnotatedClasses() { @Test - @RequiresDialect({ SQLServer2005Dialect.class }) + @RequiresDialect({ SQLServerDialect.class }) + @RequiresDialectFeature(DialectChecks.SupportsSkipLocked.class) public void testSQLServerSkipLocked() { doInHibernate( this::sessionFactory, session -> { @@ -67,7 +72,8 @@ public void testSQLServerSkipLocked() { } @Test - @RequiresDialect({ PostgreSQL95Dialect.class }) + @RequiresDialect({ PostgreSQLDialect.class }) + @RequiresDialectFeature(DialectChecks.SupportsSkipLocked.class) public void testPostgreSQLSkipLocked() { doInHibernate( this::sessionFactory, session -> { @@ -106,7 +112,8 @@ public void testPostgreSQLSkipLocked() { } @Test - @RequiresDialect({ Oracle8iDialect.class }) + @RequiresDialect({ OracleDialect.class }) + @RequiresDialectFeature(DialectChecks.SupportsSkipLocked.class) public void testOracleSkipLocked() { doInHibernate( this::sessionFactory, session -> { @@ -141,7 +148,8 @@ public void testOracleSkipLocked() { } @Test - @RequiresDialect({ MySQL8Dialect.class }) + @RequiresDialect({ MySQLDialect.class }) + @RequiresDialectFeature(DialectChecks.SupportsSkipLocked.class) public void testMySQLSkipLocked() { doInHibernate( this::sessionFactory, session -> { diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/HANAOptimisticLockingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/HANAOptimisticLockingTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/test/locking/HANAOptimisticLockingTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/HANAOptimisticLockingTest.java index 93eeaae9628a..dfc20ae3fa65 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/HANAOptimisticLockingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/HANAOptimisticLockingTest.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.test.locking; +package org.hibernate.orm.test.locking; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/JoinedInheritanceOptimisticForceIncrementTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/JoinedInheritanceOptimisticForceIncrementTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/test/locking/JoinedInheritanceOptimisticForceIncrementTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/JoinedInheritanceOptimisticForceIncrementTest.java index e626a692feb2..98ef4c67da7c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/JoinedInheritanceOptimisticForceIncrementTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/JoinedInheritanceOptimisticForceIncrementTest.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.test.locking; +package org.hibernate.orm.test.locking; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/LockModeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockModeTest.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/test/locking/LockModeTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockModeTest.java index 50bf945e2a8c..128d2ff74767 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/LockModeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockModeTest.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.test.locking; +package org.hibernate.orm.test.locking; import java.util.Collections; import java.util.concurrent.CountDownLatch; @@ -23,6 +23,9 @@ import org.hibernate.dialect.SybaseASE15Dialect; import org.hibernate.dialect.SybaseDialect; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaQuery; +import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.testing.DialectChecks; import org.hibernate.testing.RequiresDialectFeature; @@ -115,10 +118,12 @@ public void testCriteria() { public void testCriteriaAliasSpecific() { // open a session, begin a transaction and lock row doInHibernate( this::sessionFactory, session -> { - CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); - CriteriaQuery criteria = criteriaBuilder.createQuery( A.class ); - criteria.from( A.class ); - A it = session.createQuery( criteria ).setLockMode("this",LockMode.PESSIMISTIC_WRITE ).uniqueResult(); + HibernateCriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); + JpaCriteriaQuery criteria = criteriaBuilder.createQuery( A.class ); + ( (SqmPath) criteria.from( A.class ) ).setExplicitAlias( "this" ); + A it = session.createQuery( criteria ) + .setLockMode( "this", LockMode.PESSIMISTIC_WRITE ) + .uniqueResult(); // A it = (A) session.createCriteria( A.class ) // .setLockMode( "this", LockMode.PESSIMISTIC_WRITE ) @@ -179,7 +184,7 @@ public void testQueryLockModeNoneWithAlias() { public void testQueryLockModePessimisticWriteWithAlias() { doInHibernate( this::sessionFactory, session -> { // shouldn't throw an exception - session.createQuery( "SELECT MAX(a.id)+1 FROM A a where a.value = :value" ) + session.createQuery( "SELECT a.id+1 FROM A a where a.value = :value" ) .setLockMode( "a", LockMode.PESSIMISTIC_WRITE ) .setParameter( "value", "it" ) .list(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/LockRefreshTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockRefreshTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/test/locking/LockRefreshTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockRefreshTest.java index 7d9a13ea710e..d5c45bf64404 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/LockRefreshTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/LockRefreshTest.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.test.locking; +package org.hibernate.orm.test.locking; import java.util.Arrays; import javax.persistence.Column; diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticReadSkipLockedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/PessimisticReadSkipLockedTest.java similarity index 85% rename from hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticReadSkipLockedTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/PessimisticReadSkipLockedTest.java index 817fd99b1aae..d2d0716ceaca 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticReadSkipLockedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/PessimisticReadSkipLockedTest.java @@ -1,4 +1,4 @@ -package org.hibernate.test.locking; +package org.hibernate.orm.test.locking; import org.hibernate.LockMode; diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteLockTimeoutTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/PessimisticWriteLockTimeoutTest.java similarity index 85% rename from hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteLockTimeoutTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/PessimisticWriteLockTimeoutTest.java index 736663018349..ebed5a3f44f1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteLockTimeoutTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/PessimisticWriteLockTimeoutTest.java @@ -1,13 +1,13 @@ -package org.hibernate.test.locking; +package org.hibernate.orm.test.locking; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.Session; import org.hibernate.boot.SessionFactoryBuilder; -import org.hibernate.dialect.Oracle8iDialect; -import org.hibernate.dialect.PostgreSQL81Dialect; -import org.hibernate.dialect.PostgreSQL95Dialect; -import org.hibernate.dialect.SQLServer2005Dialect; +import org.hibernate.dialect.OracleDialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.dialect.SQLServerDialect; + import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; @@ -51,8 +51,7 @@ public void createTestData() { } @Test - @RequiresDialect({ Oracle8iDialect.class, PostgreSQL81Dialect.class, - SQLServer2005Dialect.class } ) + @RequiresDialect({ OracleDialect.class, PostgreSQLDialect.class, SQLServerDialect.class } ) public void testNoWait() throws NoSuchFieldException, IllegalAccessException { @@ -77,7 +76,7 @@ public void testNoWait() } @Test - @RequiresDialect({ Oracle8iDialect.class, PostgreSQL95Dialect.class }) + @RequiresDialect({ OracleDialect.class, PostgreSQLDialect.class }) public void testSkipLocked() throws NoSuchFieldException, IllegalAccessException { diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteSkipLockedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/PessimisticWriteSkipLockedTest.java similarity index 85% rename from hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteSkipLockedTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/PessimisticWriteSkipLockedTest.java index a81e17a0aa91..ffac603f7bde 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteSkipLockedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/PessimisticWriteSkipLockedTest.java @@ -1,4 +1,4 @@ -package org.hibernate.test.locking; +package org.hibernate.orm.test.locking; import org.hibernate.LockMode; diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/UpgradeSkipLockedTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/UpgradeSkipLockedTest.java similarity index 91% rename from hibernate-core/src/test/java/org/hibernate/test/locking/UpgradeSkipLockedTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/UpgradeSkipLockedTest.java index c8d387974889..5513de0b5ce6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/UpgradeSkipLockedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/UpgradeSkipLockedTest.java @@ -1,4 +1,4 @@ -package org.hibernate.test.locking; +package org.hibernate.orm.test.locking; import org.hibernate.LockMode; import org.hibernate.LockOptions; diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/paging/Door.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/paging/Door.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/test/locking/paging/Door.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/paging/Door.java index 8d7595de25d3..8f9c31349309 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/paging/Door.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/paging/Door.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.test.locking.paging; +package org.hibernate.orm.test.locking.paging; import javax.persistence.Entity; import javax.persistence.Id; diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/paging/PagingAndLockingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/paging/PagingAndLockingTest.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/test/locking/paging/PagingAndLockingTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/locking/paging/PagingAndLockingTest.java index 97e72358c2cd..547afc66886c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/paging/PagingAndLockingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/paging/PagingAndLockingTest.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.test.locking.paging; +package org.hibernate.orm.test.locking.paging; import java.util.List; import javax.persistence.LockModeType; @@ -51,7 +51,7 @@ public void createTestData() { @After public void deleteTestData() { inTransaction( - s -> session.createQuery( "delete Door" ).executeUpdate() + s -> s.createQuery( "delete Door" ).executeUpdate() ); } @@ -90,7 +90,7 @@ public void testCriteria() { .list(); assertEquals( 2, results.size() ); for ( Door door : results ) { - assertEquals( LockMode.PESSIMISTIC_WRITE, session.getCurrentLockMode( door ) ); + assertEquals( LockMode.PESSIMISTIC_WRITE, s.getCurrentLockMode( door ) ); } } ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/BasicGetLoadAccessTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/BasicGetLoadAccessTest.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/BasicGetLoadAccessTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/BasicGetLoadAccessTest.java index 3775fbf18650..1813a62217ff 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/BasicGetLoadAccessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/BasicGetLoadAccessTest.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.test.ops.genericApi; +package org.hibernate.orm.test.ops.genericApi; import java.util.NoSuchElementException; import java.util.Optional; diff --git a/hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/ProxiedGetLoadAccessTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/ProxiedGetLoadAccessTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/ProxiedGetLoadAccessTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/ProxiedGetLoadAccessTest.java index 1735096f72a4..805c8d89a08b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/ops/genericApi/ProxiedGetLoadAccessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/ops/genericApi/ProxiedGetLoadAccessTest.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.test.ops.genericApi; +package org.hibernate.orm.test.ops.genericApi; import javax.persistence.Entity; import javax.persistence.GeneratedValue; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/QueryParametersValidationArrayTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/QueryParametersValidationArrayTest.java index 67d2b1832ef1..103100c0bb0f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/QueryParametersValidationArrayTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/QueryParametersValidationArrayTest.java @@ -68,7 +68,7 @@ public static class Event { @GeneratedValue(strategy = GenerationType.AUTO) private Long id; - @Column(columnDefinition = "ARRAY(1)") + @Column(columnDefinition = "ARRAY") private String[] readings; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/BaseSqmUnitTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/BaseSqmUnitTest.java index c086fc577d61..a2a4496b1fd5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/BaseSqmUnitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/BaseSqmUnitTest.java @@ -9,8 +9,10 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.loader.ast.spi.AfterLoadAction; import org.hibernate.metamodel.spi.MetamodelImplementor; +import org.hibernate.persister.entity.Loadable; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.service.ServiceRegistry; import org.hibernate.sql.ast.spi.SqlAstCreationContext; @@ -48,6 +50,10 @@ protected boolean strictJpaCompliance() { public void registerAfterLoadAction(AfterLoadAction afterLoadAction) { } + @Override + public void invokeAfterLoadActions(SharedSessionContractImplementor session, Object entity, Loadable persister) { + } + protected SqmSelectStatement interpretSelect(String hql) { return interpretSelect( hql, sessionFactory() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/mutation/multitable/IdSelectionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/mutation/multitable/IdSelectionTests.java index 800e5f5add1a..bd5da0f00bed 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/mutation/multitable/IdSelectionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/sqm/mutation/multitable/IdSelectionTests.java @@ -201,8 +201,7 @@ public QueryParameterBindings getQueryParameterBindings() { @Override public Callback getCallback() { - return afterLoadAction -> { - }; + throw new UnsupportedOperationException(); } } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/DialectChecks.java b/hibernate-testing/src/main/java/org/hibernate/testing/DialectChecks.java index 18d603980b25..a2779cc681d4 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/DialectChecks.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/DialectChecks.java @@ -190,6 +190,12 @@ public boolean isMatch(Dialect dialect) { } } + public static class SupportsSkipLocked implements DialectCheck { + public boolean isMatch(Dialect dialect) { + return dialect.supportsSkipLocked(); + } + } + public static class DoubleQuoteQuoting implements DialectCheck { @Override public boolean isMatch(Dialect dialect) { @@ -255,6 +261,12 @@ public boolean isMatch(Dialect dialect) { } } + public static class SupportWait implements DialectCheck { + public boolean isMatch(Dialect dialect) { + return dialect.supportsWait(); + } + } + public static class SupportDropConstraints implements DialectCheck { public boolean isMatch(Dialect dialect) { return dialect.dropConstraints(); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java index c1ea6fb79117..81baadf6fde7 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java @@ -52,6 +52,7 @@ import org.hibernate.testing.SkipLog; import org.hibernate.testing.cache.CachingRegionFactory; import org.hibernate.testing.jdbc.SharedDriverManagerConnectionProviderImpl; +import org.hibernate.testing.orm.junit.DialectContext; import org.hibernate.testing.transaction.TransactionUtil2; import org.junit.After; import org.junit.Before; @@ -68,7 +69,7 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase { public static final String VALIDATE_DATA_CLEANUP = "hibernate.test.validateDataCleanup"; - public static final Dialect DIALECT = Dialect.getDialect(); + public static final Dialect DIALECT = DialectContext.getDialect(); private Configuration configuration; private StandardServiceRegistryImpl serviceRegistry; diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DialectFeatureChecks.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DialectFeatureChecks.java index 139016720602..8900dbbc0cbd 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DialectFeatureChecks.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DialectFeatureChecks.java @@ -210,6 +210,12 @@ public boolean apply(Dialect dialect) { } } + public static class SupportsSkipLocked implements DialectFeatureCheck { + public boolean apply(Dialect dialect) { + return dialect.supportsSkipLocked(); + } + } + public static class DoubleQuoteQuoting implements DialectFeatureCheck { @Override public boolean apply(Dialect dialect) {