HHH-2304 Wrong type detection for sql type char(x) columns

This commit is contained in:
Strong Liu 2011-10-13 21:20:48 +08:00
parent 0aa3a7b608
commit bcae560079
9 changed files with 248 additions and 64 deletions

View File

@ -1181,8 +1181,12 @@ public final class HbmBinder {
Properties parameters = new Properties(); Properties parameters = new Properties();
Attribute typeNode = node.attribute( "type" ); Attribute typeNode = node.attribute( "type" );
if ( typeNode == null ) typeNode = node.attribute( "id-type" ); // for an any if ( typeNode == null ) {
if ( typeNode != null ) typeName = typeNode.getValue(); typeNode = node.attribute( "id-type" ); // for an any
}
else {
typeName = typeNode.getValue();
}
Element typeChild = node.element( "type" ); Element typeChild = node.element( "type" );
if ( typeName == null && typeChild != null ) { if ( typeName == null && typeChild != null ) {

View File

@ -179,6 +179,8 @@ public abstract class Dialect {
registerHibernateType( Types.BIT, StandardBasicTypes.BOOLEAN.getName() ); registerHibernateType( Types.BIT, StandardBasicTypes.BOOLEAN.getName() );
registerHibernateType( Types.BOOLEAN, StandardBasicTypes.BOOLEAN.getName() ); registerHibernateType( Types.BOOLEAN, StandardBasicTypes.BOOLEAN.getName() );
registerHibernateType( Types.CHAR, StandardBasicTypes.CHARACTER.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.DATE, StandardBasicTypes.DATE.getName() );
registerHibernateType( Types.DOUBLE, StandardBasicTypes.DOUBLE.getName() ); registerHibernateType( Types.DOUBLE, StandardBasicTypes.DOUBLE.getName() );
registerHibernateType( Types.FLOAT, StandardBasicTypes.FLOAT.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 { public String getTypeName(int code, long length, int precision, int scale) throws HibernateException {
String result = typeNames.get( code, length, precision, scale ); String result = typeNames.get( code, length, precision, scale );
if ( result == null ) { if ( result == null ) {
throw new HibernateException( throw new HibernateException(String.format( "No type mapping for java.sql.Types code: %s, length: %s", code, length ));
"No type mapping for java.sql.Types code: " +
code +
", length: " +
length
);
} }
return result; return result;
} }

View File

@ -26,6 +26,7 @@ package org.hibernate.dialect;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Types; import java.sql.Types;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter; import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
@ -183,8 +184,8 @@ public class H2Dialect extends Dialect {
registerFunction( "database", new NoArgSQLFunction( "database", StandardBasicTypes.STRING ) ); registerFunction( "database", new NoArgSQLFunction( "database", StandardBasicTypes.STRING ) );
registerFunction( "user", new NoArgSQLFunction( "user", StandardBasicTypes.STRING ) ); registerFunction( "user", new NoArgSQLFunction( "user", StandardBasicTypes.STRING ) );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE ); getDefaultProperties().setProperty( AvailableSettings.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.NON_CONTEXTUAL_LOB_CREATION, "true" ); // http://code.google.com/p/h2database/issues/detail?id=235
} }
public String getAddColumnString() { public String getAddColumnString() {

View File

@ -78,15 +78,15 @@ public class TypeNames {
/** /**
* get type name for specified type and size * get type name for specified type and size
* @param typecode the type key * @param typeCode the type key
* @param size the SQL length * @param size the SQL length
* @param scale the SQL scale * @param scale the SQL scale
* @param precision the SQL precision * @param precision the SQL precision
* @return the associated name with smallest capacity >= size, * @return the associated name with smallest capacity >= size,
* if available and the default type name otherwise * if available and the default type name otherwise
*/ */
public String get(int typecode, long size, int precision, int scale) throws MappingException { public String get(int typeCode, long size, int precision, int scale) throws MappingException {
Map<Long, String> map = weighted.get( typecode ); Map<Long, String> map = weighted.get( typeCode );
if ( map!=null && map.size()>0 ) { if ( map!=null && map.size()>0 ) {
// iterate entries ordered by capacity to find first fit // iterate entries ordered by capacity to find first fit
for (Map.Entry<Long, String> entry: map.entrySet()) { for (Map.Entry<Long, String> 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) { private static String replace(String type, long size, int precision, int scale) {

View File

@ -158,54 +158,15 @@ public class Column implements Selectable, Serializable, Cloneable {
this.typeIndex = typeIndex; 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() { public boolean isUnique() {
return unique; return unique;
} }
//used also for generation of FK names!
public String getSqlType(Dialect dialect, Mapping mapping) throws HibernateException { public int hashCode() {
return sqlType==null ? return isQuoted() ?
dialect.getTypeName( getSqlTypeCode(mapping), getLength(), getPrecision(), getScale() ) : name.hashCode() :
sqlType; name.toLowerCase().hashCode();
} }
public boolean equals(Object object) { public boolean equals(Object object) {
@ -221,12 +182,51 @@ public class Column implements Selectable, Serializable, Cloneable {
name.equalsIgnoreCase(column.name); name.equalsIgnoreCase(column.name);
} }
//used also for generation of FK names! public int getSqlTypeCode(Mapping mapping) throws MappingException {
public int hashCode() { org.hibernate.type.Type type = getValue().getType();
return isQuoted() ? try {
name.hashCode() : int sqlTypeCode = type.sqlTypes( mapping )[getTypeIndex()];
name.toLowerCase().hashCode(); 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() { public String getSqlType() {
return sqlType; return sqlType;

View File

@ -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; package org.hibernate.test.typedescriptor;
import org.junit.Assert; import org.junit.Assert;

View File

@ -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 );
}
}

View File

@ -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;
}
}

View File

@ -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; package org.hibernate.test.typedescriptor;
import java.io.Serializable; import java.io.Serializable;