From 8bf9791254ed72b184ed8e25e3ca53c328e30dd2 Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Thu, 17 Nov 2011 17:51:30 +0100 Subject: [PATCH] HHH-6828 Taking case sensitivity into account when accessing the database metadata Also extending the test and formatting the code. --- .../dataTypes/BasicOperationsTest.java | 106 ++++++++++++++---- .../annotations/dataTypes/SomeEntity.java | 10 +- .../dataTypes/SomeOtherEntity.java | 61 +++++----- 3 files changed, 116 insertions(+), 61 deletions(-) diff --git a/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/BasicOperationsTest.java b/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/BasicOperationsTest.java index 7fd7fbd562..fcfa7e09e8 100644 --- a/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/BasicOperationsTest.java +++ b/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/BasicOperationsTest.java @@ -24,8 +24,10 @@ package org.hibernate.test.annotations.dataTypes; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.util.Date; import org.junit.Test; @@ -43,8 +45,12 @@ import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole */ -@RequiresDialectFeature( DialectChecks.SupportsExpectedLobUsagePattern.class ) +@RequiresDialectFeature(DialectChecks.SupportsExpectedLobUsagePattern.class) 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 protected Class[] getAnnotatedClasses() { return new Class[] { SomeEntity.class, SomeOtherEntity.class }; @@ -55,43 +61,95 @@ public class BasicOperationsTest extends BaseCoreFunctionalTestCase { Date now = new Date(); 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) - validateColumn( connection, "TIMEDATA", java.sql.Types.TIME ); + s.doWork( new ValidateSomeEntityColumns() ); + 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(); SomeEntity someEntity = new SomeEntity( now ); - SomeOtherEntity someOtherEntity = new SomeOtherEntity(1); + SomeOtherEntity someOtherEntity = new SomeOtherEntity( 1 ); s.save( someEntity ); s.save( someOtherEntity ); s.getTransaction().commit(); s.close(); s = openSession(); + + s.doWork( new ValidateRowCount( SOME_ENTITY_TABLE_NAME, 1 ) ); + s.doWork( new ValidateRowCount( SOME_OTHER_ENTITY_TABLE_NAME, 1 ) ); + s.beginTransaction(); s.delete( someEntity ); s.delete( someOtherEntity ); s.getTransaction().commit(); + + s.doWork( new ValidateRowCount( SOME_ENTITY_TABLE_NAME, 0 ) ); + s.doWork( new ValidateRowCount( SOME_OTHER_ENTITY_TABLE_NAME, 0 ) ); + 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 ); + } + } } + diff --git a/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/SomeEntity.java b/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/SomeEntity.java index 21096abbfb..fe38b11d44 100644 --- a/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/SomeEntity.java +++ b/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/SomeEntity.java @@ -22,6 +22,7 @@ * Boston, MA 02110-1301 USA */ package org.hibernate.test.annotations.dataTypes; + import java.util.Date; import javax.persistence.Access; import javax.persistence.AccessType; @@ -34,8 +35,6 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; /** - * TODO : javadoc - * * @author Steve Ebersole */ @Entity @@ -44,11 +43,11 @@ import javax.persistence.TemporalType; public class SomeEntity { @Id @Temporal(TemporalType.DATE) - @Column(name = "ID") + @Column(name = "ID") private java.util.Date id; - @Column(name = "TIMEDATA") + @Column(name = "TIMEDATA") private java.sql.Time timeData; - @Column(name = "TSDATA") + @Column(name = "TSDATA") private java.sql.Timestamp tsData; @Lob private Byte[] byteData; @@ -100,5 +99,4 @@ public class SomeEntity { public void setByteData(Byte[] byteData) { this.byteData = byteData; } - } diff --git a/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/SomeOtherEntity.java b/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/SomeOtherEntity.java index 6ccb800145..ef8b0dad38 100644 --- a/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/SomeOtherEntity.java +++ b/hibernate-core/src/matrix/java/org/hibernate/test/annotations/dataTypes/SomeOtherEntity.java @@ -22,6 +22,7 @@ * Boston, MA 02110-1301 USA */ package org.hibernate.test.annotations.dataTypes; + import javax.persistence.Access; import javax.persistence.AccessType; import javax.persistence.Entity; @@ -30,37 +31,36 @@ import javax.persistence.Enumerated; import javax.persistence.Id; /** - * TODO : javadoc - * * @author Steve Ebersole */ @Entity @Access(AccessType.FIELD) public class SomeOtherEntity { @Id - protected int id; - protected boolean booleanData; - protected byte byteData; - protected char characterData; - protected short shortData; - protected int integerData; - protected long longData; - protected double doubleData; - protected float floatData; - @Enumerated(EnumType.STRING) - protected Grade grade; + protected int id; + protected boolean booleanData; + protected byte byteData; + // setting a arbitrary character here to make this test also pass against PostgreSQL + // PostgreSQL throws otherwise an exception when persisting the null value + // org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00 + protected char characterData = 'a'; + protected short shortData; + protected int integerData; + protected long longData; + protected double doubleData; + protected float floatData; + @Enumerated(EnumType.STRING) + protected Grade grade; - public SomeOtherEntity() - { - } + public SomeOtherEntity() { + } - public SomeOtherEntity(int id) - { - this.id = id; - } + public SomeOtherEntity(int id) { + this.id = id; + } - public SomeOtherEntity( + public SomeOtherEntity( int id, boolean booleanData, byte byteData, @@ -71,15 +71,15 @@ public class SomeOtherEntity { double doubleData, float floatData) { this.id = id; - this.booleanData = booleanData; - this.byteData = byteData; - this.characterData = characterData; - this.shortData = shortData; - this.integerData = integerData; - this.longData = longData; - this.doubleData = doubleData; - this.floatData = floatData; - } + this.booleanData = booleanData; + this.byteData = byteData; + this.characterData = characterData; + this.shortData = shortData; + this.integerData = integerData; + this.longData = longData; + this.doubleData = doubleData; + this.floatData = floatData; + } public Integer getId() { return id; @@ -144,5 +144,4 @@ public class SomeOtherEntity { public void setGrade(Grade grade) { this.grade = grade; } - }