Skip to content

Commit

Permalink
HHH-17435 --wip-- allow parameters as trim character
Browse files Browse the repository at this point in the history
  • Loading branch information
mbladel committed Jan 4, 2024
1 parent c3d8c82 commit 07db7b4
Show file tree
Hide file tree
Showing 14 changed files with 140 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,23 @@ public int getDefaultStatementBatchSize() {
}

@Override
public String trimPattern(TrimSpec specification, char character) {
final String charString = trimCharString( character );
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
switch ( specification ) {
case BOTH:
return charString == null
? "trim(?1)"
: "trim(?1, " + charString + ")";
return explicitCharacter ?
"trim(?1,?2)"
: "trim(?1)";
case LEADING:
return charString == null
? "ltrim(?1)"
: "ltrim(?1," + charString + ")";
return explicitCharacter ?
"ltrim(?1,?2)"
: "ltrim(?1)";
case TRAILING:
return charString == null
? "rtrim(?1)"
: "rtrim(?1," + charString + ")";
return explicitCharacter ?
"rtrim(?1,?2)"
: "rtrim(?1)";
}

return super.trimPattern( specification, character );
return super.trimPattern( specification, explicitCharacter );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
}

@Override
public String trimPattern(TrimSpec specification, char character) {
return AbstractTransactSQLDialect.replaceLtrimRtrim( specification, character);
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
return AbstractTransactSQLDialect.replaceLtrimRtrim( specification, explicitCharacter );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ public void appendDatetimeFormat(SqlAppender appender, String format) {
}

@Override
public String trimPattern(TrimSpec specification, char character) {
return AbstractTransactSQLDialect.replaceLtrimRtrim( specification, character);
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
return AbstractTransactSQLDialect.replaceLtrimRtrim( specification, explicitCharacter );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -390,26 +390,25 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
}

@Override
public String trimPattern(TrimSpec specification, char character) {
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
if ( getVersion().isSameOrAfter( 16 ) ) {
final String charString = trimCharString( character );
switch ( specification ) {
case BOTH:
return charString == null
? "trim(?1)"
: "trim(" + charString + " from ?1)";
return explicitCharacter
? "trim(?2 from ?1)"
: "trim(?1)";
case LEADING:
return charString == null
? "ltrim(?1)"
: "ltrim(?1," + charString + ")";
return explicitCharacter
? "ltrim(?1,?2)"
: "ltrim(?1)";
case TRAILING:
return charString == null
? "rtrim(?1)"
: "rtrim(?1," + charString + ")";
return explicitCharacter
? "rtrim(?1,?2)"
: "rtrim(?1)";
}
throw new UnsupportedOperationException( "Unsupported specification: " + specification );
}
return super.trimPattern( specification, character );
return super.trimPattern( specification, explicitCharacter );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,21 +353,20 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
}

@Override
public String trimPattern(TrimSpec specification, char character) {
final String charString = trimCharString( character );
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
switch ( specification ) {
case BOTH:
return charString == null
? "trim(?1)"
: "trim(?1," + charString + ")";
return explicitCharacter
? "trim(?1,?2)"
: "trim(?1)";
case LEADING:
return charString == null
? "ltrim(?1)"
: "ltrim(?1," + charString + ")";
return explicitCharacter
? "ltrim(?1,?2)"
: "ltrim(?1)";
case TRAILING:
return charString == null
? "rtrim(?1)"
: "rtrim(?1," + charString + ")";
return explicitCharacter
? "rtrim(?1,?2)"
: "rtrim(?1)";
}
throw new UnsupportedOperationException( "Unsupported specification: " + specification );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,8 @@ public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalT
}

@Override
public String trimPattern(TrimSpec specification, char character) {
return super.trimPattern(specification, character)
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
return super.trimPattern(specification, explicitCharacter)
.replace("replace", "str_replace");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1369,6 +1369,7 @@ trimSpecification

trimCharacter
: STRING_LITERAL
| parameter
;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,28 +166,24 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
}

@Override
public String trimPattern(TrimSpec specification, char character) {
return replaceLtrimRtrim(specification, character);
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
return replaceLtrimRtrim( specification, explicitCharacter );
}

public static String replaceLtrimRtrim(TrimSpec specification, char character) {
final String charString = trimCharString( character );
public static String replaceLtrimRtrim(TrimSpec specification, boolean explicitCharacter) {
switch ( specification ) {
case LEADING:
return charString == null
? "ltrim(?1)"
: "replace(replace(ltrim(replace(replace(?1,' ','#%#%'),'@',' ')),' ','@'),'#%#%',' ')"
.replace("@", charString);
return explicitCharacter
? "replace(replace(ltrim(replace(replace(?1,' ','#%#%'),?2,' ')),' ',?2),'#%#%',' ')"
: "ltrim(?1)";
case TRAILING:
return charString == null
? "rtrim(?1)"
: "replace(replace(rtrim(replace(replace(?1,' ','#%#%'),'@',' ')),' ','@'),'#%#%',' ')"
.replace("@", charString);
return explicitCharacter
? "replace(replace(rtrim(replace(replace(?1,' ','#%#%'),?2,' ')),' ',?2),'#%#%',' ')"
: "rtrim(?1)";
default:
return charString == null
? "ltrim(rtrim(?1))"
: "replace(replace(ltrim(rtrim(replace(replace(?1,' ','#%#%'),'@',' '))),' ','@'),'#%#%',' ')"
.replace("@", charString);
return explicitCharacter
? "replace(replace(ltrim(rtrim(replace(replace(?1,' ','#%#%'),?2,' '))),' ',?2),'#%#%',' ')"
: "ltrim(rtrim(?1))";
}
}

Expand Down
38 changes: 18 additions & 20 deletions hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java
Original file line number Diff line number Diff line change
Expand Up @@ -1484,30 +1484,28 @@ public String castPattern(CastType from, CastType to) {
*
* @param specification {@code leading} or {@code trailing}
* @param character the character to trim
*
* @deprecated Use {@link #trimPattern(TrimSpec, boolean)} instead.
*/
@Deprecated
@Deprecated( since = "6.5" )
public String trimPattern(TrimSpec specification, char character) {
final String charString = trimCharString( character );
return "trim(" + specification + ( charString == null ? "" : " " + charString ) + " from ?1)";
}

public String trimPattern(TrimSpec specification, boolean customCharacter) {
return "trim(" + specification + (customCharacter ? " ?2" : "" ) + " from ?1)";
return trimPattern( specification, character != ' ' );
}

protected static String trimCharString(char character) {
final String charString;
switch (character) {
case ' ':
charString = null;
break;
case '\'':
charString = "''''";
break;
default:
charString = "'" + character + "'";
}
return charString;
/**
* 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 explicitCharacter}
* was specified.
*
* @param specification {@code leading} or {@code trailing}
* @param explicitCharacter {@code true} if the pattern must include a ?2 placeholder
* for an explicit trim charachter, {@code false} otherwise
*/
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
return "trim(" + specification + ( explicitCharacter ? " ?2" : "" ) + " from ?1)";
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,11 @@ public String trimPattern(TrimSpec specification, char character) {
return wrapped.trimPattern( specification, character );
}

@Override
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
return wrapped.trimPattern( specification, explicitCharacter );
}

@Override
public boolean supportsFractionalTimestampArithmetic() {
return wrapped.supportsFractionalTimestampArithmetic();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,26 +399,25 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
}

@Override
public String trimPattern(TrimSpec specification, char character) {
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
if ( getVersion().isSameOrAfter( 16 ) ) {
final String charString = trimCharString( character );
switch ( specification ) {
case BOTH:
return charString == null
? "trim(?1)"
: "trim(" + charString + " from ?1)";
return explicitCharacter
? "trim(?2 from ?1)"
: "trim(?1)";
case LEADING:
return charString == null
? "ltrim(?1)"
: "ltrim(?1," + charString + ")";
return explicitCharacter
? "ltrim(?1,?2)"
: "ltrim(?1)";
case TRAILING:
return charString == null
? "rtrim(?1)"
: "rtrim(?1," + charString + ")";
return explicitCharacter
? "rtrim(?1,?2)"
: "rtrim(?1)";
}
throw new UnsupportedOperationException( "Unsupported specification: " + specification );
}
return super.trimPattern( specification, character );
return super.trimPattern( specification, explicitCharacter );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,8 @@ public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalT
}

@Override
public String trimPattern(TrimSpec specification, char character) {
return super.trimPattern(specification, character)
public String trimPattern(TrimSpec specification, boolean explicitCharacter) {
return super.trimPattern(specification, explicitCharacter)
.replace("replace", "str_replace");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,39 @@
*/
package org.hibernate.dialect.function;

import java.util.Collections;
import java.util.List;

import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
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.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)}.
* <p>
* For example, {@code trim(leading ' ' from text)}.
*
Expand Down Expand Up @@ -65,12 +70,36 @@ public void render(
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 explicitChar = isExplicitChar( trimCharacter );
final Expression sourceExpr = (Expression) sqlAstArguments.get( 2 );

String trim = dialect.trimPattern( specification, (char) trimCharacter );
final String trim = dialect.trimPattern( specification, explicitChar );

final List<? extends SqlAstNode> args = explicitChar ?
List.of( sourceExpr, trimCharacter ) :
Collections.singletonList( sourceExpr );
new PatternRenderer( trim ).render( sqlAppender, args, walker );
}

new PatternRenderer( trim ).render( sqlAppender, Collections.singletonList( sourceExpr ), walker );
private static boolean isExplicitChar(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 binding used as trim character must to be Character typed, instead was [%s]",
jdbcType.getFriendlyName()
) );
}
return true;
}
}

// @Override
Expand Down
Loading

0 comments on commit 07db7b4

Please sign in to comment.