HHH-6828 Taking case sensitivity into account when accessing the database metadata

Also extending the test and formatting the code.
This commit is contained in:
Hardy Ferentschik 2011-11-17 17:51:30 +01:00
parent 6b2972884a
commit 8bf9791254
3 changed files with 116 additions and 61 deletions

View File

@ -24,8 +24,10 @@
package org.hibernate.test.annotations.dataTypes; package org.hibernate.test.annotations.dataTypes;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date; import java.util.Date;
import org.junit.Test; import org.junit.Test;
@ -43,8 +45,12 @@ import static org.junit.Assert.assertTrue;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@RequiresDialectFeature( DialectChecks.SupportsExpectedLobUsagePattern.class ) @RequiresDialectFeature(DialectChecks.SupportsExpectedLobUsagePattern.class)
public class BasicOperationsTest extends BaseCoreFunctionalTestCase { public class BasicOperationsTest extends BaseCoreFunctionalTestCase {
private static final String SOME_ENTITY_TABLE_NAME = "SOMEENTITY";
private static final String SOME_OTHER_ENTITY_TABLE_NAME = "SOMEOTHERENTITY";
@Override @Override
protected Class<?>[] getAnnotatedClasses() { protected Class<?>[] getAnnotatedClasses() {
return new Class[] { SomeEntity.class, SomeOtherEntity.class }; return new Class[] { SomeEntity.class, SomeOtherEntity.class };
@ -55,43 +61,95 @@ public class BasicOperationsTest extends BaseCoreFunctionalTestCase {
Date now = new Date(); Date now = new Date();
Session s = openSession(); Session s = openSession();
s.doWork(
new Work() {
public void execute(Connection connection) throws SQLException {
// id -> java.util.Date (DATE - becase of explicit TemporalType)
validateColumn( connection, "ID", java.sql.Types.DATE );
// timeData -> java.sql.Time (TIME) s.doWork( new ValidateSomeEntityColumns() );
validateColumn( connection, "TIMEDATA", java.sql.Types.TIME ); s.doWork( new ValidateRowCount( SOME_ENTITY_TABLE_NAME, 0 ) );
s.doWork( new ValidateRowCount( SOME_OTHER_ENTITY_TABLE_NAME, 0 ) );
// tsData -> java.sql.Timestamp (TIMESTAMP)
validateColumn( connection, "TSDATA", java.sql.Types.TIMESTAMP );
}
private void validateColumn(Connection connection, String columnName, int expectedJdbcTypeCode)
throws SQLException {
ResultSet columnInfo = connection.getMetaData().getColumns( null, null, "SOMEENTITY", columnName );
assertTrue( columnInfo.next() );
int dataType = columnInfo.getInt( "DATA_TYPE" );
columnInfo.close();
assertEquals( columnName, JdbcTypeNameMapper.getTypeName(expectedJdbcTypeCode), JdbcTypeNameMapper.getTypeName(dataType) );
}
}
);
s.beginTransaction(); s.beginTransaction();
SomeEntity someEntity = new SomeEntity( now ); SomeEntity someEntity = new SomeEntity( now );
SomeOtherEntity someOtherEntity = new SomeOtherEntity(1); SomeOtherEntity someOtherEntity = new SomeOtherEntity( 1 );
s.save( someEntity ); s.save( someEntity );
s.save( someOtherEntity ); s.save( someOtherEntity );
s.getTransaction().commit(); s.getTransaction().commit();
s.close(); s.close();
s = openSession(); s = openSession();
s.doWork( new ValidateRowCount( SOME_ENTITY_TABLE_NAME, 1 ) );
s.doWork( new ValidateRowCount( SOME_OTHER_ENTITY_TABLE_NAME, 1 ) );
s.beginTransaction(); s.beginTransaction();
s.delete( someEntity ); s.delete( someEntity );
s.delete( someOtherEntity ); s.delete( someOtherEntity );
s.getTransaction().commit(); s.getTransaction().commit();
s.doWork( new ValidateRowCount( SOME_ENTITY_TABLE_NAME, 0 ) );
s.doWork( new ValidateRowCount( SOME_OTHER_ENTITY_TABLE_NAME, 0 ) );
s.close(); s.close();
} }
// verify all the expected columns are created
class ValidateSomeEntityColumns implements Work {
public void execute(Connection connection) throws SQLException {
// id -> java.util.Date (DATE - becase of explicit TemporalType)
validateColumn( connection, "ID", java.sql.Types.DATE );
// timeData -> java.sql.Time (TIME)
validateColumn( connection, "TIMEDATA", java.sql.Types.TIME );
// tsData -> java.sql.Timestamp (TIMESTAMP)
validateColumn( connection, "TSDATA", java.sql.Types.TIMESTAMP );
}
private void validateColumn(Connection connection, String columnName, int expectedJdbcTypeCode)
throws SQLException {
DatabaseMetaData meta = connection.getMetaData();
// DBs treat the meta information differently, in particular case sensitivity.
// We need to use the meta information to find out how to treat names
String tableNamePattern = generateFinalNamePattern( meta, SOME_ENTITY_TABLE_NAME );
String columnNamePattern = generateFinalNamePattern( meta, columnName );
ResultSet columnInfo = meta.getColumns( null, null, tableNamePattern, columnNamePattern );
assertTrue( columnInfo.next() );
int dataType = columnInfo.getInt( "DATA_TYPE" );
columnInfo.close();
assertEquals(
columnName,
JdbcTypeNameMapper.getTypeName( expectedJdbcTypeCode ),
JdbcTypeNameMapper.getTypeName( dataType )
);
}
private String generateFinalNamePattern(DatabaseMetaData meta, String name) throws SQLException {
if ( meta.storesLowerCaseIdentifiers() ) {
return name.toLowerCase();
}
else {
return name;
}
}
}
// verify we have the right amount of columns
class ValidateRowCount implements Work {
private final int expectedRowCount;
private final String table;
public ValidateRowCount(String table, int count) {
this.expectedRowCount = count;
this.table = table;
}
public void execute(Connection connection) throws SQLException {
Statement st = connection.createStatement();
ResultSet result = st.executeQuery( "SELECT COUNT(*) FROM " + table );
result.next();
int rowCount = result.getInt( 1 );
assertEquals( "Unexpected row count", expectedRowCount, rowCount );
}
}
} }

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.test.annotations.dataTypes; package org.hibernate.test.annotations.dataTypes;
import java.util.Date; import java.util.Date;
import javax.persistence.Access; import javax.persistence.Access;
import javax.persistence.AccessType; import javax.persistence.AccessType;
@ -34,8 +35,6 @@ import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
/** /**
* TODO : javadoc
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@Entity @Entity
@ -44,11 +43,11 @@ import javax.persistence.TemporalType;
public class SomeEntity { public class SomeEntity {
@Id @Id
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
@Column(name = "ID") @Column(name = "ID")
private java.util.Date id; private java.util.Date id;
@Column(name = "TIMEDATA") @Column(name = "TIMEDATA")
private java.sql.Time timeData; private java.sql.Time timeData;
@Column(name = "TSDATA") @Column(name = "TSDATA")
private java.sql.Timestamp tsData; private java.sql.Timestamp tsData;
@Lob @Lob
private Byte[] byteData; private Byte[] byteData;
@ -100,5 +99,4 @@ public class SomeEntity {
public void setByteData(Byte[] byteData) { public void setByteData(Byte[] byteData) {
this.byteData = byteData; this.byteData = byteData;
} }
} }

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.test.annotations.dataTypes; package org.hibernate.test.annotations.dataTypes;
import javax.persistence.Access; import javax.persistence.Access;
import javax.persistence.AccessType; import javax.persistence.AccessType;
import javax.persistence.Entity; import javax.persistence.Entity;
@ -30,37 +31,36 @@ import javax.persistence.Enumerated;
import javax.persistence.Id; import javax.persistence.Id;
/** /**
* TODO : javadoc
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@Entity @Entity
@Access(AccessType.FIELD) @Access(AccessType.FIELD)
public class SomeOtherEntity { public class SomeOtherEntity {
@Id @Id
protected int id; protected int id;
protected boolean booleanData; protected boolean booleanData;
protected byte byteData; protected byte byteData;
protected char characterData; // setting a arbitrary character here to make this test also pass against PostgreSQL
protected short shortData; // PostgreSQL throws otherwise an exception when persisting the null value
protected int integerData; // org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00
protected long longData; protected char characterData = 'a';
protected double doubleData; protected short shortData;
protected float floatData; protected int integerData;
@Enumerated(EnumType.STRING) protected long longData;
protected Grade grade; protected double doubleData;
protected float floatData;
@Enumerated(EnumType.STRING)
protected Grade grade;
public SomeOtherEntity() public SomeOtherEntity() {
{ }
}
public SomeOtherEntity(int id) public SomeOtherEntity(int id) {
{ this.id = id;
this.id = id; }
}
public SomeOtherEntity( public SomeOtherEntity(
int id, int id,
boolean booleanData, boolean booleanData,
byte byteData, byte byteData,
@ -71,15 +71,15 @@ public class SomeOtherEntity {
double doubleData, double doubleData,
float floatData) { float floatData) {
this.id = id; this.id = id;
this.booleanData = booleanData; this.booleanData = booleanData;
this.byteData = byteData; this.byteData = byteData;
this.characterData = characterData; this.characterData = characterData;
this.shortData = shortData; this.shortData = shortData;
this.integerData = integerData; this.integerData = integerData;
this.longData = longData; this.longData = longData;
this.doubleData = doubleData; this.doubleData = doubleData;
this.floatData = floatData; this.floatData = floatData;
} }
public Integer getId() { public Integer getId() {
return id; return id;
@ -144,5 +144,4 @@ public class SomeOtherEntity {
public void setGrade(Grade grade) { public void setGrade(Grade grade) {
this.grade = grade; this.grade = grade;
} }
} }