HHH-17693 Fix typecheck assertions for converted properties
Also introduce a custom `DurationJdbcType`, mainly for validation purposes.
This commit is contained in:
parent
658e9bc215
commit
6138c76c72
|
@ -686,7 +686,7 @@ public class MetadataBuildingProcess {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.INTERVAL_SECOND, SqlTypes.NUMERIC );
|
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.INTERVAL_SECOND, SqlTypes.DURATION );
|
||||||
}
|
}
|
||||||
|
|
||||||
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.INET, SqlTypes.VARBINARY );
|
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.INET, SqlTypes.VARBINARY );
|
||||||
|
|
|
@ -776,6 +776,7 @@ public abstract class AbstractPostgreSQLStructJdbcType implements AggregateJdbcT
|
||||||
case SqlTypes.DOUBLE:
|
case SqlTypes.DOUBLE:
|
||||||
case SqlTypes.DECIMAL:
|
case SqlTypes.DECIMAL:
|
||||||
case SqlTypes.NUMERIC:
|
case SqlTypes.NUMERIC:
|
||||||
|
case SqlTypes.DURATION:
|
||||||
jdbcJavaType.appendEncodedString(
|
jdbcJavaType.appendEncodedString(
|
||||||
appender,
|
appender,
|
||||||
jdbcJavaType.unwrap(
|
jdbcJavaType.unwrap(
|
||||||
|
|
|
@ -194,6 +194,7 @@ public class JsonHelper {
|
||||||
break;
|
break;
|
||||||
case SqlTypes.DECIMAL:
|
case SqlTypes.DECIMAL:
|
||||||
case SqlTypes.NUMERIC:
|
case SqlTypes.NUMERIC:
|
||||||
|
case SqlTypes.DURATION:
|
||||||
case SqlTypes.UUID:
|
case SqlTypes.UUID:
|
||||||
// These types need to be serialized as JSON string, but don't have a need for escaping
|
// These types need to be serialized as JSON string, but don't have a need for escaping
|
||||||
appender.append( '"' );
|
appender.append( '"' );
|
||||||
|
|
|
@ -564,6 +564,7 @@ public class XmlHelper {
|
||||||
case SqlTypes.DOUBLE:
|
case SqlTypes.DOUBLE:
|
||||||
case SqlTypes.DECIMAL:
|
case SqlTypes.DECIMAL:
|
||||||
case SqlTypes.NUMERIC:
|
case SqlTypes.NUMERIC:
|
||||||
|
case SqlTypes.DURATION:
|
||||||
jdbcJavaType.appendEncodedString(
|
jdbcJavaType.appendEncodedString(
|
||||||
appender,
|
appender,
|
||||||
jdbcJavaType.unwrap(
|
jdbcJavaType.unwrap(
|
||||||
|
|
|
@ -546,7 +546,7 @@ public final class ConfigurationHelper {
|
||||||
return explicitSetting;
|
return explicitSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SqlTypes.NUMERIC;
|
return SqlTypes.DURATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Incubating
|
@Incubating
|
||||||
|
|
|
@ -507,39 +507,24 @@ public class TypecheckUtil {
|
||||||
public static void assertString(SqmExpression<?> expression) {
|
public static void assertString(SqmExpression<?> expression) {
|
||||||
final SqmExpressible<?> nodeType = expression.getNodeType();
|
final SqmExpressible<?> nodeType = expression.getNodeType();
|
||||||
if ( nodeType != null ) {
|
if ( nodeType != null ) {
|
||||||
final Class<?> javaType = nodeType.getExpressibleJavaType().getJavaTypeClass();
|
final DomainType<?> domainType = nodeType.getSqmType();
|
||||||
if ( javaType != String.class && javaType != char[].class ) {
|
if ( !( domainType instanceof JdbcMapping ) || !( (JdbcMapping) domainType ).getJdbcType().isStringLike() ) {
|
||||||
throw new SemanticException(
|
throw new SemanticException(
|
||||||
"Operand of 'like' is of type '" + nodeType.getTypeName() +
|
"Operand of 'like' is of type '" + nodeType.getTypeName() +
|
||||||
"' which is not a string (it is not an instance of 'java.lang.String' or 'char[]')"
|
"' which is not a string (its JDBC type code is not string-like)"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// public static void assertNumeric(SqmExpression<?> expression, BinaryArithmeticOperator op) {
|
|
||||||
// final SqmExpressible<?> nodeType = expression.getNodeType();
|
|
||||||
// if ( nodeType != null ) {
|
|
||||||
// final Class<?> javaType = nodeType.getExpressibleJavaType().getJavaTypeClass();
|
|
||||||
// if ( !Number.class.isAssignableFrom( javaType )
|
|
||||||
// && !Temporal.class.isAssignableFrom( javaType )
|
|
||||||
// && !TemporalAmount.class.isAssignableFrom( javaType )
|
|
||||||
// && !java.util.Date.class.isAssignableFrom( javaType ) ) {
|
|
||||||
// throw new SemanticException( "Operand of " + op.getOperatorSqlText()
|
|
||||||
// + " is of type '" + nodeType.getTypeName() + "' which is not a numeric type"
|
|
||||||
// + " (it is not an instance of 'java.lang.Number', 'java.time.Temporal', or 'java.time.TemporalAmount')" );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static void assertDuration(SqmExpression<?> expression) {
|
public static void assertDuration(SqmExpression<?> expression) {
|
||||||
final SqmExpressible<?> nodeType = expression.getNodeType();
|
final SqmExpressible<?> nodeType = expression.getNodeType();
|
||||||
if ( nodeType != null ) {
|
if ( nodeType != null ) {
|
||||||
final Class<?> javaType = nodeType.getExpressibleJavaType().getJavaTypeClass();
|
final DomainType<?> domainType = nodeType.getSqmType();
|
||||||
if ( !TemporalAmount.class.isAssignableFrom( javaType ) ) {
|
if ( !( domainType instanceof JdbcMapping ) || !( (JdbcMapping) domainType ).getJdbcType().isDuration() ) {
|
||||||
throw new SemanticException(
|
throw new SemanticException(
|
||||||
"Operand of 'by' is of type '" + nodeType.getTypeName() +
|
"Operand of 'by' is of type '" + nodeType.getTypeName() +
|
||||||
"' which is not a duration (it is not an instance of 'java.time.TemporalAmount')"
|
"' which is not a duration (its JDBC type code is not duration-like)"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -548,11 +533,11 @@ public class TypecheckUtil {
|
||||||
public static void assertNumeric(SqmExpression<?> expression, UnaryArithmeticOperator op) {
|
public static void assertNumeric(SqmExpression<?> expression, UnaryArithmeticOperator op) {
|
||||||
final SqmExpressible<?> nodeType = expression.getNodeType();
|
final SqmExpressible<?> nodeType = expression.getNodeType();
|
||||||
if ( nodeType != null ) {
|
if ( nodeType != null ) {
|
||||||
final Class<?> javaType = nodeType.getExpressibleJavaType().getJavaTypeClass();
|
final DomainType<?> domainType = nodeType.getSqmType();
|
||||||
if ( !Number.class.isAssignableFrom( javaType ) ) {
|
if ( !( domainType instanceof JdbcMapping ) || !( (JdbcMapping) domainType ).getJdbcType().isNumber() ) {
|
||||||
throw new SemanticException(
|
throw new SemanticException(
|
||||||
"Operand of " + op.getOperatorChar() + " is of type '" + nodeType.getTypeName() +
|
"Operand of " + op.getOperatorChar() + " is of type '" + nodeType.getTypeName() +
|
||||||
"' which is not a numeric type (it is not an instance of 'java.lang.Number')"
|
"' which is not a numeric type (its JDBC type code is not numeric)"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -498,6 +498,14 @@ public class SqlTypes {
|
||||||
*/
|
*/
|
||||||
public static final int TIME_UTC = 3007;
|
public static final int TIME_UTC = 3007;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type code representing a "virtual mapping" of {@linkplain java.time.Duration}.
|
||||||
|
*
|
||||||
|
* @see Types#NUMERIC
|
||||||
|
* @see org.hibernate.type.descriptor.jdbc.DurationJdbcType
|
||||||
|
*/
|
||||||
|
public static final int DURATION = 3015;
|
||||||
|
|
||||||
// Interval types
|
// Interval types
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -779,6 +787,13 @@ public class SqlTypes {
|
||||||
return typeCode == INTERVAL_SECOND;
|
return typeCode == INTERVAL_SECOND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the given typecode represent a {@code duration} type?
|
||||||
|
*/
|
||||||
|
public static boolean isDurationType(int typeCode) {
|
||||||
|
return typeCode == DURATION;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does the given typecode represent a SQL date or timestamp type?
|
* Does the given typecode represent a SQL date or timestamp type?
|
||||||
* @param typeCode a JDBC type code from {@link Types}
|
* @param typeCode a JDBC type code from {@link Types}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.type.descriptor.jdbc;
|
||||||
|
|
||||||
|
import java.sql.Types;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
import org.hibernate.type.SqlTypes;
|
||||||
|
import org.hibernate.type.descriptor.WrapperOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Descriptor for {@link java.time.Duration}.
|
||||||
|
*
|
||||||
|
* @author Marco Belladelli
|
||||||
|
*/
|
||||||
|
public class DurationJdbcType extends NumericJdbcType {
|
||||||
|
public static final DurationJdbcType INSTANCE = new DurationJdbcType();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDdlTypeCode() {
|
||||||
|
return Types.NUMERIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDefaultSqlTypeCode() {
|
||||||
|
return SqlTypes.DURATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFriendlyName() {
|
||||||
|
return "DURATION";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "DurationJdbcType";
|
||||||
|
}
|
||||||
|
}
|
|
@ -287,6 +287,12 @@ public interface JdbcType extends Serializable {
|
||||||
return isIntervalType( getDdlTypeCode() );
|
return isIntervalType( getDdlTypeCode() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default boolean isDuration() {
|
||||||
|
final int ddlTypeCode = getDefaultSqlTypeCode();
|
||||||
|
return isDurationType( ddlTypeCode )
|
||||||
|
|| isIntervalType( ddlTypeCode );
|
||||||
|
}
|
||||||
|
|
||||||
default CastType getCastType() {
|
default CastType getCastType() {
|
||||||
return getCastType( getDdlTypeCode() );
|
return getCastType( getDdlTypeCode() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.DateJdbcType;
|
import org.hibernate.type.descriptor.jdbc.DateJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.DecimalJdbcType;
|
import org.hibernate.type.descriptor.jdbc.DecimalJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.DoubleJdbcType;
|
import org.hibernate.type.descriptor.jdbc.DoubleJdbcType;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.DurationJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.FloatJdbcType;
|
import org.hibernate.type.descriptor.jdbc.FloatJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.IntegerJdbcType;
|
import org.hibernate.type.descriptor.jdbc.IntegerJdbcType;
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
|
@ -66,6 +67,7 @@ public class JdbcTypeBaseline {
|
||||||
target.addDescriptor( TimestampWithTimeZoneJdbcType.INSTANCE );
|
target.addDescriptor( TimestampWithTimeZoneJdbcType.INSTANCE );
|
||||||
target.addDescriptor( TimeJdbcType.INSTANCE );
|
target.addDescriptor( TimeJdbcType.INSTANCE );
|
||||||
target.addDescriptor( TimeWithTimeZoneJdbcType.INSTANCE );
|
target.addDescriptor( TimeWithTimeZoneJdbcType.INSTANCE );
|
||||||
|
target.addDescriptor( DurationJdbcType.INSTANCE );
|
||||||
|
|
||||||
target.addDescriptor( BinaryJdbcType.INSTANCE );
|
target.addDescriptor( BinaryJdbcType.INSTANCE );
|
||||||
target.addDescriptor( VarbinaryJdbcType.INSTANCE );
|
target.addDescriptor( VarbinaryJdbcType.INSTANCE );
|
||||||
|
|
Loading…
Reference in New Issue