From a5e5ea48ce065e7be9577d9d04b37aa3574bd002 Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Mon, 4 Jun 2018 14:07:34 +0300 Subject: [PATCH] HHH-12561 - bulk_id_strategy does not work with globally_quoted_identifiers --- .../hql/spi/id/AbstractIdsBulkIdHandler.java | 8 +- .../AbstractCteValuesListBulkIdHandler.java | 8 +- .../GlobalQuotedIdentifiersBulkIdTest.java | 157 ++++++++++++++++++ 3 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bulkid/GlobalQuotedIdentifiersBulkIdTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractIdsBulkIdHandler.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractIdsBulkIdHandler.java index 166d647a9e..72ce906f1f 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractIdsBulkIdHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractIdsBulkIdHandler.java @@ -21,6 +21,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.hql.internal.ast.HqlSqlWalker; import org.hibernate.hql.internal.ast.tree.AbstractRestrictableStatement; import org.hibernate.hql.internal.ast.tree.FromElement; +import org.hibernate.internal.util.StringHelper; import org.hibernate.param.ParameterSpecification; import org.hibernate.persister.entity.Queryable; @@ -83,6 +84,8 @@ public abstract class AbstractIdsBulkIdHandler position += parameterSpecification.bind( ps, queryParameters, session, position ); } + Dialect dialect = session.getFactory().getServiceRegistry().getService( JdbcServices.class ).getDialect(); + ResultSet rs = session .getJdbcCoordinator() .getResultSetReturn() @@ -90,8 +93,9 @@ public abstract class AbstractIdsBulkIdHandler while ( rs.next() ) { Object[] result = new Object[targetedPersister.getIdentifierColumnNames().length]; for ( String columnName : targetedPersister.getIdentifierColumnNames() ) { - Object column = rs.getObject( columnName ); - result[rs.findColumn( columnName ) - 1] = column; + int columnIndex = rs.findColumn( StringHelper.unquote( columnName, dialect ) ); + Object column = rs.getObject(columnIndex); + result[columnIndex - 1] = column; } ids.add( result ); } 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 b0bff2b9ec..bf3600ced9 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 @@ -16,6 +16,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; 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.entity.Queryable; /** @@ -63,11 +64,16 @@ public abstract class AbstractCteValuesListBulkIdHandler extends } protected String determineIdTableName(Queryable persister) { + + String qualifiedTableName = jdbcEnvironment.getIdentifierHelper().applyGlobalQuoting( + "HT_" + StringHelper.unquote( persister.getTableName(), jdbcEnvironment.getDialect() ) + ).render(); + return jdbcEnvironment.getQualifiedObjectNameFormatter().format( new QualifiedTableName( Identifier.toIdentifier( catalog ), Identifier.toIdentifier( schema ), - Identifier.toIdentifier( "HT_" + persister.getTableName() ) + Identifier.toIdentifier( qualifiedTableName ) ), jdbcEnvironment.getDialect() ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bulkid/GlobalQuotedIdentifiersBulkIdTest.java b/hibernate-core/src/test/java/org/hibernate/test/bulkid/GlobalQuotedIdentifiersBulkIdTest.java new file mode 100644 index 0000000000..2ca13e346f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bulkid/GlobalQuotedIdentifiersBulkIdTest.java @@ -0,0 +1,157 @@ +package org.hibernate.test.bulkid; + +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.Date; +import java.util.Map; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; +import org.hibernate.hql.spi.id.inline.InlineIdsOrClauseBulkIdStrategy; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +/** + * @author Vlad Mihalcea + */ +@TestForIssue( jiraKey = "HHH-12561" ) +public class GlobalQuotedIdentifiersBulkIdTest + extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, + Doctor.class, + Engineer.class + }; + } + + @Override + protected void addConfigOptions(Map options) { + options.put( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, Boolean.TRUE ); + options.put( AvailableSettings.HQL_BULK_ID_STRATEGY, InlineIdsOrClauseBulkIdStrategy.class.getName() ); + } + + @Before + public void setUp() { + doInJPA( this::entityManagerFactory, entityManager -> { + for ( int i = 0; i < entityCount(); i++ ) { + Doctor doctor = new Doctor(); + doctor.setEmployed( ( i % 2 ) == 0 ); + doctor.setEmployedOn( Timestamp.valueOf( "2018-06-01 00:00:00" ) ); + entityManager.persist( doctor ); + } + + for ( int i = 0; i < entityCount(); i++ ) { + Engineer engineer = new Engineer(); + engineer.setEmployed( ( i % 2 ) == 0 ); + engineer.setEmployedOn( Timestamp.valueOf( "2018-06-01 00:00:00" ) ); + engineer.setFellow( ( i % 2 ) == 1 ); + entityManager.persist( engineer ); + } + }); + } + + protected int entityCount() { + return 5; + } + + @Test + public void testBulkUpdate() { + doInJPA( this::entityManagerFactory, entityManager -> { + int updateCount = entityManager.createQuery( + "UPDATE Person u " + + "SET u.employedOn = :date " + + "WHERE u.id IN :userIds" + ) + .setParameter( "date", Timestamp.valueOf( "2018-06-03 00:00:00" ) ) + .setParameter( "userIds", Arrays.asList(1L, 2L, 3L ) ) + .executeUpdate(); + + assertEquals(3, updateCount); + }); + } + + @Entity(name = "Person") + @Inheritance(strategy = InheritanceType.JOINED) + public static class Person { + + @Id + @GeneratedValue + private Long id; + + private String name; + + private boolean employed; + + @Temporal( TemporalType.TIMESTAMP ) + private Date employedOn; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getEmployedOn() { + return employedOn; + } + + public void setEmployedOn(Date employedOn) { + this.employedOn = employedOn; + } + + public boolean isEmployed() { + return employed; + } + + public void setEmployed(boolean employed) { + this.employed = employed; + } + } + + @Entity(name = "Doctor") + public static class Doctor extends Person { + } + + @Entity(name = "Engineer") + public static class Engineer extends Person { + + private boolean fellow; + + public boolean isFellow() { + return fellow; + } + + public void setFellow(boolean fellow) { + this.fellow = fellow; + } + } +} \ No newline at end of file