diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB297Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB297Dialect.java index fd80bc4eeb..314f1eba2d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB297Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB297Dialect.java @@ -6,11 +6,14 @@ */ package org.hibernate.dialect; +import org.hibernate.dialect.function.DB2SubstringFunction; +import org.hibernate.dialect.function.StandardSQLFunction; import org.hibernate.hql.spi.id.IdTableSupportStandardImpl; import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy; import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; import org.hibernate.hql.spi.id.local.AfterUseAction; import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; +import org.hibernate.type.StandardBasicTypes; /** * An SQL dialect for DB2 9.7. @@ -19,6 +22,11 @@ import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; */ public class DB297Dialect extends DB2Dialect { + public DB297Dialect() { + super(); + registerFunction( "substring", new DB2SubstringFunction() ); + } + @Override public String getCrossJoinSeparator() { // DB2 9.7 and later support "cross join" diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2SubstringFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2SubstringFunction.java new file mode 100644 index 0000000000..fd9c5033aa --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/DB2SubstringFunction.java @@ -0,0 +1,51 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.dialect.function; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.hibernate.type.StandardBasicTypes; + +/** + * When "substring" function is used for DB2, this implementation of {@link StandardSQLFunction} + * will render "substr" or "substring", depending on the last argument being used. If the last + * argument is a string unit ("CODEUNITS16", "CODEUNITS32", or "OCTETS"), then the function + * will be rendered as "substring"; otherwise, it will be rendered as "substr". + *

+ * ANSI SQL-92 standard defines "substring" without string units, which is more similar to DB2's "substr", + * so it makes sense to use DB2's "substr" function when string units are not provided. + *

+ * Background: DB2 has both "substr" and "substring", which are different functions that are not + * interchangeable. Prior to DB2 11.1, DB2's "substring" function requires an argument for string + * units; without this argument, DB2 throws an exception. DB2's "substr" function throws an exception + * if string unit is provided as an argument. + * + * @author Gail Badner + */ +public class DB2SubstringFunction extends StandardSQLFunction { + private static final Set possibleStringUnits = new HashSet<>( + Arrays.asList( "CODEUNITS16", "CODEUNITS32", "OCTETS" ) + ); + + public DB2SubstringFunction() { + super( "substring", StandardBasicTypes.STRING ); + } + + @Override + protected String getRenderedName(List arguments) { + final String lastArgument = (String) arguments.get( arguments.size() - 1 ); + if ( lastArgument != null && possibleStringUnits.contains( lastArgument.toUpperCase() ) ) { + return getName(); + } + else{ + return "substr"; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/function/StandardSQLFunction.java b/hibernate-core/src/main/java/org/hibernate/dialect/function/StandardSQLFunction.java index d3fd714b9d..bdd98d3a39 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/function/StandardSQLFunction.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/function/StandardSQLFunction.java @@ -86,7 +86,7 @@ public class StandardSQLFunction implements SQLFunction { @Override public String render(Type firstArgumentType, List arguments, SessionFactoryImplementor sessionFactory) { final StringBuilder buf = new StringBuilder(); - buf.append( name ).append( '(' ); + buf.append( getRenderedName( arguments) ).append( '(' ); for ( int i = 0; i < arguments.size(); i++ ) { buf.append( arguments.get( i ) ); if ( i < arguments.size() - 1 ) { @@ -96,6 +96,10 @@ public class StandardSQLFunction implements SQLFunction { return buf.append( ')' ).toString(); } + protected String getRenderedName(List arguments) { + return getName(); + } + @Override public String toString() { return name;