HHH-18201 Configure NO_PLAIN_PARAMETER rendering mode for timestamps in timestampadd and -diff

This commit is contained in:
Christian Beikov 2024-06-04 14:42:45 +02:00
parent edbece8125
commit dba38f84fc
5 changed files with 65 additions and 13 deletions

View File

@ -1221,11 +1221,8 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun
//timestampadd()/timestampdiff() delegated back to the Dialect itself
//since there is a great variety of different ways to emulate them
functionContributions.getFunctionRegistry().register( "timestampadd",
new TimestampaddFunction( this, typeConfiguration ) );
functionContributions.getFunctionRegistry().register( "timestampdiff",
new TimestampdiffFunction( this, typeConfiguration ) );
//by default, we don't allow plain parameters for the timestamp argument as most database don't support this
functionFactory.timestampaddAndDiff( this, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
functionContributions.getFunctionRegistry().registerAlternateKey( "dateadd", "timestampadd" );
functionContributions.getFunctionRegistry().registerAlternateKey( "datediff", "timestampdiff" );

View File

@ -2381,6 +2381,29 @@ public class CommonFunctionFactory {
.register();
}
public void timestampaddAndDiff(Dialect dialect, SqlAstNodeRenderingMode timestampRenderingMode) {
functionRegistry.register(
"timestampadd",
new TimestampaddFunction(
dialect,
typeConfiguration,
SqlAstNodeRenderingMode.DEFAULT,
SqlAstNodeRenderingMode.DEFAULT,
timestampRenderingMode
)
);
functionRegistry.register(
"timestampdiff",
new TimestampdiffFunction(
dialect,
typeConfiguration,
SqlAstNodeRenderingMode.DEFAULT,
timestampRenderingMode,
timestampRenderingMode
)
);
}
/**
* MySQL style, returns the number of days between two dates
*/

View File

@ -18,6 +18,7 @@ import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -47,8 +48,13 @@ public class TimestampaddFunction
extends AbstractSqmSelfRenderingFunctionDescriptor {
private final Dialect dialect;
private final SqlAstNodeRenderingMode[] renderingModes;
public TimestampaddFunction(Dialect dialect, TypeConfiguration typeConfiguration) {
this( dialect, typeConfiguration, SqlAstNodeRenderingMode.DEFAULT );
}
public TimestampaddFunction(Dialect dialect, TypeConfiguration typeConfiguration, SqlAstNodeRenderingMode... renderingModes) {
super(
"timestampadd",
new ArgumentTypesValidator(
@ -59,6 +65,7 @@ public class TimestampaddFunction
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL_UNIT, INTEGER, TEMPORAL )
);
this.dialect = dialect;
this.renderingModes = renderingModes;
}
@Override
@ -78,7 +85,7 @@ public class TimestampaddFunction
PatternRenderer patternRenderer(TemporalUnit unit, Expression interval, Expression to) {
TemporalType temporalType = getSqlTemporalType( to.getExpressionType() );
IntervalType intervalType = getSqlIntervalType( interval.getExpressionType().getSingleJdbcMapping() );
return new PatternRenderer( dialect.timestampaddPattern( unit, temporalType, intervalType ) );
return new PatternRenderer( dialect.timestampaddPattern( unit, temporalType, intervalType ), renderingModes );
}
// @Override

View File

@ -26,6 +26,7 @@ import org.hibernate.query.sqm.produce.function.internal.PatternRenderer;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.expression.SqmDurationUnit;
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -56,8 +57,13 @@ public class TimestampdiffFunction
extends AbstractSqmSelfRenderingFunctionDescriptor {
private final Dialect dialect;
private final SqlAstNodeRenderingMode[] renderingModes;
public TimestampdiffFunction(Dialect dialect, TypeConfiguration typeConfiguration) {
this( dialect, typeConfiguration, SqlAstNodeRenderingMode.DEFAULT );
}
public TimestampdiffFunction(Dialect dialect, TypeConfiguration typeConfiguration, SqlAstNodeRenderingMode... renderingModes) {
super(
"timestampdiff",
new ArgumentTypesValidator(
@ -71,6 +77,7 @@ public class TimestampdiffFunction
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL_UNIT, TEMPORAL, TEMPORAL )
);
this.dialect = dialect;
this.renderingModes = renderingModes;
}
@Override
@ -90,7 +97,7 @@ public class TimestampdiffFunction
private PatternRenderer patternRenderer(TemporalUnit unit, Expression from, Expression to) {
TemporalType lhsTemporalType = getSqlTemporalType( from.getExpressionType() );
TemporalType rhsTemporalType = getSqlTemporalType( to.getExpressionType() );
return new PatternRenderer( dialect.timestampdiffPattern( unit, lhsTemporalType, rhsTemporalType ) );
return new PatternRenderer( dialect.timestampdiffPattern( unit, lhsTemporalType, rhsTemporalType ), renderingModes );
}
public SelfRenderingFunctionSqlAstExpression expression(

View File

@ -36,7 +36,7 @@ public class PatternRenderer {
private final int[] paramIndexes;
private final int varargParam;
private final int maxParamIndex;
private final SqlAstNodeRenderingMode argumentRenderingMode;
private final SqlAstNodeRenderingMode[] argumentRenderingModes;
public PatternRenderer(String pattern) {
this( pattern, SqlAstNodeRenderingMode.DEFAULT );
@ -49,6 +49,16 @@ public class PatternRenderer {
* @param argumentRenderingMode The rendering mode for arguments
*/
public PatternRenderer(String pattern, SqlAstNodeRenderingMode argumentRenderingMode) {
this( pattern, new SqlAstNodeRenderingMode[] { argumentRenderingMode } );
}
/**
* Constructs a template renderer
*
* @param pattern The template
* @param argumentRenderingModes The rendering modes for arguments
*/
public PatternRenderer(String pattern, SqlAstNodeRenderingMode[] argumentRenderingModes) {
final Set<Integer> paramNumbers = new HashSet<>();
final List<String> chunkList = new ArrayList<>();
final List<Integer> paramList = new ArrayList<>();
@ -116,7 +126,7 @@ public class PatternRenderer {
paramIndexes[i] = paramList.get( i );
}
this.paramIndexes = paramIndexes;
this.argumentRenderingMode = argumentRenderingMode;
this.argumentRenderingModes = argumentRenderingModes;
}
public boolean hasVarargs() {
@ -185,6 +195,7 @@ public class PatternRenderer {
for ( int i = 0; i < chunks.length; i++ ) {
if ( i == varargParam ) {
final SqlAstNodeRenderingMode argumentRenderingMode = getArgumentRenderingMode(varargParam - 1);
for ( int j = i; j < numberOfArguments; j++ ) {
final SqlAstNode arg = args.get( j );
if ( arg != null ) {
@ -217,11 +228,11 @@ public class PatternRenderer {
filter.accept( translator );
translator.getCurrentClauseStack().pop();
sqlAppender.appendSql( " then " );
translator.render( arg, argumentRenderingMode );
translator.render( arg, getArgumentRenderingMode(index) );
sqlAppender.appendSql( " else null end" );
}
else {
translator.render( arg, argumentRenderingMode );
translator.render( arg, getArgumentRenderingMode(index) );
}
}
}
@ -233,10 +244,10 @@ public class PatternRenderer {
if ( withinGroup != null && !withinGroup.isEmpty() ) {
translator.getCurrentClauseStack().push( Clause.WITHIN_GROUP );
sqlAppender.appendSql( " within group (order by" );
translator.render( withinGroup.get( 0 ), argumentRenderingMode );
translator.render( withinGroup.get( 0 ), getArgumentRenderingMode( 0 ) );
for ( int i = 1; i < withinGroup.size(); i++ ) {
sqlAppender.appendSql( SqlAppender.COMMA_SEPARATOR_CHAR );
translator.render( withinGroup.get( 0 ), argumentRenderingMode );
translator.render( withinGroup.get( 0 ), getArgumentRenderingMode( 0 ) );
}
sqlAppender.appendSql( ')' );
translator.getCurrentClauseStack().pop();
@ -267,4 +278,11 @@ public class PatternRenderer {
translator.getCurrentClauseStack().pop();
}
}
private SqlAstNodeRenderingMode getArgumentRenderingMode(int index) {
if ( index < argumentRenderingModes.length ) {
return argumentRenderingModes[index];
}
return argumentRenderingModes[argumentRenderingModes.length - 1];
}
}