HHH-1657 - hql update generate wrong sql with joined subclass hierarcy
This commit is contained in:
parent
8f7b8e10d0
commit
23f49f19b5
|
@ -345,13 +345,20 @@ class FromElementType {
|
|||
LOG.debugf( "toColumns(%s,%s) : subquery = %s", tableAlias, path, subquery );
|
||||
return new String[]{"(" + subquery + ")"};
|
||||
}
|
||||
|
||||
if (forceAlias) {
|
||||
return propertyMapping.toColumns(tableAlias, path);
|
||||
} else if (fromElement.getWalker().getStatementType() == HqlSqlTokenTypes.SELECT) {
|
||||
}
|
||||
|
||||
if (fromElement.getWalker().getStatementType() == HqlSqlTokenTypes.SELECT) {
|
||||
return propertyMapping.toColumns(tableAlias, path);
|
||||
} else if (fromElement.getWalker().getCurrentClauseType() == HqlSqlTokenTypes.SELECT) {
|
||||
}
|
||||
|
||||
if (fromElement.getWalker().getCurrentClauseType() == HqlSqlTokenTypes.SELECT) {
|
||||
return propertyMapping.toColumns(tableAlias, path);
|
||||
} else if (fromElement.getWalker().isSubQuery()) {
|
||||
}
|
||||
|
||||
if (fromElement.getWalker().isSubQuery()) {
|
||||
// for a subquery, the alias to use depends on a few things (we
|
||||
// already know this is not an overall SELECT):
|
||||
// 1) if this FROM_ELEMENT represents a correlation to the
|
||||
|
@ -366,15 +373,24 @@ class FromElementType {
|
|||
// table name as the column qualification
|
||||
// 2) otherwise (not correlated), use the given alias
|
||||
if (isCorrelation()) {
|
||||
if (isMultiTable()) return propertyMapping.toColumns(tableAlias, path);
|
||||
if (isMultiTable()) {
|
||||
return propertyMapping.toColumns(tableAlias, path);
|
||||
}
|
||||
return propertyMapping.toColumns(extractTableName(), path);
|
||||
}
|
||||
return propertyMapping.toColumns(tableAlias, path);
|
||||
} else {
|
||||
String[] columns = propertyMapping.toColumns( path );
|
||||
LOG.tracev( "Using non-qualified column reference [{0} -> ({1})]", path, ArrayHelper.toString( columns ) );
|
||||
return columns;
|
||||
}
|
||||
|
||||
if ( isManipulationQuery() && isMultiTable() && inWhereClause() ) {
|
||||
// the actual where-clause will end up being ripped out the update/delete and used in
|
||||
// a select to populate the temp table, so its ok to use the table alias to qualify the table refs
|
||||
// and safer to do so to protect from same-named columns
|
||||
return propertyMapping.toColumns( tableAlias, path );
|
||||
}
|
||||
|
||||
String[] columns = propertyMapping.toColumns( path );
|
||||
LOG.tracev( "Using non-qualified column reference [{0} -> ({1})]", path, ArrayHelper.toString( columns ) );
|
||||
return columns;
|
||||
}
|
||||
|
||||
private boolean isCorrelation() {
|
||||
|
@ -394,12 +410,19 @@ class FromElementType {
|
|||
return fromElement.getQueryable().getTableName();
|
||||
}
|
||||
|
||||
private boolean isManipulationQuery() {
|
||||
return fromElement.getWalker().getStatementType() == HqlSqlTokenTypes.UPDATE
|
||||
|| fromElement.getWalker().getStatementType() == HqlSqlTokenTypes.DELETE;
|
||||
}
|
||||
|
||||
private boolean inWhereClause() {
|
||||
return fromElement.getWalker().getCurrentTopLevelClauseType() == HqlSqlTokenTypes.WHERE;
|
||||
}
|
||||
|
||||
private static final List SPECIAL_MANY2MANY_TREATMENT_FUNCTION_NAMES = java.util.Arrays.asList(
|
||||
new String[] {
|
||||
CollectionPropertyNames.COLLECTION_INDEX,
|
||||
CollectionPropertyNames.COLLECTION_MIN_INDEX,
|
||||
CollectionPropertyNames.COLLECTION_MAX_INDEX
|
||||
}
|
||||
CollectionPropertyNames.COLLECTION_INDEX,
|
||||
CollectionPropertyNames.COLLECTION_MIN_INDEX,
|
||||
CollectionPropertyNames.COLLECTION_MAX_INDEX
|
||||
);
|
||||
|
||||
PropertyMapping getPropertyMapping(String propertyName) {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.hql.joinedSubclass;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity
|
||||
public class Employee extends Person {
|
||||
private String employeeNumber;
|
||||
|
||||
public Employee() {
|
||||
}
|
||||
|
||||
public Employee(String name) {
|
||||
super( name );
|
||||
}
|
||||
|
||||
public Employee(String name, String employeeNumber) {
|
||||
super( name );
|
||||
this.employeeNumber = employeeNumber;
|
||||
}
|
||||
|
||||
public String getEmployeeNumber() {
|
||||
return employeeNumber;
|
||||
}
|
||||
|
||||
public void setEmployeeNumber(String employeeNumber) {
|
||||
this.employeeNumber = employeeNumber;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.hql.joinedSubclass;
|
||||
|
||||
import org.hibernate.Session;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JoinedSubclassBulkManipTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Employee.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-1657" )
|
||||
public void testHqlDeleteOnJoinedSubclass() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
// syntax checking on the database...
|
||||
s.createQuery( "delete from Employee" ).executeUpdate();
|
||||
s.createQuery( "delete from Person" ).executeUpdate();
|
||||
s.createQuery( "delete from Employee e" ).executeUpdate();
|
||||
s.createQuery( "delete from Person p" ).executeUpdate();
|
||||
s.createQuery( "delete from Employee where name like 'S%'" ).executeUpdate();
|
||||
s.createQuery( "delete from Employee e where e.name like 'S%'" ).executeUpdate();
|
||||
s.createQuery( "delete from Person where name like 'S%'" ).executeUpdate();
|
||||
s.createQuery( "delete from Person p where p.name like 'S%'" ).executeUpdate();
|
||||
|
||||
// now the forms that actually fail from problem underlying HHH-1657
|
||||
// which is limited to references to properties mapped to column names existing in both tables
|
||||
// which is normally just the pks. super critical ;)
|
||||
|
||||
s.createQuery( "delete from Employee where id = 1" ).executeUpdate();
|
||||
s.createQuery( "delete from Employee e where e.id = 1" ).executeUpdate();
|
||||
s.createQuery( "delete from Person where id = 1" ).executeUpdate();
|
||||
s.createQuery( "delete from Person p where p.id = 1" ).executeUpdate();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-1657" )
|
||||
public void testHqlUpdateOnJoinedSubclass() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
// syntax checking on the database...
|
||||
s.createQuery( "update Employee set name = 'Some Other Name' where employeeNumber like 'A%'" ).executeUpdate();
|
||||
s.createQuery( "update Employee e set e.name = 'Some Other Name' where e.employeeNumber like 'A%'" ).executeUpdate();
|
||||
s.createQuery( "update Person set name = 'Some Other Name' where name like 'S%'" ).executeUpdate();
|
||||
s.createQuery( "update Person p set p.name = 'Some Other Name' where p.name like 'S%'" ).executeUpdate();
|
||||
|
||||
// now the forms that actually fail from problem underlying HHH-1657
|
||||
// which is limited to references to properties mapped to column names existing in both tables
|
||||
// which is normally just the pks. super critical ;)
|
||||
|
||||
s.createQuery( "update Employee set name = 'Some Other Name' where id = 1" ).executeUpdate();
|
||||
s.createQuery( "update Employee e set e.name = 'Some Other Name' where e.id = 1" ).executeUpdate();
|
||||
s.createQuery( "update Person set name = 'Some Other Name' where id = 1" ).executeUpdate();
|
||||
s.createQuery( "update Person p set p.name = 'Some Other Name' where p.id = 1" ).executeUpdate();
|
||||
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.hql.joinedSubclass;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity
|
||||
@Inheritance( strategy = InheritanceType.JOINED )
|
||||
public class Person {
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public Person(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue( generator = "increment" )
|
||||
@GenericGenerator( strategy = "increment", name = "increment" )
|
||||
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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue