Skip to content

Commit

Permalink
apacheGH-2883: Fix for an NPE in OpAsQuery.
Browse files Browse the repository at this point in the history
  • Loading branch information
Aklakan committed Dec 11, 2024
1 parent 3d34ac9 commit 10a1360
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,25 @@ public static Query asQuery(Op op) {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

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;

Expand All @@ -43,7 +44,15 @@ public ExprTransformApplyElementTransform(ElementTransform transform, boolean al
@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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public static Query transform(Query query, ElementTransform transform, ExprTrans
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)
Expand Down Expand Up @@ -116,7 +116,7 @@ private static void setAggregators(Query newQuery, Query query, ExprTransform ex
}

// 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 :
Expand All @@ -125,7 +125,7 @@ private static void mutateByQueryType(Query q2, ElementTransform transform, Expr
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);
Expand All @@ -145,7 +145,8 @@ private static void mutateByQueryType(Query q2, ElementTransform transform, Expr
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");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,11 @@ public void testSubQuery3() {
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)
Expand Down Expand Up @@ -482,6 +487,83 @@ public void testMinus02() {
"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); }
Expand All @@ -503,8 +585,6 @@ public void testMinus02() {
"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 { } }" ;
Expand Down Expand Up @@ -603,6 +683,12 @@ private static void test_roundTripQuery(String query, String outcome) {
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);
Expand Down

0 comments on commit 10a1360

Please sign in to comment.