make TimestampaddFunction understandable using Extract Method
This commit is contained in:
parent
52c7f61815
commit
3e97fe39a7
|
@ -6,11 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.dialect.function;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.query.sqm.BinaryArithmeticOperator;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
|
||||
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.type.BasicType;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
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.TEMPORAL;
|
||||
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
|
||||
|
@ -73,89 +75,89 @@ public class TimestampaddFunction
|
|||
SqlAstTranslator<?> walker) {
|
||||
|
||||
final DurationUnit field = (DurationUnit) arguments.get( 0 );
|
||||
final Expression magnitude = (Expression) arguments.get(1);
|
||||
final Expression to = (Expression) arguments.get( 2 );
|
||||
final TemporalUnit unit;
|
||||
if ( dialect.supportsFractionalTimestampArithmetic() ) {
|
||||
unit = field.getUnit();
|
||||
|
||||
final TemporalUnit unit = bestTemporalUnit( magnitude, field );
|
||||
if ( unit != field.getUnit() ) {
|
||||
renderWithUnitConversion( sqlAppender, arguments, walker, field, unit );
|
||||
}
|
||||
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;
|
||||
}
|
||||
patternRenderer( to, magnitude, unit ).render( sqlAppender, arguments, walker );
|
||||
}
|
||||
}
|
||||
|
||||
final String pattern = dialect.timestampaddPattern(
|
||||
unit,
|
||||
TypeConfiguration.getSqlTemporalType( to.getExpressionType() ),
|
||||
TypeConfiguration.getSqlIntervalType(
|
||||
( (Expression) arguments.get( 1 ) ).getExpressionType().getJdbcMappings().get( 0 )
|
||||
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> newArguments = new ArrayList<>( arguments );
|
||||
|
||||
castArguments.add( convertedArgument( field, unit, magnitude ) );
|
||||
castArguments.add( new CastTarget( integerType ) );
|
||||
newArguments.set( 0, new DurationUnit( unit, field.getExpressionType() ) );
|
||||
newArguments.set(
|
||||
1,
|
||||
new SelfRenderingFunctionSqlAstExpression(
|
||||
"cast",
|
||||
castFunction,
|
||||
castArguments,
|
||||
integerType,
|
||||
integerType
|
||||
)
|
||||
);
|
||||
|
||||
final PatternRenderer renderer = new PatternRenderer( pattern );
|
||||
if ( unit != field.getUnit() ) {
|
||||
final List<SqlAstNode> castArguments = new ArrayList<>( 2 );
|
||||
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 );
|
||||
);
|
||||
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 {
|
||||
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 {
|
||||
castArguments.add(
|
||||
new BinaryArithmeticExpression(
|
||||
magnitude,
|
||||
conversionFactor.charAt( 0 ) == '*'
|
||||
? BinaryArithmeticOperator.MULTIPLY
|
||||
: BinaryArithmeticOperator.DIVIDE,
|
||||
new QueryLiteral<>(
|
||||
expressionType.getExpressibleJavaType()
|
||||
.fromString( conversionFactor.substring( 1 ) ),
|
||||
expressionType
|
||||
),
|
||||
expressionType
|
||||
)
|
||||
);
|
||||
return field.getUnit();
|
||||
}
|
||||
|
||||
castArguments.add( new CastTarget( integerType ) );
|
||||
newArguments.set( 0, new DurationUnit( unit, field.getExpressionType() ) );
|
||||
newArguments.set(
|
||||
1,
|
||||
new SelfRenderingFunctionSqlAstExpression(
|
||||
"cast",
|
||||
castFunction,
|
||||
castArguments,
|
||||
integerType,
|
||||
integerType
|
||||
)
|
||||
|
||||
);
|
||||
renderer.render( sqlAppender, newArguments, walker );
|
||||
}
|
||||
else {
|
||||
renderer.render( sqlAppender, arguments, walker );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4683,7 +4683,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
SqmExpression<?> leftOperand = expression.getLeftHandOperand();
|
||||
SqmExpression<?> rightOperand = expression.getRightHandOperand();
|
||||
|
||||
boolean durationToRight = TypeConfiguration.isDuration( rightOperand.getNodeType() );
|
||||
boolean durationToRight = isDuration( rightOperand.getNodeType() );
|
||||
TypeConfiguration typeConfiguration = getCreationContext().getMappingMetamodel().getTypeConfiguration();
|
||||
TemporalType temporalTypeToLeft = typeConfiguration.getSqlTemporalType( leftOperand.getNodeType() );
|
||||
TemporalType temporalTypeToRight = typeConfiguration.getSqlTemporalType( rightOperand.getNodeType() );
|
||||
|
|
Loading…
Reference in New Issue