Skip to content

Commit 44e6b45

Browse files
HHH-14711 unsigned types causing out of range on MySQL/MariaDB
1 parent 6c573e9 commit 44e6b45

File tree

3 files changed

+188
-0
lines changed

3 files changed

+188
-0
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,10 @@ protected boolean isLob(int sqlTypeCode) {
448448
};
449449
}
450450

451+
protected boolean isUnsigned(String columnTypeName) {
452+
return columnTypeName.contains( "UNSIGNED" );
453+
}
454+
451455
private DdlTypeImpl simpleSqlType(int sqlTypeCode) {
452456
return new DdlTypeImpl(
453457
sqlTypeCode,

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,33 @@ public JdbcType resolveSqlTypeDescriptor(
534534
jdbcTypeCode = GEOMETRY;
535535
}
536536
break;
537+
case Types.TINYINT:
538+
if ( isUnsigned( columnTypeName ) ) {
539+
return jdbcTypeRegistry.getDescriptor( Types.SMALLINT );
540+
}
541+
break;
542+
case Types.SMALLINT:
543+
if ( isUnsigned( columnTypeName ) ) {
544+
return columnTypeName.contains( "TINYINT" ) ? jdbcTypeRegistry.getDescriptor( Types.SMALLINT )
545+
: jdbcTypeRegistry.getDescriptor( Types.INTEGER );
546+
}
547+
break;
548+
case Types.INTEGER:
549+
if ( isUnsigned( columnTypeName ) ) {
550+
if ( columnTypeName.contains( "SMALLINT" ) ) {
551+
return jdbcTypeRegistry.getDescriptor( Types.INTEGER );
552+
}
553+
else if ( !columnTypeName.contains( "MEDIUMINT" ) ) {
554+
return jdbcTypeRegistry.getDescriptor( Types.BIGINT );
555+
}
556+
}
557+
break;
558+
case Types.BIGINT:
559+
if ( isUnsigned( columnTypeName ) ) {
560+
return columnTypeName.contains( "INTEGER" ) ? jdbcTypeRegistry.getDescriptor( Types.BIGINT )
561+
: jdbcTypeRegistry.getDescriptor( Types.NUMERIC );
562+
}
563+
break;
537564
}
538565
return super.resolveSqlTypeDescriptor(
539566
columnTypeName,
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.orm.test.type;
6+
7+
import jakarta.persistence.Column;
8+
import jakarta.persistence.Entity;
9+
import jakarta.persistence.GeneratedValue;
10+
import jakarta.persistence.Id;
11+
import org.hibernate.dialect.MariaDBDialect;
12+
import org.hibernate.dialect.MySQLDialect;
13+
import org.hibernate.testing.orm.junit.DomainModel;
14+
import org.hibernate.testing.orm.junit.JiraKey;
15+
import org.hibernate.testing.orm.junit.RequiresDialect;
16+
import org.hibernate.testing.orm.junit.SessionFactory;
17+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
18+
import org.junit.jupiter.api.AfterAll;
19+
import org.junit.jupiter.api.Test;
20+
21+
import java.math.BigDecimal;
22+
23+
import static org.junit.jupiter.api.Assertions.assertEquals;
24+
25+
@SessionFactory
26+
@DomainModel(annotatedClasses = {
27+
UnsignedJdbcTypeTest.AccountTinyint.class,
28+
UnsignedJdbcTypeTest.AccountSmallint.class,
29+
UnsignedJdbcTypeTest.AccountMediumint.class,
30+
UnsignedJdbcTypeTest.AccountInteger.class,
31+
UnsignedJdbcTypeTest.AccountBigint.class,
32+
})
33+
@JiraKey("HHH-14711")
34+
@RequiresDialect(MySQLDialect.class)
35+
@RequiresDialect(MariaDBDialect.class)
36+
public class UnsignedJdbcTypeTest {
37+
38+
@Test
39+
void testUnsignedTinyint(SessionFactoryScope scope) {
40+
scope.inTransaction( session -> {
41+
short value = 255;
42+
session.createNativeMutationQuery( "insert into AccountTinyint (id,balance) values(1," + value + ")" )
43+
.executeUpdate();
44+
short result = (short) session.createNativeQuery( "select balance from AccountTinyint" )
45+
.getSingleResult();
46+
assertEquals( value, result );
47+
} );
48+
}
49+
50+
@Test
51+
void testUnsignedSmallint(SessionFactoryScope scope) {
52+
scope.inTransaction( session -> {
53+
int value = 65535;
54+
session.createNativeMutationQuery( "insert into AccountSmallint (id,balance) values(1," + value + ")" )
55+
.executeUpdate();
56+
int result = (int) session.createNativeQuery( "select balance from AccountSmallint" )
57+
.getSingleResult();
58+
assertEquals( value, result );
59+
} );
60+
}
61+
62+
@Test
63+
void testUnsignedMediumint(SessionFactoryScope scope) {
64+
scope.inTransaction( session -> {
65+
int value = 16777215;
66+
session.createNativeMutationQuery( "insert into AccountMediumint (id,balance) values(1," + value + ")" )
67+
.executeUpdate();
68+
int result = (int) session.createNativeQuery( "select balance from AccountMediumint" )
69+
.getSingleResult();
70+
assertEquals( value, result );
71+
} );
72+
}
73+
74+
@Test
75+
void testUnsignedInteger(SessionFactoryScope scope) {
76+
scope.inTransaction( session -> {
77+
long value = 4294967295l;
78+
session.createNativeMutationQuery( "insert into AccountInteger (id,balance) values(1," + value + ")" )
79+
.executeUpdate();
80+
long result = (long) session.createNativeQuery( "select balance from AccountInteger" )
81+
.getSingleResult();
82+
assertEquals( value, result );
83+
} );
84+
}
85+
86+
@Test
87+
void testUnsignedBigint(SessionFactoryScope scope) {
88+
scope.inTransaction( session -> {
89+
BigDecimal value = new BigDecimal( "18446744073709551615" );
90+
session.createNativeMutationQuery( "insert into AccountBigint (id,balance) values(1," + value + ")" )
91+
.executeUpdate();
92+
BigDecimal result = (BigDecimal) session.createNativeQuery( "select balance from AccountBigint" )
93+
.getSingleResult();
94+
assertEquals( value, result );
95+
} );
96+
}
97+
98+
@AfterAll
99+
public void dropTestData(SessionFactoryScope scope) {
100+
scope.dropData();
101+
}
102+
103+
@Entity(name = "AccountTinyint")
104+
public static class AccountTinyint {
105+
106+
@Id
107+
@GeneratedValue
108+
long id;
109+
110+
@Column(columnDefinition = "tinyint unsigned")
111+
short balance;
112+
}
113+
114+
@Entity(name = "AccountSmallint")
115+
public static class AccountSmallint {
116+
117+
@Id
118+
@GeneratedValue
119+
long id;
120+
121+
@Column(columnDefinition = "smallint unsigned")
122+
short balance;
123+
}
124+
125+
@Entity(name = "AccountMediumint")
126+
public static class AccountMediumint {
127+
128+
@Id
129+
@GeneratedValue
130+
long id;
131+
132+
@Column(columnDefinition = "mediumint unsigned")
133+
short balance;
134+
}
135+
136+
@Entity(name = "AccountInteger")
137+
public static class AccountInteger {
138+
139+
@Id
140+
@GeneratedValue
141+
long id;
142+
143+
@Column(columnDefinition = "integer unsigned")
144+
long balance;
145+
}
146+
147+
@Entity(name = "AccountBigint")
148+
public static class AccountBigint {
149+
150+
@Id
151+
@GeneratedValue
152+
long id;
153+
154+
@Column(columnDefinition = "bigint unsigned")
155+
long balance;
156+
}
157+
}

0 commit comments

Comments
 (0)