From df393f90f4b7a010837034730c6b666865a64b58 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Sun, 16 Jan 2022 11:51:02 +0100 Subject: [PATCH] [#1413] Add support for Hibernate 5.6.3 through a custom integration. Also fire CDI event for CriteriaBuilderConfiguration in Quarkus integration --- CHANGELOG.md | 4 +- core/testsuite/pom.xml | 18 +- dist/bom/pom.xml | 20 +- dist/full/pom.xml | 16 + .../core/manual/en_US/getting_started.adoc | 49 +- .../asciidoc/core/manual/en_US/querydsl.adoc | 4 +- .../entity-view/manual/en_US/quarkus.adoc | 18 + .../entity-view/manual/en_US/spring_data.adoc | 2 +- .../manual/en_US/spring_hateoas.adoc | 2 +- entity-view/testsuite/pom.xml | 12 +- .../config/BlazePersistenceConfigurator.java | 12 + .../quarkus/base/view/DocumentView.java | 3 + .../base/AbstractQuarkusExampleTest.java | 1 + integration/deltaspike-data/testsuite/pom.xml | 12 +- .../Hibernate53DelegatingDialect.java | 86 ++ .../pom.xml | 10 +- integration/hibernate-5.5/pom.xml | 170 +++ integration/hibernate-5.6-jakarta/pom.xml | 219 ++++ integration/hibernate-5.6/pom.xml | 145 +++ .../CustomBasicCollectionPersister.java | 53 + .../CustomMultiTableBulkIdStrategy.java | 81 ++ .../hibernate/CustomOneToManyPersister.java | 53 + .../CustomPersisterClassResolver.java | 37 + .../CustomSubselectCollectionLoader.java | 67 ++ .../CustomSubselectOneToManyLoader.java | 67 ++ .../CustomTableBasedUpdateHandlerImpl.java | 177 +++ .../DelegatingStatementPreparerImpl.java | 66 ++ .../hibernate/Hibernate56Access.java | 263 +++++ .../Hibernate56DelegatingDialect.java | 1026 +++++++++++++++++ ...rnate56EntityManagerFactoryIntegrator.java | 107 ++ .../hibernate/Hibernate56Integrator.java | 108 ++ .../hibernate/Hibernate56LimitHandler.java | 81 ++ .../Hibernate56LimitHandlingDialect.java | 41 + .../Hibernate56MetadataContributor.java | 103 ++ .../Hibernate56ServiceContributor.java | 49 + ...nate56SessionFactoryInvocationHandler.java | 47 + .../Hibernate56SessionInvocationHandler.java | 47 + ...ityTransactionSynchronizationStrategy.java | 69 ++ ...ormTransactionSynchronizationStrategy.java | 71 ++ .../Hibernate5TransactionAccessFactory.java | 57 + .../JdbcCoordinatorInvocationHandler.java | 48 + .../hibernate/NativeTableNameFormatter.java | 41 + .../PreparedStatementInvocationHandler.java | 74 ++ ...ingPreparedStatementInvocationHandler.java | 105 ++ .../hibernate/StatementPreparerImpl.java | 200 ++++ integration/pom.xml | 5 +- .../BlazePersistenceCdiProcessor.java | 4 +- .../quarkus/runtime/EntityViewRecorder.java | 10 +- integration/querydsl/testsuite/pom.xml | 12 +- .../spring-data/testsuite/webflux/pom.xml | 12 +- .../spring-data/testsuite/webmvc/pom.xml | 12 +- jpa-criteria/testsuite/pom.xml | 12 +- parent/pom.xml | 19 +- 53 files changed, 3958 insertions(+), 69 deletions(-) rename integration/{hibernate-5.4-jakarta => hibernate-5.5-jakarta}/pom.xml (97%) create mode 100644 integration/hibernate-5.5/pom.xml create mode 100644 integration/hibernate-5.6-jakarta/pom.xml create mode 100644 integration/hibernate-5.6/pom.xml create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomBasicCollectionPersister.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomMultiTableBulkIdStrategy.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomOneToManyPersister.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomPersisterClassResolver.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomSubselectCollectionLoader.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomSubselectOneToManyLoader.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomTableBasedUpdateHandlerImpl.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/DelegatingStatementPreparerImpl.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56Access.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56DelegatingDialect.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56EntityManagerFactoryIntegrator.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56Integrator.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56LimitHandler.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56LimitHandlingDialect.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56MetadataContributor.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56ServiceContributor.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56SessionFactoryInvocationHandler.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56SessionInvocationHandler.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5EntityTransactionSynchronizationStrategy.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5JtaPlatformTransactionSynchronizationStrategy.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5TransactionAccessFactory.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/JdbcCoordinatorInvocationHandler.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/NativeTableNameFormatter.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/PreparedStatementInvocationHandler.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/SecondaryTableUpdateSupportingPreparedStatementInvocationHandler.java create mode 100644 integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/StatementPreparerImpl.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a177be100..d0580124b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ Not yet released ### New features -* None yet +* Fire CDI event for `CriteriaBuilderConfiguration` on boot also in Quarkus integration +* Create custom integrations for Hibernate 5.5 and 5.6 to avoid confusion ### Bug fixes @@ -18,6 +19,7 @@ Not yet released ### Backwards-incompatible changes * Throw exception if non-streaming capable object builder is used for streaming +* Replace `blaze-persistence-integration-hibernate-5.4-jakarta` with `blaze-persistence-integration-hibernate-5.5-jakarta` ## 1.6.4 diff --git a/core/testsuite/pom.xml b/core/testsuite/pom.xml index de5e1addd0..f567c04a38 100644 --- a/core/testsuite/pom.xml +++ b/core/testsuite/pom.xml @@ -1669,7 +1669,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.5 test @@ -1801,7 +1801,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2694,26 +2694,26 @@ org.hibernate hibernate-entitymanager - ${version.hibernate-5.4} + ${version.hibernate-5.6} org.hibernate hibernate-envers - ${version.hibernate-5.4} + ${version.hibernate-5.6} org.hibernate hibernate-testing - ${version.hibernate-5.4} + ${version.hibernate-5.6} com.vladmihalcea - hibernate-types-52 + hibernate-types-55 ${version.hibernate-types} ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2725,7 +2725,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} provided @@ -2789,7 +2789,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} jakarta.xml.bind diff --git a/dist/bom/pom.xml b/dist/bom/pom.xml index ce0f9d514c..a4165bdf70 100644 --- a/dist/bom/pom.xml +++ b/dist/bom/pom.xml @@ -211,7 +211,25 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4-jakarta + blaze-persistence-integration-hibernate-5.5 + ${project.version} + runtime + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.5-jakarta + ${project.version} + runtime + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.6 + ${project.version} + runtime + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.6-jakarta ${project.version} runtime diff --git a/dist/full/pom.xml b/dist/full/pom.xml index 7742a87fc0..d86fd25262 100644 --- a/dist/full/pom.xml +++ b/dist/full/pom.xml @@ -105,6 +105,22 @@ ${project.groupId} blaze-persistence-integration-hibernate-5.4 + + ${project.groupId} + blaze-persistence-integration-hibernate-5.5 + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.5-jakarta + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.6 + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.6-jakarta + ${project.groupId} blaze-persistence-integration-hibernate-6.0 diff --git a/documentation/src/main/asciidoc/core/manual/en_US/getting_started.adoc b/documentation/src/main/asciidoc/core/manual/en_US/getting_started.adoc index 9ee5636732..d6f7c84671 100644 --- a/documentation/src/main/asciidoc/core/manual/en_US/getting_started.adoc +++ b/documentation/src/main/asciidoc/core/manual/en_US/getting_started.adoc @@ -76,25 +76,60 @@ or if you are using Jakarta JPA Depending on the JPA provider that should be used, one of the following integrations is required -[[maven-setup-hibernate54-jakarta]] -===== Hibernate 5.4+ Jakarta +[[maven-setup-hibernate56-jakarta]] +===== Hibernate 5.6+ Jakarta -This integration works for Hibernate 5.4, 5.5 and 5.6 +[source,xml] +---- + + com.blazebit + blaze-persistence-integration-hibernate-5.6-jakarta + ${blaze-persistence.version} + runtime + +---- + +[[maven-setup-hibernate56]] +===== Hibernate 5.6 [source,xml] ---- com.blazebit - blaze-persistence-integration-hibernate-5.4-jakarta + blaze-persistence-integration-hibernate-5.6 ${blaze-persistence.version} runtime ---- -[[maven-setup-hibernate54]] -===== Hibernate 5.4+ +[[maven-setup-hibernate55-jakarta]] +===== Hibernate 5.5 Jakarta + +[source,xml] +---- + + com.blazebit + blaze-persistence-integration-hibernate-5.5-jakarta + ${blaze-persistence.version} + runtime + +---- -This integration works for Hibernate 5.4, 5.5 and 5.6 +[[maven-setup-hibernate55]] +===== Hibernate 5.5 + +[source,xml] +---- + + com.blazebit + blaze-persistence-integration-hibernate-5.5 + ${blaze-persistence.version} + runtime + +---- + +[[maven-setup-hibernate54]] +===== Hibernate 5.4 [source,xml] ---- diff --git a/documentation/src/main/asciidoc/core/manual/en_US/querydsl.adoc b/documentation/src/main/asciidoc/core/manual/en_US/querydsl.adoc index 512a407f84..a1e8e281cb 100644 --- a/documentation/src/main/asciidoc/core/manual/en_US/querydsl.adoc +++ b/documentation/src/main/asciidoc/core/manual/en_US/querydsl.adoc @@ -31,7 +31,7 @@ As outlined in the <> you need the following com.blazebit - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 ${blaze-persistence.version} runtime @@ -49,7 +49,7 @@ or if you are using Jakarta JPA com.blazebit - blaze-persistence-integration-hibernate-5.4-jakarta + blaze-persistence-integration-hibernate-5.6-jakarta ${blaze-persistence.version} runtime diff --git a/documentation/src/main/asciidoc/entity-view/manual/en_US/quarkus.adoc b/documentation/src/main/asciidoc/entity-view/manual/en_US/quarkus.adoc index a7292b9885..c3416440f6 100644 --- a/documentation/src/main/asciidoc/entity-view/manual/en_US/quarkus.adoc +++ b/documentation/src/main/asciidoc/entity-view/manual/en_US/quarkus.adoc @@ -290,3 +290,21 @@ In order to make proper use of a custom type in entity views, it is necessary to Configure default values for optional parameters:: Sometimes it is useful to provide access to services into entity views through optional parameters, for which a global default value can be registered on `EntityViewConfiguration`. + +As of version 1.6.5, also a CDI event of the type `CriteriaBuilderConfiguration` is fired with an optional `@BlazePersistenceInstance` qualifier at boot time. +This allows to further customize the configuration which is often necessary if the context-less variant `CriteriaBuilderConfigurationContributor` isn't enough + +Register named type for VALUES:: +If you want to use a type that isn't supported out of the box, it needs to be registered under a name. + +Register custom JpqlFunctionGroup:: +If you want to register a CDI context aware `JpqlFunctionGroup`. + +Register JpqlMacro:: +If you want to register a CDI context aware `JpqlMacro`. + +Register custom dialect:: +When a dialect has a bug, needs a customization, or a new kind of dialect should be registered. + +Configure properties:: +Sometimes it is simply necessary to override a configuration property through `setProperty` diff --git a/documentation/src/main/asciidoc/entity-view/manual/en_US/spring_data.adoc b/documentation/src/main/asciidoc/entity-view/manual/en_US/spring_data.adoc index 788acd2dd4..96faed2f2c 100644 --- a/documentation/src/main/asciidoc/entity-view/manual/en_US/spring_data.adoc +++ b/documentation/src/main/asciidoc/entity-view/manual/en_US/spring_data.adoc @@ -22,7 +22,7 @@ In short, the following Maven dependencies are required com.blazebit - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 ${blaze-persistence.version} runtime diff --git a/documentation/src/main/asciidoc/entity-view/manual/en_US/spring_hateoas.adoc b/documentation/src/main/asciidoc/entity-view/manual/en_US/spring_hateoas.adoc index e0b0cc6e74..61e33de7c7 100644 --- a/documentation/src/main/asciidoc/entity-view/manual/en_US/spring_hateoas.adoc +++ b/documentation/src/main/asciidoc/entity-view/manual/en_US/spring_hateoas.adoc @@ -20,7 +20,7 @@ In short, the following Maven dependencies are required com.blazebit - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 ${blaze-persistence.version} runtime diff --git a/entity-view/testsuite/pom.xml b/entity-view/testsuite/pom.xml index f1f01f73dd..badd13c630 100644 --- a/entity-view/testsuite/pom.xml +++ b/entity-view/testsuite/pom.xml @@ -1249,7 +1249,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.5 test @@ -1349,7 +1349,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2176,11 +2176,11 @@ org.hibernate hibernate-entitymanager - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2192,7 +2192,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} provided @@ -2234,7 +2234,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} diff --git a/examples/quarkus/base/src/main/java/com/blazebit/persistence/examples/quarkus/base/config/BlazePersistenceConfigurator.java b/examples/quarkus/base/src/main/java/com/blazebit/persistence/examples/quarkus/base/config/BlazePersistenceConfigurator.java index 1d63b536bb..8cd58431e6 100644 --- a/examples/quarkus/base/src/main/java/com/blazebit/persistence/examples/quarkus/base/config/BlazePersistenceConfigurator.java +++ b/examples/quarkus/base/src/main/java/com/blazebit/persistence/examples/quarkus/base/config/BlazePersistenceConfigurator.java @@ -16,6 +16,9 @@ package com.blazebit.persistence.examples.quarkus.base.config; +import com.blazebit.persistence.spi.CriteriaBuilderConfiguration; +import com.blazebit.persistence.spi.FunctionRenderContext; +import com.blazebit.persistence.spi.JpqlMacro; import com.blazebit.persistence.view.spi.EntityViewConfiguration; import javax.enterprise.context.ApplicationScoped; @@ -24,6 +27,15 @@ @ApplicationScoped public class BlazePersistenceConfigurator { + public void observe(@Observes CriteriaBuilderConfiguration config) { + config.registerMacro("my_macro", new JpqlMacro() { + @Override + public void render(FunctionRenderContext context) { + context.addArgument(0); + } + }); + } + public void observe(@Observes EntityViewConfiguration config) { config.setOptionalParameter("optionalParameter", "test"); } diff --git a/examples/quarkus/base/src/main/java/com/blazebit/persistence/examples/quarkus/base/view/DocumentView.java b/examples/quarkus/base/src/main/java/com/blazebit/persistence/examples/quarkus/base/view/DocumentView.java index f9c02060b2..b961d860da 100644 --- a/examples/quarkus/base/src/main/java/com/blazebit/persistence/examples/quarkus/base/view/DocumentView.java +++ b/examples/quarkus/base/src/main/java/com/blazebit/persistence/examples/quarkus/base/view/DocumentView.java @@ -41,4 +41,7 @@ public interface DocumentView { @MappingParameter("optionalParameter") String getOptionalParameter(); + + @Mapping("my_macro(name)") + String getMacroName(); } diff --git a/examples/quarkus/testsuite/base/src/main/java/com/blazebit/persistence/examples/quarkus/testsuite/base/AbstractQuarkusExampleTest.java b/examples/quarkus/testsuite/base/src/main/java/com/blazebit/persistence/examples/quarkus/testsuite/base/AbstractQuarkusExampleTest.java index c45ab3b289..0dda098897 100644 --- a/examples/quarkus/testsuite/base/src/main/java/com/blazebit/persistence/examples/quarkus/testsuite/base/AbstractQuarkusExampleTest.java +++ b/examples/quarkus/testsuite/base/src/main/java/com/blazebit/persistence/examples/quarkus/testsuite/base/AbstractQuarkusExampleTest.java @@ -99,6 +99,7 @@ public void getDocumentsWithJsonIgnoredName() { assertFalse(document.containsKey("name")); assertEquals("test", document.get("optionalParameter")); + assertEquals("Doc1", document.get("macroName")); } @Test diff --git a/integration/deltaspike-data/testsuite/pom.xml b/integration/deltaspike-data/testsuite/pom.xml index 95c6167bd5..8ec1d86e70 100644 --- a/integration/deltaspike-data/testsuite/pom.xml +++ b/integration/deltaspike-data/testsuite/pom.xml @@ -1227,7 +1227,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.5 test @@ -1327,7 +1327,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2163,11 +2163,11 @@ org.hibernate hibernate-entitymanager - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2179,7 +2179,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} provided @@ -2229,7 +2229,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} diff --git a/integration/hibernate-5.3/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate53DelegatingDialect.java b/integration/hibernate-5.3/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate53DelegatingDialect.java index 2afccdd0bf..d8a4a04cef 100644 --- a/integration/hibernate-5.3/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate53DelegatingDialect.java +++ b/integration/hibernate-5.3/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate53DelegatingDialect.java @@ -36,6 +36,7 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver; +import org.hibernate.engine.spi.QueryParameters; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.SQLExceptionConverter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; @@ -902,6 +903,91 @@ public void augmentRecognizedTableTypes(List tableTypesList) { delegate.augmentRecognizedTableTypes(tableTypesList); } + @Override + public String getNativeIdentifierGeneratorStrategy() { + return delegate.getNativeIdentifierGeneratorStrategy(); + } + + @Override + public String getWriteLockString(String aliases, int timeout) { + return delegate.getWriteLockString(aliases, timeout); + } + + @Override + public String getReadLockString(String aliases, int timeout) { + return delegate.getReadLockString(aliases, timeout); + } + + @Override + public String getAlterTableString(String tableName) { + return delegate.getAlterTableString(tableName); + } + + @Override + public String getAddForeignKeyConstraintString(String constraintName, String foreignKeyDefinition) { + return delegate.getAddForeignKeyConstraintString(constraintName, foreignKeyDefinition); + } + + @Override + public boolean supportsIfExistsAfterAlterTable() { + return delegate.supportsIfExistsAfterAlterTable(); + } + + @Override + public boolean useFollowOnLocking(QueryParameters parameters) { + return delegate.useFollowOnLocking(parameters); + } + + @Override + public String getQueryHintString(String query, String hints) { + return delegate.getQueryHintString(query, hints); + } + + @Override + public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) throws SQLException { + return delegate.supportsNamedParameters(databaseMetaData); + } + + @Override + public boolean supportsNationalizedTypes() { + return delegate.supportsNationalizedTypes(); + } + + @Override + public boolean supportsNonQueryWithCTE() { + return delegate.supportsNonQueryWithCTE(); + } + + @Override + public boolean supportsValuesList() { + return delegate.supportsValuesList(); + } + + @Override + public boolean supportsSkipLocked() { + return delegate.supportsSkipLocked(); + } + + @Override + public boolean supportsNoWait() { + return delegate.supportsNoWait(); + } + + @Override + public boolean isLegacyLimitHandlerBehaviorEnabled() { + return delegate.isLegacyLimitHandlerBehaviorEnabled(); + } + + @Override + public String inlineLiteral(String literal) { + return delegate.inlineLiteral(literal); + } + + @Override + public String addSqlHintOrComment(String sql, QueryParameters parameters, boolean commentsEnabled) { + return delegate.addSqlHintOrComment(sql, parameters, commentsEnabled); + } + @Override public boolean supportsPartitionBy() { // NOTE: we can't delegate because this is called in constructor diff --git a/integration/hibernate-5.4-jakarta/pom.xml b/integration/hibernate-5.5-jakarta/pom.xml similarity index 97% rename from integration/hibernate-5.4-jakarta/pom.xml rename to integration/hibernate-5.5-jakarta/pom.xml index f563b2e713..d007af5663 100644 --- a/integration/hibernate-5.4-jakarta/pom.xml +++ b/integration/hibernate-5.5-jakarta/pom.xml @@ -25,13 +25,13 @@ ../pom.xml - blaze-persistence-integration-hibernate-5.4-jakarta + blaze-persistence-integration-hibernate-5.5-jakarta jar ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.5 provided @@ -66,7 +66,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -117,7 +117,7 @@ - + diff --git a/integration/hibernate-5.5/pom.xml b/integration/hibernate-5.5/pom.xml new file mode 100644 index 0000000000..560c1e0186 --- /dev/null +++ b/integration/hibernate-5.5/pom.xml @@ -0,0 +1,170 @@ + + + + + 4.0.0 + + + com.blazebit + blaze-persistence-integration + 1.6.5-SNAPSHOT + ../pom.xml + + + blaze-persistence-integration-hibernate-5.5 + jar + + Blazebit Persistence Integration Hibernate 5.5 + + + com.blazebit.persistence.integration.hibernate + + + + + ${project.groupId} + blaze-persistence-core-api + + + ${project.groupId} + blaze-persistence-integration-hibernate-base + + + com.blazebit + blaze-persistence-integration-hibernate-5.3 + ${project.version} + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + true + + + ${project.groupId}:blaze-persistence-integration-hibernate-5.3 + + + + + + + + org.moditect + moditect-maven-plugin + + + add-module-infos + package + + add-module-info + + + + + module ${module.name} { + requires java.sql; + requires java.persistence; + requires org.hibernate.orm.core; + requires com.blazebit.persistence.core; + requires transitive com.blazebit.persistence.integration.hibernate.base; + requires static com.blazebit.persistence.view; + provides com.blazebit.persistence.integration.hibernate.base.HibernateAccess with com.blazebit.persistence.integration.hibernate.Hibernate53Access; + provides com.blazebit.persistence.spi.EntityManagerFactoryIntegrator with com.blazebit.persistence.integration.hibernate.Hibernate53EntityManagerFactoryIntegrator; + provides com.blazebit.persistence.view.spi.TransactionAccessFactory with com.blazebit.persistence.integration.hibernate.Hibernate5TransactionAccessFactory; + provides org.hibernate.integrator.spi.Integrator with com.blazebit.persistence.integration.hibernate.Hibernate53Integrator; + provides org.hibernate.persister.spi.PersisterClassResolver with com.blazebit.persistence.integration.hibernate.CustomPersisterClassResolver; + provides org.hibernate.boot.spi.MetadataContributor with com.blazebit.persistence.integration.hibernate.Hibernate53MetadataContributor; + provides org.hibernate.service.spi.ServiceContributor with com.blazebit.persistence.integration.hibernate.Hibernate53ServiceContributor; + exports com.blazebit.persistence.integration.hibernate; + } + + + + + + + + + + + + blazebit-release + + + + maven-dependency-plugin + + + shade-javadoc + + copy + + + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.3 + ${project.version} + jar + javadoc + true + ${project.build.directory} + ${project.artifactId}-${project.version}-javadoc.jar + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + package + + attach-artifact + + + + + ${project.build.directory}/${project.artifactId}-${project.version}-javadoc.jar + javadoc + jar + + + + + + + + + + + + diff --git a/integration/hibernate-5.6-jakarta/pom.xml b/integration/hibernate-5.6-jakarta/pom.xml new file mode 100644 index 0000000000..40fc0bc3fe --- /dev/null +++ b/integration/hibernate-5.6-jakarta/pom.xml @@ -0,0 +1,219 @@ + + + + + 4.0.0 + + + com.blazebit + blaze-persistence-integration + 1.6.5-SNAPSHOT + ../pom.xml + + + blaze-persistence-integration-hibernate-5.6-jakarta + jar + + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.6 + provided + + + jakarta.persistence + jakarta.persistence-api + ${version.jakarta-jpa-api} + + + ${project.groupId} + blaze-persistence-core-api-jakarta + + + + ${project.groupId} + blaze-persistence-integration-hibernate-base-jakarta + + + + + + + maven-antrun-plugin + + + transform-jar + package + + run + + + + + + + + + + + + + + + + + + + + + + transform-sources-jar + package + + run + + + + + + + + + + + + + + + + + + + + + + + + transform-javadoc + package + + run + + + + + + + + + + + + + + + + + + + + + + + + + + org.eclipse.transformer + org.eclipse.transformer.cli + 0.2.0 + + + ant-contrib + ant-contrib + 1.0b3 + + + ant + ant + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + package + + attach-artifact + + + + + ${project.build.directory}/${project.build.finalName}-sources.jar + sources + jar + + + + + + + + + + + blazebit-release + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-artifacts + package + + attach-artifact + + + + + ${project.build.directory}/${project.build.finalName}-sources.jar + sources + jar + + + ${project.build.directory}/${project.build.finalName}-javadoc.jar + javadoc + jar + + + + + + + + + + + + diff --git a/integration/hibernate-5.6/pom.xml b/integration/hibernate-5.6/pom.xml new file mode 100644 index 0000000000..dc9895dde0 --- /dev/null +++ b/integration/hibernate-5.6/pom.xml @@ -0,0 +1,145 @@ + + + + + 4.0.0 + + + com.blazebit + blaze-persistence-integration + 1.6.5-SNAPSHOT + ../pom.xml + + + blaze-persistence-integration-hibernate-5.6 + jar + + Blazebit Persistence Integration Hibernate 5.6 + + + com.blazebit.persistence.integration.hibernate + + + + + ${project.groupId} + blaze-persistence-core-api + + + ${project.groupId} + blaze-persistence-integration-hibernate-base + + + ${project.groupId} + blaze-persistence-entity-view-api + provided + + + + ${project.groupId} + blaze-apt-utils + provided + + + + org.hibernate + hibernate-core + ${version.hibernate-5.6} + provided + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-resource + generate-resources + + add-resource + + + + + target/generated/resources + + + + + + + + org.bsc.maven + maven-processor-plugin + + + process-resources + + process + + generate-resources + + target/generated/resources + + + com.blazebit.apt.service.ServiceProviderAnnotationProcessor + + + + + + + org.moditect + moditect-maven-plugin + + + add-module-infos + package + + add-module-info + + + + + module ${module.name} { + requires java.sql; + requires java.persistence; + requires org.hibernate.orm.core; + requires com.blazebit.persistence.core; + requires transitive com.blazebit.persistence.integration.hibernate.base; + requires static com.blazebit.persistence.view; + provides com.blazebit.persistence.integration.hibernate.base.HibernateAccess with com.blazebit.persistence.integration.hibernate.Hibernate56Access; + provides com.blazebit.persistence.spi.EntityManagerFactoryIntegrator with com.blazebit.persistence.integration.hibernate.Hibernate56EntityManagerFactoryIntegrator; + provides com.blazebit.persistence.view.spi.TransactionAccessFactory with com.blazebit.persistence.integration.hibernate.Hibernate5TransactionAccessFactory; + provides org.hibernate.integrator.spi.Integrator with com.blazebit.persistence.integration.hibernate.Hibernate56Integrator; + provides org.hibernate.persister.spi.PersisterClassResolver with com.blazebit.persistence.integration.hibernate.CustomPersisterClassResolver; + provides org.hibernate.boot.spi.MetadataContributor with com.blazebit.persistence.integration.hibernate.Hibernate56MetadataContributor; + provides org.hibernate.service.spi.ServiceContributor with com.blazebit.persistence.integration.hibernate.Hibernate56ServiceContributor; + exports com.blazebit.persistence.integration.hibernate; + } + + + + + + + + + diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomBasicCollectionPersister.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomBasicCollectionPersister.java new file mode 100644 index 0000000000..890e5f473b --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomBasicCollectionPersister.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.integration.hibernate.base.CustomCollectionPersister; +import org.hibernate.MappingException; +import org.hibernate.cache.CacheException; +import org.hibernate.cache.spi.access.CollectionDataAccess; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.SubselectFetch; +import org.hibernate.loader.collection.CollectionInitializer; +import org.hibernate.mapping.Collection; +import org.hibernate.persister.collection.BasicCollectionPersister; +import org.hibernate.persister.spi.PersisterCreationContext; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +public class CustomBasicCollectionPersister extends BasicCollectionPersister implements CustomCollectionPersister { + + public CustomBasicCollectionPersister(Collection collectionBinding, CollectionDataAccess cacheAccessStrategy, PersisterCreationContext creationContext) throws MappingException, CacheException { + super(collectionBinding, cacheAccessStrategy, creationContext); + } + + @Override + protected CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SharedSessionContractImplementor session) { + return new CustomSubselectCollectionLoader( + this, + subselect.toSubselectString( getCollectionType().getLHSPropertyName() ), + subselect.getResult(), + subselect.getQueryParameters(), + subselect.getNamedParameterLocMap(), + session.getFactory(), + session.getLoadQueryInfluencers() + ); + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomMultiTableBulkIdStrategy.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomMultiTableBulkIdStrategy.java new file mode 100644 index 0000000000..e09ee8abf5 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomMultiTableBulkIdStrategy.java @@ -0,0 +1,81 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; +import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.hql.internal.ast.HqlSqlWalker; +import org.hibernate.hql.internal.ast.tree.FromElement; +import org.hibernate.hql.internal.ast.tree.UpdateStatement; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.TableBasedUpdateHandlerImpl; +import org.hibernate.persister.entity.AbstractEntityPersister; + +import java.util.logging.Logger; + +/** + * @author Christian Beikov + * @since 1.3.0 + */ +public class CustomMultiTableBulkIdStrategy implements MultiTableBulkIdStrategy { + + private static final Logger LOG = Logger.getLogger(CustomMultiTableBulkIdStrategy.class.getName()); + private final MultiTableBulkIdStrategy delegate; + + public CustomMultiTableBulkIdStrategy(MultiTableBulkIdStrategy delegate) { + this.delegate = delegate; + } + + @Override + public UpdateHandler buildUpdateHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { + UpdateHandler updateHandler = delegate.buildUpdateHandler(factory, walker); + + final UpdateStatement updateStatement = (UpdateStatement) walker.getAST(); + final FromElement fromElement = updateStatement.getFromClause().getFromElement(); + final AbstractEntityPersister targetedPersister = (AbstractEntityPersister) fromElement.getQueryable(); + + // Only do this when we have secondary tables + if (targetedPersister.getConstraintOrderedTableNameClosure().length > 1) { + if (updateHandler instanceof TableBasedUpdateHandlerImpl) { + return new CustomTableBasedUpdateHandlerImpl((TableBasedUpdateHandlerImpl) updateHandler, walker); + } else { + LOG.warning("Unsupported update handler that can't be adapted to support updates to secondary tables: " + updateHandler); + } + } + + return updateHandler; + } + + @Override + public DeleteHandler buildDeleteHandler(SessionFactoryImplementor factory, HqlSqlWalker walker) { + return delegate.buildDeleteHandler(factory, walker); + } + + @Override + public void prepare(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata, SessionFactoryOptions sessionFactoryOptions, SqlStringGenerationContext sqlStringGenerationContext) { + delegate.prepare(jdbcServices, connectionAccess, metadata, sessionFactoryOptions, sqlStringGenerationContext); + } + + @Override + public void release(JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess) { + delegate.release(jdbcServices, connectionAccess); + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomOneToManyPersister.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomOneToManyPersister.java new file mode 100644 index 0000000000..ef248cdfc6 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomOneToManyPersister.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.integration.hibernate.base.CustomCollectionPersister; +import org.hibernate.MappingException; +import org.hibernate.cache.CacheException; +import org.hibernate.cache.spi.access.CollectionDataAccess; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.SubselectFetch; +import org.hibernate.loader.collection.CollectionInitializer; +import org.hibernate.mapping.Collection; +import org.hibernate.persister.collection.OneToManyPersister; +import org.hibernate.persister.spi.PersisterCreationContext; + +/** + * + * @author Christian Beikov + * @since 1.2.0 + */ +public class CustomOneToManyPersister extends OneToManyPersister implements CustomCollectionPersister { + + public CustomOneToManyPersister(Collection collectionBinding, CollectionDataAccess cacheAccessStrategy, PersisterCreationContext creationContext) throws MappingException, CacheException { + super(collectionBinding, cacheAccessStrategy, creationContext); + } + + @Override + protected CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SharedSessionContractImplementor session) { + return new CustomSubselectOneToManyLoader( + this, + subselect.toSubselectString( getCollectionType().getLHSPropertyName() ), + subselect.getResult(), + subselect.getQueryParameters(), + subselect.getNamedParameterLocMap(), + session.getFactory(), + session.getLoadQueryInfluencers() + ); + } +} \ No newline at end of file diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomPersisterClassResolver.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomPersisterClassResolver.java new file mode 100644 index 0000000000..d0a438e85d --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomPersisterClassResolver.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.apt.service.ServiceProvider; +import org.hibernate.mapping.Collection; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.persister.internal.StandardPersisterClassResolver; +import org.hibernate.persister.spi.PersisterClassResolver; + +/** + * @author Jan-Willem Gmelig Meyling + * @since 1.2.0 + */ +@ServiceProvider(PersisterClassResolver.class) +public class CustomPersisterClassResolver extends StandardPersisterClassResolver implements PersisterClassResolver { + + @Override + public Class getCollectionPersisterClass(Collection metadata) { + return metadata.isOneToMany() ? CustomOneToManyPersister.class : CustomBasicCollectionPersister.class; + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomSubselectCollectionLoader.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomSubselectCollectionLoader.java new file mode 100644 index 0000000000..c719eadda1 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomSubselectCollectionLoader.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.integration.hibernate.base.SubselectLoaderUtils; +import org.hibernate.MappingException; +import org.hibernate.engine.spi.LoadQueryInfluencers; +import org.hibernate.engine.spi.QueryParameters; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.loader.collection.SubselectCollectionLoader; +import org.hibernate.persister.collection.QueryableCollection; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Collection; +import java.util.Map; + +import static com.blazebit.persistence.integration.hibernate.base.SubselectLoaderUtils.getPreparedStatementProxy; + +/** + * @author Jan-Willem Gmelig Meyling + * @since 1.2.0 + */ +public class CustomSubselectCollectionLoader extends SubselectCollectionLoader { + + private final int cteParameterCount; + private final int selectParameterCount; + + public CustomSubselectCollectionLoader(QueryableCollection persister, String subquery, Collection entityKeys, QueryParameters queryParameters, Map namedParameterLocMap, SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) throws MappingException { + super(persister, subquery, entityKeys, queryParameters, namedParameterLocMap, factory, loadQueryInfluencers); + String originalSql = queryParameters.getFilteredSQL(); + if (originalSql.startsWith("with ")) { + StringBuilder sb = new StringBuilder(sql.length() + originalSql.length()); + cteParameterCount = SubselectLoaderUtils.applyCteAndCountParameters(originalSql, sb); + selectParameterCount = SubselectLoaderUtils.countSelectParameters(originalSql, sb.length()); + sb.append(sql); + this.sql = sb.toString(); + } else { + cteParameterCount = 0; + selectParameterCount = 0; + } + } + + @Override + protected int bindParameterValues(PreparedStatement statement, QueryParameters queryParameters, int startIndex, SharedSessionContractImplementor session) throws SQLException { + if (cteParameterCount > 0) { + statement = getPreparedStatementProxy(statement, queryParameters, cteParameterCount, selectParameterCount); + } + return super.bindParameterValues(statement, queryParameters, startIndex, session); + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomSubselectOneToManyLoader.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomSubselectOneToManyLoader.java new file mode 100644 index 0000000000..44b993ab69 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomSubselectOneToManyLoader.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.integration.hibernate.base.SubselectLoaderUtils; +import org.hibernate.MappingException; +import org.hibernate.engine.spi.LoadQueryInfluencers; +import org.hibernate.engine.spi.QueryParameters; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.loader.collection.SubselectOneToManyLoader; +import org.hibernate.persister.collection.QueryableCollection; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Map; + +import static com.blazebit.persistence.integration.hibernate.base.SubselectLoaderUtils.getPreparedStatementProxy; + +/** + * + * @author Christian Beikov + * @since 1.2.0 + */ +public class CustomSubselectOneToManyLoader extends SubselectOneToManyLoader { + + private final int cteParameterCount; + private final int selectParameterCount; + + public CustomSubselectOneToManyLoader(QueryableCollection persister, String subquery, java.util.Collection entityKeys, QueryParameters queryParameters, Map namedParameterLocMap, SessionFactoryImplementor factory, LoadQueryInfluencers loadQueryInfluencers) throws MappingException { + super(persister, subquery, entityKeys, queryParameters, namedParameterLocMap, factory, loadQueryInfluencers); + String originalSql = queryParameters.getFilteredSQL(); + if (originalSql.startsWith("with ")) { + StringBuilder sb = new StringBuilder(sql.length() + originalSql.length()); + cteParameterCount = SubselectLoaderUtils.applyCteAndCountParameters(originalSql, sb); + selectParameterCount = SubselectLoaderUtils.countSelectParameters(originalSql, sb.length()); + sb.append(sql); + this.sql = sb.toString(); + } else { + cteParameterCount = 0; + selectParameterCount = 0; + } + } + + @Override + protected int bindParameterValues(PreparedStatement statement, QueryParameters queryParameters, int startIndex, SharedSessionContractImplementor session) throws SQLException { + if (cteParameterCount > 0) { + statement = getPreparedStatementProxy(statement, queryParameters, cteParameterCount, selectParameterCount); + } + return super.bindParameterValues(statement, queryParameters, startIndex, session); + } + +} \ No newline at end of file diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomTableBasedUpdateHandlerImpl.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomTableBasedUpdateHandlerImpl.java new file mode 100644 index 0000000000..bb99a8e61a --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/CustomTableBasedUpdateHandlerImpl.java @@ -0,0 +1,177 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.engine.spi.QueryParameters; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.event.spi.EventSource; +import org.hibernate.hql.internal.ast.HqlSqlWalker; +import org.hibernate.hql.internal.ast.tree.AssignmentSpecification; +import org.hibernate.hql.internal.ast.tree.FromElement; +import org.hibernate.hql.internal.ast.tree.UpdateStatement; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.TableBasedUpdateHandlerImpl; +import org.hibernate.persister.entity.AbstractEntityPersister; +import org.hibernate.persister.entity.Queryable; + +import java.lang.reflect.Proxy; +import java.sql.PreparedStatement; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author Christian Beikov + * @since 1.3.0 + */ +public class CustomTableBasedUpdateHandlerImpl implements MultiTableBulkIdStrategy.UpdateHandler { + + private final TableBasedUpdateHandlerImpl delegate; + private final String[] secondaryTableUpdates; + private final String[] secondaryTableInserts; + + public CustomTableBasedUpdateHandlerImpl(TableBasedUpdateHandlerImpl delegate, HqlSqlWalker walker) { + this.delegate = delegate; + // Here comes the madness... + // We need to somehow execute our code within the temporary table scope, but since there is no way for use to do this externally, + // we need to use invocation handlers to get a callback at the right time + // First, we reduce the update statements + String[] updates = delegate.getSqlStatements(); + UpdateStatement updateStatement = (UpdateStatement) walker.getAST(); + FromElement fromElement = updateStatement.getFromClause().getFromElement(); + AbstractEntityPersister targetedPersister = (AbstractEntityPersister) fromElement.getQueryable(); + String[] tableNames = targetedPersister.getConstraintOrderedTableNameClosure(); + String[][] columnNames = targetedPersister.getContraintOrderedTableKeyColumnClosure(); + + int subclassCount = delegate.getTargetedQueryable().getEntityMetamodel().getSubclassEntityNames().size(); + Set subclassTableNames = new HashSet<>(); + for (int i = 0; i < subclassCount; i++) { + subclassTableNames.add(delegate.getTargetedQueryable().getSubclassTableName(i)); + } + + final String[] secondaryTableUpdates = updates.clone(); + final String[] secondaryTableInserts = new String[updates.length]; + + StringBuilder sb = new StringBuilder(); + StringBuilder selectSb = new StringBuilder(); + String selectString = "select "; + String inString = "IN ("; + for (int tableIndex = 0; tableIndex < tableNames.length; tableIndex++) { + if (updates[tableIndex] != null) { + // We introduce a dummy update statement that we react upon + if (subclassTableNames.contains(tableNames[tableIndex])) { + secondaryTableUpdates[tableIndex] = null; + } else { + sb.setLength(0); + selectSb.setLength(0); + + boolean affected = false; + String idSubselect = updates[tableIndex].substring(updates[tableIndex].lastIndexOf(inString) + inString.length(), updates[tableIndex].length() - 1); + + sb.append("insert into ").append(tableNames[tableIndex]); + String[] keyColumnNames = columnNames[tableIndex]; + sb.append('('); + + final List assignmentSpecifications = walker.getAssignmentSpecifications(); + for (AssignmentSpecification assignmentSpecification : assignmentSpecifications) { + if (assignmentSpecification.affectsTable(tableNames[tableIndex])) { + String sqlAssignmentFragment = assignmentSpecification.getSqlAssignmentFragment(); + int eqIndex = sqlAssignmentFragment.indexOf('='); + sb.append(sqlAssignmentFragment, 0, eqIndex); + sb.append(','); + selectSb.append(sqlAssignmentFragment, eqIndex + 1, sqlAssignmentFragment.length()); + selectSb.append(','); + + affected = true; + } + } + if (affected) { + for (int i = 0; i < keyColumnNames.length; i++) { + sb.append(keyColumnNames[i]); + sb.append(','); + } + sb.setCharAt(sb.length() - 1, ')'); + sb.append(' ').append(selectString); + sb.append(selectSb); + sb.append(idSubselect, selectString.length(), idSubselect.length()); + sb.append(" where not exists (select 1 from "); + sb.append(tableNames[tableIndex]); + sb.append(" a where "); + + for (int i = 0; i < keyColumnNames.length; i++) { + sb.append("a."); + sb.append(keyColumnNames[i]); + sb.append(" = "); + sb.append(keyColumnNames[i]); + sb.append(" and "); + } + + sb.setLength(sb.length() - " and ".length()); + sb.append(")"); + + secondaryTableInserts[tableIndex] = sb.toString(); + } + + updates[tableIndex] = ""; + } + } + } + + this.secondaryTableUpdates = secondaryTableUpdates; + this.secondaryTableInserts = secondaryTableInserts; + } + + @Override + public int execute(SharedSessionContractImplementor s, QueryParameters queryParameters) { + final SessionImplementor session = (SessionImplementor) s; + final JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator(); + + Object jdbcCoordinatorProxy = Proxy.newProxyInstance(jdbcCoordinator.getClass().getClassLoader(), new Class[]{JdbcCoordinator.class}, new JdbcCoordinatorInvocationHandler(jdbcCoordinator, new DelegatingStatementPreparerImpl(jdbcCoordinator.getStatementPreparer()) { + PreparedStatement statementProxy; + SecondaryTableUpdateSupportingPreparedStatementInvocationHandler invocationHandler; + + @Override + public PreparedStatement prepareStatement(String sql, boolean isCallable) { + if (sql.isEmpty()) { + // Return the statement proxy which collects parameters and then executes update/insert statements for secondary tables + invocationHandler.prepareNext(); + return statementProxy; + } else { + PreparedStatement insertStatement = super.prepareStatement(sql, isCallable); + this.invocationHandler = new SecondaryTableUpdateSupportingPreparedStatementInvocationHandler(session, jdbcCoordinator.getStatementPreparer(), insertStatement, secondaryTableUpdates, secondaryTableInserts); + this.statementProxy = (PreparedStatement) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{PreparedStatement.class}, invocationHandler); + return statementProxy; + } + } + })); + SessionImplementor sessionProxy = (SessionImplementor) Proxy.newProxyInstance(session.getClass().getClassLoader(), new Class[]{SessionImplementor.class, EventSource.class}, new Hibernate56SessionInvocationHandler(session, jdbcCoordinatorProxy)); + + return delegate.execute(sessionProxy, queryParameters); + } + + @Override + public Queryable getTargetedQueryable() { + return delegate.getTargetedQueryable(); + } + + @Override + public String[] getSqlStatements() { + return delegate.getSqlStatements(); + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/DelegatingStatementPreparerImpl.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/DelegatingStatementPreparerImpl.java new file mode 100644 index 0000000000..fa550d5abd --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/DelegatingStatementPreparerImpl.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import org.hibernate.ScrollMode; +import org.hibernate.engine.jdbc.spi.StatementPreparer; + +import java.sql.PreparedStatement; +import java.sql.Statement; + +/** + * @author Christian Beikov + * @since 1.3.0 + */ +public class DelegatingStatementPreparerImpl implements StatementPreparer { + + private StatementPreparer delegate; + + public DelegatingStatementPreparerImpl(StatementPreparer delegate) { + this.delegate = delegate; + } + + @Override + public Statement createStatement() { + return delegate.createStatement(); + } + + @Override + public PreparedStatement prepareStatement(String sql) { + return delegate.prepareStatement(sql); + } + + @Override + public PreparedStatement prepareStatement(String sql, boolean isCallable) { + return delegate.prepareStatement(sql, isCallable); + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) { + return delegate.prepareStatement(sql, autoGeneratedKeys); + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) { + return delegate.prepareStatement(sql, columnNames); + } + + @Override + public PreparedStatement prepareQueryStatement(String sql, boolean isCallable, ScrollMode scrollMode) { + return delegate.prepareQueryStatement(sql, isCallable, scrollMode); + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56Access.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56Access.java new file mode 100644 index 0000000000..79720d2bd6 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56Access.java @@ -0,0 +1,263 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.apt.service.ServiceProvider; +import com.blazebit.persistence.integration.hibernate.base.HibernateAccess; +import com.blazebit.persistence.integration.hibernate.base.HibernateReturningResult; +import com.blazebit.persistence.integration.hibernate.base.ScrollableResultsIterator; +import com.blazebit.persistence.spi.DbmsDialect; +import org.hibernate.HibernateException; +import org.hibernate.LockOptions; +import org.hibernate.Query; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.engine.query.spi.HQLQueryPlan; +import org.hibernate.engine.spi.ExceptionConverter; +import org.hibernate.engine.spi.QueryParameters; +import org.hibernate.engine.spi.RowSelection; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.TypedValue; +import org.hibernate.event.spi.EventSource; +import org.hibernate.hql.internal.ast.ParameterTranslationsImpl; +import org.hibernate.hql.internal.ast.exec.BasicExecutor; +import org.hibernate.hql.internal.ast.exec.StatementExecutor; +import org.hibernate.hql.spi.ParameterTranslations; +import org.hibernate.loader.hql.QueryLoader; +import org.hibernate.param.ParameterSpecification; +import org.hibernate.query.internal.AbstractProducedQuery; +import org.hibernate.query.internal.QueryParameterBindingsImpl; +import org.hibernate.query.spi.QueryImplementor; +import org.hibernate.query.spi.ScrollableResultsImplementor; +import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl; +import org.hibernate.resource.transaction.spi.TransactionCoordinator; +import org.hibernate.type.Type; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceException; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +@ServiceProvider(HibernateAccess.class) +public class Hibernate56Access implements HibernateAccess { + + private static final Method DO_EXECUTE_METHOD; + private static final Method DO_EXECUTE_METHOD_NEW; + private static final Constructor PARAMETER_TRANSLATIONS_CONSTRUCTOR; + + static { + Method m = null; + Method mNew = null; + try { + m = BasicExecutor.class.getDeclaredMethod("doExecute", QueryParameters.class, SharedSessionContractImplementor.class, String.class, List.class); + m.setAccessible(true); + } catch (Exception e) { + // As of Hibernate 5.4.21 the signature changed... + try { + mNew = BasicExecutor.class.getDeclaredMethod("doExecute", String.class, QueryParameters.class, List.class, SharedSessionContractImplementor.class); + mNew.setAccessible(true); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + DO_EXECUTE_METHOD = m; + DO_EXECUTE_METHOD_NEW = mNew; + try { + Constructor c = ParameterTranslationsImpl.class.getDeclaredConstructor(List.class); + c.setAccessible(true); + PARAMETER_TRANSLATIONS_CONSTRUCTOR = c; + } catch (Exception ex) { + // As of Hibernate 5.4.21 the signature changed... + throw new RuntimeException(ex); + } + } + + @Override + public SessionImplementor wrapSession(SessionImplementor session, DbmsDialect dbmsDialect, String[][] columns, int[] returningSqlTypes, HibernateReturningResult returningResult) { + JdbcCoordinator jdbcCoordinator = session.getJdbcCoordinator(); + + Object jdbcCoordinatorProxy = Proxy.newProxyInstance(jdbcCoordinator.getClass().getClassLoader(), new Class[]{ JdbcCoordinator.class }, new JdbcCoordinatorInvocationHandler(jdbcCoordinator, new StatementPreparerImpl(jdbcCoordinator, session.getFactory(), dbmsDialect, columns, returningSqlTypes, returningResult))); + Object sessionProxy = Proxy.newProxyInstance(session.getClass().getClassLoader(), new Class[]{ SessionImplementor.class, EventSource.class }, new Hibernate56SessionInvocationHandler(session, jdbcCoordinatorProxy)); + return (SessionImplementor) sessionProxy; + } + + @Override + public SessionFactoryImplementor wrapSessionFactory(SessionFactoryImplementor sessionFactory, DbmsDialect dbmsDialect) { + Object dialectProxy = new Hibernate56LimitHandlingDialect(sessionFactory.getDialect(), dbmsDialect); + Object sessionFactoryProxy = Proxy.newProxyInstance(sessionFactory.getClass().getClassLoader(), new Class[]{ SessionFactoryImplementor.class }, new Hibernate56SessionFactoryInvocationHandler(sessionFactory, dialectProxy)); + return (SessionFactoryImplementor) sessionFactoryProxy; + } + + @Override + public void checkTransactionSynchStatus(SessionImplementor session) { + TransactionCoordinator coordinator = session.getTransactionCoordinator(); + coordinator.pulse(); + if (coordinator instanceof JtaTransactionCoordinatorImpl) { + ((JtaTransactionCoordinatorImpl) coordinator).getSynchronizationCallbackCoordinator().processAnyDelayedAfterCompletion(); + } + } + + @Override + public void afterTransaction(SessionImplementor session, boolean success) { + TransactionCoordinator coordinator = session.getTransactionCoordinator(); + if (!session.isTransactionInProgress() ) { + session.getJdbcCoordinator().afterTransaction(); + } + if (coordinator instanceof JtaTransactionCoordinatorImpl) { + ((JtaTransactionCoordinatorImpl) coordinator).getSynchronizationCallbackCoordinator().processAnyDelayedAfterCompletion(); + } + } + + @Override + @SuppressWarnings({ "unchecked" }) + public List list(QueryLoader queryLoader, SessionImplementor sessionImplementor, QueryParameters queryParameters) { + return queryLoader.list(sessionImplementor, queryParameters); + } + + @Override + public List performList(HQLQueryPlan queryPlan, SessionImplementor sessionImplementor, QueryParameters queryParameters) { + return queryPlan.performList(queryParameters, sessionImplementor); + } + + @Override + public Stream performStream(HQLQueryPlan queryPlan, SessionImplementor sessionImplementor, QueryParameters queryParameters) { + final ScrollableResultsImplementor scrollableResults = queryPlan.performScroll(queryParameters, sessionImplementor); + final Iterator iterator = new ScrollableResultsIterator(scrollableResults); + final Spliterator spliterator = Spliterators.spliteratorUnknownSize(iterator, Spliterator.NONNULL); + return StreamSupport.stream(spliterator, false).onClose(new Runnable() { + @Override + public void run() { + scrollableResults.close(); + } + }); + } + + @Override + public int performExecuteUpdate(HQLQueryPlan queryPlan, SessionImplementor sessionImplementor, QueryParameters queryParameters) { + return queryPlan.performExecuteUpdate(queryParameters, sessionImplementor); + } + + @Override + public void doExecute(StatementExecutor executor, String delete, QueryParameters parameters, SessionImplementor session, List parameterSpecifications) { + try { + if (DO_EXECUTE_METHOD == null) { + DO_EXECUTE_METHOD_NEW.invoke(executor, delete, parameters, parameterSpecifications, session); + } else { + DO_EXECUTE_METHOD.invoke(executor, parameters, session, delete, parameterSpecifications); + } + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + @Override + public QueryParameters getQueryParameters(Query hibernateQuery, Map namedParams) { + return ((AbstractProducedQuery) hibernateQuery).getQueryParameters(); + } + + @Override + public Map getNamedParams(Query hibernateQuery) { + QueryParameterBindingsImpl queryParameterBindings = hibernateQuery.unwrap(QueryParameterBindingsImpl.class); + return queryParameterBindings.collectNamedParameterBindings(); + } + + @Override + public String expandParameterLists(SessionImplementor session, org.hibernate.Query hibernateQuery, Map namedParamsCopy) { + QueryParameterBindingsImpl queryParameterBindings = hibernateQuery.unwrap(QueryParameterBindingsImpl.class); + SharedSessionContractImplementor producer = (SharedSessionContractImplementor) ((QueryImplementor) hibernateQuery).getProducer(); + String query = hibernateQuery.getQueryString(); + + // NOTE: In Hibernate 5.3.0.CR1 this is call causes a side effect which is why this is essentially unusable for us + query = queryParameterBindings.expandListValuedParameters(query, producer); + return query; + } + + private ExceptionConverter getExceptionConverter(EntityManager em) { + return em.unwrap(SharedSessionContractImplementor.class).getExceptionConverter(); + } + + @Override + public RuntimeException convert(EntityManager em, HibernateException e) { + return getExceptionConverter(em).convert(e); + } + + @Override + public void handlePersistenceException(EntityManager em, PersistenceException e) { + getExceptionConverter(em).convert(e); + } + + @Override + public void throwPersistenceException(EntityManager em, HibernateException e) { + getExceptionConverter(em).convert(e); + } + + @Override + public QueryParameters createQueryParameters( + final Type[] positionalParameterTypes, + final Object[] positionalParameterValues, + final Map namedParameters, + final LockOptions lockOptions, + final RowSelection rowSelection, + final boolean isReadOnlyInitialized, + final boolean readOnly, + final boolean cacheable, + final String cacheRegion, + //final boolean forceCacheRefresh, + final String comment, + final List queryHints, + final Serializable[] collectionKeys) { + return new QueryParameters( + positionalParameterTypes, + positionalParameterValues, + namedParameters, + lockOptions, + rowSelection, + isReadOnlyInitialized, + readOnly, + cacheable, + cacheRegion, + comment, + queryHints, + collectionKeys, + null + ); + } + + @Override + public ParameterTranslations createParameterTranslations(List queryParameterSpecifications) { + try { + return PARAMETER_TRANSLATIONS_CONSTRUCTOR.newInstance(queryParameterSpecifications); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56DelegatingDialect.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56DelegatingDialect.java new file mode 100644 index 0000000000..d9e1fc337f --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56DelegatingDialect.java @@ -0,0 +1,1026 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import org.hibernate.HibernateException; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; +import org.hibernate.MappingException; +import org.hibernate.NullPrecedence; +import org.hibernate.ScrollMode; +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; +import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.dialect.ColumnAliasExtractor; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.LobMergeStrategy; +import org.hibernate.dialect.identity.IdentityColumnSupport; +import org.hibernate.dialect.lock.LockingStrategy; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.unique.UniqueDelegate; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; +import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver; +import org.hibernate.engine.spi.QueryParameters; +import org.hibernate.exception.spi.SQLExceptionConversionDelegate; +import org.hibernate.exception.spi.SQLExceptionConverter; +import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.loader.BatchLoadSizingStrategy; +import org.hibernate.mapping.Constraint; +import org.hibernate.mapping.ForeignKey; +import org.hibernate.mapping.Index; +import org.hibernate.mapping.Table; +import org.hibernate.persister.entity.Lockable; +import org.hibernate.procedure.spi.CallableStatementSupport; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.sql.CaseFragment; +import org.hibernate.sql.JoinFragment; +import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; +import org.hibernate.tool.schema.spi.Exporter; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +import java.sql.CallableStatement; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +public class Hibernate56DelegatingDialect extends Dialect { + + private final Dialect delegate; + + public Hibernate56DelegatingDialect(Dialect delegate) { + this.delegate = delegate; + } + + @Override + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + delegate.contributeTypes(typeContributions, serviceRegistry); + } + + @Override + public String getTypeName(int code) throws HibernateException { + return delegate.getTypeName(code); + } + + @Override + public String getTypeName(int code, long length, int precision, int scale) throws HibernateException { + return delegate.getTypeName(code, length, precision, scale); + } + + @Override + public String getCastTypeName(int code) { + return delegate.getCastTypeName(code); + } + + @Override + public String cast(String value, int jdbcTypeCode, int length, int precision, int scale) { + return delegate.cast(value, jdbcTypeCode, length, precision, scale); + } + + @Override + public String cast(String value, int jdbcTypeCode, int length) { + return delegate.cast(value, jdbcTypeCode, length); + } + + @Override + public String cast(String value, int jdbcTypeCode, int precision, int scale) { + return delegate.cast(value, jdbcTypeCode, precision, scale); + } + + @Override + public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) { + return delegate.remapSqlTypeDescriptor(sqlTypeDescriptor); + } + + @Override + public LobMergeStrategy getLobMergeStrategy() { + return delegate.getLobMergeStrategy(); + } + + @Override + public String getHibernateTypeName(int code) throws HibernateException { + return delegate.getHibernateTypeName(code); + } + + @Override + public boolean isTypeNameRegistered(String typeName) { + return delegate.isTypeNameRegistered(typeName); + } + + @Override + public String getHibernateTypeName(int code, int length, int precision, int scale) throws HibernateException { + return delegate.getHibernateTypeName(code, length, precision, scale); + } + + @Override + @SuppressWarnings({ "rawtypes", "deprecation" }) + public Class getNativeIdentifierGeneratorClass() { + return delegate.getNativeIdentifierGeneratorClass(); + } + + @Override + public IdentityColumnSupport getIdentityColumnSupport() { + return delegate.getIdentityColumnSupport(); + } + + @Override + public boolean supportsSequences() { + return delegate.supportsSequences(); + } + + @Override + public boolean supportsPooledSequences() { + return delegate.supportsPooledSequences(); + } + + @Override + public String getSequenceNextValString(String sequenceName) throws MappingException { + return delegate.getSequenceNextValString(sequenceName); + } + + @Override + public String getSelectSequenceNextValString(String sequenceName) throws MappingException { + return delegate.getSelectSequenceNextValString(sequenceName); + } + + @Override + @Deprecated + public String[] getCreateSequenceStrings(String sequenceName) throws MappingException { + return delegate.getCreateSequenceStrings(sequenceName); + } + + @Override + public String[] getCreateSequenceStrings(String sequenceName, int initialValue, int incrementSize) throws MappingException { + return delegate.getCreateSequenceStrings(sequenceName, initialValue, incrementSize); + } + + @Override + public String[] getDropSequenceStrings(String sequenceName) throws MappingException { + return delegate.getDropSequenceStrings(sequenceName); + } + + @Override + public String getQuerySequencesString() { + return delegate.getQuerySequencesString(); + } + + @Override + public SequenceInformationExtractor getSequenceInformationExtractor() { + return delegate.getSequenceInformationExtractor(); + } + + @Override + public String getSelectGUIDString() { + return delegate.getSelectGUIDString(); + } + + @Override + public LimitHandler getLimitHandler() { + return delegate.getLimitHandler(); + } + + @Override + @Deprecated + public boolean supportsLimit() { + return delegate.supportsLimit(); + } + + @Override + @Deprecated + public boolean supportsLimitOffset() { + return delegate.supportsLimitOffset(); + } + + @Override + @Deprecated + public boolean supportsVariableLimit() { + return delegate.supportsVariableLimit(); + } + + @Override + @Deprecated + public boolean bindLimitParametersInReverseOrder() { + return delegate.bindLimitParametersInReverseOrder(); + } + + @Override + @Deprecated + public boolean bindLimitParametersFirst() { + return delegate.bindLimitParametersFirst(); + } + + @Override + @Deprecated + public boolean useMaxForLimit() { + return delegate.useMaxForLimit(); + } + + @Override + @Deprecated + public boolean forceLimitUsage() { + return delegate.forceLimitUsage(); + } + + @Override + @Deprecated + public String getLimitString(String query, int offset, int limit) { + return delegate.getLimitString(query, offset, limit); + } + + @Override + @Deprecated + public int convertToFirstRowValue(int zeroBasedFirstResult) { + return delegate.convertToFirstRowValue(zeroBasedFirstResult); + } + + @Override + public boolean supportsLockTimeouts() { + return delegate.supportsLockTimeouts(); + } + + @Override + public boolean isLockTimeoutParameterized() { + return delegate.isLockTimeoutParameterized(); + } + + @Override + public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) { + return delegate.getLockingStrategy(lockable, lockMode); + } + + @Override + public String getForUpdateString(LockOptions lockOptions) { + return delegate.getForUpdateString(lockOptions); + } + + @Override + public String getForUpdateString(LockMode lockMode) { + return delegate.getForUpdateString(lockMode); + } + + @Override + public String getForUpdateString() { + return delegate.getForUpdateString(); + } + + @Override + public String getWriteLockString(int timeout) { + return delegate.getWriteLockString(timeout); + } + + @Override + public String getReadLockString(int timeout) { + return delegate.getReadLockString(timeout); + } + + @Override + public boolean forUpdateOfColumns() { + return delegate.forUpdateOfColumns(); + } + + @Override + public boolean supportsOuterJoinForUpdate() { + return delegate.supportsOuterJoinForUpdate(); + } + + @Override + public String getForUpdateString(String aliases) { + return delegate.getForUpdateString(aliases); + } + + @Override + public String getForUpdateString(String aliases, LockOptions lockOptions) { + return delegate.getForUpdateString(aliases, lockOptions); + } + + @Override + public String getForUpdateNowaitString() { + return delegate.getForUpdateNowaitString(); + } + + @Override + public String getForUpdateSkipLockedString() { + return delegate.getForUpdateSkipLockedString(); + } + + @Override + public String getForUpdateNowaitString(String aliases) { + return delegate.getForUpdateNowaitString(aliases); + } + + @Override + public String getForUpdateSkipLockedString(String aliases) { + return delegate.getForUpdateSkipLockedString(aliases); + } + + @Override + @Deprecated + public String appendLockHint(LockMode mode, String tableName) { + return delegate.appendLockHint(mode, tableName); + } + + @Override + public String appendLockHint(LockOptions lockOptions, String tableName) { + return delegate.appendLockHint(lockOptions, tableName); + } + + @Override + public String applyLocksToSql(String sql, LockOptions aliasedLockOptions, Map keyColumnNames) { + return delegate.applyLocksToSql(sql, aliasedLockOptions, keyColumnNames); + } + + @Override + public String getCreateTableString() { + return delegate.getCreateTableString(); + } + + @Override + public String getCreateMultisetTableString() { + return delegate.getCreateMultisetTableString(); + } + + @Override + public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { + return delegate.getDefaultMultiTableBulkIdStrategy(); + } + + @Override + public int registerResultSetOutParameter(CallableStatement statement, int position) throws SQLException { + return delegate.registerResultSetOutParameter(statement, position); + } + + @Override + public int registerResultSetOutParameter(CallableStatement statement, String name) throws SQLException { + return delegate.registerResultSetOutParameter(statement, name); + } + + @Override + public ResultSet getResultSet(CallableStatement statement) throws SQLException { + return delegate.getResultSet(statement); + } + + @Override + public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException { + return delegate.getResultSet(statement, position); + } + + @Override + public ResultSet getResultSet(CallableStatement statement, String name) throws SQLException { + return delegate.getResultSet(statement, name); + } + + @Override + public boolean supportsCurrentTimestampSelection() { + return delegate.supportsCurrentTimestampSelection(); + } + + @Override + public boolean isCurrentTimestampSelectStringCallable() { + return delegate.isCurrentTimestampSelectStringCallable(); + } + + @Override + public String getCurrentTimestampSelectString() { + return delegate.getCurrentTimestampSelectString(); + } + + @Override + public String getCurrentTimestampSQLFunctionName() { + return delegate.getCurrentTimestampSQLFunctionName(); + } + + @Override + @Deprecated + public SQLExceptionConverter buildSQLExceptionConverter() { + return delegate.buildSQLExceptionConverter(); + } + + @Override + public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { + return delegate.buildSQLExceptionConversionDelegate(); + } + + @Override + public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() { + return delegate.getViolatedConstraintNameExtracter(); + } + + @Override + public String getSelectClauseNullString(int sqlType) { + return delegate.getSelectClauseNullString(sqlType); + } + + @Override + public boolean supportsUnionAll() { + return delegate.supportsUnionAll(); + } + + @Override + public JoinFragment createOuterJoinFragment() { + return delegate.createOuterJoinFragment(); + } + + @Override + public CaseFragment createCaseFragment() { + return delegate.createCaseFragment(); + } + + @Override + public String getNoColumnsInsertString() { + return delegate.getNoColumnsInsertString(); + } + + @Override + public String getLowercaseFunction() { + return delegate.getLowercaseFunction(); + } + + @Override + public String getCaseInsensitiveLike() { + return delegate.getCaseInsensitiveLike(); + } + + @Override + public boolean supportsCaseInsensitiveLike() { + return delegate.supportsCaseInsensitiveLike(); + } + + @Override + public String transformSelectString(String select) { + return delegate.transformSelectString(select); + } + + @Override + public int getMaxAliasLength() { + return delegate.getMaxAliasLength(); + } + + @Override + public String toBooleanValueString(boolean bool) { + return delegate.toBooleanValueString(bool); + } + + @Override + @Deprecated + public Set getKeywords() { + return delegate.getKeywords(); + } + + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { + return delegate.buildIdentifierHelper(builder, dbMetaData); + } + + @Override + public char openQuote() { + return delegate.openQuote(); + } + + @Override + public char closeQuote() { + return delegate.closeQuote(); + } + + @Override + public Exporter getTableExporter() { + return delegate.getTableExporter(); + } + + @Override + public Exporter getSequenceExporter() { + return delegate.getSequenceExporter(); + } + + @Override + public Exporter getIndexExporter() { + return delegate.getIndexExporter(); + } + + @Override + public Exporter getForeignKeyExporter() { + return delegate.getForeignKeyExporter(); + } + + @Override + public Exporter getUniqueKeyExporter() { + return delegate.getUniqueKeyExporter(); + } + + @Override + public Exporter getAuxiliaryDatabaseObjectExporter() { + return delegate.getAuxiliaryDatabaseObjectExporter(); + } + + @Override + public boolean canCreateCatalog() { + return delegate.canCreateCatalog(); + } + + @Override + public String[] getCreateCatalogCommand(String catalogName) { + return delegate.getCreateCatalogCommand(catalogName); + } + + @Override + public String[] getDropCatalogCommand(String catalogName) { + return delegate.getDropCatalogCommand(catalogName); + } + + @Override + public boolean canCreateSchema() { + return delegate.canCreateSchema(); + } + + @Override + public String[] getCreateSchemaCommand(String schemaName) { + return delegate.getCreateSchemaCommand(schemaName); + } + + @Override + public String[] getDropSchemaCommand(String schemaName) { + return delegate.getDropSchemaCommand(schemaName); + } + + @Override + public String getCurrentSchemaCommand() { + return delegate.getCurrentSchemaCommand(); + } + + @Override + public SchemaNameResolver getSchemaNameResolver() { + return delegate.getSchemaNameResolver(); + } + + @Override + public boolean hasAlterTable() { + return delegate.hasAlterTable(); + } + + @Override + public boolean dropConstraints() { + return delegate.dropConstraints(); + } + + @Override + public boolean qualifyIndexName() { + return delegate.qualifyIndexName(); + } + + @Override + public String getAddColumnString() { + return delegate.getAddColumnString(); + } + + @Override + public String getAddColumnSuffixString() { + return delegate.getAddColumnSuffixString(); + } + + @Override + public String getDropForeignKeyString() { + return delegate.getDropForeignKeyString(); + } + + @Override + public String getTableTypeString() { + return delegate.getTableTypeString(); + } + + @Override + public String getAddForeignKeyConstraintString(String constraintName, String[] foreignKey, String referencedTable, String[] primaryKey, boolean referencesPrimaryKey) { + return delegate.getAddForeignKeyConstraintString(constraintName, foreignKey, referencedTable, primaryKey, referencesPrimaryKey); + } + + @Override + public String getAddPrimaryKeyConstraintString(String constraintName) { + return delegate.getAddPrimaryKeyConstraintString(constraintName); + } + + @Override + public boolean hasSelfReferentialForeignKeyBug() { + return delegate.hasSelfReferentialForeignKeyBug(); + } + + @Override + public String getNullColumnString() { + return delegate.getNullColumnString(); + } + + @Override + public boolean supportsCommentOn() { + return delegate.supportsCommentOn(); + } + + @Override + public String getTableComment(String comment) { + return delegate.getTableComment(comment); + } + + @Override + public String getColumnComment(String comment) { + return delegate.getColumnComment(comment); + } + + @Override + public boolean supportsIfExistsBeforeTableName() { + return delegate.supportsIfExistsBeforeTableName(); + } + + @Override + public boolean supportsIfExistsAfterTableName() { + return delegate.supportsIfExistsAfterTableName(); + } + + @Override + public boolean supportsIfExistsBeforeConstraintName() { + return delegate.supportsIfExistsBeforeConstraintName(); + } + + @Override + public boolean supportsIfExistsAfterConstraintName() { + return delegate.supportsIfExistsAfterConstraintName(); + } + + @Override + public String getDropTableString(String tableName) { + return delegate.getDropTableString(tableName); + } + + @Override + public boolean supportsColumnCheck() { + return delegate.supportsColumnCheck(); + } + + @Override + public boolean supportsTableCheck() { + return delegate.supportsTableCheck(); + } + + @Override + public boolean supportsCascadeDelete() { + return delegate.supportsCascadeDelete(); + } + + @Override + public String getCascadeConstraintsString() { + return delegate.getCascadeConstraintsString(); + } + + @Override + public String getCrossJoinSeparator() { + return delegate.getCrossJoinSeparator(); + } + + @Override + public ColumnAliasExtractor getColumnAliasExtractor() { + return delegate.getColumnAliasExtractor(); + } + + @Override + public boolean supportsEmptyInList() { + return delegate.supportsEmptyInList(); + } + + @Override + public boolean areStringComparisonsCaseInsensitive() { + return delegate.areStringComparisonsCaseInsensitive(); + } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return delegate.supportsRowValueConstructorSyntax(); + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return delegate.supportsRowValueConstructorSyntaxInInList(); + } + + @Override + public boolean useInputStreamToInsertBlob() { + return delegate.useInputStreamToInsertBlob(); + } + + @Override + public boolean supportsParametersInInsertSelect() { + return delegate.supportsParametersInInsertSelect(); + } + + @Override + public boolean replaceResultVariableInOrderByClauseWithPosition() { + return delegate.replaceResultVariableInOrderByClauseWithPosition(); + } + + @Override + public String renderOrderByElement(String expression, String collation, String order, NullPrecedence nulls) { + return delegate.renderOrderByElement(expression, collation, order, nulls); + } + + @Override + public boolean requiresCastingOfParametersInSelectClause() { + return delegate.requiresCastingOfParametersInSelectClause(); + } + + @Override + public boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() { + return delegate.supportsResultSetPositionQueryMethodsOnForwardOnlyCursor(); + } + + @Override + public boolean supportsCircularCascadeDeleteConstraints() { + return delegate.supportsCircularCascadeDeleteConstraints(); + } + + @Override + public boolean supportsSubselectAsInPredicateLHS() { + return delegate.supportsSubselectAsInPredicateLHS(); + } + + @Override + public boolean supportsExpectedLobUsagePattern() { + return delegate.supportsExpectedLobUsagePattern(); + } + + @Override + public boolean supportsLobValueChangePropogation() { + return delegate.supportsLobValueChangePropogation(); + } + + @Override + public boolean supportsUnboundedLobLocatorMaterialization() { + return delegate.supportsUnboundedLobLocatorMaterialization(); + } + + @Override + public boolean supportsSubqueryOnMutatingTable() { + return delegate.supportsSubqueryOnMutatingTable(); + } + + @Override + public boolean supportsExistsInSelect() { + return delegate.supportsExistsInSelect(); + } + + @Override + public boolean doesReadCommittedCauseWritersToBlockReaders() { + return delegate.doesReadCommittedCauseWritersToBlockReaders(); + } + + @Override + public boolean doesRepeatableReadCauseReadersToBlockWriters() { + return delegate.doesRepeatableReadCauseReadersToBlockWriters(); + } + + @Override + public boolean supportsBindAsCallableArgument() { + return delegate.supportsBindAsCallableArgument(); + } + + @Override + public boolean supportsTupleCounts() { + return delegate.supportsTupleCounts(); + } + + @Override + public boolean supportsTupleDistinctCounts() { + return delegate.supportsTupleDistinctCounts(); + } + + @Override + public boolean requiresParensForTupleDistinctCounts() { + return delegate.requiresParensForTupleDistinctCounts(); + } + + @Override + public int getInExpressionCountLimit() { + return delegate.getInExpressionCountLimit(); + } + + @Override + public boolean forceLobAsLastValue() { + return delegate.forceLobAsLastValue(); + } + + @Override + public boolean useFollowOnLocking() { + return delegate.useFollowOnLocking(); + } + + @Override + public String getNotExpression(String expression) { + return delegate.getNotExpression(expression); + } + + @Override + public UniqueDelegate getUniqueDelegate() { + return delegate.getUniqueDelegate(); + } + + @Override + @Deprecated + public boolean supportsUnique() { + return delegate.supportsUnique(); + } + + @Override + @Deprecated + public boolean supportsUniqueConstraintInCreateAlterTable() { + return delegate.supportsUniqueConstraintInCreateAlterTable(); + } + + @Override + @Deprecated + public String getAddUniqueConstraintString(String constraintName) { + return delegate.getAddUniqueConstraintString(constraintName); + } + + @Override + @Deprecated + public boolean supportsNotNullUnique() { + return delegate.supportsNotNullUnique(); + } + + @Override + public String getQueryHintString(String query, List hints) { + return delegate.getQueryHintString(query, hints); + } + + @Override + public ScrollMode defaultScrollMode() { + return delegate.defaultScrollMode(); + } + + @Override + public boolean supportsTuplesInSubqueries() { + return delegate.supportsTuplesInSubqueries(); + } + + @Override + public CallableStatementSupport getCallableStatementSupport() { + return delegate.getCallableStatementSupport(); + } + + @Override + public NameQualifierSupport getNameQualifierSupport() { + return delegate.getNameQualifierSupport(); + } + + @Override + public BatchLoadSizingStrategy getDefaultBatchLoadSizingStrategy() { + return delegate.getDefaultBatchLoadSizingStrategy(); + } + + @Override + public boolean isJdbcLogWarningsEnabledByDefault() { + return delegate.isJdbcLogWarningsEnabledByDefault(); + } + + @Override + public void augmentRecognizedTableTypes(List tableTypesList) { + delegate.augmentRecognizedTableTypes(tableTypesList); + } + + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return delegate.equivalentTypes(typeCode1, typeCode2); + } + + @Override + public String getNativeIdentifierGeneratorStrategy() { + return delegate.getNativeIdentifierGeneratorStrategy(); + } + + @Override + public String getWriteLockString(String aliases, int timeout) { + return delegate.getWriteLockString(aliases, timeout); + } + + @Override + public String getReadLockString(String aliases, int timeout) { + return delegate.getReadLockString(aliases, timeout); + } + + @Override + public String getAlterTableString(String tableName) { + return delegate.getAlterTableString(tableName); + } + + @Override + public boolean supportsNoColumnsInsert() { + return delegate.supportsNoColumnsInsert(); + } + + @Override + public String getAddForeignKeyConstraintString(String constraintName, String foreignKeyDefinition) { + return delegate.getAddForeignKeyConstraintString(constraintName, foreignKeyDefinition); + } + + @Override + public boolean supportsIfExistsAfterAlterTable() { + return delegate.supportsIfExistsAfterAlterTable(); + } + + @Override + public boolean supportsRowValueConstructorSyntaxInSet() { + return delegate.supportsRowValueConstructorSyntaxInSet(); + } + + @Override + public boolean useFollowOnLocking(QueryParameters parameters) { + return delegate.useFollowOnLocking(parameters); + } + + @Override + public String getQueryHintString(String query, String hints) { + return delegate.getQueryHintString(query, hints); + } + + @Override + public boolean supportsNamedParameters(DatabaseMetaData databaseMetaData) throws SQLException { + return delegate.supportsNamedParameters(databaseMetaData); + } + + @Override + public boolean supportsNationalizedTypes() { + return delegate.supportsNationalizedTypes(); + } + + @Override + public boolean supportsNonQueryWithCTE() { + return delegate.supportsNonQueryWithCTE(); + } + + @Override + public boolean supportsValuesList() { + return delegate.supportsValuesList(); + } + + @Override + public boolean supportsSkipLocked() { + return delegate.supportsSkipLocked(); + } + + @Override + public boolean supportsNoWait() { + return delegate.supportsNoWait(); + } + + @Override + public boolean isLegacyLimitHandlerBehaviorEnabled() { + return delegate.isLegacyLimitHandlerBehaviorEnabled(); + } + + @Override + public String inlineLiteral(String literal) { + return delegate.inlineLiteral(literal); + } + + @Override + public boolean supportsJdbcConnectionLobCreation(DatabaseMetaData databaseMetaData) { + return delegate.supportsJdbcConnectionLobCreation(databaseMetaData); + } + + @Override + public String addSqlHintOrComment(String sql, QueryParameters parameters, boolean commentsEnabled) { + return delegate.addSqlHintOrComment(sql, parameters, commentsEnabled); + } + + @Override + public boolean supportsSelectAliasInGroupByClause() { + return delegate.supportsSelectAliasInGroupByClause(); + } + + @Override + public String getCreateTemporaryTableColumnAnnotation(int sqlTypeCode) { + return delegate.getCreateTemporaryTableColumnAnnotation(sqlTypeCode); + } + + @Override + public boolean supportsPartitionBy() { + // NOTE: we can't delegate because this is called in constructor + return false; + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56EntityManagerFactoryIntegrator.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56EntityManagerFactoryIntegrator.java new file mode 100644 index 0000000000..da4e943d82 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56EntityManagerFactoryIntegrator.java @@ -0,0 +1,107 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.apt.service.ServiceProvider; +import com.blazebit.persistence.integration.hibernate.base.HibernateJpa21Provider; +import com.blazebit.persistence.integration.hibernate.base.function.AbstractHibernateEntityManagerFactoryIntegrator; +import com.blazebit.persistence.spi.EntityManagerFactoryIntegrator; +import com.blazebit.persistence.spi.JpaProvider; +import com.blazebit.persistence.spi.JpaProviderFactory; +import org.hibernate.Session; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.jpa.HibernateEntityManagerFactory; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.persister.entity.EntityPersister; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.PersistenceUnitUtil; +import java.util.Map; + +/** + * + * @author Christian Beikov + * @since 1.2.0 + */ +@ServiceProvider(EntityManagerFactoryIntegrator.class) +public class Hibernate56EntityManagerFactoryIntegrator extends AbstractHibernateEntityManagerFactoryIntegrator { + + @Override + public String getDbms(EntityManagerFactory entityManagerFactory) { + if (entityManagerFactory == null) { + return null; + } + + return getDbmsName(entityManagerFactory, null, entityManagerFactory.unwrap(SessionFactoryImplementor.class).getDialect()); + } + + private String getDbms(EntityManager entityManager) { + if (entityManager == null) { + return null; + } + Session s = entityManager.unwrap(Session.class); + Dialect dialect = getDialect(s); + return getDbmsName(entityManager.getEntityManagerFactory(), entityManager, dialect); + } + + private Map getCollectionPersisters(EntityManager em) { + if (em == null) { + return null; + } + + return em.unwrap(SessionImplementor.class).getFactory().getCollectionPersisters(); + } + + private Map getEntityPersisters(EntityManager em) { + if (em == null) { + return null; + } + + return em.unwrap(SessionImplementor.class).getFactory().getEntityPersisters(); + } + + @Override + public JpaProviderFactory getJpaProviderFactory(final EntityManagerFactory entityManagerFactory) { + return new JpaProviderFactory() { + @Override + public JpaProvider createJpaProvider(EntityManager em) { + SessionFactoryImplementor factory = null; + PersistenceUnitUtil persistenceUnitUtil = entityManagerFactory == null ? null : entityManagerFactory.getPersistenceUnitUtil(); + if (persistenceUnitUtil == null && em != null) { + persistenceUnitUtil = em.getEntityManagerFactory().getPersistenceUnitUtil(); + } + if (em == null) { + if (entityManagerFactory instanceof SessionFactoryImplementor) { + factory = (SessionFactoryImplementor) entityManagerFactory; + } else if (entityManagerFactory instanceof HibernateEntityManagerFactory) { + factory = (SessionFactoryImplementor) ((HibernateEntityManagerFactory) entityManagerFactory).getSessionFactory(); + } + if (factory == null && entityManagerFactory != null) { + factory = entityManagerFactory.unwrap(SessionFactoryImplementor.class); + } + if (factory != null) { + return new HibernateJpa21Provider(persistenceUnitUtil, getDbmsName(entityManagerFactory, em, factory.getDialect()), factory.getEntityPersisters(), factory.getCollectionPersisters(), MAJOR, MINOR, FIX, TYPE); + } + } + return new HibernateJpa21Provider(persistenceUnitUtil, getDbms(em), getEntityPersisters(em), getCollectionPersisters(em), MAJOR, MINOR, FIX, TYPE); + } + }; + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56Integrator.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56Integrator.java new file mode 100644 index 0000000000..392af20503 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56Integrator.java @@ -0,0 +1,108 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.apt.service.ServiceProvider; +import com.blazebit.persistence.CTE; +import com.blazebit.persistence.integration.hibernate.base.Database; +import com.blazebit.persistence.integration.hibernate.base.MultiIterator; +import com.blazebit.persistence.integration.hibernate.base.SimpleDatabase; +import com.blazebit.persistence.integration.hibernate.base.TableNameFormatter; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.Namespace; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.integrator.spi.Integrator; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.Table; +import org.hibernate.persister.spi.PersisterClassResolver; +import org.hibernate.service.spi.SessionFactoryServiceRegistry; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +@ServiceProvider(Integrator.class) +public class Hibernate56Integrator implements Integrator { + + @Override + public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { + // TODO: remember metadata for exact column types + List invalidPolymorphicCtes = new ArrayList<>(); + List invalidFormulaCtes = new ArrayList<>(); + for (PersistentClass clazz : metadata.getEntityBindings()) { + Class entityClass = clazz.getMappedClass(); + + if (entityClass != null && entityClass.isAnnotationPresent(CTE.class)) { + if (clazz.isPolymorphic()) { + invalidPolymorphicCtes.add(clazz); + } + Iterator iterator = clazz.getSubclassPropertyClosureIterator(); + while (iterator.hasNext()) { + Property property = iterator.next(); + if (property.getValue().hasFormula()) { + invalidFormulaCtes.add(clazz.getClassName() + "#" + property.getName()); + } + } + clazz.getTable().setSubselect("select * from " + clazz.getJpaEntityName()); + } + } + + if (!invalidPolymorphicCtes.isEmpty()) { + StringBuilder sb = new StringBuilder(); + sb.append("Found invalid polymorphic CTE entity definitions. CTE entities may not extend other entities:"); + for (PersistentClass invalidPolymorphicCte : invalidPolymorphicCtes) { + sb.append("\n - ").append(invalidPolymorphicCte.getMappedClass().getName()); + } + + throw new RuntimeException(sb.toString()); + } + if (!invalidFormulaCtes.isEmpty()) { + StringBuilder sb = new StringBuilder(); + sb.append("Found uses of @Formula in CTE entity definitions. CTE entities can't use @Formula:"); + for (String invalidFormulaCte : invalidFormulaCtes) { + sb.append("\n - ").append(invalidFormulaCte); + } + + throw new RuntimeException(sb.toString()); + } + + serviceRegistry.locateServiceBinding(PersisterClassResolver.class).setService(new CustomPersisterClassResolver()); + TableNameFormatter formatter = new NativeTableNameFormatter(sessionFactory.getJdbcServices().getJdbcEnvironment().getQualifiedObjectNameFormatter()); + serviceRegistry.locateServiceBinding(Database.class).setService(new SimpleDatabase(getTableIterator(metadata.getDatabase().getNamespaces()), sessionFactory.getDialect(), formatter, metadata)); + } + + private Iterator
getTableIterator(Iterable namespaces) { + List> iterators = new ArrayList<>(); + Iterator namespaceIterator = namespaces.iterator(); + + while (namespaceIterator.hasNext()) { + iterators.add(namespaceIterator.next().getTables().iterator()); + } + + return new MultiIterator<>(iterators); + } + + @Override + public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56LimitHandler.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56LimitHandler.java new file mode 100644 index 0000000000..2fa076c36f --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56LimitHandler.java @@ -0,0 +1,81 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.spi.DbmsDialect; +import com.blazebit.persistence.spi.DbmsLimitHandler; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.engine.spi.RowSelection; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +public class Hibernate56LimitHandler implements LimitHandler { + + private final DbmsLimitHandler limitHandler; + private Integer limit; + private Integer offset; + + public Hibernate56LimitHandler(Dialect dialect, DbmsDialect dbmsDialect) { + this.limitHandler = dbmsDialect.createLimitHandler(); + } + + @Override + public boolean supportsLimit() { + return limitHandler.supportsLimit(); + } + + @Override + public boolean supportsLimitOffset() { + return limitHandler.supportsLimitOffset(); + } + + @Override + public String processSql(String sql, RowSelection selection) { + if (selection == null || selection.getMaxRows() == null || selection.getMaxRows().intValue() == Integer.MAX_VALUE) { + this.limit = null; + } else { + this.limit = selection.getMaxRows(); + } + if (selection == null || selection.getFirstRow() == null || selection.getFirstRow().intValue() < 1) { + this.offset = null; + } else { + this.offset = selection.getFirstRow(); + } + return limitHandler.applySql(sql, false, limit, offset); + } + + @Override + public int bindLimitParametersAtStartOfQuery(RowSelection selection, PreparedStatement statement, int index) throws SQLException { + return limitHandler.bindLimitParametersAtStartOfQuery(limit, offset, statement, index); + } + + @Override + public int bindLimitParametersAtEndOfQuery(RowSelection selection, PreparedStatement statement, int index) throws SQLException { + return limitHandler.bindLimitParametersAtEndOfQuery(limit, offset, statement, index); + } + + @Override + public void setMaxRows(RowSelection selection, PreparedStatement statement) throws SQLException { + limitHandler.setMaxRows(limit, offset, statement); + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56LimitHandlingDialect.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56LimitHandlingDialect.java new file mode 100644 index 0000000000..007b9821fd --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56LimitHandlingDialect.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.spi.DbmsDialect; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.pagination.LimitHandler; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +public class Hibernate56LimitHandlingDialect extends Hibernate56DelegatingDialect { + + private final DbmsDialect dbmsDialect; + + public Hibernate56LimitHandlingDialect(Dialect delegate, DbmsDialect dbmsDialect) { + super(delegate); + this.dbmsDialect = dbmsDialect; + } + + @Override + public LimitHandler getLimitHandler() { + return new Hibernate56LimitHandler(this, dbmsDialect); + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56MetadataContributor.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56MetadataContributor.java new file mode 100644 index 0000000000..d88985e196 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56MetadataContributor.java @@ -0,0 +1,103 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.apt.service.ServiceProvider; +import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; +import org.hibernate.boot.spi.InFlightMetadataCollector; +import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.boot.spi.MetadataBuildingOptions; +import org.hibernate.boot.spi.MetadataContributor; +import org.hibernate.cfg.AnnotationBinder; +import org.hibernate.cfg.InheritanceState; +import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.service.Service; +import org.hibernate.service.spi.Configurable; +import org.hibernate.service.spi.ServiceBinding; +import org.jboss.jandex.IndexView; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +@ServiceProvider(MetadataContributor.class) +public class Hibernate56MetadataContributor implements MetadataContributor, Service, Configurable { + + private static final Logger LOG = Logger.getLogger(Hibernate56MetadataContributor.class.getName()); + private Map configurationValues; + + @Override + public void configure(Map configurationValues) { + this.configurationValues = configurationValues; + } + + @Override + public void contribute(InFlightMetadataCollector metadataCollector, IndexView jandexIndex) { + ServiceBinding.ServiceLifecycleOwner lifecycleOwner = (ServiceBinding.ServiceLifecycleOwner) metadataCollector.getBootstrapContext().getServiceRegistry(); + lifecycleOwner.configureService(new ServiceBinding<>(lifecycleOwner, Hibernate56MetadataContributor.class, this)); + Object existingStrategy = configurationValues.get("hibernate.hql.bulk_id_strategy"); + if (existingStrategy == null) { + JdbcServices jdbcService = metadataCollector.getBootstrapContext().getServiceRegistry().getService(JdbcServices.class); + MultiTableBulkIdStrategy defaultMultiTableBulkIdStrategy = jdbcService.getDialect().getDefaultMultiTableBulkIdStrategy(); + configurationValues.put("hibernate.hql.bulk_id_strategy", new CustomMultiTableBulkIdStrategy(defaultMultiTableBulkIdStrategy)); + } else { + LOG.warning("Can't replace hibernate.hql.bulk_id_strategy because it was overridden by the user with: " + existingStrategy); + } + // Skip if already registered + if (metadataCollector.getEntityBinding("com.blazebit.persistence.impl.function.entity.ValuesEntity") != null) { + return; + } + + MetadataBuildingContext metadataBuildingContext = new MetadataBuildingContextRootImpl( + metadataCollector.getBootstrapContext(), + metadataCollector.getMetadataBuildingOptions(), + metadataCollector); + + addEntity("com.blazebit.persistence.impl.function.entity.ValuesEntity", metadataBuildingContext); + } + + private void addEntity(String className, MetadataBuildingContext metadataBuildingContext) { + try { + MetadataBuildingOptions options = metadataBuildingContext.getBuildingOptions(); + Object /*ReflectionManager*/ reflectionManager = MetadataBuildingOptions.class.getMethod("getReflectionManager").invoke(options); + // Object /*XClass*/ clazz = reflectionManager.classForName(className); + Method classForName = reflectionManager.getClass().getMethod("classForName", String.class); + Object /*XClass*/ clazz = classForName.invoke(reflectionManager, className); + Map inheritanceStatePerClass = new HashMap(1); + + // InheritanceState state = new InheritanceState(clazz, inheritanceStatePerClass, metadataBuildingContext); + InheritanceState state = InheritanceState.class.getConstructor(classForName.getReturnType(), Map.class, MetadataBuildingContext.class) + .newInstance(clazz, inheritanceStatePerClass, metadataBuildingContext); + + inheritanceStatePerClass.put(clazz, state); + + // AnnotationBinder.bindClass(clazz, inheritanceStatePerClass, metadataBuildingContext); + AnnotationBinder.class.getMethod("bindClass", classForName.getReturnType(), Map.class, MetadataBuildingContext.class) + .invoke(null, clazz, inheritanceStatePerClass, metadataBuildingContext); + } catch (RuntimeException ex) { + throw ex; + } catch (Exception ex) { + throw new RuntimeException("Could not add entity", ex); + } + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56ServiceContributor.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56ServiceContributor.java new file mode 100644 index 0000000000..4745310d1e --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56ServiceContributor.java @@ -0,0 +1,49 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.apt.service.ServiceProvider; +import com.blazebit.persistence.integration.hibernate.base.Database; +import org.hibernate.boot.registry.StandardServiceInitiator; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.service.spi.ServiceContributor; +import org.hibernate.service.spi.ServiceRegistryImplementor; + +import java.util.Map; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +@ServiceProvider(ServiceContributor.class) +public class Hibernate56ServiceContributor implements ServiceContributor { + + @Override + public void contribute(StandardServiceRegistryBuilder serviceRegistryBuilder) { + serviceRegistryBuilder.addInitiator(new StandardServiceInitiator() { + @Override + public Database initiateService(@SuppressWarnings("rawtypes") Map configurationValues, ServiceRegistryImplementor registry) { + return null; + } + + @Override + public Class getServiceInitiated() { + return Database.class; + } + }); + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56SessionFactoryInvocationHandler.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56SessionFactoryInvocationHandler.java new file mode 100644 index 0000000000..d81c1b3cc3 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56SessionFactoryInvocationHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import org.hibernate.engine.spi.SessionFactoryImplementor; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +public class Hibernate56SessionFactoryInvocationHandler implements InvocationHandler { + + private final SessionFactoryImplementor delegate; + private final Object dialect; + + public Hibernate56SessionFactoryInvocationHandler(SessionFactoryImplementor delegate, Object dialect) { + this.delegate = delegate; + this.dialect = dialect; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("getDialect".equals(method.getName())) { + return dialect; + } + + return method.invoke(delegate, args); + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56SessionInvocationHandler.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56SessionInvocationHandler.java new file mode 100644 index 0000000000..01cd74f1bb --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate56SessionInvocationHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import org.hibernate.engine.spi.SessionImplementor; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +public class Hibernate56SessionInvocationHandler implements InvocationHandler { + + private final SessionImplementor delegate; + private final Object jdbcCoordinatorProxy; + + public Hibernate56SessionInvocationHandler(SessionImplementor delegate, Object jdbcCoordinatorProxy) { + this.delegate = delegate; + this.jdbcCoordinatorProxy = jdbcCoordinatorProxy; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("getJdbcCoordinator".equals(method.getName())) { + return jdbcCoordinatorProxy; + } + + return method.invoke(delegate, args); + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5EntityTransactionSynchronizationStrategy.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5EntityTransactionSynchronizationStrategy.java new file mode 100644 index 0000000000..c2d5c3c371 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5EntityTransactionSynchronizationStrategy.java @@ -0,0 +1,69 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.view.spi.TransactionAccess; +import com.blazebit.persistence.view.spi.TransactionSupport; +import org.hibernate.Session; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.resource.transaction.spi.SynchronizationRegistry; + +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; +import javax.transaction.Synchronization; + +/** + * + * @author Christian Beikov + * @since 1.2.0 + */ +public class Hibernate5EntityTransactionSynchronizationStrategy implements TransactionAccess, TransactionSupport { + + private final EntityTransaction tx; + private final SynchronizationRegistry synchronizationRegistry; + + public Hibernate5EntityTransactionSynchronizationStrategy(EntityManager em) { + try { + this.tx = em.getTransaction(); + } catch (IllegalStateException e) { + throw new IllegalStateException("Could not access entity transaction!", e); + } + Session s = em.unwrap(Session.class); + this.synchronizationRegistry = ((SessionImplementor) s).getTransactionCoordinator().getLocalSynchronizations(); + } + + @Override + public boolean isActive() { + return tx.isActive(); + } + + @Override + public void markRollbackOnly() { + tx.setRollbackOnly(); + } + + @Override + public void registerSynchronization(Synchronization synchronization) { + synchronizationRegistry.registerSynchronization(synchronization); + } + + @Override + public void transactional(Runnable runnable) { + // In resource local mode, we have no global transaction state + runnable.run(); + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5JtaPlatformTransactionSynchronizationStrategy.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5JtaPlatformTransactionSynchronizationStrategy.java new file mode 100644 index 0000000000..c583712084 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5JtaPlatformTransactionSynchronizationStrategy.java @@ -0,0 +1,71 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.view.spi.TransactionAccess; +import com.blazebit.persistence.view.spi.TransactionSupport; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; + +import javax.transaction.Status; +import javax.transaction.Synchronization; +import javax.transaction.SystemException; +import javax.transaction.TransactionManager; + +/** + * @author Moritz Becker + * @since 1.4.0 + */ +public class Hibernate5JtaPlatformTransactionSynchronizationStrategy implements TransactionAccess, TransactionSupport { + + private final JtaPlatform jtaPlatform; + private final TransactionManager jtaTransactionManager; + + public Hibernate5JtaPlatformTransactionSynchronizationStrategy(JtaPlatform jtaPlatform) { + this.jtaPlatform = jtaPlatform; + this.jtaTransactionManager = jtaPlatform.retrieveTransactionManager(); + } + + @Override + public boolean isActive() { + try { + return jtaPlatform.getCurrentStatus() == Status.STATUS_ACTIVE; + } catch (SystemException e) { + throw new RuntimeException(e); + } + } + + @Override + public void markRollbackOnly() { + try { + jtaTransactionManager.setRollbackOnly(); + } catch (SystemException e) { + throw new RuntimeException(e); + } + } + + @Override + public void registerSynchronization(Synchronization synchronization) { + jtaPlatform.registerSynchronization(synchronization); + } + + @Override + public void transactional(Runnable runnable) { + // In resource local mode, we have no global transaction state + runnable.run(); + } + +} \ No newline at end of file diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5TransactionAccessFactory.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5TransactionAccessFactory.java new file mode 100644 index 0000000000..6ab413eb87 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/Hibernate5TransactionAccessFactory.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.apt.service.ServiceProvider; +import com.blazebit.persistence.view.spi.TransactionAccess; +import com.blazebit.persistence.view.spi.TransactionAccessFactory; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; +import org.hibernate.service.ServiceRegistry; + +import javax.persistence.EntityManager; + +/** + * @author Moritz Becker + * @since 1.5.0 + */ +@ServiceProvider(TransactionAccessFactory.class) +public class Hibernate5TransactionAccessFactory implements TransactionAccessFactory { + @Override + public TransactionAccess createTransactionAccess(EntityManager entityManager) { + JtaPlatform jtaPlatform = getHibernate5JtaPlatformPresent(entityManager); + if (jtaPlatform == null || NoJtaPlatform.class == jtaPlatform.getClass()) { + return new Hibernate5EntityTransactionSynchronizationStrategy(entityManager); + } else { + return new Hibernate5JtaPlatformTransactionSynchronizationStrategy(jtaPlatform); + } + } + + @Override + public int getPriority() { + return 100; + } + + private static JtaPlatform getHibernate5JtaPlatformPresent(EntityManager em) { + Session hibernateSession = em.unwrap(Session.class); + SessionFactory hibernateSessionFactory = hibernateSession.getSessionFactory(); + ServiceRegistry hibernateServiceRegistry = ((SessionFactoryImplementor) hibernateSessionFactory).getServiceRegistry(); + return hibernateServiceRegistry.getService(JtaPlatform.class); + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/JdbcCoordinatorInvocationHandler.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/JdbcCoordinatorInvocationHandler.java new file mode 100644 index 0000000000..474d16f5c5 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/JdbcCoordinatorInvocationHandler.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.engine.jdbc.spi.StatementPreparer; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +public class JdbcCoordinatorInvocationHandler implements InvocationHandler { + + private final JdbcCoordinator delegate; + private final transient StatementPreparer statementPreparer; + + public JdbcCoordinatorInvocationHandler(JdbcCoordinator delegate, StatementPreparer statementPreparer) { + this.delegate = delegate; + this.statementPreparer = statementPreparer; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("getStatementPreparer".equals(method.getName())) { + return statementPreparer; + } + + return method.invoke(delegate, args); + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/NativeTableNameFormatter.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/NativeTableNameFormatter.java new file mode 100644 index 0000000000..d9e7b05eeb --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/NativeTableNameFormatter.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.integration.hibernate.base.TableNameFormatter; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter; +import org.hibernate.mapping.Table; + +/** + * + * @author Christian Beikov + * @since 1.2.0 + */ +public class NativeTableNameFormatter implements TableNameFormatter { + + private final QualifiedObjectNameFormatter formatter; + + public NativeTableNameFormatter(QualifiedObjectNameFormatter formatter) { + this.formatter = formatter; + } + + @Override + public String getQualifiedTableName(Dialect dialect, Table table) { + return formatter.format(table.getQualifiedTableName(), dialect); + } +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/PreparedStatementInvocationHandler.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/PreparedStatementInvocationHandler.java new file mode 100644 index 0000000000..a0d13387b2 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/PreparedStatementInvocationHandler.java @@ -0,0 +1,74 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.integration.hibernate.base.HibernateReturningResult; +import com.blazebit.persistence.integration.hibernate.base.ResultSetInvocationHandler; +import com.blazebit.persistence.spi.DbmsDialect; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +public class PreparedStatementInvocationHandler implements InvocationHandler { + + private final PreparedStatement delegate; + private final DbmsDialect dbmsDialect; + private final Map aliasIndex; + private final HibernateReturningResult returningResult; + + public PreparedStatementInvocationHandler(PreparedStatement delegate, DbmsDialect dbmsDialect, String[][] columns, HibernateReturningResult returningResult) { + this.delegate = delegate; + this.dbmsDialect = dbmsDialect; + this.aliasIndex = new HashMap(columns.length); + this.returningResult = returningResult; + + for (int i = 0; i < columns.length; i++) { + aliasIndex.put(columns[i][1], i + 1); + } + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("executeQuery".equals(method.getName()) && method.getParameterTypes().length == 0) { + ResultSet rs; + HibernateReturningResult result; + + if (delegate.execute()) { + rs = delegate.getResultSet(); + result = returningResult; + } else { + result = null; + returningResult.setUpdateCount(delegate.getUpdateCount()); + rs = dbmsDialect.extractReturningResult(delegate); + } + + return Proxy.newProxyInstance(rs.getClass().getClassLoader(), new Class[]{ ResultSet.class }, new ResultSetInvocationHandler(rs, aliasIndex, result)); + } + + return method.invoke(delegate, args); + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/SecondaryTableUpdateSupportingPreparedStatementInvocationHandler.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/SecondaryTableUpdateSupportingPreparedStatementInvocationHandler.java new file mode 100644 index 0000000000..0341809eb9 --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/SecondaryTableUpdateSupportingPreparedStatementInvocationHandler.java @@ -0,0 +1,105 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import org.hibernate.engine.jdbc.spi.StatementPreparer; +import org.hibernate.engine.spi.SessionImplementor; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.sql.PreparedStatement; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author Christian Beikov + * @since 1.3.0 + */ +public class SecondaryTableUpdateSupportingPreparedStatementInvocationHandler implements InvocationHandler { + + private final SessionImplementor session; + private final StatementPreparer statementPreparer; + private final PreparedStatement insertStatement; + private final String[] updates; + private final String[] inserts; + private final List> parameters = new ArrayList<>(); + private PreparedStatement preparedStatement; + private int index; + private int insertCount; + + public SecondaryTableUpdateSupportingPreparedStatementInvocationHandler(SessionImplementor session, StatementPreparer statementPreparer, PreparedStatement insertStatement, String[] updates, String[] inserts) { + this.session = session; + this.statementPreparer = statementPreparer; + this.insertStatement = insertStatement; + this.updates = updates; + this.inserts = inserts; + } + + public void prepareNext() { + preparedStatement = null; + parameters.clear(); + while (index < updates.length) { + String updateSql = updates[index++]; + if (updateSql != null) { + preparedStatement = statementPreparer.prepareStatement(updateSql, false); + break; + } + } + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + PreparedStatement s; + if (preparedStatement == null) { + s = insertStatement; + } else { + s = preparedStatement; + } + if ("executeUpdate".equals(method.getName()) && method.getParameterTypes().length == 0) { + if (preparedStatement == null) { + return insertCount = insertStatement.executeUpdate(); + } else { + int updateRows = preparedStatement.executeUpdate(); + if (updateRows != insertCount) { + // This is where our secondary table insert comes in + PreparedStatement ps = null; + int i = index - 1; + try { + ps = statementPreparer.prepareStatement(inserts[i], false); + for (Map.Entry entry : parameters) { + entry.getKey().invoke(ps, entry.getValue()); + } + session.getJdbcCoordinator().getResultSetReturn().executeUpdate(ps); + } finally { + if (ps != null) { + session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release(ps); + session.getJdbcCoordinator().afterStatementExecution(); + } + } + } + return 0; + } + } + if (method.getName().startsWith("set")) { + parameters.add(new AbstractMap.SimpleEntry<>(method, args)); + } + return method.invoke(s, args); + } + +} diff --git a/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/StatementPreparerImpl.java b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/StatementPreparerImpl.java new file mode 100644 index 0000000000..235707c42e --- /dev/null +++ b/integration/hibernate-5.6/src/main/java/com/blazebit/persistence/integration/hibernate/StatementPreparerImpl.java @@ -0,0 +1,200 @@ +/* + * Copyright 2014 - 2022 Blazebit. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.blazebit.persistence.integration.hibernate; + +import com.blazebit.persistence.integration.hibernate.base.HibernateReturningResult; +import com.blazebit.persistence.spi.DbmsDialect; +import org.hibernate.ScrollMode; +import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; +import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; +import org.hibernate.engine.jdbc.spi.StatementPreparer; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor; + +import java.lang.reflect.Proxy; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * @author Christian Beikov + * @since 1.2.0 + */ +public class StatementPreparerImpl implements StatementPreparer { + + private JdbcCoordinator jdbcCoordinator; + private SessionFactoryImplementor sessionFactoryImplementor; + private DbmsDialect dbmsDialect; + private String[][] columns; + private int[] returningSqlTypes; + private HibernateReturningResult returningResult; + + public StatementPreparerImpl(JdbcCoordinator jdbcCoordinator, SessionFactoryImplementor sessionFactoryImplementor, DbmsDialect dbmsDialect, String[][] columns, int[] returningSqlTypes, HibernateReturningResult returningResult) { + this.jdbcCoordinator = jdbcCoordinator; + this.sessionFactoryImplementor = sessionFactoryImplementor; + this.dbmsDialect = dbmsDialect; + this.columns = columns; + this.returningSqlTypes = returningSqlTypes; + this.returningResult = returningResult; + } + + protected final SessionFactoryOptions settings() { + return sessionFactoryImplementor.getSessionFactoryOptions(); + } + + protected final Connection connection() { + return logicalConnection().getPhysicalConnection(); + } + + protected final LogicalConnectionImplementor logicalConnection() { + return jdbcCoordinator.getLogicalConnection(); + } + + protected final SqlExceptionHelper sqlExceptionHelper() { + return getJdbcService().getSqlExceptionHelper(); + } + + @Override + public Statement createStatement() { + throw new UnsupportedOperationException("Not yet implemented!"); + } + + @Override + public PreparedStatement prepareStatement(String sql) { + throw new UnsupportedOperationException("Not yet implemented!"); + } + + @Override + public PreparedStatement prepareStatement(String sql, final boolean isCallable) { + throw new UnsupportedOperationException("Not yet implemented!"); + } + + private void checkAutoGeneratedKeysSupportEnabled() { + // Not sure if we should respect this +// if (!settings().isGetGeneratedKeysEnabled()) { +// throw new AssertionFailure("getGeneratedKeys() support is not enabled"); +// } + } + + @Override + public PreparedStatement prepareStatement(String sql, final int autoGeneratedKeys) { + throw new UnsupportedOperationException("Not yet implemented!"); + } + + @Override + public PreparedStatement prepareStatement(String sql, final String[] columnNames) { + throw new UnsupportedOperationException("Not yet implemented!"); + } + + @Override + public PreparedStatement prepareQueryStatement(String sql, final boolean isCallable, final ScrollMode scrollMode) { + checkAutoGeneratedKeysSupportEnabled(); + jdbcCoordinator.executeBatch(); + PreparedStatement ps = new QueryStatementPreparationTemplate(sql) { + + public PreparedStatement doPrepare() throws SQLException { + PreparedStatement ps; + ps = connection().prepareStatement(sql, dbmsDialect.getPrepareFlags()); + return dbmsDialect.prepare(ps, returningSqlTypes); + } + }.prepareStatement(); + ps = (PreparedStatement) Proxy.newProxyInstance(ps.getClass().getClassLoader(), new Class[]{PreparedStatement.class}, new PreparedStatementInvocationHandler(ps, dbmsDialect, columns, returningResult)); + jdbcCoordinator.registerLastQuery(ps); + return ps; + } + + /** + * @author Christian Beikov + * @since 1.2.0 + */ + private abstract class StatementPreparationTemplate { + + protected final String sql; + + protected StatementPreparationTemplate(String incomingSql) { + final String inspectedSql = jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getStatementInspector().inspect(incomingSql); + this.sql = inspectedSql == null ? incomingSql : inspectedSql; + } + + public PreparedStatement prepareStatement() { + try { + getJdbcService().getSqlStatementLogger().logStatement(sql); + + final PreparedStatement preparedStatement; + try { + jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getObserver().jdbcPrepareStatementStart(); + preparedStatement = doPrepare(); + setStatementTimeout(preparedStatement); + } finally { + jdbcCoordinator.getJdbcSessionOwner().getJdbcSessionContext().getObserver().jdbcPrepareStatementEnd(); + } + postProcess(preparedStatement); + return preparedStatement; + } catch (SQLException e) { + throw sqlExceptionHelper().convert(e, "could not prepare statement", sql); + } + } + + protected abstract PreparedStatement doPrepare() throws SQLException; + + public void postProcess(PreparedStatement preparedStatement) throws SQLException { + jdbcCoordinator.getResourceRegistry().register(preparedStatement, true); + // logicalConnection().notifyObserversStatementPrepared(); + } + + private void setStatementTimeout(PreparedStatement preparedStatement) throws SQLException { + final int remainingTransactionTimeOutPeriod = jdbcCoordinator.determineRemainingTransactionTimeOutPeriod(); + if (remainingTransactionTimeOutPeriod > 0) { + preparedStatement.setQueryTimeout(remainingTransactionTimeOutPeriod); + } + } + } + + private JdbcServices getJdbcService() { + return jdbcCoordinator + .getJdbcSessionOwner() + .getJdbcSessionContext() + .getServiceRegistry() + .getService(JdbcServices.class); + } + + /** + * @author Christian Beikov + * @since 1.2.0 + */ + private abstract class QueryStatementPreparationTemplate extends StatementPreparationTemplate { + + protected QueryStatementPreparationTemplate(String sql) { + super(sql); + } + + public void postProcess(PreparedStatement preparedStatement) throws SQLException { + super.postProcess(preparedStatement); + setStatementFetchSize(preparedStatement); + } + } + + private void setStatementFetchSize(PreparedStatement statement) throws SQLException { + if (settings().getJdbcFetchSize() != null) { + statement.setFetchSize(settings().getJdbcFetchSize()); + } + } + +} diff --git a/integration/pom.xml b/integration/pom.xml index 76d9907480..322ffd9e46 100644 --- a/integration/pom.xml +++ b/integration/pom.xml @@ -39,6 +39,8 @@ hibernate-5.2 hibernate-5.3 hibernate-5.4 + hibernate-5.5 + hibernate-5.6 hibernate-6.0 datanucleus datanucleus-5.1 @@ -65,7 +67,8 @@ jpa-base-jakarta hibernate-base-jakarta - hibernate-5.4-jakarta + hibernate-5.5-jakarta + hibernate-5.6-jakarta entity-view-cdi-jakarta jaxrs-jackson-jakarta jaxrs-jsonb-jakarta diff --git a/integration/quarkus/deployment/src/main/java/com/blazebit/persistence/integration/quarkus/deployment/BlazePersistenceCdiProcessor.java b/integration/quarkus/deployment/src/main/java/com/blazebit/persistence/integration/quarkus/deployment/BlazePersistenceCdiProcessor.java index 62ea71f3ba..ed38053f12 100644 --- a/integration/quarkus/deployment/src/main/java/com/blazebit/persistence/integration/quarkus/deployment/BlazePersistenceCdiProcessor.java +++ b/integration/quarkus/deployment/src/main/java/com/blazebit/persistence/integration/quarkus/deployment/BlazePersistenceCdiProcessor.java @@ -124,7 +124,7 @@ void generateBeans(EntityViewRecorder recorder, .produce(createSyntheticBean(blazePersistenceInstanceName, true, CriteriaBuilderFactory.class, - recorder.criteriaBuilderFactorySupplier(blazePersistenceConfig, persistenceUnitName), + recorder.criteriaBuilderFactorySupplier(blazePersistenceConfig, blazePersistenceInstanceName, persistenceUnitName), true)); syntheticBeanBuildItemBuildProducer @@ -152,7 +152,7 @@ void generateBeans(EntityViewRecorder recorder, .produce(createSyntheticBean(blazePersistenceInstanceName, defaultBlazePersistenceInstance, CriteriaBuilderFactory.class, - recorder.criteriaBuilderFactorySupplier(blazePersistenceConfig, persistenceUnitName), + recorder.criteriaBuilderFactorySupplier(blazePersistenceConfig, blazePersistenceInstanceName, persistenceUnitName), true)); syntheticBeanBuildItemBuildProducer diff --git a/integration/quarkus/runtime/src/main/java/com/blazebit/persistence/integration/quarkus/runtime/EntityViewRecorder.java b/integration/quarkus/runtime/src/main/java/com/blazebit/persistence/integration/quarkus/runtime/EntityViewRecorder.java index 240ae14796..aad03fb5d6 100644 --- a/integration/quarkus/runtime/src/main/java/com/blazebit/persistence/integration/quarkus/runtime/EntityViewRecorder.java +++ b/integration/quarkus/runtime/src/main/java/com/blazebit/persistence/integration/quarkus/runtime/EntityViewRecorder.java @@ -40,10 +40,18 @@ @Recorder public class EntityViewRecorder { - public Supplier criteriaBuilderFactorySupplier(BlazePersistenceInstanceConfiguration blazePersistenceConfig, String persistenceUnitName) { + public Supplier criteriaBuilderFactorySupplier(BlazePersistenceInstanceConfiguration blazePersistenceConfig, String blazePersistenceInstanceName, String persistenceUnitName) { return () -> { CriteriaBuilderConfiguration criteriaBuilderConfiguration = Criteria.getDefault(); blazePersistenceConfig.apply(criteriaBuilderConfiguration); + Annotation[] cbfQualifiers; + if (BlazePersistenceInstanceUtil.isDefaultBlazePersistenceInstance(blazePersistenceInstanceName)) { + cbfQualifiers = new Annotation[] { new Default.Literal() }; + } else { + cbfQualifiers = new Annotation[] { new BlazePersistenceInstance.BlazePersistenceInstanceLiteral(blazePersistenceInstanceName) }; + } + + Arc.container().beanManager().fireEvent(criteriaBuilderConfiguration, cbfQualifiers); EntityManagerFactory emf = Arc.container().instance(JPAConfig.class, new Annotation[0]).get().getEntityManagerFactory(persistenceUnitName); return criteriaBuilderConfiguration.createCriteriaBuilderFactory(emf); }; diff --git a/integration/querydsl/testsuite/pom.xml b/integration/querydsl/testsuite/pom.xml index 379ac51f8c..bb0a79a284 100644 --- a/integration/querydsl/testsuite/pom.xml +++ b/integration/querydsl/testsuite/pom.xml @@ -1110,7 +1110,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.5 test @@ -1210,7 +1210,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2046,11 +2046,11 @@ org.hibernate hibernate-entitymanager - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2062,7 +2062,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} provided @@ -2112,7 +2112,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} diff --git a/integration/spring-data/testsuite/webflux/pom.xml b/integration/spring-data/testsuite/webflux/pom.xml index 6d5c95f808..3574ef2634 100644 --- a/integration/spring-data/testsuite/webflux/pom.xml +++ b/integration/spring-data/testsuite/webflux/pom.xml @@ -1233,7 +1233,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.5 test @@ -1334,7 +1334,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2232,11 +2232,11 @@ org.hibernate hibernate-entitymanager - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2248,7 +2248,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} provided @@ -2298,7 +2298,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} diff --git a/integration/spring-data/testsuite/webmvc/pom.xml b/integration/spring-data/testsuite/webmvc/pom.xml index f91c380268..f2a43b2fca 100644 --- a/integration/spring-data/testsuite/webmvc/pom.xml +++ b/integration/spring-data/testsuite/webmvc/pom.xml @@ -1238,7 +1238,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.5 test @@ -1339,7 +1339,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2214,11 +2214,11 @@ org.hibernate hibernate-entitymanager - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -2230,7 +2230,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} provided @@ -2280,7 +2280,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} diff --git a/jpa-criteria/testsuite/pom.xml b/jpa-criteria/testsuite/pom.xml index 72d8274d34..903ee71471 100644 --- a/jpa-criteria/testsuite/pom.xml +++ b/jpa-criteria/testsuite/pom.xml @@ -875,7 +875,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.5 test @@ -975,7 +975,7 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -1798,11 +1798,11 @@ org.hibernate hibernate-entitymanager - ${version.hibernate-5.4} + ${version.hibernate-5.6} ${project.groupId} - blaze-persistence-integration-hibernate-5.4 + blaze-persistence-integration-hibernate-5.6 test @@ -1814,7 +1814,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} provided @@ -1844,7 +1844,7 @@ org.hibernate hibernate-jpamodelgen - ${version.hibernate-5.4} + ${version.hibernate-5.6} jakarta.xml.bind diff --git a/parent/pom.xml b/parent/pom.xml index fe397eda3b..d401f68f24 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -66,7 +66,7 @@ 5.4.10.Final 5.5.0.Final - 5.6.0.CR1 + 5.6.3.Final 5.3.1.Final @@ -351,7 +351,22 @@ ${project.groupId} - blaze-persistence-integration-hibernate-5.4-jakarta + blaze-persistence-integration-hibernate-5.5 + ${project.version} + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.5-jakarta + ${project.version} + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.6 + ${project.version} + + + ${project.groupId} + blaze-persistence-integration-hibernate-5.6-jakarta ${project.version}