From d79d2d238c2b4a48860d9b374fcc744354d07cd2 Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Tue, 18 Jun 2013 13:05:56 -0400 Subject: [PATCH 01/14] HHH-8288 Upgrade to Javassist 3.18 --- libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries.gradle b/libraries.gradle index 7b49cb4c88..1c9f8ea666 100644 --- a/libraries.gradle +++ b/libraries.gradle @@ -51,7 +51,7 @@ ext { dom4j: 'dom4j:dom4j:1.6.1@jar', // Javassist - javassist: 'org.javassist:javassist:3.15.0-GA', + javassist: 'org.javassist:javassist:3.18.0-GA', // javax jpa: 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Draft-16', From e4eadbb9fe0a9ec62bcb88dbcb474cbbf6150a8d Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Tue, 18 Jun 2013 13:33:45 -0400 Subject: [PATCH 02/14] HHH-8318 test case --- .../test/annotations/query/Attrset.java | 37 ++++++++++++++ .../test/annotations/query/Attrvalue.java | 30 ++++++++++++ .../test/annotations/query/Employee.java | 44 +++++++++++++++++ .../test/annotations/query/Employeegroup.java | 49 +++++++++++++++++++ .../annotations/query/QueryAndSQLTest.java | 22 ++++++++- 5 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/query/Attrset.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/query/Attrvalue.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/query/Employee.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/query/Employeegroup.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Attrset.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Attrset.java new file mode 100644 index 0000000000..d3f9344eb0 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Attrset.java @@ -0,0 +1,37 @@ +package org.hibernate.test.annotations.query; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinTable; +import javax.persistence.OneToMany; + +@Entity +public class Attrset { + @Id + @GeneratedValue + private Long id; + + @OneToMany + @JoinTable(name = "ATTRSET_X_ATTRVALUE") + private Set attrvalues = new HashSet(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Set getAttrvalues() { + return attrvalues; + } + + public void setAttrvalues(Set attrvalues) { + this.attrvalues = attrvalues; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Attrvalue.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Attrvalue.java new file mode 100644 index 0000000000..2d0ef1a8ca --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Attrvalue.java @@ -0,0 +1,30 @@ +package org.hibernate.test.annotations.query; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Attrvalue { + @Id + @GeneratedValue + private Long id; + + private String value; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Employee.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Employee.java new file mode 100644 index 0000000000..acc69e841b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Employee.java @@ -0,0 +1,44 @@ +package org.hibernate.test.annotations.query; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +@Entity +public class Employee { + @Id + @GeneratedValue + private Long id; + + @ManyToOne + private Employeegroup employeegroup; + + @ManyToOne + private Attrset attrset; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Employeegroup getEmployeegroup() { + return employeegroup; + } + + public void setEmployeegroup(Employeegroup employeegroup) { + this.employeegroup = employeegroup; + } + + public Attrset getAttrset() { + return attrset; + } + + public void setAttrset(Attrset attrset) { + this.attrset = attrset; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Employeegroup.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Employeegroup.java new file mode 100644 index 0000000000..020b5021dd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/Employeegroup.java @@ -0,0 +1,49 @@ +package org.hibernate.test.annotations.query; + +import java.util.ArrayList; +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +@Entity +public class Employeegroup { + @Id + @GeneratedValue + private Long id; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "employeegroup") + private List employees = new ArrayList(); + + @ManyToOne + private Attrset attrset; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public List getEmployees() { + return employees; + } + + public void setEmployees(List employees) { + this.employees = employees; + } + + public Attrset getAttrset() { + return attrset; + } + + public void setAttrset(Attrset attrset) { + this.attrset = attrset; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java index 7e99db3e96..e0119657f9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java @@ -46,6 +46,7 @@ import org.hibernate.test.annotations.A320b; import org.hibernate.test.annotations.Plane; import org.hibernate.testing.FailureExpected; import org.hibernate.testing.SkipForDialect; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import static org.junit.Assert.assertEquals; @@ -451,6 +452,21 @@ public class QueryAndSQLTest extends BaseCoreFunctionalTestCase { tx.rollback(); s.close(); } + + @Test + @TestForIssue( jiraKey = "HHH-8318" ) + @FailureExpected( jiraKey = "HHH-8318" ) + public void testDeleteMemberOf() { + Session s = openSession(); + s.getTransaction().begin(); + s.createQuery( + "delete Attrvalue aval where aval.id in ( " + + "select val2.id from Employee e, Employeegroup eg, Attrset aset, Attrvalue val2 " + + "where eg.id = e.employeegroup.id " + "and aset.id = e.attrset.id " + + "and val2.id member of aset.attrvalues)" ).executeUpdate(); + s.getTransaction().commit(); + s.close(); + } @Override protected Class[] getAnnotatedClasses() { @@ -468,7 +484,11 @@ public class QueryAndSQLTest extends BaseCoreFunctionalTestCase { Captain.class, Chaos.class, CasimirParticle.class, - AllTables.class + AllTables.class, + Attrset.class, + Attrvalue.class, + Employee.class, + Employeegroup.class }; } From 2c1605904d666e38f477835fccc121b470953d36 Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Thu, 20 Jun 2013 12:00:24 -0400 Subject: [PATCH 03/14] HHH-8318 updated test case --- .../org/hibernate/test/annotations/query/QueryAndSQLTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java index e0119657f9..4662baa6ed 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java @@ -463,7 +463,7 @@ public class QueryAndSQLTest extends BaseCoreFunctionalTestCase { "delete Attrvalue aval where aval.id in ( " + "select val2.id from Employee e, Employeegroup eg, Attrset aset, Attrvalue val2 " + "where eg.id = e.employeegroup.id " + "and aset.id = e.attrset.id " - + "and val2.id member of aset.attrvalues)" ).executeUpdate(); + + "and val2 member of aset.attrvalues)" ).executeUpdate(); s.getTransaction().commit(); s.close(); } From 4ab3caa78937687c2c48b0903fc40d9274d0fa32 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 20 Jun 2013 22:05:38 -0500 Subject: [PATCH 04/14] HHH-8318 - Problem determining qualifier to use for column names from HQL query parser in certain circumstances --- .../hql/internal/ast/tree/DotNode.java | 40 +++++++--- .../internal/ast/tree/FromReferenceNode.java | 12 +++ .../hql/internal/ast/tree/IdentNode.java | 74 +++++++++++-------- .../hibernate/internal/util/StringHelper.java | 22 +++++- .../annotations/query/QueryAndSQLTest.java | 15 ---- .../test/hql/DeleteWhereMemberOfTest.java | 66 +++++++++++++++++ 6 files changed, 171 insertions(+), 58 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/hql/DeleteWhereMemberOfTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/DotNode.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/DotNode.java index c83370e8cd..90055d8540 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/DotNode.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/DotNode.java @@ -38,6 +38,7 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.entity.Queryable; import org.hibernate.sql.JoinFragment; import org.hibernate.sql.JoinType; import org.hibernate.type.CollectionType; @@ -282,19 +283,36 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec String propName = getPath(); FromClause currentFromClause = getWalker().getCurrentFromClause(); - if ( getWalker().getStatementType() != SqlTokenTypes.SELECT && indexed && classAlias == null ) { - // should indicate that we are processing an INSERT/UPDATE/DELETE - // query with a subquery implied via a collection property - // function. Here, we need to use the table name itself as the - // qualification alias. - // TODO : verify this works for all databases... - // TODO : is this also the case in non-"indexed" scenarios? - String alias = getLhs().getFromElement().getQueryable().getTableName(); - columns = getFromElement().toColumns( alias, propertyPath, false, true ); + // determine whether we should use the table name or table alias to qualify the column names... + // we need to use the table-name when: + // 1) the top-level statement is not a SELECT + // 2) the LHS FromElement is *the* FromElement from the top-level statement + // + // there is a caveat here.. if the update/delete statement are "multi-table" we should continue to use + // the alias also, even if the FromElement is the root one... + // + // in all other cases, we should use the table alias + final FromElement lhsFromElement = getLhs().getFromElement(); + if ( getWalker().getStatementType() != SqlTokenTypes.SELECT ) { + if ( isFromElementUpdateOrDeleteRoot( lhsFromElement ) ) { + // at this point we know we have the 2 conditions above, + // lets see if we have the mentioned "multi-table" caveat... + boolean useAlias = false; + if ( getWalker().getStatementType() != SqlTokenTypes.INSERT ) { + final Queryable persister = lhsFromElement.getQueryable(); + if ( persister.isMultiTable() ) { + useAlias = true; + } + } + if ( ! useAlias ) { + final String lhsTableName = lhsFromElement.getQueryable().getTableName(); + columns = getFromElement().toColumns( lhsTableName, propertyPath, false, true ); + } + } } - //We do not look for an existing join on the same path, because - //it makes sense to join twice on the same collection role + // We do not look for an existing join on the same path, because + // it makes sense to join twice on the same collection role FromElementFactory factory = new FromElementFactory( currentFromClause, getLhs().getFromElement(), diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromReferenceNode.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromReferenceNode.java index 8f1cdc663f..9658c4d65d 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromReferenceNode.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/FromReferenceNode.java @@ -27,6 +27,7 @@ import antlr.SemanticException; import antlr.collections.AST; import org.jboss.logging.Logger; +import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes; import org.hibernate.internal.CoreMessageLogger; /** @@ -130,4 +131,15 @@ public abstract class FromReferenceNode extends AbstractSelectExpression return null; } + @SuppressWarnings("SimplifiableIfStatement") + protected boolean isFromElementUpdateOrDeleteRoot(FromElement element) { + if ( element.getFromClause().getParentFromClause() != null ) { + // its not even a root... + return false; + } + + return getWalker().getStatementType() == HqlSqlTokenTypes.DELETE + || getWalker().getStatementType() == HqlSqlTokenTypes.UPDATE; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/IdentNode.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/IdentNode.java index ff79488f61..119838102b 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/IdentNode.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/IdentNode.java @@ -150,42 +150,54 @@ public class IdentNode extends FromReferenceNode implements SelectExpression { private boolean resolveAsAlias() { // This is not actually a constant, but a reference to FROM element. - FromElement element = getWalker().getCurrentFromClause().getFromElement( getText() ); - if ( element != null ) { - setType( SqlTokenTypes.ALIAS_REF ); - setFromElement( element ); - String[] columnExpressions = element.getIdentityColumns(); - final boolean isInNonDistinctCount = getWalker().isInCount() && ! getWalker().isInCountDistinct(); - final boolean isCompositeValue = columnExpressions.length > 1; - if ( isCompositeValue ) { - if ( isInNonDistinctCount && ! getWalker().getSessionFactoryHelper().getFactory().getDialect().supportsTupleCounts() ) { - setText( columnExpressions[0] ); - } - else { - String joinedFragment = StringHelper.join( ", ", columnExpressions ); - // avoid wrapping in parenthesis (explicit tuple treatment) if possible due to varied support for - // tuple syntax across databases.. - final boolean shouldSkipWrappingInParenthesis = - getWalker().isInCount() - || getWalker().getCurrentTopLevelClauseType() == HqlSqlTokenTypes.ORDER - || getWalker().getCurrentTopLevelClauseType() == HqlSqlTokenTypes.GROUP; - if ( ! shouldSkipWrappingInParenthesis ) { - joinedFragment = "(" + joinedFragment + ")"; - } - setText( joinedFragment ); - } - return true; - } - else if ( columnExpressions.length > 0 ) { - setText( columnExpressions[0] ); - return true; + final FromElement element = getWalker().getCurrentFromClause().getFromElement( getText() ); + if ( element == null ) { + return false; + } + + setType( SqlTokenTypes.ALIAS_REF ); + setFromElement( element ); + + String[] columnExpressions = element.getIdentityColumns(); + + // determine whether to apply qualification (table alias) to the column(s)... + if ( ! isFromElementUpdateOrDeleteRoot( element ) ) { + if ( StringHelper.isNotEmpty( element.getTableAlias() ) ) { + // apparently we also need to check that they are not already qualified. Ugh! + columnExpressions = StringHelper.qualifyIfNot( element.getTableAlias(), columnExpressions ); } } + + final boolean isInNonDistinctCount = getWalker().isInCount() && ! getWalker().isInCountDistinct(); + final boolean isCompositeValue = columnExpressions.length > 1; + if ( isCompositeValue ) { + if ( isInNonDistinctCount && ! getWalker().getSessionFactoryHelper().getFactory().getDialect().supportsTupleCounts() ) { + setText( columnExpressions[0] ); + } + else { + String joinedFragment = StringHelper.join( ", ", columnExpressions ); + // avoid wrapping in parenthesis (explicit tuple treatment) if possible due to varied support for + // tuple syntax across databases.. + final boolean shouldSkipWrappingInParenthesis = + getWalker().isInCount() + || getWalker().getCurrentTopLevelClauseType() == HqlSqlTokenTypes.ORDER + || getWalker().getCurrentTopLevelClauseType() == HqlSqlTokenTypes.GROUP; + if ( ! shouldSkipWrappingInParenthesis ) { + joinedFragment = "(" + joinedFragment + ")"; + } + setText( joinedFragment ); + } + return true; + } + else if ( columnExpressions.length > 0 ) { + setText( columnExpressions[0] ); + return true; + } + return false; } - private Type getNakedPropertyType(FromElement fromElement) - { + private Type getNakedPropertyType(FromElement fromElement) { if (fromElement == null) { return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java index bf5107a635..f5711ef8d6 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java @@ -460,7 +460,9 @@ public final class StringHelper { } public static String[] qualify(String prefix, String[] names) { - if ( prefix == null ) return names; + if ( prefix == null ) { + return names; + } int len = names.length; String[] qualified = new String[len]; for ( int i = 0; i < len; i++ ) { @@ -468,6 +470,24 @@ public final class StringHelper { } return qualified; } + + public static String[] qualifyIfNot(String prefix, String[] names) { + if ( prefix == null ) { + return names; + } + int len = names.length; + String[] qualified = new String[len]; + for ( int i = 0; i < len; i++ ) { + if ( names[i].indexOf( '.' ) < 0 ) { + qualified[i] = qualify( prefix, names[i] ); + } + else { + qualified[i] = names[i]; + } + } + return qualified; + } + public static int firstIndexOfChar(String sqlString, BitSet keys, int startindex) { for ( int i = startindex, size = sqlString.length(); i < size; i++ ) { if ( keys.get( sqlString.charAt( i ) ) ) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java index 4662baa6ed..7f358a4b12 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryAndSQLTest.java @@ -452,21 +452,6 @@ public class QueryAndSQLTest extends BaseCoreFunctionalTestCase { tx.rollback(); s.close(); } - - @Test - @TestForIssue( jiraKey = "HHH-8318" ) - @FailureExpected( jiraKey = "HHH-8318" ) - public void testDeleteMemberOf() { - Session s = openSession(); - s.getTransaction().begin(); - s.createQuery( - "delete Attrvalue aval where aval.id in ( " - + "select val2.id from Employee e, Employeegroup eg, Attrset aset, Attrvalue val2 " - + "where eg.id = e.employeegroup.id " + "and aset.id = e.attrset.id " - + "and val2 member of aset.attrvalues)" ).executeUpdate(); - s.getTransaction().commit(); - s.close(); - } @Override protected Class[] getAnnotatedClasses() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/DeleteWhereMemberOfTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/DeleteWhereMemberOfTest.java new file mode 100644 index 0000000000..a2c9aeabb7 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/DeleteWhereMemberOfTest.java @@ -0,0 +1,66 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2013, 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; + +import org.hibernate.Session; + +import org.junit.Test; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.test.annotations.query.Attrset; +import org.hibernate.test.annotations.query.Attrvalue; +import org.hibernate.test.annotations.query.Employee; +import org.hibernate.test.annotations.query.Employeegroup; + +/** + * @author Steve Ebersole + */ +public class DeleteWhereMemberOfTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Attrset.class, + Attrvalue.class, + Employee.class, + Employeegroup.class + }; + } + + @Test + @TestForIssue( jiraKey = "HHH-8318" ) +// @FailureExpected( jiraKey = "HHH-8318" ) + public void testDeleteMemberOf() { + final String qry = "delete Attrvalue aval where aval.id in ( " + + "select val2.id from Employee e, Employeegroup eg, Attrset aset, Attrvalue val2 " + + "where eg.id = e.employeegroup.id " + "and aset.id = e.attrset.id " + + "and val2 member of aset.attrvalues)"; + Session s = openSession(); + s.getTransaction().begin(); + s.createQuery( qry ).executeUpdate(); + s.getTransaction().commit(); + s.close(); + } +} From f1439b560142dd81d83c6142acb27956459e922f Mon Sep 17 00:00:00 2001 From: justinsubert Date: Fri, 21 Jun 2013 10:26:43 +0100 Subject: [PATCH 05/14] HHH-8319 --- .../org/hibernate/dialect/MySQL5Dialect.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java index 6065a7dada..fbef8ae0d5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java @@ -23,8 +23,13 @@ */ package org.hibernate.dialect; +import java.sql.SQLException; import java.sql.Types; +import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; +import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; +import org.hibernate.internal.util.JdbcExceptionHelper; + /** * An SQL dialect for MySQL 5.x specific features. * @@ -43,4 +48,27 @@ public class MySQL5Dialect extends MySQLDialect { public boolean supportsColumnCheck() { return false; } + + public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() { + return EXTRACTER; + } + + private static ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() { + + public String extractConstraintName(SQLException sqle) { + try { + int sqlState = Integer.valueOf( JdbcExceptionHelper.extractSqlState( sqle ) ).intValue(); + switch ( sqlState ) { + case 23000: + return extractUsingTemplate( " for key '", "'", sqle.getMessage() ); + default: + return null; + } + } + catch (NumberFormatException nfe) { + return null; + } + } + }; + } From c785c5e7a86b2671aab3be5e272cf4dad6abfeed Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Fri, 21 Jun 2013 10:51:42 -0400 Subject: [PATCH 06/14] HHH-8319 checkstyle --- .../java/org/hibernate/dialect/MySQL5Dialect.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java index fbef8ae0d5..f9802147f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQL5Dialect.java @@ -53,19 +53,19 @@ public class MySQL5Dialect extends MySQLDialect { return EXTRACTER; } - private static ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() { + private static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() { public String extractConstraintName(SQLException sqle) { try { - int sqlState = Integer.valueOf( JdbcExceptionHelper.extractSqlState( sqle ) ).intValue(); + final int sqlState = Integer.valueOf( JdbcExceptionHelper.extractSqlState( sqle ) ).intValue(); switch ( sqlState ) { - case 23000: - return extractUsingTemplate( " for key '", "'", sqle.getMessage() ); - default: - return null; + case 23000: + return extractUsingTemplate( " for key '", "'", sqle.getMessage() ); + default: + return null; } } - catch (NumberFormatException nfe) { + catch ( NumberFormatException nfe ) { return null; } } From edf1fa9fbcc8346b15459a7ed49915df1a3a048c Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Sun, 23 Jun 2013 13:17:05 -0400 Subject: [PATCH 07/14] HHH-8331 Create PostgreSQL9Dialect --- .../internal/StrategySelectorBuilder.java | 4 ++- .../hibernate/dialect/PostgreSQL9Dialect.java | 36 +++++++++++++++++++ .../StandardDatabaseInfoDialectResolver.java | 11 +++--- .../dialect/resolver/DialectFactoryTest.java | 14 ++++---- ...rdDatabaseMetaDataDialectResolverTest.java | 7 ++-- 5 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL9Dialect.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java index 2a9f1c56f7..57a16987ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java @@ -27,9 +27,9 @@ import java.util.ArrayList; import java.util.List; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl; import org.hibernate.boot.registry.selector.StrategyRegistration; import org.hibernate.boot.registry.selector.StrategyRegistrationProvider; -import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl; import org.hibernate.boot.registry.selector.spi.StrategySelectionException; import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.dialect.CUBRIDDialect; @@ -61,6 +61,7 @@ import org.hibernate.dialect.Oracle9iDialect; import org.hibernate.dialect.PointbaseDialect; import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.PostgreSQL82Dialect; +import org.hibernate.dialect.PostgreSQL9Dialect; import org.hibernate.dialect.PostgresPlusDialect; import org.hibernate.dialect.ProgressDialect; import org.hibernate.dialect.SAPDBDialect; @@ -219,6 +220,7 @@ public class StrategySelectorBuilder { addDialect( strategySelector, PostgresPlusDialect.class ); addDialect( strategySelector, PostgreSQL81Dialect.class ); addDialect( strategySelector, PostgreSQL82Dialect.class ); + addDialect( strategySelector, PostgreSQL9Dialect.class ); addDialect( strategySelector, ProgressDialect.class ); addDialect( strategySelector, SAPDBDialect.class ); addDialect( strategySelector, SQLServerDialect.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL9Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL9Dialect.java new file mode 100644 index 0000000000..d1908e96fb --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL9Dialect.java @@ -0,0 +1,36 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2010, 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.dialect; + +/** + * An SQL dialect for Postgres 9 and later. Adds support for "if exists" when dropping constraints + * + * @author edalquist + */ +public class PostgreSQL9Dialect extends PostgreSQL81Dialect { + @Override + public boolean supportsIfExistsBeforeConstraintName() { + return true; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseInfoDialectResolver.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseInfoDialectResolver.java index 6b70e520b3..60bf5c1e02 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseInfoDialectResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseInfoDialectResolver.java @@ -23,8 +23,6 @@ */ package org.hibernate.engine.jdbc.dialect.internal; -import org.jboss.logging.Logger; - import org.hibernate.dialect.CUBRIDDialect; import org.hibernate.dialect.DB2400Dialect; import org.hibernate.dialect.DB2Dialect; @@ -45,6 +43,7 @@ import org.hibernate.dialect.Oracle8iDialect; import org.hibernate.dialect.Oracle9iDialect; import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.PostgreSQL82Dialect; +import org.hibernate.dialect.PostgreSQL9Dialect; import org.hibernate.dialect.SQLServer2005Dialect; import org.hibernate.dialect.SQLServer2008Dialect; import org.hibernate.dialect.SQLServerDialect; @@ -52,6 +51,7 @@ import org.hibernate.dialect.SybaseASE15Dialect; import org.hibernate.dialect.SybaseAnywhereDialect; import org.hibernate.engine.jdbc.dialect.spi.DatabaseInfoDialectResolver; import org.hibernate.internal.CoreMessageLogger; +import org.jboss.logging.Logger; /** * The standard DatabaseInfoDialectResolver implementation @@ -93,10 +93,11 @@ public class StandardDatabaseInfoDialectResolver implements DatabaseInfoDialectR final int majorVersion = databaseInfo.getDatabaseMajorVersion(); final int minorVersion = databaseInfo.getDatabaseMinorVersion(); - if ( majorVersion > 8 || ( majorVersion == 8 && minorVersion >= 2 ) ) { - return new PostgreSQL82Dialect(); + if ( majorVersion == 8 ) { + return minorVersion >= 2 ? new PostgreSQL82Dialect() : new PostgreSQL81Dialect(); } - return new PostgreSQL81Dialect(); + + return new PostgreSQL9Dialect(); } if ( "Apache Derby".equals( databaseName ) ) { diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java b/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java index 71a937875e..4cab9a4017 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java @@ -23,6 +23,10 @@ */ package org.hibernate.dialect.resolver; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + import java.sql.Connection; import java.util.Collections; import java.util.HashMap; @@ -51,6 +55,7 @@ import org.hibernate.dialect.Oracle8iDialect; import org.hibernate.dialect.Oracle9iDialect; import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.PostgreSQL82Dialect; +import org.hibernate.dialect.PostgreSQL9Dialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.dialect.SybaseASE15Dialect; import org.hibernate.dialect.SybaseAnywhereDialect; @@ -60,16 +65,10 @@ import org.hibernate.engine.jdbc.dialect.internal.DialectResolverSet; import org.hibernate.engine.jdbc.dialect.internal.StandardDatabaseInfoDialectResolver; import org.hibernate.engine.jdbc.dialect.internal.StandardDatabaseMetaDataDialectResolver; import org.hibernate.engine.jdbc.dialect.spi.DialectResolver; - +import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.Before; import org.junit.Test; -import org.hibernate.testing.junit4.BaseUnitTestCase; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; - /** * @author Steve Ebersole */ @@ -148,6 +147,7 @@ public class DialectFactoryTest extends BaseUnitTestCase { testDetermination( "MySQL", MySQLDialect.class, resolver ); testDetermination( "PostgreSQL", PostgreSQL81Dialect.class, resolver ); testDetermination( "PostgreSQL", 8, 2, PostgreSQL82Dialect.class, resolver ); + testDetermination( "PostgreSQL", 9, 0, PostgreSQL9Dialect.class, resolver ); testDetermination( "Apache Derby", 10, 4, DerbyDialect.class, resolver ); testDetermination( "Apache Derby", 10, 5, DerbyTenFiveDialect.class, resolver ); testDetermination( "Apache Derby", 10, 6, DerbyTenSixDialect.class, resolver ); diff --git a/hibernate-core/src/test/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseMetaDataDialectResolverTest.java b/hibernate-core/src/test/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseMetaDataDialectResolverTest.java index 12f711da00..6d918518ab 100644 --- a/hibernate-core/src/test/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseMetaDataDialectResolverTest.java +++ b/hibernate-core/src/test/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseMetaDataDialectResolverTest.java @@ -35,6 +35,7 @@ import java.sql.SQLException; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.PostgreSQL82Dialect; +import org.hibernate.dialect.PostgreSQL9Dialect; import org.hibernate.dialect.SQLServer2005Dialect; import org.hibernate.dialect.SQLServer2008Dialect; import org.hibernate.dialect.SQLServerDialect; @@ -102,17 +103,17 @@ public class StandardDatabaseMetaDataDialectResolverTest extends BaseUnitTestCas @Test public void testResolveDialectInternalForPostgres9() throws SQLException { - runPostgresDialectTest( 9, 0, PostgreSQL82Dialect.class ); + runPostgresDialectTest( 9, 0, PostgreSQL9Dialect.class ); } @Test public void testResolveDialectInternalForPostgres91() throws SQLException { - runPostgresDialectTest( 9, 1, PostgreSQL82Dialect.class ); + runPostgresDialectTest( 9, 1, PostgreSQL9Dialect.class ); } @Test public void testResolveDialectInternalForPostgres92() throws SQLException { - runPostgresDialectTest( 9, 2, PostgreSQL82Dialect.class ); + runPostgresDialectTest( 9, 2, PostgreSQL9Dialect.class ); } private static void runSQLServerDialectTest( From 81affe3afe95129e835c00e7623da482cc326007 Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Sun, 23 Jun 2013 13:17:28 -0400 Subject: [PATCH 08/14] HHH-7002 added support for "if exists" on "drop constraint" --- .../java/org/hibernate/dialect/Dialect.java | 22 +++++++++++++++++++ .../java/org/hibernate/dialect/H2Dialect.java | 5 +++++ .../dialect/unique/DefaultUniqueDelegate.java | 14 +++++++++--- .../org/hibernate/mapping/ForeignKey.java | 15 +++++++++---- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index bd1e08cbbd..0d6bc2f5d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -2141,6 +2141,28 @@ public abstract class Dialect implements ConversionContext { return false; } + /** + * For dropping a constraint with an "alter table", can the phrase "if exists" be applied before the constraint name? + *

+ * NOTE : Only one or the other (or neither) of this and {@link #supportsIfExistsAfterConstraintName} should return true + * + * @return {@code true} if the "if exists" can be applied before the constraint name + */ + public boolean supportsIfExistsBeforeConstraintName() { + return false; + } + + /** + * For dropping a constraint with an "alter table", can the phrase "if exists" be applied after the constraint name? + *

+ * NOTE : Only one or the other (or neither) of this and {@link #supportsIfExistsBeforeConstraintName} should return true + * + * @return {@code true} if the "if exists" can be applied after the constraint name + */ + public boolean supportsIfExistsAfterConstraintName() { + return false; + } + /** * Generate a DROP TABLE statement * diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index e085a9ba18..15b1c4d6c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -255,6 +255,11 @@ public class H2Dialect extends Dialect { return true; } + @Override + public boolean supportsIfExistsAfterConstraintName() { + return true; + } + @Override public boolean supportsSequences() { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/unique/DefaultUniqueDelegate.java b/hibernate-core/src/main/java/org/hibernate/dialect/unique/DefaultUniqueDelegate.java index 4529760fd1..b65fa4e9bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/unique/DefaultUniqueDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/unique/DefaultUniqueDelegate.java @@ -94,9 +94,17 @@ public class DefaultUniqueDelegate implements UniqueDelegate { String defaultSchema) { // Do this here, rather than allowing UniqueKey/Constraint to do it. // We need full, simplified control over whether or not it happens. - final String tableName = uniqueKey.getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ); - final String constraintName = dialect.quote( uniqueKey.getName() ); - return "alter table " + tableName + " drop constraint " + constraintName; + final StringBuilder buf = new StringBuilder( "alter table " ); + buf.append( uniqueKey.getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ) ); + buf.append(" drop constraint " ); + if ( dialect.supportsIfExistsBeforeConstraintName() ) { + buf.append( "if exists " ); + } + buf.append( dialect.quote( uniqueKey.getName() ) ); + if ( dialect.supportsIfExistsAfterConstraintName() ) { + buf.append( " if exists" ); + } + return buf.toString(); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java index 02caf61783..a36cf87a9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java @@ -127,10 +127,17 @@ public class ForeignKey extends Constraint { } public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) { - return "alter table " + - getTable().getQualifiedName(dialect, defaultCatalog, defaultSchema) + - dialect.getDropForeignKeyString() + - getName(); + final StringBuilder buf = new StringBuilder( "alter table " ); + buf.append( getTable().getQualifiedName(dialect, defaultCatalog, defaultSchema) ); + buf.append( dialect.getDropForeignKeyString() ); + if ( dialect.supportsIfExistsBeforeConstraintName() ) { + buf.append( "if exists " ); + } + buf.append( getName() ); + if ( dialect.supportsIfExistsAfterConstraintName() ) { + buf.append( " if exists" ); + } + return buf.toString(); } public boolean isCascadeDeleteEnabled() { From b9185ac43bb9d6a8db7a8762bceaff884b720937 Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Sun, 23 Jun 2013 13:42:53 -0400 Subject: [PATCH 09/14] HHH-8331 keep postgres81 as the default --- .../internal/StandardDatabaseInfoDialectResolver.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseInfoDialectResolver.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseInfoDialectResolver.java index 60bf5c1e02..996fa571fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseInfoDialectResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/dialect/internal/StandardDatabaseInfoDialectResolver.java @@ -93,11 +93,15 @@ public class StandardDatabaseInfoDialectResolver implements DatabaseInfoDialectR final int majorVersion = databaseInfo.getDatabaseMajorVersion(); final int minorVersion = databaseInfo.getDatabaseMinorVersion(); - if ( majorVersion == 8 ) { - return minorVersion >= 2 ? new PostgreSQL82Dialect() : new PostgreSQL81Dialect(); + if ( majorVersion == 9 ) { + return new PostgreSQL9Dialect(); } - return new PostgreSQL9Dialect(); + if ( majorVersion == 8 && minorVersion >= 2 ) { + return new PostgreSQL82Dialect(); + } + + return new PostgreSQL81Dialect(); } if ( "Apache Derby".equals( databaseName ) ) { From 97304a291defe24977ae9b962b185d8958727531 Mon Sep 17 00:00:00 2001 From: Emmanuel Bernard Date: Thu, 27 Jun 2013 15:50:50 +0200 Subject: [PATCH 10/14] Add test for HHH-8314 --- .../hibernate/test/annotations/id/IdTest.java | 42 ++++++++++++++++++- .../test/annotations/id/entities/Hotel.java | 33 +++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/id/entities/Hotel.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/IdTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/IdTest.java index 04dce6c33c..34f2181615 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/IdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/IdTest.java @@ -23,6 +23,7 @@ */ package org.hibernate.test.annotations.id; +import org.hibernate.test.annotations.id.entities.Hotel; import org.junit.Test; import org.hibernate.Session; @@ -49,12 +50,51 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; /** * @author Emmanuel Bernard */ @SuppressWarnings("unchecked") public class IdTest extends BaseCoreFunctionalTestCase { + + @Test + public void testNoGenerator() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + Hotel hotel = new Hotel(); + hotel.setId( 12l ); + hotel.setName("California"); + s.saveOrUpdate(hotel); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + hotel = (Hotel) s.get(Hotel.class, 12l); + assertNotNull(hotel); + assertEquals("California", hotel.getName()); + assertNull(s.get(Hotel.class, 13l)); + tx.commit(); + + s = openSession(); + tx = s.beginTransaction(); + //hotel is now detached + hotel.setName("Hotel du nord"); + s.saveOrUpdate(hotel); + tx.commit(); + s.close(); + + s = openSession(); + tx = s.beginTransaction(); + hotel = (Hotel) s.get(Hotel.class, 12l); + assertNotNull(hotel); + assertEquals("Hotel du nord", hotel.getName()); + s.delete(hotel); + tx.commit(); + s.close(); + } + @Test public void testGenericGenerator() throws Exception { Session s = openSession(); @@ -318,7 +358,7 @@ public class IdTest extends BaseCoreFunctionalTestCase { Department.class, Dog.class, Computer.class, Home.class, Phone.class, Tree.class, FirTree.class, Footballer.class, SoundSystem.class, Furniture.class, GoalKeeper.class, - BreakDance.class, Monkey.class}; + BreakDance.class, Monkey.class, Hotel.class }; } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/entities/Hotel.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/entities/Hotel.java new file mode 100644 index 0000000000..ffb61941c6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/entities/Hotel.java @@ -0,0 +1,33 @@ +package org.hibernate.test.annotations.id.entities; + +import javax.persistence.Entity; +import javax.persistence.Id; + +/** + * Entity with assigned identity + * + * @author Emmanuel Bernard + */ +@Entity +public class Hotel { + @Id + private Long id; + + private String name; + + 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; + } +} From 4ee9ade3532406a2a74fcfa3e21a490a69f4011d Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Thu, 27 Jun 2013 22:48:48 -0400 Subject: [PATCH 11/14] HHH-8210 JdbcCoordinatorImpl logs excessive warnings with some connection pools --- .../engine/jdbc/internal/JdbcCoordinatorImpl.java | 8 ++++++-- .../java/org/hibernate/internal/CoreMessageLogger.java | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java index 4dc5bbd544..922e8b89d2 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java @@ -420,7 +420,9 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator { } } if ( statement != null ) { - if ( LOG.isEnabled( Level.WARN ) && !xref.containsKey( statement ) ) { + // Keep this at DEBUG level, rather than warn. Numerous connection pool implementations can return a + // proxy/wrapper around the JDBC Statement, causing excessive logging here. See HHH-8210. + if ( LOG.isEnabled( Level.DEBUG ) && !xref.containsKey( statement ) ) { LOG.unregisteredStatement(); } Set resultSets = xref.get( statement ); @@ -447,7 +449,9 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator { } } if ( statement != null ) { - if ( LOG.isEnabled( Level.WARN ) && !xref.containsKey( statement ) ) { + // Keep this at DEBUG level, rather than warn. Numerous connection pool implementations can return a + // proxy/wrapper around the JDBC Statement, causing excessive logging here. See HHH-8210. + if ( LOG.isEnabled( Level.DEBUG ) && !xref.containsKey( statement ) ) { LOG.unregisteredStatement(); } final Set resultSets = xref.get( statement ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index 20f6388fb2..f2026995c4 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1342,7 +1342,9 @@ public interface CoreMessageLogger extends BasicLogger { @Message(value = "ResultSet had no statement associated with it, but was not yet registered", id = 386) void unregisteredResultSetWithoutStatement(); - @LogMessage(level = WARN) + // Keep this at DEBUG level, rather than warn. Numerous connection pool implementations can return a + // proxy/wrapper around the JDBC Statement, causing excessive logging here. See HHH-8210. + @LogMessage(level = DEBUG) @Message(value = "ResultSet's statement was not registered", id = 387) void unregisteredStatement(); From 4ab29b481104e4136958a2e6b41e42af489255fc Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Sat, 29 Jun 2013 12:46:40 -0400 Subject: [PATCH 12/14] HHH-8335 Hibernate OSGi not included in build's /lib --- release/release.gradle | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/release/release.gradle b/release/release.gradle index 280d448965..6d58ce21a6 100644 --- a/release/release.gradle +++ b/release/release.gradle @@ -201,6 +201,17 @@ distributions { ) } + into( 'lib/osgi' ) { + from( + ( parent.project( 'hibernate-osgi' ).configurations.archives.allArtifacts.files.filter{ file -> !file.name.endsWith('-sources.jar') } + + parent.project( 'hibernate-osgi' ).configurations.runtime ) + - parent.project( 'hibernate-core' ).configurations.runtime + - parent.project( 'hibernate-core' ).configurations.archives.allArtifacts.files + - parent.project( 'hibernate-entitymanager' ).configurations.runtime + - parent.project( 'hibernate-entitymanager' ).configurations.archives.allArtifacts.files + ) + } + // todo : this closure is problematic as it does not write into the hibernate-release-$project.version directory // due to http://issues.gradle.org/browse/GRADLE-1450 [ 'hibernate-c3p0', 'hibernate-proxool', 'hibernate-ehcache', 'hibernate-infinispan' ].each { feature -> From 87004f9815eeffad635d00ed25eda7894cb26b6d Mon Sep 17 00:00:00 2001 From: Tommy Knowlton Date: Tue, 19 Jun 2012 22:11:19 -0600 Subject: [PATCH 13/14] HHH-7116 test case and fix --- .../java/org/hibernate/loader/JoinWalker.java | 2 +- .../java/org/hibernate/test/criteria/Bid.java | 20 ++++ .../test/criteria/CriteriaOrderByTest.java | 108 ++++++++++++++++++ .../org/hibernate/test/criteria/Item.java | 20 ++++ 4 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/criteria/Bid.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaOrderByTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/criteria/Item.java diff --git a/hibernate-core/src/main/java/org/hibernate/loader/JoinWalker.java b/hibernate-core/src/main/java/org/hibernate/loader/JoinWalker.java index affb387682..c05f4db8e8 100755 --- a/hibernate-core/src/main/java/org/hibernate/loader/JoinWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/JoinWalker.java @@ -847,7 +847,7 @@ public class JoinWalker { } protected String orderBy(final List associations, final String orderBy) { - return mergeOrderings( orderBy( associations ), orderBy ); + return mergeOrderings( orderBy, orderBy( associations ) ); } protected static String mergeOrderings(String ordering1, String ordering2) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/Bid.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/Bid.java new file mode 100644 index 0000000000..e6927fc279 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/Bid.java @@ -0,0 +1,20 @@ +package org.hibernate.test.criteria; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import java.io.Serializable; + +/** + * @author tknowlton at iamhisfriend dot org + * @since 5/21/12 12:45 AM + */ +@Entity +public class Bid implements Serializable { + @Id + float amount; + + @Id + @ManyToOne + Item item; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaOrderByTest.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaOrderByTest.java new file mode 100644 index 0000000000..265bde7f3a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaOrderByTest.java @@ -0,0 +1,108 @@ +package org.hibernate.test.criteria; + +import org.hibernate.Criteria; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.criterion.Projections; +import org.hibernate.sql.JoinType; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.transform.ResultTransformer; +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +/** + * @author tknowlton at iamhisfriend dot org + * @since 5/20/12 10:50 PM + */ +public class CriteriaOrderByTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[]{ + Bid.class, Item.class + }; + } + + @Test + @TestForIssue(jiraKey = "HHH-7116") + public void testCriteriaOrderBy() { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + + Item item; + Bid bid; + + item = new Item(); + item.name = "ZZZZ"; + s.persist(item); + + bid = new Bid(); + bid.amount = 444.44f; + bid.item = item; + s.persist(bid); + + item = new Item(); + item.name = "AAAA"; + s.persist(item); + + bid = new Bid(); + bid.amount = 222.22f; + bid.item = item; + s.persist(bid); + + item = new Item(); + item.name = "MMMM"; + s.persist(item); + + bid = new Bid(); + bid.amount = 999.99f; + bid.item = item; + s.persist(bid); + + s.flush(); + + // For each item, ordered by name, show all bids made by bidders on this item. + // The joined collections item.bids and bidder.bids have orderings specified on the mappings. + // For some reason, the association mappings' ordering specifications are not honored if default (INNER) join type is used. + Criteria criteria = s.createCriteria(Item.class) + .addOrder(org.hibernate.criterion.Order.asc("this.name")) + .createAlias("this.bids", "i_bid", JoinType.LEFT_OUTER_JOIN) + .setProjection(Projections.projectionList() + .add(Projections.property("this.name"), "item_name") + .add(Projections.property("i_bid.amount"), "bid_amount")) + .setResultTransformer(new ResultTransformer() { + boolean first = true; + Object[] previous; + + @Override + public Object transformTuple(Object[] tuple, String[] aliases) { + if (first) { + first = false; + previous = tuple; + } else { + String previousName = (String) previous[0]; + String name = (String) tuple[0]; + + Assert.assertTrue("The resultset tuples should be ordered by item name, as specified on the Criteria", previousName.compareTo(name) < 1); + + previous = tuple; + } + + return tuple; + } + + @Override + public List transformList(List collection) { + return collection; + } + }); + + List results = criteria.list(); + + tx.rollback(); + s.close(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/Item.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/Item.java new file mode 100644 index 0000000000..d38c8f5f3b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/Item.java @@ -0,0 +1,20 @@ +package org.hibernate.test.criteria; + +import javax.persistence.*; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +/** + * @author tknowlton at iamhisfriend dot org + * @since 5/21/12 12:38 AM + */ +@Entity +public class Item implements Serializable { + @Id + String name; + + @OneToMany(mappedBy = "item", fetch = FetchType.EAGER) + @OrderBy("amount desc") + Set bids = new HashSet(); +} From 17d9a2c1fc4c817a26d9ba08c65d10642b9722b0 Mon Sep 17 00:00:00 2001 From: Brett Meyer Date: Mon, 1 Jul 2013 14:03:51 -0400 Subject: [PATCH 14/14] HHH-7116 Moved orderBy fix to AbstractEntityJoinWalker. Copyrights, formatting, and checkstyle --- .../loader/AbstractEntityJoinWalker.java | 10 ++ .../java/org/hibernate/loader/JoinWalker.java | 2 +- .../java/org/hibernate/test/criteria/Bid.java | 11 +- .../test/criteria/CriteriaOrderByTest.java | 162 ++++++++++-------- .../org/hibernate/test/criteria/Item.java | 11 +- 5 files changed, 113 insertions(+), 83 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java b/hibernate-core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java index 673741e8fb..9d39122c46 100755 --- a/hibernate-core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/AbstractEntityJoinWalker.java @@ -205,6 +205,16 @@ public abstract class AbstractEntityJoinWalker extends JoinWalker { public final String getAlias() { return alias; } + + /** + * For entities, orderings added by, for example, Criteria#addOrder need to come before the associations' @OrderBy + * values. However, other sub-classes of JoinWalker (BasicCollectionJoinWalker, OneToManyJoinWalker, etc.) + * still need the other way around. So, override here instead. See HHH-7116. + */ + @Override + protected String orderBy(final List associations, final String orderBy) { + return mergeOrderings( orderBy, orderBy( associations ) ); + } public String toString() { return getClass().getName() + '(' + getPersister().getEntityName() + ')'; diff --git a/hibernate-core/src/main/java/org/hibernate/loader/JoinWalker.java b/hibernate-core/src/main/java/org/hibernate/loader/JoinWalker.java index c05f4db8e8..affb387682 100755 --- a/hibernate-core/src/main/java/org/hibernate/loader/JoinWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/JoinWalker.java @@ -847,7 +847,7 @@ public class JoinWalker { } protected String orderBy(final List associations, final String orderBy) { - return mergeOrderings( orderBy, orderBy( associations ) ); + return mergeOrderings( orderBy( associations ), orderBy ); } protected static String mergeOrderings(String ordering1, String ordering2) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/Bid.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/Bid.java index e6927fc279..334b80921e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/criteria/Bid.java +++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/Bid.java @@ -7,14 +7,13 @@ import java.io.Serializable; /** * @author tknowlton at iamhisfriend dot org - * @since 5/21/12 12:45 AM */ @Entity public class Bid implements Serializable { - @Id - float amount; + @Id + float amount; - @Id - @ManyToOne - Item item; + @Id + @ManyToOne + Item item; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaOrderByTest.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaOrderByTest.java index 265bde7f3a..6d69666c86 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaOrderByTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/CriteriaOrderByTest.java @@ -1,3 +1,23 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * JBoss, Home of Professional Open Source + * Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + * See the copyright.txt in the distribution for a + * full listing of individual contributors. + * + * 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, v. 2.1. + * This program is distributed in the hope that it will be useful, but WITHOUT A + * 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, + * v.2.1 along with this distribution; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ package org.hibernate.test.criteria; import org.hibernate.Criteria; @@ -15,94 +35,96 @@ import java.util.List; /** * @author tknowlton at iamhisfriend dot org - * @since 5/20/12 10:50 PM */ public class CriteriaOrderByTest extends BaseCoreFunctionalTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[]{ - Bid.class, Item.class - }; - } + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Bid.class, Item.class }; + } - @Test - @TestForIssue(jiraKey = "HHH-7116") - public void testCriteriaOrderBy() { - Session s = openSession(); - Transaction tx = s.beginTransaction(); + @Test + @TestForIssue(jiraKey = "HHH-7116") + public void testCriteriaOrderBy() { + final Session s = openSession(); + final Transaction tx = s.beginTransaction(); - Item item; - Bid bid; + Item item; + Bid bid; - item = new Item(); - item.name = "ZZZZ"; - s.persist(item); + item = new Item(); + item.name = "ZZZZ"; + s.persist( item ); - bid = new Bid(); - bid.amount = 444.44f; - bid.item = item; - s.persist(bid); + bid = new Bid(); + bid.amount = 444.44f; + bid.item = item; + s.persist( bid ); - item = new Item(); - item.name = "AAAA"; - s.persist(item); + item = new Item(); + item.name = "AAAA"; + s.persist( item ); - bid = new Bid(); - bid.amount = 222.22f; - bid.item = item; - s.persist(bid); + bid = new Bid(); + bid.amount = 222.22f; + bid.item = item; + s.persist( bid ); - item = new Item(); - item.name = "MMMM"; - s.persist(item); + item = new Item(); + item.name = "MMMM"; + s.persist( item ); - bid = new Bid(); - bid.amount = 999.99f; - bid.item = item; - s.persist(bid); + bid = new Bid(); + bid.amount = 999.99f; + bid.item = item; + s.persist( bid ); - s.flush(); + s.flush(); - // For each item, ordered by name, show all bids made by bidders on this item. - // The joined collections item.bids and bidder.bids have orderings specified on the mappings. - // For some reason, the association mappings' ordering specifications are not honored if default (INNER) join type is used. - Criteria criteria = s.createCriteria(Item.class) - .addOrder(org.hibernate.criterion.Order.asc("this.name")) - .createAlias("this.bids", "i_bid", JoinType.LEFT_OUTER_JOIN) - .setProjection(Projections.projectionList() - .add(Projections.property("this.name"), "item_name") - .add(Projections.property("i_bid.amount"), "bid_amount")) - .setResultTransformer(new ResultTransformer() { - boolean first = true; - Object[] previous; + // For each item, ordered by name, show all bids made by bidders on this item. + // The joined collections item.bids and bidder.bids have orderings specified on the mappings. + // For some reason, the association mappings' ordering specifications are not honored if default (INNER) join + // type is used. + final Criteria criteria = s + .createCriteria( Item.class ) + .addOrder( org.hibernate.criterion.Order.asc( "this.name" ) ) + .createAlias( "this.bids", "i_bid", JoinType.LEFT_OUTER_JOIN ) + .setProjection( + Projections.projectionList().add( Projections.property( "this.name" ), "item_name" ) + .add( Projections.property( "i_bid.amount" ), "bid_amount" ) ) + .setResultTransformer( new ResultTransformer() { + boolean first = true; + Object[] previous; - @Override - public Object transformTuple(Object[] tuple, String[] aliases) { - if (first) { - first = false; - previous = tuple; - } else { - String previousName = (String) previous[0]; - String name = (String) tuple[0]; + @Override + public Object transformTuple(Object[] tuple, String[] aliases) { + if ( first ) { + first = false; + previous = tuple; + } + else { + final String previousName = (String) previous[0]; + final String name = (String) tuple[0]; - Assert.assertTrue("The resultset tuples should be ordered by item name, as specified on the Criteria", previousName.compareTo(name) < 1); + Assert.assertTrue( + "The resultset tuples should be ordered by item name, as specified on the Criteria", + previousName.compareTo( name ) < 1 ); - previous = tuple; - } + previous = tuple; + } - return tuple; - } + return tuple; + } - @Override - public List transformList(List collection) { - return collection; - } - }); + @Override + public List transformList(List collection) { + return collection; + } + } ); - List results = criteria.list(); + criteria.list(); - tx.rollback(); - s.close(); - } + tx.rollback(); + s.close(); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/criteria/Item.java b/hibernate-core/src/test/java/org/hibernate/test/criteria/Item.java index d38c8f5f3b..c1187fd012 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/criteria/Item.java +++ b/hibernate-core/src/test/java/org/hibernate/test/criteria/Item.java @@ -7,14 +7,13 @@ import java.util.Set; /** * @author tknowlton at iamhisfriend dot org - * @since 5/21/12 12:38 AM */ @Entity public class Item implements Serializable { - @Id - String name; + @Id + String name; - @OneToMany(mappedBy = "item", fetch = FetchType.EAGER) - @OrderBy("amount desc") - Set bids = new HashSet(); + @OneToMany(mappedBy = "item", fetch = FetchType.EAGER) + @OrderBy("amount desc") + Set bids = new HashSet(); }