Re-enabled additional tests

This commit is contained in:
Andrea Boriero 2021-10-12 14:38:26 +02:00 committed by Andrea Boriero
parent 6745f71f88
commit 67c2c51d47
31 changed files with 1122 additions and 990 deletions

View File

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

View File

@ -9,7 +9,7 @@
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.lob">
<hibernate-mapping package="org.hibernate.orm.test.lob">
<class name="LongByteArrayHolder" table="LOB_ENTITY_IMAGE">
<id name="id" type="long" column="ID">

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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" };
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}
}
}

View File

@ -9,7 +9,7 @@
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.lob">
<hibernate-mapping package="org.hibernate.orm.test.lob">
<class name="LobAsLastValueEntity">
<id name="id" type="integer">

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.lob;
package org.hibernate.orm.test.lob;
import java.io.Serializable;
import java.util.Objects;

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 );
} );
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.lob;
package org.hibernate.orm.test.lob;
import java.sql.Blob;

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<TestEntity> 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<TestEntity> 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<String> 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<String> 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<byte[]> 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();
}
}

View File

@ -7,7 +7,7 @@
//$Id: $
package org.hibernate.test.lob;
package org.hibernate.orm.test.lob;
/**

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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" );
}
}
}

View File

@ -7,7 +7,7 @@
//$Id: $
package org.hibernate.test.lob;
package org.hibernate.orm.test.lob;
/**

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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();
}
}

View File

@ -9,7 +9,7 @@
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.lob">
<hibernate-mapping package="org.hibernate.orm.test.lob">
<class name="LongByteArrayHolder" table="LOB_ENTITY_MAT_BLOB">
<id name="id" type="long" column="ID">

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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" };
}
}

View File

@ -9,7 +9,7 @@
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.lob">
<hibernate-mapping package="org.hibernate.orm.test.lob">
<class name="LongStringHolder" table="LOB_ENTITY_MAT_CLOB">
<id name="id" type="long" column="ID">

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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" };
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<TestEntity> 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<TestEntity> 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;
// }
}

View File

@ -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;
/**

View File

@ -7,7 +7,7 @@
//$Id: $
package org.hibernate.test.lob;
package org.hibernate.orm.test.lob;
import java.io.Serializable;
/**

View File

@ -9,7 +9,7 @@
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.lob">
<hibernate-mapping package="org.hibernate.orm.test.lob">
<!-- HHH-7734: Don't use LOB_ENTITY as the table name. Others use it
and there were some odd locking issue with 1 version of Oracle. -->

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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 );
}
);
}
}

View File

@ -9,7 +9,7 @@
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.test.lob">
<hibernate-mapping package="org.hibernate.orm.test.lob">
<class name="LongStringHolder" table="LOB_ENTITY_TEXT">
<id name="id" type="long" column="ID">

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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" };
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<TestEntity> 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<TestEntity> 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<String> 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<String> 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<byte[]> 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();
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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" );
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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();
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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<TestEntity> 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<TestEntity> 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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
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();
}
}

View File

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