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 89d9ee2c44 GH-2883: Fix for an NPE in OpAsQuery.
89d9ee2c44 is described below
commit 89d9ee2c445cc57944d50792017fa14f36e0d8ae
Author: Claus Stadler <[email protected]>
AuthorDate: Sun Dec 8 00:44:36 2024 +0100
GH-2883: Fix for an NPE in OpAsQuery.
---
.../org/apache/jena/sparql/algebra/OpAsQuery.java | 19 +++++
.../ExprTransformApplyElementTransform.java | 11 ++-
.../syntax/syntaxtransform/QueryTransformOps.java | 9 ++-
.../apache/jena/sparql/algebra/TestOpAsQuery.java | 90 +++++++++++++++++++++-
4 files changed, 122 insertions(+), 7 deletions(-)
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/OpAsQuery.java
b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/OpAsQuery.java
index 594139040c..9be1eb36ab 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/OpAsQuery.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/OpAsQuery.java
@@ -81,6 +81,25 @@ public class OpAsQuery {
return converter.convert() ;
}
+ public static Element asElement(Op op) {
+ Query query = asQuery(op);
+ Element elt = isPrimitiveQuery(query)
+ ? query.getQueryPattern()
+ : new ElementSubQuery(query);
+ return elt;
+ }
+
+ /** Whether the query is a plain <code>SELECT * { pattern }</code>. */
+ private static boolean isPrimitiveQuery(Query query) {
+ boolean isNonPrimitive =
+ !query.isQueryResultStar() || query.isDistinct() ||
query.isReduced() ||
+ query.hasLimit() || query.hasOffset() ||
+ query.hasAggregators() || query.hasGroupBy() || query.hasHaving()
||
+ query.hasOrderBy() ||
+ query.hasValues();
+ return !isNonPrimitive;
+ }
+
static class /* struct */ QueryLevelDetails {
// The stack of processing in a query is:
// slice-distinct/reduce-project-order-filter[having]-extend*[AS and
aggregate naming]-group-pattern
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/ExprTransformApplyElementTransform.java
b/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/ExprTransformApplyElementTransform.java
index 9e4e3f5806..698f04492e 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/ExprTransformApplyElementTransform.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/ExprTransformApplyElementTransform.java
@@ -20,6 +20,7 @@ package org.apache.jena.sparql.syntax.syntaxtransform;
import org.apache.jena.sparql.ARQInternalErrorException;
import org.apache.jena.sparql.algebra.Op;
+import org.apache.jena.sparql.algebra.OpAsQuery;
import org.apache.jena.sparql.expr.*;
import org.apache.jena.sparql.syntax.Element;
@@ -43,7 +44,15 @@ public class ExprTransformApplyElementTransform extends
ExprTransformCopy
@Override
public Expr transform(ExprFunctionOp funcOp, ExprList args, Op opArg)
{
- Element el2 = ElementTransformer.transform(funcOp.getElement(),
transform);
+ // If the element is null then an attempt is made to obtain it from
the algebra.
+ // A given element takes precedence over the algebra.
+ Element el1 = funcOp.getElement();
+ if (el1 == null) {
+ Op op = funcOp.getGraphPattern();
+ el1 = op == null ? null : OpAsQuery.asElement(op);
+ }
+ // ElementTransformer will warn should it happen that null is passed
to it.
+ Element el2 = ElementTransformer.transform(el1, transform, this);
if ( el2 == funcOp.getElement() )
return super.transform(funcOp, args, opArg);
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/QueryTransformOps.java
b/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/QueryTransformOps.java
index 313f75245b..b4f987a3bf 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/QueryTransformOps.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/QueryTransformOps.java
@@ -69,7 +69,7 @@ public class QueryTransformOps {
Query q2 = QueryTransformOps.shallowCopy(query);
// Mutate the q2 structures which are already allocated and no other
code can access yet.
- mutateByQueryType(q2, transform, exprTransform);
+ mutateByQueryType(q2, exprTransform);
mutateVarExprList(q2.getGroupBy(), exprTransform);
mutateExprList(q2.getHavingExprs(), exprTransform);
if (q2.getOrderBy() != null)
@@ -116,7 +116,7 @@ public class QueryTransformOps {
}
// Do the result form part of the cloned query.
- private static void mutateByQueryType(Query q2, ElementTransform
transform, ExprTransform exprTransform) {
+ private static void mutateByQueryType(Query q2, ExprTransform
exprTransform) {
switch(q2.queryType()) {
case ASK : break;
case CONSTRUCT :
@@ -125,7 +125,7 @@ public class QueryTransformOps {
Template template = q2.getConstructTemplate();
QuadAcc acc = new QuadAcc();
List<Quad> quads = template.getQuads();
- template.getQuads().forEach(q->{
+ quads.forEach(q->{
Node g = transform(q.getGraph(), exprTransform);
Node s = transform(q.getSubject(), exprTransform);
Node p = transform(q.getPredicate(), exprTransform);
@@ -145,7 +145,8 @@ public class QueryTransformOps {
case CONSTRUCT_JSON :
throw new UnsupportedOperationException("Transform of JSON
template queries");
case UNKNOWN :
- throw new JenaException("Unknown qu ery type");
+ default :
+ throw new JenaException("Unknown query type");
}
}
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/algebra/TestOpAsQuery.java
b/jena-arq/src/test/java/org/apache/jena/sparql/algebra/TestOpAsQuery.java
index 3d91b293b9..af58d9c09d 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/algebra/TestOpAsQuery.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/algebra/TestOpAsQuery.java
@@ -329,6 +329,11 @@ public class TestOpAsQuery {
test_roundTripQuery(query) ;
}
+ @Test
+ public void testSubQuery4() {
+ test_roundTripQuery("SELECT ?z { SELECT ?x { } }");
+ }
+
@Test
public void testAggregatesInSubQuery1() {
//Simplified form of a test case provided via the mailing list
(JENA-445)
@@ -482,6 +487,83 @@ public class TestOpAsQuery {
"SELECT * { GRAPH
?g { { ?x ?y ?z FILTER(EXISTS { ?s ?p ?o }) } ?x ?y ?z } }",
syntaxARQ); }
+ @Test
+ public void testExists07a() {
+ String query = """
+ SELECT ?x {
+ ?x a ?y .
+ FILTER EXISTS { ?y a ?z }
+ }
+ """;
+ test_roundTripQuery(query);
+ }
+
+ @Test
+ public void testExists07b() {
+ String input = """
+ SELECT ?x {
+ ?x a ?y
+ FILTER EXISTS { SELECT * { ?y a ?z } }
+ }
+ """;
+ // Going through the algebra is expected to lose the SELECT * { } part
within EXISTS.
+ String expected = """
+ SELECT ?x {
+ ?x a ?y
+ FILTER EXISTS { ?y a ?z }
+ }
+ """;
+ test_roundTripQueryViaAlgebra(input, expected);
+ }
+
+ @Test
+ public void testExists08a() {
+ String input = """
+ SELECT * {
+ ?x a ?y
+ FILTER EXISTS { SELECT * { ?y a ?z } LIMIT 1 }
+ }
+ """;
+ test_roundTripQuery(input);
+ test_roundTripQueryViaAlgebra(input, input);
+ }
+
+ // Tests exists with a subquery within a subquery.
+ @Test
+ public void testExists09a() {
+ String input = """
+ SELECT ?x {
+ SELECT ?x {
+ ?x a ?y
+ FILTER EXISTS { SELECT * { ?y a ?z } }
+ }
+ }
+ """;
+ // Going through the algebra is expected to lose the SELECT * { } part
within EXISTS.
+ String expected = """
+ SELECT ?x {
+ SELECT ?x {
+ ?x a ?y
+ FILTER EXISTS { ?y a ?z }
+ }
+ }
+ """;
+ test_roundTripQueryViaAlgebra(input, expected);
+ }
+
+ @Test
+ public void testExists09b() {
+ String queryStr = """
+ SELECT ?x {
+ SELECT ?x {
+ ?x a ?y
+ FILTER EXISTS { SELECT * { ?y a ?z } LIMIT 1 }
+ }
+ }
+ """;
+ test_roundTripQuery(queryStr, Syntax.syntaxARQ);
+ }
+
@Test public void testNotExists01() { test_roundTripQuery("SELECT * { ?x
?y ?z NOT EXISTS { ?s ?p ?o } }",
"SELECT * { ?x ?y
?z FILTER NOT EXISTS { ?s ?p ?o } }",
syntaxARQ); }
@@ -503,8 +585,6 @@ public class TestOpAsQuery {
"SELECT * { GRAPH
?g { { ?x ?y ?z FILTER(NOT EXISTS { ?s ?p ?o }) } ?x ?y ?z } }",
syntaxARQ); }
-
-
@Test
public void testTable1() {
String query = "SELECT * WHERE { ?x ?p ?z . VALUES ?y { } }" ;
@@ -603,6 +683,12 @@ public class TestOpAsQuery {
test_roundTripQuery(query, outcome, Syntax.syntaxSPARQL_11);
}
+ /** query->algebra->OpAsQuery->assert equality with outcome */
+ private static void test_roundTripQueryViaAlgebra(String query, String
outcome) {
+ String opStr = Algebra.compile(QueryFactory.create(query)).toString();
+ test_AlgebraToQuery(opStr, outcome);
+ }
+
private static void test_roundTripQuery(String query, String outcome,
Syntax syntax) {
// This must also be true.
test_roundTripAlegbra(query, syntax);