Move annotations.immutable tests and implement immutable update warning/error

This commit is contained in:
Christian Beikov 2021-08-04 16:08:01 +02:00
parent eaba3acc20
commit f84585c5ed
13 changed files with 66 additions and 25 deletions

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.internal; package org.hibernate.query.sqm.internal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -32,6 +33,7 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.IdentitySet; import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable; import org.hibernate.persister.entity.Loadable;
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
import org.hibernate.query.Query; import org.hibernate.query.Query;
import org.hibernate.query.QueryTypeMismatchException; import org.hibernate.query.QueryTypeMismatchException;
import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl; import org.hibernate.query.hql.internal.NamedHqlQueryMementoImpl;
@ -128,6 +130,9 @@ public class QuerySqmImpl<R>
throw new IllegalArgumentException( "Non-select queries cannot be typed" ); throw new IllegalArgumentException( "Non-select queries cannot be typed" );
} }
} }
else if ( sqmStatement instanceof SqmUpdateStatement<?> ) {
verifyImmutableEntityUpdate( hqlString, (SqmUpdateStatement<R>) sqmStatement, producer.getFactory() );
}
this.resultType = resultType; this.resultType = resultType;
this.domainParameterXref = hqlInterpretation.getDomainParameterXref(); this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
this.parameterMetadata = hqlInterpretation.getParameterMetadata(); this.parameterMetadata = hqlInterpretation.getParameterMetadata();
@ -182,6 +187,9 @@ public class QuerySqmImpl<R>
producer.getFactory() producer.getFactory()
); );
} }
else if ( sqmStatement instanceof SqmUpdateStatement<?> ) {
verifyImmutableEntityUpdate( hqlString, (SqmUpdateStatement<R>) sqmStatement, producer.getFactory() );
}
this.parameterMetadata = hqlInterpretation.getParameterMetadata(); this.parameterMetadata = hqlInterpretation.getParameterMetadata();
this.domainParameterXref = hqlInterpretation.getDomainParameterXref(); this.domainParameterXref = hqlInterpretation.getDomainParameterXref();
@ -209,6 +217,9 @@ public class QuerySqmImpl<R>
producer.getFactory() producer.getFactory()
); );
} }
else if ( sqmStatement instanceof SqmUpdateStatement<?> ) {
verifyImmutableEntityUpdate( CRITERIA_HQL_STRING, (SqmUpdateStatement<R>) sqmStatement, producer.getFactory() );
}
this.hqlString = CRITERIA_HQL_STRING; this.hqlString = CRITERIA_HQL_STRING;
this.sqmStatement = sqmStatement; this.sqmStatement = sqmStatement;
@ -339,6 +350,37 @@ public class QuerySqmImpl<R>
} }
} }
private void verifyImmutableEntityUpdate(
String hqlString,
SqmUpdateStatement<R> sqmStatement,
SessionFactoryImplementor factory) {
final EntityPersister entityDescriptor = factory.getDomainModel()
.getEntityDescriptor( sqmStatement.getTarget().getEntityName() );
if ( entityDescriptor.isMutable() ) {
return;
}
final ImmutableEntityUpdateQueryHandlingMode immutableEntityUpdateQueryHandlingMode = factory
.getSessionFactoryOptions()
.getImmutableEntityUpdateQueryHandlingMode();
String querySpaces = Arrays.toString( entityDescriptor.getQuerySpaces() );
switch ( immutableEntityUpdateQueryHandlingMode ) {
case WARNING:
LOG.immutableEntityUpdateQuery( hqlString, querySpaces );
break;
case EXCEPTION:
throw new HibernateException(
"The query: [" + hqlString + "] attempts to update an immutable entity: " + querySpaces
);
default:
throw new UnsupportedOperationException(
"The " + immutableEntityUpdateQueryHandlingMode + " is not supported!"
);
}
}
public SessionFactoryImplementor getSessionFactory() { public SessionFactoryImplementor getSessionFactory() {
return getSession().getFactory(); return getSession().getFactory();
} }

View File

@ -260,9 +260,11 @@ import org.hibernate.sql.ast.tree.expression.Summarization;
import org.hibernate.sql.ast.tree.expression.TrimSpecification; import org.hibernate.sql.ast.tree.expression.TrimSpecification;
import org.hibernate.sql.ast.tree.expression.UnaryOperation; import org.hibernate.sql.ast.tree.expression.UnaryOperation;
import org.hibernate.sql.ast.tree.from.CorrelatedTableGroup; import org.hibernate.sql.ast.tree.from.CorrelatedTableGroup;
import org.hibernate.sql.ast.tree.from.LazyTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer; import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.from.VirtualTableGroup;
import org.hibernate.sql.ast.tree.insert.InsertStatement; import org.hibernate.sql.ast.tree.insert.InsertStatement;
import org.hibernate.sql.ast.tree.insert.Values; import org.hibernate.sql.ast.tree.insert.Values;
import org.hibernate.sql.ast.tree.predicate.BetweenPredicate; import org.hibernate.sql.ast.tree.predicate.BetweenPredicate;
@ -662,9 +664,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
consumeReusablePaths( sqmPath, correspondingTableGroup, BaseSqmToSqlAstConverter::verifyManipulationImplicitJoin ); consumeReusablePaths( sqmPath, correspondingTableGroup, BaseSqmToSqlAstConverter::verifyManipulationImplicitJoin );
} }
private static void verifyManipulationImplicitJoin(SqmPath<?> joinedPath) { private static void verifyManipulationImplicitJoin(TableGroup tableGroup) {
//noinspection StatementWithEmptyBody //noinspection StatementWithEmptyBody
if ( joinedPath instanceof SqmEmbeddedValuedSimplePath<?> ) { if ( tableGroup instanceof LazyTableGroup && ( (LazyTableGroup) tableGroup ).getUnderlyingTableGroup() == null
|| tableGroup instanceof VirtualTableGroup ) {
// this is fine // this is fine
} }
else { else {
@ -2155,13 +2158,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
} }
private void consumeReusablePaths(SqmPath<?> sqmPath, TableGroup tableGroup) { private void consumeReusablePaths(SqmPath<?> sqmPath, TableGroup tableGroup) {
consumeReusablePaths( sqmPath, tableGroup, (sqmSubPath) -> {} ); consumeReusablePaths( sqmPath, tableGroup, tg -> {} );
} }
private void consumeReusablePaths( private void consumeReusablePaths(
SqmPath<?> sqmPath, SqmPath<?> sqmPath,
TableGroup parentTableGroup, TableGroup parentTableGroup,
Consumer<SqmPath<?>> implicitJoinChecker) { Consumer<TableGroup> implicitJoinChecker) {
if ( log.isTraceEnabled() ) { if ( log.isTraceEnabled() ) {
log.tracef( "Visiting implicit joins for `%s`", sqmPath.getNavigablePath() ); log.tracef( "Visiting implicit joins for `%s`", sqmPath.getNavigablePath() );
} }
@ -2187,7 +2190,6 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final TableGroup tableGroup; final TableGroup tableGroup;
if ( subPart instanceof TableGroupJoinProducer ) { if ( subPart instanceof TableGroupJoinProducer ) {
implicitJoinChecker.accept( joinedPath );
final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart; final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart;
final SqlAstJoinType defaultSqlAstJoinType = joinProducer.getDefaultSqlAstJoinType( final SqlAstJoinType defaultSqlAstJoinType = joinProducer.getDefaultSqlAstJoinType(
parentTableGroup ); parentTableGroup );
@ -2207,6 +2209,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
tableGroup = null; tableGroup = null;
} }
consumeReusablePaths( joinedPath, tableGroup, implicitJoinChecker ); consumeReusablePaths( joinedPath, tableGroup, implicitJoinChecker );
if ( tableGroup != null ) {
implicitJoinChecker.accept( tableGroup );
}
} }
); );
} }

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import org.hibernate.annotations.Immutable; import org.hibernate.annotations.Immutable;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import javax.persistence.AttributeConverter; import javax.persistence.AttributeConverter;

View File

@ -6,7 +6,7 @@
*/ */
//$Id$ //$Id$
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import javax.persistence.Entity; import javax.persistence.Entity;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import java.util.Collections; import java.util.Collections;
import javax.persistence.AttributeConverter; import javax.persistence.AttributeConverter;

View File

@ -6,7 +6,7 @@
*/ */
// $Id$ // $Id$
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import java.util.Map; import java.util.Map;
@ -122,12 +122,8 @@ public class ImmutableEntityUpdateQueryHandlingModeExceptionTest extends BaseNon
String statement = "Update ImmutableEntity e set e.selector = :changeable where e.id in " + String statement = "Update ImmutableEntity e set e.selector = :changeable where e.id in " +
"(select i.id from MutableEntity i where i.changeable = :selector)"; "(select i.id from MutableEntity i where i.changeable = :selector)";
Query query = session.createQuery(statement);
query.setParameter("changeable", "end");
query.setParameter("selector", "foo");
try { try {
query.executeUpdate(); session.createQuery(statement);
fail("Should have throw exception"); fail("Should have throw exception");
} }

View File

@ -4,10 +4,10 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.SessionImpl; import org.hibernate.query.sqm.internal.QuerySqmImpl;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
@ -30,7 +30,7 @@ public class ImmutableEntityUpdateQueryHandlingModeWarningTest extends BaseNonCo
@Rule @Rule
public LoggerInspectionRule logInspection = new LoggerInspectionRule( public LoggerInspectionRule logInspection = new LoggerInspectionRule(
Logger.getMessageLogger( CoreMessageLogger.class, SessionImpl.class.getName() ) ); Logger.getMessageLogger( CoreMessageLogger.class, QuerySqmImpl.class.getName() ) );
@Override @Override
protected Class[] getAnnotatedClasses() { protected Class[] getAnnotatedClasses() {

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -22,8 +22,6 @@ import org.hibernate.service.ServiceRegistry;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test; import org.junit.Test;
import org.jboss.logging.Logger;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later. * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import java.io.Serializable; import java.io.Serializable;
import javax.persistence.Convert; import javax.persistence.Convert;

View File

@ -6,7 +6,7 @@
*/ */
// $Id$ // $Id$
package org.hibernate.test.annotations.immutable; package org.hibernate.orm.test.annotations.immutable;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;