[hibernate-commits] Hibernate SVN: r10808 - in trunk/Hibernate3/test/org/hibernate/test: . lob

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Nov 14 18:19:31 EST 2006


Author: steve.ebersole at jboss.com
Date: 2006-11-14 18:19:28 -0500 (Tue, 14 Nov 2006)
New Revision: 10808

Added:
   trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml
   trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java
   trunk/Hibernate3/test/org/hibernate/test/lob/ClobTest.java
Modified:
   trunk/Hibernate3/test/org/hibernate/test/AllTests.java
   trunk/Hibernate3/test/org/hibernate/test/TestCase.java
Log:
lob tests

Modified: trunk/Hibernate3/test/org/hibernate/test/AllTests.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/AllTests.java	2006-11-14 23:18:34 UTC (rev 10807)
+++ trunk/Hibernate3/test/org/hibernate/test/AllTests.java	2006-11-14 23:19:28 UTC (rev 10808)
@@ -27,6 +27,7 @@
 import org.hibernate.test.criteria.CriteriaQueryTest;
 import org.hibernate.test.cuk.CompositePropertyRefTest;
 import org.hibernate.test.cut.CompositeUserTypeTest;
+import org.hibernate.test.dialect.cache.SQLFunctionsInterSystemsTest;
 import org.hibernate.test.discriminator.DiscriminatorTest;
 import org.hibernate.test.dom4j.Dom4jAccessorTest;
 import org.hibernate.test.dom4j.Dom4jManyToOneTest;
@@ -82,6 +83,8 @@
 import org.hibernate.test.legacy.SQLFunctionsTest;
 import org.hibernate.test.legacy.SQLLoaderTest;
 import org.hibernate.test.legacy.StatisticsTest;
+import org.hibernate.test.lob.ClobTest;
+import org.hibernate.test.lob.LobTest;
 import org.hibernate.test.manytomany.ManyToManyTest;
 import org.hibernate.test.map.MapIndexFormulaTest;
 import org.hibernate.test.mapcompelem.MapCompositeElementTest;
@@ -130,7 +133,6 @@
 import org.hibernate.test.version.db.DbVersionTest;
 import org.hibernate.test.version.sybase.SybaseTimestampVersioningTest;
 import org.hibernate.test.where.WhereTest;
-import org.hibernate.test.dialect.cache.SQLFunctionsInterSystemsTest;
 
 /**
  * @author Gavin King
@@ -290,6 +292,8 @@
 			suite.addTest( UtilSuite.suite() );
 			suite.addTest( AnyTypeTest.suite() );
 			suite.addTest( SQLFunctionsInterSystemsTest.suite() );
+			suite.addTest( LobTest.suite() );
+			suite.addTest( ClobTest.suite() );
 
 			return filter( suite );
 			//return suite;

Modified: trunk/Hibernate3/test/org/hibernate/test/TestCase.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/TestCase.java	2006-11-14 23:18:34 UTC (rev 10807)
+++ trunk/Hibernate3/test/org/hibernate/test/TestCase.java	2006-11-14 23:19:28 UTC (rev 10808)
@@ -30,6 +30,7 @@
 import org.hibernate.dialect.TimesTenDialect;
 import org.hibernate.dialect.DerbyDialect;
 import org.hibernate.dialect.Cache71Dialect;
+import org.hibernate.dialect.H2Dialect;
 import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.mapping.Collection;
 import org.hibernate.mapping.PersistentClass;
@@ -558,18 +559,91 @@
 		}
 	}
 
+	/**
+	 * Expected LOB usage pattern is such that I can perform an insert
+	 * via prepared statement with a parameter binding for a LOB value
+	 * without crazy casting to JDBC driver implementation-specific classes...
+	 * <p/>
+	 * Part of the trickiness here is the fact that this is largely
+	 * driver dependent.  For Oracle, which is notoriously bad with
+	 * LOB support in their drivers actually does a pretty good job with
+	 * LOB support as of the 10.2.x versions of their drivers...
+	 *
+	 * @return True if expected usage pattern is support; false otherwise.
+	 */
+	protected boolean supportsExpectedLobUsagePattern() {
+		// note : For H2, the insertions get truncated...
+		// note : For Derby, the insertions get truncated...
+		Class[] exceptions = new Class[] { H2Dialect.class, DerbyDialect.class };
+		if ( dialectIsOneOf( exceptions ) ) {
+			reportSkip( "database/driver does not support expected LOB usage pattern", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Does the current dialect support propogating changes to LOB
+	 * values back to the database?  Talking about mutating the
+	 * underlying value as opposed to supplying a new
+	 * LOB instance...
+	 *
+	 * @return True if the changes are propogated back to the
+	 * database; false otherwise.
+	 */
+	protected boolean supportsLobValueChangePropogation() {
+		// note: at least my local MySQL 5.1 install shows this not working...
+		// note: at least my local SQL Server 2005 Express shows this not working...
+		Class[] exceptions = new Class[] {
+				HSQLDialect.class, MySQLDialect.class, SQLServerDialect.class
+		};
+		if ( dialectIsOneOf( exceptions ) ) {
+			reportSkip( "database/driver does not support propogating LOB value change back to database", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Is it supported to materialize a LOB locator outside the transaction in
+	 * which it was created?
+	 * <p/>
+	 * Again, part of the trickiness here is the fact that this is largely
+	 * driver dependent.
+	 * <p/>
+	 * NOTE: all database I have tested which {@link #supportsExpectedLobUsagePattern()}
+	 * also support the ability to materialize a LOB outside the owning transaction...
+	 *
+	 * @return True if unbounded materialization is supported; false otherwise.
+	 */
+	protected boolean supportsUnboundedLobLocatorMaterialization() {
+		Class[] exceptions = new Class[] { }; // none known of...
+		if ( dialectIsOneOf( exceptions ) ) {
+			reportSkip( "database/driver does not support materializing a LOB locator outside the 'owning' transaction", "LOB support" );
+			return false;
+		}
+		return true;
+	}
+
+	private boolean dialectIs(Class dialectClass) {
+		return dialectClass.isInstance( getDialect() );
+	}
+
 	private boolean dialectIsNot(Class dialectClass) {
-		return dialectIsNot( new Class[] { dialectClass } );
+		return ! dialectIs( dialectClass );
 	}
-	
-	private boolean dialectIsNot(Class[] dialectClasses) {
-		for (int i = 0; i < dialectClasses.length; i++) {
-			Class dialectClass = dialectClasses[i];
-			if(dialectClass.isInstance(getDialect())) {
-				return false;
+
+	private boolean dialectIsOneOf(Class[] dialectClasses) {
+		for ( int i = 0; i < dialectClasses.length; i++ ) {
+			if ( dialectClasses[i].isInstance( getDialect() ) ) {
+				return true;
 			}
 		}
-		return true;
+		return false;
 	}
 
+	private boolean dialectIsNot(Class[] dialectClasses) {
+		return ! dialectIsOneOf( dialectClasses );
+	}
+
 }
\ No newline at end of file

Added: trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml	2006-11-14 23:18:34 UTC (rev 10807)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.hbm.xml	2006-11-14 23:19:28 UTC (rev 10808)
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+	"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
+	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.test.lob">
+
+	<class name="ClobHoldingEntity" table="CLOB_ENTITY">
+		<id name="id" type="long" column="ID">
+			<generator class="increment"/>
+		</id>
+		<property name="serialData" column="SER_DATA" type="text"/>
+        <property name="clobData" column="CLOB_DATA" type="clob" />
+    </class>
+
+</hibernate-mapping>
\ No newline at end of file

Added: trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java	2006-11-14 23:18:34 UTC (rev 10807)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/ClobHoldingEntity.java	2006-11-14 23:19:28 UTC (rev 10808)
@@ -0,0 +1,57 @@
+package org.hibernate.test.lob;
+
+import java.sql.Clob;
+
+/**
+ * Used to test materialized and lazy-materialized CLOB data.
+ * <p/>
+ * The {@link #serialData} field is used to hold CLOB data that is
+ * materialized into a String immediately (mapped via the
+ * Hibernate text type).
+ * <p/>
+ * The {@link #clobData} field is used to hold CLOB data that is
+ * materialized lazily via a JDBC CLOB locator (mapped via
+ * the Hibernate clob type).
+ *
+ * @author Steve Ebersole
+ */
+public class ClobHoldingEntity {
+	private Long id;
+	private String serialData;
+	private Clob clobData;
+
+	public ClobHoldingEntity() {
+	}
+
+	public ClobHoldingEntity(String serialData) {
+		this.serialData = serialData;
+	}
+
+	public ClobHoldingEntity(Clob clobData) {
+		this.clobData = clobData;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getSerialData() {
+		return serialData;
+	}
+
+	public void setSerialData(String serialData) {
+		this.serialData = serialData;
+	}
+
+	public Clob getClobData() {
+		return clobData;
+	}
+
+	public void setClobData(Clob clobData) {
+		this.clobData = clobData;
+	}
+}

Added: trunk/Hibernate3/test/org/hibernate/test/lob/ClobTest.java
===================================================================
--- trunk/Hibernate3/test/org/hibernate/test/lob/ClobTest.java	2006-11-14 23:18:34 UTC (rev 10807)
+++ trunk/Hibernate3/test/org/hibernate/test/lob/ClobTest.java	2006-11-14 23:19:28 UTC (rev 10808)
@@ -0,0 +1,189 @@
+package org.hibernate.test.lob;
+
+import java.sql.Clob;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.hibernate.test.TestCase;
+import org.hibernate.Session;
+import org.hibernate.Hibernate;
+import org.hibernate.LockMode;
+
+/**
+ * Test various access scenarios for eager and lazy materialization
+ * of CLOB data, as well as bounded and unbounded materialization
+ * and mutation.
+ *
+ * @author Steve Ebersole
+ */
+public class ClobTest extends TestCase {
+	private static final int CLOB_SIZE = 10000;
+
+	public ClobTest(String name) {
+		super( name );
+	}
+
+	protected String[] getMappings() {
+		return new String[] { "lob/ClobHoldingEntity.hbm.xml" };
+	}
+
+	public static Test suite() {
+		return new TestSuite( ClobTest.class );
+	}
+
+	public void testBoundedMaterializedClobAccess() {
+		if ( !supportsExpectedLobUsagePattern() ) {
+			return;
+		}
+
+		String original = buildRecursively( CLOB_SIZE, 'x' );
+		String changed = buildRecursively( CLOB_SIZE, 'y' );
+
+		Session s = openSession();
+		s.beginTransaction();
+		ClobHoldingEntity entity = new ClobHoldingEntity();
+		entity.setSerialData( original );
+		s.save( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
+		assertEquals( CLOB_SIZE, entity.getSerialData().length() );
+		assertEquals( original, entity.getSerialData() );
+		entity.setSerialData( changed );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
+		assertEquals( CLOB_SIZE, entity.getSerialData().length() );
+		assertEquals( changed, entity.getSerialData() );
+		s.delete( entity );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	public void testBoundedClobLocatorAccess() throws Throwable {
+		if ( !supportsExpectedLobUsagePattern() ) {
+			return;
+		}
+
+		String original = buildRecursively( CLOB_SIZE, 'x' );
+		String changed = buildRecursively( CLOB_SIZE, 'y' );
+
+		Session s = openSession();
+		s.beginTransaction();
+		ClobHoldingEntity entity = new ClobHoldingEntity();
+		entity.setClobData( Hibernate.createClob( original ) );
+		s.save( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
+		assertEquals( CLOB_SIZE, entity.getClobData().length() );
+		assertEquals( original, extractData( entity.getClobData() ) );
+		s.getTransaction().commit();
+		s.close();
+
+		// test mutation via setting the new clob data...
+		if ( supportsLobValueChangePropogation() ) {
+			s = openSession();
+			s.beginTransaction();
+			entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId(), LockMode.UPGRADE );
+			entity.getClobData().truncate( 1 );
+			entity.getClobData().setString( 1, changed );
+			s.getTransaction().commit();
+			s.close();
+
+			s = openSession();
+			s.beginTransaction();
+			entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId(), LockMode.UPGRADE );
+			assertNotNull( entity.getClobData() );
+			assertEquals( CLOB_SIZE, entity.getClobData().length() );
+			assertEquals( changed, extractData( entity.getClobData() ) );
+			entity.getClobData().truncate( 1 );
+			entity.getClobData().setString( 1, original );
+			s.getTransaction().commit();
+			s.close();
+		}
+
+		// test mutation via supplying a new clob locator instance...
+		s = openSession();
+		s.beginTransaction();
+		entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId(), LockMode.UPGRADE );
+		assertNotNull( entity.getClobData() );
+		assertEquals( CLOB_SIZE, entity.getClobData().length() );
+		assertEquals( original, extractData( entity.getClobData() ) );
+		entity.setClobData( Hibernate.createClob( changed ) );
+		s.getTransaction().commit();
+		s.close();
+
+		s = openSession();
+		s.beginTransaction();
+		entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
+		assertEquals( CLOB_SIZE, entity.getClobData().length() );
+		assertEquals( changed, extractData( entity.getClobData() ) );
+		s.delete( entity );
+		s.getTransaction().commit();
+		s.close();
+
+	}
+
+	public void testUnboundedClobLocatorAccess() throws Throwable {
+		if ( !supportsExpectedLobUsagePattern() || ! supportsUnboundedLobLocatorMaterialization() ) {
+			return;
+		}
+
+		// Note: unbounded mutation of the underlying lob data is completely
+		// unsupported; most databases would not allow such a construct anyway.
+		// Thus here we are only testing materialization...
+
+		String original = buildRecursively( CLOB_SIZE, 'x' );
+
+		Session s = openSession();
+		s.beginTransaction();
+		ClobHoldingEntity entity = new ClobHoldingEntity();
+		entity.setClobData( Hibernate.createClob( original ) );
+		s.save( entity );
+		s.getTransaction().commit();
+		s.close();
+
+		// load the entity with the clob locator, and close the session/transaction;
+		// at that point it is unbounded...
+		s = openSession();
+		s.beginTransaction();
+		entity = ( ClobHoldingEntity ) s.get( ClobHoldingEntity.class, entity.getId() );
+		s.getTransaction().commit();
+		s.close();
+
+		assertEquals( CLOB_SIZE, entity.getClobData().length() );
+		assertEquals( original, extractData( entity.getClobData() ) );
+
+		s = openSession();
+		s.beginTransaction();
+		s.delete( entity );
+		s.getTransaction().commit();
+		s.close();
+	}
+
+	private String extractData(Clob clob) throws Throwable {
+		char[] data = new char[ (int) clob.length() ];
+		clob.getCharacterStream().read( data );
+		return new String( data );
+	}
+
+
+	private String buildRecursively(int size, char baseChar) {
+		StringBuffer buff = new StringBuffer();
+		for( int i = 0; i < size; i++ ) {
+			buff.append( baseChar );
+		}
+		return buff.toString();
+	}
+}




More information about the hibernate-commits mailing list