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

commit 8f265909ffe648808001b7117c1e6240415fd762
Author: Andy Seaborne <[email protected]>
AuthorDate: Wed Jan 7 15:15:32 2026 +0000

    Implement SameVALUE (ARQ keyword)
---
 .../org/apache/jena/sparql/expr/E_SameValue.java   | 25 ++++++++++++----
 .../org/apache/jena/sparql/expr/NodeValue.java     |  4 +--
 .../sparql/expr/TestSparqlKeywordFunctions.java    | 34 +++++++++++++++++-----
 3 files changed, 48 insertions(+), 15 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 231760e9ce..30f7530643 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,7 +18,6 @@
 
 package org.apache.jena.sparql.expr;
 
-import org.apache.jena.sparql.ARQNotImplemented;
 import org.apache.jena.sparql.sse.Tags;
 
 public class E_SameValue extends ExprFunction2 {
@@ -30,15 +29,29 @@ public class E_SameValue extends ExprFunction2 {
 
     @Override
     public NodeValue eval(NodeValue x, NodeValue y) {
-        throw new ARQNotImplemented("E_SameValue");
-        // "strict/plain" and "extended"
-// // EXCEPT NaN
-// boolean b = NodeValue.sameValueAs(x, y) ;
-// return NodeValue.booleanReturn(b) ;
+        if ( isNaN(x) ) {
+            if ( isNaN(y) )
+                return NodeValue.TRUE;
+            return NodeValue.FALSE;
+        }
+        boolean b = NodeValue.sameValueAs(x, y) ;
+        return NodeValue.booleanReturn(b) ;
     }
 
     @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/NodeValue.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java
index e127b4aaf0..f7e417ce2f 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/NodeValue.java
@@ -401,8 +401,8 @@ public abstract class NodeValue extends ExprNode
     // Every langtag implies another value space as well.
 
     /**
-     * Return true if the two NodeValues are known to be the same value return 
false
-     * if known to be different values, throw ExprEvalException otherwise
+     * Return true if the two NodeValues are known to be the same value. 
Return false
+     * if known to be different values, else throw ExprEvalException
      */
     public static boolean sameValueAs(NodeValue nv1, NodeValue nv2) {
         return NVCompare.sameValueAs(nv1, nv2);
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
index b4b06b6362..25f2e6150d 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
@@ -84,7 +84,7 @@ public class TestSparqlKeywordFunctions
     | 'NOW' NIL
     | 'MD5' '(' Expression ')'
     | 'SHA1' '(' Expression ')'
-    | SHA224 '(' Expression ')'
+    | 'SHA224' '(' Expression ')'
     | 'SHA256' '(' Expression ')'
     | 'SHA384' '(' Expression ')'
     | 'SHA512' '(' Expression ')'
@@ -409,12 +409,32 @@ public class TestSparqlKeywordFunctions
     @Test public void replace30()       { test("REPLACE('b'@en--ltr, '(a|b)?', 
'Z')", "'Z'@en--ltr"); }
     @Test public void replace31()       { test("REPLACE('b'@en--ltr, '(a|b)?', 
'Z'@en--ltr)", "'Z'@en--ltr"); }
 
-    @Test public void sameTerm1()       { test("sameTerm(1,1)",           
kwTRUE); }
-    @Test public void sameTerm2()       { test("sameTerm(1,1.0)",         
kwFALSE); }
-    @Test public void sameTerm3()       { test("sameTerm(1,1e0)",         
kwFALSE); }
-    @Test public void sameTerm4()       { test("sameTerm(<_:a>, <_:a>)",  
kwTRUE); }
-    @Test public void sameTerm5()       { test("sameTerm(<x>, <x>)",      
kwTRUE); }
-    @Test public void sameTerm6()       { test("sameTerm(<x>, <y>)",      
kwFALSE); }
+    @Test public void sameTerm_01()     { test("sameTerm(1,1)",           
kwTRUE); }
+    @Test public void sameTerm_02()     { test("sameTerm(1,1.0)",         
kwFALSE); }
+    @Test public void sameTerm_03()     { test("sameTerm(1,1e0)",         
kwFALSE); }
+    @Test public void sameTerm_04()     { test("sameTerm(<_:a>, <_:a>)",  
kwTRUE); }
+    @Test public void sameTerm_05()     { test("sameTerm(<x>, <x>)",      
kwTRUE); }
+    @Test public void sameTerm_06()     { test("sameTerm(<x>, <y>)",      
kwFALSE); }
+
+    @Test public void sameTerm_07()     { test("sameTerm('abc'@en, 'abc'@EN)", 
kwTRUE); }
+    @Test public void sameTerm_08()     { test("sameTerm('abc'@en--ltr, 
'abc'@EN--ltr)", kwTRUE); }
+    @Test public void sameTerm_09()     { test("sameTerm('abc'@en--ltr, 
'abc'@en--rtl)", kwFALSE); }
+    @Test public void sameTerm_10()     { test("sameTerm(<<( <x> <p> 123 )>>, 
<<( <x> <p> 123 )>>)", kwTRUE); }
+
+    // 'SameValue' is not in SPARQL 1.2 as a keyword.
+    // However, ARQ provides access to the function.
+
+    @Test public void sameValue_01()    { test("sameValue(<x>, <x>)",      
kwTRUE); }
+    @Test public void sameValue_02()    { test("sameValue(<x>, <y>)",      
kwFALSE); }
+    @Test public void sameValue_03()    { test("sameValue(1, 1.0e0)",      
kwTRUE); }
+    @Test public void sameValue_04()    { test("sameValue('NaN'^^xsd:double, 
'NaN'^^xsd:double)",     kwTRUE); }
+    @Test public void sameValue_05()    { test("sameValue('NaN'^^xsd:float, 
'NaN'^^xsd:double)",      kwTRUE); }
+    @Test public void sameValue_06()    { test("sameValue('NaN'^^xsd:double, 
'NaN'^^xsd:float)",      kwTRUE); }
+    @Test public void sameValue_07()    { test("sameValue('NaN'^^xsd:float, 
'NaN'^^xsd:float)",       kwTRUE); }
+    @Test public void sameValue_08()    { test("sameValue('NaN'^^xsd:float, 
'INF'^^xsd:float)",       kwFALSE); }
+    @Test public void sameValue_09()    { test("sameValue(<<( <x> <p> 123 )>>, 
<<( <x> <p> 123.0e0 )>>)", kwTRUE); }
+    @Test public void sameValue_10()    { test("sameValue(<<( <x> <p> 'abc'@en 
)>>, <<( <x> <p> 'abc'@en--ltr )>>)", kwFALSE); }
+    @Test public void sameValue_11()    { test("sameValue(<<( <x> <p> 
'abc'@en--ltr )>>, <<( <x> <p> 'abc'@en--rtl )>>)", kwFALSE); }
 
     @Test public void OneOf_01()        { test("57 in (xsd:integer, '123')",   
kwFALSE); }
     @Test public void OneOf_02()        { test("57 in (57)",                   
kwTRUE); }

Reply via email to