[#8429] Fix escaping in AbstractField#endsWith(Object)

Since client code can specify a different value when the query is being
executed, the escaping must be done in SQL rather than in Java. The same
applies to AbstractField#startsWith(Object) and some more LIKE-based
predicates.
This commit is contained in:
Knut Wannheden 2019-04-09 16:37:22 +02:00
parent f37d66de12
commit f50f71eb9f
4 changed files with 20 additions and 79 deletions

View File

@ -903,18 +903,14 @@ abstract class AbstractField<T> extends AbstractNamed implements Field<T> {
return contains(value).not();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public final Condition containsIgnoreCase(T value) {
if (value instanceof Field)
return containsIgnoreCase((Field) value);
else
return new ContainsIgnoreCase<T>(this, value, true, true);
return containsIgnoreCase(Tools.field(value, this));
}
@Override
public final Condition containsIgnoreCase(Field<T> value) {
return new ContainsIgnoreCase<T>(this, value, true, true);
return new ContainsIgnoreCase(this, value, true, true);
}
@Override
@ -927,14 +923,9 @@ abstract class AbstractField<T> extends AbstractNamed implements Field<T> {
return containsIgnoreCase(value).not();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public final Condition startsWith(T value) {
if (value instanceof Field)
return startsWith((Field) value);
Field<String> concat = DSL.concat(Tools.escapeForLike(value), inline("%"));
return like(concat, Tools.ESCAPE);
return startsWith(Tools.field(value, this));
}
@Override
@ -943,28 +934,19 @@ abstract class AbstractField<T> extends AbstractNamed implements Field<T> {
return like(concat, Tools.ESCAPE);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public final Condition startsWithIgnoreCase(T value) {
if (value instanceof Field)
return startsWithIgnoreCase((Field) value);
else
return new ContainsIgnoreCase<T>(this, value, false, true);
return startsWithIgnoreCase(Tools.field(value, this));
}
@Override
public final Condition startsWithIgnoreCase(Field<T> value) {
return new ContainsIgnoreCase<T>(this, value, false, true);
return new ContainsIgnoreCase(this, value, false, true);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public final Condition endsWith(T value) {
if (value instanceof Field)
return endsWith((Field) value);
Field<String> concat = DSL.concat(inline("%"), Tools.escapeForLike(value));
return like(concat, Tools.ESCAPE);
return endsWith(Tools.field(value, this));
}
@Override
@ -973,18 +955,14 @@ abstract class AbstractField<T> extends AbstractNamed implements Field<T> {
return like(concat, Tools.ESCAPE);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public final Condition endsWithIgnoreCase(T value) {
if (value instanceof Field)
return endsWithIgnoreCase((Field) value);
else
return new ContainsIgnoreCase<T>(this, value, true, false);
return endsWithIgnoreCase(Tools.field(value, this));
}
@Override
public final Condition endsWithIgnoreCase(Field<T> value) {
return new ContainsIgnoreCase<T>(this, value, true, false);
return new ContainsIgnoreCase(this, value, true, false);
}
private final boolean isAccidentalSelect(T[] values) {

View File

@ -98,9 +98,13 @@ final class Contains<T> extends AbstractCondition {
// "contains" operations on Strings
else
return lhs.like((rhs == null)
? DSL.concat(inline("%"), Tools.escapeForLike(value, configuration), inline("%"))
: DSL.concat(inline("%"), Tools.escapeForLike(rhs, configuration), inline("%")), Tools.ESCAPE);
return lhs.like(
DSL.concat(
inline("%"),
Tools.escapeForLike(rhs == null ? Tools.field(value, lhs) : rhs, configuration),
inline("%")
), Tools.ESCAPE
);
}
/**

View File

@ -52,7 +52,7 @@ import org.jooq.Field;
*
* @author lmarchau
*/
final class ContainsIgnoreCase<T> extends AbstractCondition {
final class ContainsIgnoreCase extends AbstractCondition {
/**
* Generated UID
@ -61,24 +61,14 @@ final class ContainsIgnoreCase<T> extends AbstractCondition {
private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON };
private final Field<T> lhs;
private final Field<T> rhs;
private final Field<?> lhs;
private final Field<?> rhs;
private final boolean leftWildcard;
private final boolean rightWildcard;
private final T value;
ContainsIgnoreCase(Field<T> field, T value, boolean leftWildcard, boolean rightWildcard) {
this.lhs = field;
this.rhs = null;
this.value = value;
this.leftWildcard = leftWildcard;
this.rightWildcard = rightWildcard;
}
ContainsIgnoreCase(Field<T> field, Field<T> rhs, boolean leftWildcard, boolean rightWildcard) {
ContainsIgnoreCase(Field<?> field, Field<?> rhs, boolean leftWildcard, boolean rightWildcard) {
this.lhs = field;
this.rhs = rhs;
this.value = null;
this.leftWildcard = leftWildcard;
this.rightWildcard = rightWildcard;
}
@ -100,10 +90,7 @@ final class ContainsIgnoreCase<T> extends AbstractCondition {
if (leftWildcard)
array[i++] = inline("%");
if (rhs == null)
array[i++] = Tools.escapeForLike(value, configuration);
else
array[i++] = Tools.escapeForLike(rhs, configuration);
array[i++] = Tools.escapeForLike(rhs, configuration);
if (rightWildcard)
array[i++] = inline("%");

View File

@ -2767,34 +2767,6 @@ final class Tools {
return 0x7FFFFFF & CTX.render(part).hashCode();
}
/**
* Utility method to escape strings or "toString" other objects
*/
static final Field<String> escapeForLike(Object value) {
return escapeForLike(value, new DefaultConfiguration());
}
/**
* Utility method to escape strings or "toString" other objects
*/
static final Field<String> escapeForLike(Object value, Configuration configuration) {
if (value != null && value.getClass() == String.class) {
{
return val(escape("" + value, ESCAPE));
}
}
else {
return val("" + value);
}
}
/**
* Utility method to escape string fields, or cast other fields
*/