org.hibernate.dialect.function.DerbyConcatFunction Maven / Gradle / Ivy
/*
* 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.Iterator;
import java.util.List;
import org.hibernate.QueryException;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
/**
* A specialized concat() function definition in which:
* - we translate to use the concat operator ('||')
* - wrap dynamic parameters in CASTs to VARCHAR
*
*
* This last spec is to deal with a limitation on DB2 and variants (e.g. Derby)
* where dynamic parameters cannot be used in concatenation unless they are being
* concatenated with at least one non-dynamic operand. And even then, the rules
* are so convoluted as to what is allowed and when the CAST is needed and when
* it is not that we just go ahead and do the CASTing.
*
* @author Steve Ebersole
*/
public class DerbyConcatFunction implements SQLFunction {
/**
* {@inheritDoc}
*
* Here we always return true
*/
@Override
public boolean hasArguments() {
return true;
}
/**
* {@inheritDoc}
*
* Here we always return true
*/
@Override
public boolean hasParenthesesIfNoArguments() {
return true;
}
/**
* {@inheritDoc}
*
* Here we always return {@link StandardBasicTypes#STRING}.
*/
@Override
public Type getReturnType(Type argumentType, Mapping mapping) throws QueryException {
return StandardBasicTypes.STRING;
}
/**
* {@inheritDoc}
*
* Here's the meat.. The whole reason we have a separate impl for this for Derby is to re-define
* this method. The logic here says that if not all the incoming args are dynamic parameters
* (i.e. ?) then we simply use the Derby concat operator (||) on the unchanged
* arg elements. However, if all the args are dynamic parameters, then we need to wrap the individual
* arg elements in cast function calls, use the concatenation operator on the cast
* returns, and then wrap that whole thing in a call to the Derby varchar function.
*/
@Override
public String render(Type argumentType, List args, SessionFactoryImplementor factory) throws QueryException {
// first figure out if all arguments are dynamic (jdbc parameters) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
boolean areAllArgumentsDynamic = true;
for ( Object arg1 : args ) {
final String arg = (String) arg1;
if ( !"?".equals( arg ) ) {
// we found a non-dynamic argument
areAllArgumentsDynamic = false;
break;
}
}
if ( areAllArgumentsDynamic ) {
return join(
args.iterator(),
CAST_STRING_TRANSFORMER,
new StringJoinTemplate() {
public String getBeginning() {
return "varchar( ";
}
public String getSeparator() {
return " || ";
}
public String getEnding() {
return " )";
}
}
);
}
else {
return join(
args.iterator(),
NO_TRANSFORM_STRING_TRANSFORMER,
new StringJoinTemplate() {
public String getBeginning() {
return "(";
}
public String getSeparator() {
return "||";
}
public String getEnding() {
return ")";
}
}
);
}
}
private static interface StringTransformer {
/**
* Transform a string to another
*
* @param string The String to be transformed
*
* @return The transformed form
*/
public String transform(String string);
}
private static final StringTransformer CAST_STRING_TRANSFORMER = new StringTransformer() {
@Override
public String transform(String string) {
// expectation is that incoming string is "?"
return "cast( ? as varchar(32672) )";
}
};
private static final StringTransformer NO_TRANSFORM_STRING_TRANSFORMER = new StringTransformer() {
@Override
public String transform(String string) {
return string;
}
};
private static interface StringJoinTemplate {
/**
* Getter for property 'beginning'.
*
* @return Value for property 'beginning'.
*/
public String getBeginning();
/**
* Getter for property 'separator'.
*
* @return Value for property 'separator'.
*/
public String getSeparator();
/**
* Getter for property 'ending'.
*
* @return Value for property 'ending'.
*/
public String getEnding();
}
private static String join(Iterator/**/ elements, StringTransformer elementTransformer, StringJoinTemplate template) {
// todo : make this available via StringHelper?
final StringBuilder buffer = new StringBuilder( template.getBeginning() );
while ( elements.hasNext() ) {
final String element = (String) elements.next();
buffer.append( elementTransformer.transform( element ) );
if ( elements.hasNext() ) {
buffer.append( template.getSeparator() );
}
}
return buffer.append( template.getEnding() ).toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy