HHH-16185 Implement portable date_trunc function emulation and tests
This commit is contained in:
parent
d52a44c8eb
commit
789c131c2d
|
@ -201,6 +201,7 @@ public class HSQLLegacyDialect extends Dialect {
|
||||||
functionFactory.rand();
|
functionFactory.rand();
|
||||||
functionFactory.trunc();
|
functionFactory.trunc();
|
||||||
// functionFactory.truncate();
|
// functionFactory.truncate();
|
||||||
|
functionFactory.dateTrunc_trunc();
|
||||||
functionFactory.pi();
|
functionFactory.pi();
|
||||||
functionFactory.soundex();
|
functionFactory.soundex();
|
||||||
functionFactory.reverse();
|
functionFactory.reverse();
|
||||||
|
|
|
@ -562,6 +562,7 @@ public class MySQLLegacyDialect extends Dialect {
|
||||||
functionFactory.position();
|
functionFactory.position();
|
||||||
functionFactory.nowCurdateCurtime();
|
functionFactory.nowCurdateCurtime();
|
||||||
functionFactory.trunc_truncate();
|
functionFactory.trunc_truncate();
|
||||||
|
functionFactory.dateTrunc_format( "str_to_date", false );
|
||||||
functionFactory.insert();
|
functionFactory.insert();
|
||||||
functionFactory.bitandorxornot_operator();
|
functionFactory.bitandorxornot_operator();
|
||||||
functionFactory.bitAndOr();
|
functionFactory.bitAndOr();
|
||||||
|
|
|
@ -366,6 +366,10 @@ public class SQLServerLegacyDialect extends AbstractTransactSQLDialect {
|
||||||
}
|
}
|
||||||
if ( getVersion().isSameOrAfter( 16 ) ) {
|
if ( getVersion().isSameOrAfter( 16 ) ) {
|
||||||
functionFactory.leastGreatest();
|
functionFactory.leastGreatest();
|
||||||
|
functionFactory.dateTrunc_datetrunc();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
functionFactory.dateTrunc_format( "convert", false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -218,6 +218,7 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect {
|
||||||
functionFactory.varPopSamp();
|
functionFactory.varPopSamp();
|
||||||
functionFactory.trunc_floorPower();
|
functionFactory.trunc_floorPower();
|
||||||
functionFactory.round_round();
|
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
|
// For SQL-Server we need to cast certain arguments to varchar(16384) to be able to concat them
|
||||||
functionContributions.getFunctionRegistry().register(
|
functionContributions.getFunctionRegistry().register(
|
||||||
|
|
|
@ -398,6 +398,7 @@ public abstract class AbstractHANADialect extends Dialect {
|
||||||
functionFactory.sinh();
|
functionFactory.sinh();
|
||||||
functionFactory.tanh();
|
functionFactory.tanh();
|
||||||
functionFactory.trunc_roundMode();
|
functionFactory.trunc_roundMode();
|
||||||
|
functionFactory.dateTrunc_format( "to_date", false );
|
||||||
functionFactory.log10_log();
|
functionFactory.log10_log();
|
||||||
functionFactory.log();
|
functionFactory.log();
|
||||||
functionFactory.bitand();
|
functionFactory.bitand();
|
||||||
|
|
|
@ -142,6 +142,7 @@ public class HSQLDialect extends Dialect {
|
||||||
functionFactory.rand();
|
functionFactory.rand();
|
||||||
functionFactory.trunc();
|
functionFactory.trunc();
|
||||||
// functionFactory.truncate();
|
// functionFactory.truncate();
|
||||||
|
functionFactory.dateTrunc_trunc();
|
||||||
functionFactory.pi();
|
functionFactory.pi();
|
||||||
functionFactory.soundex();
|
functionFactory.soundex();
|
||||||
functionFactory.reverse();
|
functionFactory.reverse();
|
||||||
|
|
|
@ -561,6 +561,7 @@ public class MySQLDialect extends Dialect {
|
||||||
functionFactory.position();
|
functionFactory.position();
|
||||||
functionFactory.nowCurdateCurtime();
|
functionFactory.nowCurdateCurtime();
|
||||||
functionFactory.trunc_truncate();
|
functionFactory.trunc_truncate();
|
||||||
|
functionFactory.dateTrunc_format( "str_to_date", false );
|
||||||
functionFactory.insert();
|
functionFactory.insert();
|
||||||
functionFactory.bitandorxornot_operator();
|
functionFactory.bitandorxornot_operator();
|
||||||
functionFactory.bitAndOr();
|
functionFactory.bitAndOr();
|
||||||
|
|
|
@ -370,6 +370,10 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
|
||||||
}
|
}
|
||||||
if ( getVersion().isSameOrAfter( 16 ) ) {
|
if ( getVersion().isSameOrAfter( 16 ) ) {
|
||||||
functionFactory.leastGreatest();
|
functionFactory.leastGreatest();
|
||||||
|
functionFactory.dateTrunc_datetrunc();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
functionFactory.dateTrunc_format( "convert", false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.hibernate.persister.entity.Lockable;
|
||||||
import org.hibernate.query.SemanticException;
|
import org.hibernate.query.SemanticException;
|
||||||
import org.hibernate.query.sqm.IntervalType;
|
import org.hibernate.query.sqm.IntervalType;
|
||||||
import org.hibernate.query.sqm.TemporalUnit;
|
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.SqlAstTranslator;
|
||||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||||
|
@ -393,7 +394,7 @@ public class SpannerDialect extends Dialect {
|
||||||
.setExactArgumentCount( 3 )
|
.setExactArgumentCount( 3 )
|
||||||
.register();
|
.register();
|
||||||
functionContributions.getFunctionRegistry().namedDescriptorBuilder( "date_trunc" )
|
functionContributions.getFunctionRegistry().namedDescriptorBuilder( "date_trunc" )
|
||||||
.setInvariantType( dateType )
|
.setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useArgType( 2 ) )
|
||||||
.setExactArgumentCount( 2 )
|
.setExactArgumentCount( 2 )
|
||||||
.register();
|
.register();
|
||||||
functionContributions.getFunctionRegistry().namedDescriptorBuilder( "date_from_unix_date" )
|
functionContributions.getFunctionRegistry().namedDescriptorBuilder( "date_from_unix_date" )
|
||||||
|
|
|
@ -222,6 +222,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
|
||||||
functionFactory.varPopSamp();
|
functionFactory.varPopSamp();
|
||||||
functionFactory.trunc_floorPower();
|
functionFactory.trunc_floorPower();
|
||||||
functionFactory.round_round();
|
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
|
// For SQL-Server we need to cast certain arguments to varchar(16384) to be able to concat them
|
||||||
functionContributions.getFunctionRegistry().register(
|
functionContributions.getFunctionRegistry().register(
|
||||||
|
|
|
@ -2560,7 +2560,16 @@ public class CommonFunctionFactory {
|
||||||
|
|
||||||
public void dateTrunc() {
|
public void dateTrunc() {
|
||||||
functionRegistry.patternDescriptorBuilder( "date_trunc", "date_trunc('?1',?2)" )
|
functionRegistry.patternDescriptorBuilder( "date_trunc", "date_trunc('?1',?2)" )
|
||||||
.setInvariantType(timestampType)
|
.setReturnTypeResolver( useArgType( 2 ) )
|
||||||
|
.setExactArgumentCount( 2 )
|
||||||
|
.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 )
|
.setExactArgumentCount( 2 )
|
||||||
.setParameterTypes( TEMPORAL_UNIT, TEMPORAL )
|
.setParameterTypes( TEMPORAL_UNIT, TEMPORAL )
|
||||||
.setArgumentListSignature( "(TEMPORAL_UNIT field, TEMPORAL datetime)" )
|
.setArgumentListSignature( "(TEMPORAL_UNIT field, TEMPORAL datetime)" )
|
||||||
|
@ -2568,12 +2577,13 @@ public class CommonFunctionFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void dateTrunc_trunc() {
|
public void dateTrunc_trunc() {
|
||||||
functionRegistry.patternDescriptorBuilder( "date_trunc", "trunc(?2,'?1')" )
|
functionRegistry.register( "date_trunc", new DateTruncTrunc( typeConfiguration ) );
|
||||||
.setInvariantType(timestampType)
|
|
||||||
.setExactArgumentCount( 2 )
|
|
||||||
.setParameterTypes(TEMPORAL_UNIT, TEMPORAL)
|
|
||||||
.setArgumentListSignature( "(TEMPORAL_UNIT field, TEMPORAL datetime)" )
|
|
||||||
.register();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void dateTrunc_format(String toDateFunction, boolean useConvertToFormat) {
|
||||||
|
functionRegistry.register(
|
||||||
|
"date_trunc",
|
||||||
|
new DateTruncEmulation( toDateFunction, useConvertToFormat, typeConfiguration )
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<? extends SqlAstNode> 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 <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
|
||||||
|
List<? extends SqmTypedNode<?>> arguments,
|
||||||
|
ReturnableType<T> 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<SqmTypedNode<?>> 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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<? extends SqlAstNode> sqlAstArguments,
|
||||||
|
SqlAstTranslator<?> walker) {
|
||||||
|
sqlAppender.appendSql( "trunc(" );
|
||||||
|
sqlAstArguments.get( 1 ).accept( walker );
|
||||||
|
sqlAppender.append( ',' );
|
||||||
|
sqlAstArguments.get( 0 ).accept( walker );
|
||||||
|
sqlAppender.append( ')' );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
|
||||||
|
List<? extends SqmTypedNode<?>> arguments,
|
||||||
|
ReturnableType<T> 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<SqmTypedNode<?>> 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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -513,13 +513,17 @@ public class FunctionTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@RequiresDialect(H2Dialect.class)
|
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby doesn't support any form of date truncation")
|
||||||
@RequiresDialect(DB2Dialect.class)
|
|
||||||
@RequiresDialect(OracleDialect.class)
|
|
||||||
@RequiresDialect(PostgreSQLDialect.class)
|
|
||||||
public void testDateTruncFunction(SessionFactoryScope scope) {
|
public void testDateTruncFunction(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
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();
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue