HHH-14211 Switch to using oid for CLOB in PostgreSQL to avoid losing data after vacuumlo

This commit is contained in:
Christian Beikov 2021-12-06 19:19:33 +01:00
parent 0f46ee2466
commit e1a976bce0
2 changed files with 27 additions and 19 deletions

View File

@ -125,7 +125,7 @@ public class PostgreSQLDialect extends Dialect {
//use oid as the blob type on Postgres because //use oid as the blob type on Postgres because
//the JDBC driver is rubbish //the JDBC driver is rubbish
registerColumnType( Types.BLOB, "oid" ); registerColumnType( Types.BLOB, "oid" );
registerColumnType( Types.CLOB, "text" ); registerColumnType( Types.CLOB, "oid" );
//there are no nchar/nvarchar types in Postgres //there are no nchar/nvarchar types in Postgres
registerColumnType( Types.NCHAR, "char($l)" ); registerColumnType( Types.NCHAR, "char($l)" );

View File

@ -21,6 +21,7 @@ import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.util.ExceptionUtil; import org.hibernate.testing.util.ExceptionUtil;
import org.junit.Assert;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -69,9 +70,9 @@ public class PostgreSqlLobStringTest {
" (?, ?, ?, -1)" " (?, ?, ?, -1)"
)) { )) {
int index = 1; int index = 1;
statement.setString( index++, value1 ); statement.setClob( index++, session.getLobHelper().createClob( value1 ) );
statement.setString( index++, value2 ); statement.setClob( index++, session.getLobHelper().createClob( value2 ) );
statement.setString( index++, value3 ); statement.setClob( index++, session.getLobHelper().createClob( value3 ) );
assertEquals( 1, statement.executeUpdate() ); assertEquals( 1, statement.executeUpdate() );
} }
@ -81,21 +82,28 @@ public class PostgreSqlLobStringTest {
@Test @Test
public void testBadClobDataSavedAsStringFails(SessionFactoryScope scope) { public void testBadClobDataSavedAsStringFails(SessionFactoryScope scope) {
try {
scope.inTransaction( scope.inTransaction(
session -> { session -> {
final Query query = session.createQuery( "from TestEntity" ); final Query query = session.createQuery( "from TestEntity" );
final List<TestEntity> results = query.list(); final List<TestEntity> results = query.list();
fail( "Exception thrown expected" ); 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 (Exception e) { catch (SQLException e) {
Exception rootException = (Exception) ExceptionUtil.rootCause( e ); fail( e.getMessage() );
assertTrue( rootException.getMessage().startsWith( "Bad value for type long" ) );
} }
} }
);
}
@Test @Test
public void testBadClobDataSavedAsStringworksAfterUpdate(SessionFactoryScope scope) { public void testBadClobDataSavedAsStringworksAfterUpdate(SessionFactoryScope scope) {
@ -107,9 +115,9 @@ public class PostgreSqlLobStringTest {
statement.executeUpdate( statement.executeUpdate(
"update test_entity\n" + "update test_entity\n" +
"set \n" + "set \n" +
" clobfield = lo_from_bytea(0, cast(clobfield as bytea)),\n" + " clobfield = lo_from_bytea(0, lo_get(clobfield)),\n" +
" firstlobfield = lo_from_bytea(0, cast(firstlobfield as bytea)),\n" + " firstlobfield = lo_from_bytea(0, lo_get(firstlobfield)),\n" +
" secondlobfield = lo_from_bytea(0, cast(secondlobfield as bytea))" " secondlobfield = lo_from_bytea(0, lo_get(secondlobfield))"
); );
} }
} ); } );