HHH-3701 : trim function emulation for sybase
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15860 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
5e77669afd
commit
1e45c666e6
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.dialect.function;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.engine.Mapping;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A {@link org.hibernate.dialect.function.SQLFunction} providing support for implementing TRIM functionality
|
||||
* (as defined by both the ANSI SQL and JPA specs) in cases where the dialect may not support the full <tt>trim</tt>
|
||||
* function itself.
|
||||
* <p/>
|
||||
* Follows the <a href="http://en.wikipedia.org/wiki/Template_method_pattern">template</a> pattern in order to implement
|
||||
* the {@link #render} method.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractAnsiTrimEmulationFunction implements SQLFunction {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public final Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
|
||||
return Hibernate.STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public final boolean hasArguments() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public final boolean hasParenthesesIfNoArguments() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public final String render(List args, SessionFactoryImplementor factory) throws QueryException {
|
||||
// According to both the ANSI-SQL and JPA specs, trim takes a variable number of parameters between 1 and 4.
|
||||
// at least one paramer (trimSource) is required. From the SQL spec:
|
||||
//
|
||||
// <trim function> ::=
|
||||
// TRIM <left paren> <trim operands> <right paren>
|
||||
//
|
||||
// <trim operands> ::=
|
||||
// [ [ <trim specification> ] [ <trim character> ] FROM ] <trim source>
|
||||
//
|
||||
// <trim specification> ::=
|
||||
// LEADING
|
||||
// | TRAILING
|
||||
// | BOTH
|
||||
//
|
||||
// If <trim specification> is omitted, BOTH is assumed.
|
||||
// If <trim character> is omitted, space is assumed
|
||||
if ( args.size() == 1 ) {
|
||||
// we have the form: trim(trimSource)
|
||||
// so we trim leading and trailing spaces
|
||||
return resolveBothSpaceTrimFunction().render( args, factory ); // EARLY EXIT!!!!
|
||||
}
|
||||
else if ( "from".equalsIgnoreCase( ( String ) args.get( 0 ) ) ) {
|
||||
// we have the form: trim(from trimSource).
|
||||
// This is functionally equivalent to trim(trimSource)
|
||||
return resolveBothSpaceTrimFromFunction().render( args, factory ); // EARLY EXIT!!!!
|
||||
}
|
||||
else {
|
||||
// otherwise, a trim-specification and/or a trim-character
|
||||
// have been specified; we need to decide which options
|
||||
// are present and "do the right thing"
|
||||
boolean leading = true; // should leading trim-characters be trimmed?
|
||||
boolean trailing = true; // should trailing trim-characters be trimmed?
|
||||
String trimCharacter; // the trim-character (what is to be trimmed off?)
|
||||
String trimSource; // the trim-source (from where should it be trimmed?)
|
||||
|
||||
// potentialTrimCharacterArgIndex = 1 assumes that a
|
||||
// trim-specification has been specified. we handle the
|
||||
// exception to that explicitly
|
||||
int potentialTrimCharacterArgIndex = 1;
|
||||
String firstArg = ( String ) args.get( 0 );
|
||||
if ( "leading".equalsIgnoreCase( firstArg ) ) {
|
||||
trailing = false;
|
||||
}
|
||||
else if ( "trailing".equalsIgnoreCase( firstArg ) ) {
|
||||
leading = false;
|
||||
}
|
||||
else if ( "both".equalsIgnoreCase( firstArg ) ) {
|
||||
}
|
||||
else {
|
||||
potentialTrimCharacterArgIndex = 0;
|
||||
}
|
||||
|
||||
String potentialTrimCharacter = ( String ) args.get( potentialTrimCharacterArgIndex );
|
||||
if ( "from".equalsIgnoreCase( potentialTrimCharacter ) ) {
|
||||
trimCharacter = "' '";
|
||||
trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
|
||||
}
|
||||
else if ( potentialTrimCharacterArgIndex + 1 >= args.size() ) {
|
||||
trimCharacter = "' '";
|
||||
trimSource = potentialTrimCharacter;
|
||||
}
|
||||
else {
|
||||
trimCharacter = potentialTrimCharacter;
|
||||
if ( "from".equalsIgnoreCase( ( String ) args.get( potentialTrimCharacterArgIndex + 1 ) ) ) {
|
||||
trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 2 );
|
||||
}
|
||||
else {
|
||||
trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
List argsToUse = new ArrayList();
|
||||
argsToUse.add( trimSource );
|
||||
argsToUse.add( trimCharacter );
|
||||
|
||||
if ( trimCharacter.equals( "' '" ) ) {
|
||||
if ( leading && trailing ) {
|
||||
return resolveBothSpaceTrimFunction().render( argsToUse, factory );
|
||||
}
|
||||
else if ( leading ) {
|
||||
return resolveLeadingSpaceTrimFunction().render( argsToUse, factory );
|
||||
}
|
||||
else {
|
||||
return resolveTrailingSpaceTrimFunction().render( argsToUse, factory );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( leading && trailing ) {
|
||||
return resolveBothTrimFunction().render( argsToUse, factory );
|
||||
}
|
||||
else if ( leading ) {
|
||||
return resolveLeadingTrimFunction().render( argsToUse, factory );
|
||||
}
|
||||
else {
|
||||
return resolveTrailingTrimFunction().render( argsToUse, factory );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the function definition which should be used to trim both leading and trailing spaces.
|
||||
* <p/>
|
||||
* In this form, the imput arguments is missing the <tt>FROM</tt> keyword.
|
||||
*
|
||||
* @return The sql function
|
||||
*/
|
||||
protected abstract SQLFunction resolveBothSpaceTrimFunction();
|
||||
|
||||
/**
|
||||
* Resolve the function definition which should be used to trim both leading and trailing spaces.
|
||||
* <p/>
|
||||
* The same as {#link resolveBothSpaceTrimFunction} except that here the<tt>FROM</tt> is included and
|
||||
* will need to be accounted for during {@link SQLFunction#render} processing.
|
||||
*
|
||||
* @return The sql function
|
||||
*/
|
||||
protected abstract SQLFunction resolveBothSpaceTrimFromFunction();
|
||||
|
||||
/**
|
||||
* Resolve the function definition which should be used to trim leading spaces.
|
||||
*
|
||||
* @return The sql function
|
||||
*/
|
||||
protected abstract SQLFunction resolveLeadingSpaceTrimFunction();
|
||||
|
||||
/**
|
||||
* Resolve the function definition which should be used to trim trailing spaces.
|
||||
*
|
||||
* @return The sql function
|
||||
*/
|
||||
protected abstract SQLFunction resolveTrailingSpaceTrimFunction();
|
||||
|
||||
/**
|
||||
* Resolve the function definition which should be used to trim the specified character from both the
|
||||
* beginning (leading) and end (trailing) of the trim source.
|
||||
*
|
||||
* @return The sql function
|
||||
*/
|
||||
protected abstract SQLFunction resolveBothTrimFunction();
|
||||
|
||||
/**
|
||||
* Resolve the function definition which should be used to trim the specified character from the
|
||||
* beginning (leading) of the trim source.
|
||||
*
|
||||
* @return The sql function
|
||||
*/
|
||||
protected abstract SQLFunction resolveLeadingTrimFunction();
|
||||
|
||||
/**
|
||||
* Resolve the function definition which should be used to trim the specified character from the
|
||||
* end (trailing) of the trim source.
|
||||
*
|
||||
* @return The sql function
|
||||
*/
|
||||
protected abstract SQLFunction resolveTrailingTrimFunction();
|
||||
}
|
|
@ -25,13 +25,6 @@
|
|||
package org.hibernate.dialect.function;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.engine.Mapping;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A {@link SQLFunction} implementation that emulates the ANSI SQL trim function
|
||||
|
@ -42,129 +35,222 @@ import java.util.ArrayList;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AnsiTrimEmulationFunction implements SQLFunction {
|
||||
public class AnsiTrimEmulationFunction extends AbstractAnsiTrimEmulationFunction {
|
||||
public static final String LTRIM = "ltrim";
|
||||
public static final String RTRIM = "rtrim";
|
||||
public static final String REPLACE = "replace";
|
||||
public static final String SPACE_PLACEHOLDER = "${space}$";
|
||||
|
||||
private static final SQLFunction LEADING_SPACE_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "ltrim( ?1 )");
|
||||
private static final SQLFunction TRAILING_SPACE_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "rtrim( ?1 )");
|
||||
private static final SQLFunction BOTH_SPACE_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "ltrim( rtrim( ?1 ) )");
|
||||
private static final SQLFunction BOTH_SPACE_TRIM_FROM = new SQLFunctionTemplate( Hibernate.STRING, "ltrim( rtrim( ?2 ) )");
|
||||
public static final String LEADING_SPACE_TRIM_TEMPLATE = LTRIM + "(?1)";
|
||||
public static final String TRAILING_SPACE_TRIM_TEMPLATE = RTRIM + "(?1)";
|
||||
public static final String BOTH_SPACE_TRIM_TEMPLATE = LTRIM + "(" + RTRIM + "(?1))";
|
||||
public static final String BOTH_SPACE_TRIM_FROM_TEMPLATE = LTRIM + "(" + RTRIM + "(?2))"; //skip the FROM keyword in params
|
||||
|
||||
private static final SQLFunction LEADING_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "replace( replace( rtrim( replace( replace( ?1, ' ', '${space}$' ), ?2, ' ' ) ), ' ', ?2 ), '${space}$', ' ' )" );
|
||||
private static final SQLFunction TRAILING_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "replace( replace( ltrim( replace( replace( ?1, ' ', '${space}$' ), ?2, ' ' ) ), ' ', ?2 ), '${space}$', ' ' )" );
|
||||
private static final SQLFunction BOTH_TRIM = new SQLFunctionTemplate( Hibernate.STRING, "replace( replace( ltrim( rtrim( replace( replace( ?1, ' ', '${space}$' ), ?2, ' ' ) ) ), ' ', ?2 ), '${space}$', ' ' )" );
|
||||
/**
|
||||
* A template for the series of calls required to trim non-space chars from the beginning of text.
|
||||
* <p/>
|
||||
* NOTE : essentially we:</ol>
|
||||
* <li>replace all space chars with the text '${space}$'</li>
|
||||
* <li>replace all the actual replacement chars with space chars</li>
|
||||
* <li>perform left-trimming (that removes any of the space chars we just added which occur at the beginning of the text)</li>
|
||||
* <li>replace all space chars with the replacement char</li>
|
||||
* <li>replace all the '${space}$' text with space chars</li>
|
||||
* </ol>
|
||||
*/
|
||||
public static final String LEADING_TRIM_TEMPLATE =
|
||||
REPLACE + "(" +
|
||||
REPLACE + "(" +
|
||||
LTRIM + "(" +
|
||||
REPLACE + "(" +
|
||||
REPLACE + "(" +
|
||||
"?1," +
|
||||
"' '," +
|
||||
"'" + SPACE_PLACEHOLDER + "'" +
|
||||
")," +
|
||||
"?2," +
|
||||
"' '" +
|
||||
")" +
|
||||
")," +
|
||||
"' '," +
|
||||
"?2" +
|
||||
")," +
|
||||
"'" + SPACE_PLACEHOLDER + "'," +
|
||||
"' '" +
|
||||
")";
|
||||
|
||||
public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
|
||||
return Hibernate.STRING;
|
||||
/**
|
||||
* A template for the series of calls required to trim non-space chars from the end of text.
|
||||
* <p/>
|
||||
* NOTE: essentially the same series of calls as outlined in {@link #LEADING_TRIM_TEMPLATE} except that here,
|
||||
* instead of left-trimming the added spaces, we right-trim them to remove them from the end of the text.
|
||||
*/
|
||||
public static final String TRAILING_TRIM_TEMPLATE =
|
||||
REPLACE + "(" +
|
||||
REPLACE + "(" +
|
||||
RTRIM + "(" +
|
||||
REPLACE + "(" +
|
||||
REPLACE + "(" +
|
||||
"?1," +
|
||||
"' '," +
|
||||
"'" + SPACE_PLACEHOLDER + "'" +
|
||||
")," +
|
||||
"?2," +
|
||||
"' '" +
|
||||
")" +
|
||||
")," +
|
||||
"' '," +
|
||||
"?2" +
|
||||
")," +
|
||||
"'" + SPACE_PLACEHOLDER + "'," +
|
||||
"' '" +
|
||||
")";
|
||||
|
||||
/**
|
||||
* A template for the series of calls required to trim non-space chars from both the beginning and the end of text.
|
||||
* <p/>
|
||||
* NOTE: again, we have a series of calls that is essentially the same as outlined in {@link #LEADING_TRIM_TEMPLATE}
|
||||
* except that here we perform both left (leading) and right (trailing) trimming.
|
||||
*/
|
||||
public static final String BOTH_TRIM_TEMPLATE =
|
||||
REPLACE + "(" +
|
||||
REPLACE + "(" +
|
||||
LTRIM + "(" +
|
||||
RTRIM + "(" +
|
||||
REPLACE + "(" +
|
||||
REPLACE + "(" +
|
||||
"?1," +
|
||||
"' '," +
|
||||
"'" + SPACE_PLACEHOLDER + "'" +
|
||||
")," +
|
||||
"?2," +
|
||||
"' '" +
|
||||
")" +
|
||||
")" +
|
||||
")," +
|
||||
"' '," +
|
||||
"?2" +
|
||||
")," +
|
||||
"'" + SPACE_PLACEHOLDER + "'," +
|
||||
"' '" +
|
||||
")";
|
||||
|
||||
private final SQLFunction leadingSpaceTrim;
|
||||
private final SQLFunction trailingSpaceTrim;
|
||||
private final SQLFunction bothSpaceTrim;
|
||||
private final SQLFunction bothSpaceTrimFrom;
|
||||
|
||||
private final SQLFunction leadingTrim;
|
||||
private final SQLFunction trailingTrim;
|
||||
private final SQLFunction bothTrim;
|
||||
|
||||
/**
|
||||
* Constructs a new AnsiTrimEmulationFunction using {@link #LTRIM}, {@link #RTRIM}, and {@link #REPLACE}
|
||||
* respectively.
|
||||
*
|
||||
* @see #AnsiTrimEmulationFunction(String,String,String)
|
||||
*/
|
||||
public AnsiTrimEmulationFunction() {
|
||||
this( LTRIM, RTRIM, REPLACE );
|
||||
}
|
||||
|
||||
public boolean hasArguments() {
|
||||
return true;
|
||||
/**
|
||||
* Constructs a <tt>trim()</tt> emulation function definition using the specified function calls.
|
||||
*
|
||||
* @param ltrimFunctionName The <tt>left trim</tt> function to use.
|
||||
* @param rtrimFunctionName The <tt>right trim</tt> function to use.
|
||||
* @param replaceFunctionName The <tt>replace</tt> function to use.
|
||||
*/
|
||||
public AnsiTrimEmulationFunction(String ltrimFunctionName, String rtrimFunctionName, String replaceFunctionName) {
|
||||
leadingSpaceTrim = new SQLFunctionTemplate(
|
||||
Hibernate.STRING,
|
||||
LEADING_SPACE_TRIM_TEMPLATE.replaceAll( LTRIM, ltrimFunctionName )
|
||||
);
|
||||
|
||||
trailingSpaceTrim = new SQLFunctionTemplate(
|
||||
Hibernate.STRING,
|
||||
TRAILING_SPACE_TRIM_TEMPLATE.replaceAll( RTRIM, rtrimFunctionName )
|
||||
);
|
||||
|
||||
bothSpaceTrim = new SQLFunctionTemplate(
|
||||
Hibernate.STRING,
|
||||
BOTH_SPACE_TRIM_TEMPLATE.replaceAll( LTRIM, ltrimFunctionName )
|
||||
.replaceAll( RTRIM, rtrimFunctionName )
|
||||
);
|
||||
|
||||
bothSpaceTrimFrom = new SQLFunctionTemplate(
|
||||
Hibernate.STRING,
|
||||
BOTH_SPACE_TRIM_FROM_TEMPLATE.replaceAll( LTRIM, ltrimFunctionName )
|
||||
.replaceAll( RTRIM, rtrimFunctionName )
|
||||
);
|
||||
|
||||
leadingTrim = new SQLFunctionTemplate(
|
||||
Hibernate.STRING,
|
||||
LEADING_TRIM_TEMPLATE.replaceAll( LTRIM, ltrimFunctionName )
|
||||
.replaceAll( RTRIM, rtrimFunctionName )
|
||||
.replaceAll( REPLACE,replaceFunctionName )
|
||||
);
|
||||
|
||||
trailingTrim = new SQLFunctionTemplate(
|
||||
Hibernate.STRING,
|
||||
TRAILING_TRIM_TEMPLATE.replaceAll( LTRIM, ltrimFunctionName )
|
||||
.replaceAll( RTRIM, rtrimFunctionName )
|
||||
.replaceAll( REPLACE,replaceFunctionName )
|
||||
);
|
||||
|
||||
bothTrim = new SQLFunctionTemplate(
|
||||
Hibernate.STRING,
|
||||
BOTH_TRIM_TEMPLATE.replaceAll( LTRIM, ltrimFunctionName )
|
||||
.replaceAll( RTRIM, rtrimFunctionName )
|
||||
.replaceAll( REPLACE,replaceFunctionName )
|
||||
);
|
||||
}
|
||||
|
||||
public boolean hasParenthesesIfNoArguments() {
|
||||
return false;
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected SQLFunction resolveBothSpaceTrimFunction() {
|
||||
return bothSpaceTrim;
|
||||
}
|
||||
|
||||
public String render(List args, SessionFactoryImplementor factory) throws QueryException {
|
||||
// according to both the ANSI-SQL and EJB3 specs, trim can either take
|
||||
// exactly one parameter or a variable number of parameters between 1 and 4.
|
||||
// from the SQL spec:
|
||||
//
|
||||
// <trim function> ::=
|
||||
// TRIM <left paren> <trim operands> <right paren>
|
||||
//
|
||||
// <trim operands> ::=
|
||||
// [ [ <trim specification> ] [ <trim character> ] FROM ] <trim source>
|
||||
//
|
||||
// <trim specification> ::=
|
||||
// LEADING
|
||||
// | TRAILING
|
||||
// | BOTH
|
||||
//
|
||||
// If only <trim specification> is omitted, BOTH is assumed;
|
||||
// if <trim character> is omitted, space is assumed
|
||||
if ( args.size() == 1 ) {
|
||||
// we have the form: trim(trimSource)
|
||||
// so we trim leading and trailing spaces
|
||||
return BOTH_SPACE_TRIM.render( args, factory );
|
||||
}
|
||||
else if ( "from".equalsIgnoreCase( ( String ) args.get( 0 ) ) ) {
|
||||
// we have the form: trim(from trimSource).
|
||||
// This is functionally equivalent to trim(trimSource)
|
||||
return BOTH_SPACE_TRIM_FROM.render( args, factory );
|
||||
}
|
||||
else {
|
||||
// otherwise, a trim-specification and/or a trim-character
|
||||
// have been specified; we need to decide which options
|
||||
// are present and "do the right thing"
|
||||
boolean leading = true; // should leading trim-characters be trimmed?
|
||||
boolean trailing = true; // should trailing trim-characters be trimmed?
|
||||
String trimCharacter = null; // the trim-character
|
||||
String trimSource = null; // the trim-source
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected SQLFunction resolveBothSpaceTrimFromFunction() {
|
||||
return bothSpaceTrimFrom;
|
||||
}
|
||||
|
||||
// potentialTrimCharacterArgIndex = 1 assumes that a
|
||||
// trim-specification has been specified. we handle the
|
||||
// exception to that explicitly
|
||||
int potentialTrimCharacterArgIndex = 1;
|
||||
String firstArg = ( String ) args.get( 0 );
|
||||
if ( "leading".equalsIgnoreCase( firstArg ) ) {
|
||||
trailing = false;
|
||||
}
|
||||
else if ( "trailing".equalsIgnoreCase( firstArg ) ) {
|
||||
leading = false;
|
||||
}
|
||||
else if ( "both".equalsIgnoreCase( firstArg ) ) {
|
||||
}
|
||||
else {
|
||||
potentialTrimCharacterArgIndex = 0;
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected SQLFunction resolveLeadingSpaceTrimFunction() {
|
||||
return leadingSpaceTrim;
|
||||
}
|
||||
|
||||
String potentialTrimCharacter = ( String ) args.get( potentialTrimCharacterArgIndex );
|
||||
if ( "from".equalsIgnoreCase( potentialTrimCharacter ) ) {
|
||||
trimCharacter = "' '";
|
||||
trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
|
||||
}
|
||||
else if ( potentialTrimCharacterArgIndex + 1 >= args.size() ) {
|
||||
trimCharacter = "' '";
|
||||
trimSource = potentialTrimCharacter;
|
||||
}
|
||||
else {
|
||||
trimCharacter = potentialTrimCharacter;
|
||||
if ( "from".equalsIgnoreCase( ( String ) args.get( potentialTrimCharacterArgIndex + 1 ) ) ) {
|
||||
trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 2 );
|
||||
}
|
||||
else {
|
||||
trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected SQLFunction resolveTrailingSpaceTrimFunction() {
|
||||
return trailingSpaceTrim;
|
||||
}
|
||||
|
||||
List argsToUse = null;
|
||||
argsToUse = new ArrayList();
|
||||
argsToUse.add( trimSource );
|
||||
argsToUse.add( trimCharacter );
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected SQLFunction resolveBothTrimFunction() {
|
||||
return bothTrim;
|
||||
}
|
||||
|
||||
if ( trimCharacter.equals( "' '" ) ) {
|
||||
if ( leading && trailing ) {
|
||||
return BOTH_SPACE_TRIM.render( argsToUse, factory );
|
||||
}
|
||||
else if ( leading ) {
|
||||
return LEADING_SPACE_TRIM.render( argsToUse, factory );
|
||||
}
|
||||
else {
|
||||
return TRAILING_SPACE_TRIM.render( argsToUse, factory );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( leading && trailing ) {
|
||||
return BOTH_TRIM.render( argsToUse, factory );
|
||||
}
|
||||
else if ( leading ) {
|
||||
return LEADING_TRIM.render( argsToUse, factory );
|
||||
}
|
||||
else {
|
||||
return TRAILING_TRIM.render( argsToUse, factory );
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected SQLFunction resolveLeadingTrimFunction() {
|
||||
return leadingTrim;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected SQLFunction resolveTrailingTrimFunction() {
|
||||
return trailingTrim;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.dialect.function;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.hibernate.dialect.function.AnsiTrimEmulationFunction;
|
||||
|
||||
/**
|
||||
* TODO : javadoc
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class AnsiTrimEmulationFunctionTest extends TestCase {
|
||||
private static final String trimSource = "a.column";
|
||||
|
||||
public void testBasicSqlServerProcessing() {
|
||||
AnsiTrimEmulationFunction function = new AnsiTrimEmulationFunction();
|
||||
|
||||
performBasicSpaceTrimmingTests( function );
|
||||
|
||||
final String expectedTrimPrep = "replace(replace(a.column,' ','${space}$'),'-',' ')";
|
||||
final String expectedPostTrimPrefix = "replace(replace(";
|
||||
final String expectedPostTrimSuffix = ",' ','-'),'${space}$',' ')";
|
||||
|
||||
// -> trim(LEADING '-' FROM a.column)
|
||||
String rendered = function.render( argList( "LEADING", "'-'", "FROM", trimSource ), null );
|
||||
String expected = expectedPostTrimPrefix + "ltrim(" + expectedTrimPrep + ")" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim(TRAILING '-' FROM a.column)
|
||||
rendered = function.render( argList( "TRAILING", "'-'", "FROM", trimSource ), null );
|
||||
expected = expectedPostTrimPrefix + "rtrim(" + expectedTrimPrep + ")" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim(BOTH '-' FROM a.column)
|
||||
rendered = function.render( argList( "BOTH", "'-'", "FROM", trimSource ), null );
|
||||
expected = expectedPostTrimPrefix + "ltrim(rtrim(" + expectedTrimPrep + "))" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim('-' FROM a.column)
|
||||
rendered = function.render( argList( "'-'", "FROM", trimSource ), null );
|
||||
expected = expectedPostTrimPrefix + "ltrim(rtrim(" + expectedTrimPrep + "))" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
}
|
||||
|
||||
public void testBasicSybaseProcessing() {
|
||||
AnsiTrimEmulationFunction function = new AnsiTrimEmulationFunction(
|
||||
AnsiTrimEmulationFunction.LTRIM,
|
||||
AnsiTrimEmulationFunction.RTRIM,
|
||||
"str_replace"
|
||||
);
|
||||
|
||||
performBasicSpaceTrimmingTests( function );
|
||||
|
||||
final String expectedTrimPrep = "str_replace(str_replace(a.column,' ','${space}$'),'-',' ')";
|
||||
final String expectedPostTrimPrefix = "str_replace(str_replace(";
|
||||
final String expectedPostTrimSuffix = ",' ','-'),'${space}$',' ')";
|
||||
|
||||
// -> trim(LEADING '-' FROM a.column)
|
||||
String rendered = function.render( argList( "LEADING", "'-'", "FROM", trimSource ), null );
|
||||
String expected = expectedPostTrimPrefix + "ltrim(" + expectedTrimPrep + ")" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim(TRAILING '-' FROM a.column)
|
||||
rendered = function.render( argList( "TRAILING", "'-'", "FROM", trimSource ), null );
|
||||
expected = expectedPostTrimPrefix + "rtrim(" + expectedTrimPrep + ")" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim(BOTH '-' FROM a.column)
|
||||
rendered = function.render( argList( "BOTH", "'-'", "FROM", trimSource ), null );
|
||||
expected = expectedPostTrimPrefix + "ltrim(rtrim(" + expectedTrimPrep + "))" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
|
||||
// -> trim('-' FROM a.column)
|
||||
rendered = function.render( argList( "'-'", "FROM", trimSource ), null );
|
||||
expected = expectedPostTrimPrefix + "ltrim(rtrim(" + expectedTrimPrep + "))" + expectedPostTrimSuffix;
|
||||
assertEquals( expected, rendered );
|
||||
}
|
||||
|
||||
private void performBasicSpaceTrimmingTests(AnsiTrimEmulationFunction function) {
|
||||
// -> trim(a.column)
|
||||
String rendered = function.render( argList( trimSource ), null );
|
||||
assertEquals( "ltrim(rtrim(a.column))", rendered );
|
||||
|
||||
// -> trim(FROM a.column)
|
||||
rendered = function.render( argList( "FROM", trimSource ), null );
|
||||
assertEquals( "ltrim(rtrim(a.column))", rendered );
|
||||
|
||||
// -> trim(BOTH FROM a.column)
|
||||
rendered = function.render( argList( "BOTH", "FROM", trimSource ), null );
|
||||
assertEquals( "ltrim(rtrim(a.column))", rendered );
|
||||
|
||||
// -> trim(BOTH ' ' FROM a.column)
|
||||
rendered = function.render( argList( "BOTH", "' '", "FROM", trimSource ), null );
|
||||
assertEquals( "ltrim(rtrim(a.column))", rendered );
|
||||
|
||||
// -> trim(LEADING FROM a.column)
|
||||
rendered = function.render( argList( "LEADING", "FROM", trimSource ), null );
|
||||
assertEquals( "ltrim(a.column)", rendered );
|
||||
|
||||
// -> trim(LEADING ' ' FROM a.column)
|
||||
rendered = function.render( argList( "LEADING", "' '", "FROM", trimSource ), null );
|
||||
assertEquals( "ltrim(a.column)", rendered );
|
||||
|
||||
// -> trim(TRAILING FROM a.column)
|
||||
rendered = function.render( argList( "TRAILING", "FROM", trimSource ), null );
|
||||
assertEquals( "rtrim(a.column)", rendered );
|
||||
|
||||
// -> trim(TRAILING ' ' FROM a.column)
|
||||
rendered = function.render( argList( "TRAILING", "' '", "FROM", trimSource ), null );
|
||||
assertEquals( "rtrim(a.column)", rendered );
|
||||
}
|
||||
|
||||
private List argList(String arg) {
|
||||
ArrayList args = new ArrayList();
|
||||
args.add( arg );
|
||||
return args;
|
||||
}
|
||||
|
||||
private List argList(String arg1, String arg2) {
|
||||
ArrayList args = new ArrayList();
|
||||
args.add( arg1 );
|
||||
args.add( arg2 );
|
||||
return args;
|
||||
}
|
||||
|
||||
private List argList(String arg1, String arg2, String arg3) {
|
||||
ArrayList args = new ArrayList();
|
||||
args.add( arg1 );
|
||||
args.add( arg2 );
|
||||
args.add( arg3 );
|
||||
return args;
|
||||
}
|
||||
|
||||
private List argList(String arg1, String arg2, String arg3, String arg4) {
|
||||
ArrayList args = new ArrayList();
|
||||
args.add( arg1 );
|
||||
args.add( arg2 );
|
||||
args.add( arg3 );
|
||||
args.add( arg4 );
|
||||
return args;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue