make TimestampaddFunction understandable using Extract Method
This commit is contained in:
parent
52c7f61815
commit
3e97fe39a7
|
@ -6,11 +6,12 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.dialect.function;
|
package org.hibernate.dialect.function;
|
||||||
|
|
||||||
|
import jakarta.persistence.TemporalType;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
|
||||||
import org.hibernate.query.ReturnableType;
|
import org.hibernate.query.ReturnableType;
|
||||||
import org.hibernate.query.sqm.BinaryArithmeticOperator;
|
import org.hibernate.query.sqm.BinaryArithmeticOperator;
|
||||||
|
import org.hibernate.query.sqm.IntervalType;
|
||||||
import org.hibernate.query.sqm.TemporalUnit;
|
import org.hibernate.query.sqm.TemporalUnit;
|
||||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||||
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
||||||
|
@ -28,10 +29,9 @@ import org.hibernate.sql.ast.tree.expression.Expression;
|
||||||
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.StandardBasicTypes;
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
import org.hibernate.type.spi.TypeConfiguration;
|
import org.hibernate.type.spi.TypeConfiguration;
|
||||||
|
|
||||||
import java.sql.Types;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -39,6 +39,8 @@ import static java.util.Arrays.asList;
|
||||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.INTEGER;
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.INTEGER;
|
||||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL;
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL;
|
||||||
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL_UNIT;
|
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL_UNIT;
|
||||||
|
import static org.hibernate.type.spi.TypeConfiguration.getSqlIntervalType;
|
||||||
|
import static org.hibernate.type.spi.TypeConfiguration.getSqlTemporalType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
|
@ -73,72 +75,38 @@ public class TimestampaddFunction
|
||||||
SqlAstTranslator<?> walker) {
|
SqlAstTranslator<?> walker) {
|
||||||
|
|
||||||
final DurationUnit field = (DurationUnit) arguments.get( 0 );
|
final DurationUnit field = (DurationUnit) arguments.get( 0 );
|
||||||
|
final Expression magnitude = (Expression) arguments.get(1);
|
||||||
final Expression to = (Expression) arguments.get( 2 );
|
final Expression to = (Expression) arguments.get( 2 );
|
||||||
final TemporalUnit unit;
|
|
||||||
if ( dialect.supportsFractionalTimestampArithmetic() ) {
|
|
||||||
unit = field.getUnit();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final Expression magnitude = (Expression) arguments.get( 1 );
|
|
||||||
final JdbcMapping magnitudeJdbcMapping = magnitude.getExpressionType().getJdbcMappings().get( 0 );
|
|
||||||
switch ( magnitudeJdbcMapping.getJdbcType().getJdbcTypeCode() ) {
|
|
||||||
case Types.INTEGER:
|
|
||||||
case Types.TINYINT:
|
|
||||||
case Types.SMALLINT:
|
|
||||||
case Types.BIGINT:
|
|
||||||
unit = field.getUnit();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if ( magnitudeJdbcMapping.getMappedJavaType().getJavaTypeClass() == Duration.class ) {
|
|
||||||
// Don't scale durations
|
|
||||||
unit = field.getUnit();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// We need to multiply the magnitude by the conversion factor and cast to int
|
|
||||||
// Use second by default and nanosecond if we encounter fractional seconds
|
|
||||||
unit = field.getUnit() == TemporalUnit.SECOND
|
|
||||||
? TemporalUnit.NANOSECOND
|
|
||||||
: TemporalUnit.SECOND;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final String pattern = dialect.timestampaddPattern(
|
final TemporalUnit unit = bestTemporalUnit( magnitude, field );
|
||||||
unit,
|
|
||||||
TypeConfiguration.getSqlTemporalType( to.getExpressionType() ),
|
|
||||||
TypeConfiguration.getSqlIntervalType(
|
|
||||||
( (Expression) arguments.get( 1 ) ).getExpressionType().getJdbcMappings().get( 0 )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
final PatternRenderer renderer = new PatternRenderer( pattern );
|
|
||||||
if ( unit != field.getUnit() ) {
|
if ( unit != field.getUnit() ) {
|
||||||
|
renderWithUnitConversion( sqlAppender, arguments, walker, field, unit );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
patternRenderer( to, magnitude, unit ).render( sqlAppender, arguments, walker );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PatternRenderer patternRenderer(Expression to, Expression interval, TemporalUnit unit) {
|
||||||
|
TemporalType temporalType = getSqlTemporalType( to.getExpressionType() );
|
||||||
|
IntervalType intervalType = getSqlIntervalType( interval.getExpressionType().getJdbcMappings().get(0) );
|
||||||
|
return new PatternRenderer( dialect.timestampaddPattern( unit, temporalType, intervalType ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderWithUnitConversion(
|
||||||
|
SqlAppender sqlAppender,
|
||||||
|
List<? extends SqlAstNode> arguments,
|
||||||
|
SqlAstTranslator<?> walker,
|
||||||
|
DurationUnit field,
|
||||||
|
TemporalUnit unit) {
|
||||||
|
final Expression magnitude = (Expression) arguments.get( 1 );
|
||||||
|
final Expression to = (Expression) arguments.get( 2 );
|
||||||
|
final Expression interval = (Expression) arguments.get(1);
|
||||||
|
|
||||||
final List<SqlAstNode> castArguments = new ArrayList<>( 2 );
|
final List<SqlAstNode> castArguments = new ArrayList<>( 2 );
|
||||||
final List<SqlAstNode> newArguments = new ArrayList<>( arguments );
|
final List<SqlAstNode> newArguments = new ArrayList<>( arguments );
|
||||||
final Expression magnitude = (Expression) arguments.get( 1 );
|
|
||||||
final BasicValuedMapping expressionType = (BasicValuedMapping) magnitude.getExpressionType();
|
|
||||||
final String conversionFactor = field.getUnit().conversionFactor( unit, dialect );
|
|
||||||
if ( conversionFactor.isEmpty() ) {
|
|
||||||
castArguments.add( magnitude );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
castArguments.add(
|
|
||||||
new BinaryArithmeticExpression(
|
|
||||||
magnitude,
|
|
||||||
conversionFactor.charAt( 0 ) == '*'
|
|
||||||
? BinaryArithmeticOperator.MULTIPLY
|
|
||||||
: BinaryArithmeticOperator.DIVIDE,
|
|
||||||
new QueryLiteral<>(
|
|
||||||
expressionType.getExpressibleJavaType()
|
|
||||||
.fromString( conversionFactor.substring( 1 ) ),
|
|
||||||
expressionType
|
|
||||||
),
|
|
||||||
expressionType
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
castArguments.add( convertedArgument( field, unit, magnitude ) );
|
||||||
castArguments.add( new CastTarget( integerType ) );
|
castArguments.add( new CastTarget( integerType ) );
|
||||||
newArguments.set( 0, new DurationUnit( unit, field.getExpressionType() ) );
|
newArguments.set( 0, new DurationUnit( unit, field.getExpressionType() ) );
|
||||||
newArguments.set(
|
newArguments.set(
|
||||||
|
@ -152,10 +120,44 @@ public class TimestampaddFunction
|
||||||
)
|
)
|
||||||
|
|
||||||
);
|
);
|
||||||
renderer.render( sqlAppender, newArguments, walker );
|
patternRenderer( to, interval, unit ).render( sqlAppender, newArguments, walker );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Expression convertedArgument(DurationUnit field, TemporalUnit unit, Expression magnitude) {
|
||||||
|
final BasicValuedMapping expressionType = (BasicValuedMapping) magnitude.getExpressionType();
|
||||||
|
final String conversionFactor = field.getUnit().conversionFactor( unit, dialect );
|
||||||
|
return conversionFactor.isEmpty()
|
||||||
|
? magnitude
|
||||||
|
: new BinaryArithmeticExpression(
|
||||||
|
magnitude,
|
||||||
|
conversionFactor.charAt(0) == '*'
|
||||||
|
? BinaryArithmeticOperator.MULTIPLY
|
||||||
|
: BinaryArithmeticOperator.DIVIDE,
|
||||||
|
new QueryLiteral<>(
|
||||||
|
expressionType.getExpressibleJavaType().fromString( conversionFactor.substring(1) ),
|
||||||
|
expressionType
|
||||||
|
),
|
||||||
|
expressionType
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TemporalUnit bestTemporalUnit(Expression magnitude, DurationUnit field) {
|
||||||
|
if ( dialect.supportsFractionalTimestampArithmetic() ) {
|
||||||
|
return field.getUnit();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
renderer.render( sqlAppender, arguments, walker );
|
final JdbcType jdbcType = magnitude.getExpressionType().getJdbcMappings().get( 0 ).getJdbcType();
|
||||||
|
if ( jdbcType.isFloat() ) {
|
||||||
|
// Some databases don't support fractional seconds
|
||||||
|
// We need to multiply the magnitude by the conversion factor and cast to int
|
||||||
|
// Use second by default and nanosecond if we encounter fractional seconds
|
||||||
|
return field.getUnit() == TemporalUnit.SECOND
|
||||||
|
? TemporalUnit.NANOSECOND
|
||||||
|
: TemporalUnit.SECOND;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return field.getUnit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4683,7 +4683,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
SqmExpression<?> leftOperand = expression.getLeftHandOperand();
|
SqmExpression<?> leftOperand = expression.getLeftHandOperand();
|
||||||
SqmExpression<?> rightOperand = expression.getRightHandOperand();
|
SqmExpression<?> rightOperand = expression.getRightHandOperand();
|
||||||
|
|
||||||
boolean durationToRight = TypeConfiguration.isDuration( rightOperand.getNodeType() );
|
boolean durationToRight = isDuration( rightOperand.getNodeType() );
|
||||||
TypeConfiguration typeConfiguration = getCreationContext().getMappingMetamodel().getTypeConfiguration();
|
TypeConfiguration typeConfiguration = getCreationContext().getMappingMetamodel().getTypeConfiguration();
|
||||||
TemporalType temporalTypeToLeft = typeConfiguration.getSqlTemporalType( leftOperand.getNodeType() );
|
TemporalType temporalTypeToLeft = typeConfiguration.getSqlTemporalType( leftOperand.getNodeType() );
|
||||||
TemporalType temporalTypeToRight = typeConfiguration.getSqlTemporalType( rightOperand.getNodeType() );
|
TemporalType temporalTypeToRight = typeConfiguration.getSqlTemporalType( rightOperand.getNodeType() );
|
||||||
|
|
Loading…
Reference in New Issue