From 821e31b48176b8eb5a8710e4730bab855676825c Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Tue, 14 Feb 2023 22:11:45 +0100 Subject: [PATCH] HHH-16185 Implement portable date_trunc function emulation and tests --- .../community/dialect/HSQLLegacyDialect.java | 1 + .../community/dialect/MySQLLegacyDialect.java | 1 + .../dialect/SQLServerLegacyDialect.java | 4 + .../dialect/SybaseLegacyDialect.java | 1 + .../dialect/AbstractHANADialect.java | 1 + .../org/hibernate/dialect/HSQLDialect.java | 1 + .../org/hibernate/dialect/MySQLDialect.java | 1 + .../hibernate/dialect/SQLServerDialect.java | 4 + .../org/hibernate/dialect/SpannerDialect.java | 3 +- .../org/hibernate/dialect/SybaseDialect.java | 1 + .../function/CommonFunctionFactory.java | 26 ++- .../dialect/function/DateTruncEmulation.java | 196 ++++++++++++++++++ .../dialect/function/DateTruncTrunc.java | 127 ++++++++++++ .../orm/test/query/hql/FunctionTests.java | 14 +- 14 files changed, 367 insertions(+), 14 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncEmulation.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncTrunc.java diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java index bfb5e17cdd..b7c14573a8 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java @@ -201,6 +201,7 @@ public class HSQLLegacyDialect extends Dialect { functionFactory.rand(); functionFactory.trunc(); // functionFactory.truncate(); + functionFactory.dateTrunc_trunc(); functionFactory.pi(); functionFactory.soundex(); functionFactory.reverse(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java index 183c02dd3a..8eb3d124c1 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java @@ -562,6 +562,7 @@ public class MySQLLegacyDialect extends Dialect { functionFactory.position(); functionFactory.nowCurdateCurtime(); functionFactory.trunc_truncate(); + functionFactory.dateTrunc_format( "str_to_date", false ); functionFactory.insert(); functionFactory.bitandorxornot_operator(); functionFactory.bitAndOr(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java index 2988715051..ab295fb4a5 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java @@ -366,6 +366,10 @@ public class SQLServerLegacyDialect extends AbstractTransactSQLDialect { } if ( getVersion().isSameOrAfter( 16 ) ) { functionFactory.leastGreatest(); + functionFactory.dateTrunc_datetrunc(); + } + else { + functionFactory.dateTrunc_format( "convert", false ); } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacyDialect.java index 1610d34c82..6e14d34cc6 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacyDialect.java @@ -218,6 +218,7 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect { functionFactory.varPopSamp(); functionFactory.trunc_floorPower(); functionFactory.round_round(); + functionFactory.dateTrunc_format( "convert", true ); // For SQL-Server we need to cast certain arguments to varchar(16384) to be able to concat them functionContributions.getFunctionRegistry().register( diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java index eebb2dada7..84e0b589ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java @@ -398,6 +398,7 @@ public abstract class AbstractHANADialect extends Dialect { functionFactory.sinh(); functionFactory.tanh(); functionFactory.trunc_roundMode(); + functionFactory.dateTrunc_format( "to_date", false ); functionFactory.log10_log(); functionFactory.log(); functionFactory.bitand(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java index 9c4fb5e866..fbf8480f20 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java @@ -142,6 +142,7 @@ public class HSQLDialect extends Dialect { functionFactory.rand(); functionFactory.trunc(); // functionFactory.truncate(); + functionFactory.dateTrunc_trunc(); functionFactory.pi(); functionFactory.soundex(); functionFactory.reverse(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index dd7c94c384..927b4fc537 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -561,6 +561,7 @@ public class MySQLDialect extends Dialect { functionFactory.position(); functionFactory.nowCurdateCurtime(); functionFactory.trunc_truncate(); + functionFactory.dateTrunc_format( "str_to_date", false ); functionFactory.insert(); functionFactory.bitandorxornot_operator(); functionFactory.bitAndOr(); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index 25641c3ecc..a8972e4a26 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -370,6 +370,10 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { } if ( getVersion().isSameOrAfter( 16 ) ) { functionFactory.leastGreatest(); + functionFactory.dateTrunc_datetrunc(); + } + else { + functionFactory.dateTrunc_format( "convert", false ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java index fea646ca18..34f0469469 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SpannerDialect.java @@ -38,6 +38,7 @@ import org.hibernate.persister.entity.Lockable; import org.hibernate.query.SemanticException; import org.hibernate.query.sqm.IntervalType; import org.hibernate.query.sqm.TemporalUnit; +import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers; import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.SqlAppender; @@ -393,7 +394,7 @@ public class SpannerDialect extends Dialect { .setExactArgumentCount( 3 ) .register(); functionContributions.getFunctionRegistry().namedDescriptorBuilder( "date_trunc" ) - .setInvariantType( dateType ) + .setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 2 ) ) .setExactArgumentCount( 2 ) .register(); functionContributions.getFunctionRegistry().namedDescriptorBuilder( "date_from_unix_date" ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java index 36ec09ed0e..ec610bdfb4 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java @@ -222,6 +222,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect { functionFactory.varPopSamp(); functionFactory.trunc_floorPower(); functionFactory.round_round(); + functionFactory.dateTrunc_format( "convert", true ); // For SQL-Server we need to cast certain arguments to varchar(16384) to be able to concat them functionContributions.getFunctionRegistry().register( 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 79a148a4bd..e67d2b59fa 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 @@ -2560,20 +2560,30 @@ public class CommonFunctionFactory { public void dateTrunc() { functionRegistry.patternDescriptorBuilder( "date_trunc", "date_trunc('?1',?2)" ) - .setInvariantType(timestampType) + .setReturnTypeResolver( useArgType( 2 ) ) .setExactArgumentCount( 2 ) - .setParameterTypes(TEMPORAL_UNIT, TEMPORAL) + .setParameterTypes( TEMPORAL_UNIT, TEMPORAL ) + .setArgumentListSignature( "(TEMPORAL_UNIT field, TEMPORAL datetime)" ) + .register(); + } + + public void dateTrunc_datetrunc() { + functionRegistry.patternDescriptorBuilder( "date_trunc", "datetrunc(?1,?2)" ) + .setReturnTypeResolver( useArgType( 2 ) ) + .setExactArgumentCount( 2 ) + .setParameterTypes( TEMPORAL_UNIT, TEMPORAL ) .setArgumentListSignature( "(TEMPORAL_UNIT field, TEMPORAL datetime)" ) .register(); } public void dateTrunc_trunc() { - functionRegistry.patternDescriptorBuilder( "date_trunc", "trunc(?2,'?1')" ) - .setInvariantType(timestampType) - .setExactArgumentCount( 2 ) - .setParameterTypes(TEMPORAL_UNIT, TEMPORAL) - .setArgumentListSignature( "(TEMPORAL_UNIT field, TEMPORAL datetime)" ) - .register(); + functionRegistry.register( "date_trunc", new DateTruncTrunc( typeConfiguration ) ); } + public void dateTrunc_format(String toDateFunction, boolean useConvertToFormat) { + functionRegistry.register( + "date_trunc", + new DateTruncEmulation( toDateFunction, useConvertToFormat, typeConfiguration ) + ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncEmulation.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncEmulation.java new file mode 100644 index 0000000000..e26c2c051e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncEmulation.java @@ -0,0 +1,196 @@ +/* + * 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.dialect.function; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.query.ReturnableType; +import org.hibernate.query.spi.QueryEngine; +import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.TemporalUnit; +import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; +import org.hibernate.query.sqm.function.FunctionRenderingSupport; +import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; +import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; +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.tree.SqmTypedNode; +import org.hibernate.query.sqm.tree.expression.SqmDurationUnit; +import org.hibernate.query.sqm.tree.expression.SqmExpression; +import org.hibernate.query.sqm.tree.expression.SqmFormat; +import org.hibernate.query.sqm.tree.expression.SqmLiteral; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.spi.SqlAppender; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.type.spi.TypeConfiguration; + +import static java.util.Arrays.asList; +import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL; +import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL_UNIT; + +/** + * Emulation of {@code datetrunc} function that leverages + * formatting the datetime to string and back to truncate it + * + * @author Marco Belladelli + */ +public class DateTruncEmulation extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport { + private final String toDateFunction; + + private final boolean useConvertToFormat; + + public DateTruncEmulation(String toDateFunction, boolean useConvertToFormat, TypeConfiguration typeConfiguration) { + super( + "date_trunc", + new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), TEMPORAL_UNIT, TEMPORAL ), + StandardFunctionReturnTypeResolvers.useArgType( 2 ), + StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL_UNIT, TEMPORAL ) + ); + this.toDateFunction = toDateFunction; + this.useConvertToFormat = useConvertToFormat; + } + + @Override + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + SqlAstTranslator walker) { + sqlAppender.appendSql( toDateFunction ); + sqlAppender.append( '(' ); + if ( !useConvertToFormat ) { + if ( toDateFunction.equalsIgnoreCase( "convert" ) ) { + sqlAppender.append( "datetime," ); + sqlAstArguments.get( 0 ).accept( walker ); + } + else { + sqlAstArguments.get( 0 ).accept( walker ); + sqlAppender.append( ',' ); + sqlAstArguments.get( 1 ).accept( walker ); + } + } + else { + // custom implementation that uses convert instead of format for Sybase + // see: https://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc36271.1600/doc/html/san1393050437990.html + sqlAppender.append( "datetime,substring(convert(varchar," ); + sqlAstArguments.get( 1 ).accept( walker ); + sqlAppender.append( ",21),1,17-len(" ); + sqlAstArguments.get( 0 ).accept( walker ); + sqlAppender.append( "))+" ); + sqlAstArguments.get( 0 ).accept( walker ); + sqlAppender.append( ",21" ); + } + sqlAppender.append( ')' ); + } + + @Override + protected SelfRenderingSqmFunction generateSqmFunctionExpression( + List> arguments, + ReturnableType impliedResultType, + QueryEngine queryEngine, + TypeConfiguration typeConfiguration) { + final NodeBuilder nodeBuilder = queryEngine.getCriteriaBuilder(); + final TemporalUnit temporalUnit = ( (SqmDurationUnit) arguments.get( 0 ) ).getUnit(); + final String pattern; + final String literal; + switch ( temporalUnit ) { + case YEAR: + pattern = "yyyy"; + literal = "-01-01 00:00:00"; + break; + case MONTH: + pattern = "yyyy-MM"; + literal = "-01 00:00:00"; + break; + case DAY: + pattern = "yyyy-MM-dd"; + literal = " 00:00:00"; + break; + case HOUR: + pattern = "yyyy-MM-dd HH"; + literal = ":00:00"; + break; + case MINUTE: + pattern = "yyyy-MM-dd HH:mm"; + literal = ":00"; + break; + case SECOND: + pattern = "yyyy-MM-dd HH:mm:ss"; + literal = null; + break; + default: + throw new UnsupportedOperationException( "Temporal unit not supported [" + temporalUnit + "]" ); + } + + final SqmTypedNode datetime = arguments.get( 1 ); + final List> args = new ArrayList<>( 2 ); + if ( !useConvertToFormat ) { + // use standard format function + final SqmExpression formatExpression = queryEngine.getSqmFunctionRegistry() + .findFunctionDescriptor( "format" ) + .generateSqmExpression( + asList( + datetime, + new SqmFormat( + pattern, + typeConfiguration.getBasicTypeForJavaType( String.class ), + nodeBuilder + ) + ), + null, + queryEngine, + typeConfiguration + ); + final SqmExpression formattedDatetime; + if ( literal != null ) { + formattedDatetime = queryEngine.getSqmFunctionRegistry() + .findFunctionDescriptor( "concat" ) + .generateSqmExpression( + asList( + formatExpression, + new SqmLiteral<>( + literal, + typeConfiguration.getBasicTypeForJavaType( String.class ), + nodeBuilder + ) + ), + null, + queryEngine, + typeConfiguration + ); + } + else { + formattedDatetime = formatExpression; + } + args.add( formattedDatetime ); + args.add( new SqmFormat( + "yyyy-MM-dd HH:mm:ss", + typeConfiguration.getBasicTypeForJavaType( String.class ), + nodeBuilder + ) ); + } + else { + args.add( new SqmLiteral<>( + literal != null ? literal.replace( "-", "/" ) : "", + typeConfiguration.getBasicTypeForJavaType( String.class ), + nodeBuilder + ) ); + args.add( datetime ); + } + return new SelfRenderingSqmFunction<>( + this, + this, + args, + impliedResultType, + getArgumentsValidator(), + getReturnTypeResolver(), + nodeBuilder, + "date_trunc" + ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncTrunc.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncTrunc.java new file mode 100644 index 0000000000..0688d64b93 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DateTruncTrunc.java @@ -0,0 +1,127 @@ +/* + * 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.dialect.function; + +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.dialect.OracleDialect; +import org.hibernate.query.ReturnableType; +import org.hibernate.query.spi.QueryEngine; +import org.hibernate.query.sqm.NodeBuilder; +import org.hibernate.query.sqm.TemporalUnit; +import org.hibernate.query.sqm.function.AbstractSqmFunctionDescriptor; +import org.hibernate.query.sqm.function.FunctionRenderingSupport; +import org.hibernate.query.sqm.function.SelfRenderingSqmFunction; +import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; +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.tree.SqmTypedNode; +import org.hibernate.query.sqm.tree.expression.SqmDurationUnit; +import org.hibernate.query.sqm.tree.expression.SqmLiteral; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.spi.SqlAppender; +import org.hibernate.sql.ast.tree.SqlAstNode; +import org.hibernate.type.spi.TypeConfiguration; + +import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL; +import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TEMPORAL_UNIT; + +/** + * Trunc function which converts the {@link TemporalUnit} + * to the format required for {@code trunc()} + * + * @author Marco Belladelli + */ +public class DateTruncTrunc extends AbstractSqmFunctionDescriptor implements FunctionRenderingSupport { + + public DateTruncTrunc(TypeConfiguration typeConfiguration) { + super( + "date_trunc", + new ArgumentTypesValidator( StandardArgumentsValidators.exactly( 2 ), TEMPORAL_UNIT, TEMPORAL ), + StandardFunctionReturnTypeResolvers.useArgType( 2 ), + StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TEMPORAL_UNIT, TEMPORAL ) + ); + } + + @Override + public void render( + SqlAppender sqlAppender, + List sqlAstArguments, + SqlAstTranslator walker) { + sqlAppender.appendSql( "trunc(" ); + sqlAstArguments.get( 1 ).accept( walker ); + sqlAppender.append( ',' ); + sqlAstArguments.get( 0 ).accept( walker ); + sqlAppender.append( ')' ); + } + + @Override + protected SelfRenderingSqmFunction generateSqmFunctionExpression( + List> arguments, + ReturnableType impliedResultType, + QueryEngine queryEngine, + TypeConfiguration typeConfiguration) { + final NodeBuilder nodeBuilder = queryEngine.getCriteriaBuilder(); + final TemporalUnit temporalUnit = ( (SqmDurationUnit) arguments.get( 0 ) ).getUnit(); + final String pattern; + switch ( temporalUnit ) { + case YEAR: + pattern = "YYYY"; + break; + case MONTH: + pattern = "MM"; + break; + case WEEK: + pattern = "IW"; + break; + case DAY: + pattern = "DD"; + break; + case HOUR: + pattern = "HH"; + break; + case MINUTE: + pattern = "MI"; + break; + case SECOND: + if ( nodeBuilder.getSessionFactory().getJdbcServices().getDialect() instanceof OracleDialect ) { + // Oracle does not support truncating to seconds with the native function, use emulation + return new DateTruncEmulation( "to_date", false, typeConfiguration ) + .generateSqmFunctionExpression( + arguments, + impliedResultType, + queryEngine, + typeConfiguration + ); + } + pattern = "SS"; + break; + default: + throw new UnsupportedOperationException( "Temporal unit not supported [" + temporalUnit + "]" ); + } + + final List> args = new ArrayList<>( 2 ); + args.add( new SqmLiteral<>( + pattern, + typeConfiguration.getBasicTypeForJavaType( String.class ), + nodeBuilder + ) ); + args.add( arguments.get( 1 ) ); + return new SelfRenderingSqmFunction<>( + this, + this, + args, + impliedResultType, + getArgumentsValidator(), + getReturnTypeResolver(), + nodeBuilder, + "date_trunc" + ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java index 14a296ff8b..392c8eccf8 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java @@ -513,13 +513,17 @@ public class FunctionTests { } @Test - @RequiresDialect(H2Dialect.class) - @RequiresDialect(DB2Dialect.class) - @RequiresDialect(OracleDialect.class) - @RequiresDialect(PostgreSQLDialect.class) + @SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't support any form of date truncation") public void testDateTruncFunction(SessionFactoryScope scope) { scope.inTransaction( - session -> session.createQuery("select date_trunc(year,current_timestamp)", Timestamp.class).getSingleResult() + session -> { + session.createQuery( "select date_trunc(year,current_timestamp)", Timestamp.class ).getSingleResult(); + session.createQuery( "select date_trunc(month,current_timestamp)", Timestamp.class ).getSingleResult(); + session.createQuery( "select date_trunc(day,current_timestamp)", Timestamp.class ).getSingleResult(); + session.createQuery( "select date_trunc(hour,current_timestamp)", Timestamp.class ).getSingleResult(); + session.createQuery( "select date_trunc(minute,current_timestamp)", Timestamp.class ).getSingleResult(); + session.createQuery( "select date_trunc(second,current_timestamp)", Timestamp.class ).getSingleResult(); + } ); }