[#2001] Named Params are treated as null literals on right sides of
comparisons
This commit is contained in:
parent
56d1dd1250
commit
0977fccd6d
@ -364,9 +364,7 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T725,
|
||||
for (Field<Integer> n : asList(n1, n2)) {
|
||||
assertEquals(null, create().select(n).fetchOne(n));
|
||||
assertEquals(Integer.valueOf(1), create().select(c).from(TAuthor()).where(TAuthor_ID().equal(1)).and(n.isNull()).fetchOne(c));
|
||||
assertEquals(Integer.valueOf(1), create().select(c).from(TAuthor()).where(TAuthor_ID().equal(1)).and(n.equal(n)).fetchOne(c));
|
||||
assertEquals(null, create().selectOne().from(TAuthor()).where(n.isNotNull()).fetchAny());
|
||||
assertEquals(null, create().selectOne().from(TAuthor()).where(n.notEqual(n)).fetchAny());
|
||||
}
|
||||
|
||||
UpdateQuery<A> u = create().updateQuery(TAuthor());
|
||||
|
||||
@ -9164,6 +9164,7 @@ for (Record record : create().select(
|
||||
<h3>GroupField</h3>
|
||||
<h3>? extends T has been relaxed, e.g. for casting, Field.getType(), etc.</h3>
|
||||
<h3>Ant task removed</h3>
|
||||
<h3>#2001 eq/equal(null) and ne/notEqual(null) now work as in SQL</h3>
|
||||
|
||||
<h3>Object renames</h3>
|
||||
<ul>
|
||||
|
||||
@ -124,17 +124,6 @@ public interface Field<T> extends GroupField {
|
||||
@Override
|
||||
boolean equals(Object other);
|
||||
|
||||
/**
|
||||
* Whether this field represents a <code>null</code> literal.
|
||||
* <p>
|
||||
* This method is for JOOQ INTERNAL USE only!
|
||||
* <p>
|
||||
* This method was added to be able to recognise <code>null</code> literals
|
||||
* within jOOQ and handle them specially, as some SQL dialects have a rather
|
||||
* un-intuitive way of handling <code>null</code> values.
|
||||
*/
|
||||
boolean isNullLiteral();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Type casts
|
||||
// ------------------------------------------------------------------------
|
||||
@ -1284,10 +1273,6 @@ public interface Field<T> extends GroupField {
|
||||
|
||||
/**
|
||||
* <code>this = value</code>
|
||||
* <p>
|
||||
* If <code>value == null</code>, then this will return a condition
|
||||
* equivalent to {@link #isNull()} for convenience. SQL's ternary
|
||||
* <code>NULL</code> logic is rarely of use for Java programmers.
|
||||
*/
|
||||
@Support
|
||||
Condition equal(T value);
|
||||
@ -1319,10 +1304,6 @@ public interface Field<T> extends GroupField {
|
||||
|
||||
/**
|
||||
* <code>this = value</code>
|
||||
* <p>
|
||||
* If <code>value == null</code>, then this will return a condition
|
||||
* equivalent to {@link #isNull()} for convenience. SQL's ternary
|
||||
* <code>NULL</code> logic is rarely of use for Java programmers.
|
||||
*
|
||||
* @see #equal(Object)
|
||||
*/
|
||||
@ -1360,10 +1341,6 @@ public interface Field<T> extends GroupField {
|
||||
|
||||
/**
|
||||
* <code>this != value</code>
|
||||
* <p>
|
||||
* If <code>value == null</code>, then this will return a condition
|
||||
* equivalent to {@link #isNotNull()} for convenience. SQL's ternary
|
||||
* <code>NULL</code> logic is rarely of use for Java programmers.
|
||||
*/
|
||||
@Support
|
||||
Condition notEqual(T value);
|
||||
@ -1395,10 +1372,6 @@ public interface Field<T> extends GroupField {
|
||||
|
||||
/**
|
||||
* <code>this != value</code>
|
||||
* <p>
|
||||
* If <code>value == null</code>, then this will return a condition
|
||||
* equivalent to {@link #isNotNull()} for convenience. SQL's ternary
|
||||
* <code>NULL</code> logic is rarely of use for Java programmers.
|
||||
*
|
||||
* @see #notEqual(Object)
|
||||
*/
|
||||
|
||||
@ -106,9 +106,6 @@ abstract class AbstractField<T> extends AbstractQueryPart implements Field<T> {
|
||||
@Override
|
||||
public abstract void bind(BindContext context);
|
||||
|
||||
@Override
|
||||
public abstract boolean isNullLiteral();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// XXX: API
|
||||
// ------------------------------------------------------------------------
|
||||
@ -313,12 +310,12 @@ abstract class AbstractField<T> extends AbstractQueryPart implements Field<T> {
|
||||
|
||||
@Override
|
||||
public final Condition isNull() {
|
||||
return equal((T) null);
|
||||
return new IsNull(this, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Condition isNotNull() {
|
||||
return notEqual((T) null);
|
||||
return new IsNull(this, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -72,11 +72,6 @@ abstract class AbstractFunction<T> extends AbstractField<T> {
|
||||
context.bind(getFunction(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
final QueryPart getFunction(Configuration configuration) {
|
||||
return getFunction0(configuration);
|
||||
}
|
||||
|
||||
@ -80,9 +80,4 @@ class ArrayConstant<T> extends AbstractField<T> {
|
||||
public final void bind(BindContext context) {
|
||||
context.bindValues(array);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return array == null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,9 +139,4 @@ class CaseConditionStepImpl<T> extends AbstractField<T> implements CaseCondition
|
||||
context.keyword("end")
|
||||
.formatIndentLockEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,9 +198,4 @@ class CaseWhenStepImpl<V, T> extends AbstractField<T> implements CaseWhenStep<V,
|
||||
context.keyword("end")
|
||||
.formatIndentLockEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,9 +187,4 @@ class Cast<T> extends AbstractField<T> {
|
||||
|
||||
context.bind(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return field.isNullLiteral();
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,10 +37,8 @@
|
||||
package org.jooq.impl;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.jooq.Comparator.EQUALS;
|
||||
import static org.jooq.Comparator.LIKE;
|
||||
import static org.jooq.Comparator.LIKE_IGNORE_CASE;
|
||||
import static org.jooq.Comparator.NOT_EQUALS;
|
||||
import static org.jooq.Comparator.NOT_LIKE;
|
||||
import static org.jooq.Comparator.NOT_LIKE_IGNORE_CASE;
|
||||
import static org.jooq.SQLDialect.ASE;
|
||||
@ -79,12 +77,7 @@ class CompareCondition extends AbstractCondition {
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext context) {
|
||||
context.bind(field1);
|
||||
|
||||
// [#1084] Bind field2 only if it is actually rendered
|
||||
if (!field2.isNullLiteral() || !asList(EQUALS, NOT_EQUALS).contains(comparator)) {
|
||||
context.bind(field2);
|
||||
}
|
||||
context.bind(field1).bind(field2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -117,18 +110,6 @@ class CompareCondition extends AbstractCondition {
|
||||
context.sql(lhs)
|
||||
.sql(" ");
|
||||
|
||||
if (rhs.isNullLiteral()) {
|
||||
switch (op) {
|
||||
case EQUALS:
|
||||
context.keyword("is null");
|
||||
return;
|
||||
|
||||
case NOT_EQUALS:
|
||||
context.keyword("is not null");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// [#1131] Some weird DB2 issue stops "LIKE" from working with a
|
||||
// concatenated search expression, if the expression is more than 4000
|
||||
// characters long
|
||||
|
||||
@ -91,16 +91,6 @@ public abstract class CustomField<T> extends AbstractField<T> {
|
||||
// Further overrides allowed
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Subclasses may further override this method
|
||||
* <hr/>
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// No further overrides allowed
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -79,13 +79,13 @@ class Decode<T, Z> extends AbstractFunction<Z> {
|
||||
default: {
|
||||
CaseConditionStep<Z> when = Factory
|
||||
.decode()
|
||||
.when(field.equal(search), result);
|
||||
.when(field.isNotDistinctFrom(search), result);
|
||||
|
||||
for (int i = 0; i < more.length; i += 2) {
|
||||
|
||||
// search/result pair
|
||||
if (i + 1 < more.length) {
|
||||
when = when.when(field.equal((Field<T>) more[i]), (Field<Z>) more[i + 1]);
|
||||
when = when.when(field.isNotDistinctFrom((Field<T>) more[i]), (Field<Z>) more[i + 1]);
|
||||
}
|
||||
|
||||
// trailing default value
|
||||
|
||||
@ -536,10 +536,5 @@ class Expression<T> extends AbstractFunction<T> {
|
||||
public final void bind(BindContext context) {
|
||||
context.bind(lhs).bind((QueryPart) rhs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3113,15 +3113,19 @@ public class Factory {
|
||||
* Returns the dialect's equivalent to DECODE:
|
||||
* <ul>
|
||||
* <li>Oracle <a
|
||||
* href="http://www.techonthenet.com/oracle/functions/decode.php">DECODE</a></li>
|
||||
* href="http://www.techonthenet.com/oracle/functions/decode.php">DECODE</a>
|
||||
* </li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Other dialects: <code><pre>
|
||||
* CASE WHEN [this = search] THEN [result],
|
||||
* [WHEN more... THEN more...]
|
||||
* CASE WHEN [this IS NOT DISTINCT FROM search] THEN [result],
|
||||
* [WHEN more... THEN more...]
|
||||
* [ELSE more...]
|
||||
* END
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* Note the use of the <code>DISTINCT</code> predicate to produce the same,
|
||||
* conveniently <code>NULL</code>-agnostic behaviour as Oracle.
|
||||
*
|
||||
* @param value The value to decode
|
||||
* @param search the mandatory first search parameter
|
||||
@ -3129,7 +3133,7 @@ public class Factory {
|
||||
* @param more the optional parameters. If <code>more.length</code> is even,
|
||||
* then it is assumed that it contains more search/result pairs.
|
||||
* If <code>more.length</code> is odd, then it is assumed that it
|
||||
* contains more search/result pairs plus a default at the end. *
|
||||
* contains more search/result pairs plus a default at the end.
|
||||
*/
|
||||
@Support
|
||||
public static <Z, T> Field<Z> decode(Field<T> value, Field<T> search, Field<Z> result, Field<?>... more) {
|
||||
|
||||
@ -70,11 +70,6 @@ class FieldAlias<T> extends AbstractField<T> {
|
||||
return alias.wrapped().as(as);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return alias.wrapped().isNullLiteral();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean declaresFields() {
|
||||
return true;
|
||||
|
||||
@ -438,11 +438,6 @@ class Function<T> extends AbstractField<T> implements
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX aggregate and window function fluent API methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
67
jOOQ/src/main/java/org/jooq/impl/IsNull.java
Normal file
67
jOOQ/src/main/java/org/jooq/impl/IsNull.java
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.RenderContext;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class IsNull extends AbstractCondition {
|
||||
|
||||
private static final long serialVersionUID = -747240442279619486L;
|
||||
|
||||
private final Field<?> field;
|
||||
private final boolean isNull;
|
||||
|
||||
IsNull(Field<?> field, boolean isNull) {
|
||||
this.field = field;
|
||||
this.isNull = isNull;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext context) {
|
||||
context.bind(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void toSQL(RenderContext context) {
|
||||
context.sql(field).keyword(isNull ? " is null" : " is not null");
|
||||
}
|
||||
}
|
||||
@ -100,9 +100,4 @@ class Neg<T> extends AbstractField<T> {
|
||||
public final void bind(BindContext context) {
|
||||
context.bind(field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,9 +78,4 @@ class QualifiedField<T> extends AbstractField<T> {
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext context) {}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,9 +72,4 @@ class SQLField<T> extends AbstractField<T> {
|
||||
public final void bind(BindContext context) {
|
||||
Utils.renderAndBind(null, context, sql, substitutes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return "null".equalsIgnoreCase(("" + sql).trim());
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,9 +101,4 @@ class SelectQueryAsField<T> extends AbstractField<T> {
|
||||
.sql(")");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,9 +82,4 @@ class TableFieldImpl<R extends Record, T> extends AbstractField<T> implements Ta
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext context) {}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,9 +175,4 @@ class UDTConstant<R extends UDTRecord<R>> extends AbstractField<R> {
|
||||
throw new SQLDialectNotSupportedException("UDTs not supported in dialect " + context.getDialect());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return record == null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,9 +77,4 @@ class UDTFieldImpl<R extends UDTRecord<R>, T> extends AbstractField<T> implement
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext context) {}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -541,11 +541,6 @@ class Val<T> extends AbstractField<T> implements Param<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return getValue() == null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// XXX: Param API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user