shawnsmith opened a new issue, #2650: URL: https://github.com/apache/jena/issues/2650
### Version 5.1.0 ### What happened? https://github.com/apache/jena/issues/2028 deprecated `QueryExecutionDatasetBuilder.initialBinding()` and https://github.com/apache/jena/issues/2435 deprecated it for removal. But the `substitution()` method isn't a perfect replacement for `initialBinding()`. I ran across an edge case where `initialBinding()` appears to work correctly but `substitution()` does not: Substitute `?a <- 123` in this query: ```sparql PREFIX : <https://example.com/> SELECT (SUM(?a + ?b) AS ?c) WHERE { ?s :p ?a ; :q ?b . } ``` and you get this, where `?a` in the aggregation expression is not defined: ```sparql PREFIX : <https://example.com/> SELECT (SUM(( ?a + ?b )) AS ?c) WHERE { ?s :p 123 ; :q ?b } ``` It looks like `substitution()` doesn't replace variable references in aggregation expressions. I don't know if that's a bug or intended. For now I'm sticking with `initialBinding()`, so I'm concerned that it's marked for removal. ### Relevant output and stacktrace ```shell package jena_test; import org.apache.jena.datatypes.xsd.XSDDatatype; import org.apache.jena.graph.Graph; import org.apache.jena.graph.Node; import org.apache.jena.query.Query; import org.apache.jena.query.QueryFactory; import org.apache.jena.riot.Lang; import org.apache.jena.sparql.core.Var; import org.apache.jena.sparql.engine.binding.Binding; import org.apache.jena.sparql.engine.binding.BindingBuilder; import org.apache.jena.sparql.exec.QueryExec; import org.apache.jena.sparql.graph.GraphFactory; import org.apache.jena.sparql.resultset.ResultsWriter; import org.apache.jena.sparql.syntax.syntaxtransform.QueryTransformOps; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; import java.util.Map; import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.jena.graph.NodeFactory.createLiteralByValue; import static org.apache.jena.graph.NodeFactory.createURI; import static org.junit.jupiter.api.Assertions.assertEquals; class AggregationSubstitutionTest { @Test void testSubstitution_Aggregation() { // Current versions of Jena strongly recommend using `QueryExecBuilder.substitution(Binding)` instead of // `QueryExecDatasetBuilder.initialBinding(Binding), even to the point of marking the `initialBinding()` // method deprecated. But the two methods aren't equivalent, as shown in the following query: String sparql = """ PREFIX : <https://example.com/> SELECT (SUM(?a + ?b) AS ?c) WHERE { ?s :p ?a ; :q ?b . } """; Map<Var, Node> params = Map.of( Var.alloc("d"), createURI("https://example.com/Bar"), Var.alloc("a"), createLiteralByValue(123, XSDDatatype.XSDinteger)); // Note: QueryExecDatasetBuilder.build() implements substitutionMap using QueryTransformOps.transform(). Query transformed = QueryTransformOps.transform(QueryFactory.create(sparql), params); // Note: substitution results in ?a being undefined in the SUM expression! assertEquals(""" PREFIX : <https://example.com/> SELECT (SUM(( ?a + ?b )) AS ?c) WHERE { ?s :p 123 ; :q ?b } """, transformed.toString()); QueryFactory.create(transformed.toString()); String ns = "https://example.com/"; Graph graph = GraphFactory.createDefaultGraph(); graph.add(createURI(ns + "Bar"), createURI(ns + "p"), createLiteralByValue(123, XSDDatatype.XSDinteger)); graph.add(createURI(ns + "Bar"), createURI(ns + "q"), createLiteralByValue(456, XSDDatatype.XSDinteger)); run(sparql, graph, params); } private static void run(String sparql, Graph graph, Map<Var, Node> params) { BindingBuilder builder = Binding.builder(); params.forEach(builder::add); Binding binding = builder.build(); // Use substitution() ByteArrayOutputStream buf1 = new ByteArrayOutputStream(); try (QueryExec qe1 = QueryExec.graph(graph).query(sparql).substitution(binding).build()) { ResultsWriter.create().lang(Lang.CSV).write(buf1, qe1.select()); } String csv1 = buf1.toString(UTF_8); System.out.println("substitution:\n" + csv1.trim()); // Use initialBinding() ByteArrayOutputStream buf2 = new ByteArrayOutputStream(); try (QueryExec qe2 = QueryExec.newBuilder().graph(graph).query(sparql).initialBinding(binding).build()) { ResultsWriter.create().lang(Lang.CSV).write(buf2, qe2.select()); } String csv2 = buf2.toString(UTF_8); System.out.println("initialBinding:\n" + csv2.trim()); assertEquals(csv1, csv2, "Query results should be the same"); } } ``` ### Are you interested in making a pull request? None -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
