Skip to content

Commit d0ce380

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

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
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.exception.DataException;
14+
import org.hibernate.testing.orm.junit.DomainModel;
15+
import org.hibernate.testing.orm.junit.JiraKey;
16+
import org.hibernate.testing.orm.junit.RequiresDialect;
17+
import org.hibernate.testing.orm.junit.SessionFactory;
18+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
19+
import org.hibernate.testing.orm.junit.SkipForDialect;
20+
import org.hibernate.type.StandardBasicTypes;
21+
import org.junit.jupiter.api.AfterEach;
22+
import org.junit.jupiter.api.Test;
23+
24+
import java.math.BigDecimal;
25+
26+
import static org.junit.jupiter.api.Assertions.assertEquals;
27+
import static org.junit.jupiter.api.Assertions.assertThrows;
28+
29+
/**
30+
* HHH-14711 reported a bug (out-of-range) when using unsigned numeric types with native queries
31+
* we do not fix this, because
32+
* - a fix would be a breaking change
33+
* - using e.g. addScalar can be used as a simple workaround
34+
* - unsigned numeric types are not standard
35+
* note: the MariaDB implementation differs from MySQL
36+
*/
37+
@SessionFactory
38+
@DomainModel(annotatedClasses = {UnsignedJdbcTypeTest.Account.class})
39+
@JiraKey("HHH-14711")
40+
public class UnsignedJdbcTypeTest {
41+
42+
@Test
43+
@RequiresDialect(value = MariaDBDialect.class, matchSubTypes = false)
44+
void testUnsignedMariaDB(SessionFactoryScope scope) {
45+
46+
scope.inTransaction( session -> {
47+
48+
short balanceTinyint = 255;
49+
int balanceSmallint = 65535;
50+
int balanceMediumint = 16777215;
51+
long balanceInteger = 4294967295L;
52+
BigDecimal balanceBigint = new BigDecimal( "18446744073709551615" );
53+
54+
session.createNativeMutationQuery( """
55+
insert into Account (id,balanceTinyint,balanceSmallint,balanceMediumint,
56+
balanceInteger,balanceBigint)
57+
values(1,:balanceTinyint,:balanceSmallint,:balanceMediumint,
58+
:balanceInteger,:balanceBigint)
59+
""" )
60+
.setParameter( "balanceTinyint", balanceTinyint )
61+
.setParameter( "balanceSmallint", balanceSmallint )
62+
.setParameter( "balanceMediumint", balanceMediumint )
63+
.setParameter( "balanceInteger", balanceInteger )
64+
.setParameter( "balanceBigint", balanceBigint )
65+
.executeUpdate();
66+
67+
// what works with MariaDB
68+
assertEquals( balanceTinyint, session.createNativeQuery( "select balanceTinyint from Account" )
69+
.getSingleResult() );
70+
assertEquals( balanceSmallint, session.createNativeQuery( "select balanceSmallint from Account" )
71+
.getSingleResult() );
72+
assertEquals( balanceMediumint, session.createNativeQuery( "select balanceMediumint from Account" )
73+
.getSingleResult() );
74+
assertEquals( balanceInteger, session.createNativeQuery( "select balanceInteger from Account" )
75+
.getSingleResult() );
76+
77+
// what doesn't work + workaround
78+
assertThrows( DataException.class, () -> session.createNativeQuery( "select balanceBigint from Account" )
79+
.getSingleResult() );
80+
assertEquals( balanceBigint, session.createNativeQuery( "select balanceBigint from Account" )
81+
.addScalar( "balanceBigint", StandardBasicTypes.BIG_DECIMAL )
82+
.getSingleResult() );
83+
} );
84+
}
85+
86+
@Test
87+
@RequiresDialect(MySQLDialect.class)
88+
@SkipForDialect(dialectClass = MariaDBDialect.class)
89+
void testUnsignedMySQL(SessionFactoryScope scope) {
90+
91+
scope.inTransaction( session -> {
92+
93+
short balanceTinyint = 255;
94+
int balanceSmallint = 65535;
95+
int balanceMediumint = 16777215;
96+
long balanceInteger = 4294967295L;
97+
BigDecimal balanceBigint = new BigDecimal( "18446744073709551615" );
98+
99+
session.createNativeMutationQuery( """
100+
insert into Account (id,balanceTinyint,balanceSmallint,balanceMediumint,
101+
balanceInteger,balanceBigint)
102+
values(1,:balanceTinyint,:balanceSmallint,:balanceMediumint,
103+
:balanceInteger,:balanceBigint)
104+
""" )
105+
.setParameter( "balanceTinyint", balanceTinyint )
106+
.setParameter( "balanceSmallint", balanceSmallint )
107+
.setParameter( "balanceMediumint", balanceMediumint )
108+
.setParameter( "balanceInteger", balanceInteger )
109+
.setParameter( "balanceBigint", balanceBigint )
110+
.executeUpdate();
111+
112+
// what works with MySQL
113+
assertEquals( balanceMediumint, session.createNativeQuery( "select balanceMediumint from Account" )
114+
.getSingleResult() );
115+
116+
// what doesn't work + workaround
117+
assertThrows( DataException.class, () -> session.createNativeQuery( "select balanceTinyint from Account" )
118+
.getSingleResult() );
119+
assertEquals( balanceTinyint, session.createNativeQuery( "select balanceTinyint from Account" )
120+
.addScalar( "balanceTinyint", StandardBasicTypes.SHORT )
121+
.getSingleResult() );
122+
123+
assertThrows( DataException.class, () -> session.createNativeQuery( "select balanceSmallint from Account" )
124+
.getSingleResult() );
125+
assertEquals( balanceSmallint, session.createNativeQuery( "select balanceSmallint from Account" )
126+
.addScalar( "balanceSmallint", StandardBasicTypes.INTEGER )
127+
.getSingleResult() );
128+
129+
assertThrows( DataException.class, () -> session.createNativeQuery( "select balanceInteger from Account" )
130+
.getSingleResult() );
131+
assertEquals( balanceInteger, session.createNativeQuery( "select balanceInteger from Account" )
132+
.addScalar( "balanceInteger", StandardBasicTypes.LONG )
133+
.getSingleResult() );
134+
135+
assertThrows( DataException.class, () -> session.createNativeQuery( "select balanceBigint from Account" )
136+
.getSingleResult() );
137+
assertEquals( balanceBigint, session.createNativeQuery( "select balanceBigint from Account" )
138+
.addScalar( "balanceBigint", StandardBasicTypes.BIG_DECIMAL )
139+
.getSingleResult() );
140+
} );
141+
}
142+
143+
@AfterEach
144+
public void dropTestData(SessionFactoryScope scope) {
145+
scope.dropData();
146+
}
147+
148+
@Entity(name = "Account")
149+
public static class Account {
150+
151+
@Id
152+
@GeneratedValue
153+
long id;
154+
155+
@Column(columnDefinition = "tinyint unsigned")
156+
short balanceTinyint;
157+
158+
@Column(columnDefinition = "smallint unsigned")
159+
short balanceSmallint;
160+
161+
@Column(columnDefinition = "mediumint unsigned")
162+
short balanceMediumint;
163+
164+
@Column(columnDefinition = "integer unsigned")
165+
long balanceInteger;
166+
167+
@Column(columnDefinition = "bigint unsigned")
168+
long balanceBigint;
169+
}
170+
}

0 commit comments

Comments
 (0)