Skip to content

Commit 505e64b

Browse files
committed
HHH-18016 change ArgumentTypesValidator to delegate to the JdbcType
Signed-off-by: Gavin King <[email protected]>
1 parent 27bbdfc commit 505e64b

File tree

3 files changed

+111
-100
lines changed

3 files changed

+111
-100
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/ArgumentTypesValidator.java

Lines changed: 64 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
package org.hibernate.query.sqm.produce.function;
88

99
import java.lang.reflect.Type;
10-
import java.sql.Types;
1110
import java.util.List;
1211

12+
import org.hibernate.Internal;
1313
import org.hibernate.metamodel.MappingMetamodel;
1414
import org.hibernate.metamodel.mapping.JdbcMapping;
1515
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
@@ -26,25 +26,10 @@
2626
import org.hibernate.type.BasicType;
2727
import org.hibernate.type.JavaObjectType;
2828
import org.hibernate.type.descriptor.java.JavaType;
29-
import org.hibernate.type.descriptor.java.spi.JdbcTypeRecommendationException;
3029
import org.hibernate.type.descriptor.jdbc.JdbcType;
31-
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
3230
import org.hibernate.type.spi.TypeConfiguration;
3331

34-
import static org.hibernate.type.SqlTypes.BIT;
35-
import static org.hibernate.type.SqlTypes.BOOLEAN;
36-
import static org.hibernate.type.SqlTypes.SMALLINT;
37-
import static org.hibernate.type.SqlTypes.TINYINT;
38-
import static org.hibernate.type.SqlTypes.UUID;
39-
import static org.hibernate.type.SqlTypes.hasDatePart;
40-
import static org.hibernate.type.SqlTypes.hasTimePart;
41-
import static org.hibernate.type.SqlTypes.isCharacterOrClobType;
42-
import static org.hibernate.type.SqlTypes.isCharacterType;
43-
import static org.hibernate.type.SqlTypes.isEnumType;
44-
import static org.hibernate.type.SqlTypes.isIntegral;
45-
import static org.hibernate.type.SqlTypes.isNumericType;
46-
import static org.hibernate.type.SqlTypes.isSpatialType;
47-
import static org.hibernate.type.SqlTypes.isTemporalType;
32+
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.COMPARABLE;
4833
import static org.hibernate.type.descriptor.java.JavaTypeHelper.isUnknown;
4934

5035

@@ -66,7 +51,7 @@
6651
public class ArgumentTypesValidator implements ArgumentsValidator {
6752
// a JDBC type code of an enum when we don't know if it's mapped STRING or ORDINAL
6853
// this number has to be distinct from every code in SqlTypes!
69-
private static final int ENUM_UNKNOWN_JDBC_TYPE = -101977;
54+
// private static final int ENUM_UNKNOWN_JDBC_TYPE = -101977;
7055

7156
final ArgumentsValidator delegate;
7257
private final FunctionParameterType[] types;
@@ -93,13 +78,13 @@ public void validate(
9378
delegate.validate( arguments, functionName, typeConfiguration);
9479
int count = 0;
9580
for (SqmTypedNode<?> argument : arguments) {
96-
JdbcTypeIndicators indicators = typeConfiguration.getCurrentBaseSqlTypeIndicators();
81+
// JdbcTypeIndicators indicators = typeConfiguration.getCurrentBaseSqlTypeIndicators();
9782
SqmExpressible<?> nodeType = argument.getNodeType();
9883
FunctionParameterType type = count < types.length ? types[count++] : types[types.length - 1];
9984
if ( nodeType != null && type != FunctionParameterType.ANY ) {
10085
JavaType<?> javaType = nodeType.getRelationalJavaType();
10186
if (javaType != null) {
102-
checkArgumentType( functionName, count, argument, indicators, type, javaType );
87+
checkArgumentType( functionName, count, argument, type, javaType );
10388
}
10489
switch (type) {
10590
case TEMPORAL_UNIT:
@@ -144,46 +129,44 @@ private void checkArgumentType(
144129
String functionName,
145130
int count,
146131
SqmTypedNode<?> argument,
147-
JdbcTypeIndicators indicators,
148132
FunctionParameterType type,
149133
JavaType<?> javaType) {
150134
if ( !isUnknown( javaType ) ) {
151135
DomainType<?> domainType = argument.getExpressible().getSqmType();
152136
if ( domainType instanceof JdbcMapping ) {
153-
JdbcType jdbcType = ((JdbcMapping) domainType).getJdbcType();
137+
JdbcMapping jdbcMapping = (JdbcMapping) domainType;
154138
checkArgumentType(
155139
count, functionName, type,
156-
jdbcType.getDefaultSqlTypeCode(),
157-
jdbcType.getFriendlyName(),
140+
jdbcMapping.getJdbcType(),
158141
javaType.getJavaTypeClass()
159142
);
160143
}
161-
else {
162-
//TODO: this branch is now probably obsolete and can be deleted!
163-
try {
164-
checkArgumentType(
165-
count, functionName, type,
166-
getJdbcType( indicators, javaType ),
167-
null,
168-
javaType.getJavaTypeClass()
169-
);
170-
}
171-
catch (JdbcTypeRecommendationException e) {
172-
// it's a converter or something like that, and we will check it later
173-
}
174-
}
144+
// else {
145+
// //TODO: this branch is now probably obsolete and can be deleted!
146+
// try {
147+
// checkArgumentType(
148+
// count, functionName, type,
149+
// getJdbcType( indicators, javaType ),
150+
// null,
151+
// javaType.getJavaTypeClass()
152+
// );
153+
// }
154+
// catch (JdbcTypeRecommendationException e) {
155+
// // it's a converter or something like that, and we will check it later
156+
// }
157+
// }
175158
}
176159
}
177160

178-
private int getJdbcType(JdbcTypeIndicators indicators, JavaType<?> javaType) {
179-
if ( javaType.getJavaTypeClass().isEnum() ) {
180-
// we can't tell if the enum is mapped STRING or ORDINAL
181-
return ENUM_UNKNOWN_JDBC_TYPE;
182-
}
183-
else {
184-
return javaType.getRecommendedJdbcType( indicators ).getDefaultSqlTypeCode();
185-
}
186-
}
161+
// private int getJdbcType(JdbcTypeIndicators indicators, JavaType<?> javaType) {
162+
// if ( javaType.getJavaTypeClass().isEnum() ) {
163+
// // we can't tell if the enum is mapped STRING or ORDINAL
164+
// return ENUM_UNKNOWN_JDBC_TYPE;
165+
// }
166+
// else {
167+
// return javaType.getRecommendedJdbcType( indicators ).getDefaultSqlTypeCode();
168+
// }
169+
// }
187170

188171
/**
189172
* This is the final validation phase with the fully-typed SQL nodes. Note that these
@@ -232,8 +215,7 @@ private int validateArgument(int paramNumber, JdbcMappingContainer expressionTyp
232215
paramNumber,
233216
functionName,
234217
type,
235-
mapping.getJdbcType().getDefaultSqlTypeCode(),
236-
mapping.getJdbcType().getFriendlyName(),
218+
mapping.getJdbcType(),
237219
mapping.getJavaTypeDescriptor().getJavaType()
238220
);
239221
}
@@ -242,65 +224,49 @@ private int validateArgument(int paramNumber, JdbcMappingContainer expressionTyp
242224
}
243225

244226
private static void checkArgumentType(
245-
int paramNumber, String functionName, FunctionParameterType type, int code, String sqlType, Type javaType) {
246-
switch (type) {
227+
int paramNumber, String functionName, FunctionParameterType type, JdbcType jdbcType, Type javaType) {
228+
if ( !isCompatible( type, jdbcType )
229+
// as a special case, we consider a binary column
230+
// comparable when it is mapped by a Java UUID
231+
&& !( type == COMPARABLE && isBinaryUuid( jdbcType, javaType ) ) ) {
232+
throwError( type, javaType, jdbcType.getFriendlyName(), functionName, paramNumber );
233+
}
234+
}
235+
236+
private static boolean isBinaryUuid(JdbcType jdbcType, Type javaType) {
237+
return javaType == java.util.UUID.class
238+
&& jdbcType.isBinary();
239+
}
240+
241+
@Internal
242+
private static boolean isCompatible(FunctionParameterType type, JdbcType jdbcType) {
243+
switch ( type ) {
247244
case COMPARABLE:
248-
if ( !isCharacterType(code) && !isTemporalType(code) && !isNumericType(code) && !isEnumType( code )
249-
// both Java and the database consider UUIDs
250-
// comparable, so go ahead and accept them
251-
&& code != UUID
252-
// as a special case, we consider a binary column
253-
// comparable when it is mapped by a Java UUID
254-
&& !( javaType == java.util.UUID.class && code == Types.BINARY ) ) {
255-
throwError(type, javaType, sqlType, functionName, paramNumber);
256-
}
257-
break;
245+
return jdbcType.isComparable();
258246
case STRING:
259-
if ( !isCharacterType(code) && !isEnumType(code) ) {
260-
throwError(type, javaType, sqlType, functionName, paramNumber);
261-
}
262-
break;
247+
return jdbcType.isStringLikeExcludingClob();
263248
case STRING_OR_CLOB:
264-
if ( !isCharacterOrClobType(code) ) {
265-
throwError(type, javaType, sqlType, functionName, paramNumber);
266-
}
267-
break;
249+
return jdbcType.isString(); // should it be isStringLike()
268250
case NUMERIC:
269-
if ( !isNumericType(code) ) {
270-
throwError(type, javaType, sqlType, functionName, paramNumber);
271-
}
272-
break;
251+
return jdbcType.isNumber();
273252
case INTEGER:
274-
if ( !isIntegral(code) ) {
275-
throwError(type, javaType, sqlType, functionName, paramNumber);
276-
}
277-
break;
253+
return jdbcType.isInteger();
278254
case BOOLEAN:
279-
// ugh, need to be careful here, need to accept all the
280-
// JDBC type codes that a Dialect might use for BOOLEAN
281-
if ( code != BOOLEAN && code != BIT && code != TINYINT && code != SMALLINT ) {
282-
throwError(type, javaType, sqlType, functionName, paramNumber);
283-
}
284-
break;
255+
return jdbcType.isBoolean()
256+
// some Dialects map Boolean to SMALLINT or TINYINT
257+
// TODO: check with Dialect.getPreferredSqlTypeCodeForBoolean
258+
|| jdbcType.isSmallInteger();
285259
case TEMPORAL:
286-
if ( !isTemporalType(code) ) {
287-
throwError(type, javaType, sqlType, functionName, paramNumber);
288-
}
289-
break;
260+
return jdbcType.isTemporal();
290261
case DATE:
291-
if ( !hasDatePart(code) ) {
292-
throwError(type, javaType, sqlType, functionName, paramNumber);
293-
}
294-
break;
262+
return jdbcType.hasDatePart();
295263
case TIME:
296-
if ( !hasTimePart(code) ) {
297-
throwError(type, javaType, sqlType, functionName, paramNumber);
298-
}
299-
break;
264+
return jdbcType.hasTimePart();
300265
case SPATIAL:
301-
if ( !isSpatialType( code ) ) {
302-
throwError( type, javaType, sqlType, functionName, paramNumber );
303-
}
266+
return jdbcType.isSpatial();
267+
default:
268+
// TODO: should we throw here?
269+
return true;
304270
}
305271
}
306272

hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/BooleanJdbcType.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import org.hibernate.type.descriptor.ValueBinder;
1616
import org.hibernate.type.descriptor.ValueExtractor;
1717
import org.hibernate.type.descriptor.WrapperOptions;
18-
import org.hibernate.type.descriptor.java.BasicJavaType;
1918
import org.hibernate.type.descriptor.java.JavaType;
2019
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterBoolean;
2120
import org.hibernate.type.spi.TypeConfiguration;

hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/JdbcType.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ default boolean isInterval() {
290290
default boolean isDuration() {
291291
final int ddlTypeCode = getDefaultSqlTypeCode();
292292
return isDurationType( ddlTypeCode )
293-
|| isIntervalType( ddlTypeCode );
293+
|| isIntervalType( ddlTypeCode );
294294
}
295295

296296
default boolean isArray() {
@@ -402,4 +402,50 @@ default void addAuxiliaryDatabaseObjects(
402402
default String getExtraCreateTableInfo(JavaType<?> javaType, String columnName, String tableName, Database database) {
403403
return "";
404404
}
405+
406+
@Incubating
407+
default boolean isComparable() {
408+
final int code = getDefaultSqlTypeCode();
409+
return isCharacterType( code )
410+
|| isTemporalType( code )
411+
|| isNumericType( code )
412+
|| isEnumType( code )
413+
// both Java and the SQL database consider
414+
// that false < true is a sensible thing
415+
|| isBoolean()
416+
// both Java and the database consider UUIDs
417+
// comparable, so go ahead and accept them
418+
|| code == UUID;
419+
}
420+
421+
@Incubating
422+
default boolean hasDatePart() {
423+
return SqlTypes.hasDatePart( getDefaultSqlTypeCode() );
424+
}
425+
426+
@Incubating
427+
default boolean hasTimePart() {
428+
return SqlTypes.hasTimePart( getDefaultSqlTypeCode() );
429+
}
430+
431+
@Incubating
432+
default boolean isStringLikeExcludingClob() {
433+
final int code = getDefaultSqlTypeCode();
434+
return isCharacterType( code ) || isEnumType( code );
435+
}
436+
437+
@Incubating
438+
default boolean isSpatial() {
439+
return isSpatialType( getDefaultSqlTypeCode() );
440+
}
441+
442+
@Incubating
443+
default boolean isBoolean() {
444+
return getDefaultSqlTypeCode() == BOOLEAN;
445+
}
446+
447+
@Incubating
448+
default boolean isSmallInteger() {
449+
return isSmallOrTinyInt( getDefaultSqlTypeCode() );
450+
}
405451
}

0 commit comments

Comments
 (0)