Skip to content

Commit ba8451e

Browse files
committed
HHH-17246 - Guard against Sybase being configured for truncating trailing zeros
Signed-off-by: Jan Schatteman <[email protected]>
1 parent 8ca2481 commit ba8451e

File tree

8 files changed

+193
-3
lines changed

8 files changed

+193
-3
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
import org.hibernate.type.descriptor.jdbc.JsonArrayAsStringJdbcType;
8989
import org.hibernate.type.descriptor.jdbc.JsonAsStringJdbcType;
9090
import org.hibernate.type.descriptor.jdbc.XmlAsStringJdbcType;
91+
import org.hibernate.type.descriptor.jdbc.UuidAsBinaryJdbcType;
9192
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
9293
import org.hibernate.type.descriptor.sql.DdlType;
9394
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
@@ -787,7 +788,7 @@ public void contributeType(CompositeUserType<?> type) {
787788
);
788789
}
789790
else {
790-
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.UUID, SqlTypes.BINARY );
791+
jdbcTypeRegistry.addDescriptorIfAbsent( UuidAsBinaryJdbcType.INSTANCE );
791792
}
792793

793794
final int preferredSqlTypeCodeForArray = getPreferredSqlTypeCodeForArray( serviceRegistry );

hibernate-core/src/main/java/org/hibernate/dialect/JsonHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ private static void convertedBasicValueToString(
245245
case SqlTypes.DECIMAL:
246246
case SqlTypes.NUMERIC:
247247
case SqlTypes.DURATION:
248-
case SqlTypes.UUID:
248+
case SqlTypes.UUID:
249249
// These types need to be serialized as JSON string, but don't have a need for escaping
250250
appender.append( '"' );
251251
javaType.appendEncodedString( appender, value );

hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import org.hibernate.type.JavaObjectType;
8383
import org.hibernate.type.NullType;
8484
import org.hibernate.type.StandardBasicTypes;
85+
import org.hibernate.type.descriptor.java.OracleUUIDJavaType;
8586
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
8687
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
8788
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
@@ -1033,6 +1034,8 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
10331034
)
10341035
);
10351036

1037+
typeContributions.contributeJavaType( OracleUUIDJavaType.INSTANCE );
1038+
10361039
if(getVersion().isSameOrAfter(23)) {
10371040
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration().getJdbcTypeRegistry();
10381041
jdbcTypeRegistry.addDescriptor(OracleEnumJdbcType.INSTANCE);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.type.descriptor.java;
6+
7+
import java.util.UUID;
8+
9+
/**
10+
* @author Jan Schatteman
11+
*/
12+
public class OracleUUIDJavaType extends UUIDJavaType {
13+
14+
/* This class is related to the changes that were made for HHH-17246 */
15+
16+
public static final OracleUUIDJavaType INSTANCE = new OracleUUIDJavaType();
17+
18+
@Override
19+
public String toString(UUID value) {
20+
return NoDashesStringTransformer.INSTANCE.transform( value );
21+
}
22+
23+
@Override
24+
public UUID fromString(CharSequence string) {
25+
return NoDashesStringTransformer.INSTANCE.parse( string.toString() );
26+
}
27+
}

hibernate-core/src/main/java/org/hibernate/type/descriptor/java/UUIDJavaType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public String toString(UUID value) {
4141
return ToStringTransformer.INSTANCE.transform( value );
4242
}
4343

44-
public UUID fromString(CharSequence string) {
44+
public UUID fromString(CharSequence string) {
4545
return ToStringTransformer.INSTANCE.parse( string.toString() );
4646
}
4747

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.type.descriptor.jdbc;
6+
7+
import org.hibernate.type.descriptor.ValueExtractor;
8+
import org.hibernate.type.descriptor.WrapperOptions;
9+
import org.hibernate.type.descriptor.java.JavaType;
10+
11+
import java.sql.CallableStatement;
12+
import java.sql.ResultSet;
13+
import java.sql.SQLException;
14+
import java.sql.Types;
15+
import java.util.Arrays;
16+
17+
import static org.hibernate.type.SqlTypes.UUID;
18+
19+
/**
20+
* @author Jan Schatteman
21+
*/
22+
public class UuidAsBinaryJdbcType extends BinaryJdbcType {
23+
24+
public static final UuidAsBinaryJdbcType INSTANCE = new UuidAsBinaryJdbcType();
25+
26+
@Override
27+
public int getDdlTypeCode() {
28+
return Types.BINARY;
29+
}
30+
31+
@Override
32+
public int getDefaultSqlTypeCode() {
33+
return UUID;
34+
}
35+
36+
@Override
37+
public <X> ValueExtractor<X> getExtractor( JavaType<X> javaType ) {
38+
return new BasicExtractor<>( javaType, this ) {
39+
@Override
40+
protected X doExtract( ResultSet rs, int paramIndex, WrapperOptions options ) throws SQLException {
41+
final byte[] bytes = rs.getBytes( paramIndex );
42+
return javaType.wrap( bytes == null || bytes.length == 16 ? bytes : Arrays.copyOf( bytes, 16 ), options );
43+
}
44+
45+
@Override
46+
protected X doExtract( CallableStatement statement, int index, WrapperOptions options ) throws SQLException {
47+
final byte[] bytes = statement.getBytes( index );
48+
return javaType.wrap( bytes == null || bytes.length == 16 ? bytes : Arrays.copyOf( bytes, 16 ), options );
49+
}
50+
51+
@Override
52+
protected X doExtract( CallableStatement statement, String name, WrapperOptions options )
53+
throws SQLException {
54+
final byte[] bytes = statement.getBytes( name );
55+
return javaType.wrap( bytes == null || bytes.length == 16 ? bytes : Arrays.copyOf( bytes, 16 ), options );
56+
}
57+
};
58+
}
59+
60+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.id.uuid;
6+
7+
import jakarta.persistence.Entity;
8+
import jakarta.persistence.Id;
9+
import org.hibernate.annotations.JdbcType;
10+
import org.hibernate.dialect.SybaseASEDialect;
11+
import org.hibernate.testing.orm.junit.DomainModel;
12+
import org.hibernate.testing.orm.junit.JiraKey;
13+
import org.hibernate.testing.orm.junit.RequiresDialect;
14+
import org.hibernate.testing.orm.junit.SessionFactory;
15+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
16+
import org.junit.jupiter.api.AfterEach;
17+
import org.junit.jupiter.api.BeforeEach;
18+
import org.junit.jupiter.api.Test;
19+
20+
import java.util.UUID;
21+
22+
import static org.junit.jupiter.api.Assertions.assertEquals;
23+
24+
/**
25+
* @author Jan Schatteman
26+
*/
27+
@RequiresDialect(value = SybaseASEDialect.class)
28+
@DomainModel(annotatedClasses = { SybaseASEUUIDTest.Book.class })
29+
@SessionFactory
30+
public class SybaseASEUUIDTest {
31+
32+
private static final UUID uuid = UUID.fromString("53886a8a-7082-4879-b430-25cb94415b00");
33+
34+
@BeforeEach
35+
void setUp(SessionFactoryScope scope) {
36+
scope.inTransaction( session -> {
37+
final Book book = new Book(uuid, "John Doe");
38+
session.persist( book );
39+
} );
40+
}
41+
42+
@AfterEach
43+
void tearDown(SessionFactoryScope scope) {
44+
scope.inTransaction(
45+
session -> session.createMutationQuery( "delete from Book" ).executeUpdate()
46+
);
47+
}
48+
49+
@Test
50+
@JiraKey( value = "HHH-17246" )
51+
public void testTrailingZeroByteTruncation(SessionFactoryScope scope) {
52+
scope.inSession(
53+
session -> assertEquals( 15, session.createNativeQuery("select id from Book", byte[].class).getSingleResult().length )
54+
);
55+
scope.inTransaction(
56+
session -> {
57+
Book b = session.createQuery( "from Book", Book.class ).getSingleResult();
58+
assertEquals(uuid, b.id);
59+
}
60+
);
61+
}
62+
63+
@Entity(name = "Book")
64+
static class Book {
65+
@Id
66+
// The purpose is to effectively provoke the trailing 0 bytes truncation
67+
@JdbcType( SybaseUuidAsVarbinaryJdbcType.class )
68+
UUID id;
69+
70+
String author;
71+
72+
public Book() {
73+
}
74+
75+
public Book(UUID id, String author) {
76+
this.id = id;
77+
this.author = author;
78+
}
79+
}
80+
81+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* SPDX-License-Identifier: LGPL-2.1-or-later
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.id.uuid;
6+
7+
import org.hibernate.type.descriptor.jdbc.UuidAsBinaryJdbcType;
8+
import java.sql.Types;
9+
10+
/**
11+
* @author Jan Schatteman
12+
*/
13+
public class SybaseUuidAsVarbinaryJdbcType extends UuidAsBinaryJdbcType {
14+
@Override
15+
public int getDdlTypeCode() {
16+
return Types.VARBINARY;
17+
}
18+
}

0 commit comments

Comments
 (0)