Skip to content

Subquery with GROUP BY incorrectly propagates bindings — leads to inconsistent results #161

Description

@remiceres

Reported by: Olivier Corby

Description:
There is a bug in the Corese engine related to subqueries using GROUP BY variables combined with external bindings. Specifically, when a variable used in the GROUP BY clause is bound before the subquery, the query yields different results depending on the position of the triple pattern relative to the subquery.

🔍 Example

Query:

prefix ns: <http://ns.inria.fr/test/>

select * where {
  ?x ns:p ?y
  {
    select ?x (count(*) as ?c)
    where {
      ?x ns:q ?z
    } group by ?x
  }
}

Dataset:

prefix ns: <http://ns.inria.fr/test/>

ns:a ns:p ns:b .

ns:c ns:q ns:d .

If the triple ?x ns:p ?y is placed before the subquery block, the result differs from the case where it is placed after the subquery — although the SPARQL semantics dictate that the result should be the same.

Cause:
The issue lies in the propagation of bindings to subqueries using GROUP BY. Specifically, the variable used in the GROUP BY clause (?x in this case) should not be passed as a bound variable to the subquery, as this affects its internal grouping logic.

Proposed Fix:
In class fr.inria.corese.kgram.core.Exp, update the method queryNodeList(ExpHandler h) with the following code:

void queryNodeList(ExpHandler h) {
    List<Node> selectList    = h.getSelectNodeList();
    List<Node> subSelectList = getQuery().getSelect();

    if (h.isInSubScope()) {
        List<Node> scopeList = getQuery().getBody().getTheNodes(h.copy());
        for (Node node : scopeList) {
            if (subSelectList.contains(node)) {
                if (!contain(getQuery().getGroupBy(), node)) {
                    add(selectList, node);
                }
            }
        }
    } else {
        for (Node node : subSelectList) {
            if (!contain(getQuery().getGroupBy(), node)) {
                add(selectList, node);
            }
        }
    }
}

Trade-off:
This change may cause a minor performance degradation, as group-by variables are no longer optimized via direct binding injection. However, it ensures correctness and prevents logically inconsistent results.

⚠️ Regression warning:
After applying this fix, TestQuery1 > testLetQuery() fails with a StackOverflowError at Graph.java:1669. This may indicate a recursion or cyclic reference introduced indirectly by the fix.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions