From dba38f84fc8a7b16af0fdad3007a709bd5492e7b Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 4 Jun 2024 14:42:45 +0200 Subject: [PATCH] HHH-18201 Configure NO_PLAIN_PARAMETER rendering mode for timestamps in timestampadd and -diff --- .../java/org/hibernate/dialect/Dialect.java | 7 ++--- .../function/CommonFunctionFactory.java | 23 ++++++++++++++ .../function/TimestampaddFunction.java | 9 +++++- .../function/TimestampdiffFunction.java | 9 +++++- .../function/internal/PatternRenderer.java | 30 +++++++++++++++---- 5 files changed, 65 insertions(+), 13 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index a8c2acad66..399588ac20 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -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" ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java index 3fa1d183d8..0fc7902c1f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/CommonFunctionFactory.java @@ -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 */ diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampaddFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampaddFunction.java index f8513def73..6c1a4566c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampaddFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampaddFunction.java @@ -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 diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampdiffFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampdiffFunction.java index 339529a36b..37f9b9f89b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampdiffFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TimestampdiffFunction.java @@ -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( diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java index 665d855d07..20e9d56583 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/produce/function/internal/PatternRenderer.java @@ -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 paramNumbers = new HashSet<>(); final List chunkList = new ArrayList<>(); final List 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]; + } }