From bcae5600790bb7329bdb308686208bd1413f932e Mon Sep 17 00:00:00 2001 From: Strong Liu Date: Thu, 13 Oct 2011 21:20:48 +0800 Subject: [PATCH] HHH-2304 Wrong type detection for sql type char(x) columns --- .../java/org/hibernate/cfg/HbmBinder.java | 8 +- .../java/org/hibernate/dialect/Dialect.java | 9 +- .../java/org/hibernate/dialect/H2Dialect.java | 5 +- .../java/org/hibernate/dialect/TypeNames.java | 8 +- .../java/org/hibernate/mapping/Column.java | 100 +++++++++--------- .../test/typedescriptor/ByteTest.java | 23 ++++ .../typedescriptor/CharInNativeQueryTest.java | 69 ++++++++++++ .../hibernate/test/typedescriptor/Issue.java | 67 ++++++++++++ .../typedescriptor/VariousTypesEntity.java | 23 ++++ 9 files changed, 248 insertions(+), 64 deletions(-) create mode 100644 hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/CharInNativeQueryTest.java create mode 100644 hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/Issue.java diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java index cd5b9801b8..40a68e6a3a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/HbmBinder.java @@ -1181,8 +1181,12 @@ public final class HbmBinder { Properties parameters = new Properties(); Attribute typeNode = node.attribute( "type" ); - if ( typeNode == null ) typeNode = node.attribute( "id-type" ); // for an any - if ( typeNode != null ) typeName = typeNode.getValue(); + if ( typeNode == null ) { + typeNode = node.attribute( "id-type" ); // for an any + } + else { + typeName = typeNode.getValue(); + } Element typeChild = node.element( "type" ); if ( typeName == null && typeChild != null ) { 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 db736fd1f2..042b4dd7ab 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -179,6 +179,8 @@ public abstract class Dialect { registerHibernateType( Types.BIT, StandardBasicTypes.BOOLEAN.getName() ); registerHibernateType( Types.BOOLEAN, StandardBasicTypes.BOOLEAN.getName() ); registerHibernateType( Types.CHAR, StandardBasicTypes.CHARACTER.getName() ); + registerHibernateType( Types.CHAR, 1, StandardBasicTypes.CHARACTER.getName() ); + registerHibernateType( Types.CHAR, 255, StandardBasicTypes.STRING.getName() ); registerHibernateType( Types.DATE, StandardBasicTypes.DATE.getName() ); registerHibernateType( Types.DOUBLE, StandardBasicTypes.DOUBLE.getName() ); registerHibernateType( Types.FLOAT, StandardBasicTypes.FLOAT.getName() ); @@ -289,12 +291,7 @@ public abstract class Dialect { public String getTypeName(int code, long length, int precision, int scale) throws HibernateException { String result = typeNames.get( code, length, precision, scale ); if ( result == null ) { - throw new HibernateException( - "No type mapping for java.sql.Types code: " + - code + - ", length: " + - length - ); + throw new HibernateException(String.format( "No type mapping for java.sql.Types code: %s, length: %s", code, length )); } return result; } 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 ba281ce6cf..2cbe8ab3bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -26,6 +26,7 @@ package org.hibernate.dialect; import java.sql.SQLException; import java.sql.Types; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; import org.hibernate.internal.CoreMessageLogger; @@ -183,8 +184,8 @@ public class H2Dialect extends Dialect { registerFunction( "database", new NoArgSQLFunction( "database", StandardBasicTypes.STRING ) ); registerFunction( "user", new NoArgSQLFunction( "user", StandardBasicTypes.STRING ) ); - getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE ); - getDefaultProperties().setProperty( Environment.NON_CONTEXTUAL_LOB_CREATION, "true" ); // http://code.google.com/p/h2database/issues/detail?id=235 + getDefaultProperties().setProperty( AvailableSettings.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE ); + getDefaultProperties().setProperty( AvailableSettings.NON_CONTEXTUAL_LOB_CREATION, "true" ); // http://code.google.com/p/h2database/issues/detail?id=235 } public String getAddColumnString() { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TypeNames.java b/hibernate-core/src/main/java/org/hibernate/dialect/TypeNames.java index 19fa52f999..d531370e3c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TypeNames.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/TypeNames.java @@ -78,15 +78,15 @@ public class TypeNames { /** * get type name for specified type and size - * @param typecode the type key + * @param typeCode the type key * @param size the SQL length * @param scale the SQL scale * @param precision the SQL precision * @return the associated name with smallest capacity >= size, * if available and the default type name otherwise */ - public String get(int typecode, long size, int precision, int scale) throws MappingException { - Map map = weighted.get( typecode ); + public String get(int typeCode, long size, int precision, int scale) throws MappingException { + Map map = weighted.get( typeCode ); if ( map!=null && map.size()>0 ) { // iterate entries ordered by capacity to find first fit for (Map.Entry entry: map.entrySet()) { @@ -95,7 +95,7 @@ public class TypeNames { } } } - return replace( get(typecode), size, precision, scale ); + return replace( get(typeCode), size, precision, scale ); } private static String replace(String type, long size, int precision, int scale) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java index 5241248423..b1dd367ebf 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java @@ -158,54 +158,15 @@ public class Column implements Selectable, Serializable, Cloneable { this.typeIndex = typeIndex; } - public int getSqlTypeCode(Mapping mapping) throws MappingException { - org.hibernate.type.Type type = getValue().getType(); - try { - int sqlTypeCode = type.sqlTypes(mapping)[ getTypeIndex() ]; - if(getSqlTypeCode()!=null && getSqlTypeCode().intValue()!=sqlTypeCode) { - throw new MappingException("SQLType code's does not match. mapped as " + sqlTypeCode + " but is " + getSqlTypeCode() ); - } - return sqlTypeCode; - } - catch (Exception e) { - throw new MappingException( - "Could not determine type for column " + - name + - " of type " + - type.getClass().getName() + - ": " + - e.getClass().getName(), - e - ); - } - } - - /** - * Returns the underlying columns sqltypecode. - * If null, it is because the sqltype code is unknown. - * - * Use #getSqlTypeCode(Mapping) to retreive the sqltypecode used - * for the columns associated Value/Type. - * - * @return sqltypecode if it is set, otherwise null. - */ - public Integer getSqlTypeCode() { - return sqlTypeCode; - } - - public void setSqlTypeCode(Integer typecode) { - sqlTypeCode=typecode; - } - public boolean isUnique() { return unique; } - - public String getSqlType(Dialect dialect, Mapping mapping) throws HibernateException { - return sqlType==null ? - dialect.getTypeName( getSqlTypeCode(mapping), getLength(), getPrecision(), getScale() ) : - sqlType; + //used also for generation of FK names! + public int hashCode() { + return isQuoted() ? + name.hashCode() : + name.toLowerCase().hashCode(); } public boolean equals(Object object) { @@ -221,12 +182,51 @@ public class Column implements Selectable, Serializable, Cloneable { name.equalsIgnoreCase(column.name); } - //used also for generation of FK names! - public int hashCode() { - return isQuoted() ? - name.hashCode() : - name.toLowerCase().hashCode(); - } + public int getSqlTypeCode(Mapping mapping) throws MappingException { + org.hibernate.type.Type type = getValue().getType(); + try { + int sqlTypeCode = type.sqlTypes( mapping )[getTypeIndex()]; + if ( getSqlTypeCode() != null && getSqlTypeCode() != sqlTypeCode ) { + throw new MappingException( "SQLType code's does not match. mapped as " + sqlTypeCode + " but is " + getSqlTypeCode() ); + } + return sqlTypeCode; + } + catch ( Exception e ) { + throw new MappingException( + "Could not determine type for column " + + name + + " of type " + + type.getClass().getName() + + ": " + + e.getClass().getName(), + e + ); + } + } + + /** + * Returns the underlying columns sqltypecode. + * If null, it is because the sqltype code is unknown. + * + * Use #getSqlTypeCode(Mapping) to retreive the sqltypecode used + * for the columns associated Value/Type. + * + * @return sqlTypeCode if it is set, otherwise null. + */ + public Integer getSqlTypeCode() { + return sqlTypeCode; + } + + public void setSqlTypeCode(Integer typeCode) { + sqlTypeCode=typeCode; + } + + public String getSqlType(Dialect dialect, Mapping mapping) throws HibernateException { + if ( sqlType == null ) { + sqlType = dialect.getTypeName( getSqlTypeCode( mapping ), getLength(), getPrecision(), getScale() ); + } + return sqlType; + } public String getSqlType() { return sqlType; diff --git a/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/ByteTest.java b/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/ByteTest.java index 5fcdf29829..b2a467b369 100644 --- a/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/ByteTest.java +++ b/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/ByteTest.java @@ -1,3 +1,26 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.typedescriptor; import org.junit.Assert; diff --git a/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/CharInNativeQueryTest.java b/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/CharInNativeQueryTest.java new file mode 100644 index 0000000000..fdc2397269 --- /dev/null +++ b/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/CharInNativeQueryTest.java @@ -0,0 +1,69 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.typedescriptor; + +import static org.junit.Assert.*; +import org.junit.Test; + +import org.hibernate.Session; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; + + /** + * @author Strong Liu + */ +public class CharInNativeQueryTest extends BaseCoreFunctionalTestCase { + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Issue.class + }; + } + @Test + @TestForIssue(jiraKey = "HHH-2304") + public void testNativeQuery() { + Issue issue = new Issue(); + issue.setIssueNumber( "HHH-2304" ); + issue.setDescription( "Wrong type detection for sql type char(x) columns" ); + + Session session = openSession(); + session.beginTransaction(); + session.persist( issue ); + session.getTransaction().commit(); + session.close(); + + session = openSession( ); + session.beginTransaction(); + Object issueNumber = session.createSQLQuery( "select issue.issueNumber from Issue issue" ).uniqueResult(); + session.getTransaction().commit(); + session.close(); + + assertNotNull( issueNumber ); + assertTrue( issueNumber instanceof String ); + assertEquals( "HHH-2304", issueNumber ); + + + } + + } \ No newline at end of file diff --git a/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/Issue.java b/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/Issue.java new file mode 100644 index 0000000000..2f162719f9 --- /dev/null +++ b/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/Issue.java @@ -0,0 +1,67 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.typedescriptor; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + + /** + * @author Strong Liu + */ +@Entity + public class Issue { + @Id + @GeneratedValue + private Long id; + private String description; + @Column(columnDefinition = "char(8)") + private String issueNumber; + + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getIssueNumber() { + return issueNumber; + } + + public void setIssueNumber(String issueNumber) { + this.issueNumber = issueNumber; + } + } \ No newline at end of file diff --git a/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/VariousTypesEntity.java b/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/VariousTypesEntity.java index 7a8e9d82cc..0586dca6d3 100644 --- a/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/VariousTypesEntity.java +++ b/hibernate-core/src/matrix/java/org/hibernate/test/typedescriptor/VariousTypesEntity.java @@ -1,3 +1,26 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.typedescriptor; import java.io.Serializable;