Skip to content

Commit 31ff2cc

Browse files
committed
HHH-16578 - Add a test that shows the more restrictive schema validation (less dependant on columnDefinition info, and more on the use of @JdbcTypeCode)
Signed-off-by: Jan Schatteman <jschatte@redhat.com>
1 parent a8ffff6 commit 31ff2cc

File tree

1 file changed

+266
-0
lines changed

1 file changed

+266
-0
lines changed
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
6+
*/
7+
package org.hibernate.orm.test.tool.schema;
8+
9+
import java.sql.Connection;
10+
import java.sql.SQLException;
11+
import java.sql.Statement;
12+
import java.sql.Types;
13+
import java.util.Map;
14+
15+
import org.hibernate.annotations.JdbcTypeCode;
16+
import org.hibernate.cfg.AvailableSettings;
17+
import org.hibernate.cfg.Environment;
18+
import org.hibernate.dialect.MySQLDialect;
19+
import org.hibernate.engine.config.spi.ConfigurationService;
20+
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
21+
import org.hibernate.internal.util.PropertiesHelper;
22+
import org.hibernate.tool.schema.internal.DefaultSchemaFilter;
23+
import org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl;
24+
import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool;
25+
import org.hibernate.tool.schema.internal.IndividuallySchemaValidatorImpl;
26+
import org.hibernate.tool.schema.spi.ContributableMatcher;
27+
import org.hibernate.tool.schema.spi.ExceptionHandler;
28+
import org.hibernate.tool.schema.spi.ExecutionOptions;
29+
import org.hibernate.tool.schema.spi.SchemaFilter;
30+
import org.hibernate.tool.schema.spi.SchemaManagementException;
31+
import org.hibernate.tool.schema.spi.SchemaManagementTool;
32+
import org.hibernate.tool.schema.spi.SchemaValidator;
33+
34+
import org.hibernate.testing.orm.junit.DomainModel;
35+
import org.hibernate.testing.orm.junit.JiraKey;
36+
import org.hibernate.testing.orm.junit.RequiresDialect;
37+
import org.hibernate.testing.orm.junit.ServiceRegistry;
38+
import org.hibernate.testing.orm.junit.SessionFactory;
39+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
40+
import org.hibernate.testing.orm.junit.Setting;
41+
import org.junit.jupiter.api.AfterAll;
42+
import org.junit.jupiter.api.BeforeAll;
43+
import org.junit.jupiter.api.Test;
44+
45+
import jakarta.persistence.Column;
46+
import jakarta.persistence.Entity;
47+
import jakarta.persistence.Id;
48+
import jakarta.persistence.Table;
49+
50+
import static org.junit.Assert.assertEquals;
51+
import static org.junit.jupiter.api.Assertions.fail;
52+
53+
/**
54+
* @author Jan Schatteman
55+
*/
56+
@ServiceRegistry(
57+
settings = {
58+
@Setting( name = AvailableSettings.HBM2DDL_AUTO, value = "none" )
59+
}
60+
)
61+
@DomainModel(
62+
annotatedClasses = {
63+
MySQLColumnValidationTest.TestEntity1.class,
64+
MySQLColumnValidationTest.TestEntity2.class,
65+
MySQLColumnValidationTest.TestEntity3.class
66+
}
67+
)
68+
@SessionFactory( exportSchema = false )
69+
@JiraKey( value = "HHH-16578" )
70+
@RequiresDialect( value = MySQLDialect.class )
71+
public class MySQLColumnValidationTest {
72+
73+
private DriverManagerConnectionProviderImpl connectionProvider;
74+
75+
@BeforeAll
76+
public void init() {
77+
connectionProvider = new DriverManagerConnectionProviderImpl();
78+
connectionProvider.configure( PropertiesHelper.map( Environment.getProperties() ) );
79+
80+
try( Connection connection = connectionProvider.getConnection();
81+
Statement statement = connection.createStatement() ) {
82+
83+
try {
84+
statement.execute( "DROP TABLE TEST_DATA1" );
85+
statement.execute( "DROP TABLE TEST_DATA2" );
86+
statement.execute( "DROP TABLE TEST_DATA3" );
87+
}
88+
catch (SQLException e) {
89+
}
90+
91+
statement.execute( "CREATE TABLE `TEST_DATA1` ( " +
92+
" `ID` int unsigned NOT NULL, " +
93+
" `INTEGRAL1` tinyint unsigned DEFAULT '0', " +
94+
" `INTEGRAL2` tinyint unsigned DEFAULT '0', " +
95+
" PRIMARY KEY (`ID`)" +
96+
") ENGINE=InnoDB" );
97+
98+
statement.execute( "CREATE TABLE `TEST_DATA2` ( " +
99+
" `ID` int unsigned NOT NULL, " +
100+
" `INTEGRAL1` tinyint unsigned DEFAULT '0', " +
101+
" PRIMARY KEY (`ID`)" +
102+
") ENGINE=InnoDB" );
103+
104+
statement.execute( "CREATE TABLE `TEST_DATA3` ( " +
105+
" `ID` int unsigned NOT NULL, " +
106+
" `INTEGRAL1` tinyint unsigned DEFAULT '0', " +
107+
" PRIMARY KEY (`ID`)" +
108+
") ENGINE=InnoDB" );
109+
110+
}
111+
catch (SQLException e) {
112+
fail(e.getMessage());
113+
}
114+
}
115+
116+
@AfterAll
117+
public void releaseResources() {
118+
try( Connection connection = connectionProvider.getConnection();
119+
Statement statement = connection.createStatement() ) {
120+
try {
121+
statement.execute( "DROP TABLE TEST_DATA1" );
122+
statement.execute( "DROP TABLE TEST_DATA2" );
123+
statement.execute( "DROP TABLE TEST_DATA3" );
124+
}
125+
catch (SQLException e) {
126+
}
127+
}
128+
catch (SQLException e) {
129+
fail(e.getMessage());
130+
}
131+
132+
connectionProvider.stop();
133+
}
134+
135+
@Test
136+
public void testValidateColumn(SessionFactoryScope scope) {
137+
scope.inTransaction(
138+
session -> {
139+
TestEntity1 te1 = new TestEntity1( 1, 1, 2 );
140+
session.persist( te1 );
141+
}
142+
);
143+
144+
ConfigurationService configurationService = scope.getSessionFactory().getServiceRegistry().getService(
145+
ConfigurationService.class );
146+
ExecutionOptions executionOptions = new ExecutionOptions() {
147+
@Override
148+
public boolean shouldManageNamespaces() {
149+
return true;
150+
}
151+
152+
@Override
153+
public Map getConfigurationValues() {
154+
return configurationService.getSettings();
155+
}
156+
157+
@Override
158+
public ExceptionHandler getExceptionHandler() {
159+
return ExceptionHandlerLoggedImpl.INSTANCE;
160+
}
161+
162+
@Override
163+
public SchemaFilter getSchemaFilter() {
164+
return SchemaFilter.ALL;
165+
}
166+
};
167+
168+
HibernateSchemaManagementTool hsmt = (HibernateSchemaManagementTool) scope.getSessionFactory()
169+
.getServiceRegistry()
170+
.getService( SchemaManagementTool.class );
171+
SchemaValidator schemaValidator = new IndividuallySchemaValidatorImpl( hsmt, DefaultSchemaFilter.INSTANCE );
172+
173+
try {
174+
schemaValidator.doValidation( scope.getMetadataImplementor(), executionOptions,
175+
contributed -> {
176+
return "test_data1".equalsIgnoreCase( contributed.getExportIdentifier() );
177+
} );
178+
}
179+
catch (SchemaManagementException e) {
180+
fail( e.getMessage() );
181+
}
182+
183+
try {
184+
schemaValidator.doValidation( scope.getMetadataImplementor(), executionOptions,
185+
contributed -> {
186+
return "test_data2".equalsIgnoreCase( contributed.getExportIdentifier() );
187+
} );
188+
fail( "SchemaManagementException expected" );
189+
}
190+
catch (SchemaManagementException e) {
191+
assertEquals(
192+
"Schema-validation: wrong column type encountered in column [integral1] in table [TEST_DATA2]; found [tinyint unsigned (Types#TINYINT)], but expecting [tinyint (Types#INTEGER)]",
193+
e.getMessage()
194+
);
195+
}
196+
197+
try {
198+
schemaValidator.doValidation( scope.getMetadataImplementor(), executionOptions,
199+
contributed -> {
200+
return "test_data3".equalsIgnoreCase( contributed.getExportIdentifier() );
201+
} );
202+
fail( "SchemaManagementException expected" );
203+
}
204+
catch (SchemaManagementException e) {
205+
assertEquals(
206+
"Schema-validation: wrong column type encountered in column [integral1] in table [TEST_DATA3]; found [tinyint unsigned (Types#TINYINT)], but expecting [tinyint unsigned default '0' (Types#INTEGER)]",
207+
e.getMessage()
208+
);
209+
}
210+
}
211+
212+
@Entity(name = "test_entity1")
213+
@Table(name = "TEST_DATA1")
214+
public static class TestEntity1 {
215+
@Id
216+
@Column(name = "id", columnDefinition = "INT(10) UNSIGNED NOT NULL")
217+
private Integer id;
218+
219+
@JdbcTypeCode( Types.TINYINT )
220+
@Column(name = "integral1", columnDefinition = "tinyint")
221+
private int integral1;
222+
223+
@JdbcTypeCode( Types.TINYINT )
224+
@Column(name = "integral2", columnDefinition = "tinyint UNSIGNED DEFAULT '0'")
225+
private int integral2;
226+
227+
public TestEntity1( Integer id, int integral1, int integral2 ) {
228+
this.id = id;
229+
this.integral1 = integral1;
230+
this.integral2 = integral2;
231+
}
232+
}
233+
234+
@Entity(name = "test_entity2")
235+
@Table(name = "TEST_DATA2")
236+
public static class TestEntity2 {
237+
@Id
238+
@Column(name = "id", columnDefinition = "INT(10) UNSIGNED NOT NULL")
239+
private Integer id;
240+
241+
@Column(name = "integral1", columnDefinition = "tinyint")
242+
private int integral1;
243+
244+
public TestEntity2( Integer id, int integral1 ) {
245+
this.id = id;
246+
this.integral1 = integral1;
247+
}
248+
}
249+
250+
@Entity(name = "test_entity3")
251+
@Table(name = "TEST_DATA3")
252+
public static class TestEntity3 {
253+
@Id
254+
@Column(name = "id", columnDefinition = "INT(10) UNSIGNED NOT NULL")
255+
private Integer id;
256+
257+
@Column(name = "integral1", columnDefinition = "tinyint UNSIGNED DEFAULT '0'")
258+
private int integral1;
259+
260+
public TestEntity3( Integer id, int integral1 ) {
261+
this.id = id;
262+
this.integral1 = integral1;
263+
}
264+
}
265+
266+
}

0 commit comments

Comments
 (0)