[hibernate-commits] Hibernate SVN: r18252 - in core/trunk/core/src/main/java/org/hibernate/dialect: function and 1 other directory.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Dec 16 18:15:02 EST 2009


Author: steve.ebersole at jboss.com
Date: 2009-12-16 18:15:01 -0500 (Wed, 16 Dec 2009)
New Revision: 18252

Added:
   core/trunk/core/src/main/java/org/hibernate/dialect/function/AnsiTrimFunction.java
   core/trunk/core/src/main/java/org/hibernate/dialect/function/TrimFunctionTemplate.java
Modified:
   core/trunk/core/src/main/java/org/hibernate/dialect/DerbyDialect.java
Log:
HHH-4705 - Derby does now in fact support the full ANSI SQL TRIM function

Modified: core/trunk/core/src/main/java/org/hibernate/dialect/DerbyDialect.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/DerbyDialect.java	2009-12-16 22:18:03 UTC (rev 18251)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/DerbyDialect.java	2009-12-16 23:15:01 UTC (rev 18252)
@@ -24,27 +24,18 @@
  */
 package org.hibernate.dialect;
 
-import org.hibernate.Hibernate;
-import org.hibernate.QueryException;
-import org.hibernate.HibernateException;
-import org.hibernate.util.ReflectHelper;
-import org.hibernate.engine.Mapping;
-import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.type.Type;
-import org.hibernate.dialect.function.SQLFunction;
-import org.hibernate.dialect.function.SQLFunctionTemplate;
-import org.hibernate.dialect.function.DerbyConcatFunction;
-import org.hibernate.id.TableHiLoGenerator;
-import org.hibernate.sql.CaseFragment;
-import org.hibernate.sql.DerbyCaseFragment;
-
-import java.util.List;
-import java.util.ArrayList;
 import java.lang.reflect.Method;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.hibernate.dialect.function.AnsiTrimFunction;
+import org.hibernate.dialect.function.DerbyConcatFunction;
+import org.hibernate.id.TableHiLoGenerator;
+import org.hibernate.sql.CaseFragment;
+import org.hibernate.sql.DerbyCaseFragment;
+import org.hibernate.util.ReflectHelper;
+
 /**
  * Hibernate Dialect for Cloudscape 10 - aka Derby. This implements both an 
  * override for the identity column generator as well as for the case statement
@@ -62,7 +53,7 @@
 	public DerbyDialect() {
 		super();
 		registerFunction( "concat", new DerbyConcatFunction() );
-		registerFunction( "trim", new SQLFunctionTemplate( Hibernate.STRING, "trim(?1 ?2 ?3 ?4)" ) );
+		registerFunction( "trim", new AnsiTrimFunction() );
 		determineDriverVersion();
 	}
 
@@ -210,125 +201,7 @@
 	   return null ;
 	}
 
-	/**
-	 * A specialized function template to emulate the ANSI trim function on Derby DB
-	 * since it does not support the full trim specification.  However, we cannot even
-	 * fully emulate it because there is not standard 'replace' function either. :(
-	 */
-	public static class DerbyTrimFunctionEmulation implements SQLFunction {
-		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 Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
-			return Hibernate.STRING;
-		}
-
-		public boolean hasArguments() {
-			return true;
-		}
-
-		public boolean hasParenthesesIfNoArguments() {
-			return false;
-		}
-
-		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;    		// the trim-character
-				String trimSource;       		// the trim-source
-
-				// 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 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 {
-					throw new HibernateException( "cannot specify trim character when using Derby as Derby does not support the ANSI trim function, not does it support a replace function to properly emmulate it" );
-				}
-			}
-		}
-	}
-
-
 	// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 	public boolean supportsLobValueChangePropogation() {

Added: core/trunk/core/src/main/java/org/hibernate/dialect/function/AnsiTrimFunction.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/function/AnsiTrimFunction.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/function/AnsiTrimFunction.java	2009-12-16 23:15:01 UTC (rev 18252)
@@ -0,0 +1,45 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Inc. 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 Inc.
+ *
+ * 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.engine.SessionFactoryImplementor;
+
+/**
+ * Defines support for rendering according to ANSI SQL <tt>TRIM<//tt> function specification.
+ *
+ * @author Steve Ebersole
+ */
+public class AnsiTrimFunction extends TrimFunctionTemplate {
+	protected String render(Options options, String trimSource, SessionFactoryImplementor factory) {
+		return new StringBuffer()
+				.append( "trim(" )
+				.append( options.getTrimSpecification().getName() )
+				.append( ' ' )
+				.append( options.getTrimCharacter() )
+				.append( " from " )
+				.append( trimSource )
+				.append( ')' )
+				.toString();
+	}
+}

Added: core/trunk/core/src/main/java/org/hibernate/dialect/function/TrimFunctionTemplate.java
===================================================================
--- core/trunk/core/src/main/java/org/hibernate/dialect/function/TrimFunctionTemplate.java	                        (rev 0)
+++ core/trunk/core/src/main/java/org/hibernate/dialect/function/TrimFunctionTemplate.java	2009-12-16 23:15:01 UTC (rev 18252)
@@ -0,0 +1,148 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Inc. 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 Inc.
+ *
+ * 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 java.util.List;
+
+import org.hibernate.Hibernate;
+import org.hibernate.QueryException;
+import org.hibernate.engine.Mapping;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.type.Type;
+
+/**
+ * Defines the basic template support for <tt>TRIM</tt> functions
+ *
+ * @author Steve Ebersole
+ */
+public abstract class TrimFunctionTemplate implements SQLFunction {
+	public Type getReturnType(Type columnType, Mapping mapping) throws QueryException {
+		return Hibernate.STRING;
+	}
+
+	public boolean hasArguments() {
+		return true;
+	}
+
+	public boolean hasParenthesesIfNoArguments() {
+		return false;
+	}
+
+	public String render(List args, SessionFactoryImplementor factory) throws QueryException {
+		final Options options = new Options();
+		final String trimSource;
+
+		if ( args.size() == 1 ) {
+			// we have the form: trim(trimSource)
+			trimSource = ( String ) args.get( 0 );
+		}
+		else if ( "from".equalsIgnoreCase( ( String ) args.get( 0 ) ) ) {
+			// we have the form: trim(from trimSource).
+			//      This is functionally equivalent to trim(trimSource)
+			trimSource = ( String ) args.get( 1 );
+		}
+		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"
+			//
+			// 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 ) ) {
+				options.setTrimSpecification( Specification.LEADING );
+			}
+			else if ( "trailing".equalsIgnoreCase( firstArg ) ) {
+				options.setTrimSpecification( Specification.TRAILING );
+			}
+			else if ( "both".equalsIgnoreCase( firstArg ) ) {
+				// already the default in Options
+			}
+			else {
+				potentialTrimCharacterArgIndex = 0;
+			}
+
+			String potentialTrimCharacter = ( String ) args.get( potentialTrimCharacterArgIndex );
+			if ( "from".equalsIgnoreCase( potentialTrimCharacter ) ) {
+				trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
+			}
+			else if ( potentialTrimCharacterArgIndex + 1 >= args.size() ) {
+				trimSource = potentialTrimCharacter;
+			}
+			else {
+				options.setTrimCharacter( potentialTrimCharacter );
+				if ( "from".equalsIgnoreCase( ( String ) args.get( potentialTrimCharacterArgIndex + 1 ) ) ) {
+					trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 2 );
+				}
+				else {
+					trimSource = ( String ) args.get( potentialTrimCharacterArgIndex + 1 );
+				}
+			}
+		}
+		return render( options, trimSource, factory );
+	}
+
+	protected abstract String render(Options options, String trimSource, SessionFactoryImplementor factory);
+
+	public static class Options {
+		public static final String DEFAULT_TRIM_CHARACTER = "' '";
+
+		private String trimCharacter = DEFAULT_TRIM_CHARACTER;
+		private Specification trimSpecification = Specification.BOTH;
+
+		public String getTrimCharacter() {
+			return trimCharacter;
+		}
+
+		public void setTrimCharacter(String trimCharacter) {
+			this.trimCharacter = trimCharacter;
+		}
+
+		public Specification getTrimSpecification() {
+			return trimSpecification;
+		}
+
+		public void setTrimSpecification(Specification trimSpecification) {
+			this.trimSpecification = trimSpecification;
+		}
+	}
+
+	public static class Specification {
+		public static final Specification LEADING = new Specification( "leading" );
+		public static final Specification TRAILING = new Specification( "trailing" );
+		public static final Specification BOTH = new Specification( "both" );
+
+		private final String name;
+
+		private Specification(String name) {
+			this.name = name;
+		}
+
+		public String getName() {
+			return name;
+		}
+	}
+}



More information about the hibernate-commits mailing list