Merge remote-tracking branch 'upstream5/master' into wip/6.0_merge_15
This commit is contained in:
commit
d2865a54df
|
@ -3133,4 +3133,9 @@ public abstract class Dialect implements ConversionContext {
|
|||
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean supportsSelectAliasInGroupByClause() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -444,4 +444,10 @@ public class H2Dialect extends Dialect {
|
|||
public String getQueryHintString(String query, String hints) {
|
||||
return IndexQueryHintHandler.INSTANCE.addQueryHints( query, hints );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSelectAliasInGroupByClause() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -612,4 +612,10 @@ public class MySQLDialect extends Dialect {
|
|||
protected String escapeLiteral(String literal) {
|
||||
return ESCAPE_PATTERN.matcher( super.escapeLiteral( literal ) ).replaceAll( ESCAPE_PATTERN_REPLACEMENT );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSelectAliasInGroupByClause() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ public class Oracle8iDialect extends Dialect {
|
|||
|
||||
private static final Pattern UNION_KEYWORD_PATTERN = Pattern.compile( "\\bunion\\b" );
|
||||
|
||||
private static final Pattern SQL_STATEMENT_TYPE_PATTERN = Pattern.compile("^(?:\\/\\*.*?\\*\\/)?\\s*(select|insert|update|delete)\\s+.*?");
|
||||
private static final Pattern SQL_STATEMENT_TYPE_PATTERN = Pattern.compile("^(?:\\/\\*.*?\\*\\/)?\\s*(select|insert|update|delete)\\s+.*?", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
|
||||
@Override
|
||||
|
|
|
@ -647,4 +647,10 @@ public class PostgreSQL81Dialect extends Dialect {
|
|||
public boolean supportsJdbcConnectionLobCreation(DatabaseMetaData databaseMetaData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSelectAliasInGroupByClause() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -398,6 +398,24 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
protected abstract boolean isClassOrSuperclassTable(int j);
|
||||
|
||||
protected boolean isClassOrSuperclassJoin(int j) {
|
||||
/*
|
||||
* TODO:
|
||||
* SingleTableEntityPersister incorrectly used isClassOrSuperclassJoin == isClassOrSuperclassTable,
|
||||
* this caused HHH-12895, as this resulted in the subclass tables always being joined, even if no
|
||||
* property on these tables was accessed.
|
||||
*
|
||||
* JoinedTableEntityPersister does not use isClassOrSuperclassJoin at all, probably incorrectly so.
|
||||
* I however haven't been able to reproduce any quirks regarding <join>s, secondary tables or
|
||||
* @JoinTable's.
|
||||
*
|
||||
* Probably this method needs to be properly implemented for the various entity persisters,
|
||||
* but this at least fixes the SingleTableEntityPersister, while maintaining the the
|
||||
* previous behaviour for other persisters.
|
||||
*/
|
||||
return isClassOrSuperclassTable( j );
|
||||
}
|
||||
|
||||
public abstract int getSubclassTableSpan();
|
||||
|
||||
protected abstract int getTableSpan();
|
||||
|
@ -4281,7 +4299,7 @@ public abstract class AbstractEntityPersister
|
|||
Set<String> treatAsDeclarations,
|
||||
Set<String> referencedTables) {
|
||||
|
||||
if ( isClassOrSuperclassTable( subclassTableNumber ) ) {
|
||||
if ( isClassOrSuperclassJoin( subclassTableNumber ) ) {
|
||||
String superclassTableName = getSubclassTableName( subclassTableNumber );
|
||||
if ( referencedTables != null && canOmitSuperclassTableJoin() && !referencedTables.contains(
|
||||
superclassTableName ) ) {
|
||||
|
|
|
@ -91,6 +91,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
private final boolean[] subclassTableSequentialSelect;
|
||||
private final String[][] subclassTableKeyColumnClosure;
|
||||
private final boolean[] isClassOrSuperclassTable;
|
||||
private final boolean[] isClassOrSuperclassJoin;
|
||||
|
||||
// properties of this class, including inherited properties
|
||||
private final int[] propertyTableNumbers;
|
||||
|
@ -243,6 +244,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
ArrayList<String> subclassTables = new ArrayList<String>();
|
||||
ArrayList<String[]> joinKeyColumns = new ArrayList<String[]>();
|
||||
ArrayList<Boolean> isConcretes = new ArrayList<Boolean>();
|
||||
ArrayList<Boolean> isClassOrSuperclassJoins = new ArrayList<Boolean>();
|
||||
ArrayList<Boolean> isDeferreds = new ArrayList<Boolean>();
|
||||
ArrayList<Boolean> isInverses = new ArrayList<Boolean>();
|
||||
ArrayList<Boolean> isNullables = new ArrayList<Boolean>();
|
||||
|
@ -250,6 +252,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
subclassTables.add( qualifiedTableNames[0] );
|
||||
joinKeyColumns.add( getIdentifierColumnNames() );
|
||||
isConcretes.add( Boolean.TRUE );
|
||||
isClassOrSuperclassJoins.add( Boolean.TRUE );
|
||||
isDeferreds.add( Boolean.FALSE );
|
||||
isInverses.add( Boolean.FALSE );
|
||||
isNullables.add( Boolean.FALSE );
|
||||
|
@ -257,14 +260,15 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
joinIter = persistentClass.getSubclassJoinClosureIterator();
|
||||
while ( joinIter.hasNext() ) {
|
||||
Join join = (Join) joinIter.next();
|
||||
isConcretes.add( persistentClass.isClassOrSuperclassJoin( join ) );
|
||||
isDeferreds.add( join.isSequentialSelect() );
|
||||
isConcretes.add( persistentClass.isClassOrSuperclassTable( join.getTable() ) );
|
||||
isClassOrSuperclassJoins.add( persistentClass.isClassOrSuperclassJoin( join ) );
|
||||
isInverses.add( join.isInverse() );
|
||||
isNullables.add( join.isOptional() );
|
||||
isLazies.add( lazyAvailable && join.isLazy() );
|
||||
if ( join.isSequentialSelect() && !persistentClass.isClassOrSuperclassJoin( join ) ) {
|
||||
hasDeferred = true;
|
||||
}
|
||||
|
||||
boolean isDeferred = join.isSequentialSelect() && ! persistentClass.isClassOrSuperclassJoin( join ) ;
|
||||
isDeferreds.add( isDeferred );
|
||||
hasDeferred |= isDeferred;
|
||||
|
||||
String joinTableName = determineTableName( join.getTable(), jdbcEnvironment );
|
||||
subclassTables.add( joinTableName );
|
||||
|
@ -284,6 +288,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
subclassTableIsLazyClosure = ArrayHelper.toBooleanArray( isLazies );
|
||||
subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray( joinKeyColumns );
|
||||
isClassOrSuperclassTable = ArrayHelper.toBooleanArray( isConcretes );
|
||||
isClassOrSuperclassJoin = ArrayHelper.toBooleanArray( isClassOrSuperclassJoins );
|
||||
isInverseSubclassTable = ArrayHelper.toBooleanArray( isInverses );
|
||||
isNullableSubclassTable = ArrayHelper.toBooleanArray( isNullables );
|
||||
hasSequentialSelects = hasDeferred;
|
||||
|
@ -813,6 +818,10 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
return isClassOrSuperclassTable[j];
|
||||
}
|
||||
|
||||
protected boolean isClassOrSuperclassJoin(int j) {
|
||||
return isClassOrSuperclassJoin[j];
|
||||
}
|
||||
|
||||
protected boolean isSubclassTableLazy(int j) {
|
||||
return subclassTableIsLazyClosure[j];
|
||||
}
|
||||
|
@ -847,6 +856,11 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canOmitSuperclassTableJoin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isMultiTable() {
|
||||
return getTableSpan() > 1;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.jointable;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@Entity(name="House")
|
||||
public class Address {
|
||||
private Long id;
|
||||
private String street;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.jointable;
|
||||
|
||||
import org.hibernate.engine.query.spi.HQLQueryPlan;
|
||||
import org.hibernate.hql.spi.QueryTranslator;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class ManyToOneJoinTableTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Person.class,
|
||||
Address.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAvoidJoin() {
|
||||
final HQLQueryPlan plan = sessionFactory().getQueryPlanCache().getHQLQueryPlan(
|
||||
"SELECT e.id FROM Person e",
|
||||
false,
|
||||
Collections.EMPTY_MAP
|
||||
);
|
||||
assertEquals( 1, plan.getTranslators().length );
|
||||
final QueryTranslator translator = plan.getTranslators()[0];
|
||||
final String generatedSql = translator.getSQLString();
|
||||
// Ideally, we could detect that *ToOne join tables aren't used, but that requires tracking the uses of properties
|
||||
// Since *ToOne join tables are treated like secondary or subclass/superclass tables, the proper fix will allow many more optimizations
|
||||
assertFalse( generatedSql.contains( "join" ) );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.jointable;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@Entity
|
||||
public class Person {
|
||||
private Long id;
|
||||
private Address address;
|
||||
private Set<Address> addresses;
|
||||
|
||||
@Id
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@ManyToOne
|
||||
@JoinTable( name = "SOME_OTHER_TABLE" )
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(Address address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@OneToMany
|
||||
@JoinTable( name = "SOME_OTHER_TABLE2" )
|
||||
public Set<Address> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public void setAddresses(Set<Address> addresses) {
|
||||
this.addresses = addresses;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.query;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.testing.DialectChecks;
|
||||
import org.hibernate.testing.RequiresDialectFeature;
|
||||
import org.hibernate.testing.jdbc.SQLStatementInterceptor;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Tuple;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Jan-Willem Gmelig Meyling
|
||||
* @author Sayra Ranjha
|
||||
*/
|
||||
@RequiresDialectFeature(value = DialectChecks.SupportsSelectAliasInGroupByClause.class, jiraKey = "HHH-9301")
|
||||
public class GroupByAliasTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
public static final int MAX_COUNT = 15;
|
||||
|
||||
private SQLStatementInterceptor sqlStatementInterceptor;
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
sqlStatementInterceptor = new SQLStatementInterceptor( options );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Person.class,
|
||||
Association.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterEntityManagerFactoryBuilt() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
for ( int i = 0; i < MAX_COUNT; i++ ) {
|
||||
Association association = new Association();
|
||||
association.setId( i );
|
||||
association.setName(String.format( "Association nr %d", i ) );
|
||||
|
||||
Person person = new Person();
|
||||
person.setId( i );
|
||||
person.setName( String.format( "Person nr %d", i ) );
|
||||
person.setAssociation(association);
|
||||
person.setAge(5);
|
||||
entityManager.persist( person );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleIdAlias() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
List<Tuple> list = doInJPA(this::entityManagerFactory, entityManager -> {
|
||||
return entityManager.createQuery(
|
||||
"select p.id as id_alias, sum(p.age) " +
|
||||
"from Person p group by id_alias order by id_alias", Tuple.class)
|
||||
.getResultList();
|
||||
});
|
||||
|
||||
String s = sqlStatementInterceptor.getSqlQueries().get(0);
|
||||
assertNotNull(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompoundIdAlias() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
List<Tuple> list = doInJPA(this::entityManagerFactory, entityManager -> {
|
||||
return entityManager.createQuery(
|
||||
"select p.association as id_alias, sum(p.age) " +
|
||||
"from Person p group by id_alias order by id_alias", Tuple.class)
|
||||
.getResultList();
|
||||
});
|
||||
|
||||
String s = sqlStatementInterceptor.getSqlQueries().get(0);
|
||||
assertNotNull(s);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMultiIdAlias() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
List<Tuple> list = doInJPA(this::entityManagerFactory, entityManager -> {
|
||||
return entityManager.createQuery(
|
||||
"select p.id as id_alias_1, p.association as id_alias_2, sum(p.age) " +
|
||||
"from Person p group by id_alias_1, id_alias_2 order by id_alias_1, id_alias_2 ", Tuple.class)
|
||||
.getResultList();
|
||||
});
|
||||
|
||||
String s = sqlStatementInterceptor.getSqlQueries().get(0);
|
||||
assertNotNull(s);
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer age;
|
||||
|
||||
@ManyToOne(cascade = CascadeType.PERSIST)
|
||||
private Association association;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public Association getAssociation() {
|
||||
return association;
|
||||
}
|
||||
|
||||
public void setAssociation(Association association) {
|
||||
this.association = association;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@IdClass(Association.IdClass.class)
|
||||
@Entity(name = "Association")
|
||||
public static class Association {
|
||||
|
||||
public static class IdClass implements Serializable {
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
IdClass id1 = (IdClass) o;
|
||||
return Objects.equals(id, id1.id) &&
|
||||
Objects.equals(name, id1.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
@Id
|
||||
private String name;
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.query.hhh13670;
|
||||
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.junit.Before;
|
||||
|
@ -101,6 +100,74 @@ public class HHH13670Test extends BaseCoreFunctionalTestCase {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubTypePropertyReferencedFromEntityJoinInSyntheticSubquery() {
|
||||
doInJPA(this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery(
|
||||
"SELECT subB_0.id, subA_0.id, subB_0.id, subA_0.id FROM SubB subB_0 INNER JOIN SubA subA_0 ON 1=1 WHERE (EXISTS (SELECT 1 FROM subB_0.parent _synth_subquery_0 WHERE subA_0.id = _synth_subquery_0.id)) ORDER BY subB_0.id ASC, subA_0.id ASC", Tuple.class)
|
||||
.getResultList();
|
||||
|
||||
assertEquals(1, resultList.size());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubTypePropertyReferencedFromEntityJoinInSyntheticSubquery2() {
|
||||
doInJPA(this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery(
|
||||
"SELECT subB_0.id, subA_0.id, subB_0.id, subA_0.id FROM SubB subB_0 INNER JOIN SubA subA_0 ON 1=1 WHERE (EXISTS (SELECT 1 FROM Super s WHERE subA_0.id = s.parent.id)) ORDER BY subB_0.id ASC, subA_0.id ASC", Tuple.class)
|
||||
.getResultList();
|
||||
|
||||
assertEquals(4, resultList.size());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubTypePropertyReferencedFromEntityJoinInSyntheticSubquery3() {
|
||||
doInJPA(this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery(
|
||||
"SELECT subB_0.id, subA_0.id, subB_0.id, subA_0.id FROM SubB subB_0 INNER JOIN SubA subA_0 ON 1=1 WHERE (EXISTS (SELECT 1 FROM Super s WHERE s.id = subB_0.parent.id)) ORDER BY subB_0.id ASC, subA_0.id ASC", Tuple.class)
|
||||
.getResultList();
|
||||
|
||||
assertEquals(6, resultList.size());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubTypePropertyReferencedFromEntityJoinInSyntheticSubquery4() {
|
||||
doInJPA(this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery(
|
||||
"SELECT subB_0.id, subA_0.id, subB_0.id, subA_0.id FROM SubB subB_0 INNER JOIN SubA subA_0 ON 1=1 WHERE (EXISTS (SELECT 1 FROM Super s WHERE s.id = subA_0.parent.id)) ORDER BY subB_0.id ASC, subA_0.id ASC", Tuple.class)
|
||||
.getResultList();
|
||||
|
||||
assertEquals(0, resultList.size());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubTypePropertyReferencedFromWhereClause() {
|
||||
doInJPA(this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT subB_0.id FROM SubB subB_0 WHERE subB_0.parent.id IS NOT NULL", Tuple.class)
|
||||
.getResultList();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubTypePropertyReferencedFromGroupByClause() {
|
||||
doInJPA(this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT subB_0.id FROM SubB subB_0 GROUP BY subB_0.id , subB_0.parent.id", Tuple.class)
|
||||
.getResultList();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubTypePropertyReferencedFromOrderByClause() {
|
||||
doInJPA(this::sessionFactory, em -> {
|
||||
List<Tuple> resultList = em.createQuery("SELECT subB_0.id FROM SubB subB_0 ORDER BY subB_0.id , subB_0.parent.id", Tuple.class)
|
||||
.getResultList();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] { Super.class, SubA.class, SubB.class };
|
||||
|
|
|
@ -162,7 +162,32 @@ public class QueryHintTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
sqlStatementInterceptor.clear();
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-13608")
|
||||
public void testQueryHintCaseInsensitive() {
|
||||
sqlStatementInterceptor.clear();
|
||||
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
List results = s.createNativeQuery(
|
||||
"SELECT e.id as id " +
|
||||
"FROM Employee e " +
|
||||
"JOIN Department d ON e.department_id = d.id " +
|
||||
"WHERE d.name = :departmentName" )
|
||||
.addQueryHint( "ALL_ROWS" )
|
||||
.setComment( "My_Query" )
|
||||
.setParameter( "departmentName", "Sales" )
|
||||
.getResultList();
|
||||
|
||||
assertEquals(results.size(), 2);
|
||||
} );
|
||||
|
||||
sqlStatementInterceptor.assertExecutedCount( 1 );
|
||||
|
||||
assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).contains( "/* My_Query */ SELECT /*+ ALL_ROWS */" ) );
|
||||
sqlStatementInterceptor.clear();
|
||||
}
|
||||
|
||||
@Entity(name = "Employee")
|
||||
public static class Employee {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
@ -172,7 +197,7 @@ public class QueryHintTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
public Department department;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Entity(name = "Department")
|
||||
public static class Department {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
|
|
@ -266,6 +266,12 @@ abstract public class DialectChecks {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SupportsSelectAliasInGroupByClause implements DialectCheck {
|
||||
public boolean isMatch(Dialect dialect) {
|
||||
return dialect.supportsSelectAliasInGroupByClause();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SupportsNClob implements DialectCheck {
|
||||
@Override
|
||||
public boolean isMatch(Dialect dialect) {
|
||||
|
|
Loading…
Reference in New Issue