HHH-18016 change ArgumentTypesValidator to delegate to the JdbcType
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
27bbdfc839
commit
505e64b19a
|
@ -7,9 +7,9 @@
|
|||
package org.hibernate.query.sqm.produce.function;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
|
||||
|
@ -26,25 +26,10 @@ import org.hibernate.sql.ast.tree.expression.Expression;
|
|||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.JavaObjectType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.JdbcTypeRecommendationException;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.BIT;
|
||||
import static org.hibernate.type.SqlTypes.BOOLEAN;
|
||||
import static org.hibernate.type.SqlTypes.SMALLINT;
|
||||
import static org.hibernate.type.SqlTypes.TINYINT;
|
||||
import static org.hibernate.type.SqlTypes.UUID;
|
||||
import static org.hibernate.type.SqlTypes.hasDatePart;
|
||||
import static org.hibernate.type.SqlTypes.hasTimePart;
|
||||
import static org.hibernate.type.SqlTypes.isCharacterOrClobType;
|
||||
import static org.hibernate.type.SqlTypes.isCharacterType;
|
||||
import static org.hibernate.type.SqlTypes.isEnumType;
|
||||
import static org.hibernate.type.SqlTypes.isIntegral;
|
||||
import static org.hibernate.type.SqlTypes.isNumericType;
|
||||
import static org.hibernate.type.SqlTypes.isSpatialType;
|
||||
import static org.hibernate.type.SqlTypes.isTemporalType;
|
||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.COMPARABLE;
|
||||
import static org.hibernate.type.descriptor.java.JavaTypeHelper.isUnknown;
|
||||
|
||||
|
||||
|
@ -66,7 +51,7 @@ import static org.hibernate.type.descriptor.java.JavaTypeHelper.isUnknown;
|
|||
public class ArgumentTypesValidator implements ArgumentsValidator {
|
||||
// a JDBC type code of an enum when we don't know if it's mapped STRING or ORDINAL
|
||||
// this number has to be distinct from every code in SqlTypes!
|
||||
private static final int ENUM_UNKNOWN_JDBC_TYPE = -101977;
|
||||
// private static final int ENUM_UNKNOWN_JDBC_TYPE = -101977;
|
||||
|
||||
final ArgumentsValidator delegate;
|
||||
private final FunctionParameterType[] types;
|
||||
|
@ -93,13 +78,13 @@ public class ArgumentTypesValidator implements ArgumentsValidator {
|
|||
delegate.validate( arguments, functionName, typeConfiguration);
|
||||
int count = 0;
|
||||
for (SqmTypedNode<?> argument : arguments) {
|
||||
JdbcTypeIndicators indicators = typeConfiguration.getCurrentBaseSqlTypeIndicators();
|
||||
// JdbcTypeIndicators indicators = typeConfiguration.getCurrentBaseSqlTypeIndicators();
|
||||
SqmExpressible<?> nodeType = argument.getNodeType();
|
||||
FunctionParameterType type = count < types.length ? types[count++] : types[types.length - 1];
|
||||
if ( nodeType != null && type != FunctionParameterType.ANY ) {
|
||||
JavaType<?> javaType = nodeType.getRelationalJavaType();
|
||||
if (javaType != null) {
|
||||
checkArgumentType( functionName, count, argument, indicators, type, javaType );
|
||||
checkArgumentType( functionName, count, argument, type, javaType );
|
||||
}
|
||||
switch (type) {
|
||||
case TEMPORAL_UNIT:
|
||||
|
@ -144,46 +129,44 @@ public class ArgumentTypesValidator implements ArgumentsValidator {
|
|||
String functionName,
|
||||
int count,
|
||||
SqmTypedNode<?> argument,
|
||||
JdbcTypeIndicators indicators,
|
||||
FunctionParameterType type,
|
||||
JavaType<?> javaType) {
|
||||
if ( !isUnknown( javaType ) ) {
|
||||
DomainType<?> domainType = argument.getExpressible().getSqmType();
|
||||
if ( domainType instanceof JdbcMapping ) {
|
||||
JdbcType jdbcType = ((JdbcMapping) domainType).getJdbcType();
|
||||
JdbcMapping jdbcMapping = (JdbcMapping) domainType;
|
||||
checkArgumentType(
|
||||
count, functionName, type,
|
||||
jdbcType.getDefaultSqlTypeCode(),
|
||||
jdbcType.getFriendlyName(),
|
||||
jdbcMapping.getJdbcType(),
|
||||
javaType.getJavaTypeClass()
|
||||
);
|
||||
}
|
||||
else {
|
||||
//TODO: this branch is now probably obsolete and can be deleted!
|
||||
try {
|
||||
checkArgumentType(
|
||||
count, functionName, type,
|
||||
getJdbcType( indicators, javaType ),
|
||||
null,
|
||||
javaType.getJavaTypeClass()
|
||||
);
|
||||
}
|
||||
catch (JdbcTypeRecommendationException e) {
|
||||
// it's a converter or something like that, and we will check it later
|
||||
}
|
||||
}
|
||||
// else {
|
||||
// //TODO: this branch is now probably obsolete and can be deleted!
|
||||
// try {
|
||||
// checkArgumentType(
|
||||
// count, functionName, type,
|
||||
// getJdbcType( indicators, javaType ),
|
||||
// null,
|
||||
// javaType.getJavaTypeClass()
|
||||
// );
|
||||
// }
|
||||
// catch (JdbcTypeRecommendationException e) {
|
||||
// // it's a converter or something like that, and we will check it later
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
private int getJdbcType(JdbcTypeIndicators indicators, JavaType<?> javaType) {
|
||||
if ( javaType.getJavaTypeClass().isEnum() ) {
|
||||
// we can't tell if the enum is mapped STRING or ORDINAL
|
||||
return ENUM_UNKNOWN_JDBC_TYPE;
|
||||
}
|
||||
else {
|
||||
return javaType.getRecommendedJdbcType( indicators ).getDefaultSqlTypeCode();
|
||||
}
|
||||
}
|
||||
// private int getJdbcType(JdbcTypeIndicators indicators, JavaType<?> javaType) {
|
||||
// if ( javaType.getJavaTypeClass().isEnum() ) {
|
||||
// // we can't tell if the enum is mapped STRING or ORDINAL
|
||||
// return ENUM_UNKNOWN_JDBC_TYPE;
|
||||
// }
|
||||
// else {
|
||||
// return javaType.getRecommendedJdbcType( indicators ).getDefaultSqlTypeCode();
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* This is the final validation phase with the fully-typed SQL nodes. Note that these
|
||||
|
@ -232,8 +215,7 @@ public class ArgumentTypesValidator implements ArgumentsValidator {
|
|||
paramNumber,
|
||||
functionName,
|
||||
type,
|
||||
mapping.getJdbcType().getDefaultSqlTypeCode(),
|
||||
mapping.getJdbcType().getFriendlyName(),
|
||||
mapping.getJdbcType(),
|
||||
mapping.getJavaTypeDescriptor().getJavaType()
|
||||
);
|
||||
}
|
||||
|
@ -242,65 +224,49 @@ public class ArgumentTypesValidator implements ArgumentsValidator {
|
|||
}
|
||||
|
||||
private static void checkArgumentType(
|
||||
int paramNumber, String functionName, FunctionParameterType type, int code, String sqlType, Type javaType) {
|
||||
switch (type) {
|
||||
int paramNumber, String functionName, FunctionParameterType type, JdbcType jdbcType, Type javaType) {
|
||||
if ( !isCompatible( type, jdbcType )
|
||||
// as a special case, we consider a binary column
|
||||
// comparable when it is mapped by a Java UUID
|
||||
&& !( type == COMPARABLE && isBinaryUuid( jdbcType, javaType ) ) ) {
|
||||
throwError( type, javaType, jdbcType.getFriendlyName(), functionName, paramNumber );
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isBinaryUuid(JdbcType jdbcType, Type javaType) {
|
||||
return javaType == java.util.UUID.class
|
||||
&& jdbcType.isBinary();
|
||||
}
|
||||
|
||||
@Internal
|
||||
private static boolean isCompatible(FunctionParameterType type, JdbcType jdbcType) {
|
||||
switch ( type ) {
|
||||
case COMPARABLE:
|
||||
if ( !isCharacterType(code) && !isTemporalType(code) && !isNumericType(code) && !isEnumType( code )
|
||||
// both Java and the database consider UUIDs
|
||||
// comparable, so go ahead and accept them
|
||||
&& code != UUID
|
||||
// as a special case, we consider a binary column
|
||||
// comparable when it is mapped by a Java UUID
|
||||
&& !( javaType == java.util.UUID.class && code == Types.BINARY ) ) {
|
||||
throwError(type, javaType, sqlType, functionName, paramNumber);
|
||||
}
|
||||
break;
|
||||
return jdbcType.isComparable();
|
||||
case STRING:
|
||||
if ( !isCharacterType(code) && !isEnumType(code) ) {
|
||||
throwError(type, javaType, sqlType, functionName, paramNumber);
|
||||
}
|
||||
break;
|
||||
return jdbcType.isStringLikeExcludingClob();
|
||||
case STRING_OR_CLOB:
|
||||
if ( !isCharacterOrClobType(code) ) {
|
||||
throwError(type, javaType, sqlType, functionName, paramNumber);
|
||||
}
|
||||
break;
|
||||
return jdbcType.isString(); // should it be isStringLike()
|
||||
case NUMERIC:
|
||||
if ( !isNumericType(code) ) {
|
||||
throwError(type, javaType, sqlType, functionName, paramNumber);
|
||||
}
|
||||
break;
|
||||
return jdbcType.isNumber();
|
||||
case INTEGER:
|
||||
if ( !isIntegral(code) ) {
|
||||
throwError(type, javaType, sqlType, functionName, paramNumber);
|
||||
}
|
||||
break;
|
||||
return jdbcType.isInteger();
|
||||
case BOOLEAN:
|
||||
// ugh, need to be careful here, need to accept all the
|
||||
// JDBC type codes that a Dialect might use for BOOLEAN
|
||||
if ( code != BOOLEAN && code != BIT && code != TINYINT && code != SMALLINT ) {
|
||||
throwError(type, javaType, sqlType, functionName, paramNumber);
|
||||
}
|
||||
break;
|
||||
return jdbcType.isBoolean()
|
||||
// some Dialects map Boolean to SMALLINT or TINYINT
|
||||
// TODO: check with Dialect.getPreferredSqlTypeCodeForBoolean
|
||||
|| jdbcType.isSmallInteger();
|
||||
case TEMPORAL:
|
||||
if ( !isTemporalType(code) ) {
|
||||
throwError(type, javaType, sqlType, functionName, paramNumber);
|
||||
}
|
||||
break;
|
||||
return jdbcType.isTemporal();
|
||||
case DATE:
|
||||
if ( !hasDatePart(code) ) {
|
||||
throwError(type, javaType, sqlType, functionName, paramNumber);
|
||||
}
|
||||
break;
|
||||
return jdbcType.hasDatePart();
|
||||
case TIME:
|
||||
if ( !hasTimePart(code) ) {
|
||||
throwError(type, javaType, sqlType, functionName, paramNumber);
|
||||
}
|
||||
break;
|
||||
return jdbcType.hasTimePart();
|
||||
case SPATIAL:
|
||||
if ( !isSpatialType( code ) ) {
|
||||
throwError( type, javaType, sqlType, functionName, paramNumber );
|
||||
}
|
||||
return jdbcType.isSpatial();
|
||||
default:
|
||||
// TODO: should we throw here?
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ import java.sql.Types;
|
|||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
import org.hibernate.type.descriptor.ValueExtractor;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.internal.JdbcLiteralFormatterBoolean;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
|
|
@ -290,7 +290,7 @@ public interface JdbcType extends Serializable {
|
|||
default boolean isDuration() {
|
||||
final int ddlTypeCode = getDefaultSqlTypeCode();
|
||||
return isDurationType( ddlTypeCode )
|
||||
|| isIntervalType( ddlTypeCode );
|
||||
|| isIntervalType( ddlTypeCode );
|
||||
}
|
||||
|
||||
default boolean isArray() {
|
||||
|
@ -402,4 +402,50 @@ public interface JdbcType extends Serializable {
|
|||
default String getExtraCreateTableInfo(JavaType<?> javaType, String columnName, String tableName, Database database) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Incubating
|
||||
default boolean isComparable() {
|
||||
final int code = getDefaultSqlTypeCode();
|
||||
return isCharacterType( code )
|
||||
|| isTemporalType( code )
|
||||
|| isNumericType( code )
|
||||
|| isEnumType( code )
|
||||
// both Java and the SQL database consider
|
||||
// that false < true is a sensible thing
|
||||
|| isBoolean()
|
||||
// both Java and the database consider UUIDs
|
||||
// comparable, so go ahead and accept them
|
||||
|| code == UUID;
|
||||
}
|
||||
|
||||
@Incubating
|
||||
default boolean hasDatePart() {
|
||||
return SqlTypes.hasDatePart( getDefaultSqlTypeCode() );
|
||||
}
|
||||
|
||||
@Incubating
|
||||
default boolean hasTimePart() {
|
||||
return SqlTypes.hasTimePart( getDefaultSqlTypeCode() );
|
||||
}
|
||||
|
||||
@Incubating
|
||||
default boolean isStringLikeExcludingClob() {
|
||||
final int code = getDefaultSqlTypeCode();
|
||||
return isCharacterType( code ) || isEnumType( code );
|
||||
}
|
||||
|
||||
@Incubating
|
||||
default boolean isSpatial() {
|
||||
return isSpatialType( getDefaultSqlTypeCode() );
|
||||
}
|
||||
|
||||
@Incubating
|
||||
default boolean isBoolean() {
|
||||
return getDefaultSqlTypeCode() == BOOLEAN;
|
||||
}
|
||||
|
||||
@Incubating
|
||||
default boolean isSmallInteger() {
|
||||
return isSmallOrTinyInt( getDefaultSqlTypeCode() );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue