diff --git a/core/src/main/java/org/hibernate/dialect/function/AbstractAnsiTrimEmulationFunction.java b/core/src/main/java/org/hibernate/dialect/function/AbstractAnsiTrimEmulationFunction.java
new file mode 100644
index 0000000000..278fd9fe01
--- /dev/null
+++ b/core/src/main/java/org/hibernate/dialect/function/AbstractAnsiTrimEmulationFunction.java
@@ -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 trim
+ * function itself.
+ *
+ * Follows the template 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
+ //
+ // ::=
+ // [ [ ] [ ] FROM ]
+ //
+ // ::=
+ // LEADING
+ // | TRAILING
+ // | BOTH
+ //
+ // If is omitted, BOTH is assumed.
+ // If 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.
+ *
+ * In this form, the imput arguments is missing the FROM keyword.
+ *
+ * @return The sql function
+ */
+ protected abstract SQLFunction resolveBothSpaceTrimFunction();
+
+ /**
+ * Resolve the function definition which should be used to trim both leading and trailing spaces.
+ *
+ * The same as {#link resolveBothSpaceTrimFunction} except that here theFROM 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();
+}
diff --git a/core/src/main/java/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java b/core/src/main/java/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java
index cd730fcd71..6a63db4e11 100644
--- a/core/src/main/java/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java
+++ b/core/src/main/java/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java
@@ -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.
+ *
+ * NOTE : essentially we:
+ * replace all space chars with the text '${space}$'
+ * replace all the actual replacement chars with space chars
+ * perform left-trimming (that removes any of the space chars we just added which occur at the beginning of the text)
+ * replace all space chars with the replacement char
+ * replace all the '${space}$' text with space chars
+ *
+ */
+ 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.
+ *
+ * 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.
+ *
+ * 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 trim() emulation function definition using the specified function calls.
+ *
+ * @param ltrimFunctionName The left trim function to use.
+ * @param rtrimFunctionName The right trim function to use.
+ * @param replaceFunctionName The replace 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
- //
- // ::=
- // [ [ ] [ ] FROM ]
- //
- // ::=
- // LEADING
- // | TRAILING
- // | BOTH
- //
- // If only is omitted, BOTH is assumed;
- // if 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;
}
}
diff --git a/testsuite/src/test/java/org/hibernate/test/dialect/function/AnsiTrimEmulationFunctionTest.java b/testsuite/src/test/java/org/hibernate/test/dialect/function/AnsiTrimEmulationFunctionTest.java
new file mode 100644
index 0000000000..f4cc4c4d9f
--- /dev/null
+++ b/testsuite/src/test/java/org/hibernate/test/dialect/function/AnsiTrimEmulationFunctionTest.java
@@ -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;
+ }
+
+}