Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,36 @@ public TupleExpr visit(ASTPathSequence pathSeqNode, Object data) throws VisitorE
subjVar = mapValueExprToVar(data);
}

List<ValueExpr> objectList = null;
if (!(data instanceof PathSequenceContext)) {
ASTObjectList objectListNode = getObjectList(pathSeqNode);
if (objectListNode != null) {
@SuppressWarnings("unchecked")
List<ValueExpr> evaluatedObjectList = (List<ValueExpr>) objectListNode.jjtAccept(this, null);
objectList = evaluatedObjectList;

if (objectList.size() > 1) {
TupleExpr result = null;
for (ValueExpr objectItem : objectList) {
PathSequenceContext objectContext = new PathSequenceContext();
objectContext.scope = graphPattern.getStatementPatternScope();
objectContext.contextVar = graphPattern.getContextVar();
objectContext.startVar = subjVar;
objectContext.endVar = mapValueExprToVar(objectItem);

TupleExpr pathExpr = (TupleExpr) pathSeqNode.jjtAccept(this, objectContext);

if (result == null) {
result = pathExpr;
} else {
result = new Join(result, pathExpr);
}
}
return result;
}
}
}

List<ASTPathElt> pathElements = pathSeqNode.getPathElements();
int pathLength = pathElements.size();

Expand All @@ -1470,10 +1500,15 @@ public TupleExpr visit(ASTPathSequence pathSeqNode, Object data) throws VisitorE

// We handle this here instead of higher up in the tree visitor because here we have
// a reference to the "temporary" endVar that needs to be replaced.
@SuppressWarnings("unchecked")
List<ValueExpr> objectList = (List<ValueExpr>) getObjectList(pathSeqNode).jjtAccept(this, null);
List<ValueExpr> finalObjectList = objectList;
if (finalObjectList == null) {
@SuppressWarnings("unchecked")
List<ValueExpr> evaluatedObjectList = (List<ValueExpr>) getObjectList(pathSeqNode)
.jjtAccept(this, null);
finalObjectList = evaluatedObjectList;
}

for (ValueExpr objectItem : objectList) {
for (ValueExpr objectItem : finalObjectList) {
Var objectVar = mapValueExprToVar(objectItem);
Var replacement = objectVar;
if (objectVar.equals(subjVar)) { // corner case for cyclic expressions, see SES-1685
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@
*******************************************************************************/
package org.eclipse.rdf4j.query.parser.sparql;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.eclipse.rdf4j.query.algebra.ArbitraryLengthPath;
import org.eclipse.rdf4j.query.algebra.Distinct;
import org.eclipse.rdf4j.query.algebra.Join;
Expand All @@ -22,6 +27,7 @@
import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.Union;
import org.eclipse.rdf4j.query.algebra.ZeroLengthPath;
import org.eclipse.rdf4j.query.algebra.helpers.collectors.StatementPatternCollector;
import org.eclipse.rdf4j.query.parser.ParsedQuery;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
Expand Down Expand Up @@ -109,4 +115,30 @@ public void testGH3053() {
"expect Union Right arg to be StatementPattern");
assertTrue(!proj2.isSubquery(), "expect projection to do NOT be a subQuery");
}

@Test
public void testGH3220() {
String query = "select * where { ?i <urn:prop1> / <urn:prop2> ?v1, ?v2 . }";
ParsedQuery parsedQuery = parser.parseQuery(query, "http://example.org/");

assertNotNull(parsedQuery);

List<StatementPattern> statementPatterns = StatementPatternCollector
.process(parsedQuery.getTupleExpr());

List<StatementPattern> prop1Patterns = statementPatterns.stream()
.filter(sp -> sp.getPredicateVar().hasValue()
&& "urn:prop1".equals(sp.getPredicateVar().getValue().stringValue()))
.collect(Collectors.toList());

assertEquals(2, prop1Patterns.size(),
"expected each object list entry to yield its own statement pattern for the first path element");

Set<String> intermediateVarNames = prop1Patterns.stream()
.map(sp -> sp.getObjectVar().getName())
.collect(Collectors.toSet());

assertEquals(2, intermediateVarNames.size(),
"expected unique intermediate variable per object list entry for the first path element");
}
}
Loading