[hibernate-commits] Hibernate SVN: r15962 - in core/branches/Branch_3_2_4_SP1_CP: src/org/hibernate/dialect/function and 3 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Feb 12 02:49:32 EST 2009


Author: gbadner
Date: 2009-02-12 02:49:32 -0500 (Thu, 12 Feb 2009)
New Revision: 15962

Added:
   core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/function/AbstractAnsiTrimEmulationFunction.java
   core/branches/Branch_3_2_4_SP1_CP/test/org/hibernate/test/dialect/function/
   core/branches/Branch_3_2_4_SP1_CP/test/org/hibernate/test/dialect/function/AnsiTrimEmulationFunctionTest.java
Modified:
   core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/SybaseASE15Dialect.java
   core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java
   core/branches/Branch_3_2_4_SP1_CP/test/org/hibernate/test/AllTests.java
Log:
JBPAPP-1564 JBPAPP-1563 HHH-3701 HHH-3640 : Add support for mod, bit_length, and trim to SybaseASE15Dialect


Modified: core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/SybaseASE15Dialect.java
===================================================================
--- core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/SybaseASE15Dialect.java	2009-02-12 06:17:17 UTC (rev 15961)
+++ core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/SybaseASE15Dialect.java	2009-02-12 07:49:32 UTC (rev 15962)
@@ -11,6 +11,7 @@
 import org.hibernate.Hibernate;
 import org.hibernate.LockMode;
 import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.function.AnsiTrimEmulationFunction;
 import org.hibernate.dialect.function.CharIndexFunction;
 import org.hibernate.dialect.function.NoArgSQLFunction;
 import org.hibernate.dialect.function.SQLFunctionTemplate;
@@ -29,6 +30,9 @@
 		registerFunction( "minute", new SQLFunctionTemplate(Hibernate.INTEGER, "datepart(minute, ?1)") );
 		registerFunction( "hour", new SQLFunctionTemplate(Hibernate.INTEGER, "datepart(hour, ?1)") );
 		registerFunction( "extract", new SQLFunctionTemplate( Hibernate.INTEGER, "datepart(?1, ?3)" ) );
+		registerFunction( "mod", new SQLFunctionTemplate( Hibernate.INTEGER, "?1 % ?2" ) );
+		registerFunction( "bit_length", new SQLFunctionTemplate( Hibernate.INTEGER, "datalength(?1) * 8" ) );
+		registerFunction( "trim", new AnsiTrimEmulationFunction( AnsiTrimEmulationFunction.LTRIM, AnsiTrimEmulationFunction.RTRIM, "str_replace" ) ); 
 	}
 
 	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Added: core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/function/AbstractAnsiTrimEmulationFunction.java
===================================================================
--- core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/function/AbstractAnsiTrimEmulationFunction.java	                        (rev 0)
+++ core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/function/AbstractAnsiTrimEmulationFunction.java	2009-02-12 07:49:32 UTC (rev 15962)
@@ -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();
+}
\ No newline at end of file

Modified: core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java
===================================================================
--- core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java	2009-02-12 06:17:17 UTC (rev 15961)
+++ core/branches/Branch_3_2_4_SP1_CP/src/org/hibernate/dialect/function/AnsiTrimEmulationFunction.java	2009-02-12 07:49:32 UTC (rev 15962)
@@ -1,14 +1,7 @@
 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
  * on dialects which do not support the full definition.  However, this function
@@ -18,129 +11,222 @@
  *
  * @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;
+	}
 }

Modified: core/branches/Branch_3_2_4_SP1_CP/test/org/hibernate/test/AllTests.java
===================================================================
--- core/branches/Branch_3_2_4_SP1_CP/test/org/hibernate/test/AllTests.java	2009-02-12 06:17:17 UTC (rev 15961)
+++ core/branches/Branch_3_2_4_SP1_CP/test/org/hibernate/test/AllTests.java	2009-02-12 07:49:32 UTC (rev 15962)
@@ -30,6 +30,7 @@
 import org.hibernate.test.cuk.CompositePropertyRefTest;
 import org.hibernate.test.cut.CompositeUserTypeTest;
 import org.hibernate.test.deletetransient.DeleteTransientEntityTest;
+import org.hibernate.test.dialect.function.AnsiTrimEmulationFunctionTest;
 import org.hibernate.test.dialect.functional.DialectFunctionalTestsSuite;
 import org.hibernate.test.dialect.unit.DialectUnitTestsSuite;
 import org.hibernate.test.discriminator.DiscriminatorTest;
@@ -303,6 +304,7 @@
 			suite.addTest( DeleteTransientEntityTest.suite() );
 			suite.addTest( UserCollectionTypeSuite.suite() );
 			suite.addTest( KeyManyToOneSuite.suite() );
+			suite.addTest( AnsiTrimEmulationFunctionTest.suite() );
 			suite.addTest( DialectFunctionalTestsSuite.suite() );
 			suite.addTest( DialectUnitTestsSuite.suite() );
 			suite.addTest( InsertOrderingTest.suite() );

Added: core/branches/Branch_3_2_4_SP1_CP/test/org/hibernate/test/dialect/function/AnsiTrimEmulationFunctionTest.java
===================================================================
--- core/branches/Branch_3_2_4_SP1_CP/test/org/hibernate/test/dialect/function/AnsiTrimEmulationFunctionTest.java	                        (rev 0)
+++ core/branches/Branch_3_2_4_SP1_CP/test/org/hibernate/test/dialect/function/AnsiTrimEmulationFunctionTest.java	2009-02-12 07:49:32 UTC (rev 15962)
@@ -0,0 +1,175 @@
+/*
+ * 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.Test;
+import junit.framework.TestCase;
+
+import org.hibernate.dialect.function.AnsiTrimEmulationFunction;
+import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
+
+/**
+ * TODO : javadoc
+ *
+ * @author Steve Ebersole
+ */
+public class AnsiTrimEmulationFunctionTest extends TestCase {
+	private static final String trimSource = "a.column";
+
+	public static Test suite() {
+		return new FunctionalTestClassTestSuite( AnsiTrimEmulationFunctionTest.class );
+	}
+
+	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;
+	}
+
+}




More information about the hibernate-commits mailing list