Problem
When a sub-SELECT exposes a correlation variable that it produces via an aggregate (or BIND/OPTIONAL) rather than a top-level triple, the natural join with the enclosing pattern is not enforced on that variable. Rows that should be filtered out by the join survive with the parent's binding.
Repro
SELECT ?s
WHERE {
?s :p ?c .
{
SELECT ?s (COUNT(?x) AS ?c)
WHERE { ?s :r ?x }
GROUP BY ?s
}
}
Data: ex:a :p 2 ; :r ex:x1, ex:x2 (COUNT=2, matches :p) and ex:b :p 5 ; :r ex:y1 (COUNT=1, does NOT match :p=5).
Expected: only ex:a (the :p ?c == COUNT equality must hold).
Actual: both ex:a and ex:b returned — the ?c equality is never checked.
Root cause
In fluree-db-query/src/subquery.rs, the materialize-once hash join keys only on join_keys (correlation vars the subquery produces via a top-level required triple). A correlation var produced by an aggregate is excluded from join_keys, and the non-clobbering merge (subquery.rs:~420-430) keeps the parent's value without an equality check. So the join degenerates to the other keys (here ?s) only.
Scope / status
Suggested fix direction
Either include aggregate/BIND-produced correlation vars in the post-join equality check (filter merged rows where the parent binding ≠ the subquery binding for such vars), or extend the hash key to cover them. Needs care for the unbound-compatible case.
Problem
When a sub-SELECT exposes a correlation variable that it produces via an aggregate (or BIND/OPTIONAL) rather than a top-level triple, the natural join with the enclosing pattern is not enforced on that variable. Rows that should be filtered out by the join survive with the parent's binding.
Repro
Data:
ex:a :p 2 ; :r ex:x1, ex:x2(COUNT=2, matches:p) andex:b :p 5 ; :r ex:y1(COUNT=1, does NOT match:p=5).Expected: only
ex:a(the:p ?c == COUNTequality must hold).Actual: both
ex:aandex:breturned — the?cequality is never checked.Root cause
In
fluree-db-query/src/subquery.rs, the materialize-once hash join keys only onjoin_keys(correlation vars the subquery produces via a top-level required triple). A correlation var produced by an aggregate is excluded fromjoin_keys, and the non-clobbering merge (subquery.rs:~420-430) keeps the parent's value without an equality check. So the join degenerates to the other keys (here?s) only.Scope / status
origin/mainas well as on the PR branch (fix/groupby-datatype-expr-1362).Suggested fix direction
Either include aggregate/BIND-produced correlation vars in the post-join equality check (filter merged rows where the parent binding ≠ the subquery binding for such vars), or extend the hash key to cover them. Needs care for the unbound-compatible case.