This commit is contained in:
Lukas Eder 2021-09-24 15:13:33 +02:00
parent db8c811cca
commit e6f3232710
8 changed files with 553 additions and 172 deletions

View File

@ -943,6 +943,22 @@ extends
@Support
Condition lessThan(Field<T> arg2);
/**
* The <code>LIKE</code> operator.
*
* @param pattern is wrapped as {@link #val(Object)}.
*/
@NotNull
@Support
LikeEscapeStep like(@Stringly.Param String pattern);
/**
* The <code>LIKE</code> operator.
*/
@NotNull
@Support
LikeEscapeStep like(Field<String> pattern);
/**
* The <code>LT</code> operator.
*/
@ -1006,6 +1022,22 @@ extends
@Support
Condition notEqual(Field<T> arg2);
/**
* The <code>NOT_LIKE</code> operator.
*
* @param pattern is wrapped as {@link #val(Object)}.
*/
@NotNull
@Support
LikeEscapeStep notLike(@Stringly.Param String pattern);
/**
* The <code>NOT_LIKE</code> operator.
*/
@NotNull
@Support
LikeEscapeStep notLike(Field<String> pattern);
// -------------------------------------------------------------------------
// XML predicates
// -------------------------------------------------------------------------
@ -2079,15 +2111,6 @@ extends
// LIKE predicates
// ------------------------------------------------------------------------
/**
* Create a condition to pattern-check this field against a value.
* <p>
* SQL: <code>this like value</code>
*/
@NotNull
@Support
LikeEscapeStep like(Field<String> value);
/**
* Create a condition to pattern-check this field against a value.
* <p>
@ -2099,15 +2122,6 @@ extends
@Support
Condition like(Field<String> value, char escape);
/**
* Create a condition to pattern-check this field against a value.
* <p>
* SQL: <code>this like value</code>
*/
@NotNull
@Support
LikeEscapeStep like(String value);
/**
* Create a condition to pattern-check this field against a value.
* <p>
@ -2191,15 +2205,6 @@ extends
@Support
Condition likeIgnoreCase(String value, char escape);
/**
* Create a condition to pattern-check this field against a field.
* <p>
* SQL: <code>this not like field</code>
*/
@NotNull
@Support
LikeEscapeStep notLike(Field<String> field);
/**
* Create a condition to pattern-check this field against a field.
* <p>
@ -2211,15 +2216,6 @@ extends
@Support
Condition notLike(Field<String> field, char escape);
/**
* Create a condition to pattern-check this field against a value.
* <p>
* SQL: <code>this not like value</code>
*/
@NotNull
@Support
LikeEscapeStep notLike(String value);
/**
* Create a condition to pattern-check this field against a value.
* <p>

View File

@ -37,37 +37,14 @@
*/
package org.jooq;
// ...
// ...
// ...
// ...
import static org.jooq.SQLDialect.CUBRID;
// ...
import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.FIREBIRD;
import static org.jooq.SQLDialect.H2;
// ...
import static org.jooq.SQLDialect.HSQLDB;
import static org.jooq.SQLDialect.IGNITE;
// ...
// ...
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
// ...
import static org.jooq.SQLDialect.POSTGRES;
// ...
// ...
import static org.jooq.SQLDialect.SQLITE;
// ...
// ...
// ...
// ...
import static org.jooq.SQLDialect.*;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import org.jetbrains.annotations.*;
/**
* A step in the creation of a <code>LIKE</code> predicate to which an
* <code>ESCAPE</code> clause can be appended.
* A step in the construction of the <code>NOT LIKE</code> function.
* <p>
* <h3>Referencing <code>XYZ*Step</code> types directly from client code</h3>
* <p>
@ -86,22 +63,20 @@ import org.jetbrains.annotations.NotNull;
* <li>They're less readable</li>
* <li>They might have binary incompatible changes between minor releases</li>
* </ul>
*
* @author Lukas Eder
*/
@SuppressWarnings({ "unused" })
public interface LikeEscapeStep extends Condition {
/**
* Add an <code>ESCAPE</code> clause to the <code>LIKE</code> predicate.
* Add the <code>ESCAPE</code> clause to the <code>NOT LIKE</code> function.
* <p>
* For example:
*
*
* <code><pre>
* some_column LIKE 'A!%%' ESCAPE '!'
* </pre></code>
*/
@NotNull
@Support({ CUBRID, DERBY, FIREBIRD, H2, HSQLDB, IGNITE, MARIADB, MYSQL, POSTGRES, SQLITE })
Condition escape(char c);
@NotNull @CheckReturnValue
Condition escape(char escape);
}

View File

@ -532,6 +532,18 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
return lt(arg2);
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final LikeEscapeStep like(String pattern) {
return new Like(this, Tools.field(pattern));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final LikeEscapeStep like(Field<String> pattern) {
return new Like(this, nullSafe(pattern, getDataType()));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final Condition lt(T arg2) {
@ -583,6 +595,18 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
return ne(arg2);
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final LikeEscapeStep notLike(String pattern) {
return new NotLike(this, Tools.field(pattern));
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public final LikeEscapeStep notLike(Field<String> pattern) {
return new NotLike(this, nullSafe(pattern, getDataType()));
}
// -------------------------------------------------------------------------
// XML predicates
// -------------------------------------------------------------------------
@ -1067,19 +1091,9 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
return notSimilarTo(field).escape(escape);
}
@Override
public final LikeEscapeStep like(String value) {
return like(Tools.field(value));
}
@Override
public final Condition like(String value, char escape) {
return like(Tools.field(value), escape);
}
@Override
public final LikeEscapeStep like(Field<String> field) {
return new CompareCondition(this, nullSafe(field, getDataType()), LIKE);
return like(value).escape(escape);
}
@Override
@ -1122,21 +1136,11 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
return new RegexpLike(this, nullSafe(pattern, getDataType()));
}
@Override
public final LikeEscapeStep notLike(String value) {
return notLike(Tools.field(value));
}
@Override
public final Condition notLike(String value, char escape) {
return notLike(Tools.field(value), escape);
}
@Override
public final LikeEscapeStep notLike(Field<String> field) {
return new CompareCondition(this, nullSafe(field, getDataType()), NOT_LIKE);
}
@Override
public final Condition notLike(Field<String> field, char escape) {
return notLike(field).escape(escape);
@ -1456,6 +1460,11 @@ abstract class AbstractField<T> extends AbstractTypedNamed<T> implements Field<T
case NOT_EQUALS:
return new Ne<>(this, nullSafe(field, getDataType()));
case LIKE:
return new Like(this, (Field) nullSafe(field, getDataType()));
case NOT_LIKE:
return new NotLike(this, (Field) nullSafe(field, getDataType()));
case IS_DISTINCT_FROM:
return new IsDistinctFrom<>(this, nullSafe(field, getDataType()));
case IS_NOT_DISTINCT_FROM:

View File

@ -204,6 +204,21 @@ implements
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------

View File

@ -179,6 +179,9 @@ implements
@ -213,17 +216,6 @@ implements
|| field instanceof ScalarSubquery && isJSONArray(((ScalarSubquery<?>) field).query.getSelect().get(0));
}
private final void acceptStandard(Context<?> ctx) {
JSONNull jsonNull;
JSONReturning jsonReturning = new JSONReturning(returning);
@ -244,6 +236,21 @@ implements
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------

View File

@ -0,0 +1,209 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import static org.jooq.impl.DSL.*;
import static org.jooq.impl.Internal.*;
import static org.jooq.impl.Keywords.*;
import static org.jooq.impl.Names.*;
import static org.jooq.impl.SQLDataType.*;
import static org.jooq.impl.Tools.*;
import static org.jooq.impl.Tools.BooleanDataKey.*;
import static org.jooq.impl.Tools.DataExtendedKey.*;
import static org.jooq.impl.Tools.DataKey.*;
import static org.jooq.SQLDialect.*;
import org.jooq.*;
import org.jooq.Record;
import org.jooq.conf.*;
import org.jooq.impl.*;
import org.jooq.tools.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
/**
* The <code>LIKE</code> statement.
*/
@SuppressWarnings({ "hiding", "rawtypes", "unchecked", "unused" })
final class Like
extends
AbstractCondition
implements
LikeEscapeStep
{
final Field<?> value;
final Field<String> pattern;
Character escape;
Like(
Field<?> value,
Field<String> pattern
) {
this(
value,
pattern,
null
);
}
Like(
Field<?> value,
Field<String> pattern,
Character escape
) {
this.value = nullSafeNotNull(value, OTHER);
this.pattern = nullSafeNotNull(pattern, VARCHAR);
this.escape = escape;
}
// -------------------------------------------------------------------------
// XXX: DSL API
// -------------------------------------------------------------------------
@Override
public final Like escape(char escape) {
this.escape = escape;
return this;
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
private static final Set<SQLDialect> REQUIRES_CAST_ON_LIKE = SQLDialect.supportedBy(DERBY, POSTGRES, YUGABYTE);
@Override
public final void accept(Context<?> ctx) {
accept0(ctx, value, org.jooq.Comparator.LIKE, pattern, escape);
}
static final boolean castRhs(Context<?> ctx, Field<?> arg2) {
boolean castRhs = false;
return castRhs;
}
static final ParamType forcedParamType(Context<?> ctx, Character escape) {
ParamType forcedParamType = ctx.paramType();
return forcedParamType;
}
static final void accept0(Context<?> ctx, Field<?> arg1, org.jooq.Comparator op, Field<?> arg2, Character escape) {
// [#1159] [#1725] Some dialects cannot auto-convert the LHS operand to a
// VARCHAR when applying a LIKE predicate
if (arg1.getType() != String.class && REQUIRES_CAST_ON_LIKE.contains(ctx.dialect()))
arg1 = castIfNeeded(arg1, String.class);
boolean castRhs = castRhs(ctx, arg2);
ctx.visit(arg1).sql(' ').visit(op.toKeyword()).sql(' ');
if (castRhs)
ctx.visit(K_CAST).sql('(');
ctx.visit(arg2, forcedParamType(ctx, escape));
if (castRhs)
ctx.sql(' ').visit(K_AS).sql(' ').visit(K_VARCHAR).sql("(4000))");
if (escape != null) {
ctx.sql(' ').visit(K_ESCAPE).sql(' ')
.visit(inline(escape));
}
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof Like) {
return
StringUtils.equals(value, ((Like) that).value) &&
StringUtils.equals(pattern, ((Like) that).pattern) &&
StringUtils.equals(escape, ((Like) that).escape)
;
}
else
return super.equals(that);
}
}

View File

@ -0,0 +1,155 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.impl;
import static org.jooq.impl.DSL.*;
import static org.jooq.impl.Internal.*;
import static org.jooq.impl.Keywords.*;
import static org.jooq.impl.Names.*;
import static org.jooq.impl.SQLDataType.*;
import static org.jooq.impl.Tools.*;
import static org.jooq.impl.Tools.BooleanDataKey.*;
import static org.jooq.impl.Tools.DataExtendedKey.*;
import static org.jooq.impl.Tools.DataKey.*;
import static org.jooq.SQLDialect.*;
import org.jooq.*;
import org.jooq.Record;
import org.jooq.conf.*;
import org.jooq.impl.*;
import org.jooq.tools.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
/**
* The <code>NOT LIKE</code> statement.
*/
@SuppressWarnings({ "hiding", "rawtypes", "unchecked", "unused" })
final class NotLike
extends
AbstractCondition
implements
LikeEscapeStep
{
final Field<?> value;
final Field<String> pattern;
Character escape;
NotLike(
Field<?> value,
Field<String> pattern
) {
this(
value,
pattern,
null
);
}
NotLike(
Field<?> value,
Field<String> pattern,
Character escape
) {
this.value = nullSafeNotNull(value, OTHER);
this.pattern = nullSafeNotNull(pattern, VARCHAR);
this.escape = escape;
}
// -------------------------------------------------------------------------
// XXX: DSL API
// -------------------------------------------------------------------------
@Override
public final NotLike escape(char escape) {
this.escape = escape;
return this;
}
// -------------------------------------------------------------------------
// XXX: QueryPart API
// -------------------------------------------------------------------------
@Override
public final void accept(Context<?> ctx) {
Like.accept0(ctx, value, org.jooq.Comparator.NOT_LIKE, pattern, escape);
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof NotLike) {
return
StringUtils.equals(value, ((NotLike) that).value) &&
StringUtils.equals(pattern, ((NotLike) that).pattern) &&
StringUtils.equals(escape, ((NotLike) that).escape)
;
}
else
return super.equals(that);
}
}

View File

@ -124,72 +124,87 @@ package org.jooq.impl;
case POSTGRES:
case YUGABYTE:
acceptPostgres(ctx);
break;
case HSQLDB:
case MARIADB:
case MYSQL:
acceptDefaultPullingUpDeclarations(ctx);
break;
default:
acceptDefault(ctx, value, messageText);
break;
}
}
private final void acceptPostgres(Context<?> ctx) {
ctx.visit(K_RAISE).sql(' ').visit(K_SQLSTATE).sql(' ').visit(value);
if (messageText != null)
ctx.sql(' ').visit(K_USING).sql(' ').visit(K_MESSAGE).sql(" = ").visit(messageText);
}
private final void acceptDefaultPullingUpDeclarations(Context<?> ctx) {
boolean bv = value instanceof ParamOrVariable;
boolean bm = messageText == null || messageText instanceof ParamOrVariable;
if (bv && bm) {
ctx.paramType(ParamType.INLINED, c -> acceptDefault(c, value, messageText));
}
else {
List<Statement> s = new ArrayList<>();
Field<?> v = bv ? value : variable("sqlstate", CHAR(5));
Field<String> m = bm ? messageText : variable("messagetext", VARCHAR);
if (v != value)
s.add(declare((Variable) v).set(value));
if (m != messageText)
s.add(declare((Variable<String>) m).set(messageText));
s.add(messageText != null ? signalSQLState(v).setMessageText(m) : signalSQLState(v));
ctx.visit(begin(s));
}
}
private static final void acceptDefault(Context<?> ctx, Field<?> value, Field<String> messageText) {
ctx.visit(K_SIGNAL).sql(' ').visit(ctx.family() == HANA ? K_SQL_ERROR_CODE : K_SQLSTATE).sql(' ').visit(value);
if (messageText != null)
ctx.sql(' ').visit(K_SET).sql(' ').visit(K_MESSAGE_TEXT).sql(" = ").visit(messageText);
}
@Pro
private final void acceptJava(Context<?> ctx) {
ctx.sql("signalSQLState(");
String s = "";
ctx.sql(s).visit(Val.getJavaValue(value)); s = ", ";
ctx.sql(s).visit(Val.getJavaValue(messageText)); s = ", ";
ctx.sql(')');
}
// -------------------------------------------------------------------------
// The Object API
// -------------------------------------------------------------------------
@Override
public boolean equals(Object that) {
if (that instanceof Signal) {
return
StringUtils.equals(value, ((Signal) that).value) &&
StringUtils.equals(messageText, ((Signal) that).messageText)
;
}
else
return super.equals(that);
}
}
/* [/pro] */