This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new 377f9ad7fc Move SPARQL SameValue function to NodeFunctions
377f9ad7fc is described below
commit 377f9ad7fcbfd959efe9600b2a95b124258fd8c5
Author: Andy Seaborne <[email protected]>
AuthorDate: Sat Jan 10 14:36:11 2026 +0000
Move SPARQL SameValue function to NodeFunctions
---
.../org/apache/jena/sparql/expr/E_SameValue.java | 22 +----
.../org/apache/jena/sparql/expr/NVCompare.java | 17 +++-
.../jena/sparql/expr/nodevalue/NodeFunctions.java | 84 +++++++++++++++---
.../java/org/apache/jena/sparql/expr/TS_Expr.java | 3 +-
.../apache/jena/sparql/expr/TestNodeFunctions.java | 69 ---------------
.../jena/sparql/expr/TestNodeFunctionsMisc.java | 99 ++++++++++++++++++++++
...ctions.java => TestSPARQLKeywordFunctions.java} | 2 +-
7 files changed, 189 insertions(+), 107 deletions(-)
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_SameValue.java
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_SameValue.java
index 30f7530643..2739a273e7 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_SameValue.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_SameValue.java
@@ -18,6 +18,7 @@
package org.apache.jena.sparql.expr;
+import org.apache.jena.sparql.expr.nodevalue.NodeFunctions;
import org.apache.jena.sparql.sse.Tags;
public class E_SameValue extends ExprFunction2 {
@@ -29,29 +30,12 @@ public class E_SameValue extends ExprFunction2 {
@Override
public NodeValue eval(NodeValue x, NodeValue y) {
- if ( isNaN(x) ) {
- if ( isNaN(y) )
- return NodeValue.TRUE;
- return NodeValue.FALSE;
- }
- boolean b = NodeValue.sameValueAs(x, y) ;
- return NodeValue.booleanReturn(b) ;
+ return NodeFunctions.sameValueFunction(x, y);
}
+
@Override
public Expr copy(Expr e1, Expr e2) {
return new E_SameValue(e1, e2);
}
-
- private static boolean isNaN(NodeValue nv) {
- if ( nv.isDouble() ) {
- double d = nv.getDouble();
- return Double.isNaN(d);
- }
- if ( nv.isFloat() ) {
- float f = nv.getFloat();
- return Float.isNaN(f);
- }
- return false;
- }
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVCompare.java
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVCompare.java
index 16fc63d397..ea36410d26 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVCompare.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NVCompare.java
@@ -114,8 +114,8 @@ class NVCompare {
Node node2 = nv2.asNode();
if ( !SystemARQ.ValueExtensions )
- // No value extensions => raw rdfTermEquals
- return NodeFunctions.rdfTermEquals(node1, node2);
+ // No value extensions => raw SameValue, value testing
done.
+ raise(new ExprEvalException("Unknown equality test: " +
nv1 + " and " + nv2));
// Some "value spaces" are know to be not equal (no overlap).
// Like one literal with a language tag, and one without can't
be
@@ -127,12 +127,21 @@ class NVCompare {
return false;
// Two literals at this point.
+ // Any known to be disjoint value spaces.
if ( NodeFunctions.sameTerm(node1, node2) )
return true;
- if ( !node1.getLiteralLanguage().equals("") ||
!node2.getLiteralLanguage().equals("") )
- // One had lang tag but weren't sameNode => not equals
+ boolean hasLang1 = NodeFunctions.hasLang(node1);
+ boolean hasLang2 = NodeFunctions.hasLang(node2);
+ if ( hasLang1 != hasLang2 )
+ // One had lang tag, one doeesn't
+ return false;
+
+ boolean hasLangDir1 = NodeFunctions.hasLangDir(node1);
+ boolean hasLangDir2 = NodeFunctions.hasLangDir(node2);
+ if ( hasLangDir1 != hasLangDir2 )
+ // One had lang direction, one doesn't
return false;
raise(new ExprEvalException("Unknown equality test: " + nv1 +
" and " + nv2));
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java
index b1592ce414..c795cafb3d 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java
@@ -59,15 +59,15 @@ public class NodeFunctions {
return NodeValue.booleanReturn(sameTerm(nv1.asNode(), nv2.asNode()));
}
- // Jena - up to Jena 4.
- // Language tags were kept in the case form they were given as.
- // Jena5 - language tags are canonicalised.
-
/** sameTerm(x,y) */
public static boolean sameTerm(Node node1, Node node2) {
return node1.sameTermAs(node2);
}
+ // Jena - up to Jena 4.
+ // Language tags were kept in the case form they were given as.
+ // Jena5 - language tags are canonicalised.
+
// Before jena stored normalized language tags ...
// /** sameTerm(x,y) */
// public static boolean sameTerm(Node node1, Node node2) {
@@ -94,44 +94,102 @@ public class NodeFunctions {
// -------- sameValue
+ /** sameValue as equality */
public static boolean sameValue(NodeValue nv1, NodeValue nv2) {
return NodeValue.sameValueAs(nv1, nv2);
}
+ /** sameValue as equality */
public static boolean sameValue(Node node1, Node node2) {
NodeValue nv1 = NodeValue.makeNode(node1);
NodeValue nv2 = NodeValue.makeNode(node2);
return NodeValue.sameValueAs(nv1, nv2);
}
+ /** notSameValue as "not value-equals" */
public static boolean notSameValue(NodeValue nv1, NodeValue nv2) {
return NodeValue.notSameValueAs(nv1, nv2);
}
+ /** notSameValue as "not value-equals" */
public static boolean notSameValue(Node node1, Node node2) {
NodeValue nv1 = NodeValue.makeNode(node1);
NodeValue nv2 = NodeValue.makeNode(node2);
return NodeValue.notSameValueAs(nv1, nv2);
}
- // -------- RDFterm-equals -- raises an exception on "don't know" for
literals.
+ /**
+ * The sameValue function in SPARQL.
+ * NaN's do not follow value-equality.
+ */
+ public static NodeValue sameValueFunction(NodeValue x, NodeValue y) {
+ // Case: sameValue("NaN"^^xsd:double, "NaN"^^xsd:float) = true
+ if ( isNaN(x) )
+ return NodeValue.booleanReturn(isNaN(y));
+ else {
+ if ( isNaN(y) )
+ // x is not NaN
+ return NodeValue.FALSE;
+ }
+
+ // Case: sameValue("NaN"^^xsd:double, "NaN"^^xsd:float) = false
+ if ( false ) {
+ if ( isDoubleNaN(x) )
+ return NodeValue.booleanReturn(isDoubleNaN(y));
+ if ( isFloatNaN(x) )
+ return NodeValue.booleanReturn(isFloatNaN(y));
+ if ( isNaN(y) )
+ // x is not NaN
+ return NodeValue.FALSE;
+ }
+
+ boolean b = NodeValue.sameValueAs(x, y) ;
+ return NodeValue.booleanReturn(b) ;
+ }
+
+ /** Test whether the argument is a NaN, either as a double or as a float.
*/
+ public static boolean isNaN(NodeValue nv) {
+ return isDoubleNaN(nv) || isFloatNaN(nv);
+ }
+
+ /** Test whether the argument is NaN as a double : "NaN"^^xsd:double. */
+ public static boolean isDoubleNaN(NodeValue nv) {
+ if ( nv.isDouble() ) {
+ double d = nv.getDouble();
+ return Double.isNaN(d);
+ }
+ return false;
+ }
+
+ /** Test whether the argument is NaN as a float : "NaN"^^xsd:float. */
+ public static boolean isFloatNaN(NodeValue nv) {
+ if ( nv.isFloat() ) {
+ float f = nv.getFloat();
+ return Float.isNaN(f);
+ }
+ return false;
+ }
+
- // Exact as defined by SPARQL spec, when there are no value extensions.
- // Exception for two literals that might be equal but we don't know
because of language tags.
+ // -------- RDFterm-equals -- raises an exception on "don't know" for
literals; no value extensions.
+ // Exact as defined by SPARQL 1.1 spec, when there are no value extensions.
// THIS IS NOT:
- // SPARQL 1.1 = RDFterm-equals
// SPARQL 1.2 = sameValue
- public static boolean rdfTermEquals(Node n1, Node n2) {
+ // Legacy
+ @Deprecated(forRemoval = true)
+ public static boolean rdfTermEqual11_legacy(Node n1, Node n2) {
if ( n1.equals(n2) )
return true;
if ( n1.isLiteral() && n2.isLiteral() ) {
+ // Jena4.
// Two literals, may be sameTerm by language tag case
insensitivity.
String lang1 = n1.getLiteralLanguage();
String lang2 = n2.getLiteralLanguage();
if ( isNotEmpty(lang1) && isNotEmpty(lang2) ) {
+ // Jena4.
// Two language tags, both not "", equal by case insensitivity
=> lexical test.
if ( lang1.equalsIgnoreCase(lang2) ) {
boolean b =
n1.getLiteralLexicalForm().equals(n2.getLiteralLexicalForm());
@@ -141,7 +199,7 @@ public class NodeFunctions {
}
// Two literals:
- // Were not .equals
+ // They were not .equals
// case 1: At least one language tag., not same lexical form ->
unknown.
// case 2: No language tags, not .equals -> unknown.
// Raise error (rather than return false).
@@ -151,9 +209,9 @@ public class NodeFunctions {
if ( n1.isTripleTerm() && n2.isTripleTerm() ) {
Triple t1 = n1.getTriple();
Triple t2 = n2.getTriple();
- return rdfTermEquals(t1.getSubject(), t2.getSubject())
- && rdfTermEquals(t1.getPredicate(), t2.getPredicate())
- && rdfTermEquals(t1.getObject(), t2.getObject());
+ return rdfTermEqual11_legacy(t1.getSubject(), t2.getSubject())
+ && rdfTermEqual11_legacy(t1.getPredicate(), t2.getPredicate())
+ && rdfTermEqual11_legacy(t1.getObject(), t2.getObject());
}
// Not both literal nor both triple terms - .equals would have worked.
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TS_Expr.java
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TS_Expr.java
index 1ef5eb3696..309a26e83d 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TS_Expr.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TS_Expr.java
@@ -35,10 +35,11 @@ import
org.apache.jena.sparql.expr.nodevalue.TestNodeValueSortKey;
, TestExpressions4.class
, TestCastXSD.class
, TestNodeFunctions.class
+ , TestNodeFunctionsMisc.class
, TestExpressionsMath.class
, TestFunctions.class
, TestStringArgCompatibility.class
- , TestSparqlKeywordFunctions.class
+ , TestSPARQLKeywordFunctions.class
, TestFunctionsByURI.class
, TestExprTripleTerms.class
, TestLeviathanFunctions.class
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java
index cc3ee94148..449071e7f1 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java
@@ -29,7 +29,6 @@ import org.apache.jena.graph.TextDirection;
import org.apache.jena.query.ARQ;
import org.apache.jena.sparql.expr.nodevalue.NodeFunctions;
import org.apache.jena.sparql.graph.NodeConst;
-import org.apache.jena.sparql.sse.SSE;
import org.apache.jena.vocabulary.XSD;
public class TestNodeFunctions {
@@ -72,74 +71,6 @@ public class TestNodeFunctions {
assertTrue(NodeFunctions.sameTerm(n1, n2));
}
- @Test public void testRDFtermEquals1() {
- Node n1 = NodeFactory.createURI("xyz");
- Node n2 = NodeFactory.createLiteralString("xyz");
- assertFalse(NodeFunctions.rdfTermEquals(n1, n2));
- }
-
- @Test public void testRDFtermEquals2() {
- Node n1 = NodeFactory.createLiteralLang("xyz", "en");
- Node n2 = NodeFactory.createLiteralLang("xyz", "EN");
- assertTrue(NodeFunctions.rdfTermEquals(n1, n2));
- }
-
- @Test
- public void testRDFtermEquals3() {
- // Unextended - not known to be same (no language tag support).
- Node n1 = NodeFactory.createLiteralString("xyz");
- Node n2 = NodeFactory.createLiteralLang("xyz", "en");
- assertThrows(ExprEvalException.class,
- ()-> NodeFunctions.rdfTermEquals(n1, n2) );
- }
-
- @Test
- public void testRDFtermEquals4() {
- // Unextended - not known to be same.
- Node n1 = NodeFactory.createLiteralDT("123", XSDDatatype.XSDinteger);
- Node n2 = NodeFactory.createLiteralDT("456", XSDDatatype.XSDinteger);
- assertThrows(ExprEvalException.class,
- ()-> assertTrue(NodeFunctions.rdfTermEquals(n1, n2)) );
- }
-
- @Test
- public void testRDFtermEquals5() {
- Node n1 = SSE.parseNode("<<(:s :p 123)>>");
- Node n2 = SSE.parseNode("<<(:s :p 123)>>");
- assertTrue(NodeFunctions.rdfTermEquals(n1, n2));
- }
-
- @Test
- public void testRDFtermEquals6() {
- Node n1 = SSE.parseNode("<<(:s :p1 123)>>");
- Node n2 = SSE.parseNode("<<(:s :p2 123)>>");
- assertFalse(NodeFunctions.rdfTermEquals(n1, n2));
- }
-
- @Test
- public void testRDFtermEquals7() {
- Node n1 = SSE.parseNode("<<(:s :p <<(:a :b 'abc')>>)>>");
- Node n2 = SSE.parseNode("<<(:s :p <<(:a :b 123)>>)>>");
- assertThrows(ExprEvalException.class,
- ()-> NodeFunctions.rdfTermEquals(n1, n2) );
- }
-
- @Test
- public void testRDFtermEquals8() {
- Node n1 = SSE.parseNode("<<(:s :p 123)>>");
- Node n2 = SSE.parseNode("<<(:s :p 'xyz')>>");
- assertThrows(ExprEvalException.class,
- ()-> assertFalse(NodeFunctions.rdfTermEquals(n2, n1)) );
- }
-
- @Test
- public void testRDFtermEquals9() {
- Node n1 = SSE.parseNode("<<(:s :p 123)>>");
- Node n2 = SSE.parseNode("'xyz'");
- assertFalse(NodeFunctions.rdfTermEquals(n1, n2));
- assertFalse(NodeFunctions.rdfTermEquals(n2, n1));
- }
-
@Test public void testStr1() {
NodeValue nv = NodeValue.makeNodeInteger(56);
NodeValue s = NodeFunctions.str(nv);
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctionsMisc.java
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctionsMisc.java
new file mode 100644
index 0000000000..80465d7a88
--- /dev/null
+++
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctionsMisc.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.apache.jena.sparql.expr;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import org.apache.jena.datatypes.xsd.XSDDatatype;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.nodevalue.NodeFunctions;
+import org.apache.jena.sparql.sse.SSE;
+
+/**
+ * Tests for "RDFterm-equal" - fallback function for testing for the
'='operator.
+ * Extended for triple terms.
+ * Replaced in SPARQL 1.2 by sameValue.
+ */
+@SuppressWarnings("removal")
+public class TestNodeFunctionsMisc {
+ @Test public void testRDFtermEquals1() {
+ Node n1 = NodeFactory.createURI("xyz");
+ Node n2 = NodeFactory.createLiteralString("xyz");
+ assertFalse(NodeFunctions.rdfTermEqual11_legacy(n1, n2));
+ }
+
+ @Test public void testRDFtermEquals2() {
+ Node n1 = NodeFactory.createLiteralLang("xyz", "en");
+ Node n2 = NodeFactory.createLiteralLang("xyz", "EN");
+ assertTrue(NodeFunctions.rdfTermEqual11_legacy(n1, n2));
+ }
+
+ @Test public void testRDFtermEquals3() {
+ // Unextended - not known to be same (no language tag support).
+ Node n1 = NodeFactory.createLiteralString("xyz");
+ Node n2 = NodeFactory.createLiteralLang("xyz", "en");
+ assertThrows(ExprEvalException.class, ()->
NodeFunctions.rdfTermEqual11_legacy(n1, n2) );
+ }
+
+ @Test public void testRDFtermEquals4() {
+ // Unextended - not known to be same.
+ Node n1 = NodeFactory.createLiteralDT("123", XSDDatatype.XSDinteger);
+ Node n2 = NodeFactory.createLiteralDT("456", XSDDatatype.XSDinteger);
+ assertThrows(ExprEvalException.class, ()->
assertTrue(NodeFunctions.rdfTermEqual11_legacy(n1, n2)) );
+ }
+
+ @Test public void testRDFtermEquals5() {
+ Node n1 = SSE.parseNode("<<(:s :p 123)>>");
+ Node n2 = SSE.parseNode("<<(:s :p 123)>>");
+ assertTrue(NodeFunctions.rdfTermEqual11_legacy(n1, n2));
+ }
+
+ @Test public void testRDFtermEquals6() {
+ Node n1 = SSE.parseNode("<<(:s :p1 123)>>");
+ Node n2 = SSE.parseNode("<<(:s :p2 123)>>");
+ assertFalse(NodeFunctions.rdfTermEqual11_legacy(n1, n2));
+ }
+
+ @Test public void testRDFtermEquals7() {
+ Node n1 = SSE.parseNode("<<(:s :p <<(:a :b 'abc')>>)>>");
+ Node n2 = SSE.parseNode("<<(:s :p <<(:a :b 123)>>)>>");
+ assertThrows(ExprEvalException.class, ()->
NodeFunctions.rdfTermEqual11_legacy(n1, n2) );
+ }
+
+ @Test public void testRDFtermEquals8() {
+ Node n1 = SSE.parseNode("<<(:s :p 123)>>");
+ Node n2 = SSE.parseNode("<<(:s :p 'xyz')>>");
+ assertThrows(ExprEvalException.class, ()->
assertFalse(NodeFunctions.rdfTermEqual11_legacy(n2, n1)) );
+ }
+
+ @Test public void testRDFtermEquals9() {
+ Node n1 = SSE.parseNode("<<(:s :p 123)>>");
+ Node n2 = SSE.parseNode("'xyz'");
+ assertFalse(NodeFunctions.rdfTermEqual11_legacy(n1, n2));
+ assertFalse(NodeFunctions.rdfTermEqual11_legacy(n2, n1));
+ }
+}
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestSparqlKeywordFunctions.java
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestSPARQLKeywordFunctions.java
similarity index 99%
rename from
jena-arq/src/test/java/org/apache/jena/sparql/expr/TestSparqlKeywordFunctions.java
rename to
jena-arq/src/test/java/org/apache/jena/sparql/expr/TestSPARQLKeywordFunctions.java
index 25f2e6150d..177c4e54da 100644
---
a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestSparqlKeywordFunctions.java
+++
b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestSPARQLKeywordFunctions.java
@@ -36,7 +36,7 @@ import org.apache.jena.sparql.util.ExprUtils;
import org.apache.jena.sparql.util.NodeFactoryExtra;
import org.apache.jena.sys.JenaSystem;
-public class TestSparqlKeywordFunctions
+public class TestSPARQLKeywordFunctions
{
static { JenaSystem.init(); }
// Some overlap with TestFunctions except those are direct function calls
and these are via SPARQL 1.1 syntax.