diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java index 62fda8d2b1..ecc99eaa99 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java @@ -138,23 +138,23 @@ public class AltibaseDialect extends Dialect { } @Override - public String trimPattern(TrimSpec specification, char character) { + public String trimPattern(TrimSpec specification, boolean isWhitespace) { switch ( specification ) { case BOTH: - return character == ' ' + return isWhitespace ? "trim(?1)" - : "trim(?1, '" + character + "')"; + : "trim(?1,?2)"; case LEADING: - return character == ' ' + return isWhitespace ? "ltrim(?1)" - : "ltrim(?1,'" + character + "')"; + : "ltrim(?1,?2)"; case TRAILING: - return character == ' ' + return isWhitespace ? "rtrim(?1)" - : "rtrim(?1,'" + character + "')"; + : "rtrim(?1,?2)"; } - return super.trimPattern( specification, character ); + return super.trimPattern( specification, isWhitespace ); } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java index 746a565f32..03b25ea348 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java @@ -34,6 +34,7 @@ import org.hibernate.dialect.function.CountFunction; import org.hibernate.dialect.function.DB2FormatEmulation; import org.hibernate.dialect.function.DB2PositionFunction; import org.hibernate.dialect.function.DB2SubstringFunction; +import org.hibernate.dialect.function.TrimFunction; import org.hibernate.dialect.identity.DB2IdentityColumnSupport; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.pagination.DB2LimitHandler; @@ -403,6 +404,13 @@ public class DB2LegacyDialect extends Dialect { .setArgumentListSignature("(STRING string, STRING pattern)") .register(); + //trim() requires trim characters to be constant literals + functionContributions.getFunctionRegistry().register( "trim", new TrimFunction( + this, + functionContributions.getTypeConfiguration(), + SqlAstNodeRenderingMode.INLINE_PARAMETERS + ) ); + functionFactory.windowFunctions(); if ( getDB2Version().isSameOrAfter( 9, 5 ) ) { functionFactory.listagg( null ); 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 3a59956a70..d3ddb745a3 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 @@ -16,6 +16,7 @@ import org.hibernate.StaleObjectStateException; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.dialect.*; import org.hibernate.dialect.function.CommonFunctionFactory; +import org.hibernate.dialect.function.TrimFunction; import org.hibernate.dialect.identity.HSQLIdentityColumnSupport; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.lock.LockingStrategy; @@ -268,6 +269,13 @@ public class HSQLLegacyDialect extends Dialect { functionFactory.arrayTrim_trim_array(); functionFactory.arrayFill_hsql(); functionFactory.arrayToString_hsql(); + + //trim() requires parameters to be cast when used as trim character + functionContributions.getFunctionRegistry().register( "trim", new TrimFunction( + this, + functionContributions.getTypeConfiguration(), + SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER + ) ); } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java index fe2ee0fa27..e527bd5baa 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java @@ -203,8 +203,8 @@ public class MaxDBDialect extends Dialect { } @Override - public String trimPattern(TrimSpec specification, char character) { - return AbstractTransactSQLDialect.replaceLtrimRtrim( specification, character); + public String trimPattern(TrimSpec specification, boolean isWhitespace) { + return AbstractTransactSQLDialect.replaceLtrimRtrim( specification, isWhitespace ); } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java index 3bdea363ea..b4b111aa52 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java @@ -431,7 +431,7 @@ public class RDMSOS2200Dialect extends Dialect { } @Override - public String trimPattern(TrimSpec specification, char character) { - return AbstractTransactSQLDialect.replaceLtrimRtrim( specification, character); + public String trimPattern(TrimSpec specification, boolean isWhitespace) { + return AbstractTransactSQLDialect.replaceLtrimRtrim( specification, isWhitespace ); } } 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 53b67b94a3..0600065ad2 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 @@ -390,25 +390,25 @@ public class SQLServerLegacyDialect extends AbstractTransactSQLDialect { } @Override - public String trimPattern(TrimSpec specification, char character) { + public String trimPattern(TrimSpec specification, boolean isWhitespace) { if ( getVersion().isSameOrAfter( 16 ) ) { switch ( specification ) { case BOTH: - return character == ' ' + return isWhitespace ? "trim(?1)" - : "trim('" + character + "' from ?1)"; + : "trim(?2 from ?1)"; case LEADING: - return character == ' ' + return isWhitespace ? "ltrim(?1)" - : "ltrim(?1,'" + character + "')"; + : "ltrim(?1,?2)"; case TRAILING: - return character == ' ' + return isWhitespace ? "rtrim(?1)" - : "rtrim(?1,'" + character + "')"; + : "rtrim(?1,?2)"; } throw new UnsupportedOperationException( "Unsupported specification: " + specification ); } - return super.trimPattern( specification, character ); + return super.trimPattern( specification, isWhitespace ); } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java index 0f66ac3356..65725af641 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java @@ -353,20 +353,20 @@ public class SQLiteDialect extends Dialect { } @Override - public String trimPattern(TrimSpec specification, char character) { + public String trimPattern(TrimSpec specification, boolean isWhitespace) { switch ( specification ) { case BOTH: - return character == ' ' + return isWhitespace ? "trim(?1)" - : "trim(?1,'" + character + "')"; + : "trim(?1,?2)"; case LEADING: - return character == ' ' + return isWhitespace ? "ltrim(?1)" - : "ltrim(?1,'" + character + "')"; + : "ltrim(?1,?2)"; case TRAILING: - return character == ' ' + return isWhitespace ? "rtrim(?1)" - : "rtrim(?1,'" + character + "')"; + : "rtrim(?1,?2)"; } throw new UnsupportedOperationException( "Unsupported specification: " + specification ); } 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 5e143c7540..b5fade8185 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 @@ -425,12 +425,6 @@ public class SybaseLegacyDialect extends AbstractTransactSQLDialect { return "datediff(?1,?2,?3)"; } - @Override - public String trimPattern(TrimSpec specification, char character) { - return super.trimPattern(specification, character) - .replace("replace", "str_replace"); - } - @Override public void appendDatetimeFormat(SqlAppender appender, String format) { throw new UnsupportedOperationException( "format() function not supported on Sybase"); diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 index cb69e6bc15..1d5b5904fa 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 @@ -1369,6 +1369,7 @@ trimSpecification trimCharacter : STRING_LITERAL + | parameter ; /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java index ba2a49f1a6..2b6e5252b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractTransactSQLDialect.java @@ -166,28 +166,32 @@ public abstract class AbstractTransactSQLDialect extends Dialect { } @Override - public String trimPattern(TrimSpec specification, char character) { - return replaceLtrimRtrim(specification, character); + public String trimPattern(TrimSpec specification, boolean isWhitespace) { + return replaceLtrimRtrim( specification, isWhitespace ); } + /** + * @deprecated Use {@link #replaceLtrimRtrim(TrimSpec, boolean)} instead. + */ + @Deprecated( forRemoval = true ) public static String replaceLtrimRtrim(TrimSpec specification, char character) { - boolean blank = character == ' '; + return replaceLtrimRtrim( specification, character == ' ' ); + } + + public static String replaceLtrimRtrim(TrimSpec specification, boolean isWhitespace) { switch ( specification ) { case LEADING: - return blank + return isWhitespace ? "ltrim(?1)" - : "replace(replace(ltrim(replace(replace(?1,' ','#%#%'),'@',' ')),' ','@'),'#%#%',' ')" - .replace('@', character); + : "substring(?1,patindex('%[^'+?2+']%',?1),len(?1)-patindex('%[^'+?2+']%',?1)+1)"; case TRAILING: - return blank + return isWhitespace ? "rtrim(?1)" - : "replace(replace(rtrim(replace(replace(?1,' ','#%#%'),'@',' ')),' ','@'),'#%#%',' ')" - .replace('@', character); + : "substring(?1,1,len(?1)-patindex('%[^'+?2+']%',reverse(?1))+1)"; default: - return blank + return isWhitespace ? "ltrim(rtrim(?1))" - : "replace(replace(ltrim(rtrim(replace(replace(?1,' ','#%#%'),'@',' '))),' ','@'),'#%#%',' ')" - .replace('@', character); + : "substring(?1,patindex('%[^'+?2+']%',?1),len(?1)-patindex('%[^'+?2+']%',?1)-patindex('%[^'+?2+']%',reverse(?1))+2)"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java index 7b8e8105e5..f4503d2c8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -28,6 +28,7 @@ import org.hibernate.dialect.function.CountFunction; import org.hibernate.dialect.function.DB2FormatEmulation; import org.hibernate.dialect.function.DB2PositionFunction; import org.hibernate.dialect.function.DB2SubstringFunction; +import org.hibernate.dialect.function.TrimFunction; import org.hibernate.dialect.identity.DB2IdentityColumnSupport; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.pagination.DB2LimitHandler; @@ -391,6 +392,13 @@ public class DB2Dialect extends Dialect { .setArgumentListSignature("(STRING string, STRING pattern)") .register(); + //trim() requires trim characters to be constant literals + functionContributions.getFunctionRegistry().register( "trim", new TrimFunction( + this, + functionContributions.getTypeConfiguration(), + SqlAstNodeRenderingMode.INLINE_PARAMETERS + ) ); + functionFactory.windowFunctions(); functionFactory.listagg( null ); } 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 d937500b65..41606b5db3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -1484,11 +1484,29 @@ public abstract class Dialect implements ConversionContext, TypeContributor, Fun * * @param specification {@code leading} or {@code trailing} * @param character the character to trim + * + * @deprecated Use {@link #trimPattern(TrimSpec, boolean)} instead. */ + @Deprecated( forRemoval = true ) public String trimPattern(TrimSpec specification, char character) { - return character == ' ' - ? "trim(" + specification + " from ?1)" - : "trim(" + specification + " '" + character + "' from ?1)"; + return trimPattern( specification, character == ' ' ); + } + + /** + * Obtain a pattern for the SQL equivalent to a + * {@code trim()} function call. The resulting + * pattern must contain a ?1 placeholder for the + * argument of type {@link String} and a ?2 placeholder + * for the trim character if {@code isWhitespace} + * was false. + * + * @param specification {@linkplain TrimSpec#LEADING leading}, {@linkplain TrimSpec#TRAILING trailing} + * or {@linkplain TrimSpec#BOTH both} + * @param isWhitespace {@code true} if the trim character is a whitespace and can be omitted, + * {@code false} if it must be explicit and a ?2 placeholder should be included in the pattern + */ + public String trimPattern(TrimSpec specification, boolean isWhitespace) { + return "trim(" + specification + ( isWhitespace ? "" : " ?2" ) + " from ?1)"; } /** diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DialectDelegateWrapper.java b/hibernate-core/src/main/java/org/hibernate/dialect/DialectDelegateWrapper.java index 64befb71da..a6370d76aa 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DialectDelegateWrapper.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DialectDelegateWrapper.java @@ -290,6 +290,11 @@ public class DialectDelegateWrapper extends Dialect { return wrapped.trimPattern( specification, character ); } + @Override + public String trimPattern(TrimSpec specification, boolean isWhitespace) { + return wrapped.trimPattern( specification, isWhitespace ); + } + @Override public boolean supportsFractionalTimestampArithmetic() { return wrapped.supportsFractionalTimestampArithmetic(); 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 2357b9f9ad..f14dfac708 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HSQLDialect.java @@ -12,6 +12,7 @@ import java.sql.Types; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.dialect.function.CommonFunctionFactory; +import org.hibernate.dialect.function.TrimFunction; import org.hibernate.dialect.identity.HSQLIdentityColumnSupport; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.pagination.LimitHandler; @@ -208,6 +209,13 @@ public class HSQLDialect extends Dialect { functionFactory.arrayTrim_trim_array(); functionFactory.arrayFill_hsql(); functionFactory.arrayToString_hsql(); + + //trim() requires parameters to be cast when used as trim character + functionContributions.getFunctionRegistry().register( "trim", new TrimFunction( + this, + functionContributions.getTypeConfiguration(), + SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER + ) ); } @Override 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 f4a37338d8..beec70ab5e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -399,25 +399,25 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { } @Override - public String trimPattern(TrimSpec specification, char character) { + public String trimPattern(TrimSpec specification, boolean isWhitespace) { if ( getVersion().isSameOrAfter( 16 ) ) { switch ( specification ) { case BOTH: - return character == ' ' + return isWhitespace ? "trim(?1)" - : "trim('" + character + "' from ?1)"; + : "trim(?2 from ?1)"; case LEADING: - return character == ' ' + return isWhitespace ? "ltrim(?1)" - : "ltrim(?1,'" + character + "')"; + : "ltrim(?1,?2)"; case TRAILING: - return character == ' ' + return isWhitespace ? "rtrim(?1)" - : "rtrim(?1,'" + character + "')"; + : "rtrim(?1,?2)"; } throw new UnsupportedOperationException( "Unsupported specification: " + specification ); } - return super.trimPattern( specification, character ); + return super.trimPattern( specification, isWhitespace ); } @Override 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 a30ddc165f..0cba4a8f84 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java @@ -447,12 +447,6 @@ public class SybaseDialect extends AbstractTransactSQLDialect { return "datediff(?1,?2,?3)"; } - @Override - public String trimPattern(TrimSpec specification, char character) { - return super.trimPattern(specification, character) - .replace("replace", "str_replace"); - } - @Override public void appendDatetimeFormat(SqlAppender appender, String format) { throw new UnsupportedOperationException( "format() function not supported on Sybase"); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java index fa44b7ba69..1f39f70b72 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/TrimFunction.java @@ -6,44 +6,56 @@ */ package org.hibernate.dialect.function; +import java.util.Collections; +import java.util.List; + import org.hibernate.dialect.Dialect; import org.hibernate.query.ReturnableType; import org.hibernate.query.sqm.TrimSpec; import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescriptor; import org.hibernate.query.sqm.produce.function.ArgumentTypesValidator; +import org.hibernate.query.sqm.produce.function.FunctionArgumentException; 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.query.sqm.sql.internal.SqmParameterInterpretation; +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; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Literal; import org.hibernate.sql.ast.tree.expression.TrimSpecification; +import org.hibernate.type.SqlTypes; import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.spi.TypeConfiguration; -import java.util.Collections; -import java.util.List; - -import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TRIM_SPEC; import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING; +import static org.hibernate.query.sqm.produce.function.FunctionParameterType.TRIM_SPEC; /** * ANSI SQL-standard {@code trim()} function, which has a funny syntax * involving a {@link TrimSpec}, and portability is achieved using - * {@link Dialect#trimPattern(TrimSpec, char)}. + * {@link Dialect#trimPattern(TrimSpec, boolean)}. *
* For example, {@code trim(leading ' ' from text)}.
*
* @author Gavin King
*/
public class TrimFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
-
private final Dialect dialect;
+ private SqlAstNodeRenderingMode argumentRenderingMode;
public TrimFunction(Dialect dialect, TypeConfiguration typeConfiguration) {
+ this( dialect, typeConfiguration, SqlAstNodeRenderingMode.DEFAULT );
+ }
+
+ public TrimFunction(
+ Dialect dialect,
+ TypeConfiguration typeConfiguration,
+ SqlAstNodeRenderingMode argumentRenderingMode) {
super(
"trim",
new ArgumentTypesValidator(
@@ -56,6 +68,7 @@ public class TrimFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
StandardFunctionArgumentTypeResolvers.invariant( typeConfiguration, TRIM_SPEC, STRING, STRING )
);
this.dialect = dialect;
+ this.argumentRenderingMode = argumentRenderingMode;
}
@Override
@@ -65,12 +78,36 @@ public class TrimFunction extends AbstractSqmSelfRenderingFunctionDescriptor {
ReturnableType> returnType,
SqlAstTranslator> walker) {
final TrimSpec specification = ( (TrimSpecification) sqlAstArguments.get( 0 ) ).getSpecification();
- final Object trimCharacter = ( (Literal) sqlAstArguments.get( 1 ) ).getLiteralValue();
+ final SqlAstNode trimCharacter = sqlAstArguments.get( 1 );
+ final boolean isWhitespace = isWhitespace( trimCharacter );
final Expression sourceExpr = (Expression) sqlAstArguments.get( 2 );
- String trim = dialect.trimPattern( specification, (char) trimCharacter );
+ final String trim = dialect.trimPattern( specification, isWhitespace );
- new PatternRenderer( trim ).render( sqlAppender, Collections.singletonList( sourceExpr ), walker );
+ final List extends SqlAstNode> args = isWhitespace ?
+ Collections.singletonList( sourceExpr ) :
+ List.of( sourceExpr, trimCharacter );
+ new PatternRenderer( trim, argumentRenderingMode ).render( sqlAppender, args, walker );
+ }
+
+ private static boolean isWhitespace(SqlAstNode trimCharacter) {
+ if ( trimCharacter instanceof Literal ) {
+ final char literalValue = (char) ( (Literal) trimCharacter ).getLiteralValue();
+ return literalValue == ' ';
+ }
+ else {
+ assert trimCharacter instanceof SqmParameterInterpretation;
+ final JdbcType jdbcType = ( (SqmParameterInterpretation) trimCharacter ).getExpressionType()
+ .getSingleJdbcMapping()
+ .getJdbcType();
+ if ( jdbcType.getJdbcTypeCode() != SqlTypes.CHAR ) {
+ throw new FunctionArgumentException( String.format(
+ "Expected parameter used as trim character to be Character typed, instead was [%s]",
+ jdbcType.getFriendlyName()
+ ) );
+ }
+ return false;
+ }
}
// @Override
diff --git a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java
index ef6fd0d549..f7a34a7e9f 100644
--- a/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java
+++ b/hibernate-core/src/main/java/org/hibernate/query/hql/internal/SemanticQueryBuilder.java
@@ -4782,7 +4782,7 @@ public class SemanticQueryBuilder