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:
Steve Ebersole 2009-02-03 00:47:23 +00:00
parent 5e77669afd
commit 1e45c666e6
3 changed files with 600 additions and 118 deletions

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;
}
}