Skip to content
Draft
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
@@ -0,0 +1,44 @@
/*******************************************************************************
* Copyright (c) 2025 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.query.algebra.evaluation.impl;

import org.eclipse.rdf4j.query.algebra.TupleExpr;
import org.eclipse.rdf4j.query.algebra.evaluation.optimizer.ParentReferenceChecker;
import org.eclipse.rdf4j.query.impl.EmptyBindingSet;
import org.eclipse.rdf4j.query.impl.SimpleDataset;
import org.eclipse.rdf4j.query.parser.sparql.SPARQLParser;
import org.junit.jupiter.api.Test;

/**
* Test to reproduce and fix the parent reference issue with aggregation queries.
*/
public class AggregationParentReferenceTest {

@Test
public void testAggregationParentReferences() {
String query = "SELECT (COUNT(?s) AS ?count) WHERE { ?s ?p ?o }";

TupleExpr expr = new SPARQLParser().parseQuery(query, null).getTupleExpr();

// This should not throw an AssertionError about parent references
new ParentReferenceChecker(null).optimize(expr, new SimpleDataset(), new EmptyBindingSet());
}

@Test
public void testComplexAggregationParentReferences() {
String query = "SELECT (COUNT(?s)/30 AS ?count) WHERE { ?s ?p ?o }";

TupleExpr expr = new SPARQLParser().parseQuery(query, null).getTupleExpr();

// This should not throw an AssertionError about parent references
new ParentReferenceChecker(null).optimize(expr, new SimpleDataset(), new EmptyBindingSet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -568,20 +568,27 @@ public TupleExpr visit(ASTSelect node, Object data) throws VisitorException {
}

if (operator.equals(valueExpr)) {
group.addGroupElement(new GroupElem(alias, operator));
// For simple aggregations like COUNT(?s), clone the operator to avoid
// parent reference conflicts when it's added to both GroupElem and ExtensionElem
group.addGroupElement(new GroupElem(alias, operator.clone()));
extension.setArg(group);
} else {
ValueExpr expr = (ValueExpr) operator.getParentNode();

Extension anonymousExtension = new Extension();
Var anonVar = createAnonVar();
expr.replaceChildNode(operator, anonVar);
anonymousExtension.addElement(new ExtensionElem(operator, anonVar.getName()));
// Clone the operator for the ExtensionElem to avoid parent reference conflicts
anonymousExtension.addElement(new ExtensionElem(operator.clone(), anonVar.getName()));

anonymousExtension.setArg(result);
result = anonymousExtension;
group.addGroupElement(new GroupElem(anonVar.getName(), operator));

// Update the group's argument to point to the new result structure
if (!isExistingGroup) {
group.setArg(result);
}
}

if (!isExistingGroup) {
Expand All @@ -593,7 +600,9 @@ public TupleExpr visit(ASTSelect node, Object data) throws VisitorException {
// SELECT expressions need to be captured as an extension, so that original and alias are
// available for the ORDER BY clause (which gets applied _before_ projection). See GH-4066
// and https://www.w3.org/TR/sparql11-query/#sparqlSolMod .
ExtensionElem extElem = new ExtensionElem(valueExpr, alias);
// Clone valueExpr if it contains aggregates to avoid parent reference conflicts
ValueExpr extValueExpr = !collector.getOperators().isEmpty() ? valueExpr.clone() : valueExpr;
ExtensionElem extElem = new ExtensionElem(extValueExpr, alias);
extension.addElement(extElem);
elem.setSourceExpression(extElem);
} else if (child instanceof ASTVar) {
Expand Down
Loading
Loading