You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2014/03/01 09:31:43 UTC
svn commit: r1573131 - in /cayenne/main/trunk/cayenne-server/src:
main/java/org/apache/cayenne/exp/parser/
test/java/org/apache/cayenne/exp/parser/
Author: aadamchik
Date: Sat Mar 1 08:31:43 2014
New Revision: 1573131
URL: http://svn.apache.org/r1573131
Log:
CAY-1877 In-memory evaluation of expression may fail with UnsupportedOpeartionException depending on order of nodes
Modified:
cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBetween.java
cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java
cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java
cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java
cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java
cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java
cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTNotBetween.java
cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/Evaluator.java
cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/EvaluatorTest.java
cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java
Modified: cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBetween.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBetween.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBetween.java (original)
+++ cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTBetween.java Sat Mar 1 08:31:43 2014
@@ -57,7 +57,17 @@ public class ASTBetween extends Conditio
Object o3 = evaluateChild(2, o);
Evaluator e = Evaluator.evaluator(o1);
- return e.compare(o1, o2) >= 0 && e.compare(o1, o3) <= 0 ? Boolean.TRUE : Boolean.FALSE;
+ Integer c1 = e.compare(o1, o2);
+ if (c1 == null) {
+ return Boolean.FALSE;
+ }
+
+ Integer c2 = e.compare(o1, o3);
+ if (c2 == null) {
+ return Boolean.FALSE;
+ }
+
+ return c1 >= 0 && c2 <= 0 ? Boolean.TRUE : Boolean.FALSE;
}
/**
Modified: cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java (original)
+++ cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java Sat Mar 1 08:31:43 2014
@@ -53,9 +53,9 @@ public class ASTGreater extends Conditio
Object o1 = evaluateChild(0, o);
Object o2 = evaluateChild(1, o);
- int diff = Evaluator.evaluator(o1).compare(o1, o2);
+ Integer c = Evaluator.evaluator(o1).compare(o1, o2);
- return diff > 0 ? Boolean.TRUE : Boolean.FALSE;
+ return c != null && c > 0 ? Boolean.TRUE : Boolean.FALSE;
}
/**
Modified: cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java (original)
+++ cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java Sat Mar 1 08:31:43 2014
@@ -55,9 +55,9 @@ public class ASTGreaterOrEqual extends C
Object o1 = evaluateChild(0, o);
Object o2 = evaluateChild(1, o);
- int diff = Evaluator.evaluator(o1).compare(o1, o2);
+ Integer c = Evaluator.evaluator(o1).compare(o1, o2);
- return diff >= 0 ? Boolean.TRUE : Boolean.FALSE;
+ return c != null && c >= 0 ? Boolean.TRUE : Boolean.FALSE;
}
/**
Modified: cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java (original)
+++ cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java Sat Mar 1 08:31:43 2014
@@ -56,6 +56,8 @@ public class ASTIn extends ConditionNode
}
Object o1 = evaluateChild(0, o);
+ // TODO: what if there's a NULL inside IN list?
+ // e.g. ASTEqual evals as "NULL == NULL"
if (o1 == null) {
return Boolean.FALSE;
}
Modified: cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java (original)
+++ cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java Sat Mar 1 08:31:43 2014
@@ -54,9 +54,9 @@ public class ASTLess extends ConditionNo
Object o1 = evaluateChild(0, o);
Object o2 = evaluateChild(1, o);
- int diff = Evaluator.evaluator(o1).compare(o1, o2);
+ Integer c = Evaluator.evaluator(o1).compare(o1, o2);
- return diff < 0 ? Boolean.TRUE : Boolean.FALSE;
+ return c != null && c < 0 ? Boolean.TRUE : Boolean.FALSE;
}
/**
Modified: cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java (original)
+++ cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java Sat Mar 1 08:31:43 2014
@@ -55,9 +55,9 @@ public class ASTLessOrEqual extends Cond
Object o1 = evaluateChild(0, o);
Object o2 = evaluateChild(1, o);
- int diff = Evaluator.evaluator(o1).compare(o1, o2);
+ Integer c = Evaluator.evaluator(o1).compare(o1, o2);
- return diff <= 0 ? Boolean.TRUE : Boolean.FALSE;
+ return c != null && c <= 0 ? Boolean.TRUE : Boolean.FALSE;
}
/**
Modified: cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTNotBetween.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTNotBetween.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTNotBetween.java (original)
+++ cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTNotBetween.java Sat Mar 1 08:31:43 2014
@@ -53,8 +53,18 @@ public class ASTNotBetween extends Condi
Object o2 = evaluateChild(1, o);
Object o3 = evaluateChild(2, o);
Evaluator e = Evaluator.evaluator(o1);
+
+ Integer c1 = e.compare(o1, o2);
+ if (c1 == null) {
+ return Boolean.FALSE;
+ }
- return e.compare(o1, o2) >= 0 && e.compare(o1, o3) <= 0 ? Boolean.FALSE : Boolean.TRUE;
+ Integer c2 = e.compare(o1, o3);
+ if (c2 == null) {
+ return Boolean.FALSE;
+ }
+
+ return c1 >= 0 && c2 <= 0 ? Boolean.FALSE : Boolean.TRUE;
}
/**
Modified: cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/Evaluator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/Evaluator.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/Evaluator.java (original)
+++ cayenne/main/trunk/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/Evaluator.java Sat Mar 1 08:31:43 2014
@@ -55,7 +55,7 @@ abstract class Evaluator {
}
@Override
- int compare(Object lhs, Object rhs) {
+ Integer compare(Object lhs, Object rhs) {
if (rhs == null) {
return 1;
@@ -75,8 +75,8 @@ abstract class Evaluator {
NULL_LHS_EVALUATOR = new Evaluator() {
@Override
- int compare(Object lhs, Object rhs) {
- throw new UnsupportedOperationException("Unsupported");
+ Integer compare(Object lhs, Object rhs) {
+ return null;
}
@Override
@@ -92,16 +92,16 @@ abstract class Evaluator {
}
@Override
- int compare(Object lhs, Object rhs) {
- throw new UnsupportedOperationException("Unsupported");
+ Integer compare(Object lhs, Object rhs) {
+ return null;
}
});
PERSISTENT_EVALUATOR = new NonNullLhsEvaluator(new Evaluator() {
@Override
- int compare(Object lhs, Object rhs) {
- throw new UnsupportedOperationException("Unsupported");
+ Integer compare(Object lhs, Object rhs) {
+ return null;
}
@Override
@@ -145,7 +145,7 @@ abstract class Evaluator {
BIG_DECIMAL_EVALUATOR = new NonNullLhsEvaluator(new Evaluator() {
@Override
- int compare(Object lhs, Object rhs) {
+ Integer compare(Object lhs, Object rhs) {
return ((BigDecimal) lhs).compareTo(ConversionUtil.toBigDecimal(rhs));
}
@@ -155,7 +155,8 @@ abstract class Evaluator {
// BigDecimals must be compared using compareTo (
// see CAY-280 and BigDecimal.equals JavaDoc)
- return compare(lhs, rhs) == 0;
+ Integer c = compare(lhs, rhs);
+ return c != null && c == 0;
}
});
@@ -163,7 +164,7 @@ abstract class Evaluator {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
- int compare(Object lhs, Object rhs) {
+ Integer compare(Object lhs, Object rhs) {
return ((Comparable) lhs).compareTo(ConversionUtil.toComparable(rhs));
}
@@ -229,5 +230,10 @@ abstract class Evaluator {
abstract boolean eq(Object lhs, Object rhs);
- abstract int compare(Object lhs, Object rhs);
+ /**
+ * Returns NULL if comparison is invalid, otherwise returns positive,
+ * negative or zero, with the same meaning as
+ * {@link Comparable#compareTo(Object)}.
+ */
+ abstract Integer compare(Object lhs, Object rhs);
}
Modified: cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/EvaluatorTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/EvaluatorTest.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/EvaluatorTest.java (original)
+++ cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/EvaluatorTest.java Sat Mar 1 08:31:43 2014
@@ -64,7 +64,8 @@ public class EvaluatorTest extends TestC
assertTrue(e.eq(lhs, new BigDecimal("1.1")));
assertFalse(e.eq(lhs, new BigDecimal("1.10001")));
- assertEquals(-1, e.compare(lhs, new BigDecimal("1.10001")));
+ Integer c = e.compare(lhs, new BigDecimal("1.10001"));
+ assertEquals(-1, c.intValue());
}
public void testEvaluator_Persistent() {
Modified: cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java?rev=1573131&r1=1573130&r2=1573131&view=diff
==============================================================================
--- cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java (original)
+++ cayenne/main/trunk/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java Sat Mar 1 08:31:43 2014
@@ -162,26 +162,30 @@ public class ExpressionEvaluateInMemoryT
assertTrue("Failed: " + notEqualTo, notEqualTo.match(noMatch));
}
- public void testEvaluateEQUAL_TONull() throws Exception {
- Expression equalTo = new ASTEqual(new ASTObjPath("artistName"), null);
+ public void testEvaluateEQUAL_TO_Null() throws Exception {
+ Expression equalToNull = new ASTEqual(new ASTObjPath("artistName"), null);
+ Expression equalToNotNull = new ASTEqual(new ASTObjPath("artistName"), "abc");
Artist match = new Artist();
- assertTrue(equalTo.match(match));
+ assertTrue(equalToNull.match(match));
+ assertFalse(equalToNotNull.match(match));
Artist noMatch = new Artist();
- noMatch.setArtistName("123");
- assertFalse("Failed: " + equalTo, equalTo.match(noMatch));
+ noMatch.setArtistName("abc");
+ assertFalse(equalToNull.match(noMatch));
}
public void testEvaluateNOT_EQUAL_TONull() throws Exception {
- Expression equalTo = new ASTNotEqual(new ASTObjPath("artistName"), null);
+ Expression notEqualToNull = new ASTNotEqual(new ASTObjPath("artistName"), null);
+ Expression notEqualToNotNull = new ASTNotEqual(new ASTObjPath("artistName"), "abc");
Artist match = new Artist();
- assertFalse(equalTo.match(match));
+ assertFalse(notEqualToNull.match(match));
+ assertTrue(notEqualToNotNull.match(match));
Artist noMatch = new Artist();
noMatch.setArtistName("123");
- assertTrue("Failed: " + equalTo, equalTo.match(noMatch));
+ assertTrue("Failed: " + notEqualToNull, notEqualToNull.match(noMatch));
}
public void testEvaluateEQUAL_TODataObject() throws Exception {
@@ -303,6 +307,15 @@ public class ExpressionEvaluateInMemoryT
match.setEstimatedPrice(new BigDecimal(9999));
assertTrue("Failed: " + e, e.match(match));
}
+
+ public void testEvaluateLESS_THAN_Null() throws Exception {
+ Expression ltNull = new ASTLess(new ASTObjPath("estimatedPrice"), null);
+ Expression ltNotNull = new ASTLess(new ASTObjPath("estimatedPrice"), new BigDecimal(10000d));
+
+ Painting noMatch = new Painting();
+ assertFalse(ltNull.match(noMatch));
+ assertFalse(ltNotNull.match(noMatch));
+ }
public void testEvaluateLESS_THAN_EQUAL_TO() throws Exception {
Expression e = new ASTLessOrEqual(new ASTObjPath("estimatedPrice"), new BigDecimal(10000d));
@@ -319,6 +332,15 @@ public class ExpressionEvaluateInMemoryT
match.setEstimatedPrice(new BigDecimal(9999));
assertTrue("Failed: " + e, e.match(match));
}
+
+ public void testEvaluateLESS_THAN_EQUAL_TO_Null() throws Exception {
+ Expression ltNull = new ASTLessOrEqual(new ASTObjPath("estimatedPrice"), null);
+ Expression ltNotNull = new ASTLessOrEqual(new ASTObjPath("estimatedPrice"), new BigDecimal(10000d));
+
+ Painting noMatch = new Painting();
+ assertFalse(ltNull.match(noMatch));
+ assertFalse(ltNotNull.match(noMatch));
+ }
public void testEvaluateGREATER_THAN() throws Exception {
Expression e = new ASTGreater(new ASTObjPath("estimatedPrice"), new BigDecimal(10000d));
@@ -335,6 +357,15 @@ public class ExpressionEvaluateInMemoryT
match.setEstimatedPrice(new BigDecimal(10001));
assertTrue("Failed: " + e, e.match(match));
}
+
+ public void testEvaluateGREATER_THAN_Null() throws Exception {
+ Expression gtNull = new ASTGreater(new ASTObjPath("estimatedPrice"), null);
+ Expression gtNotNull = new ASTGreater(new ASTObjPath("estimatedPrice"), new BigDecimal(10000d));
+
+ Painting noMatch = new Painting();
+ assertFalse(gtNull.match(noMatch));
+ assertFalse(gtNotNull.match(noMatch));
+ }
public void testEvaluateGREATER_THAN_EQUAL_TO() throws Exception {
Expression e = new ASTGreaterOrEqual(new ASTObjPath("estimatedPrice"), new BigDecimal(10000d));
@@ -351,6 +382,15 @@ public class ExpressionEvaluateInMemoryT
match.setEstimatedPrice(new BigDecimal(10001));
assertTrue("Failed: " + e, e.match(match));
}
+
+ public void testEvaluateGREATER_THAN_EQUAL_TO_Null() throws Exception {
+ Expression gtNull = new ASTGreaterOrEqual(new ASTObjPath("estimatedPrice"), null);
+ Expression gtNotNull = new ASTGreaterOrEqual(new ASTObjPath("estimatedPrice"), new BigDecimal(10000d));
+
+ Painting noMatch = new Painting();
+ assertFalse(gtNull.match(noMatch));
+ assertFalse(gtNotNull.match(noMatch));
+ }
public void testEvaluateBETWEEN() throws Exception {
// evaluate both BETWEEN and NOT_BETWEEN
@@ -378,6 +418,16 @@ public class ExpressionEvaluateInMemoryT
assertTrue("Failed: " + between, between.match(match3));
assertFalse("Failed: " + notBetween, notBetween.match(match3));
}
+
+ public void testEvaluateBETWEEN_Null() throws Exception {
+ Expression btNull = new ASTBetween(new ASTObjPath("estimatedPrice"), new BigDecimal(10d), new BigDecimal(20d));
+ Expression btNotNull = new ASTNotBetween(new ASTObjPath("estimatedPrice"), new BigDecimal(10d),
+ new BigDecimal(20d));
+
+ Painting noMatch = new Painting();
+ assertFalse(btNull.match(noMatch));
+ assertFalse(btNotNull.match(noMatch));
+ }
public void testEvaluateIN() throws Exception {
Expression in = new ASTIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] { new BigDecimal("10"),
@@ -406,6 +456,17 @@ public class ExpressionEvaluateInMemoryT
assertTrue("Failed: " + in, in.match(match2));
assertFalse("Failed: " + notIn, notIn.match(match2));
}
+
+ public void testEvaluateIN_Null() throws Exception {
+ Expression in = new ASTIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] {
+ new BigDecimal("10"), new BigDecimal("20") }));
+ Expression notIn = new ASTNotIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] {
+ new BigDecimal("10"), new BigDecimal("20") }));
+
+ Painting noMatch = new Painting();
+ assertFalse(in.match(noMatch));
+ assertFalse(notIn.match(noMatch));
+ }
public void testEvaluateLIKE1() throws Exception {
Expression like = new ASTLike(new ASTObjPath("artistName"), "abc%d");