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 6f9acae1ccd8342e4e9dea93e544556e8788b152
Author: Claus Stadler <[email protected]>
AuthorDate: Fri Aug 29 18:55:51 2025 +0200

    GH-3404: Canonicalize decimals during inlining for TDB2.
---
 .../org/apache/jena/sparql/util/XSDNumUtils.java   | 12 ++++
 .../org/apache/jena/tdb2/store/NodeIdInline.java   |  1 +
 .../jena/tdb2/store/value/TestNodeIdInline.java    | 67 +++++++++++++++++++---
 3 files changed, 72 insertions(+), 8 deletions(-)

diff --git 
a/jena-arq/src/main/java/org/apache/jena/sparql/util/XSDNumUtils.java 
b/jena-arq/src/main/java/org/apache/jena/sparql/util/XSDNumUtils.java
index c6bfe286b1..389fa11135 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/util/XSDNumUtils.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/util/XSDNumUtils.java
@@ -164,6 +164,18 @@ public class XSDNumUtils {
         return bd.stripTrailingZeros().toPlainString();
     }
 
+    /** Return a canonical decimal with a trailing ".0". */
+    public static BigDecimal canonicalDecimalWithDot(BigDecimal decimal) {
+        BigDecimal result = decimal;
+        if (result.scale() > 1) {
+            result = decimal.stripTrailingZeros();
+        }
+        if (result.scale() <= 0) {
+            result = result.setScale(1);
+        }
+        return result;
+    }
+
     /**
      * Integer-valued decimals have a trailing ".0".
      * (In XML Schema Datatype 1.1 they did not have a ".0".)
diff --git 
a/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/NodeIdInline.java 
b/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/NodeIdInline.java
index f13cc1f067..f28da5354c 100644
--- a/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/NodeIdInline.java
+++ b/jena-tdb2/src/main/java/org/apache/jena/tdb2/store/NodeIdInline.java
@@ -163,6 +163,7 @@ public class NodeIdInline {
             // But at this point we know it's a valid literal so the excessive
             // chopping by .trim is safe.
             BigDecimal decimal = new BigDecimal(lit.getLexicalForm().trim());
+            decimal = XSDNumUtils.canonicalDecimalWithDot(decimal);
 
             // Does range checking.
             DecimalNode56 dn = DecimalNode56.valueOf(decimal);
diff --git 
a/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestNodeIdInline.java
 
b/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestNodeIdInline.java
index b5b0bc5f92..61792b0cc9 100644
--- 
a/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestNodeIdInline.java
+++ 
b/jena-tdb2/src/test/java/org/apache/jena/tdb2/store/value/TestNodeIdInline.java
@@ -91,35 +91,68 @@ public class TestNodeIdInline
     @Test public void nodeId_int_21()
     { testNoInline("'300'^^xsd:byte"); }
 
-    @Test public void nodeId_decimal_1()
+    @Test public void nodeId_decimal_01()
     { test("3.14", "3.14"); }
 
-    @Test public void nodeId_decimal_2()
+    @Test public void nodeId_decimal_02()
     { testNoInline("123456789.123456789"); }
 
     // Just this once, directly create the Node.
-    @Test public void nodeId_decimal_3()
+    @Test public void nodeId_decimal_03()
     { test("12.89", NodeFactory.createLiteralDT("12.89", 
XSDDatatype.XSDdecimal)); }
 
-    @Test public void nodeId_decimal_4()
+    @Test public void nodeId_decimal_04()
     { test("-1.0",  "-1.0"); }
 
     // This number has > 47 bits of value : 2412.80478192688
-    @Test public void nodeId_decimal_5()
+    @Test public void nodeId_decimal_05()
     { testNoInline("2412.80478192688"); }
 
     // This number has > 47 bits of value : -2412.80478192688
-    @Test public void nodeId_decimal_6()
+    @Test public void nodeId_decimal_06()
     { testNoInline("-2412.80478192688"); }
 
-    @Test public void nodeId_decimal_7()
+    @Test public void nodeId_decimal_07()
     { test("'0.00000001'^^xsd:decimal",
            NodeFactory.createLiteralDT("0.00000001", XSDDatatype.XSDdecimal));
     }
 
-    @Test public void nodeId_decimal_8()
+    @Test public void nodeId_decimal_08()
     { test("0.00000001", NodeFactory.createLiteralDT("0.00000001", 
XSDDatatype.XSDdecimal)); }
 
+    @Test public void nodeId_decimal_09()
+    { testNodeIdRoundtripDecimal("0"); }
+
+    @Test public void nodeId_decimal_10()
+    { testNodeIdRoundtripDecimal("-0"); }
+
+    @Test public void nodeId_decimal_11()
+    { testNodeIdRoundtripDecimal("0.0"); }
+
+    @Test public void nodeId_decimal_12()
+    { testNodeIdRoundtripDecimal("-0.0"); }
+
+    @Test public void nodeId_decimal_13()
+    { testNodeIdRoundtripDecimal(".0"); }
+
+    @Test public void nodeId_decimal_14()
+    { testNodeIdRoundtripDecimal("-.0"); }
+
+    @Test public void nodeId_decimal_15()
+    { testNodeIdRoundtripDecimal("18"); }
+
+    @Test public void nodeId_decimal_16()
+    { testNodeIdRoundtripDecimal("18."); }
+
+    @Test public void nodeId_decimal_17()
+    { testNodeIdRoundtripDecimal("18.0"); }
+
+    @Test public void nodeId_decimal_18()
+    { testNodeIdRoundtripDecimal("18.00"); }
+
+    @Test public void nodeId_decimal_19()
+    { testNodeIdRoundtripDecimal("18.000"); }
+
     @Test public void nodeId_dateTime_01()
     { test("'2008-04-28T15:36:15+01:00'^^xsd:dateTime"); }
 
@@ -306,4 +339,22 @@ public class TestNodeIdInline
         // Term equality.
         assertEquals(correct, n2, ()->"Not same term");
     }
+
+    private static void testNodeIdRoundtripDecimal(String decimalStr) {
+        Node node = NodeFactory.createLiteralDT(decimalStr, 
XSDDatatype.XSDdecimal);
+        testNodeIdRoundtrip(node);
+    }
+
+    /** For a Node n assert: nodeId(n) == nodeId(extract(nodeId(n)) */
+    private static void testNodeIdRoundtrip(Node node) {
+        NodeId nodeId = NodeId.inline(node);
+        testNodeIdRoundtrip(nodeId);
+    }
+
+    /** For a NodeId n assert: n == nodeId(extract(n)) */
+    private static void testNodeIdRoundtrip(NodeId expected) {
+        Node extractedNode = NodeId.extract(expected);
+        NodeId actual = NodeId.inline(extractedNode);
+        assertEquals(expected, actual);
+    }
 }

Reply via email to