HHH-11230 - Aggregate on (mappedBy) joined column produces invalid query

This commit is contained in:
Christian Beikov 2016-11-08 09:20:31 +01:00 committed by Vlad Mihalcea
parent 36d6563998
commit 080d65de99
3 changed files with 163 additions and 4 deletions

View File

@ -207,9 +207,12 @@ public class JoinSequence {
subqueryJoinFragment.addFromFragmentString( ".*" );
// Re-alias columns of withClauseJoinAlias and rewrite withClauseFragment
// A list of possible delimited identifier types: https://en.wikibooks.org/wiki/SQL_Dialects_Reference/Data_structure_definition/Delimited_identifiers
Pattern p = Pattern.compile( Pattern.quote( withClauseJoinAlias + "." ) + "(" +
"([a-zA-Z0-9_]+)|" + // Normal identifiers
"('[a-zA-Z0-9_]+' ((''[a-zA-Z0-9_]+)+')?) | " + // Single quoted identifiers
// Ignore single quoted identifiers to avoid possible clashes with string literals
// and since SQLLite is the only DB supporting that style, we simply decide to not support it
//"('[a-zA-Z0-9_]+'((''[a-zA-Z0-9_]+)+')?)|" + // Single quoted identifiers
"(\"[a-zA-Z0-9_]+\"((\"\"[a-zA-Z0-9_]+)+\")?)|" + // Double quoted identifiers
"(`[a-zA-Z0-9_]+`((``[a-zA-Z0-9_]+)+`)?)|" + // MySQL quoted identifiers
"(\\[[a-zA-Z0-9_\\s]+\\])" + // MSSQL quoted identifiers

View File

@ -0,0 +1,136 @@
/*
* 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.test.hql;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToMany;
import javax.persistence.MappedSuperclass;
import javax.persistence.Table;
import javax.persistence.Version;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Implementation of WithClauseTest.
*
* @author Steve Ebersole
*/
public class WithClauseJoinRewriteTest extends BaseCoreFunctionalTestCase {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[]{
AbstractObject.class,
AbstractConfigurationObject.class,
ConfigurationObject.class
};
}
@Test
@TestForIssue(jiraKey = "HHH-11230")
public void testInheritanceReAliasing() {
Session s = openSession();
Transaction tx = s.beginTransaction();
// Just assert that the query is successful
List<Object[]> results = s.createQuery(
"SELECT usedBy.id, usedBy.name, COUNT(inverse.id) " +
"FROM " + AbstractConfigurationObject.class.getName() + " config " +
"INNER JOIN config.usedBy usedBy " +
"LEFT JOIN usedBy.uses inverse ON inverse.id = config.id " +
"WHERE config.id = 0 " +
"GROUP BY usedBy.id, usedBy.name",
Object[].class
).getResultList();
tx.commit();
s.close();
}
@Entity
@Table( name = "config" )
@Inheritance( strategy = InheritanceType.JOINED )
public static abstract class AbstractConfigurationObject<T extends ConfigurationObject> extends AbstractObject {
private String name;
private Set<ConfigurationObject> uses = new HashSet<>();
private Set<ConfigurationObject> usedBy = new HashSet<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToMany( targetEntity = AbstractConfigurationObject.class, fetch = FetchType.LAZY, cascade = {} )
public Set<ConfigurationObject> getUses () {
return uses;
}
public void setUses(Set<ConfigurationObject> uses) {
this.uses = uses;
}
@ManyToMany ( targetEntity = AbstractConfigurationObject.class, fetch = FetchType.LAZY, mappedBy = "uses", cascade = {} )
public Set<ConfigurationObject> getUsedBy () {
return usedBy;
}
public void setUsedBy(Set<ConfigurationObject> usedBy) {
this.usedBy = usedBy;
}
}
@Entity
@Table( name = "config_config" )
public static class ConfigurationObject extends AbstractConfigurationObject<ConfigurationObject> {
}
@MappedSuperclass
public static class AbstractObject {
private Long id;
private Long version;
@Id
@GeneratedValue
public Long getId () {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Version
@Column( nullable = false )
public Long getVersion () {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
}
}

View File

@ -201,6 +201,26 @@ public class WithClauseTest extends BaseCoreFunctionalTestCase {
data.cleanup();
}
@Test
@TestForIssue(jiraKey = "HHH-11230")
public void testWithClauseAsSubqueryWithEqualOperator() {
TestData data = new TestData();
data.prepare();
Session s = openSession();
Transaction txn = s.beginTransaction();
// Like testWithClauseAsSubquery but uses equal operator since it render differently in SQL
List list = s.createQuery( "from Human h left join h.friends as f with f.nickName = 'bubba' where h.description = 'father'" )
.list();
assertEquals( "subquery rewriting of join table did not take effect", 1, list.size() );
txn.commit();
s.close();
data.cleanup();
}
@Test
@TestForIssue(jiraKey = "HHH-9329")
public void testWithClauseAsSubqueryWithKey() {