diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ClobLocatorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ClobLocatorTest.java index 8fceeb31ad..b865ad49fc 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ClobLocatorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ClobLocatorTest.java @@ -9,17 +9,19 @@ package org.hibernate.orm.test.lob; import java.sql.Clob; import org.hibernate.LockOptions; -import org.hibernate.Session; import org.hibernate.dialect.SybaseASEDialect; import org.hibernate.type.descriptor.java.DataHelper; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; /** * Tests lazy materialization of data mapped by @@ -29,133 +31,176 @@ import static org.junit.Assert.assertNotNull; * @author Steve Ebersole */ @RequiresDialectFeature( - value = { DialectChecks.SupportsExpectedLobUsagePattern.class, DialectChecks.SupportsUnboundedLobLocatorMaterializationCheck.class }, + feature = DialectFeatureChecks.SupportsExpectedLobUsagePattern.class, comment = "database/driver does not support expected LOB usage pattern" ) -public class ClobLocatorTest extends BaseCoreFunctionalTestCase { +@RequiresDialectFeature( + feature = DialectFeatureChecks.SupportsUnboundedLobLocatorMaterializationCheck.class, + comment = "database/driver does not support expected LOB usage pattern" +) +@DomainModel( + xmlMappings = "org/hibernate/orm/test/lob/LobMappings.hbm.xml" +) +@SessionFactory +public class ClobLocatorTest { private static final int CLOB_SIZE = 10000; - @Override - protected String getBaseForMappings() { - return "org/hibernate/orm/test/"; - } public String[] getMappings() { - return new String[] { "lob/LobMappings.hbm.xml" }; + return new String[] { "" }; } @Test - public void testBoundedClobLocatorAccess() throws Throwable { + public void testBoundedClobLocatorAccess(SessionFactoryScope scope) throws Throwable { String original = buildString( CLOB_SIZE, 'x' ); String changed = buildString( CLOB_SIZE, 'y' ); String empty = ""; - Session s = openSession(); - s.beginTransaction(); - LobHolder entity = new LobHolder(); - entity.setClobLocator( s.getLobHelper().createClob( original ) ); - s.save( entity ); - s.getTransaction().commit(); - s.close(); + Long id = scope.fromTransaction( + session -> { + LobHolder entity = new LobHolder(); + entity.setClobLocator( session.getLobHelper().createClob( original ) ); + session.save( entity ); + return entity.getId(); + } + ); - s = openSession(); - s.beginTransaction(); - entity = s.get( LobHolder.class, entity.getId() ); - assertEquals( CLOB_SIZE, entity.getClobLocator().length() ); - assertEquals( original, extractData( entity.getClobLocator() ) ); - s.getTransaction().commit(); - s.close(); + scope.inTransaction( + session -> { + try { + LobHolder entity = session.get( LobHolder.class, id ); + assertEquals( CLOB_SIZE, entity.getClobLocator().length() ); + assertEquals( original, extractData( entity.getClobLocator() ) ); + } + catch (Exception e) { + fail( e ); + } + } + ); // test mutation via setting the new clob data... - if ( getDialect().supportsLobValueChangePropagation() ) { - s = openSession(); - s.beginTransaction(); - entity = ( LobHolder ) s.byId( LobHolder.class ).with( LockOptions.UPGRADE ).load( entity.getId() ); - entity.getClobLocator().truncate( 1 ); - entity.getClobLocator().setString( 1, changed ); - s.getTransaction().commit(); - s.close(); + if ( scope.getSessionFactory().getJdbcServices().getDialect().supportsLobValueChangePropagation() ) { + scope.inTransaction( + session -> { + try { + LobHolder entity = session.byId( LobHolder.class ) + .with( LockOptions.UPGRADE ) + .load( id ); + entity.getClobLocator().truncate( 1 ); + entity.getClobLocator().setString( 1, changed ); + } + catch (Exception e) { + fail( e ); + } + } + ); - s = openSession(); - s.beginTransaction(); - entity = ( LobHolder ) s.byId( LobHolder.class ).with( LockOptions.UPGRADE ).load( entity.getId() ); - assertNotNull( entity.getClobLocator() ); - assertEquals( CLOB_SIZE, entity.getClobLocator().length() ); - assertEquals( changed, extractData( entity.getClobLocator() ) ); - entity.getClobLocator().truncate( 1 ); - entity.getClobLocator().setString( 1, original ); - s.getTransaction().commit(); - s.close(); + scope.inTransaction( + session -> { + try { + LobHolder entity = session.byId( LobHolder.class ) + .with( LockOptions.UPGRADE ) + .load( id ); + assertNotNull( entity.getClobLocator() ); + + assertEquals( CLOB_SIZE, entity.getClobLocator().length() ); + + assertEquals( changed, extractData( entity.getClobLocator() ) ); + entity.getClobLocator().truncate( 1 ); + entity.getClobLocator().setString( 1, original ); + } + catch (Exception e) { + fail( e ); + } + } + ); } // test mutation via supplying a new clob locator instance... - s = openSession(); - s.beginTransaction(); - entity = ( LobHolder ) s.byId( LobHolder.class ).with( LockOptions.UPGRADE ).load( entity.getId() ); - assertNotNull( entity.getClobLocator() ); - assertEquals( CLOB_SIZE, entity.getClobLocator().length() ); - assertEquals( original, extractData( entity.getClobLocator() ) ); - entity.setClobLocator( s.getLobHelper().createClob( changed ) ); - s.getTransaction().commit(); - s.close(); + scope.inTransaction( + session -> { + try { + LobHolder entity = session.byId( LobHolder.class ).with( LockOptions.UPGRADE ).load( id ); + assertNotNull( entity.getClobLocator() ); + assertEquals( CLOB_SIZE, entity.getClobLocator().length() ); + assertEquals( original, extractData( entity.getClobLocator() ) ); + entity.setClobLocator( session.getLobHelper().createClob( changed ) ); + } + catch (Exception e) { + fail( e ); + } + } + ); // test empty clob - if ( !(getDialect() instanceof SybaseASEDialect ) ) { // Skip for Sybase. HHH-6425 - s = openSession(); - s.beginTransaction(); - entity = s.get( LobHolder.class, entity.getId() ); - assertEquals( CLOB_SIZE, entity.getClobLocator().length() ); - assertEquals( changed, extractData( entity.getClobLocator() ) ); - entity.setClobLocator( s.getLobHelper().createClob( empty ) ); - s.getTransaction().commit(); - s.close(); + if ( !( scope.getSessionFactory() + .getJdbcServices() + .getDialect() instanceof SybaseASEDialect ) ) { // Skip for Sybase. HHH-6425 + scope.inTransaction( + session -> { + try { + LobHolder entity = session.get( LobHolder.class, id ); + assertEquals( CLOB_SIZE, entity.getClobLocator().length() ); + assertEquals( changed, extractData( entity.getClobLocator() ) ); + entity.setClobLocator( session.getLobHelper().createClob( empty ) ); + } + catch (Exception e) { + fail( e ); + } + } + ); - s = openSession(); - s.beginTransaction(); - entity = s.get( LobHolder.class, entity.getId() ); - if ( entity.getClobLocator() != null) { - assertEquals( empty.length(), entity.getClobLocator().length() ); - assertEquals( empty, extractData( entity.getClobLocator() ) ); - } - s.delete( entity ); - s.getTransaction().commit(); - s.close(); + scope.inTransaction( + session -> { + try { + LobHolder entity = session.get( LobHolder.class, id ); + if ( entity.getClobLocator() != null ) { + assertEquals( empty.length(), entity.getClobLocator().length() ); + assertEquals( empty, extractData( entity.getClobLocator() ) ); + } + session.delete( entity ); + } + catch (Exception e) { + fail( e ); + } + } + ); } } @Test - public void testUnboundedClobLocatorAccess() throws Throwable { + public void testUnboundedClobLocatorAccess(SessionFactoryScope scope) throws Throwable { // 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 = buildString( CLOB_SIZE, 'x' ); - Session s = openSession(); - s.beginTransaction(); - LobHolder entity = new LobHolder(); - entity.setClobLocator( s.getLobHelper().createClob( original ) ); - s.save( entity ); - s.getTransaction().commit(); - s.close(); + Long id = scope.fromTransaction( + session -> { + LobHolder entity = new LobHolder(); + entity.setClobLocator( session.getLobHelper().createClob( original ) ); + session.save( entity ); + return entity.getId(); + } + ); // load the entity with the clob locator, and close the session/transaction; // at that point it is unbounded... - s = openSession(); - s.beginTransaction(); - entity = s.get( LobHolder.class, entity.getId() ); - s.getTransaction().commit(); - s.close(); + LobHolder lobHolder = scope.fromTransaction( + session -> + session.get( LobHolder.class, id ) - assertEquals( CLOB_SIZE, entity.getClobLocator().length() ); - assertEquals( original, extractData( entity.getClobLocator() ) ); + ); - s = openSession(); - s.beginTransaction(); - s.delete( entity ); - s.getTransaction().commit(); - s.close(); + assertEquals( CLOB_SIZE, lobHolder.getClobLocator().length() ); + assertEquals( original, extractData( lobHolder.getClobLocator() ) ); + + scope.inTransaction( + session -> + session.delete( lobHolder ) + ); } public static String extractData(Clob clob) throws Exception { @@ -164,7 +209,7 @@ public class ClobLocatorTest extends BaseCoreFunctionalTestCase { public static String buildString(int size, char baseChar) { StringBuilder buff = new StringBuilder(); - for( int i = 0; i < size; i++ ) { + for ( int i = 0; i < size; i++ ) { buff.append( baseChar ); } return buff.toString(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/ImageMappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ImageMappings.hbm.xml similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/test/lob/ImageMappings.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/ImageMappings.hbm.xml index d0363747c4..5956bb992f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/ImageMappings.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ImageMappings.hbm.xml @@ -9,7 +9,7 @@ "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - + diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/ImageTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ImageTest.java similarity index 72% rename from hibernate-core/src/test/java/org/hibernate/test/lob/ImageTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/ImageTest.java index 932847b456..68e4e002eb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/ImageTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/ImageTest.java @@ -4,7 +4,9 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; + +import org.hibernate.testing.orm.junit.DomainModel; /** * Tests eager materialization and mutation of data mapped by @@ -12,8 +14,8 @@ package org.hibernate.test.lob; * * @author Gail Badner */ +@DomainModel( + xmlMappings = "org/hibernate/orm/test/lob/ImageMappings.hbm.xml" +) public class ImageTest extends LongByteArrayTest { - public String[] getMappings() { - return new String[] { "lob/ImageMappings.hbm.xml" }; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/lob/JpaLargeBlobTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/JpaLargeBlobTest.java new file mode 100644 index 0000000000..070f5e7c88 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/JpaLargeBlobTest.java @@ -0,0 +1,109 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.lob; + +import java.io.IOException; +import java.io.InputStream; +import java.sql.Blob; +import java.util.Random; + +import org.hibernate.LobHelper; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.H2Dialect; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Brett Meyer + */ +@TestForIssue(jiraKey = "HHH-7698") +@RequiresDialect(value = H2Dialect.class, comment = "HHH-7724") +@DomainModel( + annotatedClasses = LobEntity.class +) +@SessionFactory +@ServiceRegistry( + settings = @Setting(name = Environment.USE_STREAMS_FOR_BINARY, value = "true") +) +public class JpaLargeBlobTest { + + protected Class[] getAnnotatedClasses() { + return new Class[] { LobEntity.class }; + } + + @Test + public void jpaBlobStream(SessionFactoryScope scope) throws Exception { + LobEntity o = new LobEntity(); + LobInputStream inputStream = scope.fromSession( + session -> { + LobHelper lh = session.getLobHelper(); + LobInputStream lis = new LobInputStream(); + + session.getTransaction().begin(); + try { + Blob blob = lh.createBlob( lis, LobEntity.BLOB_LENGTH ); + o.setBlob( blob ); + + // Regardless if NON_CONTEXTUAL_LOB_CREATION is set to true, + // ContextualLobCreator should use a NonContextualLobCreator to create + // a blob Proxy. If that's the case, the InputStream will not be read + // until it's persisted with the JDBC driver. + // Although HHH-7698 was about high memory consumption, this is the best + // way to test that the high memory use is being prevented. + assertFalse( lis.wasRead() ); + + session.persist( o ); + session.getTransaction().commit(); + } + catch (Exception e) { + if ( session.getTransaction().isActive() ) { + session.getTransaction().rollback(); + } + throw e; + } + + assertTrue( lis.wasRead() ); + return lis; + } + ); + inputStream.close(); + } + + private class LobInputStream extends InputStream { + private boolean read = false; + private Long count = (long) 200 * 1024 * 1024; + + @Override + public int read() throws IOException { + read = true; + if ( count > 0 ) { + count--; + return new Random().nextInt(); + } + return -1; + } + + @Override + public int available() throws IOException { + return 1; + } + + public boolean wasRead() { + return read; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LobAsLastValue.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobAsLastValue.hbm.xml similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/test/lob/LobAsLastValue.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobAsLastValue.hbm.xml index 9e655f8b7a..14f08276cd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LobAsLastValue.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobAsLastValue.hbm.xml @@ -9,7 +9,7 @@ "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - + diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LobAsLastValueEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobAsLastValueEntity.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/test/lob/LobAsLastValueEntity.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobAsLastValueEntity.java index dc972a9c5b..ce4108e007 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LobAsLastValueEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobAsLastValueEntity.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; import java.io.Serializable; import java.util.Objects; diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LobAsLastValueTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobAsLastValueTest.java similarity index 53% rename from hibernate-core/src/test/java/org/hibernate/test/lob/LobAsLastValueTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobAsLastValueTest.java index f320548a8e..3d04a01802 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LobAsLastValueTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobAsLastValueTest.java @@ -4,33 +4,32 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; import java.util.Random; -import org.junit.Test; - -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; - -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; /** * @author Chris Cranford */ -@RequiresDialectFeature(DialectChecks.ForceLobAsLastValue.class) +@RequiresDialectFeature(feature = DialectFeatureChecks.ForceLobAsLastValue.class) @TestForIssue(jiraKey = "HHH-8382") -public class LobAsLastValueTest extends BaseCoreFunctionalTestCase { - @Override - protected String[] getMappings() { - return new String[] { "lob/LobAsLastValue.hbm.xml" }; - } +@DomainModel( + xmlMappings = "org/hibernate/orm/test/lob/LobAsLastValue.hbm.xml" +) +@SessionFactory +public class LobAsLastValueTest { @Test - public void testInsertLobAsLastValue() { - doInHibernate( this::sessionFactory, session -> { + public void testInsertLobAsLastValue(SessionFactoryScope scope) { + scope.inTransaction( session -> { byte[] details = new byte[4000]; byte[] title = new byte[2000]; @@ -40,7 +39,11 @@ public class LobAsLastValueTest extends BaseCoreFunctionalTestCase { // This insert will fail on Oracle without the fix to ModelBinder flagging SimpleValue and Property as Lob // because the fields will not be placed at the end of the insert, resulting in an Oracle failure. - final LobAsLastValueEntity entity = new LobAsLastValueEntity( "Test", new String( details ), new String( title ) ); + final LobAsLastValueEntity entity = new LobAsLastValueEntity( + "Test", + new String( details ), + new String( title ) + ); session.save( entity ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LobEntity.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobEntity.java similarity index 96% rename from hibernate-core/src/test/java/org/hibernate/test/lob/LobEntity.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobEntity.java index ea81ca5608..dae0fed7ef 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LobEntity.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobEntity.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; import java.sql.Blob; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobStringTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobStringTest.java new file mode 100644 index 0000000000..2978114b15 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LobStringTest.java @@ -0,0 +1,248 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.lob; + +import java.io.UnsupportedEncodingException; +import java.sql.Clob; +import java.sql.SQLException; +import java.util.List; + +import org.hibernate.dialect.CockroachDialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.query.Query; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.RequiresDialects; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.Table; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * @author Andrea Boriero + */ +@TestForIssue(jiraKey = "HHH-11477") +@RequiresDialects({ @RequiresDialect(PostgreSQLDialect.class), @RequiresDialect(CockroachDialect.class) }) +@DomainModel( + annotatedClasses = LobStringTest.TestEntity.class +) +@SessionFactory +public class LobStringTest { + + private static final int LONG_STRING_SIZE = 3999; + + private final String value1 = buildRecursively( LONG_STRING_SIZE, 'x' ); + private final String value2 = buildRecursively( LONG_STRING_SIZE, 'y' ); + + @BeforeEach + protected void prepareTest(SessionFactoryScope scope) throws Exception { + TestEntity entity = new TestEntity(); + scope.inTransaction( session -> { + + entity.setFirstLobField( value1 ); + entity.setSecondLobField( value2 ); + entity.setClobField( session.getLobHelper().createClob( value2 ) ); + session.save( entity ); + } ); + + scope.inTransaction( session -> { + final TestEntity testEntity = session.find( TestEntity.class, entity.getId() ); + assertThat( testEntity.getFirstLobField(), is( value1 ) ); + } ); + } + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( + session -> + session.createQuery( "delete from TestEntity" ).executeUpdate() + ); + } + + @Test + @TestForIssue(jiraKey = "HHH-11477") + public void testHqlQuery(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final Query query = session.createQuery( "from TestEntity" ); + + final List results = query.list(); + + assertThat( results.size(), is( 1 ) ); + + final TestEntity testEntity = results.get( 0 ); + assertThat( testEntity.getFirstLobField(), is( value1 ) ); + assertThat( testEntity.getSecondLobField(), is( value2 ) ); + final Clob clobField = testEntity.getClobField(); + try { + + assertThat( clobField.getSubString( 1, (int) clobField.length() ), is( value2 ) ); + } + catch (SQLException e) { + fail( e.getMessage() ); + } + } ); + } + + @Test + @TestForIssue(jiraKey = "HHH-11477") + @RequiresDialect(PostgreSQLDialect.class) + public void testUsingStringLobAnnotatedPropertyInNativeQuery(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final List results = session.createNativeQuery( + "select te.* " + + "from test_entity te " + + "where lower(convert_from(lo_get(cast(te.firstLobField as oid)), 'UTF8')) LIKE :value", + TestEntity.class + ) + .setParameter( "value", value1 ) + .getResultList(); + + assertThat( results.size(), is( 1 ) ); + + final TestEntity testEntity = results.get( 0 ); + assertThat( testEntity.getFirstLobField(), is( value1 ) ); + assertThat( testEntity.getSecondLobField(), is( value2 ) ); + final Clob clobField = testEntity.getClobField(); + try { + assertThat( clobField.getSubString( 1, (int) clobField.length() ), is( value2 ) ); + } + catch (SQLException e) { + fail( e.getMessage() ); + } + } ); + } + + @Test + @TestForIssue(jiraKey = "HHH-11477") + @RequiresDialect(PostgreSQLDialect.class) + public void testSelectStringLobAnnotatedInNativeQuery(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final List results = session.createNativeQuery( + "select convert_from(lo_get(cast(te.secondLobField as oid)), 'UTF8') " + + "from test_entity te " + + "where lower(convert_from(lo_get(cast(te.firstLobField as oid)), 'UTF8')) LIKE :value" ) + .setParameter( "value", value1 ) + .list(); + + assertThat( results.size(), is( 1 ) ); + + assertThat( results.get( 0 ), is( value2 ) ); + } ); + } + + @Test + @TestForIssue(jiraKey = "HHH-11477") + @RequiresDialect(PostgreSQLDialect.class) + public void testUsingLobPropertyInNativeQuery(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final List results = session.createNativeQuery( + "select convert_from(lo_get(cast(te.secondLobField as oid)), 'UTF8') " + + "from test_entity te " + + "where lower(convert_from(lo_get(cast(te.clobField as oid)), 'UTF8')) LIKE :value" ) + .setParameter( "value", value2 ) + .list(); + + assertThat( results.size(), is( 1 ) ); + + assertThat( results.get( 0 ), is( value2 ) ); + } ); + } + + @Test + @TestForIssue(jiraKey = "HHH-11477") + @RequiresDialect(PostgreSQLDialect.class) + public void testSelectClobPropertyInNativeQuery(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final List results = session.createNativeQuery( + "select lo_get(cast(te.clobField as oid)) " + + "from test_entity te " + + "where lower(convert_from(lo_get(cast(te.clobField as oid)), 'UTF8')) LIKE :value" ) + .setParameter( "value", value2 ) + .list(); + + assertThat( results.size(), is( 1 ) ); + + try { + assertThat( new String( results.get( 0 ), "UTF8" ), is( value2 ) ); + } + catch (UnsupportedEncodingException e) { + fail( e.getMessage() ); + } + } ); + } + + @Entity(name = "TestEntity") + @Table(name = "TEST_ENTITY") + public static class TestEntity { + @Id + @GeneratedValue + private long id; + + @Lob + @Column(length = LONG_STRING_SIZE) //needed by HSQLDialect + String firstLobField; + + @Lob + @Column(length = LONG_STRING_SIZE) //needed by HSQLDialect + String secondLobField; + + @Lob + @Column(length = LONG_STRING_SIZE) //needed by HSQLDialect + Clob clobField; + + public long getId() { + return id; + } + + public String getFirstLobField() { + return firstLobField; + } + + public void setFirstLobField(String firstLobField) { + this.firstLobField = firstLobField; + } + + public String getSecondLobField() { + return secondLobField; + } + + public void setSecondLobField(String secondLobField) { + this.secondLobField = secondLobField; + } + + public Clob getClobField() { + return clobField; + } + + public void setClobField(Clob clobField) { + this.clobField = clobField; + } + } + + + private String buildRecursively(int size, char baseChar) { + StringBuilder buff = new StringBuilder(); + for ( int i = 0; i < size; i++ ) { + buff.append( baseChar ); + } + return buff.toString(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LongByteArrayHolder.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongByteArrayHolder.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/test/lob/LongByteArrayHolder.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongByteArrayHolder.java index d49c8f1ba9..8b0f0ae10e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LongByteArrayHolder.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongByteArrayHolder.java @@ -7,7 +7,7 @@ //$Id: $ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; /** diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongByteArrayTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongByteArrayTest.java new file mode 100644 index 0000000000..0f14965c05 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongByteArrayTest.java @@ -0,0 +1,156 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.lob; + +import java.util.Arrays; + +import org.hibernate.dialect.SybaseASEDialect; + +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.SkipForDialect; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.fail; + + +/** + * Tests eager materialization and mutation of long byte arrays. + * + * @author Steve Ebersole + */ +@SessionFactory +public abstract class LongByteArrayTest { + private static final int ARRAY_SIZE = 10000; + + @Test + public void testBoundedLongByteArrayAccess(SessionFactoryScope scope) { + byte[] original = buildRecursively( ARRAY_SIZE, true ); + byte[] changed = buildRecursively( ARRAY_SIZE, false ); + byte[] empty = new byte[] {}; + + Long id = scope.fromTransaction( + session -> { + LongByteArrayHolder entity = new LongByteArrayHolder(); + session.save( entity ); + return entity.getId(); + } + ); + + scope.inTransaction( + session -> { + LongByteArrayHolder entity = session.get( LongByteArrayHolder.class, id ); + assertNull( entity.getLongByteArray() ); + entity.setLongByteArray( original ); + } + ); + + scope.inTransaction( + session -> { + LongByteArrayHolder entity = session.get( LongByteArrayHolder.class, id ); + Assertions.assertEquals( ARRAY_SIZE, entity.getLongByteArray().length ); + assertEquals( original, entity.getLongByteArray() ); + entity.setLongByteArray( changed ); + } + ); + + scope.inTransaction( + session -> { + LongByteArrayHolder entity = session.get( LongByteArrayHolder.class, id ); + Assertions.assertEquals( ARRAY_SIZE, entity.getLongByteArray().length ); + assertEquals( changed, entity.getLongByteArray() ); + entity.setLongByteArray( null ); + } + ); + + scope.inTransaction( + session -> { + LongByteArrayHolder entity = session.get( LongByteArrayHolder.class, id ); + assertNull( entity.getLongByteArray() ); + entity.setLongByteArray( empty ); + } + ); + } + + @Test + @SkipForDialect(dialectClass = SybaseASEDialect.class, reason = "Sybase returns byte[]{0}") + public void testEmptyArray(SessionFactoryScope scope) { + byte[] empty = new byte[] {}; + + LongByteArrayHolder longByteArrayHolder = new LongByteArrayHolder(); + scope.inTransaction( + session -> { + longByteArrayHolder.setLongByteArray( empty ); + session.save( longByteArrayHolder ); + } + ); + + scope.inTransaction( + session -> { + LongByteArrayHolder entity = session.get( LongByteArrayHolder.class, longByteArrayHolder.getId() ); + if ( entity.getLongByteArray() != null ) { + Assertions.assertEquals( empty.length, entity.getLongByteArray().length ); + assertEquals( empty, entity.getLongByteArray() ); + } + } + ); + } + + @Test + public void testSaving(SessionFactoryScope scope) { + byte[] value = buildRecursively( ARRAY_SIZE, true ); + + Long id = scope.fromTransaction( + session -> { + LongByteArrayHolder entity = new LongByteArrayHolder(); + entity.setLongByteArray( value ); + session.persist( entity ); + return entity.getId(); + } + ); + + scope.inTransaction( + session -> { + LongByteArrayHolder entity = session.get( LongByteArrayHolder.class, id ); + Assertions.assertEquals( ARRAY_SIZE, entity.getLongByteArray().length ); + assertEquals( value, entity.getLongByteArray() ); + session.delete( entity ); + } + ); + } + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( + session -> + session.createQuery( "delete from LongByteArrayHolder" ).executeUpdate() + ); + } + + private byte[] buildRecursively(int size, boolean on) { + byte[] data = new byte[size]; + data[0] = mask( on ); + for ( int i = 0; i < size; i++ ) { + data[i] = mask( on ); + on = !on; + } + return data; + } + + private byte mask(boolean on) { + return on ? (byte) 1 : (byte) 0; + } + + public static void assertEquals(byte[] val1, byte[] val2) { + if ( !Arrays.equals( val1, val2 ) ) { + fail( "byte arrays did not match" ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LongStringHolder.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongStringHolder.java similarity index 94% rename from hibernate-core/src/test/java/org/hibernate/test/lob/LongStringHolder.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongStringHolder.java index 3834075c0c..066188b6a1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LongStringHolder.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongStringHolder.java @@ -7,7 +7,7 @@ //$Id: $ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; /** diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongStringTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongStringTest.java new file mode 100644 index 0000000000..767679a059 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/LongStringTest.java @@ -0,0 +1,104 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.lob; + + +import org.hibernate.dialect.SybaseASEDialect; + +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + + +/** + * Tests eager materialization and mutation of long strings. + * + * @author Steve Ebersole + */ +@SuppressWarnings({ "UnusedDeclaration" }) +@SessionFactory +public abstract class LongStringTest { + private static final int LONG_STRING_SIZE = 10000; + + @Test + public void testBoundedLongStringAccess(SessionFactoryScope scope) { + String original = buildRecursively( LONG_STRING_SIZE, 'x' ); + String changed = buildRecursively( LONG_STRING_SIZE, 'y' ); + String empty = ""; + + Long id = scope.fromTransaction( + session -> { + LongStringHolder entity = new LongStringHolder(); + session.save( entity ); + return entity.getId(); + } + ); + + scope.inTransaction( + session -> { + LongStringHolder entity = session.get( LongStringHolder.class, id ); + assertNull( entity.getLongString() ); + entity.setLongString( original ); + } + ); + + scope.inTransaction( + session -> { + LongStringHolder entity = session.get( LongStringHolder.class, id ); + assertEquals( LONG_STRING_SIZE, entity.getLongString().length() ); + assertEquals( original, entity.getLongString() ); + entity.setLongString( changed ); + } + ); + + scope.inTransaction( + session -> { + LongStringHolder entity = session.get( LongStringHolder.class, id ); + assertEquals( LONG_STRING_SIZE, entity.getLongString().length() ); + assertEquals( changed, entity.getLongString() ); + entity.setLongString( null ); + } + ); + + scope.inTransaction( + session -> { + LongStringHolder entity = session.get( LongStringHolder.class, id ); + assertNull( entity.getLongString() ); + entity.setLongString( empty ); + } + ); + + scope.inTransaction( + session -> { + LongStringHolder entity = session.get( LongStringHolder.class, id ); + if ( entity.getLongString() != null ) { + if ( scope.getSessionFactory().getJdbcServices().getDialect() instanceof SybaseASEDialect ) { + //Sybase uses a single blank to denote an empty string (this is by design). So, when inserting an empty string '', it is interpreted as single blank ' '. + assertEquals( empty.length(), entity.getLongString().trim().length() ); + assertEquals( empty, entity.getLongString().trim() ); + } + else { + assertEquals( empty.length(), entity.getLongString().length() ); + assertEquals( empty, entity.getLongString() ); + } + } + session.delete( entity ); + } + ); + } + + private String buildRecursively(int size, char baseChar) { + StringBuilder buff = new StringBuilder(); + for ( int i = 0; i < size; i++ ) { + buff.append( baseChar ); + } + return buff.toString(); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedBlobMappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedBlobMappings.hbm.xml similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedBlobMappings.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedBlobMappings.hbm.xml index 781417275c..e25efe8c76 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedBlobMappings.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedBlobMappings.hbm.xml @@ -9,7 +9,7 @@ "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - + diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedBlobTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedBlobTest.java similarity index 59% rename from hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedBlobTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedBlobTest.java index 8ba943c860..7e8d07ab25 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedBlobTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedBlobTest.java @@ -4,10 +4,12 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; + +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; /** * Tests eager materialization and mutation of data mapped by @@ -16,11 +18,11 @@ import org.hibernate.testing.RequiresDialectFeature; * @author Gail Badner */ @RequiresDialectFeature( - value = DialectChecks.SupportsExpectedLobUsagePattern.class, + feature = DialectFeatureChecks.SupportsExpectedLobUsagePattern.class, comment = "database/driver does not support expected LOB usage pattern" ) +@DomainModel( + xmlMappings = "org/hibernate/orm/test/lob/MaterializedBlobMappings.hbm.xml" +) public class MaterializedBlobTest extends LongByteArrayTest { - public String[] getMappings() { - return new String[] { "lob/MaterializedBlobMappings.hbm.xml" }; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedClobMappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedClobMappings.hbm.xml similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedClobMappings.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedClobMappings.hbm.xml index 224f62ffe3..7d0583e911 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedClobMappings.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedClobMappings.hbm.xml @@ -9,7 +9,7 @@ "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - + diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedClobTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedClobTest.java similarity index 53% rename from hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedClobTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedClobTest.java index 2a82bc7c4c..172618661c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/MaterializedClobTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/MaterializedClobTest.java @@ -4,10 +4,11 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; /** * Tests eager materialization and mutation of data mapped by @@ -15,9 +16,9 @@ import org.hibernate.testing.RequiresDialectFeature; * * @author Gail Badner */ -@RequiresDialectFeature( DialectChecks.SupportsExpectedLobUsagePattern.class ) +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsExpectedLobUsagePattern.class) +@DomainModel( + xmlMappings = "org/hibernate/orm/test/lob/MaterializedClobMappings.hbm.xml" +) public class MaterializedClobTest extends LongStringTest { - public String[] getMappings() { - return new String[] { "lob/MaterializedClobMappings.hbm.xml" }; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/lob/PostgreSqlLobStringTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/PostgreSqlLobStringTest.java new file mode 100644 index 0000000000..e315baf0b8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/PostgreSqlLobStringTest.java @@ -0,0 +1,204 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.lob; + +import java.sql.Clob; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; + +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.query.Query; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.util.ExceptionUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Lob; +import jakarta.persistence.Table; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +/** + * @author Andrea Boriero + */ +@TestForIssue(jiraKey = "HHH-11614") +@RequiresDialect(PostgreSQLDialect.class) +@DomainModel( + annotatedClasses = PostgreSqlLobStringTest.TestEntity.class +) +@SessionFactory +public class PostgreSqlLobStringTest { + + private final String value1 = "abc"; + private final String value2 = "def"; + private final String value3 = "ghi"; + + @BeforeEach + protected void prepareTest(SessionFactoryScope scope) + throws Exception { + + scope.inTransaction( + session -> + session.doWork( connection -> { + try (PreparedStatement statement = connection.prepareStatement( + "insert \n" + + " into\n" + + " TEST_ENTITY\n" + + " (firstLobField, secondLobField, clobfield, id) \n" + + " values\n" + + " (?, ?, ?, -1)" + )) { + int index = 1; + statement.setString( index++, value1 ); + statement.setString( index++, value2 ); + statement.setString( index++, value3 ); + + assertEquals( 1, statement.executeUpdate() ); + } + } ) + ); + } + + @Test + public void testBadClobDataSavedAsStringFails(SessionFactoryScope scope) { + try { + scope.inTransaction( + session -> { + final Query query = session.createQuery( "from TestEntity" ); + + final List results = query.list(); + + fail( "Exception thrown expected" ); + } ); + } + catch (Exception e) { + Exception rootException = (Exception) ExceptionUtil.rootCause( e ); + assertTrue( rootException.getMessage().startsWith( "Bad value for type long" ) ); + } + } + + @Test + public void testBadClobDataSavedAsStringworksAfterUpdate(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + + session.doWork( connection -> { + try (Statement statement = connection.createStatement()) { + statement.executeUpdate( + "update test_entity\n" + + "set \n" + + " clobfield = lo_from_bytea(0, cast(clobfield as bytea)),\n" + + " firstlobfield = lo_from_bytea(0, cast(firstlobfield as bytea)),\n" + + " secondlobfield = lo_from_bytea(0, cast(secondlobfield as bytea))" + ); + } + } ); + } ); + + scope.inTransaction( + session -> { + final Query query = session.createQuery( "from TestEntity" ); + + final List results = query.list(); + + assertThat( results.size(), is( 1 ) ); + + final TestEntity testEntity = results.get( 0 ); + assertThat( testEntity.getFirstLobField(), is( value1 ) ); + assertThat( testEntity.getSecondLobField(), is( value2 ) ); + final Clob clobField = testEntity.getClobField(); + try { + + assertThat( clobField.getSubString( 1, (int) clobField.length() ), is( value3 ) ); + } + catch (SQLException e) { + fail( e.getMessage() ); + } + } ); + } + + @AfterEach + public void cleanUp(SessionFactoryScope scope) { + scope.inTransaction( + session -> + session.createQuery( "delete from TestEntity" ).executeUpdate() + ); + } + + @Entity(name = "TestEntity") + @Table(name = "TEST_ENTITY") + public static class TestEntity { + @Id + @GeneratedValue + private long id; + + @Lob + @Column + String firstLobField; + + @Lob + @Column + String secondLobField; + + @Lob + @Column + Clob clobField; + + public long getId() { + return id; + } + + public String getFirstLobField() { + return firstLobField; + } + + public void setFirstLobField(String firstLobField) { + this.firstLobField = firstLobField; + } + + public String getSecondLobField() { + return secondLobField; + } + + public void setSecondLobField(String secondLobField) { + this.secondLobField = secondLobField; + } + + public Clob getClobField() { + return clobField; + } + + public void setClobField(Clob clobField) { + this.clobField = clobField; + } + } + +// @Override +// protected boolean isCleanupTestDataRequired() { +// return true; +// } + +// protected boolean isCleanupTestDataUsingBulkDelete() { +// return true; +// } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/SerializableData.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableData.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/test/lob/SerializableData.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableData.java index 9d8be10a2a..ea8eaacce4 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/SerializableData.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableData.java @@ -6,7 +6,7 @@ */ // $Id: SerializableData.java 4704 2004-11-04 21:59:22Z steveebersole $ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; import java.io.Serializable; /** diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/SerializableHolder.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableHolder.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/test/lob/SerializableHolder.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableHolder.java index b27dd88ba8..4ca19a0aa6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/SerializableHolder.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableHolder.java @@ -7,7 +7,7 @@ //$Id: $ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; import java.io.Serializable; /** diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/SerializableMappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableMappings.hbm.xml similarity index 93% rename from hibernate-core/src/test/java/org/hibernate/test/lob/SerializableMappings.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableMappings.hbm.xml index 350d0cf149..fb212f2140 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/SerializableMappings.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableMappings.hbm.xml @@ -9,7 +9,7 @@ "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - + diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableTypeTest.java new file mode 100644 index 0000000000..4cb17d197c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/SerializableTypeTest.java @@ -0,0 +1,93 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.lob; + +import org.hibernate.dialect.SybaseASEDialect; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.SkipForDialect; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + + +/** + * Tests of {@link org.hibernate.type.SerializableType} + * + * @author Steve Ebersole + */ +@DomainModel( + xmlMappings = "org/hibernate/orm/test/lob/SerializableMappings.hbm.xml" +) +@SessionFactory +public class SerializableTypeTest { + + @Test + @SkipForDialect(dialectClass = SybaseASEDialect.class, version = 1500, matchSubTypes = true, reason = "HHH-6425") + public void testNewSerializableType(SessionFactoryScope scope) { + final String initialPayloadText = "Initial payload"; + final String changedPayloadText = "Changed payload"; + final String empty = ""; + + SerializableHolder serializableHolder = scope.fromTransaction( + session -> { + SerializableHolder holder = new SerializableHolder(); + session.save( holder ); + return holder; + } + ); + + Long id = serializableHolder.getId(); + + scope.inTransaction( + session -> { + SerializableHolder holder = session.get( SerializableHolder.class, id ); + assertNull( holder.getSerialData() ); + holder.setSerialData( new SerializableData( initialPayloadText ) ); + } + ); + + scope.inTransaction( + session -> { + SerializableHolder holder = session.get( SerializableHolder.class, id ); + SerializableData serialData = (SerializableData) holder.getSerialData(); + assertEquals( initialPayloadText, serialData.getPayload() ); + holder.setSerialData( new SerializableData( changedPayloadText ) ); + } + ); + + scope.inTransaction( + session -> { + SerializableHolder holder = session.get( SerializableHolder.class, id ); + SerializableData serialData = (SerializableData) holder.getSerialData(); + assertEquals( changedPayloadText, serialData.getPayload() ); + holder.setSerialData( null ); + } + ); + + scope.inTransaction( + session -> { + SerializableHolder holder = session.get( SerializableHolder.class, id ); + assertNull( holder.getSerialData() ); + holder.setSerialData( new SerializableData( empty ) ); + } + ); + + scope.inTransaction( + session -> { + SerializableHolder holder = session.get( SerializableHolder.class, id ); + SerializableData serialData = (SerializableData) holder.getSerialData(); + assertEquals( empty, serialData.getPayload() ); + session.delete( holder ); + } + ); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/TextMappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/TextMappings.hbm.xml similarity index 92% rename from hibernate-core/src/test/java/org/hibernate/test/lob/TextMappings.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/TextMappings.hbm.xml index a473e8edac..4ea5d91914 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/TextMappings.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/TextMappings.hbm.xml @@ -9,7 +9,7 @@ "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> - + diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/TextTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/TextTest.java similarity index 71% rename from hibernate-core/src/test/java/org/hibernate/test/lob/TextTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/lob/TextTest.java index bac408643c..e88fa0525c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/TextTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/lob/TextTest.java @@ -4,7 +4,9 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.lob; +package org.hibernate.orm.test.lob; + +import org.hibernate.testing.orm.junit.DomainModel; /** * Test eager materialization and mutation data mapped by @@ -12,8 +14,8 @@ package org.hibernate.test.lob; * * @author Gail Badner */ +@DomainModel( + xmlMappings = "org/hibernate/orm/test/lob/TextMappings.hbm.xml" +) public class TextTest extends LongStringTest { - public String[] getMappings() { - return new String[] { "lob/TextMappings.hbm.xml" }; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/JpaLargeBlobTest.java b/hibernate-core/src/test/java/org/hibernate/test/lob/JpaLargeBlobTest.java deleted file mode 100644 index a9f6f261ba..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/JpaLargeBlobTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.lob; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.io.InputStream; -import java.sql.Blob; -import java.util.Random; - -import org.hibernate.LobHelper; -import org.hibernate.Session; -import org.hibernate.cfg.Configuration; -import org.hibernate.cfg.Environment; -import org.hibernate.dialect.H2Dialect; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -/** - * @author Brett Meyer - */ -@TestForIssue( jiraKey = "HHH-7698" ) -@RequiresDialect( value = H2Dialect.class, jiraKey = "HHH-7724" ) -public class JpaLargeBlobTest extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { LobEntity.class }; - } - - @Override - protected void configure(Configuration configuration) { - super.configure( configuration ); - configuration.setProperty(Environment.USE_STREAMS_FOR_BINARY, "true"); - } - - @Test - public void jpaBlobStream() throws Exception { - Session session = openSession(); - LobEntity o = new LobEntity(); - - LobHelper lh = session.getLobHelper(); - LobInputStream lis = new LobInputStream(); - - session.getTransaction().begin(); - - Blob blob = lh.createBlob(lis, LobEntity.BLOB_LENGTH); - o.setBlob(blob); - - // Regardless if NON_CONTEXTUAL_LOB_CREATION is set to true, - // ContextualLobCreator should use a NonContextualLobCreator to create - // a blob Proxy. If that's the case, the InputStream will not be read - // until it's persisted with the JDBC driver. - // Although HHH-7698 was about high memory consumption, this is the best - // way to test that the high memory use is being prevented. - assertFalse( lis.wasRead() ); - - session.persist(o); - session.getTransaction().commit(); - - assertTrue( lis.wasRead() ); - - session.close(); - - lis.close(); - } - - private class LobInputStream extends InputStream { - private boolean read = false; - private Long count = (long) 200 * 1024 * 1024; - - @Override - public int read() throws IOException { - read = true; - if (count > 0) { - count--; - return new Random().nextInt(); - } - return -1; - } - - @Override - public int available() throws IOException { - return 1; - } - - public boolean wasRead() { - return read; - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LobStringTest.java b/hibernate-core/src/test/java/org/hibernate/test/lob/LobStringTest.java deleted file mode 100644 index 97d7bdbd66..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LobStringTest.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.lob; - -import java.io.UnsupportedEncodingException; -import java.sql.Clob; -import java.sql.SQLException; -import java.util.List; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.Lob; -import jakarta.persistence.Table; - -import org.hibernate.dialect.CockroachDialect; -import org.hibernate.dialect.PostgreSQLDialect; -import org.hibernate.query.Query; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -import static org.hamcrest.core.Is.is; -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -/** - * @author Andrea Boriero - */ -@TestForIssue(jiraKey = "HHH-11477") -@RequiresDialect({ PostgreSQLDialect.class, CockroachDialect.class }) -public class LobStringTest extends BaseCoreFunctionalTestCase { - - private static final int LONG_STRING_SIZE = 3999; - - private final String value1 = buildRecursively( LONG_STRING_SIZE, 'x' ); - private final String value2 = buildRecursively( LONG_STRING_SIZE, 'y' ); - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] {TestEntity.class}; - } - - @Override - protected void prepareTest() throws Exception { - TestEntity entity = new TestEntity(); - doInHibernate( this::sessionFactory, session -> { - - entity.setFirstLobField( value1 ); - entity.setSecondLobField( value2 ); - entity.setClobField( session.getLobHelper().createClob( value2 ) ); - session.save( entity ); - } ); - - doInHibernate( this::sessionFactory, session -> { - final TestEntity testEntity = session.find( TestEntity.class, entity.getId() ); - assertThat( testEntity.getFirstLobField(), is( value1 ) ); - } ); - } - - @Test - @TestForIssue(jiraKey = "HHH-11477") - public void testHqlQuery() { - doInHibernate( this::sessionFactory, session -> { - final Query query = session.createQuery( "from TestEntity" ); - - final List results = query.list(); - - assertThat( results.size(), is( 1 ) ); - - final TestEntity testEntity = results.get( 0 ); - assertThat( testEntity.getFirstLobField(), is( value1 ) ); - assertThat( testEntity.getSecondLobField(), is( value2 ) ); - final Clob clobField = testEntity.getClobField(); - try { - - assertThat( clobField.getSubString( 1, (int) clobField.length() ), is( value2 ) ); - } - catch (SQLException e) { - fail( e.getMessage() ); - } - } ); - } - - @Test - @TestForIssue(jiraKey = "HHH-11477") - @RequiresDialect(PostgreSQLDialect.class) - public void testUsingStringLobAnnotatedPropertyInNativeQuery() { - doInHibernate( this::sessionFactory, session -> { - final List results = session.createNativeQuery( - "select te.* " + - "from test_entity te " + - "where lower(convert_from(lo_get(cast(te.firstLobField as oid)), 'UTF8')) LIKE :value", TestEntity.class ) - .setParameter( "value", value1 ) - .getResultList(); - - assertThat( results.size(), is( 1 ) ); - - final TestEntity testEntity = results.get( 0 ); - assertThat( testEntity.getFirstLobField(), is( value1 ) ); - assertThat( testEntity.getSecondLobField(), is( value2 ) ); - final Clob clobField = testEntity.getClobField(); - try { - assertThat( clobField.getSubString( 1, (int) clobField.length() ), is( value2 ) ); - } - catch (SQLException e) { - fail( e.getMessage() ); - } - } ); - } - - @Test - @TestForIssue(jiraKey = "HHH-11477") - @RequiresDialect(PostgreSQLDialect.class) - public void testSelectStringLobAnnotatedInNativeQuery() { - doInHibernate( this::sessionFactory, session -> { - final List results = session.createNativeQuery( - "select convert_from(lo_get(cast(te.secondLobField as oid)), 'UTF8') " + - "from test_entity te " + - "where lower(convert_from(lo_get(cast(te.firstLobField as oid)), 'UTF8')) LIKE :value" ) - .setParameter( "value", value1 ) - .list(); - - assertThat( results.size(), is( 1 ) ); - - assertThat( results.get( 0 ), is( value2 ) ); - } ); - } - - @Test - @TestForIssue(jiraKey = "HHH-11477") - @RequiresDialect(PostgreSQLDialect.class) - public void testUsingLobPropertyInNativeQuery() { - doInHibernate( this::sessionFactory, session -> { - final List results = session.createNativeQuery( - "select convert_from(lo_get(cast(te.secondLobField as oid)), 'UTF8') " + - "from test_entity te " + - "where lower(convert_from(lo_get(cast(te.clobField as oid)), 'UTF8')) LIKE :value" ) - .setParameter( "value", value2 ) - .list(); - - assertThat( results.size(), is( 1 ) ); - - assertThat( results.get( 0 ), is( value2 ) ); - } ); - } - - @Test - @TestForIssue(jiraKey = "HHH-11477") - @RequiresDialect(PostgreSQLDialect.class) - public void testSelectClobPropertyInNativeQuery() { - doInHibernate( this::sessionFactory, session -> { - final List results = session.createNativeQuery( - "select lo_get(cast(te.clobField as oid)) " + - "from test_entity te " + - "where lower(convert_from(lo_get(cast(te.clobField as oid)), 'UTF8')) LIKE :value" ) - .setParameter( "value", value2 ) - .list(); - - assertThat( results.size(), is( 1 ) ); - - try { - assertThat( new String( results.get( 0 ), "UTF8"), is( value2 ) ); - } - catch (UnsupportedEncodingException e) { - fail(e.getMessage()); - } - } ); - } - - @Entity(name = "TestEntity") - @Table(name = "TEST_ENTITY") - public static class TestEntity { - @Id - @GeneratedValue - private long id; - - @Lob - @Column(length = LONG_STRING_SIZE) //needed by HSQLDialect - String firstLobField; - - @Lob - @Column(length = LONG_STRING_SIZE) //needed by HSQLDialect - String secondLobField; - - @Lob - @Column(length = LONG_STRING_SIZE) //needed by HSQLDialect - Clob clobField; - - public long getId() { - return id; - } - - public String getFirstLobField() { - return firstLobField; - } - - public void setFirstLobField(String firstLobField) { - this.firstLobField = firstLobField; - } - - public String getSecondLobField() { - return secondLobField; - } - - public void setSecondLobField(String secondLobField) { - this.secondLobField = secondLobField; - } - - public Clob getClobField() { - return clobField; - } - - public void setClobField(Clob clobField) { - this.clobField = clobField; - } - } - - @Override - protected boolean isCleanupTestDataRequired() { - return true; - } - - private String buildRecursively(int size, char baseChar) { - StringBuilder buff = new StringBuilder(); - for ( int i = 0; i < size; i++ ) { - buff.append( baseChar ); - } - return buff.toString(); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LongByteArrayTest.java b/hibernate-core/src/test/java/org/hibernate/test/lob/LongByteArrayTest.java deleted file mode 100644 index f35708f864..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LongByteArrayTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.lob; - -import java.util.Arrays; - -import org.hibernate.Session; - -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Assert; -import org.junit.Test; -import junit.framework.AssertionFailedError; - -import static org.junit.Assert.assertNull; - -/** - * Tests eager materialization and mutation of long byte arrays. - * - * @author Steve Ebersole - */ -public abstract class LongByteArrayTest extends BaseCoreFunctionalTestCase { - private static final int ARRAY_SIZE = 10000; - - @Test - public void testBoundedLongByteArrayAccess() { - byte[] original = buildRecursively( ARRAY_SIZE, true ); - byte[] changed = buildRecursively( ARRAY_SIZE, false ); - byte[] empty = new byte[] {}; - - Session s = openSession(); - s.beginTransaction(); - LongByteArrayHolder entity = new LongByteArrayHolder(); - s.save( entity ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = s.get( LongByteArrayHolder.class, entity.getId() ); - assertNull( entity.getLongByteArray() ); - entity.setLongByteArray( original ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = s.get( LongByteArrayHolder.class, entity.getId() ); - Assert.assertEquals( ARRAY_SIZE, entity.getLongByteArray().length ); - assertEquals( original, entity.getLongByteArray() ); - entity.setLongByteArray( changed ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = s.get( LongByteArrayHolder.class, entity.getId() ); - Assert.assertEquals( ARRAY_SIZE, entity.getLongByteArray().length ); - assertEquals( changed, entity.getLongByteArray() ); - entity.setLongByteArray( null ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = s.get( LongByteArrayHolder.class, entity.getId() ); - assertNull( entity.getLongByteArray() ); - entity.setLongByteArray( empty ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = s.get( LongByteArrayHolder.class, entity.getId() ); - if ( entity.getLongByteArray() != null ) { - Assert.assertEquals( empty.length, entity.getLongByteArray().length ); - assertEquals( empty, entity.getLongByteArray() ); - } - s.delete( entity ); - s.getTransaction().commit(); - s.close(); - } - - @Test - public void testSaving() { - byte[] value = buildRecursively( ARRAY_SIZE, true ); - - Session s = openSession(); - s.beginTransaction(); - LongByteArrayHolder entity = new LongByteArrayHolder(); - entity.setLongByteArray( value ); - s.persist( entity ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = ( LongByteArrayHolder ) s.get( LongByteArrayHolder.class, entity.getId() ); - Assert.assertEquals( ARRAY_SIZE, entity.getLongByteArray().length ); - assertEquals( value, entity.getLongByteArray() ); - s.delete( entity ); - s.getTransaction().commit(); - s.close(); - } - - private byte[] buildRecursively(int size, boolean on) { - byte[] data = new byte[size]; - data[0] = mask( on ); - for ( int i = 0; i < size; i++ ) { - data[i] = mask( on ); - on = !on; - } - return data; - } - - private byte mask(boolean on) { - return on ? ( byte ) 1 : ( byte ) 0; - } - - public static void assertEquals(byte[] val1, byte[] val2) { - if ( !Arrays.equals( val1, val2 ) ) { - throw new AssertionFailedError( "byte arrays did not match" ); - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/LongStringTest.java b/hibernate-core/src/test/java/org/hibernate/test/lob/LongStringTest.java deleted file mode 100644 index 51380d658c..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/LongStringTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.lob; -import org.junit.Test; - -import org.hibernate.Session; -import org.hibernate.dialect.SybaseASE15Dialect; - -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -/** - * Tests eager materialization and mutation of long strings. - * - * @author Steve Ebersole - */ -@SuppressWarnings( {"UnusedDeclaration"}) -public abstract class LongStringTest extends BaseCoreFunctionalTestCase { - private static final int LONG_STRING_SIZE = 10000; - - @Test - public void testBoundedLongStringAccess() { - String original = buildRecursively( LONG_STRING_SIZE, 'x' ); - String changed = buildRecursively( LONG_STRING_SIZE, 'y' ); - String empty = ""; - - Session s = openSession(); - s.beginTransaction(); - LongStringHolder entity = new LongStringHolder(); - s.save( entity ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = ( LongStringHolder ) s.get( LongStringHolder.class, entity.getId() ); - assertNull( entity.getLongString() ); - entity.setLongString( original ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = ( LongStringHolder ) s.get( LongStringHolder.class, entity.getId() ); - assertEquals( LONG_STRING_SIZE, entity.getLongString().length() ); - assertEquals( original, entity.getLongString() ); - entity.setLongString( changed ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = ( LongStringHolder ) s.get( LongStringHolder.class, entity.getId() ); - assertEquals( LONG_STRING_SIZE, entity.getLongString().length() ); - assertEquals( changed, entity.getLongString() ); - entity.setLongString( null ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = ( LongStringHolder ) s.get( LongStringHolder.class, entity.getId() ); - assertNull( entity.getLongString() ); - entity.setLongString( empty ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - entity = ( LongStringHolder ) s.get( LongStringHolder.class, entity.getId() ); - if ( entity.getLongString() != null ) { - if(getDialect() instanceof SybaseASE15Dialect){ - //Sybase uses a single blank to denote an empty string (this is by design). So, when inserting an empty string '', it is interpreted as single blank ' '. - assertEquals( empty.length(), entity.getLongString().trim().length() ); - assertEquals( empty, entity.getLongString().trim() ); - }else{ - assertEquals( empty.length(), entity.getLongString().length() ); - assertEquals( empty, entity.getLongString() ); - } - } - s.delete( entity ); - s.getTransaction().commit(); - s.close(); - } - - private String buildRecursively(int size, char baseChar) { - StringBuilder buff = new StringBuilder(); - for( int i = 0; i < size; i++ ) { - buff.append( baseChar ); - } - return buff.toString(); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/PostgreSqlLobStringTest.java b/hibernate-core/src/test/java/org/hibernate/test/lob/PostgreSqlLobStringTest.java deleted file mode 100644 index bc096eee83..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/PostgreSqlLobStringTest.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.lob; - -import java.sql.Clob; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.List; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.Lob; -import jakarta.persistence.Table; - -import org.hibernate.dialect.PostgreSQLDialect; -import org.hibernate.query.Query; - -import org.hibernate.testing.*; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.testing.util.ExceptionUtil; -import org.junit.Test; - -import static org.hamcrest.core.Is.is; -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * @author Andrea Boriero - */ -@TestForIssue(jiraKey = "HHH-11614") -@RequiresDialect(PostgreSQLDialect.class) -public class PostgreSqlLobStringTest extends BaseCoreFunctionalTestCase { - - private final String value1 = "abc"; - private final String value2 = "def"; - private final String value3 = "ghi"; - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] {TestEntity.class}; - } - - @Override - protected void prepareTest() - throws Exception { - - doInHibernate( this::sessionFactory, session -> { - - session.doWork( connection -> { - try(PreparedStatement statement = connection.prepareStatement( - "insert \n" + - " into\n" + - " TEST_ENTITY\n" + - " (firstLobField, secondLobField, clobfield, id) \n" + - " values\n" + - " (?, ?, ?, -1)" - )) { - int index = 1; - statement.setString(index++, value1); - statement.setString(index++, value2); - statement.setString(index++, value3); - - assertEquals( 1, statement.executeUpdate() ); - } - } ); - } ); - } - - @Test - public void testBadClobDataSavedAsStringFails() { - try { - doInHibernate( this::sessionFactory, session -> { - final Query query = session.createQuery( "from TestEntity" ); - - final List results = query.list(); - - fail("Exception thrown expected"); - } ); - } - catch (Exception e) { - Exception rootException = (Exception) ExceptionUtil.rootCause( e ); - assertTrue( rootException.getMessage().startsWith( "Bad value for type long" ) ); - } - } - - @Test - public void testBadClobDataSavedAsStringworksAfterUpdate() { - doInHibernate( this::sessionFactory, session -> { - - session.doWork( connection -> { - try(Statement statement = connection.createStatement()) { - statement.executeUpdate( - "update test_entity\n" + - "set \n" + - " clobfield = lo_from_bytea(0, cast(clobfield as bytea)),\n" + - " firstlobfield = lo_from_bytea(0, cast(firstlobfield as bytea)),\n" + - " secondlobfield = lo_from_bytea(0, cast(secondlobfield as bytea))" - ); - } - } ); - } ); - - doInHibernate( this::sessionFactory, session -> { - final Query query = session.createQuery( "from TestEntity" ); - - final List results = query.list(); - - assertThat( results.size(), is( 1 ) ); - - final TestEntity testEntity = results.get( 0 ); - assertThat( testEntity.getFirstLobField(), is( value1 ) ); - assertThat( testEntity.getSecondLobField(), is( value2 ) ); - final Clob clobField = testEntity.getClobField(); - try { - - assertThat( clobField.getSubString( 1, (int) clobField.length() ), is( value3 ) ); - } - catch (SQLException e) { - fail( e.getMessage() ); - } - } ); - } - - @Entity(name = "TestEntity") - @Table(name = "TEST_ENTITY") - public static class TestEntity { - @Id - @GeneratedValue - private long id; - - @Lob - @Column - String firstLobField; - - @Lob - @Column - String secondLobField; - - @Lob - @Column - Clob clobField; - - public long getId() { - return id; - } - - public String getFirstLobField() { - return firstLobField; - } - - public void setFirstLobField(String firstLobField) { - this.firstLobField = firstLobField; - } - - public String getSecondLobField() { - return secondLobField; - } - - public void setSecondLobField(String secondLobField) { - this.secondLobField = secondLobField; - } - - public Clob getClobField() { - return clobField; - } - - public void setClobField(Clob clobField) { - this.clobField = clobField; - } - } - - @Override - protected boolean isCleanupTestDataRequired() { - return true; - } - - protected boolean isCleanupTestDataUsingBulkDelete() { - return true; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/SerializableTypeTest.java b/hibernate-core/src/test/java/org/hibernate/test/lob/SerializableTypeTest.java deleted file mode 100644 index f3b03632d7..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/SerializableTypeTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.lob; - -import org.junit.Test; - -import org.hibernate.Session; -import org.hibernate.dialect.SybaseASE15Dialect; -import org.hibernate.testing.SkipForDialect; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -/** - * Tests of {@link org.hibernate.type.SerializableType} - * - * @author Steve Ebersole - */ -public class SerializableTypeTest extends BaseCoreFunctionalTestCase { - public String[] getMappings() { - return new String[] { "lob/SerializableMappings.hbm.xml" }; - } - - public String getCacheConcurrencyStrategy() { - return null; - } - - @Test - @SkipForDialect( value = SybaseASE15Dialect.class, jiraKey = "HHH-6425") - public void testNewSerializableType() { - final String initialPayloadText = "Initial payload"; - final String changedPayloadText = "Changed payload"; - final String empty = ""; - - Session s = openSession(); - s.beginTransaction(); - SerializableHolder holder = new SerializableHolder(); - s.save( holder ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - holder = ( SerializableHolder ) s.get( SerializableHolder.class, holder.getId() ); - assertNull( holder.getSerialData() ); - holder.setSerialData( new SerializableData( initialPayloadText ) ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - holder = ( SerializableHolder ) s.get( SerializableHolder.class, holder.getId() ); - SerializableData serialData = ( SerializableData ) holder.getSerialData(); - assertEquals( initialPayloadText, serialData.getPayload() ); - holder.setSerialData( new SerializableData( changedPayloadText ) ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - holder = ( SerializableHolder ) s.get( SerializableHolder.class, holder.getId() ); - serialData = ( SerializableData ) holder.getSerialData(); - assertEquals( changedPayloadText, serialData.getPayload() ); - holder.setSerialData( null ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - holder = ( SerializableHolder ) s.get( SerializableHolder.class, holder.getId() ); - assertNull( holder.getSerialData() ); - holder.setSerialData( new SerializableData( empty ) ); - s.getTransaction().commit(); - s.close(); - - s = openSession(); - s.beginTransaction(); - holder = ( SerializableHolder ) s.get( SerializableHolder.class, holder.getId() ); - serialData = ( SerializableData ) holder.getSerialData(); - assertEquals( empty, serialData.getPayload() ); - s.delete( holder ); - s.getTransaction().commit(); - s.close(); - } - -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DialectFeatureChecks.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DialectFeatureChecks.java index a4589bc954..1535385e3a 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DialectFeatureChecks.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DialectFeatureChecks.java @@ -368,4 +368,10 @@ abstract public class DialectFeatureChecks { return dialect.currentTimestamp().startsWith( "current_timestamp" ); } } + + public static class ForceLobAsLastValue implements DialectFeatureCheck { + public boolean apply(Dialect dialect) { + return dialect.forceLobAsLastValue(); + } + } }