Skip to content

Commit 4947af9

Browse files
committed
Add an optional getMinimumSupportedVersion() to Dialect, for validation purposes
Signed-off-by: Jan Schatteman <jschatte@redhat.com>
1 parent a488e1a commit 4947af9

File tree

3 files changed

+156
-7
lines changed

3 files changed

+156
-7
lines changed

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

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.hibernate.LockMode;
4242
import org.hibernate.LockOptions;
4343
import org.hibernate.NotYetImplementedFor6Exception;
44-
import org.hibernate.query.Query;
4544
import org.hibernate.ScrollMode;
4645
import org.hibernate.boot.TempTableDdlTransactionHandling;
4746
import org.hibernate.boot.model.TypeContributions;
@@ -96,6 +95,7 @@
9695
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
9796
import org.hibernate.exception.spi.SQLExceptionConverter;
9897
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
98+
import org.hibernate.internal.CoreMessageLogger;
9999
import org.hibernate.internal.util.MathHelper;
100100
import org.hibernate.internal.util.StringHelper;
101101
import org.hibernate.internal.util.collections.ArrayHelper;
@@ -110,15 +110,16 @@
110110
import org.hibernate.persister.entity.Lockable;
111111
import org.hibernate.procedure.internal.StandardCallableStatementSupport;
112112
import org.hibernate.procedure.spi.CallableStatementSupport;
113+
import org.hibernate.query.Query;
114+
import org.hibernate.query.hql.HqlTranslator;
115+
import org.hibernate.query.spi.QueryEngine;
116+
import org.hibernate.query.spi.QueryOptions;
113117
import org.hibernate.query.sqm.CastType;
114118
import org.hibernate.query.sqm.FetchClauseType;
115119
import org.hibernate.query.sqm.IntervalType;
116120
import org.hibernate.query.sqm.NullOrdering;
117121
import org.hibernate.query.sqm.TemporalUnit;
118122
import org.hibernate.query.sqm.TrimSpec;
119-
import org.hibernate.query.hql.HqlTranslator;
120-
import org.hibernate.query.spi.QueryEngine;
121-
import org.hibernate.query.spi.QueryOptions;
122123
import org.hibernate.query.sqm.mutation.internal.temptable.AfterUseAction;
123124
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
124125
import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableInsertStrategy;
@@ -165,12 +166,49 @@
165166
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
166167
import org.hibernate.type.spi.TypeConfiguration;
167168

169+
import org.jboss.logging.Logger;
170+
168171
import jakarta.persistence.TemporalType;
169172

170173
import static java.lang.Math.ceil;
171174
import static java.lang.Math.log;
172175
import static org.hibernate.internal.util.StringHelper.parseCommaSeparatedString;
173-
import static org.hibernate.type.SqlTypes.*;
176+
import static org.hibernate.type.SqlTypes.ARRAY;
177+
import static org.hibernate.type.SqlTypes.BIGINT;
178+
import static org.hibernate.type.SqlTypes.BINARY;
179+
import static org.hibernate.type.SqlTypes.BLOB;
180+
import static org.hibernate.type.SqlTypes.BOOLEAN;
181+
import static org.hibernate.type.SqlTypes.CHAR;
182+
import static org.hibernate.type.SqlTypes.CLOB;
183+
import static org.hibernate.type.SqlTypes.DATE;
184+
import static org.hibernate.type.SqlTypes.DECIMAL;
185+
import static org.hibernate.type.SqlTypes.DOUBLE;
186+
import static org.hibernate.type.SqlTypes.FLOAT;
187+
import static org.hibernate.type.SqlTypes.INTEGER;
188+
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
189+
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
190+
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
191+
import static org.hibernate.type.SqlTypes.NCHAR;
192+
import static org.hibernate.type.SqlTypes.NCLOB;
193+
import static org.hibernate.type.SqlTypes.NUMERIC;
194+
import static org.hibernate.type.SqlTypes.NVARCHAR;
195+
import static org.hibernate.type.SqlTypes.REAL;
196+
import static org.hibernate.type.SqlTypes.SMALLINT;
197+
import static org.hibernate.type.SqlTypes.TIME;
198+
import static org.hibernate.type.SqlTypes.TIMESTAMP;
199+
import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
200+
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
201+
import static org.hibernate.type.SqlTypes.TIME_WITH_TIMEZONE;
202+
import static org.hibernate.type.SqlTypes.TINYINT;
203+
import static org.hibernate.type.SqlTypes.VARBINARY;
204+
import static org.hibernate.type.SqlTypes.VARCHAR;
205+
import static org.hibernate.type.SqlTypes.isCharacterType;
206+
import static org.hibernate.type.SqlTypes.isFloatOrRealOrDouble;
207+
import static org.hibernate.type.SqlTypes.isIntegral;
208+
import static org.hibernate.type.SqlTypes.isNumericOrDecimal;
209+
import static org.hibernate.type.SqlTypes.isNumericType;
210+
import static org.hibernate.type.SqlTypes.isVarbinaryType;
211+
import static org.hibernate.type.SqlTypes.isVarcharType;
174212
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_END;
175213
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_DATE;
176214
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIME;
@@ -235,6 +273,8 @@ public abstract class Dialect implements ConversionContext {
235273
private static final Pattern ESCAPE_CLOSING_COMMENT_PATTERN = Pattern.compile( "\\*/" );
236274
private static final Pattern ESCAPE_OPENING_COMMENT_PATTERN = Pattern.compile( "/\\*" );
237275

276+
private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, Dialect.class.getName() );
277+
238278
//needed for converting precision from decimal to binary digits
239279
protected static final double LOG_BASE2OF10 = log(10)/log(2);
240280

@@ -259,17 +299,31 @@ protected Dialect() {
259299

260300
protected Dialect(DatabaseVersion version) {
261301
this.version = version;
302+
checkVersion();
262303
registerDefaultKeywords();
263304
initDefaultProperties();
264305
}
265306

266307
protected Dialect(DialectResolutionInfo info) {
267308
this.version = info.makeCopy();
309+
checkVersion();
268310
registerDefaultKeywords();
269311
registerKeywords(info);
270312
initDefaultProperties();
271313
}
272314

315+
protected void checkVersion() {
316+
final DatabaseVersion version = getVersion();
317+
final DatabaseVersion minimumVersion = getMinimumSupportedVersion();
318+
if ( version != null && version.isBefore( minimumVersion.getMajor(), minimumVersion.getMinor(), minimumVersion.getMicro() ) ) {
319+
LOG.unsupportedDatabaseVersion(
320+
getClass().getName(),
321+
version.getMajor() + "." + version.getMinor() + "." + version.getMicro(),
322+
minimumVersion.getMajor() + "." + minimumVersion.getMinor() + "." + minimumVersion.getMicro()
323+
);
324+
}
325+
}
326+
273327
/**
274328
* Set appropriate default values for configuration properties.
275329
*/
@@ -475,6 +529,10 @@ public DatabaseVersion getVersion() {
475529
return version;
476530
}
477531

532+
protected DatabaseVersion getMinimumSupportedVersion() {
533+
return SimpleDatabaseVersion.ZERO_VERSION;
534+
}
535+
478536
/**
479537
* Resolves the {@link SqlTypes} type code for the given column type name as reported by the database,
480538
* or <code>null</code> if it can't be resolved.
@@ -1217,8 +1275,8 @@ public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType,
12171275
* {@link Types#LONGVARBINARY LONGVARBINARY} as the same type, since
12181276
* Hibernate doesn't really differentiate these types.
12191277
*
1220-
* @param column1 the first column type info
1221-
* @param column2 the second column type info
1278+
* @param typeCode1 the first column type info
1279+
* @param typeCode2 the second column type info
12221280
*
12231281
* @return {@code true} if the two type codes are equivalent
12241282
*/

hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1792,4 +1792,8 @@ void attemptToAssociateProxyWithTwoOpenSessions(
17921792
@Message(value = "Association with `fetch=\"join\"`/`@Fetch(FetchMode.JOIN)` and `lazy=\"true\"`/`FetchType.LAZY` found. This will be interpreted as lazy: %s", id = 510)
17931793
void fetchModeJoinWithLazyWarning(String role);
17941794

1795+
@LogMessage(level = WARN)
1796+
@Message(value = "The %2$s version for [%s] is no longer supported, hence certain features may not work properly. The minimum supported version is %3$s. Check the community dialects project for available legacy versions.", id = 511)
1797+
void unsupportedDatabaseVersion(String databaseName, String actualVersion, String minimumVersion);
1798+
17951799
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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.dialect;
8+
9+
import org.hibernate.dialect.CockroachDialect;
10+
import org.hibernate.dialect.DatabaseVersion;
11+
import org.hibernate.dialect.Dialect;
12+
import org.hibernate.dialect.SimpleDatabaseVersion;
13+
import org.hibernate.internal.CoreMessageLogger;
14+
15+
import org.hibernate.testing.logger.Triggerable;
16+
import org.hibernate.testing.orm.logger.LoggerInspectionExtension;
17+
import org.junit.jupiter.api.Assertions;
18+
import org.junit.jupiter.api.BeforeEach;
19+
import org.junit.jupiter.api.Test;
20+
import org.junit.jupiter.api.extension.RegisterExtension;
21+
22+
import org.jboss.logging.Logger;
23+
24+
/**
25+
* @author Jan Schatteman
26+
*/
27+
public class DialectMinimumVersionTest {
28+
29+
private Triggerable triggerable;
30+
31+
@RegisterExtension
32+
public LoggerInspectionExtension logger = LoggerInspectionExtension
33+
.builder().setLogger(
34+
Logger.getMessageLogger( CoreMessageLogger.class, Dialect.class.getName() )
35+
).build();
36+
37+
@BeforeEach
38+
public void setUp() {
39+
triggerable = logger.watchForLogMessages("HHH000511" );
40+
triggerable.reset();
41+
}
42+
43+
@Test
44+
public void testLessThanDialectMinimumVersion() {
45+
String failMsg = "HHH000511: The version for ... is no longer supported ... should have been logged";
46+
47+
DummyDialect dummyDialect = new DummyDialect( new SimpleDatabaseVersion( 9, 5, 1 ) );
48+
Assertions.assertTrue( triggerable.wasTriggered(), failMsg);
49+
triggerable.reset();
50+
dummyDialect = new DummyDialect( new SimpleDatabaseVersion( 10, 4, 1 ) );
51+
Assertions.assertTrue( triggerable.wasTriggered(), failMsg);
52+
triggerable.reset();
53+
dummyDialect = new DummyDialect( new SimpleDatabaseVersion( 10, 5, 0 ) );
54+
Assertions.assertTrue( triggerable.wasTriggered(), failMsg);
55+
}
56+
57+
@Test
58+
public void testMoreThanDialectMinimumVersion() {
59+
String failMsg = "HHH000511: The version for ... is no longer supported ... should not have been logged";
60+
61+
DummyDialect dummyDialect = new DummyDialect( new SimpleDatabaseVersion( 11, 5, 1 ) );
62+
Assertions.assertFalse( triggerable.wasTriggered(), failMsg );
63+
triggerable.reset();
64+
dummyDialect = new DummyDialect( new SimpleDatabaseVersion( 10, 6, 1 ) );
65+
Assertions.assertFalse( triggerable.wasTriggered(), failMsg );
66+
triggerable.reset();
67+
dummyDialect = new DummyDialect( new SimpleDatabaseVersion( 10, 5, 2 ) );
68+
Assertions.assertFalse( triggerable.wasTriggered(), failMsg );
69+
}
70+
71+
@Test
72+
public void testSameAsDialectMinimumVersion() {
73+
DummyDialect dummyDialect = new DummyDialect( new SimpleDatabaseVersion( 10, 5, 1 ) );
74+
Assertions.assertFalse( triggerable.wasTriggered(), "HHH000511: The version for ... is no longer supported ... should not have been logged" );
75+
}
76+
77+
private final static class DummyDialect extends Dialect {
78+
private DummyDialect(DatabaseVersion version) {
79+
super( version );
80+
}
81+
82+
@Override
83+
protected DatabaseVersion getMinimumSupportedVersion() {
84+
return new SimpleDatabaseVersion( 10, 5, 1 );
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)