From bf473681e49cb51a3de9fd163d2611516563d29b Mon Sep 17 00:00:00 2001 From: marekchodak Date: Sun, 19 Jan 2020 22:04:47 +0100 Subject: [PATCH 01/13] HHH-13780 Allow NamedQuery to set hint QueryHints.PASS_DISTINCT_THROUGH --- .../cfg/annotations/QueryBinder.java | 6 +- .../cfg/annotations/QueryHintDefinition.java | 18 ++++-- .../engine/spi/NamedQueryDefinition.java | 15 ++++- .../spi/NamedQueryDefinitionBuilder.java | 9 ++- .../engine/spi/NamedSQLQueryDefinition.java | 15 +++-- .../spi/NamedSQLQueryDefinitionBuilder.java | 8 ++- .../AbstractSharedSessionContract.java | 4 ++ .../test/distinct/SelectDistinctHqlTest.java | 64 +++++++++++++++++++ 8 files changed, 122 insertions(+), 17 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java index 11e918bdac..c330d4aed6 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryBinder.java @@ -67,6 +67,7 @@ public abstract class QueryBinder { .setReadOnly( hints.getBoolean( queryName, QueryHints.READ_ONLY ) ) .setComment( hints.getString( queryName, QueryHints.COMMENT ) ) .setParameterTypes( null ) + .setPassDistinctThrough( hints.getPassDistinctThrough( queryName ) ) .createNamedQueryDefinition(); if ( isDefault ) { @@ -108,8 +109,9 @@ public abstract class QueryBinder { .setReadOnly( hints.getBoolean( queryName, QueryHints.READ_ONLY ) ) .setComment( hints.getString( queryName, QueryHints.COMMENT ) ) .setParameterTypes( null ) - .setCallable( hints.getBoolean( queryName, QueryHints.CALLABLE ) ); - + .setCallable( hints.getBoolean( queryName, QueryHints.CALLABLE ) ) + .setPassDistinctThrough( hints.getPassDistinctThrough( queryName ) ); + if ( !BinderHelper.isEmptyAnnotationValue( resultSetMapping ) ) { //sql result set usage builder.setResultSetRef( resultSetMapping ) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryHintDefinition.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryHintDefinition.java index 0c7d9e9bf5..f69bacf01e 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryHintDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryHintDefinition.java @@ -9,6 +9,7 @@ package org.hibernate.cfg.annotations; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import javax.persistence.LockModeType; import javax.persistence.NamedQuery; import javax.persistence.QueryHint; @@ -84,21 +85,28 @@ public class QueryHintDefinition { } } + public Boolean getPassDistinctThrough(String query) { + return doGetBoolean( query, QueryHints.PASS_DISTINCT_THROUGH ).orElse( null ); + } + public boolean getBoolean(String query, String hintName) { - String value =(String) hintsMap.get( hintName ); + return doGetBoolean( query, hintName ).orElse( false ); + } + + private Optional doGetBoolean(String query, String hintName) { + String value = (String) hintsMap.get( hintName ); if ( value == null ) { - return false; + return Optional.empty(); } if ( value.equalsIgnoreCase( "true" ) ) { - return true; + return Optional.of( true ); } else if ( value.equalsIgnoreCase( "false" ) ) { - return false; + return Optional.of( false ); } else { throw new AnnotationException( "Not a boolean in hint: " + query + ":" + hintName ); } - } public String getString(String query, String hintName) { diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinition.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinition.java index 346412ab09..e9bc7b30a5 100755 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinition.java @@ -33,6 +33,7 @@ public class NamedQueryDefinition implements Serializable { private final CacheMode cacheMode; private final boolean readOnly; private final String comment; + private final Boolean passDistinctThrough; // added for jpa 2.1 private final Integer firstResult; @@ -133,7 +134,8 @@ public class NamedQueryDefinition implements Serializable { comment, parameterTypes, null, // firstResult - null // maxResults + null, // maxResults + null // passDistinctThrough ); } @@ -151,7 +153,8 @@ public class NamedQueryDefinition implements Serializable { String comment, Map parameterTypes, Integer firstResult, - Integer maxResults) { + Integer maxResults, + Boolean passDistinctThrough) { this.name = name; this.query = query; this.cacheable = cacheable; @@ -167,6 +170,7 @@ public class NamedQueryDefinition implements Serializable { this.firstResult = firstResult; this.maxResults = maxResults; + this.passDistinctThrough = passDistinctThrough; } public String getName() { @@ -230,6 +234,10 @@ public class NamedQueryDefinition implements Serializable { return maxResults; } + public Boolean getPassDistinctThrough() { + return passDistinctThrough; + } + @Override public String toString() { return getClass().getName() + '(' + name + " [" + query + "])"; @@ -250,7 +258,8 @@ public class NamedQueryDefinition implements Serializable { getComment(), getParameterTypes(), getFirstResult(), - getMaxResults() + getMaxResults(), + getPassDistinctThrough() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinitionBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinitionBuilder.java index 80e540f512..57562bcedf 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinitionBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedQueryDefinitionBuilder.java @@ -28,6 +28,7 @@ public class NamedQueryDefinitionBuilder { protected LockOptions lockOptions; protected Integer firstResult; protected Integer maxResults; + protected Boolean passDistinctThrough; public NamedQueryDefinitionBuilder() { } @@ -114,6 +115,11 @@ public class NamedQueryDefinitionBuilder { return this; } + public NamedQueryDefinitionBuilder setPassDistinctThrough(Boolean passDistinctThrough) { + this.passDistinctThrough = passDistinctThrough; + return this; + } + public NamedQueryDefinition createNamedQueryDefinition() { return new NamedQueryDefinition( name, @@ -129,7 +135,8 @@ public class NamedQueryDefinitionBuilder { comment, parameterTypes, firstResult, - maxResults + maxResults, + passDistinctThrough ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinition.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinition.java index 782fb9e47e..fd58c47fa8 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinition.java @@ -81,7 +81,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { null, // resultSetRef querySpaces, callable, - queryReturns + queryReturns, + null // passDistinctThrough ); } @@ -140,7 +141,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { resultSetRef, querySpaces, callable, - null // queryReturns + null, // queryReturns + null // passDistinctThrough ); } @@ -161,7 +163,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { String resultSetRef, List querySpaces, boolean callable, - NativeSQLQueryReturn[] queryReturns) { + NativeSQLQueryReturn[] queryReturns, + Boolean passDistinctThrough) { super( name, query.trim(), /* trim done to workaround stupid oracle bug that cant handle whitespaces before a { in a sp */ @@ -176,7 +179,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { comment, parameterTypes, firstResult, - maxResults + maxResults, + passDistinctThrough ); this.resultSetRef = resultSetRef; this.querySpaces = querySpaces; @@ -219,7 +223,8 @@ public class NamedSQLQueryDefinition extends NamedQueryDefinition { getResultSetRef(), getQuerySpaces(), isCallable(), - getQueryReturns() + getQueryReturns(), + getPassDistinctThrough() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinitionBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinitionBuilder.java index 939295bc74..6824263023 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinitionBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/NamedSQLQueryDefinitionBuilder.java @@ -149,6 +149,11 @@ public class NamedSQLQueryDefinitionBuilder extends NamedQueryDefinitionBuilder return (NamedSQLQueryDefinitionBuilder) super.setMaxResults( maxResults ); } + @Override + public NamedSQLQueryDefinitionBuilder setPassDistinctThrough(Boolean passDistinctThrough) { + return (NamedSQLQueryDefinitionBuilder) super.setPassDistinctThrough( passDistinctThrough ); + } + @Override public NamedSQLQueryDefinition createNamedQueryDefinition() { return new NamedSQLQueryDefinition( @@ -168,7 +173,8 @@ public class NamedSQLQueryDefinitionBuilder extends NamedQueryDefinitionBuilder resultSetRef, querySpacesCopy(), callable, - queryReturns + queryReturns, + passDistinctThrough ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index ea3bc13aec..f9f6317ad7 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -62,6 +62,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.transaction.internal.TransactionImpl; import org.hibernate.engine.transaction.spi.TransactionImplementor; import org.hibernate.id.uuid.StandardRandomStrategy; +import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.internal.util.FlushModeTypeHelper; import org.hibernate.jpa.spi.CriteriaQueryTupleTransformer; import org.hibernate.jpa.spi.HibernateEntityManagerImplementor; @@ -695,6 +696,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont if ( nqd.getFlushMode() != null ) { query.setHibernateFlushMode( nqd.getFlushMode() ); } + if ( nqd.getPassDistinctThrough() != null ) { + query.setHint( QueryHints.HINT_PASS_DISTINCT_THROUGH, nqd.getPassDistinctThrough() ); + } } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/distinct/SelectDistinctHqlTest.java b/hibernate-core/src/test/java/org/hibernate/test/distinct/SelectDistinctHqlTest.java index df13035c24..77ff5c5d17 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/distinct/SelectDistinctHqlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/distinct/SelectDistinctHqlTest.java @@ -14,6 +14,9 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.QueryHint; import org.hibernate.boot.SessionFactoryBuilder; import org.hibernate.jpa.QueryHints; @@ -34,6 +37,9 @@ import static org.junit.Assert.assertTrue; @TestForIssue( jiraKey = "HHH-10965" ) public class SelectDistinctHqlTest extends BaseNonConfigCoreFunctionalTestCase { + private static final String DISTINCT_PASSES_THROUGH_TRUE_NAMED_QUERY = "distinctPassesThroughTrue"; + private static final String DISTINCT_PASSES_THROUGH_FALSE_NAMED_QUERY = "distinctPassesThroughFalse"; + private static final String DISTINCT_PASSES_THROUGH_NOT_SPECIFIED_NAMED_QUERY = "distinctPassesThroughNotSpecified"; private SQLStatementInterceptor sqlStatementInterceptor; @Override @@ -137,7 +143,65 @@ public class SelectDistinctHqlTest extends BaseNonConfigCoreFunctionalTestCase { }); } + @Test + @TestForIssue(jiraKey = "HHH-13780") + public void testNamedQueryDistinctPassThroughTrue() { + doInHibernate( this::sessionFactory, session -> { + sqlStatementInterceptor.getSqlQueries().clear(); + List persons = session.createNamedQuery( DISTINCT_PASSES_THROUGH_TRUE_NAMED_QUERY, Person.class ) + .setMaxResults( 5 ) + .getResultList(); + assertEquals( 1, persons.size() ); + String sqlQuery = sqlStatementInterceptor.getSqlQueries().getLast(); + assertTrue( sqlQuery.contains( " distinct " ) ); + } ); + } + + @Test + @TestForIssue(jiraKey = "HHH-13780") + public void testNamedQueryDistinctPassThroughTrueWhenNotSpecified() { + doInHibernate( this::sessionFactory, session -> { + sqlStatementInterceptor.getSqlQueries().clear(); + List persons = + session.createNamedQuery( DISTINCT_PASSES_THROUGH_NOT_SPECIFIED_NAMED_QUERY, Person.class ) + .setMaxResults( 5 ) + .getResultList(); + assertEquals( 1, persons.size() ); + String sqlQuery = sqlStatementInterceptor.getSqlQueries().getLast(); + assertTrue( sqlQuery.contains( " distinct " ) ); + } ); + } + + @Test + @TestForIssue(jiraKey = "HHH-13780") + public void testNamedQueryDistinctPassThroughFalse() { + doInHibernate( this::sessionFactory, session -> { + sqlStatementInterceptor.getSqlQueries().clear(); + List persons = + session.createNamedQuery( DISTINCT_PASSES_THROUGH_FALSE_NAMED_QUERY, Person.class ) + .setMaxResults( 5 ) + .getResultList(); + assertEquals( 1, persons.size() ); + String sqlQuery = sqlStatementInterceptor.getSqlQueries().getLast(); + assertFalse( sqlQuery.contains( " distinct " ) ); + } ); + } + @Entity(name = "Person") + @NamedQueries({ + @NamedQuery(name = DISTINCT_PASSES_THROUGH_TRUE_NAMED_QUERY, + query = "select distinct p from Person p left join fetch p.phones", + hints = { + @QueryHint(name = QueryHints.HINT_PASS_DISTINCT_THROUGH, value = "true") + }), + @NamedQuery(name = DISTINCT_PASSES_THROUGH_FALSE_NAMED_QUERY, + query = "select distinct p from Person p left join fetch p.phones", + hints = { + @QueryHint(name = QueryHints.HINT_PASS_DISTINCT_THROUGH, value = "false") + }), + @NamedQuery(name = DISTINCT_PASSES_THROUGH_NOT_SPECIFIED_NAMED_QUERY, + query = "select distinct p from Person p left join fetch p.phones") + }) public static class Person { @Id From 33fa24d9359116a8ba31c9812e0c00f13f03d5b7 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 21 Jan 2020 12:20:47 +0000 Subject: [PATCH 02/13] HHH-13822 OSGi integration tests need to be able to download dependencies from Maven Central using HTTPS --- .../org/hibernate/osgi/test/OsgiIntegrationTest.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hibernate-osgi/src/test/java/org/hibernate/osgi/test/OsgiIntegrationTest.java b/hibernate-osgi/src/test/java/org/hibernate/osgi/test/OsgiIntegrationTest.java index 89380493e5..644fd33134 100644 --- a/hibernate-osgi/src/test/java/org/hibernate/osgi/test/OsgiIntegrationTest.java +++ b/hibernate-osgi/src/test/java/org/hibernate/osgi/test/OsgiIntegrationTest.java @@ -80,6 +80,8 @@ import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel; public class OsgiIntegrationTest { private static final boolean DEBUG = false; + private static final String jbossPublicRepository = "https://repository.jboss.org/nexus/content/groups/public-jboss/"; + private static final String mavenCentralRepository = "https://repo.maven.apache.org/maven2/"; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Prepare the Karaf container @@ -108,10 +110,15 @@ public class OsgiIntegrationTest { ) ) .useDeployFolder( false ), - editConfigurationFileExtend( + editConfigurationFilePut( // Erase the defaults: Maven Central uses HTTP by default, but HTTPS is required now. "etc/org.ops4j.pax.url.mvn.cfg", "org.ops4j.pax.url.mvn.repositories", - "https://repository.jboss.org/nexus/content/groups/public/" + mavenCentralRepository + + "@id=central" + + ", " + + jbossPublicRepository + + "@id=jboss-public-repository" + + "https://repository.jboss.org/nexus/content/groups/public/" ), configureConsole().ignoreLocalConsole().ignoreRemoteShell(), when( debug ).useOptions( keepRuntimeFolder() ), From da019405b67d5b4bf089740d00111fd850ac4ac1 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 21 Jan 2020 12:20:16 +0000 Subject: [PATCH 03/13] HHH-13821 Update to Byte Buddy 1.10.7 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 66494c2ac0..f67d127cea 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -23,7 +23,7 @@ ext { weldVersion = '3.0.0.Final' javassistVersion = '3.24.0-GA' - byteBuddyVersion = '1.10.2' + byteBuddyVersion = '1.10.7' agroalVersion = '1.7' From f59f0ce40680b02e8cfd113ef0f3a2577640b9ce Mon Sep 17 00:00:00 2001 From: gavinking Date: Sat, 18 Jan 2020 14:53:36 +0100 Subject: [PATCH 04/13] HHH-13823 Changes for Hibernate RX Mostly just expose some operations and constructors that were previously inaccessible. --- .../action/internal/EntityDeleteAction.java | 30 +++- .../internal/EntityIdentityInsertAction.java | 10 +- .../action/internal/EntityInsertAction.java | 32 +++-- .../action/internal/EntityUpdateAction.java | 64 ++++++++- .../internal/AbstractSaveEventListener.java | 61 -------- .../event/internal/AbstractVisitor.java | 2 +- .../internal/DefaultDeleteEventListener.java | 10 +- .../internal/DefaultMergeEventListener.java | 9 +- .../internal/DefaultPersistEventListener.java | 15 +- .../DefaultPostLoadEventListener.java | 6 +- .../DefaultSaveOrUpdateEventListener.java | 5 +- .../DirtyCollectionSearchVisitor.java | 4 +- .../hibernate/event/internal/EntityState.java | 71 ++++++++++ .../hibernate/event/internal/EventUtil.java | 13 ++ .../event/internal/EvictVisitor.java | 2 +- .../event/internal/FlushVisitor.java | 2 +- .../event/internal/OnReplicateVisitor.java | 2 +- .../event/internal/OnUpdateVisitor.java | 2 +- .../event/internal/ProxyVisitor.java | 1 - .../hibernate/event/internal/WrapVisitor.java | 6 +- .../internal/SessionFactoryImpl.java | 6 +- .../org/hibernate/internal/SessionImpl.java | 2 +- .../entity/AbstractEntityPersister.java | 134 ++++++++++-------- .../entity/JoinedSubclassEntityPersister.java | 18 +-- .../entity/SingleTableEntityPersister.java | 20 +-- .../entity/UnionSubclassEntityPersister.java | 10 +- 26 files changed, 324 insertions(+), 213 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/event/internal/EntityState.java create mode 100644 hibernate-core/src/main/java/org/hibernate/event/internal/EventUtil.java diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java index 32af963676..9054f3be2e 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java @@ -69,6 +69,30 @@ public class EntityDeleteAction extends EntityAction { ); } + public Object getVersion() { + return version; + } + + public boolean isCascadeDeleteEnabled() { + return isCascadeDeleteEnabled; + } + + public Object[] getState() { + return state; + } + + protected Object[] getNaturalIdValues() { + return naturalIdValues; + } + + protected SoftLock getLock() { + return lock; + } + + protected void setLock(SoftLock lock) { + this.lock = lock; + } + @Override public void execute() throws HibernateException { final Serializable id = getId(); @@ -128,7 +152,7 @@ public class EntityDeleteAction extends EntityAction { } } - private boolean preDelete() { + protected boolean preDelete() { boolean veto = false; final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_DELETE ); if ( listenerGroup.isEmpty() ) { @@ -141,7 +165,7 @@ public class EntityDeleteAction extends EntityAction { return veto; } - private void postDelete() { + protected void postDelete() { final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_DELETE ); if ( listenerGroup.isEmpty() ) { return; @@ -158,7 +182,7 @@ public class EntityDeleteAction extends EntityAction { } } - private void postCommitDelete(boolean success) { + protected void postCommitDelete(boolean success) { final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COMMIT_DELETE ); if ( listenerGroup.isEmpty() ) { return; diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java index 1276bdc218..41a078923f 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java @@ -29,7 +29,7 @@ import org.hibernate.stat.spi.StatisticsImplementor; * * @see EntityInsertAction */ -public final class EntityIdentityInsertAction extends AbstractEntityInsertAction { +public class EntityIdentityInsertAction extends AbstractEntityInsertAction { private final boolean isDelayed; private final EntityKey delayedEntityKey; @@ -141,7 +141,7 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction postCommitInsert( success ); } - private void postInsert() { + protected void postInsert() { final EventSource eventSource = eventSource(); if ( isDelayed ) { eventSource.getPersistenceContextInternal().replaceDelayedEntityIdentityInsertKeys( delayedEntityKey, generatedId ); @@ -163,7 +163,7 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction } } - private void postCommitInsert(boolean success) { + protected void postCommitInsert(boolean success) { final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COMMIT_INSERT ); if ( listenerGroup.isEmpty() ) { return; @@ -191,7 +191,7 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction } } - private boolean preInsert() { + protected boolean preInsert() { final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_INSERT ); if ( listenerGroup.isEmpty() ) { // NO_VETO @@ -241,7 +241,7 @@ public final class EntityIdentityInsertAction extends AbstractEntityInsertAction return new DelayedPostInsertIdentifier(); } - private EntityKey generateDelayedEntityKey() { + protected EntityKey generateDelayedEntityKey() { if ( !isDelayed ) { throw new AssertionFailure( "cannot request delayed entity-key for early-insert post-insert-id generation" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java index f33e682f6a..fcbadde8e0 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java @@ -35,7 +35,7 @@ import org.hibernate.stat.spi.StatisticsImplementor; * * @see EntityIdentityInsertAction */ -public final class EntityInsertAction extends AbstractEntityInsertAction { +public class EntityInsertAction extends AbstractEntityInsertAction { private Object version; private Object cacheEntry; @@ -62,6 +62,22 @@ public final class EntityInsertAction extends AbstractEntityInsertAction { this.version = version; } + public Object getVersion() { + return version; + } + + public void setVersion(Object version) { + this.version = version; + } + + protected Object getCacheEntry() { + return cacheEntry; + } + + protected void setCacheEntry(Object cacheEntry) { + this.cacheEntry = cacheEntry; + } + @Override public boolean isEarlyInsert() { return false; @@ -143,7 +159,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction { markExecuted(); } - private boolean cacheInsert(EntityPersister persister, Object ck) { + protected boolean cacheInsert(EntityPersister persister, Object ck) { SharedSessionContractImplementor session = getSession(); try { session.getEventListenerManager().cachePutStart(); @@ -154,7 +170,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction { } } - private void postInsert() { + protected void postInsert() { final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_INSERT ); if ( listenerGroup.isEmpty() ) { return; @@ -171,7 +187,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction { } } - private void postCommitInsert(boolean success) { + protected void postCommitInsert(boolean success) { final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COMMIT_INSERT ); if ( listenerGroup.isEmpty() ) { return; @@ -199,7 +215,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction { } } - private boolean preInsert() { + protected boolean preInsert() { boolean veto = false; final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_INSERT ); @@ -233,7 +249,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction { postCommitInsert( success ); } - private boolean cacheAfterInsert(EntityDataAccess cache, Object ck) { + protected boolean cacheAfterInsert(EntityDataAccess cache, Object ck) { SharedSessionContractImplementor session = getSession(); final SessionEventListenerManager eventListenerManager = session.getEventListenerManager(); try { @@ -256,8 +272,8 @@ public final class EntityInsertAction extends AbstractEntityInsertAction { return false; } - - private boolean isCachePutEnabled(EntityPersister persister, SharedSessionContractImplementor session) { + + protected boolean isCachePutEnabled(EntityPersister persister, SharedSessionContractImplementor session) { return persister.canWriteToCache() && !persister.isCacheInvalidationRequired() && session.getCacheMode().isPutEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java index 66831d369d..ea46dd973d 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java @@ -37,7 +37,7 @@ import org.hibernate.type.TypeHelper; /** * The action for performing entity updates. */ -public final class EntityUpdateAction extends EntityAction { +public class EntityUpdateAction extends EntityAction { private final Object[] state; private final Object[] previousState; private final Object previousVersion; @@ -112,6 +112,58 @@ public final class EntityUpdateAction extends EntityAction { return persistenceContext.getNaturalIdSnapshot( id, persister ); } + public Object[] getState() { + return state; + } + + public Object[] getPreviousState() { + return previousState; + } + + public Object getPreviousVersion() { + return previousVersion; + } + + public Object getNextVersion() { + return nextVersion; + } + + public void setNextVersion(Object nextVersion) { + this.nextVersion = nextVersion; + } + + public int[] getDirtyFields() { + return dirtyFields; + } + + public boolean hasDirtyCollection() { + return hasDirtyCollection; + } + + public Object getRowId() { + return rowId; + } + + public Object[] getPreviousNaturalIdValues() { + return previousNaturalIdValues; + } + + protected Object getCacheEntry() { + return cacheEntry; + } + + protected void setCacheEntry(Object cacheEntry) { + this.cacheEntry = cacheEntry; + } + + protected SoftLock getLock() { + return lock; + } + + protected void setLock(SoftLock lock) { + this.lock = lock; + } + @Override public void execute() throws HibernateException { final Serializable id = getId(); @@ -223,7 +275,7 @@ public final class EntityUpdateAction extends EntityAction { } } - private boolean cacheUpdate(EntityPersister persister, Object previousVersion, Object ck) { + protected boolean cacheUpdate(EntityPersister persister, Object previousVersion, Object ck) { final SharedSessionContractImplementor session = getSession(); try { session.getEventListenerManager().cachePutStart(); @@ -234,7 +286,7 @@ public final class EntityUpdateAction extends EntityAction { } } - private boolean preUpdate() { + protected boolean preUpdate() { boolean veto = false; final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_UPDATE ); if ( listenerGroup.isEmpty() ) { @@ -254,7 +306,7 @@ public final class EntityUpdateAction extends EntityAction { return veto; } - private void postUpdate() { + protected void postUpdate() { final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_UPDATE ); if ( listenerGroup.isEmpty() ) { return; @@ -273,7 +325,7 @@ public final class EntityUpdateAction extends EntityAction { } } - private void postCommitUpdate(boolean success) { + protected void postCommitUpdate(boolean success) { final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COMMIT_UPDATE ); if ( listenerGroup.isEmpty() ) { return; @@ -350,7 +402,7 @@ public final class EntityUpdateAction extends EntityAction { postCommitUpdate( success ); } - private boolean cacheAfterUpdate(EntityDataAccess cache, Object ck) { + protected boolean cacheAfterUpdate(EntityDataAccess cache, Object ck) { final SharedSessionContractImplementor session = getSession(); SessionEventListenerManager eventListenerManager = session.getEventListenerManager(); try { diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java index 9c8ea95ae2..78c9d9025b 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractSaveEventListener.java @@ -17,7 +17,6 @@ import org.hibernate.action.internal.EntityInsertAction; import org.hibernate.classic.Lifecycle; import org.hibernate.engine.internal.Cascade; import org.hibernate.engine.internal.CascadePoint; -import org.hibernate.engine.internal.ForeignKeys; import org.hibernate.engine.internal.Versioning; import org.hibernate.engine.spi.CascadingAction; import org.hibernate.engine.spi.EntityEntry; @@ -49,10 +48,6 @@ public abstract class AbstractSaveEventListener implements CallbackRegistryConsumer { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractSaveEventListener.class ); - public enum EntityState { - PERSISTENT, TRANSIENT, DETACHED, DELETED - } - private CallbackRegistry callbackRegistry; public void injectCallbackRegistry(CallbackRegistry callbackRegistry) { @@ -477,60 +472,4 @@ public abstract class AbstractSaveEventListener protected abstract CascadingAction getCascadeAction(); - /** - * Determine whether the entity is persistent, detached, or transient - * - * @param entity The entity to check - * @param entityName The name of the entity - * @param entry The entity's entry in the persistence context - * @param source The originating session. - * - * @return The state. - */ - protected EntityState getEntityState( - Object entity, - String entityName, - EntityEntry entry, //pass this as an argument only to avoid double looking - SessionImplementor source) { - - if ( entry != null ) { // the object is persistent - - //the entity is associated with the session, so check its status - if ( entry.getStatus() != Status.DELETED ) { - // do nothing for persistent instances - if ( LOG.isTraceEnabled() ) { - LOG.tracev( "Persistent instance of: {0}", getLoggableName( entityName, entity ) ); - } - return EntityState.PERSISTENT; - } - // ie. e.status==DELETED - if ( LOG.isTraceEnabled() ) { - LOG.tracev( "Deleted instance of: {0}", getLoggableName( entityName, entity ) ); - } - return EntityState.DELETED; - } - // the object is transient or detached - - // the entity is not associated with the session, so - // try interceptor and unsaved-value - - if ( ForeignKeys.isTransient( entityName, entity, getAssumedUnsaved(), source ) ) { - if ( LOG.isTraceEnabled() ) { - LOG.tracev( "Transient instance of: {0}", getLoggableName( entityName, entity ) ); - } - return EntityState.TRANSIENT; - } - if ( LOG.isTraceEnabled() ) { - LOG.tracev( "Detached instance of: {0}", getLoggableName( entityName, entity ) ); - } - return EntityState.DETACHED; - } - - protected String getLoggableName(String entityName, Object entity) { - return entityName == null ? entity.getClass().getName() : entityName; - } - - protected Boolean getAssumedUnsaved() { - return null; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractVisitor.java index 85ff7ba815..b6a1190fdb 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractVisitor.java @@ -121,7 +121,7 @@ public abstract class AbstractVisitor { * @param persister * @throws HibernateException */ - void process(Object object, EntityPersister persister) + public void process(Object object, EntityPersister persister) throws HibernateException { processEntityPropertyValues( persister.getPropertyValues( object ), diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java index eb09b3bf02..4f2e7fbfcd 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultDeleteEventListener.java @@ -145,13 +145,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback version = entityEntry.getVersion(); } - /*if ( !persister.isMutable() ) { - throw new HibernateException( - "attempted to delete an object of immutable class: " + - MessageHelper.infoString(persister) - ); - }*/ - + callbackRegistry.preRemove( entity ); if ( invokeDeleteLifecycle( source, entity, persister ) ) { return; } @@ -338,8 +332,6 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback } protected boolean invokeDeleteLifecycle(EventSource session, Object entity, EntityPersister persister) { - callbackRegistry.preRemove( entity ); - if ( persister.implementsLifecycle() ) { LOG.debug( "Calling onDelete()" ); if ( ( (Lifecycle) entity ).onDelete( session ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java index 39f1f47b76..0749eb0d97 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java @@ -164,7 +164,7 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme } if ( entityState == null ) { - entityState = getEntityState( entity, event.getEntityName(), entry, source ); + entityState = EntityState.getEntityState( entity, event.getEntityName(), entry, source, false ); } switch ( entityState ) { @@ -181,7 +181,7 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme throw new ObjectDeletedException( "deleted instance passed to merge", null, - getLoggableName( event.getEntityName(), entity ) + EventUtil.getLoggableName( event.getEntityName(), entity ) ); } } @@ -536,11 +536,6 @@ public class DefaultMergeEventListener extends AbstractSaveEventListener impleme return CascadingActions.MERGE; } - @Override - protected Boolean getAssumedUnsaved() { - return Boolean.FALSE; - } - /** * Cascade behavior is redefined by this subclass, disable superclass behavior */ diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java index f1a2c01d7d..a82b95aabf 100755 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPersistEventListener.java @@ -6,7 +6,6 @@ */ package org.hibernate.event.internal; -import java.io.Serializable; import java.util.IdentityHashMap; import java.util.Map; @@ -24,7 +23,6 @@ import org.hibernate.event.spi.PersistEventListener; import org.hibernate.id.ForeignGenerator; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.jpa.event.spi.CallbackRegistry; import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.pretty.MessageHelper; @@ -47,11 +45,6 @@ public class DefaultPersistEventListener return CascadingActions.PERSIST; } - @Override - protected Boolean getAssumedUnsaved() { - return Boolean.TRUE; - } - /** * Handle the given create event. * @@ -99,7 +92,7 @@ public class DefaultPersistEventListener } final EntityEntry entityEntry = source.getPersistenceContextInternal().getEntry( entity ); - EntityState entityState = getEntityState( entity, entityName, entityEntry, source ); + EntityState entityState = EntityState.getEntityState( entity, entityName, entityEntry, source, true ); if ( entityState == EntityState.DETACHED ) { // JPA 2, in its version of a "foreign generated", allows the id attribute value // to be manually set by the user, even though this manual value is irrelevant. @@ -116,7 +109,7 @@ public class DefaultPersistEventListener LOG.debug( "Resetting entity id attribute to null for foreign generator" ); } persister.setIdentifier( entity, null, source ); - entityState = getEntityState( entity, entityName, entityEntry, source ); + entityState = EntityState.getEntityState( entity, entityName, entityEntry, source, true ); } } @@ -124,7 +117,7 @@ public class DefaultPersistEventListener case DETACHED: { throw new PersistentObjectException( "detached entity passed to persist: " + - getLoggableName( event.getEntityName(), entity ) + EventUtil.getLoggableName( event.getEntityName(), entity ) ); } case PERSISTENT: { @@ -146,7 +139,7 @@ public class DefaultPersistEventListener throw new ObjectDeletedException( "deleted entity passed to persist", null, - getLoggableName( event.getEntityName(), entity ) + EventUtil.getLoggableName( event.getEntityName(), entity ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java index 46bafb8e22..c2838e65d2 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java @@ -67,10 +67,14 @@ public class DefaultPostLoadEventListener implements PostLoadEventListener, Call session.getActionQueue().registerProcess( verifyVersion ); } + invokeLoadLifecycle(event, session); + + } + + protected void invokeLoadLifecycle(PostLoadEvent event, EventSource session) { if ( event.getPersister().implementsLifecycle() ) { //log.debug( "calling onLoad()" ); ( (Lifecycle) event.getEntity() ).onLoad( session, event.getId() ); } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java index c853676843..dfbd1b6f9c 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultSaveOrUpdateEventListener.java @@ -82,11 +82,12 @@ public class DefaultSaveOrUpdateEventListener extends AbstractSaveEventListener } protected Serializable performSaveOrUpdate(SaveOrUpdateEvent event) { - EntityState entityState = getEntityState( + EntityState entityState = EntityState.getEntityState( event.getEntity(), event.getEntityName(), event.getEntry(), - event.getSession() + event.getSession(), + null ); switch ( entityState ) { diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DirtyCollectionSearchVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DirtyCollectionSearchVisitor.java index 1fce73d5fe..79fbf5a9a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DirtyCollectionSearchVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DirtyCollectionSearchVisitor.java @@ -25,12 +25,12 @@ public class DirtyCollectionSearchVisitor extends AbstractVisitor { private boolean dirty; private boolean[] propertyVersionability; - DirtyCollectionSearchVisitor(EventSource session, boolean[] propertyVersionability) { + public DirtyCollectionSearchVisitor(EventSource session, boolean[] propertyVersionability) { super( session ); this.propertyVersionability = propertyVersionability; } - boolean wasDirtyCollectionFound() { + public boolean wasDirtyCollectionFound() { return dirty; } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/EntityState.java b/hibernate-core/src/main/java/org/hibernate/event/internal/EntityState.java new file mode 100644 index 0000000000..a0f537827f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/EntityState.java @@ -0,0 +1,71 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.event.internal; + +import org.hibernate.engine.internal.ForeignKeys; +import org.hibernate.engine.spi.EntityEntry; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.engine.spi.Status; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; + +public enum EntityState { + PERSISTENT, TRANSIENT, DETACHED, DELETED; + + static final CoreMessageLogger LOG = CoreLogging.messageLogger( EntityState.class ); + + /** + * Determine whether the entity is persistent, detached, or transient + * + * @param entity The entity to check + * @param entityName The name of the entity + * @param entry The entity's entry in the persistence context + * @param source The originating session. + * + * @return The state. + */ + public static EntityState getEntityState( + Object entity, + String entityName, + EntityEntry entry, //pass this as an argument only to avoid double looking + SessionImplementor source, + Boolean assumedUnsaved) { + + if ( entry != null ) { // the object is persistent + + //the entity is associated with the session, so check its status + if ( entry.getStatus() != Status.DELETED ) { + // do nothing for persistent instances + if ( LOG.isTraceEnabled() ) { + LOG.tracev( "Persistent instance of: {0}", EventUtil.getLoggableName( entityName, entity ) ); + } + return PERSISTENT; + } + // ie. e.status==DELETED + if ( LOG.isTraceEnabled() ) { + LOG.tracev( "Deleted instance of: {0}", EventUtil.getLoggableName( entityName, entity ) ); + } + return DELETED; + } + // the object is transient or detached + + // the entity is not associated with the session, so + // try interceptor and unsaved-value + + if ( ForeignKeys.isTransient( entityName, entity, assumedUnsaved, source ) ) { + if ( LOG.isTraceEnabled() ) { + LOG.tracev( "Transient instance of: {0}", EventUtil.getLoggableName( entityName, entity ) ); + } + return TRANSIENT; + } + if ( LOG.isTraceEnabled() ) { + LOG.tracev( "Detached instance of: {0}", EventUtil.getLoggableName( entityName, entity ) ); + } + return DETACHED; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/EventUtil.java b/hibernate-core/src/main/java/org/hibernate/event/internal/EventUtil.java new file mode 100644 index 0000000000..3ea7b26d2a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/EventUtil.java @@ -0,0 +1,13 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.event.internal; + +public class EventUtil { + public static String getLoggableName(String entityName, Object entity) { + return entityName == null ? entity.getClass().getName() : entityName; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/EvictVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/EvictVisitor.java index 9e1347d6d1..c506a5a216 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/EvictVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/EvictVisitor.java @@ -30,7 +30,7 @@ public class EvictVisitor extends AbstractVisitor { private Object owner; - EvictVisitor(EventSource session, Object owner) { + public EvictVisitor(EventSource session, Object owner) { super(session); this.owner = owner; } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/FlushVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/FlushVisitor.java index a3d8987182..947d3de574 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/FlushVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/FlushVisitor.java @@ -23,7 +23,7 @@ import org.hibernate.type.CollectionType; public class FlushVisitor extends AbstractVisitor { private Object owner; - FlushVisitor(EventSource session, Object owner) { + public FlushVisitor(EventSource session, Object owner) { super(session); this.owner = owner; } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/OnReplicateVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/OnReplicateVisitor.java index 281ba1a3f8..359b55b5d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/OnReplicateVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/OnReplicateVisitor.java @@ -30,7 +30,7 @@ public class OnReplicateVisitor extends ReattachVisitor { private boolean isUpdate; - OnReplicateVisitor(EventSource session, Serializable key, Object owner, boolean isUpdate) { + public OnReplicateVisitor(EventSource session, Serializable key, Object owner, boolean isUpdate) { super( session, key, owner ); this.isUpdate = isUpdate; } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/OnUpdateVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/OnUpdateVisitor.java index 5612565499..0ed248b7da 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/OnUpdateVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/OnUpdateVisitor.java @@ -26,7 +26,7 @@ import org.hibernate.type.CollectionType; */ public class OnUpdateVisitor extends ReattachVisitor { - OnUpdateVisitor(EventSource session, Serializable key, Object owner) { + public OnUpdateVisitor(EventSource session, Serializable key, Object owner) { super( session, key, owner ); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/ProxyVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/ProxyVisitor.java index e507baf21f..cf715aeb73 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/ProxyVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/ProxyVisitor.java @@ -21,7 +21,6 @@ import org.hibernate.type.EntityType; */ public abstract class ProxyVisitor extends AbstractVisitor { - public ProxyVisitor(EventSource session) { super(session); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java index 880a238db0..49d7b1748f 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java @@ -42,11 +42,11 @@ public class WrapVisitor extends ProxyVisitor { this.id = id; } - boolean isSubstitutionRequired() { + public boolean isSubstitutionRequired() { return substitute; } - WrapVisitor(EventSource session) { + public WrapVisitor(EventSource session) { super( session ); } @@ -152,7 +152,7 @@ public class WrapVisitor extends ProxyVisitor { } @Override - void process(Object object, EntityPersister persister) throws HibernateException { + public void process(Object object, EntityPersister persister) throws HibernateException { final Object[] values = persister.getPropertyValues( object ); final Type[] types = persister.getPropertyTypes(); processEntityPropertyValues( values, types ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 4eb8540b45..06c5aa3760 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -152,7 +152,7 @@ import static org.hibernate.metamodel.internal.JpaMetaModelPopulationSetting.det * @author Steve Ebersole * @author Chris Cranford */ -public final class SessionFactoryImpl implements SessionFactoryImplementor { +public class SessionFactoryImpl implements SessionFactoryImplementor { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( SessionFactoryImpl.class ); private final String name; @@ -1121,7 +1121,7 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor { return null; } - static class SessionBuilderImpl implements SessionBuilderImplementor, SessionCreationOptions { + public static class SessionBuilderImpl implements SessionBuilderImplementor, SessionCreationOptions { private static final Logger log = CoreLogging.logger( SessionBuilderImpl.class ); private final SessionFactoryImpl sessionFactory; @@ -1145,7 +1145,7 @@ public final class SessionFactoryImpl implements SessionFactoryImplementor { //todo : expose setting private SessionOwnerBehavior sessionOwnerBehavior = SessionOwnerBehavior.LEGACY_NATIVE; - SessionBuilderImpl(SessionFactoryImpl sessionFactory) { + public SessionBuilderImpl(SessionFactoryImpl sessionFactory) { this.sessionFactory = sessionFactory; // set up default builder values... diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 0ce662253d..5f839ebf09 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -194,7 +194,7 @@ import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE; * @author Chris Cranford * @author Sanne Grinovero */ -public final class SessionImpl +public class SessionImpl extends AbstractSessionImpl implements EventSource, SessionImplementor, HibernateEntityManagerImplementor { private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( SessionImpl.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index b2d2517ff3..45a414afbe 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -338,15 +338,15 @@ public abstract class AbstractEntityPersister public abstract int getSubclassTableSpan(); - protected abstract int getTableSpan(); + public abstract int getTableSpan(); - protected abstract boolean isTableCascadeDeleteEnabled(int j); + public abstract boolean isTableCascadeDeleteEnabled(int j); - protected abstract String getTableName(int j); + public abstract String getTableName(int j); - protected abstract String[] getKeyColumns(int j); + public abstract String[] getKeyColumns(int j); - protected abstract boolean isPropertyOfTable(int property, int j); + public abstract boolean isPropertyOfTable(int property, int j); protected abstract int[] getPropertyTableNumbersInSelect(); @@ -377,19 +377,19 @@ public abstract class AbstractEntityPersister } } - protected String getDiscriminatorAlias() { + public String getDiscriminatorAlias() { return DISCRIMINATOR_ALIAS; } - protected String getDiscriminatorFormulaTemplate() { + public String getDiscriminatorFormulaTemplate() { return null; } - protected boolean isInverseTable(int j) { + public boolean isInverseTable(int j) { return false; } - protected boolean isNullableTable(int j) { + public boolean isNullableTable(int j) { return false; } @@ -413,7 +413,7 @@ public abstract class AbstractEntityPersister return rootTableKeyColumnNames; } - protected String[] getSQLUpdateByRowIdStrings() { + public String[] getSQLUpdateByRowIdStrings() { if ( sqlUpdateByRowIdString == null ) { throw new AssertionFailure( "no update by row id" ); } @@ -423,7 +423,7 @@ public abstract class AbstractEntityPersister return result; } - protected String[] getSQLLazyUpdateByRowIdStrings() { + public String[] getSQLLazyUpdateByRowIdStrings() { if ( sqlLazyUpdateByRowIdString == null ) { throw new AssertionFailure( "no update by row id" ); } @@ -433,52 +433,64 @@ public abstract class AbstractEntityPersister return result; } - protected String getSQLSnapshotSelectString() { + public String getSQLSnapshotSelectString() { return sqlSnapshotSelectString; } - protected String getSQLLazySelectString(String fetchGroup) { + public String getSQLLazySelectString(String fetchGroup) { return sqlLazySelectStringsByFetchGroup.get( fetchGroup ); } - protected String[] getSQLDeleteStrings() { + public String[] getSQLDeleteStrings() { return sqlDeleteStrings; } - protected String[] getSQLInsertStrings() { + public String[] getSQLInsertStrings() { return sqlInsertStrings; } - protected String[] getSQLUpdateStrings() { + public String[] getSQLUpdateStrings() { return sqlUpdateStrings; } - protected String[] getSQLLazyUpdateStrings() { + public String[] getSQLLazyUpdateStrings() { return sqlLazyUpdateStrings; } + public ExecuteUpdateResultCheckStyle[] getInsertResultCheckStyles() { + return insertResultCheckStyles; + } + + public ExecuteUpdateResultCheckStyle[] getUpdateResultCheckStyles() { + return updateResultCheckStyles; + } + + public ExecuteUpdateResultCheckStyle[] getDeleteResultCheckStyles() { + return deleteResultCheckStyles; + } + /** * The query that inserts a row, letting the database generate an id * * @return The IDENTITY-based insertion query. */ - protected String getSQLIdentityInsertString() { + public String getSQLIdentityInsertString() { return sqlIdentityInsertString; } - protected String getVersionSelectString() { + public String getVersionSelectString() { return sqlVersionSelectString; } - protected boolean isInsertCallable(int j) { + public boolean isInsertCallable(int j) { return insertCallable[j]; } - protected boolean isUpdateCallable(int j) { + public boolean isUpdateCallable(int j) { return updateCallable[j]; } - protected boolean isDeleteCallable(int j) { + public boolean isDeleteCallable(int j) { return deleteCallable[j]; } @@ -505,7 +517,7 @@ public abstract class AbstractEntityPersister * * @return Array of booleans indicating which table require updating. */ - protected boolean[] getTableUpdateNeeded(final int[] dirtyProperties, boolean hasDirtyCollection) { + public boolean[] getTableUpdateNeeded(final int[] dirtyProperties, boolean hasDirtyCollection) { if ( dirtyProperties == null ) { return getTableHasColumns(); // for objects that came in via update() @@ -539,15 +551,15 @@ public abstract class AbstractEntityPersister return rowIdName != null; } - protected boolean[][] getPropertyColumnUpdateable() { + public boolean[][] getPropertyColumnUpdateable() { return propertyColumnUpdateable; } - protected boolean[][] getPropertyColumnInsertable() { + public boolean[][] getPropertyColumnInsertable() { return propertyColumnInsertable; } - protected boolean[] getPropertySelectable() { + public boolean[] getPropertySelectable() { return propertySelectable; } @@ -1381,11 +1393,11 @@ public abstract class AbstractEntityPersister return rootTableKeyColumnReaderTemplates; } - protected int getIdentifierColumnSpan() { + public int getIdentifierColumnSpan() { return identifierColumnSpan; } - protected String[] getIdentifierAliases() { + public String[] getIdentifierAliases() { return identifierAliases; } @@ -1393,7 +1405,7 @@ public abstract class AbstractEntityPersister return versionColumnName; } - protected String getVersionedTableName() { + public String getVersionedTableName() { return getTableName( 0 ); } @@ -1624,7 +1636,7 @@ public abstract class AbstractEntityPersister } - protected String generateIdByUniqueKeySelectString(String uniquePropertyName) { + public String generateIdByUniqueKeySelectString(String uniquePropertyName) { Select select = new Select( getFactory().getDialect() ); if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) { @@ -1681,7 +1693,7 @@ public abstract class AbstractEntityPersister /** * Generate the SQL that selects the version number by id */ - protected String generateSelectVersionString() { + public String generateSelectVersionString() { SimpleSelect select = new SimpleSelect( getFactory().getDialect() ) .setTableName( getVersionedTableName() ); if ( isVersioned() ) { @@ -1700,11 +1712,11 @@ public abstract class AbstractEntityPersister return propertyUniqueness; } - protected String generateInsertGeneratedValuesSelectString() { + public String generateInsertGeneratedValuesSelectString() { return generateGeneratedValuesSelectString( GenerationTiming.INSERT ); } - protected String generateUpdateGeneratedValuesSelectString() { + public String generateUpdateGeneratedValuesSelectString() { return generateGeneratedValuesSelectString( GenerationTiming.ALWAYS ); } @@ -1786,7 +1798,7 @@ public abstract class AbstractEntityPersister return frag.toFragmentString(); } - protected String generateSnapshotSelectString() { + public String generateSnapshotSelectString() { //TODO: should we use SELECT .. FOR UPDATE? @@ -2162,11 +2174,11 @@ public abstract class AbstractEntityPersister return propertyColumnWriters[i]; } - protected int getPropertyColumnSpan(int i) { + public int getPropertyColumnSpan(int i) { return propertyColumnSpans[i]; } - protected boolean hasFormulaProperties() { + public boolean hasFormulaProperties() { return hasFormulaProperties; } @@ -2587,14 +2599,14 @@ public abstract class AbstractEntityPersister return true; } - protected String generateUpdateString(boolean[] includeProperty, int j, boolean useRowId) { + public String generateUpdateString(boolean[] includeProperty, int j, boolean useRowId) { return generateUpdateString( includeProperty, j, null, useRowId ); } /** * Generate the SQL that updates a row by id (and version) */ - protected String generateUpdateString( + public String generateUpdateString( final boolean[] includeProperty, final int j, final Object[] oldFields, @@ -2688,23 +2700,23 @@ public abstract class AbstractEntityPersister return hasColumns ? update.toStatementString() : null; } - protected final boolean checkVersion(final boolean[] includeProperty) { + public final boolean checkVersion(final boolean[] includeProperty) { return includeProperty[getVersionProperty()] || entityMetamodel.isVersionGenerated(); } - protected String generateInsertString(boolean[] includeProperty, int j) { + public String generateInsertString(boolean[] includeProperty, int j) { return generateInsertString( false, includeProperty, j ); } - protected String generateInsertString(boolean identityInsert, boolean[] includeProperty) { + public String generateInsertString(boolean identityInsert, boolean[] includeProperty) { return generateInsertString( identityInsert, includeProperty, 0 ); } /** * Generate the SQL that inserts a row */ - protected String generateInsertString(boolean identityInsert, boolean[] includeProperty, int j) { + public String generateInsertString(boolean identityInsert, boolean[] includeProperty, int j) { // todo : remove the identityInsert param and variations; // identity-insert strings are now generated from generateIdentityInsertString() @@ -2803,7 +2815,7 @@ public abstract class AbstractEntityPersister * * @return The insert SQL statement string */ - protected String generateIdentityInsertString(boolean[] includeProperty) { + public String generateIdentityInsertString(boolean[] includeProperty) { Insert insert = identityDelegate.prepareIdentifierGeneratingInsert(); insert.setTableName( getTableName( 0 ) ); @@ -2870,7 +2882,7 @@ public abstract class AbstractEntityPersister /** * Generate the SQL that deletes a row by id (and version) */ - protected String generateDeleteString(int j) { + public String generateDeleteString(int j) { final Delete delete = new Delete() .setTableName( getTableName( j ) ) .addPrimaryKeyColumns( getKeyColumns( j ) ); @@ -2883,7 +2895,7 @@ public abstract class AbstractEntityPersister return delete.toStatementString(); } - protected int dehydrate( + public int dehydrate( Serializable id, Object[] fields, boolean[] includeProperty, @@ -2898,7 +2910,7 @@ public abstract class AbstractEntityPersister /** * Marshall the fields of a persistent instance to a prepared statement */ - protected int dehydrate( + public int dehydrate( final Serializable id, final Object[] fields, final Object rowId, @@ -3079,11 +3091,11 @@ public abstract class AbstractEntityPersister } } - protected boolean useInsertSelectIdentity() { + public boolean useInsertSelectIdentity() { return !useGetGeneratedKeys() && getFactory().getDialect().getIdentityColumnSupport().supportsInsertSelectIdentity(); } - protected boolean useGetGeneratedKeys() { + public boolean useGetGeneratedKeys() { return getFactory().getSessionFactoryOptions().isGetGeneratedKeysEnabled(); } @@ -3097,7 +3109,7 @@ public abstract class AbstractEntityPersister * This form is used for PostInsertIdentifierGenerator-style ids (IDENTITY, * select, etc). */ - protected Serializable insert( + public Serializable insert( final Object[] fields, final boolean[] notNull, String sql, @@ -3150,7 +3162,7 @@ public abstract class AbstractEntityPersister * This for is used for all non-root tables as well as the root table * in cases where the identifier value is known before the insert occurs. */ - protected void insert( + public void insert( final Serializable id, final Object[] fields, final boolean[] notNull, @@ -3253,7 +3265,7 @@ public abstract class AbstractEntityPersister /** * Perform an SQL UPDATE or SQL INSERT */ - protected void updateOrInsert( + public void updateOrInsert( final Serializable id, final Object[] fields, final Object[] oldFields, @@ -3307,7 +3319,7 @@ public abstract class AbstractEntityPersister private BasicBatchKey updateBatchKey; - protected boolean update( + public boolean update( final Serializable id, final Object[] fields, final Object[] oldFields, @@ -3455,7 +3467,7 @@ public abstract class AbstractEntityPersister /** * Perform an SQL DELETE */ - protected void delete( + public void delete( final Serializable id, final Object version, final int j, @@ -4511,7 +4523,7 @@ public abstract class AbstractEntityPersister } } - protected final boolean isAllNull(Object[] array, int tableNumber) { + public final boolean isAllNull(Object[] array, int tableNumber) { for ( int i = 0; i < array.length; i++ ) { if ( isPropertyOfTable( i, tableNumber ) && array[i] != null ) { return false; @@ -4528,7 +4540,7 @@ public abstract class AbstractEntityPersister * Transform the array of property indexes to an array of booleans, * true when the property is dirty */ - protected final boolean[] getPropertiesToUpdate(final int[] dirtyProperties, final boolean hasDirtyCollection) { + public final boolean[] getPropertiesToUpdate(final int[] dirtyProperties, final boolean hasDirtyCollection) { final boolean[] propsToUpdate = new boolean[entityMetamodel.getPropertySpan()]; final boolean[] updateability = getPropertyUpdateability(); //no need to check laziness, dirty checking handles that for ( int j = 0; j < dirtyProperties.length; j++ ) { @@ -4552,7 +4564,7 @@ public abstract class AbstractEntityPersister * Transform the array of property indexes to an array of booleans, * true when the property is insertable and non-null */ - protected boolean[] getPropertiesToInsert(Object[] fields) { + public boolean[] getPropertiesToInsert(Object[] fields) { boolean[] notNull = new boolean[fields.length]; boolean[] insertable = getPropertyInsertability(); for ( int i = 0; i < fields.length; i++ ) { @@ -4626,7 +4638,7 @@ public abstract class AbstractEntityPersister * Which properties appear in the SQL update? * (Initialized, updateable ones!) */ - protected boolean[] getPropertyUpdateability(Object entity) { + public boolean[] getPropertyUpdateability(Object entity) { return hasUninitializedLazyProperties( entity ) ? getNonLazyPropertyUpdateability() : getPropertyUpdateability(); @@ -4863,7 +4875,7 @@ public abstract class AbstractEntityPersister return entityMetamodel.isMutable(); } - protected final boolean isModifiableEntity(EntityEntry entry) { + public final boolean isModifiableEntity(EntityEntry entry) { return ( entry == null ? isMutable() : entry.isModifiableEntity() ); } @@ -4908,7 +4920,7 @@ public abstract class AbstractEntityPersister return entityMetamodel.isDynamicInsert(); } - protected boolean hasEmbeddedCompositeIdentifier() { + public boolean hasEmbeddedCompositeIdentifier() { return entityMetamodel.getIdentifierProperty().isEmbedded(); } @@ -5170,7 +5182,7 @@ public abstract class AbstractEntityPersister return false; } - protected int getPropertySpan() { + public int getPropertySpan() { return entityMetamodel.getPropertySpan(); } @@ -5526,7 +5538,7 @@ public abstract class AbstractEntityPersister return generateEntityIdByNaturalIdSql( valueNullness ); } - protected boolean isNaturalIdNonNullable() { + public boolean isNaturalIdNonNullable() { if ( naturalIdIsNonNullable == null ) { naturalIdIsNonNullable = determineNaturalIdNullability(); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 6fc0a3b095..3731bd9219 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -736,12 +736,12 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister { } @Override - protected boolean isNullableTable(int j) { + public boolean isNullableTable(int j) { return isNullableTable[j]; } @Override - protected boolean isInverseTable(int j) { + public boolean isInverseTable(int j) { return isInverseTable[j]; } @@ -799,7 +799,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister { return getDiscriminatorColumnName(); } - protected String getDiscriminatorAlias() { + public String getDiscriminatorAlias() { return discriminatorAlias; } @@ -819,19 +819,19 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister { } - protected String getTableName(int j) { + public String getTableName(int j) { return naturalOrderTableNames[j]; } - protected String[] getKeyColumns(int j) { + public String[] getKeyColumns(int j) { return naturalOrderTableKeyColumns[j]; } - protected boolean isTableCascadeDeleteEnabled(int j) { + public boolean isTableCascadeDeleteEnabled(int j) { return naturalOrderCascadeDeleteEnabled[j]; } - protected boolean isPropertyOfTable(int property, int j) { + public boolean isPropertyOfTable(int property, int j) { return naturalOrderPropertyTableNumbers[property] == j; } @@ -928,14 +928,14 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister { } @Override - public String filterFragment(String alias) { + protected String filterFragment(String alias) { return hasWhere() ? " and " + getSQLWhereString( generateFilterConditionAlias( alias ) ) : ""; } @Override - public String filterFragment(String alias, Set treatAsDeclarations) { + protected String filterFragment(String alias, Set treatAsDeclarations) { return filterFragment( alias ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index bd1fd7c472..5a1042e7c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -450,7 +450,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { } } - protected boolean isInverseTable(int j) { + public boolean isInverseTable(int j) { return isInverseTable[j]; } @@ -470,11 +470,11 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { return discriminatorColumnReaderTemplate; } - protected String getDiscriminatorAlias() { + public String getDiscriminatorAlias() { return discriminatorAlias; } - protected String getDiscriminatorFormulaTemplate() { + public String getDiscriminatorFormulaTemplate() { return discriminatorFormulaTemplate; } @@ -525,19 +525,19 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { return discriminatorFormula; } - protected String getTableName(int j) { + public String getTableName(int j) { return qualifiedTableNames[j]; } - protected String[] getKeyColumns(int j) { + public String[] getKeyColumns(int j) { return keyColumnNames[j]; } - protected boolean isTableCascadeDeleteEnabled(int j) { + public boolean isTableCascadeDeleteEnabled(int j) { return cascadeDeleteEnabled[j]; } - protected boolean isPropertyOfTable(int property, int j) { + public boolean isPropertyOfTable(int property, int j) { return propertyTableNumbers[property] == j; } @@ -552,7 +552,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { } @Override - public String filterFragment(String alias) throws MappingException { + protected String filterFragment(String alias) throws MappingException { String result = discriminatorFilterFragment( alias ); if ( hasWhere() ) { result += " and " + getSQLWhereString( alias ); @@ -578,7 +578,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { } @Override - public String filterFragment(String alias, Set treatAsDeclarations) { + protected String filterFragment(String alias, Set treatAsDeclarations) { String result = discriminatorFilterFragment( alias, treatAsDeclarations ); if ( hasWhere() ) { result += " and " + getSQLWhereString( alias ); @@ -810,7 +810,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { return subclassTableIsLazyClosure[j]; } - protected boolean isNullableTable(int j) { + public boolean isNullableTable(int j) { return isNullableTable[j]; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java index cb3ed30119..b717086fe4 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java @@ -287,19 +287,19 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister { return null; } - protected String getTableName(int j) { + public String getTableName(int j) { return tableName; } - protected String[] getKeyColumns(int j) { + public String[] getKeyColumns(int j) { return getIdentifierColumnNames(); } - protected boolean isTableCascadeDeleteEnabled(int j) { + public boolean isTableCascadeDeleteEnabled(int j) { return false; } - protected boolean isPropertyOfTable(int property, int j) { + public boolean isPropertyOfTable(int property, int j) { return true; } @@ -310,7 +310,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister { } @Override - public String filterFragment(String name) { + protected String filterFragment(String name) { return hasWhere() ? " and " + getSQLWhereString( name ) : ""; From 96faae93b11d97fac31cfbf9df2a592e8b22e0fb Mon Sep 17 00:00:00 2001 From: gavinking Date: Sun, 19 Jan 2020 15:19:50 +0100 Subject: [PATCH 05/13] HHH-13823 Always generate lowercase column aliases This change is needed by hibernate-rx as a workaround for behavior of the Postgres client. But anyway I think it's cleaner. --- hibernate-core/src/main/java/org/hibernate/mapping/Column.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java index d2dcc5aab6..9c3fd15bc4 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java @@ -113,7 +113,7 @@ public class Column implements Selectable, Serializable, Cloneable { final int lastLetter = StringHelper.lastIndexOfLetter( name ); final String suffix = AliasConstantsHelper.get( uniqueInteger ); - String alias = name; + String alias = name.toLowerCase( Locale.ROOT ); if ( lastLetter == -1 ) { alias = "column"; } From 12a8508e669aa2824df7ab6d7ad2b58fcb20d5e3 Mon Sep 17 00:00:00 2001 From: gavinking Date: Sun, 19 Jan 2020 18:00:41 +0100 Subject: [PATCH 06/13] HHH-13823 Introduce an indirection when instantiating Insert/Update/Delete This allows hibernate-rx to intervene in the rendering of bind variables and use $n instead of ? --- .../AbstractCollectionPersister.java | 15 +++++++ .../collection/BasicCollectionPersister.java | 11 ++--- .../collection/OneToManyPersister.java | 27 ++++++------ .../entity/AbstractEntityPersister.java | 42 +++++++++++-------- 4 files changed, 58 insertions(+), 37 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index e7f9e2de1b..81cdccde6e 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -81,6 +81,9 @@ import org.hibernate.persister.walking.spi.CompositionDefinition; import org.hibernate.persister.walking.spi.EntityDefinition; import org.hibernate.pretty.MessageHelper; import org.hibernate.sql.Alias; +import org.hibernate.sql.Insert; +import org.hibernate.sql.Update; +import org.hibernate.sql.Delete; import org.hibernate.sql.SelectFragment; import org.hibernate.sql.SimpleSelect; import org.hibernate.sql.Template; @@ -2274,4 +2277,16 @@ public abstract class AbstractCollectionPersister } }; } + + protected Insert createInsert() { + return new Insert( getFactory().getJdbcServices().getDialect() ); + } + + protected Update createUpdate() { + return new Update( getFactory().getJdbcServices().getDialect() ); + } + + protected Delete createDelete() { + return new Delete(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java index d271051a69..ee45ae0f98 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java @@ -64,8 +64,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { */ @Override protected String generateDeleteString() { - final Delete delete = new Delete() - .setTableName( qualifiedTableName ) + final Delete delete = createDelete().setTableName( qualifiedTableName ) .addPrimaryKeyColumns( keyColumnNames ); if ( hasWhere ) { @@ -84,8 +83,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { */ @Override protected String generateInsertRowString() { - final Insert insert = new Insert( getDialect() ) - .setTableName( qualifiedTableName ) + final Insert insert = createInsert().setTableName( qualifiedTableName ) .addColumns( keyColumnNames ); if ( hasIdentifier ) { @@ -112,8 +110,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { */ @Override protected String generateUpdateRowString() { - final Update update = new Update( getDialect() ) - .setTableName( qualifiedTableName ); + final Update update = createUpdate().setTableName( qualifiedTableName ); //if ( !elementIsFormula ) { update.addColumns( elementColumnNames, elementColumnIsSettable, elementColumnWriters ); @@ -147,7 +144,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { */ @Override protected String generateDeleteRowString() { - final Delete delete = new Delete().setTableName( qualifiedTableName ); + final Delete delete = createDelete().setTableName( qualifiedTableName ); if ( hasIdentifier ) { delete.addPrimaryKeyColumns( new String[] {identifierColumnName} ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java index 3c4cec89d5..10b27aa383 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java @@ -78,10 +78,8 @@ public class OneToManyPersister extends AbstractCollectionPersister { */ @Override protected String generateDeleteString() { - final Update update = new Update( getDialect() ) - .setTableName( qualifiedTableName ) - .addColumns( keyColumnNames, "null" ) - .addPrimaryKeyColumns( keyColumnNames ); + final Update update = createUpdate().setTableName( qualifiedTableName ) + .addColumns( keyColumnNames, "null" ); if ( hasIndex && !indexContainsFormula ) { for ( int i = 0 ; i < indexColumnNames.length ; i++ ) { @@ -91,6 +89,8 @@ public class OneToManyPersister extends AbstractCollectionPersister { } } + update.addPrimaryKeyColumns( keyColumnNames ); + if ( hasWhere ) { update.setWhere( sqlWhereString ); } @@ -107,8 +107,7 @@ public class OneToManyPersister extends AbstractCollectionPersister { */ @Override protected String generateInsertRowString() { - final Update update = new Update( getDialect() ) - .setTableName( qualifiedTableName ) + final Update update = createUpdate().setTableName( qualifiedTableName ) .addColumns( keyColumnNames ); if ( hasIndex && !indexContainsFormula ) { @@ -134,11 +133,8 @@ public class OneToManyPersister extends AbstractCollectionPersister { */ @Override protected String generateUpdateRowString() { - final Update update = new Update( getDialect() ).setTableName( qualifiedTableName ); - update.addPrimaryKeyColumns( elementColumnNames, elementColumnIsSettable, elementColumnWriters ); - if ( hasIdentifier ) { - update.addPrimaryKeyColumns( new String[] {identifierColumnName} ); - } + final Update update = createUpdate().setTableName( qualifiedTableName ); + if ( hasIndex && !indexContainsFormula ) { for ( int i = 0 ; i < indexColumnNames.length ; i++ ) { if ( indexColumnIsSettable[i] ) { @@ -147,6 +143,12 @@ public class OneToManyPersister extends AbstractCollectionPersister { } } + update.addPrimaryKeyColumns( elementColumnNames, elementColumnIsSettable, elementColumnWriters ); + + if ( hasIdentifier ) { + update.addPrimaryKeyColumns( new String[] {identifierColumnName} ); + } + return update.toStatementString(); } @@ -156,8 +158,7 @@ public class OneToManyPersister extends AbstractCollectionPersister { */ @Override protected String generateDeleteRowString() { - final Update update = new Update( getDialect() ) - .setTableName( qualifiedTableName ) + final Update update = createUpdate().setTableName( qualifiedTableName ) .addColumns( keyColumnNames, "null" ); if ( hasIndex && !indexContainsFormula ) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 45a414afbe..f3093bcd5a 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -1894,8 +1894,7 @@ public abstract class AbstractEntityPersister } private String generateVersionIncrementUpdateString() { - Update update = new Update( getFactory().getDialect() ); - update.setTableName( getTableName( 0 ) ); + Update update = createUpdate().setTableName( getTableName( 0 ) ); if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) { update.setComment( "forced version increment" ); } @@ -2612,15 +2611,7 @@ public abstract class AbstractEntityPersister final Object[] oldFields, final boolean useRowId) { - Update update = new Update( getFactory().getDialect() ).setTableName( getTableName( j ) ); - - // select the correct row by either pk or rowid - if ( useRowId ) { - update.addPrimaryKeyColumns( new String[] {rowIdName} ); //TODO: eventually, rowIdName[j] - } - else { - update.addPrimaryKeyColumns( getKeyColumns( j ) ); - } + Update update = createUpdate().setTableName( getTableName( j ) ); boolean hasColumns = false; for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) { @@ -2649,6 +2640,14 @@ public abstract class AbstractEntityPersister } } + // select the correct row by either pk or rowid + if ( useRowId ) { + update.addPrimaryKeyColumns( new String[] {rowIdName} ); //TODO: eventually, rowIdName[j] + } + else { + update.addPrimaryKeyColumns( getKeyColumns( j ) ); + } + if ( j == 0 && isVersioned() && entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.VERSION ) { // this is the root (versioned) table, and we are using version-based // optimistic locking; if we are not updating the version, also don't @@ -2721,8 +2720,7 @@ public abstract class AbstractEntityPersister // todo : remove the identityInsert param and variations; // identity-insert strings are now generated from generateIdentityInsertString() - Insert insert = new Insert( getFactory().getDialect() ) - .setTableName( getTableName( j ) ); + Insert insert = createInsert().setTableName( getTableName( j ) ); // add normal properties for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) { @@ -2883,8 +2881,7 @@ public abstract class AbstractEntityPersister * Generate the SQL that deletes a row by id (and version) */ public String generateDeleteString(int j) { - final Delete delete = new Delete() - .setTableName( getTableName( j ) ) + final Delete delete = createDelete().setTableName( getTableName( j ) ) .addPrimaryKeyColumns( getKeyColumns( j ) ); if ( j == 0 ) { delete.setVersionColumnName( getVersionColumnName() ); @@ -3824,8 +3821,7 @@ public abstract class AbstractEntityPersister int span = getTableSpan(); String[] deleteStrings = new String[span]; for ( int j = span - 1; j >= 0; j-- ) { - Delete delete = new Delete() - .setTableName( getTableName( j ) ) + Delete delete = createDelete().setTableName( getTableName( j ) ) .addPrimaryKeyColumns( getKeyColumns( j ) ); if ( getFactory().getSessionFactoryOptions().isCommentsEnabled() ) { delete.setComment( "delete " + getEntityName() + " [" + j + "]" ); @@ -6001,4 +5997,16 @@ public abstract class AbstractEntityPersister return substituteBrackets( getOriginalQueryString() ); } } + + protected Insert createInsert() { + return new Insert( getFactory().getJdbcServices().getDialect() ); + } + + protected Update createUpdate() { + return new Update( getFactory().getJdbcServices().getDialect() ); + } + + protected Delete createDelete() { + return new Delete(); + } } From a2f21e12a4f05223de767b2fe041e4e0cc600f62 Mon Sep 17 00:00:00 2001 From: gavinking Date: Sun, 19 Jan 2020 19:43:30 +0100 Subject: [PATCH 07/13] HHH-13823 Expose members of some SQL construction classes to subclasses Allows hibernate-rx to more easily customize bind variable syntax. --- .../main/java/org/hibernate/sql/Delete.java | 16 ++++++------- .../java/org/hibernate/sql/InFragment.java | 4 ++-- .../main/java/org/hibernate/sql/Insert.java | 11 +++++---- .../java/org/hibernate/sql/InsertSelect.java | 13 ++++++---- .../main/java/org/hibernate/sql/Select.java | 20 +++++++++------- .../java/org/hibernate/sql/SimpleSelect.java | 19 ++++++++------- .../main/java/org/hibernate/sql/Update.java | 24 +++++++++---------- 7 files changed, 59 insertions(+), 48 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/Delete.java b/hibernate-core/src/main/java/org/hibernate/sql/Delete.java index a6badc0305..cd5affb8f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/Delete.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/Delete.java @@ -16,13 +16,13 @@ import java.util.Map; */ public class Delete { - private String tableName; - private String versionColumnName; - private String where; + protected String tableName; + protected String versionColumnName; + protected String where; + protected String comment; + + protected Map primaryKeyColumns = new LinkedHashMap<>(); - private Map primaryKeyColumns = new LinkedHashMap(); - - private String comment; public Delete setComment(String comment) { this.comment = comment; return this; @@ -43,9 +43,9 @@ public class Delete { buf.append( " where " ); } boolean conditionsAppended = false; - Iterator iter = primaryKeyColumns.entrySet().iterator(); + Iterator> iter = primaryKeyColumns.entrySet().iterator(); while ( iter.hasNext() ) { - Map.Entry e = (Map.Entry) iter.next(); + Map.Entry e = iter.next(); buf.append( e.getKey() ).append( '=' ).append( e.getValue() ); if ( iter.hasNext() ) { buf.append( " and " ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/InFragment.java b/hibernate-core/src/main/java/org/hibernate/sql/InFragment.java index 3237c53204..3e15777220 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/InFragment.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/InFragment.java @@ -25,8 +25,8 @@ public class InFragment { public static final String NULL = "null"; public static final String NOT_NULL = "not null"; - private String columnName; - private List values = new ArrayList(); + protected String columnName; + protected List values = new ArrayList(); /** * @param value an SQL literal, NULL, or NOT_NULL diff --git a/hibernate-core/src/main/java/org/hibernate/sql/Insert.java b/hibernate-core/src/main/java/org/hibernate/sql/Insert.java index 25b2d7d276..93083a90e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/Insert.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/Insert.java @@ -19,10 +19,13 @@ import org.hibernate.type.LiteralType; * @author Gavin King */ public class Insert { + + protected String tableName; + protected String comment; + + protected Map columns = new LinkedHashMap<>(); + private Dialect dialect; - private String tableName; - private String comment; - private Map columns = new LinkedHashMap(); public Insert(Dialect dialect) { this.dialect = dialect; @@ -111,7 +114,7 @@ public class Insert { } else { buf.append(" ("); - Iterator iter = columns.keySet().iterator(); + Iterator iter = columns.keySet().iterator(); while ( iter.hasNext() ) { buf.append( iter.next() ); if ( iter.hasNext() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java b/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java index efc4a7cf49..fc8388b982 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java @@ -18,10 +18,13 @@ import org.hibernate.dialect.Dialect; * @author Steve Ebersole */ public class InsertSelect { - private String tableName; - private String comment; - private List columnNames = new ArrayList(); - private Select select; + + protected String tableName; + protected String comment; + + protected List columnNames = new ArrayList<>(); + + protected Select select; public InsertSelect(Dialect dialect) { //This is no longer used. Deprecate & remove? @@ -70,7 +73,7 @@ public class InsertSelect { buf.append( "insert into " ).append( tableName ); if ( !columnNames.isEmpty() ) { buf.append( " (" ); - Iterator itr = columnNames.iterator(); + Iterator itr = columnNames.iterator(); while ( itr.hasNext() ) { buf.append( itr.next() ); if ( itr.hasNext() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/Select.java b/hibernate-core/src/main/java/org/hibernate/sql/Select.java index e8b0aa4f3f..30a516dfb8 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/Select.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/Select.java @@ -17,15 +17,17 @@ import org.hibernate.internal.util.StringHelper; */ public class Select { - private String selectClause; - private String fromClause; - private String outerJoinsAfterFrom; - private String whereClause; - private String outerJoinsAfterWhere; - private String orderByClause; - private String groupByClause; - private String comment; - private LockOptions lockOptions = new LockOptions(); + protected String selectClause; + protected String fromClause; + protected String outerJoinsAfterFrom; + protected String whereClause; + protected String outerJoinsAfterWhere; + protected String orderByClause; + protected String groupByClause; + protected String comment; + + protected LockOptions lockOptions = new LockOptions(); + public final Dialect dialect; private int guesstimatedBufferSize = 20; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/SimpleSelect.java b/hibernate-core/src/main/java/org/hibernate/sql/SimpleSelect.java index f27f407b2c..46f96b71cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/SimpleSelect.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/SimpleSelect.java @@ -31,15 +31,18 @@ public class SimpleSelect { //private static final Alias DEFAULT_ALIAS = new Alias(10, null); - private String tableName; - private String orderBy; - private Dialect dialect; - private LockOptions lockOptions = new LockOptions( LockMode.READ ); - private String comment; + protected String tableName; + protected String orderBy; + protected String comment; + + protected List columns = new ArrayList(); + protected Map aliases = new HashMap(); + protected List whereTokens = new ArrayList(); + + protected LockOptions lockOptions = new LockOptions( LockMode.READ ); + + private Dialect dialect; - private List columns = new ArrayList(); - private Map aliases = new HashMap(); - private List whereTokens = new ArrayList(); public SimpleSelect addColumns(String[] columnNames, String[] columnAliases) { for ( int i = 0; i < columnNames.length; i++ ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/Update.java b/hibernate-core/src/main/java/org/hibernate/sql/Update.java index 93611d73a4..7b9a3fdae8 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/Update.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/Update.java @@ -19,15 +19,15 @@ import org.hibernate.type.LiteralType; */ public class Update { - private String tableName; - private String versionColumnName; - private String where; - private String assignments; - private String comment; + protected String tableName; + protected String versionColumnName; + protected String where; + protected String assignments; + protected String comment; - private Map primaryKeyColumns = new LinkedHashMap(); - private Map columns = new LinkedHashMap(); - private Map whereColumns = new LinkedHashMap(); + protected Map primaryKeyColumns = new LinkedHashMap<>(); + protected Map columns = new LinkedHashMap<>(); + protected Map whereColumns = new LinkedHashMap<>(); private Dialect dialect; @@ -170,9 +170,9 @@ public class Update { } buf.append( "update " ).append( tableName ).append( " set " ); boolean assignmentsAppended = false; - Iterator iter = columns.entrySet().iterator(); + Iterator> iter = columns.entrySet().iterator(); while ( iter.hasNext() ) { - Map.Entry e = (Map.Entry) iter.next(); + Map.Entry e = iter.next(); buf.append( e.getKey() ).append( '=' ).append( e.getValue() ); if ( iter.hasNext() ) { buf.append( ", " ); @@ -192,7 +192,7 @@ public class Update { } iter = primaryKeyColumns.entrySet().iterator(); while ( iter.hasNext() ) { - Map.Entry e = (Map.Entry) iter.next(); + Map.Entry e = iter.next(); buf.append( e.getKey() ).append( '=' ).append( e.getValue() ); if ( iter.hasNext() ) { buf.append( " and " ); @@ -208,7 +208,7 @@ public class Update { } iter = whereColumns.entrySet().iterator(); while ( iter.hasNext() ) { - final Map.Entry e = (Map.Entry) iter.next(); + final Map.Entry e = iter.next(); if ( conditionsAppended ) { buf.append( " and " ); } From a0f9b1df0015b5747e4de7e63b1acde87a2d40ac Mon Sep 17 00:00:00 2001 From: gavinking Date: Mon, 20 Jan 2020 14:44:13 +0100 Subject: [PATCH 08/13] HHH-13823 Make three private methods of SessionImpl visible to subclasses --- .../src/main/java/org/hibernate/internal/SessionImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 5f839ebf09..58782c947c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -558,13 +558,13 @@ public class SessionImpl } } - private void checkNoUnresolvedActionsBeforeOperation() { + protected void checkNoUnresolvedActionsBeforeOperation() { if ( persistenceContext.getCascadeLevel() == 0 && actionQueue.hasUnresolvedEntityInsertActions() ) { throw new IllegalStateException( "There are delayed insert actions before operation as cascade level 0." ); } } - private void checkNoUnresolvedActionsAfterOperation() { + protected void checkNoUnresolvedActionsAfterOperation() { if ( persistenceContext.getCascadeLevel() == 0 ) { actionQueue.checkNoUnresolvedActionsAfterOperation(); } @@ -3371,7 +3371,7 @@ public class SessionImpl } } - private CacheMode determineAppropriateLocalCacheMode(Map localProperties) { + protected CacheMode determineAppropriateLocalCacheMode(Map localProperties) { CacheRetrieveMode retrieveMode = null; CacheStoreMode storeMode = null; if ( localProperties != null ) { From e5f8341aa4173ca460aa6f8b09c28c4bb05a6c67 Mon Sep 17 00:00:00 2001 From: gavinking Date: Mon, 20 Jan 2020 17:06:53 +0100 Subject: [PATCH 09/13] HHH-13823 Add setters for two of the properties of EntityIdentityInsertAction This is needed by hibernate-rx. --- .../action/internal/EntityIdentityInsertAction.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java index 41a078923f..c962c2c1d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java @@ -214,6 +214,10 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction { return generatedId; } + protected void setGeneratedId(Serializable generatedId) { + this.generatedId = generatedId; + } + /** * Access to the delayed entity key * @@ -237,6 +241,10 @@ public class EntityIdentityInsertAction extends AbstractEntityInsertAction { return entityKey != null ? entityKey : delayedEntityKey; } + protected void setEntityKey(EntityKey entityKey) { + this.entityKey = entityKey; + } + private static DelayedPostInsertIdentifier generateDelayedPostInsertIdentifier() { return new DelayedPostInsertIdentifier(); } From fa952863cf7effa61c8a3b63f72805e7d1be8b79 Mon Sep 17 00:00:00 2001 From: gavinking Date: Mon, 20 Jan 2020 21:14:30 +0100 Subject: [PATCH 10/13] HHH-13823 Make it possible to reuse MergeContext in Hibernate RX. Exposes the operations used by DefaultMergeEventListener --- .../java/org/hibernate/event/internal/MergeContext.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/MergeContext.java b/hibernate-core/src/main/java/org/hibernate/event/internal/MergeContext.java index 3f334dcd52..dfbecc414e 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/MergeContext.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/MergeContext.java @@ -77,7 +77,7 @@ import org.jboss.logging.Logger; * * @author Gail Badner */ -class MergeContext implements Map { +public class MergeContext implements Map { private static final Logger LOG = Logger.getLogger( MergeContext.class ); private final EventSource session; @@ -101,7 +101,7 @@ class MergeContext implements Map { // key is a merge entity; // value is a flag indicating if the merge entity is currently in the merge process. - MergeContext(EventSource session, EntityCopyObserver entityCopyObserver){ + public MergeContext(EventSource session, EntityCopyObserver entityCopyObserver){ this.session = session; this.entityCopyObserver = entityCopyObserver; } @@ -226,7 +226,7 @@ class MergeContext implements Map { * managed entity associated with mergeEntity * @throws IllegalStateException if internal cross-references are out of sync, */ - /* package-private */ Object put(Object mergeEntity, Object managedEntity, boolean isOperatedOn) { + public Object put(Object mergeEntity, Object managedEntity, boolean isOperatedOn) { if ( mergeEntity == null || managedEntity == null ) { throw new NullPointerException( "null merge and managed entities are not supported by " + getClass().getName() ); } @@ -347,7 +347,7 @@ class MergeContext implements Map { * @throws NullPointerException if mergeEntity is null * @throws IllegalStateException if this MergeContext does not contain a a cross-reference for mergeEntity */ - /* package-private */ void setOperatedOn(Object mergeEntity, boolean isOperatedOn) { + public void setOperatedOn(Object mergeEntity, boolean isOperatedOn) { if ( mergeEntity == null ) { throw new NullPointerException( "null entities are not supported by " + getClass().getName() ); } From 8f563fbd3146c2fe649ba14e1e5af191dba455eb Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 26 Nov 2019 16:25:10 +0100 Subject: [PATCH 11/13] HHH-13752 - Test and fix deletion of entities with many-to-many assocations using non-primary keys for join table --- .../hql/internal/ast/exec/DeleteExecutor.java | 41 +++++++++++++++---- .../id/AbstractTableBasedBulkIdHandler.java | 38 +++++++++++++++++ .../spi/id/TableBasedDeleteHandlerImpl.java | 2 +- .../AbstractCteValuesListBulkIdHandler.java | 26 ++++++++++++ .../cte/CteValuesListDeleteHandlerImpl.java | 2 +- .../AbstractInlineIdsDeleteHandlerImpl.java | 26 +++++++++++- .../spi/id/persistent/DeleteHandlerImpl.java | 6 +++ .../test/hql/NaturalIdDereferenceTest.java | 22 ++++++++++ 8 files changed, 152 insertions(+), 11 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/DeleteExecutor.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/DeleteExecutor.java index a904220098..0c2aca1f22 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/DeleteExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/DeleteExecutor.java @@ -7,6 +7,7 @@ package org.hibernate.hql.internal.ast.exec; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.hibernate.HibernateException; @@ -23,6 +24,7 @@ import org.hibernate.persister.collection.AbstractCollectionPersister; import org.hibernate.persister.entity.Queryable; import org.hibernate.sql.Delete; import org.hibernate.type.CollectionType; +import org.hibernate.type.ComponentType; import org.hibernate.type.Type; import org.jboss.logging.Logger; @@ -58,7 +60,8 @@ public class DeleteExecutor extends BasicExecutor { final SqlGenerator gen = new SqlGenerator( factory ); gen.whereClause( whereClause ); parameterSpecifications = gen.getCollectedParameters(); - idSubselectWhere = gen.getSQL().length() > 7 ? gen.getSQL() : ""; + String sql = gen.getSQL(); + idSubselectWhere = sql.length() > 7 ? sql : ""; } else { parameterSpecifications = new ArrayList<>(); @@ -74,8 +77,20 @@ public class DeleteExecutor extends BasicExecutor { final CollectionType cType = (CollectionType) type; final AbstractCollectionPersister cPersister = (AbstractCollectionPersister) metamodel.collectionPersister( cType.getRole() ); if ( cPersister.isManyToMany() ) { - if ( persister.getIdentifierColumnNames().length > 1 - && notSupportingTuplesInSubqueries ) { + Type keyType = cPersister.getKeyType(); + String[] columnNames; + if ( keyType.isComponentType() ) { + ComponentType componentType = (ComponentType) keyType; + List columns = new ArrayList<>( componentType.getPropertyNames().length ); + for ( String propertyName : componentType.getPropertyNames() ) { + Collections.addAll( columns, persister.toColumns( propertyName ) ); + } + columnNames = columns.toArray( new String[columns.size()] ); + } + else { + columnNames = persister.getIdentifierColumnNames(); + } + if ( columnNames.length > 1 && notSupportingTuplesInSubqueries ) { LOG.warn( "This dialect is unable to cascade the delete into the many-to-many join table" + " when the entity has multiple primary keys. Either properly setup cascading on" + @@ -83,11 +98,13 @@ public class DeleteExecutor extends BasicExecutor { ); } else { - final String idSubselect = "(select " - + String.join( ", ", persister.getIdentifierColumnNames() ) + " from " - + persister.getTableName() + idSubselectWhere + ")"; - final String where = "(" + String.join( ", ", cPersister.getKeyColumnNames() ) - + ") in " + idSubselect; + StringBuilder whereBuilder = new StringBuilder(); + whereBuilder.append( '(' ); + append( ", ", cPersister.getKeyColumnNames(), whereBuilder ); + whereBuilder.append( ") in (select " ); + append( ", ", columnNames, whereBuilder ); + final String where = whereBuilder.append(" from ") + .append( persister.getTableName() ).append( idSubselectWhere ).append( ")" ).toString(); final Delete delete = new Delete().setTableName( cPersister.getTableName() ).setWhere( where ); if ( commentsEnabled ) { delete.setComment( "delete FKs in join table" ); @@ -102,6 +119,14 @@ public class DeleteExecutor extends BasicExecutor { throw new HibernateException( "Unable to delete the FKs in the join table!", e ); } } + + private static void append(String delimiter, String[] parts, StringBuilder sb) { + sb.append( parts[0] ); + for ( int i = 1; i < parts.length; i++ ) { + sb.append( delimiter ); + sb.append( parts[i] ); + } + } @Override public int execute(QueryParameters parameters, SharedSessionContractImplementor session) throws HibernateException { diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractTableBasedBulkIdHandler.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractTableBasedBulkIdHandler.java index 71f696f255..0a59a4d3a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractTableBasedBulkIdHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractTableBasedBulkIdHandler.java @@ -6,6 +6,7 @@ */ package org.hibernate.hql.spi.id; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -16,6 +17,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.hql.internal.ast.HqlSqlWalker; import org.hibernate.hql.internal.ast.SqlGenerator; import org.hibernate.param.ParameterSpecification; +import org.hibernate.persister.collection.AbstractCollectionPersister; import org.hibernate.persister.entity.Queryable; import org.hibernate.sql.InsertSelect; import org.hibernate.sql.Select; @@ -23,6 +25,8 @@ import org.hibernate.sql.SelectValues; import antlr.RecognitionException; import antlr.collections.AST; +import org.hibernate.type.ComponentType; +import org.hibernate.type.Type; /** * Convenience base class for {@link MultiTableBulkIdStrategy.UpdateHandler} @@ -193,6 +197,40 @@ public abstract class AbstractTableBasedBulkIdHandler { " from " + idTableInfo.getQualifiedIdTableName(); } + protected String generateIdSubselect(Queryable persister, AbstractCollectionPersister cPersister, IdTableInfo idTableInfo) { + String[] columnNames = getKeyColumnNames( persister, cPersister ); + StringBuilder selectBuilder = new StringBuilder(); + selectBuilder.append( "select " ); + appendJoined( ", ", columnNames, selectBuilder ); + return selectBuilder.append( " from " ) + .append( idTableInfo.getQualifiedIdTableName() ).toString(); + } + + protected static String[] getKeyColumnNames(Queryable persister, AbstractCollectionPersister cPersister) { + Type keyType = cPersister.getKeyType(); + String[] columnNames; + if ( keyType.isComponentType() ) { + ComponentType componentType = (ComponentType) keyType; + List columns = new ArrayList<>(componentType.getPropertyNames().length ); + for ( String propertyName : componentType.getPropertyNames() ) { + Collections.addAll( columns, persister.toColumns( propertyName ) ); + } + columnNames = columns.toArray( new String[columns.size()] ); + } + else { + columnNames = persister.getIdentifierColumnNames(); + } + return columnNames; + } + + protected static void appendJoined(String delimiter, String[] parts, StringBuilder sb) { + sb.append( parts[0] ); + for ( int i = 1; i < parts.length; i++ ) { + sb.append( delimiter ); + sb.append( parts[i] ); + } + } + protected void prepareForUse(Queryable persister, SharedSessionContractImplementor session) { } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedDeleteHandlerImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedDeleteHandlerImpl.java index f9eee19212..6ff19ae103 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedDeleteHandlerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/TableBasedDeleteHandlerImpl.java @@ -68,7 +68,7 @@ public class TableBasedDeleteHandlerImpl AbstractCollectionPersister cPersister = (AbstractCollectionPersister) factory.getMetamodel().collectionPersister( cType.getRole() ); if ( cPersister.isManyToMany() ) { deletes.add( generateDelete( cPersister.getTableName(), - cPersister.getKeyColumnNames(), idSubselect, "bulk delete - m2m join table cleanup")); + cPersister.getKeyColumnNames(), generateIdSubselect( targetedPersister, cPersister, idTableInfo ), "bulk delete - m2m join table cleanup")); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/AbstractCteValuesListBulkIdHandler.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/AbstractCteValuesListBulkIdHandler.java index bf3600ced9..2f4b75e7fe 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/AbstractCteValuesListBulkIdHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/AbstractCteValuesListBulkIdHandler.java @@ -17,8 +17,11 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.hql.internal.ast.HqlSqlWalker; import org.hibernate.hql.spi.id.AbstractIdsBulkIdHandler; import org.hibernate.internal.util.StringHelper; +import org.hibernate.persister.collection.AbstractCollectionPersister; import org.hibernate.persister.entity.Queryable; +import java.util.Arrays; + /** * Defines how identifier values are selected from the updatable/deletable tables. * @@ -88,9 +91,32 @@ public abstract class AbstractCteValuesListBulkIdHandler extends ) ) .append( " from " ) .append( determineIdTableName( persister ) ) + .append( " tmp2" ) .toString(); } + protected String generateIdSubselect(String idSubselect, Queryable persister, AbstractCollectionPersister cPersister) { + String[] columnNames = getKeyColumnNames( persister, cPersister ); + // If the column names are equal to the identifier column names, just return the idSubselect + if ( Arrays.equals( getTargetedQueryable().getIdentifierColumnNames(), columnNames ) ) { + return idSubselect; + } + + // Otherwise, we need to fetch the key column names from the original table + // Unfortunately, this is a bit more work, as only the identifiers are fetched + // It would be great if we could adapt #selectIds to fetch key columns as well + StringBuilder selectBuilder = new StringBuilder(); + selectBuilder.append( "select " ); + appendJoined( ", ", columnNames, selectBuilder ); + selectBuilder.append( " from " ).append( getTargetedQueryable().getTableName() ); + selectBuilder.append( " tmp where (" ); + appendJoined( ", ", getTargetedQueryable().getIdentifierColumnNames(), selectBuilder ); + selectBuilder.append( ") in (select " ); + appendJoined( ", ", getTargetedQueryable().getIdentifierColumnNames(), selectBuilder ); + selectBuilder.append( " from " ).append( determineIdTableName( persister ) ).append( " tmp2)" ); + return selectBuilder.toString(); + } + protected CteValuesListBuilder prepareCteStatement( SharedSessionContractImplementor session, QueryParameters queryParameters) { diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/CteValuesListDeleteHandlerImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/CteValuesListDeleteHandlerImpl.java index b587554dd7..9c0b6c059e 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/CteValuesListDeleteHandlerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/CteValuesListDeleteHandlerImpl.java @@ -56,7 +56,7 @@ public class CteValuesListDeleteHandlerImpl deletes.add( generateDelete( cPersister.getTableName(), cPersister.getKeyColumnNames(), - idSubselect, + generateIdSubselect( idSubselect, getTargetedQueryable(), cPersister ), "bulk delete - m2m join table cleanup" ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/AbstractInlineIdsDeleteHandlerImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/AbstractInlineIdsDeleteHandlerImpl.java index 498aa24fd9..87663cddb4 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/AbstractInlineIdsDeleteHandlerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/AbstractInlineIdsDeleteHandlerImpl.java @@ -9,6 +9,7 @@ package org.hibernate.hql.spi.id.inline; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.hibernate.engine.spi.QueryParameters; @@ -17,6 +18,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.hql.internal.ast.HqlSqlWalker; import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; import org.hibernate.persister.collection.AbstractCollectionPersister; +import org.hibernate.persister.entity.Queryable; import org.hibernate.sql.Delete; import org.hibernate.type.CollectionType; import org.hibernate.type.Type; @@ -61,7 +63,7 @@ public abstract class AbstractInlineIdsDeleteHandlerImpl deletes.add( generateDelete( cPersister.getTableName(), cPersister.getKeyColumnNames(), - idSubselect, + generateIdSubselect( idSubselect, getTargetedQueryable(), cPersister ), "bulk delete - m2m join table cleanup" ).toStatementString() ); } @@ -102,6 +104,28 @@ public abstract class AbstractInlineIdsDeleteHandlerImpl return values.getIds().size(); } + protected String generateIdSubselect(String idSubselect, Queryable persister, AbstractCollectionPersister cPersister) { + String[] columnNames = getKeyColumnNames( persister, cPersister ); + // If the column names are equal to the identifier column names, just return the idSubselect + if ( Arrays.equals(getTargetedQueryable().getIdentifierColumnNames(), columnNames ) ) { + return idSubselect; + } + + // Otherwise, we need to fetch the key column names from the original table + // Unfortunately, this is a bit more work, as only the identifiers are fetched + // It would be great if we could adapt #selectIds to fetch key columns as well + StringBuilder selectBuilder = new StringBuilder(); + selectBuilder.append( "select " ); + appendJoined( ", ", columnNames, selectBuilder ); + selectBuilder.append( " from " ).append( getTargetedQueryable().getTableName() ); + selectBuilder.append( " tmp where (" ); + appendJoined( ", ", getTargetedQueryable().getIdentifierColumnNames(), selectBuilder ); + selectBuilder.append( ") in (" ); + selectBuilder.append( idSubselect ); + selectBuilder.append( ")" ); + return selectBuilder.toString(); + } + protected Delete generateDelete( String tableName, String[] columnNames, diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/DeleteHandlerImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/DeleteHandlerImpl.java index 282eb30415..7206fba012 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/DeleteHandlerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/DeleteHandlerImpl.java @@ -15,6 +15,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.hql.internal.ast.HqlSqlWalker; import org.hibernate.hql.spi.id.IdTableInfo; import org.hibernate.hql.spi.id.TableBasedDeleteHandlerImpl; +import org.hibernate.persister.collection.AbstractCollectionPersister; import org.hibernate.persister.entity.Queryable; import org.hibernate.sql.SelectValues; @@ -44,6 +45,11 @@ public class DeleteHandlerImpl extends TableBasedDeleteHandlerImpl { return super.generateIdSubselect( persister, idTableInfo ) + " where " + SESSION_ID_COLUMN_NAME + "=?"; } + @Override + protected String generateIdSubselect(Queryable persister, AbstractCollectionPersister cPersister, IdTableInfo idTableInfo) { + return super.generateIdSubselect( persister, cPersister, idTableInfo ) + " where " + SESSION_ID_COLUMN_NAME + "=?"; + } + @Override protected int handlePrependedParametersOnIdSelection(PreparedStatement ps, SharedSessionContractImplementor session, int pos) throws SQLException { Helper.INSTANCE.bindSessionIdentifier( ps, session, pos ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/NaturalIdDereferenceTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/NaturalIdDereferenceTest.java index 5dca52d552..bc6fee5fca 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/NaturalIdDereferenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/NaturalIdDereferenceTest.java @@ -11,6 +11,7 @@ import org.hibernate.annotations.NaturalId; import org.hibernate.hql.spi.FilterTranslator; import org.hibernate.query.Query; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Before; import org.junit.Test; @@ -21,10 +22,13 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; import javax.persistence.Table; import java.util.Collections; import java.util.List; +import java.util.Set; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; @@ -239,6 +243,16 @@ public class NaturalIdDereferenceTest extends BaseCoreFunctionalTestCase { } ); } + @Test + @TestForIssue(jiraKey = "HHH-13752") + public void deleteWithNaturalIdBasedJoinTable() { + doInHibernate( this::sessionFactory, session -> { + Query query = session.createQuery( + "DELETE FROM Book b WHERE 1=0" ); + query.executeUpdate(); + } ); + } + private int getSQLJoinCount(Query query) { String sqlQuery = getSQLQuery( query ).toLowerCase(); @@ -316,6 +330,14 @@ public class NaturalIdDereferenceTest extends BaseCoreFunctionalTestCase { @Column(name = "isbn", unique = true) private String isbn; + @OneToMany + @JoinTable( + name = "similar_books", + joinColumns = @JoinColumn(name = "base_isbn", referencedColumnName = "isbn"), + inverseJoinColumns = @JoinColumn(name = "ref_isbn", referencedColumnName = "isbn_ref") + ) + private Set similarBooks; + } @Entity(name = "BookRef") From a2f7f59de4578ed41241037fe161a653e49bec1f Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 5 Dec 2019 19:21:03 +0100 Subject: [PATCH 12/13] HHH-13752 - Workaround id class issues like suggested by @jwgmeligmeyling --- .../hql/internal/ast/exec/DeleteExecutor.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/DeleteExecutor.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/DeleteExecutor.java index 0c2aca1f22..ef16c1e41f 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/DeleteExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/exec/DeleteExecutor.java @@ -11,6 +11,7 @@ import java.util.Collections; import java.util.List; import org.hibernate.HibernateException; +import org.hibernate.MappingException; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -82,10 +83,16 @@ public class DeleteExecutor extends BasicExecutor { if ( keyType.isComponentType() ) { ComponentType componentType = (ComponentType) keyType; List columns = new ArrayList<>( componentType.getPropertyNames().length ); - for ( String propertyName : componentType.getPropertyNames() ) { - Collections.addAll( columns, persister.toColumns( propertyName ) ); + try { + for ( String propertyName : componentType.getPropertyNames() ) { + Collections.addAll( columns, persister.toColumns( propertyName ) ); + } + columnNames = columns.toArray( new String[0] ); + } + catch (MappingException e) { + // Property not found, due to IdClasses are not properly handled in metamodel HHH-12996 + columnNames = persister.getIdentifierColumnNames(); } - columnNames = columns.toArray( new String[columns.size()] ); } else { columnNames = persister.getIdentifierColumnNames(); From 4318349b4db5695f4cb7520b3fb8535fabba0137 Mon Sep 17 00:00:00 2001 From: Antoine Reilles Date: Fri, 10 Jan 2020 14:44:24 +0100 Subject: [PATCH 13/13] Fix String format in log Use %s in the log string format, to avoid java.util.UnknownFormatConversionException: Conversion = ']' when enabling debug logs. --- .../java/org/hibernate/graph/internal/AttributeNodeImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java index b408362634..88a960fb21 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java @@ -160,7 +160,7 @@ public class AttributeNodeImpl final SubGraphImplementor previous = subGraphMap.put( subType, (SubGraphImplementor) subGraph ); if ( previous != null ) { - log.debugf( "Adding sub-graph [%s] over-wrote existing [%]", subGraph, previous ); + log.debugf( "Adding sub-graph [%s] over-wrote existing [%s]", subGraph, previous ); } }