Skip to content

Commit

Permalink
HHH-17246 - Guard against Sybase being configured for truncating trai…
Browse files Browse the repository at this point in the history
…ling zeros

Signed-off-by: Jan Schatteman <[email protected]>
  • Loading branch information
jrenaat authored and beikov committed Nov 13, 2024
1 parent f468d92 commit a5fa3e4
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
import org.hibernate.type.descriptor.jdbc.XmlArrayJdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.XmlAsStringArrayJdbcTypeConstructor;
import org.hibernate.type.descriptor.jdbc.XmlAsStringJdbcType;
import org.hibernate.type.descriptor.jdbc.UuidAsBinaryJdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.descriptor.sql.DdlType;
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
Expand Down Expand Up @@ -752,7 +753,7 @@ public void contributeType(CompositeUserType<?> type) {
);
}
else {
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.UUID, SqlTypes.BINARY );
jdbcTypeRegistry.addDescriptorIfAbsent( UuidAsBinaryJdbcType.INSTANCE );
}

jdbcTypeRegistry.addDescriptorIfAbsent( JsonAsStringJdbcType.VARCHAR_INSTANCE );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ private static void convertedBasicValueToString(
case SqlTypes.DECIMAL:
case SqlTypes.NUMERIC:
case SqlTypes.DURATION:
case SqlTypes.UUID:
case SqlTypes.UUID:
// These types need to be serialized as JSON string, but don't have a need for escaping
appender.append( '"' );
javaType.appendEncodedString( appender, value );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.NullType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.OracleUUIDJavaType;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
Expand Down Expand Up @@ -1041,6 +1042,8 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
)
);

typeContributions.contributeJavaType( OracleUUIDJavaType.INSTANCE );

if(getVersion().isSameOrAfter(23)) {
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration().getJdbcTypeRegistry();
jdbcTypeRegistry.addDescriptor(OracleEnumJdbcType.INSTANCE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
import static org.hibernate.type.SqlTypes.TINYINT;
import static org.hibernate.type.SqlTypes.UUID;
import static org.hibernate.type.SqlTypes.VARBINARY;

public class OracleAggregateSupport extends AggregateSupportImpl {
Expand Down Expand Up @@ -209,6 +210,7 @@ public String aggregateComponentCustomReadExpression(
case BINARY:
case VARBINARY:
case LONG32VARBINARY:
case UUID:
return template.replace(
placeholder,
jdbcType.getSqlTypeName() + "_from_json(json_query(" + parentPartExpression + columnExpression + "' returning " + jsonTypeName + "))"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.type.descriptor.java;

import java.util.UUID;

/**
* @author Jan Schatteman
*/
public class OracleUUIDJavaType extends UUIDJavaType {

/* This class is related to the changes that were made for HHH-17246 */

public static final OracleUUIDJavaType INSTANCE = new OracleUUIDJavaType();

@Override
public String toString(UUID value) {
return NoDashesStringTransformer.INSTANCE.transform( value );
}

@Override
public UUID fromString(CharSequence string) {
return NoDashesStringTransformer.INSTANCE.parse( string.toString() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ public boolean useObjectEqualsHashCode() {
return true;
}

@Override
public String toString(UUID value) {
return ToStringTransformer.INSTANCE.transform( value );
}

@Override
public UUID fromString(CharSequence string) {
return ToStringTransformer.INSTANCE.parse( string.toString() );
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.type.descriptor.jdbc;

import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;

import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Arrays;

import static org.hibernate.type.SqlTypes.UUID;

/**
* @author Jan Schatteman
*/
public class UuidAsBinaryJdbcType extends BinaryJdbcType {

public static final UuidAsBinaryJdbcType INSTANCE = new UuidAsBinaryJdbcType();

@Override
public int getDdlTypeCode() {
return Types.BINARY;
}

@Override
public int getDefaultSqlTypeCode() {
return UUID;
}

@Override
public <X> ValueExtractor<X> getExtractor( JavaType<X> javaType ) {
return new BasicExtractor<>( javaType, this ) {
@Override
protected X doExtract( ResultSet rs, int paramIndex, WrapperOptions options ) throws SQLException {
final byte[] bytes = rs.getBytes( paramIndex );
return javaType.wrap( bytes == null || bytes.length == 16 ? bytes : Arrays.copyOf( bytes, 16 ), options );
}

@Override
protected X doExtract( CallableStatement statement, int index, WrapperOptions options ) throws SQLException {
final byte[] bytes = statement.getBytes( index );
return javaType.wrap( bytes == null || bytes.length == 16 ? bytes : Arrays.copyOf( bytes, 16 ), options );
}

@Override
protected X doExtract( CallableStatement statement, String name, WrapperOptions options )
throws SQLException {
final byte[] bytes = statement.getBytes( name );
return javaType.wrap( bytes == null || bytes.length == 16 ? bytes : Arrays.copyOf( bytes, 16 ), options );
}
};
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.id.uuid;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.annotations.JdbcType;
import org.hibernate.dialect.SybaseASEDialect;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.RequiresDialect;
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 java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author Jan Schatteman
*/
@RequiresDialect(value = SybaseASEDialect.class)
@DomainModel(annotatedClasses = { SybaseASEUUIDTest.Book.class })
@SessionFactory
public class SybaseASEUUIDTest {

private static final UUID uuid = UUID.fromString("53886a8a-7082-4879-b430-25cb94415b00");

@BeforeEach
void setUp(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final Book book = new Book(uuid, "John Doe");
session.persist( book );
} );
}

@AfterEach
void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> session.createMutationQuery( "delete from Book" ).executeUpdate()
);
}

@Test
@JiraKey( value = "HHH-17246" )
public void testTrailingZeroByteTruncation(SessionFactoryScope scope) {
scope.inSession(
session -> assertEquals( 15, session.createNativeQuery("select id from Book", byte[].class).getSingleResult().length )
);
scope.inTransaction(
session -> {
Book b = session.createQuery( "from Book", Book.class ).getSingleResult();
assertEquals(uuid, b.id);
}
);
}

@Entity(name = "Book")
static class Book {
@Id
// The purpose is to effectively provoke the trailing 0 bytes truncation
@JdbcType( SybaseUuidAsVarbinaryJdbcType.class )
UUID id;

String author;

public Book() {
}

public Book(UUID id, String author) {
this.id = id;
this.author = author;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.test.id.uuid;

import org.hibernate.type.descriptor.jdbc.UuidAsBinaryJdbcType;
import java.sql.Types;

/**
* @author Jan Schatteman
*/
public class SybaseUuidAsVarbinaryJdbcType extends UuidAsBinaryJdbcType {
@Override
public int getDdlTypeCode() {
return Types.VARBINARY;
}
}

0 comments on commit a5fa3e4

Please sign in to comment.