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); + } }
