[Mulgara-svn] r795 - in branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter: . arithmetic value

pag at mulgara.org pag at mulgara.org
Thu Apr 17 04:29:45 UTC 2008


Author: pag
Date: 2008-04-16 21:29:44 -0700 (Wed, 16 Apr 2008)
New Revision: 795

Added:
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/BinaryComparisonUnitTest.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/EqualityComparisonUnitTest.java
Modified:
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/AbstractFilterValue.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/NotEquals.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/NotUnitTest.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/arithmetic/AbstractNumericOperation.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractAccessorFn.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractComparable.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractComparableLiteral.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/BlankNodeValue.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/DataTypeFn.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/IRI.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/LangFn.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/SimpleLiteral.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/StrFn.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/TypedLiteral.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/TypedLiteralUnitTest.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/ValueLiteral.java
   branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/Var.java
Log:
Extensive testing of the filter package. This led to bugfixes and a few interface updates

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/AbstractFilterValue.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/AbstractFilterValue.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/AbstractFilterValue.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -13,6 +13,7 @@
 
 import org.mulgara.query.QueryException;
 import org.mulgara.query.filter.value.Bool;
+import org.mulgara.query.filter.value.ComparableExpression;
 import org.mulgara.query.filter.value.IRI;
 import org.mulgara.query.filter.value.SimpleLiteral;
 import org.mulgara.query.filter.value.ValueLiteral;
@@ -48,6 +49,9 @@
   /** @see org.mulgara.query.filter.value.ValueLiteral#getType() */
   public IRI getType() throws QueryException { return Bool.IRI_TYPE; }
 
+  /** @see org.mulgara.query.filter.value.ValueLiteral#isSimple() */
+  public boolean isSimple() throws QueryException { return false; }
+
   /**
    * @see org.mulgara.query.filter.value.ValueLiteral#getLexical()
    * @throws QueryException if this function does not resolve to a literal
@@ -94,6 +98,38 @@
   /** @see org.mulgara.query.filter.RDFTerm#sameTerm(org.mulgara.query.filter.RDFTerm) */
   public boolean sameTerm(RDFTerm v) throws QueryException { return resolve().sameTerm(v); }
 
+  /////////////////////////////////////////////////////////////////
+  // The following all implement the ComparableExpression interface
+  /////////////////////////////////////////////////////////////////
+
+  /** @see org.mulgara.query.filter.value.ComparableExpression#greaterThan(org.mulgara.query.filter.value.ComparableExpression) */
+  public boolean greaterThan(ComparableExpression v) throws QueryException {
+    if (!isLiteral()) throw new QueryException("Type Error: cannot compare a: " + getClass().getSimpleName());
+    return ((ValueLiteral)resolve()).greaterThan(v);
+  }
+
+  /** @see org.mulgara.query.filter.value.ComparableExpression#greaterThanEqualTo(org.mulgara.query.filter.value.ComparableExpression) */
+  public boolean greaterThanEqualTo(ComparableExpression v) throws QueryException {
+    if (!isLiteral()) throw new QueryException("Type Error: cannot compare a: " + getClass().getSimpleName());
+    return ((ValueLiteral)resolve()).greaterThanEqualTo(v);
+  }
+
+  /** @see org.mulgara.query.filter.value.ComparableExpression#lessThan(org.mulgara.query.filter.value.ComparableExpression) */
+  public boolean lessThan(ComparableExpression v) throws QueryException {
+    if (!isLiteral()) throw new QueryException("Type Error: cannot compare a: " + getClass().getSimpleName());
+    return ((ValueLiteral)resolve()).lessThan(v);
+  }
+
+  /** @see org.mulgara.query.filter.value.ComparableExpression#lessThanEqualTo(org.mulgara.query.filter.value.ComparableExpression) */
+  public boolean lessThanEqualTo(ComparableExpression v) throws QueryException {
+    if (!isLiteral()) throw new QueryException("Type Error: cannot compare a: " + getClass().getSimpleName());
+    return ((ValueLiteral)resolve()).lessThanEqualTo(v);
+  }
+
+  /////////////////////////////////////////////////////////////////
+  // End of the ComparableExpression interface
+  /////////////////////////////////////////////////////////////////
+
   /** @see org.mulgara.query.filter.RDFTerm#getContextOwner() */
   public ContextOwner getContextOwner() { return contextOwner; }
 

Added: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/BinaryComparisonUnitTest.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/BinaryComparisonUnitTest.java	                        (rev 0)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/BinaryComparisonUnitTest.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -0,0 +1,365 @@
+/**
+ * The contents of this file are subject to the Open Software License
+ * Version 3.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.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+package org.mulgara.query.filter;
+
+import java.net.URI;
+import java.util.Date;
+
+import org.jrdf.graph.Literal;
+import org.jrdf.graph.Node;
+import org.mulgara.query.QueryException;
+import org.mulgara.query.filter.TestContext;
+import org.mulgara.query.filter.TestContextOwner;
+import org.mulgara.query.rdf.BlankNodeImpl;
+import org.mulgara.query.rdf.LiteralImpl;
+import org.mulgara.query.rdf.URIReferenceImpl;
+
+import org.mulgara.query.filter.value.Bool;
+import org.mulgara.query.filter.value.ComparableExpression;
+import org.mulgara.query.filter.value.DateTime;
+import org.mulgara.query.filter.value.TypedLiteral;
+import org.mulgara.query.filter.value.Var;
+
+import static org.mulgara.query.filter.value.TypedLiteral.XSD_NS;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+/**
+ * Tests the inequality functions.
+ *
+ * @created Apr 16, 2008
+ * @author Paul Gearon
+ * @copyright &copy; 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class BinaryComparisonUnitTest extends TestCase {
+
+  protected URI xsdInt = URI.create(XSD_NS + "int");
+  protected URI xsdFloat = URI.create(XSD_NS + "float");
+  protected URI xsdString = URI.create(XSD_NS + "string");
+  protected URI xsdDate = URI.create(XSD_NS + "dateTime");
+  Bool t = Bool.TRUE;
+  Bool f = Bool.FALSE;
+
+  /**
+   * Build the unit test.
+   * @param name The name of the test
+   */
+  public BinaryComparisonUnitTest(String name) {
+    super(name);
+  }
+
+  /**
+   * Hook for test runner to obtain a test suite from.
+   * @return The test suite
+   */
+  public static Test suite() {
+    TestSuite suite = new TestSuite();
+    suite.addTest(new BinaryComparisonUnitTest("testLiteral"));
+    suite.addTest(new BinaryComparisonUnitTest("testVarCompatible"));
+    suite.addTest(new BinaryComparisonUnitTest("testVarInCompatible"));
+    return suite;
+  }
+
+  public void testLiteral() throws Exception {
+    // integers
+    ComparableExpression smaller = TypedLiteral.newLiteral(7);
+    ComparableExpression larger = TypedLiteral.newLiteral(8);
+    compatibleTest(smaller, larger);
+    // floats
+    smaller = TypedLiteral.newLiteral(7.0);
+    larger = TypedLiteral.newLiteral(8.0);
+    compatibleTest(smaller, larger);
+    // float/integer
+    larger = TypedLiteral.newLiteral(8);
+    compatibleTest(smaller, larger);
+
+    // simple literals
+    smaller = TypedLiteral.newLiteral("foo", null, null);
+    larger = TypedLiteral.newLiteral("goo", null, null);
+    compatibleTest(smaller, larger);
+    // simple literals, with language codes
+    smaller = TypedLiteral.newLiteral("foo", null, "en");
+    larger = TypedLiteral.newLiteral("foo", null, "fr");
+    compatibleTest(smaller, larger);
+    larger = TypedLiteral.newLiteral("goo", null, "en");
+    compatibleTest(smaller, larger);
+    // typed literal strings
+    smaller = TypedLiteral.newLiteral("foo");
+    larger = TypedLiteral.newLiteral("goo");
+    compatibleTest(smaller, larger);
+
+    // booleans
+    smaller = f;
+    larger = t;
+    compatibleTest(smaller, larger);
+
+    // typed literal strings
+    Date time = new Date();
+    smaller = new DateTime(time);
+    time = new Date();
+    time.setTime(time.getTime() + 100);
+    larger = new DateTime(time);
+    compatibleTest(smaller, larger);
+
+    // compare unequal literal types starting with an int
+    smaller = TypedLiteral.newLiteral(7);
+    larger = TypedLiteral.newLiteral("7", null, null);
+    incompatibleTest(smaller, larger);
+    larger = TypedLiteral.newLiteral("foo", null, "en");
+    incompatibleTest(smaller, larger);
+    larger = TypedLiteral.newLiteral("foo");
+    incompatibleTest(smaller, larger);
+    larger = t;
+    incompatibleTest(smaller, larger);
+    larger = new DateTime(time);
+    incompatibleTest(smaller, larger);
+
+    // compare unequal literal types starting with a float
+    smaller = TypedLiteral.newLiteral(7.0);
+    larger = TypedLiteral.newLiteral("7", null, null);
+    incompatibleTest(smaller, larger);
+    larger = TypedLiteral.newLiteral("foo", null, "en");
+    incompatibleTest(smaller, larger);
+    larger = TypedLiteral.newLiteral("foo");
+    incompatibleTest(smaller, larger);
+    larger = t;
+    incompatibleTest(smaller, larger);
+    larger = new DateTime(time);
+    incompatibleTest(smaller, larger);
+
+    // compare unequal literal types starting with a simple literal
+    smaller = TypedLiteral.newLiteral("foo", null, null);
+    larger = TypedLiteral.newLiteral("foo");
+    incompatibleTest(smaller, larger);
+    larger = t;
+    incompatibleTest(smaller, larger);
+    larger = new DateTime(time);
+    incompatibleTest(smaller, larger);
+
+    // compare unequal literal types starting with a language coded simple literal
+    smaller = TypedLiteral.newLiteral("foo", null, "en");
+    larger = TypedLiteral.newLiteral("foo");
+    incompatibleTest(smaller, larger);
+    larger = t;
+    incompatibleTest(smaller, larger);
+    larger = new DateTime(time);
+    incompatibleTest(smaller, larger);
+
+    // compare unequal literal types starting with a string literal
+    smaller = TypedLiteral.newLiteral("foo");
+    larger = t;
+    incompatibleTest(smaller, larger);
+    larger = new DateTime(time);
+    incompatibleTest(smaller, larger);
+
+    // compare unequal literal types
+    smaller = t;
+    larger = new DateTime(time);
+    incompatibleTest(smaller, larger);
+
+    
+    smaller = TypedLiteral.newLiteral("foo", null, null);
+    larger = TypedLiteral.newLiteral("foo", xsdString, null);
+    incompatibleTest(smaller, larger);
+
+  }
+
+  private void compatibleTest(ComparableExpression smaller, ComparableExpression larger) throws Exception {
+    assertTrue(t.equals(new LessThan(smaller, larger)));
+    assertTrue(f.equals(new LessThan(larger, smaller)));
+    assertTrue(f.equals(new GreaterThan(smaller, larger)));
+    assertTrue(t.equals(new GreaterThan(larger, smaller)));
+    assertTrue(t.equals(new LessThanEqualTo(smaller, larger)));
+    assertTrue(f.equals(new LessThanEqualTo(larger, smaller)));
+    assertTrue(t.equals(new LessThanEqualTo(smaller, smaller)));
+    assertTrue(f.equals(new GreaterThanEqualTo(smaller, larger)));
+    assertTrue(t.equals(new GreaterThanEqualTo(larger, smaller)));
+    assertTrue(t.equals(new GreaterThanEqualTo(smaller, smaller)));
+  }
+
+  private void checkIncompatible(BinaryComparisonFilter op) throws Exception {
+    try {
+      op.getValue();
+      fail("Successfully compared incompatible types");
+    } catch (QueryException qe) {
+      assertTrue(qe.getMessage().startsWith("Type Error:"));
+    }
+  }
+
+  private void incompatibleTest(ComparableExpression lhs, ComparableExpression rhs) throws Exception {
+    checkIncompatible(new LessThan(lhs, rhs));
+    checkIncompatible(new LessThan(rhs, lhs));
+    checkIncompatible(new GreaterThan(lhs, rhs));
+    checkIncompatible(new GreaterThan(rhs, lhs));
+    checkIncompatible(new LessThanEqualTo(lhs, rhs));
+    checkIncompatible(new LessThanEqualTo(rhs, lhs));
+    checkIncompatible(new GreaterThanEqualTo(lhs, rhs));
+    checkIncompatible(new GreaterThanEqualTo(rhs, lhs));
+  }
+
+  public void testVarCompatible() throws Exception {
+    Var x = new Var("x");
+    Var y = new Var("y");
+    BinaryComparisonFilter ltT = new LessThan(x, y);
+    BinaryComparisonFilter ltF = new LessThan(y, x);
+    BinaryComparisonFilter gtT = new GreaterThan(x, y);
+    BinaryComparisonFilter gtF = new GreaterThan(y, x);
+
+    BinaryComparisonFilter lteT = new LessThanEqualTo(x, y);
+    BinaryComparisonFilter lteF = new LessThanEqualTo(y, x);
+    BinaryComparisonFilter lteE = new LessThanEqualTo(x, x);
+    BinaryComparisonFilter gteT = new GreaterThanEqualTo(x, y);
+    BinaryComparisonFilter gteF = new GreaterThanEqualTo(y, x);
+    BinaryComparisonFilter gteE = new GreaterThanEqualTo(x, x);
+
+    BinaryComparisonFilter[] comps  = new BinaryComparisonFilter[] { ltT, ltF, gtT, gtF, lteT, lteF, lteE, gteT, gteF, gteE };
+    
+    Literal seven = new LiteralImpl("7", xsdInt);
+    Literal eight = new LiteralImpl("8", xsdInt);
+    Literal sevenF = new LiteralImpl("7.0", xsdFloat);
+    Literal eightF = new LiteralImpl("8.0", xsdFloat);
+    Literal simpleFoo = new LiteralImpl("foo");
+    Literal simpleGoo = new LiteralImpl("goo");
+    Literal simpleFooEn = new LiteralImpl("foo", "en");
+    Literal simpleFooFr = new LiteralImpl("foo", "fr");
+    Literal simpleGooEn = new LiteralImpl("goo", "en");
+    Literal foo = new LiteralImpl("foo", xsdString);
+    Literal goo = new LiteralImpl("goo", xsdString);
+    Literal litFalse = new LiteralImpl("false", t.getType().getValue());
+    Literal litTrue = new LiteralImpl("true", t.getType().getValue());
+    Literal now = new LiteralImpl("2008-04-16T21:57:00Z", xsdDate);
+    Literal soon = new LiteralImpl("2008-04-16T21:58:01Z", xsdDate);
+    Node[][] rows = {
+      new Node[] {seven, eight},
+      new Node[] {sevenF, eightF},
+
+      new Node[] {simpleFoo, simpleGoo},
+      new Node[] {simpleFooEn, simpleFooFr},
+      new Node[] {simpleFooEn, simpleGooEn},
+      new Node[] {foo, goo},
+      new Node[] {litFalse, litTrue},
+      new Node[] {now, soon}
+    };
+    TestContext c = new TestContext(new String[] {"x", "y"}, rows);
+    c.beforeFirst();
+    TestContextOwner ctxOwner = new TestContextOwner(c);
+    for (BinaryComparisonFilter f: comps) f.setContextOwner(ctxOwner);
+
+    // check the context setting
+    for (BinaryComparisonFilter f: comps) f.setCurrentContext(c);
+
+    // run the tests
+    while (c.next()) compatibleTest(c, comps);
+  }
+
+  private void compatibleTest(TestContext c, BinaryComparisonFilter[] comps) throws Exception {
+    assertTrue(t.equals(comps[0]));
+    assertTrue(f.equals(comps[1]));
+    assertTrue(f.equals(comps[2]));
+    assertTrue(t.equals(comps[3]));
+    assertTrue(t.equals(comps[4]));
+    assertTrue(f.equals(comps[5]));
+    assertTrue(t.equals(comps[6]));
+    assertTrue(f.equals(comps[7]));
+    assertTrue(t.equals(comps[8]));
+    assertTrue(t.equals(comps[9]));
+  }
+
+  public void testVarInCompatible() throws Exception {
+    Var x = new Var("x");
+    Var y = new Var("y");
+    BinaryComparisonFilter ltT = new LessThan(x, y);
+    BinaryComparisonFilter ltF = new LessThan(y, x);
+    BinaryComparisonFilter gtT = new GreaterThan(x, y);
+    BinaryComparisonFilter gtF = new GreaterThan(y, x);
+    BinaryComparisonFilter lteT = new LessThanEqualTo(x, y);
+    BinaryComparisonFilter lteF = new LessThanEqualTo(y, x);
+    BinaryComparisonFilter gteT = new GreaterThanEqualTo(x, y);
+    BinaryComparisonFilter gteF = new GreaterThanEqualTo(y, x);
+
+    BinaryComparisonFilter[] comps  = new BinaryComparisonFilter[] { ltT, ltF, gtT, gtF, lteT, lteF, gteT, gteF };
+    
+    Literal seven = new LiteralImpl("7", xsdInt);
+    Literal sevenSimple = new LiteralImpl("7");
+    Literal sevenF = new LiteralImpl("7.0", xsdFloat);
+    Literal simpleFoo = new LiteralImpl("foo");
+    Literal simpleFooEn = new LiteralImpl("foo", "en");
+    Literal foo = new LiteralImpl("foo", xsdString);
+    Literal litTrue = new LiteralImpl("true", t.getType().getValue());
+    Literal now = new LiteralImpl("2008-04-16T21:57:00Z", xsdDate);
+    URIReferenceImpl intRef = new URIReferenceImpl(xsdInt);
+    BlankNodeImpl bn = new BlankNodeImpl(101);
+    Node[][] rows = {
+      new Node[] {seven, sevenSimple},
+      new Node[] {seven, simpleFooEn},
+      new Node[] {seven, foo},
+      new Node[] {seven, litTrue},
+      new Node[] {seven, now},
+      new Node[] {sevenF, sevenSimple},
+      new Node[] {sevenF, simpleFooEn},
+      new Node[] {sevenF, foo},
+      new Node[] {sevenF, litTrue},
+      new Node[] {sevenF, now},
+      new Node[] {simpleFoo, foo},
+      new Node[] {simpleFoo, litTrue},
+      new Node[] {simpleFoo, now},
+      new Node[] {simpleFooEn, foo},
+      new Node[] {simpleFooEn, litTrue},
+      new Node[] {simpleFooEn, now},
+      new Node[] {foo, litTrue},
+      new Node[] {foo, now},  // 17
+      new Node[] {litTrue, now},
+      new Node[] {seven, intRef},  //19
+      new Node[] {sevenF, intRef},
+      new Node[] {simpleFoo, intRef},
+      new Node[] {simpleFooEn, intRef},
+      new Node[] {foo, intRef},
+      new Node[] {litTrue, intRef},
+      new Node[] {now, intRef},
+      new Node[] {seven, bn},
+      new Node[] {sevenF, bn},
+      new Node[] {simpleFoo, bn},
+      new Node[] {simpleFooEn, bn},
+      new Node[] {foo, bn},
+      new Node[] {litTrue, bn},
+      new Node[] {now, bn}
+    };
+    TestContext c = new TestContext(new String[] {"x", "y"}, rows);
+    c.beforeFirst();
+    TestContextOwner ctxOwner = new TestContextOwner(c);
+    for (BinaryComparisonFilter f: comps) f.setContextOwner(ctxOwner);
+
+    // check the context setting
+    for (BinaryComparisonFilter f: comps) f.setCurrentContext(c);
+
+    // run the tests
+    int r = 0;
+    while (c.next()) {
+      int test = 0;
+      try {
+        for (BinaryComparisonFilter f: comps) {
+          checkIncompatible(f);
+          test++;
+        }
+      } catch (Error e) {
+        System.err.println("Failed on row: " + r + "  test=" + test);
+        throw e;
+      }
+      r++;
+    }
+  }
+
+}

Added: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/EqualityComparisonUnitTest.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/EqualityComparisonUnitTest.java	                        (rev 0)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/EqualityComparisonUnitTest.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -0,0 +1,306 @@
+/**
+ * The contents of this file are subject to the Open Software License
+ * Version 3.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.opensource.org/licenses/osl-3.0.txt
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ */
+package org.mulgara.query.filter;
+
+import java.net.URI;
+
+import org.jrdf.graph.Literal;
+import org.jrdf.graph.Node;
+import org.mulgara.query.QueryException;
+import org.mulgara.query.filter.TestContext;
+import org.mulgara.query.filter.TestContextOwner;
+import org.mulgara.query.rdf.BlankNodeImpl;
+import org.mulgara.query.rdf.LiteralImpl;
+import org.mulgara.query.rdf.URIReferenceImpl;
+
+import org.mulgara.query.filter.value.BlankNodeValue;
+import org.mulgara.query.filter.value.Bool;
+import org.mulgara.query.filter.value.IRI;
+import org.mulgara.query.filter.value.TypedLiteral;
+import org.mulgara.query.filter.value.Var;
+
+import static org.mulgara.query.filter.value.TypedLiteral.XSD_NS;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+
+/**
+ * Tests the equals, not-equals, and sameTerm functions.
+ *
+ * @created Apr 15, 2008
+ * @author Paul Gearon
+ * @copyright &copy; 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
+ * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
+ */
+public class EqualityComparisonUnitTest extends TestCase {
+
+  protected URI xsdInt = URI.create(XSD_NS + "int");
+  protected URI xsdFloat = URI.create(XSD_NS + "float");
+  protected URI xsdString = URI.create(XSD_NS + "string");
+  Bool t = Bool.TRUE;
+  Bool f = Bool.FALSE;
+
+  /**
+   * Build the unit test.
+   * @param name The name of the test
+   */
+  public EqualityComparisonUnitTest(String name) {
+    super(name);
+  }
+
+  /**
+   * Hook for test runner to obtain a test suite from.
+   * @return The test suite
+   */
+  public static Test suite() {
+    TestSuite suite = new TestSuite();
+    suite.addTest(new EqualityComparisonUnitTest("testLiteral"));
+    suite.addTest(new EqualityComparisonUnitTest("testVar"));
+    return suite;
+  }
+
+  public void testLiteral() throws Exception {
+    // compares two equal literals
+    Equals fn = new Equals(t, t);
+    assertTrue(t.equals(fn));
+    assertTrue(fn.equals(t));
+    assertTrue(t.equals(new SameTerm(t, t)));
+    assertTrue(f.equals(new NotEquals(t, t)));
+
+    // compares two other equal literals
+    fn = new Equals(f, f);
+    assertTrue(t.equals(fn));
+    assertTrue(fn.equals(t));
+    assertTrue(t.equals(new SameTerm(f, f)));
+    assertTrue(f.equals(new NotEquals(f, f)));
+
+    // compare unequal literals
+    RDFTerm lhs = t;
+    RDFTerm rhs = f;
+    try {
+      assertTrue(f.equals(new Equals(lhs, rhs)));
+      fail("Unequal literals should throw an exception when compared for equality");
+    } catch (QueryException qe) {
+      assertTrue(qe.getMessage().startsWith("Type Error"));
+    }
+    assertTrue(f.equals(new SameTerm(lhs, rhs)));
+    assertTrue(t.equals(new NotEquals(lhs, rhs)));
+
+    // compare equivalent but different literals
+    lhs = TypedLiteral.newLiteral(7);
+    rhs = TypedLiteral.newLiteral(7.0);
+    try {
+      assertTrue(f.equals(new Equals(lhs, rhs)));
+      fail("Unequal literals should throw an exception when compared for equality");
+    } catch (QueryException qe) {
+      assertTrue(qe.getMessage().startsWith("Type Error"));
+    }
+    assertTrue(f.equals(new SameTerm(lhs, rhs)));
+    assertTrue(t.equals(new NotEquals(lhs, rhs)));
+
+    // compare unequal literal strings
+    lhs = TypedLiteral.newLiteral("foo", null, null);
+    rhs = TypedLiteral.newLiteral("fool", null, null);
+    try {
+      assertTrue(f.equals(new Equals(lhs, rhs)));
+      fail("Unequal literals should throw an exception when compared for equality");
+    } catch (QueryException qe) {
+      assertTrue(qe.getMessage().startsWith("Type Error"));
+    }
+    assertTrue(f.equals(new SameTerm(lhs, rhs)));
+    assertTrue(t.equals(new NotEquals(lhs, rhs)));
+
+    // compare unequal literals types
+    lhs = TypedLiteral.newLiteral("foo", null, null);
+    rhs = TypedLiteral.newLiteral("foo", xsdString, null);
+    try {
+      assertTrue(f.equals(new Equals(lhs, rhs)));
+      fail("Unequal literals should throw an exception when compared for equality");
+    } catch (QueryException qe) {
+      assertTrue(qe.getMessage().startsWith("Type Error"));
+    }
+    assertTrue(f.equals(new SameTerm(lhs, rhs)));
+    assertTrue(t.equals(new NotEquals(lhs, rhs)));
+
+    // compare unequal languages
+    lhs = TypedLiteral.newLiteral("foo", null, "en");
+    rhs = TypedLiteral.newLiteral("foo", null, "fr");
+    try {
+      assertTrue(f.equals(new Equals(lhs, rhs)));
+      fail("Unequal literals should throw an exception when compared for equality");
+    } catch (QueryException qe) {
+      assertTrue(qe.getMessage().startsWith("Type Error"));
+    }
+    assertTrue(f.equals(new SameTerm(lhs, rhs)));
+    assertTrue(t.equals(new NotEquals(lhs, rhs)));
+
+    // compare equal languages
+    lhs = TypedLiteral.newLiteral("foo", null, "en");
+    rhs = TypedLiteral.newLiteral("foo", null, "en");
+    assertTrue(t.equals(new Equals(lhs, rhs)));
+    assertTrue(t.equals(new SameTerm(lhs, rhs)));
+    assertTrue(f.equals(new NotEquals(lhs, rhs)));
+
+    // compare different URIs
+    lhs = new IRI(URI.create("http://mulgara.org/path/to/data.rdf"));
+    rhs = new IRI(URI.create("http://mulgara.org/path/to/../to/data.rdf"));
+    assertTrue(f.equals(new Equals(lhs, rhs)));
+    assertTrue(f.equals(new SameTerm(lhs, rhs)));
+    assertTrue(t.equals(new NotEquals(lhs, rhs)));
+
+    // compare the same URIs
+    lhs = new IRI(URI.create("http://mulgara.org/path/to/data.rdf"));
+    rhs = new IRI(URI.create("http://mulgara.org/path/to/data.rdf"));
+    assertTrue(t.equals(new Equals(lhs, rhs)));
+    assertTrue(t.equals(new SameTerm(lhs, rhs)));
+    assertTrue(f.equals(new NotEquals(lhs, rhs)));
+
+    // compare different blank nodes
+    lhs = new BlankNodeValue(new BlankNodeImpl(101));
+    rhs =  new BlankNodeValue(new BlankNodeImpl(102));
+    assertTrue(f.equals(new Equals(lhs, rhs)));
+    assertTrue(f.equals(new SameTerm(lhs, rhs)));
+    assertTrue(t.equals(new NotEquals(lhs, rhs)));
+
+    // compare the same blank nodes
+    lhs = new BlankNodeValue(new BlankNodeImpl(42));
+    rhs =  new BlankNodeValue(new BlankNodeImpl(42));
+    assertTrue(t.equals(new Equals(lhs, rhs)));
+    assertTrue(t.equals(new SameTerm(lhs, rhs)));
+    assertTrue(f.equals(new NotEquals(lhs, rhs)));
+  }
+
+  public void testVar() throws Exception {
+    Var x = new Var("x");
+    Var y = new Var("y");
+    AbstractFilterValue eq = new Equals(x, y);
+    AbstractFilterValue same = new SameTerm(x, y);
+    AbstractFilterValue ne = new NotEquals(x, y);
+
+    Literal seven = new LiteralImpl("7", xsdInt);
+    Literal sevenF = new LiteralImpl("7.0", xsdFloat);
+    Literal simple = new LiteralImpl("foo");
+    Literal str = new LiteralImpl("foo", xsdString);
+    Literal strEn = new LiteralImpl("foo", "en");
+    Literal strFr = new LiteralImpl("foo", "fr");
+    Node[][] rows = {
+      new Node[] {seven, seven},
+      new Node[] {seven, sevenF},
+
+      new Node[] {simple, simple},
+      new Node[] {simple, str},
+      new Node[] {simple, strEn},
+      new Node[] {simple, strFr},
+
+      new Node[] {str, str},
+      new Node[] {str, strEn},
+      new Node[] {strEn, strEn},
+      new Node[] {strEn, strFr},
+
+      new Node[] {str, new URIReferenceImpl(xsdInt)},
+      new Node[] {str, new BlankNodeImpl(101)},
+
+      new Node[] {new URIReferenceImpl(xsdInt), new URIReferenceImpl(xsdInt)},
+      new Node[] {new URIReferenceImpl(xsdInt), new URIReferenceImpl(xsdFloat)},
+      new Node[] {new URIReferenceImpl(xsdInt), new BlankNodeImpl(100)},
+
+      new Node[] {null, str},
+
+      new Node[] {new BlankNodeImpl(101), new BlankNodeImpl(101)},
+      new Node[] {new BlankNodeImpl(101), new BlankNodeImpl(102)}
+    };
+    TestContext c = new TestContext(new String[] {"x", "y"}, rows);
+    c.beforeFirst();
+    eq.setContextOwner(new TestContextOwner(c));
+    same.setContextOwner(new TestContextOwner(c));
+    ne.setContextOwner(new TestContextOwner(c));
+    // check the context setting
+    eq.setCurrentContext(c);
+    same.setCurrentContext(c);
+    ne.setCurrentContext(c);
+
+    String results = "tl tlll tltl ff tff x tf";
+    runTests(c, eq, same, ne, results);
+
+  }
+  
+  private void runTests(TestContext c, AbstractFilterValue eq, AbstractFilterValue same, AbstractFilterValue ne, String results) throws Exception {
+    c.beforeFirst();
+    for (char result: results.toCharArray()) {
+      if (result == ' ') continue;
+      assertTrue(c.next());
+      switch (result) {
+      case 't':  // equal
+        assertTrue(t.equals(eq));
+        assertTrue(t.equals(same));
+        assertTrue(f.equals(ne));
+        break;
+
+      case 'f':  // unequal
+        assertTrue(f.equals(eq));
+        assertTrue(f.equals(same));
+        assertTrue(t.equals(ne));
+        break;
+
+      case 'l':  // unequal literals
+        assertTrue(f.equals(same));
+        assertTrue(t.equals(ne));
+        try {
+          assertTrue(f.equals(eq));
+          fail("Unequal literals should throw an exception when compared for equality");
+        } catch (QueryException qe) {
+          assertTrue(qe.getMessage().startsWith("Type Error"));
+        }
+        break;
+
+      case 'e':  // equivalent but unequal
+        assertTrue(t.equals(same));
+        assertTrue(t.equals(ne));
+        try {
+          assertTrue(f.equals(eq));
+          fail("Unequal literals should throw an exception when compared for equality");
+        } catch (QueryException qe) {
+          assertTrue(qe.getMessage().startsWith("Type Error"));
+        }
+        break;
+
+      case 'x':  // exception due to unbound
+        try {
+          assertTrue(f.equals(eq));
+          fail("No exception when testing an unbound value for equality");
+        } catch (QueryException qe) {
+          assertTrue(qe.getMessage().startsWith("Unbound column"));
+        }
+        try {
+          assertTrue(f.equals(same));
+          fail("No exception when testing an unbound value for equivalency");
+        } catch (QueryException qe) {
+          assertTrue(qe.getMessage().startsWith("Unbound column"));
+        }
+        try {
+          assertTrue(f.equals(ne));
+          fail("No exception when testing an unbound value for inequality");
+        } catch (QueryException qe) {
+          assertTrue(qe.getMessage().startsWith("Unbound column"));
+        }
+        break;
+        
+      default:
+        fail("Bad test data");
+      }
+    }
+    assertFalse(c.next());
+  }
+
+}

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/NotEquals.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/NotEquals.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/NotEquals.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -24,12 +24,6 @@
  */
 public class NotEquals extends BinaryTestFilter {
 
-  /** The first operand */
-  protected RDFTerm lhs;
-
-  /** The second operand */
-  protected RDFTerm rhs;
-
   NotEquals(RDFTerm lhs, RDFTerm rhs) {
     super(lhs, rhs);
   }

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/NotUnitTest.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/NotUnitTest.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/NotUnitTest.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -32,7 +32,7 @@
 
 
 /**
- * Tests the AND operation.
+ * Tests the NOT operation.
  *
  * @created Apr 14, 2008
  * @author Paul Gearon

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/arithmetic/AbstractNumericOperation.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/arithmetic/AbstractNumericOperation.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/arithmetic/AbstractNumericOperation.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -131,4 +131,9 @@
     return NumericLiteral.getTypeFor(getValue());
   }
 
+  /** @see org.mulgara.query.filter.value.ValueLiteral#isSimple() */
+  public boolean isSimple() throws QueryException {
+    return false;
+  }
+
 }
\ No newline at end of file

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractAccessorFn.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractAccessorFn.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractAccessorFn.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -50,4 +50,34 @@
   public void setCurrentContext(Context context) {
     if (!(context.equals(getContextOwner().getCurrentContext()))) throw new AssertionError("Function context being set differently to initial calling context.");
   }
+
+  public boolean greaterThan(ComparableExpression v) throws QueryException {
+    return resolveComparable().greaterThan(v);
+  }
+
+  /** @see org.mulgara.query.filter.value.ComparableExpression#greaterThanEqualTo(org.mulgara.query.filter.value.ComparableExpression) */
+  public boolean greaterThanEqualTo(ComparableExpression v) throws QueryException {
+    return resolveComparable().greaterThanEqualTo(v);
+  }
+
+  /** @see org.mulgara.query.filter.value.ComparableExpression#lessThan(org.mulgara.query.filter.value.ComparableExpression) */
+  public boolean lessThan(ComparableExpression v) throws QueryException {
+    return resolveComparable().lessThan(v);
+  }
+
+  /** @see org.mulgara.query.filter.value.ComparableExpression#lessThanEqualTo(org.mulgara.query.filter.value.ComparableExpression) */
+  public boolean lessThanEqualTo(ComparableExpression v) throws QueryException {
+    return resolveComparable().lessThanEqualTo(v);
+  }
+
+  /**
+   * Resolves this function to a value that can be compared, or throws an exception if it cannot be compared.
+   * @return A value that can be compared for inequality.
+   * @throws QueryException If there was a problem resolving the function, or if the value is not comparable.
+   */
+  protected ComparableExpression resolveComparable() throws QueryException {
+    RDFTerm result = resolve();
+    if (!(result instanceof ComparableExpression)) throw new QueryException("Type error: cannot compare with a: " + result.getClass().getSimpleName());
+    return (ComparableExpression)result;
+  }
 }

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractComparable.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractComparable.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractComparable.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -27,11 +27,13 @@
 
   /** {@inheritDoc} */
   public boolean lessThan(ComparableExpression v) throws QueryException {
+    compatibilityTest(v);
     return compare(getValue(), v.getValue()) < 0;
   }
 
   /** {@inheritDoc} */
   public boolean greaterThan(ComparableExpression v) throws QueryException {
+    compatibilityTest(v);
     return compare(getValue(), v.getValue()) > 0;
   }
 
@@ -52,10 +54,20 @@
 
   /** {@inheritDoc} */
   public boolean notEquals(ComparableExpression v) throws QueryException {
-    return compare(getValue(), v.getValue()) != 0;
+    return !equals(v);
   }
 
   /**
+   * Tests a value to see if it is a simple literal, and throws an exception if it is.
+   * Simple literals do a similar test when compared with a ComparableExpression.
+   * @param v The comparable expression to test.
+   * @throws QueryException If the comparable expression resolves to a {@link SimpleLiteral}.
+   */
+  private void compatibilityTest(ComparableExpression v) throws QueryException {
+    if (v.isLiteral() && ((ValueLiteral)v).isSimple()) throw new QueryException("Type Error: cannot compare a simple literal with a: " + getClass().getSimpleName());
+  }
+
+  /**
    * Compares elements of the type handled by the implementing class.
    * @param left The LHS of the comparison
    * @param right The RHS of the comparison

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractComparableLiteral.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractComparableLiteral.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/AbstractComparableLiteral.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -69,36 +69,23 @@
   public boolean isLiteral() { return true; }
 
   /** {@inheritDoc} */
-  public boolean sameTerm(RDFTerm v) {
-    try {
-      if (!(v instanceof ValueLiteral)) return false;
-      IRI type = ((ValueLiteral)v).getType();
-      if (type == null || !type.equals(getType())) return false;
-      return getValue().equals(v.getValue());
-    } catch (QueryException qe) {
-      return false;
-    }
+  public boolean sameTerm(RDFTerm v) throws QueryException {
+    if (!v.isLiteral()) return false;
+    return equalLiteralTypes((ValueLiteral)v) && getValue().equals(v.getValue());
   }
 
-
   /**
    * {@inheritDoc}
-   * This method will only return <code>true</code> when the elements are identical,
-   * or if they have differing numeric types compare equal in number space.
+   * This method will only return <code>true</code> when the elements are identical.
    * Since this object is a literal, then an incorrect comparison will throw an exception.
    * {@link http://www.w3.org/TR/rdf-sparql-query/#func-RDFterm-equal}
+   * <em>produces a type error if the arguments are both literal but are not the same RDF term</em>
    */
   public boolean equals(RDFTerm v) throws QueryException {
-    if (!(v instanceof ValueLiteral)) return false;
-    IRI type = ((ValueLiteral)v).getType();
-    // check for differing types
-    if (type == null || !type.equals(getType())) {
-      // only handle equivalent numbers
-      return numberCompare(v);
-    }
-    // terms are the same type
-    if (getValue().equals(v.getValue())) return true;
-    throw new QueryException("Terms are not equal");
+    if (!v.isLiteral()) return false;
+    // compare types, and then check values
+    if (equalLiteralTypes((ValueLiteral)v) && getValue().equals(v.getValue())) return true;
+    throw new QueryException("Type Error: Terms are not equal");
   }
   
   /**
@@ -115,11 +102,32 @@
   }
 
   /**
-   * Extended numerical comparison function, for use with equals.
+   * Compares the type of this object to the type of another object. This takes into account
+   * that Simple Literals claim to have a string type, when they have no type at all.
+   * @param vl The object to test.
+   * @return <code>true</code> if the types are exactly the same. If both types are strings,
+   *   then both objects have to be typed literals, or untyped literals.
+   * @throws QueryException If there is an error accessing the type data.
+   */
+  private boolean equalLiteralTypes(ValueLiteral vl) throws QueryException {
+    IRI opType = vl.getType();
+    IRI thisType = getType();
+    assert opType != null && thisType != null;
+    // if the types differ, then not equal
+    if (!opType.equals(thisType)) return false;
+    // types are the same. If they are not strings, then definitely equal
+    if (!opType.equals(SimpleLiteral.STRING_TYPE)) return true;
+    // both types are strings. Only true if the other object is not a simple literal
+    return !vl.isSimple();
+  }
+
+  /**
+   * Extended numerical comparison function. Currently unused.
    * @param v The term to compare against.
    * @return <code>true</code> if this compares against v with semantic equivalence, regardless of lexical equivalence
    * @throws QueryException Thrown when a value cannot be resolved, or if the types are no numbers.
    */
+  @SuppressWarnings("unused")
   private boolean numberCompare(RDFTerm v) throws QueryException {
     if (!(value instanceof Number) || !(v.getValue() instanceof Number)) throw new QueryException("Terms are not equal");
     return compare(value, v) == 0;
@@ -134,7 +142,7 @@
    */
   protected int compare(Object left, Object right) throws QueryException {
     DataCompare cmpFn = typeMap.get(left.getClass());
-    if (cmpFn == null) throw new QueryException("Cannot compare a " + left.getClass() + " to a " + right.getClass());
+    if (cmpFn == null) throw new QueryException("Type Error: Cannot compare a " + left.getClass() + " to a " + right.getClass());
     return cmpFn.compare(left, right);
   }
 
@@ -174,7 +182,7 @@
   /** Implements string comparisons */
   private static class StringCompare implements DataCompare {
     public int compare(Object left, Object right) throws QueryException {
-      if (!(right instanceof String)) throw new QueryException("Cannot compare a String to a: " + right.getClass());
+      if (!(right instanceof String)) throw new QueryException("Type Error: Cannot compare a String to a: " + right.getClass());
       return ((String)left).compareTo((String)right);
     }
     public ValueLiteral newLiteral(Object data) { return new TypedLiteral((String)data, SimpleLiteral.STRING_TYPE.getValue()); }
@@ -183,7 +191,7 @@
   /** Implements string comparisons */
   private static class DateCompare implements DataCompare {
     public int compare(Object left, Object right) throws QueryException {
-      if (!(right instanceof Date)) throw new QueryException("Cannot compare a Date to a: " + right.getClass());
+      if (!(right instanceof Date)) throw new QueryException("Type Error: Cannot compare a Date to a: " + right.getClass());
       return ((Date)left).compareTo((Date)right);
     }
     public ValueLiteral newLiteral(Object data) { return new DateTime((Date)data); }
@@ -192,7 +200,7 @@
   /** Implements boolean comparisons */
   private static class BooleanCompare implements DataCompare {
     public int compare(Object left, Object right) throws QueryException {
-      if (!(right instanceof Boolean)) throw new QueryException("Cannot compare a boolean to a: " + right.getClass());
+      if (!(right instanceof Boolean)) throw new QueryException("Type Error: Cannot compare a boolean to a: " + right.getClass());
       return ((Boolean)left).compareTo((Boolean)right);
     }
     public ValueLiteral newLiteral(Object data) { return new Bool((Boolean)data); }
@@ -202,7 +210,7 @@
   private static class FloatCompare implements DataCompare {
     public int compare(Object left, Object right) throws QueryException {
       Float fleft = (Float)left;
-      if (!(right instanceof Number)) throw new QueryException("Cannot compare a float to a: " + right.getClass());
+      if (!(right instanceof Number)) throw new QueryException("Type Error: Cannot compare a float to a: " + right.getClass());
       // if right has more precision, then promote lfloat, and compare the other way around
       if (right instanceof Double) return -((Double)right).compareTo(fleft.doubleValue());
       return fleft.compareTo(((Number)right).floatValue());
@@ -213,7 +221,7 @@
   /** Implements double precision floating point comparisons */
   private static class DoubleCompare implements DataCompare {
     public int compare(Object left, Object right) throws QueryException {
-      if (!(right instanceof Number)) throw new QueryException("Cannot compare a double to a: " + right.getClass());
+      if (!(right instanceof Number)) throw new QueryException("Type Error: Cannot compare a double to a: " + right.getClass());
       return ((Double)left).compareTo(((Number)right).doubleValue());
     }
     public ValueLiteral newLiteral(Object data) { return new NumericLiteral((Double)data); }
@@ -222,7 +230,7 @@
   /** Implements integer comparisons */
   private static class DecimalCompare implements DataCompare {
     public int compare(Object left, Object right) throws QueryException {
-      if (!(right instanceof Number)) throw new QueryException("Cannot compare a decimal number to a: " + right.getClass());
+      if (!(right instanceof Number)) throw new QueryException("Type Error: Cannot compare a decimal number to a: " + right.getClass());
       Long lleft = ((Number)left).longValue();
       return lleft.compareTo(((Number)right).longValue());
     }

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/BlankNodeValue.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/BlankNodeValue.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/BlankNodeValue.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -45,12 +45,12 @@
 
   /** {@inheritDoc} */
   public boolean equals(RDFTerm v) throws QueryException {
-    return v instanceof BlankNodeValue && node.equals(((BlankNodeValue)v).node);
+    return v.isBlank() && node.equals(v.getValue());
   }
 
   /** {@inheritDoc} */
   public boolean notEquals(RDFTerm v) throws QueryException {
-    return !(v instanceof BlankNodeValue) || !node.equals(((BlankNodeValue)v).node);
+    return !equals(v);
   }
 
   /** {@inheritDoc} */

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/DataTypeFn.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/DataTypeFn.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/DataTypeFn.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -73,4 +73,14 @@
     if (!operand.isLiteral()) throw new QueryException("Disallowed type in DATATYPE function. Expected a Literal. Got a : " + operand.getClass().getSimpleName());
     return ((ValueLiteral)operand).getType();
   }
+
+  /**
+   * The return value of this class is not comparable, so always throw an exception.
+   * @return never returns a value.
+   * @throws QueryException To indicate that this class cannot be compared.
+   */
+  protected ComparableExpression resolveComparable() throws QueryException {
+    throw new QueryException("Type error: datatypes are IRIs which cannot be compared for anything but equality");
+  }
+
 }

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/IRI.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/IRI.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/IRI.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -47,7 +47,7 @@
 
   /** {@inheritDoc} */
   public boolean equals(RDFTerm v) throws QueryException {
-    return v.isIRI() && value.equals(((IRI)v).getValue());
+    return v.isIRI() && value.equals(v.getValue());
   }
 
   /** {@inheritDoc} */
@@ -68,8 +68,8 @@
   public boolean isLiteral() { return false; }
 
   /** {@inheritDoc} */
-  public boolean sameTerm(RDFTerm v) {
-    return v instanceof IRI && value.equals(((IRI)v).getValue());
+  public boolean sameTerm(RDFTerm v) throws QueryException {
+    return equals(v);
   }
 
   /** This value does not need a context */

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/LangFn.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/LangFn.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/LangFn.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -49,10 +49,15 @@
     return resolve().isLiteral();
   }
 
+  /** @see org.mulgara.query.filter.AbstractFilterValue#isSimple() */
+  public boolean isSimple() throws QueryException {
+    return ((ValueLiteral)resolve()).isSimple();
+  }
+
   /**
-   * 
-   * @return
-   * @throws QueryException
+   * Applies this function to its operands to get back a result.
+   * @return A language code for the operand.
+   * @throws QueryException If the operand was not a literal.
    */
   protected RDFTerm resolve() throws QueryException {
     if (!operand.isLiteral()) throw new QueryException("Disallowed type in LANG function. Expected a Literal. Got a : " + operand.getClass().getSimpleName());

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/SimpleLiteral.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/SimpleLiteral.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/SimpleLiteral.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -14,6 +14,7 @@
 import org.mulgara.query.QueryException;
 import org.mulgara.query.filter.Context;
 import org.mulgara.query.filter.ContextOwner;
+import org.mulgara.query.filter.RDFTerm;
 
 
 /**
@@ -27,7 +28,7 @@
 public class SimpleLiteral extends AbstractComparableLiteral {
 
   /** An empty simple literal */
-  public static final SimpleLiteral EMPTY = new SimpleLiteral("");
+  public static final SimpleLiteral EMPTY = new SimpleLiteral("", "");
 
   /** The language tag for a simple literal */
   private SimpleLiteral lang = EMPTY;
@@ -74,6 +75,11 @@
     return STRING_TYPE;
   }
 
+  /** @see org.mulgara.query.filter.value.ValueLiteral#isSimple() */
+  public boolean isSimple() throws QueryException {
+    return true;
+  }
+
   /**
    * @see org.mulgara.query.filter.value.ComparableExpression#test()
    */
@@ -87,4 +93,70 @@
   /** This value does not need a context */
   public void setContextOwner(ContextOwner owner) { }
 
+  /** {@inheritDoc} */
+  public boolean sameTerm(RDFTerm v) throws QueryException {
+    if (!v.isLiteral() || !((ValueLiteral)v).isSimple()) return false;
+    return getValue().equals(v.getValue()) && compareLangEquals((ValueLiteral)v);
+  }
+
+  /**
+   * {@inheritDoc}
+   * This method will only return <code>true</code> when the elements are identical.
+   * Since this object is a literal, then an incorrect comparison will throw an exception.
+   * {@link http://www.w3.org/TR/rdf-sparql-query/#func-RDFterm-equal}
+   * <em>produces a type error if the arguments are both literal but are not the same RDF term</em>
+   */
+  public boolean equals(RDFTerm v) throws QueryException {
+    if (!v.isLiteral()) return false;
+    if (((ValueLiteral)v).isSimple()) {
+      // check values and language codes
+      if (getValue().equals(v.getValue()) && compareLangEquals((ValueLiteral)v)) return true;
+    }
+    throw new QueryException("Type Error: Terms are not equal");
+  }
+
+  /** {@inheritDoc} */
+  public boolean lessThan(ComparableExpression v) throws QueryException {
+    if (!v.isLiteral() || !((ValueLiteral)v).isSimple()) throw new QueryException("Type Error: cannot compare a simple literal to a: " + v.getClass().getSimpleName());
+    int result = compareLang(convertToLiteral(v));
+    if (result == 0) return compare(getValue(), v.getValue()) < 0;
+    else return result < 0;
+  }
+
+  /** {@inheritDoc} */
+  public boolean greaterThan(ComparableExpression v) throws QueryException {
+    if (!v.isLiteral() || !((ValueLiteral)v).isSimple()) throw new QueryException("Type Error: cannot compare a simple literal to a: " + v.getClass().getSimpleName());
+    int result = compareLang(convertToLiteral(v));
+    if (result == 0) return compare(getValue(), v.getValue()) > 0;
+    else return result > 0;
+  }
+
+  /**
+   * Convert a comparable expression to a Literal, or throw an exception if it cannot be resolved this way.
+   * @param v The object to convert after testing
+   * @return The object as a ValueLiteral
+   * @throws QueryException Indicating that v is not a SimpleLiteral.
+   */
+  private ValueLiteral convertToLiteral(ComparableExpression v) throws QueryException {
+    if (!v.isLiteral() || !((ValueLiteral)v).isSimple()) throw new QueryException("Type Error: cannot compare a simple literal to a: " + v.getClass().getSimpleName());
+    return (ValueLiteral)v;
+  }
+
+  /**
+   * Tests equality for the language code to the language code of the given SimpleLiteral.
+   * @param sl The simple literal to compare against.
+   * @return <code>true</code> if the codes are equal, <code>false</code> otherwise.
+   */
+  private boolean compareLangEquals(ValueLiteral sl) throws QueryException {
+    return lang.equals(sl.getLang());
+  }
+
+  /**
+   * Compares the language code to the language code of the given SimpleLiteral.
+   * @param sl The simple literal to compare against.
+   * @return -1 if this code is less than the code of s1, +1 if greater, and 0 if they are equal
+   */
+  private int compareLang(ValueLiteral sl) throws QueryException {
+    return ((String)lang.getValue()).compareTo((String)sl.getLang().getValue());
+  }
 }

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/StrFn.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/StrFn.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/StrFn.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -42,6 +42,11 @@
     return SimpleLiteral.EMPTY;
   }
 
+  /** @see org.mulgara.query.filter.AbstractFilterValue#isSimple() */
+  public boolean isSimple() throws QueryException {
+    return ((ValueLiteral)resolve()).isSimple();
+  }
+
   /**
    * @see org.mulgara.query.filter.value.ValueLiteral#getLexical()
    * @throws QueryException if the operand does not resolve

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/TypedLiteral.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/TypedLiteral.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/TypedLiteral.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -96,6 +96,11 @@
     return new IRI(type);
   }
 
+  /** @see org.mulgara.query.filter.value.ValueLiteral#isSimple() */
+  public boolean isSimple() throws QueryException {
+    return false;
+  }
+
   /**
    * Gets the language ID of this literal
    * @return The language ID for this literal

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/TypedLiteralUnitTest.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/TypedLiteralUnitTest.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/TypedLiteralUnitTest.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -13,8 +13,10 @@
 
 import java.net.URI;
 
+import org.mulgara.query.QueryException;
 import org.mulgara.query.filter.Context;
 import org.mulgara.query.filter.TestContext;
+
 import static org.mulgara.query.filter.value.TypedLiteral.XSD_NS;
 
 import junit.framework.Test;
@@ -82,7 +84,12 @@
     assertFalse(l.test(c));
 
     l = (TypedLiteral)TypedLiteral.newLiteral("foobar", URI.create("foo:bar"), null);
-    assertFalse(l.test(c));
+    try {
+      l.test(c);
+      fail("Got an EBV from an unknown literal type");
+    } catch (QueryException qe) {
+      assertTrue(qe.getMessage().startsWith("Type Error:"));
+    }
 
     l = (TypedLiteral)TypedLiteral.newLiteral(Long.valueOf(5));
     assertTrue(l.test(c));

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/ValueLiteral.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/ValueLiteral.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/ValueLiteral.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -25,7 +25,7 @@
  * @copyright &copy; 2008 <a href="http://www.topazproject.org/">The Topaz Project</a>
  * @licence <a href="{@docRoot}/../../LICENCE.txt">Open Software License v3.0</a>
  */
-public interface ValueLiteral extends RDFTerm, Filter {
+public interface ValueLiteral extends RDFTerm, Filter, ComparableExpression {
 
   /**
    * Returns the data represented by this expression.
@@ -51,6 +51,12 @@
    */
   public SimpleLiteral getLang() throws QueryException;
 
+  /**
+   * Tests if this literal is a simple literal. If it is, then the type should be xsd:string.
+   * @return <code>true</code> if this literal is simple.
+   * @throws QueryException Resolving the data for this value leads to an error.
+   */
+  public boolean isSimple() throws QueryException;
 
   /**
    * Gets the type of this literal
@@ -66,5 +72,5 @@
    * @throws QueryException There was an error during resolving the literal.
    */
   public boolean test(Context context) throws QueryException;
-
+  
 }

Modified: branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/Var.java
===================================================================
--- branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/Var.java	2008-04-16 19:55:04 UTC (rev 794)
+++ branches/mgr-61-sparql/src/jar/query/java/org/mulgara/query/filter/value/Var.java	2008-04-17 04:29:44 UTC (rev 795)
@@ -93,12 +93,18 @@
     return e.getValue().toString();
   }
 
+  /**@see org.mulgara.query.filter.value.ValueLiteral#getType() */
   public IRI getType() throws QueryException {
     ComparableExpression e = resolveComparable();
     if (!e.isLiteral()) throw new QueryException("Only literals are typed");
     return ((ValueLiteral)e).getType();
   }
 
+  /** @see org.mulgara.query.filter.value.ValueLiteral#isSimple() */
+  public boolean isSimple() throws QueryException {
+    return ((ValueLiteral)resolve()).isSimple();
+  }
+
   /** {@inheritDoc} */
   public boolean equals(RDFTerm v) throws QueryException {
     return resolve().equals(v);
@@ -136,7 +142,7 @@
    */
   public ComparableExpression resolveComparable() throws QueryException {
     RDFTerm v = resolve();
-    if (!(v instanceof ComparableExpression)) throw new QueryException("Cannot compare against a " + v.getClass().getSimpleName());
+    if (!(v instanceof ComparableExpression)) throw new QueryException("Type Error: Cannot compare against a: " + v.getClass().getSimpleName());
     return (ComparableExpression)v;
   }
 




More information about the Mulgara-svn mailing list