Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@
*/
package org.hibernate.dialect.function;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.function.Supplier;

import org.hibernate.AssertionFailure;
import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.ReturnableType;
import org.hibernate.type.BindingContext;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor;
import org.hibernate.query.sqm.function.FunctionKind;
import org.hibernate.query.sqm.produce.function.ArgumentsValidator;
Expand All @@ -35,17 +34,17 @@
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.type.BasicPluralType;
import org.hibernate.type.BasicType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.ObjectJdbcType;
import org.hibernate.type.spi.TypeConfiguration;

import org.checkerframework.checker.nullness.qual.Nullable;

import static java.util.Arrays.asList;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.NUMERIC;
import static org.hibernate.type.SqlTypes.isNumericType;

/**
* @author Christian Beikov
Expand Down Expand Up @@ -90,15 +89,20 @@ public void render(
Predicate filter,
ReturnableType<?> returnType,
SqlAstTranslator<?> translator) {
final boolean caseWrapper = filter != null && !filterClauseSupported( translator );
final boolean caseWrapper =
filter != null && !filterClauseSupported( translator );
sqlAppender.appendSql( "avg(" );
final Expression arg;
if ( sqlAstArguments.get( 0 ) instanceof Distinct ) {
final var argNode = sqlAstArguments.get( 0 );
if ( argNode instanceof Distinct distinct ) {
sqlAppender.appendSql( "distinct " );
arg = ( (Distinct) sqlAstArguments.get( 0 ) ).getExpression();
arg = distinct.getExpression();
}
else if ( argNode instanceof Expression expression ) {
arg = expression;
}
else {
arg = (Expression) sqlAstArguments.get( 0 );
throw new AssertionFailure( "Unexpected argument type" );
}
if ( caseWrapper ) {
translator.getCurrentClauseStack().push( Clause.WHERE );
Expand Down Expand Up @@ -128,7 +132,7 @@ private void renderArgument(SqlAppender sqlAppender, SqlAstTranslator<?> transla
if ( sourceMapping.getJdbcType().isInteger() ) {
castFunction.render(
sqlAppender,
Arrays.asList( realArg, new CastTarget( doubleType ) ),
asList( realArg, new CastTarget( doubleType ) ),
doubleType,
translator
);
Expand Down Expand Up @@ -163,49 +167,43 @@ public void validate(
)
);
}
final SqmTypedNode<?> argument = arguments.get( 0 );
final SqmExpressible<?> expressible = argument.getExpressible();
final DomainType<?> domainType;
if ( expressible != null && ( domainType = expressible.getSqmType() ) != null ) {
final JdbcType jdbcType = getJdbcType( domainType, bindingContext.getTypeConfiguration() );
if ( !isNumeric( jdbcType ) ) {
throw new FunctionArgumentException(
String.format(
"Parameter %d of function '%s()' has type '%s', but argument is of type '%s'",
1,
functionName,
NUMERIC,
domainType.getTypeName()
)
);
final var expressible = arguments.get( 0 ).getExpressible();
if ( expressible != null ) {
final var domainType = expressible.getSqmType();
if ( domainType != null ) {
final var jdbcType = getJdbcType( domainType, bindingContext.getTypeConfiguration() );
if ( !isNumeric( jdbcType ) ) {
throw new FunctionArgumentException(
String.format(
"Parameter %d of function '%s()' has type '%s', but argument is of type '%s'",
1,
functionName,
NUMERIC,
domainType.getTypeName()
)
);
}
}
}
}

private static boolean isNumeric(JdbcType jdbcType) {
final int sqlTypeCode = jdbcType.getDefaultSqlTypeCode();
if ( SqlTypes.isNumericType( sqlTypeCode ) ) {
return true;
}
if ( jdbcType instanceof ArrayJdbcType arrayJdbcType ) {
return isNumeric( arrayJdbcType.getElementJdbcType() );
}
return false;
return isNumericType( sqlTypeCode )
|| jdbcType instanceof ArrayJdbcType arrayJdbcType
&& isNumeric( arrayJdbcType.getElementJdbcType() );
}

private static JdbcType getJdbcType(DomainType<?> domainType, TypeConfiguration typeConfiguration) {
if ( domainType instanceof JdbcMapping jdbcMapping ) {
return jdbcMapping.getJdbcType();
}
else {
final JavaType<?> javaType = domainType.getExpressibleJavaType();
if ( javaType.getJavaTypeClass().isEnum() ) {
// we can't tell if the enum is mapped STRING or ORDINAL
return ObjectJdbcType.INSTANCE;
}
else {
return javaType.getRecommendedJdbcType( typeConfiguration.getCurrentBaseSqlTypeIndicators() );
}
final var javaType = domainType.getExpressibleJavaType();
return javaType.getJavaTypeClass().isEnum()
// we can't tell if the enum is mapped STRING or ORDINAL
? ObjectJdbcType.INSTANCE
: javaType.getRecommendedJdbcType( typeConfiguration.getCurrentBaseSqlTypeIndicators() );
}
}

Expand All @@ -220,23 +218,24 @@ public static class ReturnTypeResolver implements FunctionReturnTypeResolver {
private final BasicType<Double> doubleType;

public ReturnTypeResolver(TypeConfiguration typeConfiguration) {
this.doubleType = typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE );
doubleType = typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.DOUBLE );
}

@Override
public BasicValuedMapping resolveFunctionReturnType(
Supplier<BasicValuedMapping> impliedTypeAccess,
List<? extends SqlAstNode> arguments) {
final BasicValuedMapping impliedType = impliedTypeAccess.get();
final var impliedType = impliedTypeAccess.get();
if ( impliedType != null ) {
return impliedType;
}
Expression expression = (Expression) arguments.get( 0 );
final JdbcMapping jdbcMapping = expression.getExpressionType().getSingleJdbcMapping();
if ( jdbcMapping instanceof BasicPluralType<?, ?> ) {
return (BasicValuedMapping) jdbcMapping;
else {
var expression = (Expression) arguments.get( 0 );
final var jdbcMapping = expression.getExpressionType().getSingleJdbcMapping();
return jdbcMapping instanceof BasicPluralType<?, ?>
? (BasicValuedMapping) jdbcMapping
: doubleType;
}
return doubleType;
}

@Override
Expand All @@ -245,9 +244,9 @@ public ReturnableType<?> resolveFunctionReturnType(
@Nullable SqmToSqlAstConverter converter,
List<? extends SqmTypedNode<?>> arguments,
TypeConfiguration typeConfiguration) {
final SqmExpressible<?> expressible = arguments.get( 0 ).getExpressible();
final DomainType<?> domainType;
if ( expressible != null && ( domainType = expressible.getSqmType() ) != null ) {
final var expressible = arguments.get( 0 ).getExpressible();
if ( expressible != null ) {
final var domainType = expressible.getSqmType();
if ( domainType instanceof BasicPluralType<?, ?> ) {
return (ReturnableType<?>) domainType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ public ChrLiteralEmulation(TypeConfiguration typeConfiguration) {
new ArgumentsValidator() {
@Override
public void validate(List<? extends SqmTypedNode<?>> arguments, String functionName, BindingContext bindingContext) {
if ( !( arguments.get( 0 ) instanceof SqmLiteral<?> ) ) {
final var arg = arguments.get( 0 );
if ( !( arg instanceof SqmLiteral<?> ) ) {
throw new QueryException(
String.format(
Locale.ROOT,
"Emulation of function chr() supports only integer literals, but %s argument given",
arguments.get( 0 ).getClass().getName()
arg.getClass().getName()
)
);
}
Expand All @@ -71,7 +72,7 @@ public void render(
ReturnableType<?> returnType,
SqlAstTranslator<?> walker) {
@SuppressWarnings("unchecked")
final QueryLiteral<Number> literal = (QueryLiteral<Number>) arguments.get( 0 );
final var literal = (QueryLiteral<Number>) arguments.get( 0 );
sqlAppender.appendSql( '\'' );
sqlAppender.appendSql( (char) literal.getLiteralValue().intValue() );
sqlAppender.appendSql( '\'' );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,37 +103,31 @@ protected <T> SelfRenderingSqmFunction<T> generateSqmFunctionExpression(
default:
throw new UnsupportedOperationException( "Temporal unit not supported [" + temporalUnit + "]" );
}
final SqmTypedNode<?> datetime = arguments.get( 0 );
final SqmExpression<?> formatExpression = queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor( "format" )
.generateSqmExpression(
asList(
datetime,
new SqmFormat(
pattern,
nodeBuilder.getTypeConfiguration().getBasicTypeForJavaType( String.class ),
nodeBuilder
)
),
null,
queryEngine
);
final var datetime = arguments.get( 0 );
final var formatExpression =
queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor( "format" )
.generateSqmExpression(
asList(
datetime,
new SqmFormat( pattern, nodeBuilder.getStringType(), nodeBuilder )
),
null,
queryEngine
);
final SqmExpression<?> formattedDatetime;
if ( literal != null ) {
formattedDatetime = queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor( "concat" )
.generateSqmExpression(
asList(
formatExpression,
new SqmLiteral<>(
literal,
nodeBuilder.getTypeConfiguration().getBasicTypeForJavaType( String.class ),
nodeBuilder
)
),
null,
queryEngine
);
formattedDatetime =
queryEngine.getSqmFunctionRegistry()
.findFunctionDescriptor( "concat" )
.generateSqmExpression(
asList(
formatExpression,
new SqmLiteral<>( literal, nodeBuilder.getStringType(), nodeBuilder )
),
null,
queryEngine
);
}
else {
formattedDatetime = formatExpression;
Expand Down
Loading
Loading