diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/GeneralTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/GeneralTests.java
index 204fd2fdcd..444a472a75 100644
--- a/jOOQ-test/src/org/jooq/test/_/testcases/GeneralTests.java
+++ b/jOOQ-test/src/org/jooq/test/_/testcases/GeneralTests.java
@@ -364,9 +364,7 @@ extends BaseTest 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 u = create().updateQuery(TAuthor());
diff --git a/jOOQ-website/src/main/resources/manual-3.0.xml b/jOOQ-website/src/main/resources/manual-3.0.xml
index 5bf285ee45..4a7d331d5d 100644
--- a/jOOQ-website/src/main/resources/manual-3.0.xml
+++ b/jOOQ-website/src/main/resources/manual-3.0.xml
@@ -9164,6 +9164,7 @@ for (Record record : create().select(
GroupField
? extends T has been relaxed, e.g. for casting, Field.getType(), etc.
Ant task removed
+ #2001 eq/equal(null) and ne/notEqual(null) now work as in SQL
Object renames
diff --git a/jOOQ/src/main/java/org/jooq/Field.java b/jOOQ/src/main/java/org/jooq/Field.java
index 64283fb4ee..bac23706d3 100644
--- a/jOOQ/src/main/java/org/jooq/Field.java
+++ b/jOOQ/src/main/java/org/jooq/Field.java
@@ -124,17 +124,6 @@ public interface Field extends GroupField {
@Override
boolean equals(Object other);
- /**
- * Whether this field represents a null literal.
- *
- * This method is for JOOQ INTERNAL USE only!
- *
- * This method was added to be able to recognise null literals
- * within jOOQ and handle them specially, as some SQL dialects have a rather
- * un-intuitive way of handling null values.
- */
- boolean isNullLiteral();
-
// ------------------------------------------------------------------------
// Type casts
// ------------------------------------------------------------------------
@@ -1284,10 +1273,6 @@ public interface Field extends GroupField {
/**
* this = value
- *
- * If value == null, then this will return a condition
- * equivalent to {@link #isNull()} for convenience. SQL's ternary
- * NULL logic is rarely of use for Java programmers.
*/
@Support
Condition equal(T value);
@@ -1319,10 +1304,6 @@ public interface Field extends GroupField {
/**
* this = value
- *
- * If value == null, then this will return a condition
- * equivalent to {@link #isNull()} for convenience. SQL's ternary
- * NULL logic is rarely of use for Java programmers.
*
* @see #equal(Object)
*/
@@ -1360,10 +1341,6 @@ public interface Field extends GroupField {
/**
* this != value
- *
- * If value == null, then this will return a condition
- * equivalent to {@link #isNotNull()} for convenience. SQL's ternary
- * NULL logic is rarely of use for Java programmers.
*/
@Support
Condition notEqual(T value);
@@ -1395,10 +1372,6 @@ public interface Field extends GroupField {
/**
* this != value
- *
- * If value == null, then this will return a condition
- * equivalent to {@link #isNotNull()} for convenience. SQL's ternary
- * NULL logic is rarely of use for Java programmers.
*
* @see #notEqual(Object)
*/
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
index 2bc5aac9cb..1376447331 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
@@ -106,9 +106,6 @@ abstract class AbstractField extends AbstractQueryPart implements Field {
@Override
public abstract void bind(BindContext context);
- @Override
- public abstract boolean isNullLiteral();
-
// ------------------------------------------------------------------------
// XXX: API
// ------------------------------------------------------------------------
@@ -313,12 +310,12 @@ abstract class AbstractField extends AbstractQueryPart implements Field {
@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
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractFunction.java b/jOOQ/src/main/java/org/jooq/impl/AbstractFunction.java
index c66e36fe55..8d2cc14d33 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractFunction.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractFunction.java
@@ -72,11 +72,6 @@ abstract class AbstractFunction extends AbstractField {
context.bind(getFunction(context));
}
- @Override
- public final boolean isNullLiteral() {
- return false;
- }
-
final QueryPart getFunction(Configuration configuration) {
return getFunction0(configuration);
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/ArrayConstant.java b/jOOQ/src/main/java/org/jooq/impl/ArrayConstant.java
index 26b50a2e72..64609f3eed 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ArrayConstant.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ArrayConstant.java
@@ -80,9 +80,4 @@ class ArrayConstant extends AbstractField {
public final void bind(BindContext context) {
context.bindValues(array);
}
-
- @Override
- public final boolean isNullLiteral() {
- return array == null;
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java
index a3f56ab14a..ad2efbf775 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java
@@ -139,9 +139,4 @@ class CaseConditionStepImpl extends AbstractField implements CaseCondition
context.keyword("end")
.formatIndentLockEnd();
}
-
- @Override
- public final boolean isNullLiteral() {
- return false;
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java
index c32ab6d25b..db8694d31a 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java
@@ -198,9 +198,4 @@ class CaseWhenStepImpl extends AbstractField implements CaseWhenStep extends AbstractField {
context.bind(field);
}
-
- @Override
- public final boolean isNullLiteral() {
- return field.isNullLiteral();
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java b/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java
index 08d6cf3912..5bf40fbfcc 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java
@@ -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
diff --git a/jOOQ/src/main/java/org/jooq/impl/CustomField.java b/jOOQ/src/main/java/org/jooq/impl/CustomField.java
index f3857eb2b3..bc0c61bd6b 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CustomField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CustomField.java
@@ -91,16 +91,6 @@ public abstract class CustomField extends AbstractField {
// Further overrides allowed
// -------------------------------------------------------------------------
- /**
- * Subclasses may further override this method
- *
- * {@inheritDoc}
- */
- @Override
- public boolean isNullLiteral() {
- return false;
- }
-
// -------------------------------------------------------------------------
// No further overrides allowed
// -------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/Decode.java b/jOOQ/src/main/java/org/jooq/impl/Decode.java
index dcfae5d0b2..2426dd7257 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Decode.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Decode.java
@@ -79,13 +79,13 @@ class Decode extends AbstractFunction {
default: {
CaseConditionStep 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) more[i]), (Field) more[i + 1]);
+ when = when.when(field.isNotDistinctFrom((Field) more[i]), (Field) more[i + 1]);
}
// trailing default value
diff --git a/jOOQ/src/main/java/org/jooq/impl/Expression.java b/jOOQ/src/main/java/org/jooq/impl/Expression.java
index 98c2d23902..a450650d1e 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Expression.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Expression.java
@@ -536,10 +536,5 @@ class Expression extends AbstractFunction {
public final void bind(BindContext context) {
context.bind(lhs).bind((QueryPart) rhs);
}
-
- @Override
- public final boolean isNullLiteral() {
- return false;
- }
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/Factory.java b/jOOQ/src/main/java/org/jooq/impl/Factory.java
index b3bc9176df..1ac446ce71 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Factory.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Factory.java
@@ -3113,15 +3113,19 @@ public class Factory {
* Returns the dialect's equivalent to DECODE:
*
* - Oracle DECODE
+ * href="http://www.techonthenet.com/oracle/functions/decode.php">DECODE
+ *
*
*
* Other dialects:
- * 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
*
+ *
+ * Note the use of the DISTINCT predicate to produce the same,
+ * conveniently NULL-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 more.length is even,
* then it is assumed that it contains more search/result pairs.
* If more.length 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 Field decode(Field value, Field search, Field result, Field>... more) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldAlias.java b/jOOQ/src/main/java/org/jooq/impl/FieldAlias.java
index c58b118c59..a050ba764f 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FieldAlias.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FieldAlias.java
@@ -70,11 +70,6 @@ class FieldAlias extends AbstractField {
return alias.wrapped().as(as);
}
- @Override
- public final boolean isNullLiteral() {
- return alias.wrapped().isNullLiteral();
- }
-
@Override
public final boolean declaresFields() {
return true;
diff --git a/jOOQ/src/main/java/org/jooq/impl/Function.java b/jOOQ/src/main/java/org/jooq/impl/Function.java
index 573f55f9c3..15c6aa3837 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Function.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Function.java
@@ -438,11 +438,6 @@ class Function extends AbstractField implements
}
}
- @Override
- public final boolean isNullLiteral() {
- return false;
- }
-
// -------------------------------------------------------------------------
// XXX aggregate and window function fluent API methods
// -------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/IsNull.java b/jOOQ/src/main/java/org/jooq/impl/IsNull.java
new file mode 100644
index 0000000000..575430103f
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/IsNull.java
@@ -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");
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/Neg.java b/jOOQ/src/main/java/org/jooq/impl/Neg.java
index 068586594c..9c802a99f1 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Neg.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Neg.java
@@ -100,9 +100,4 @@ class Neg extends AbstractField {
public final void bind(BindContext context) {
context.bind(field);
}
-
- @Override
- public final boolean isNullLiteral() {
- return false;
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/QualifiedField.java b/jOOQ/src/main/java/org/jooq/impl/QualifiedField.java
index 2fee6d0fd5..fab8a18583 100644
--- a/jOOQ/src/main/java/org/jooq/impl/QualifiedField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/QualifiedField.java
@@ -78,9 +78,4 @@ class QualifiedField extends AbstractField {
@Override
public final void bind(BindContext context) {}
-
- @Override
- public final boolean isNullLiteral() {
- return false;
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLField.java b/jOOQ/src/main/java/org/jooq/impl/SQLField.java
index de26ed7ae6..d7f9494bf9 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SQLField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SQLField.java
@@ -72,9 +72,4 @@ class SQLField extends AbstractField {
public final void bind(BindContext context) {
Utils.renderAndBind(null, context, sql, substitutes);
}
-
- @Override
- public final boolean isNullLiteral() {
- return "null".equalsIgnoreCase(("" + sql).trim());
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java
index fb545f6270..a0ea66b82c 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java
@@ -101,9 +101,4 @@ class SelectQueryAsField extends AbstractField {
.sql(")");
}
}
-
- @Override
- public final boolean isNullLiteral() {
- return false;
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java
index bd52d373bc..8b30d46f0b 100644
--- a/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java
@@ -82,9 +82,4 @@ class TableFieldImpl extends AbstractField implements Ta
@Override
public final void bind(BindContext context) {}
-
- @Override
- public final boolean isNullLiteral() {
- return false;
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/UDTConstant.java b/jOOQ/src/main/java/org/jooq/impl/UDTConstant.java
index 8f0090151f..bbe3c3f2d6 100644
--- a/jOOQ/src/main/java/org/jooq/impl/UDTConstant.java
+++ b/jOOQ/src/main/java/org/jooq/impl/UDTConstant.java
@@ -175,9 +175,4 @@ class UDTConstant> extends AbstractField {
throw new SQLDialectNotSupportedException("UDTs not supported in dialect " + context.getDialect());
}
}
-
- @Override
- public final boolean isNullLiteral() {
- return record == null;
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/UDTFieldImpl.java b/jOOQ/src/main/java/org/jooq/impl/UDTFieldImpl.java
index 531650089b..1b06310a60 100644
--- a/jOOQ/src/main/java/org/jooq/impl/UDTFieldImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/UDTFieldImpl.java
@@ -77,9 +77,4 @@ class UDTFieldImpl, T> extends AbstractField implement
@Override
public final void bind(BindContext context) {}
-
- @Override
- public final boolean isNullLiteral() {
- return false;
- }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/Val.java b/jOOQ/src/main/java/org/jooq/impl/Val.java
index 63f0bac238..41a80de158 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Val.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Val.java
@@ -541,11 +541,6 @@ class Val extends AbstractField implements Param {
}
}
- @Override
- public final boolean isNullLiteral() {
- return getValue() == null;
- }
-
// ------------------------------------------------------------------------
// XXX: Param API
// ------------------------------------------------------------------------