diff options
author | Rob B <73846016+robons@users.noreply.github.com> | 2023-01-29 15:50:07 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-29 16:50:07 +0100 |
commit | c5c16dfafaf32dc46a06381a774822eb9be8cfbc (patch) | |
tree | db8b55f88e5aeae4c35f0c721973331152a7b1aa /rdflib/plugins/sparql/algebra.py | |
parent | fbb8279f0127e45cfa7741a9054de86284b795e7 (diff) | |
download | rdflib-c5c16dfafaf32dc46a06381a774822eb9be8cfbc.tar.gz |
fix: bug with `SELECT *` inside `SELECT *` (#2190)
Fixing use of `SELECT *` in sub-select within `SELECT *` parent query as discovered in https://github.com/RDFLib/rdflib/issues/1722.
Now when an instance of `SELECT *` is encountered, the query tree/plan builder now correctly considers the projected variables of any sub-select statements when deciding which variables should be projected out.
Fixes <https://github.com/RDFLib/rdflib/issues/1722>.
Diffstat (limited to 'rdflib/plugins/sparql/algebra.py')
-rw-r--r-- | rdflib/plugins/sparql/algebra.py | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/rdflib/plugins/sparql/algebra.py b/rdflib/plugins/sparql/algebra.py index d538920e..923957b2 100644 --- a/rdflib/plugins/sparql/algebra.py +++ b/rdflib/plugins/sparql/algebra.py @@ -511,6 +511,7 @@ def _findVars(x, res: Set[Variable]) -> Optional[CompValue]: # type: ignore[ret elif x.name == "SubSelect": if x.projection: res.update(v.var or v.evar for v in x.projection) + return x @@ -637,6 +638,7 @@ def translate(q: CompValue) -> Tuple[CompValue, List[Variable]]: traverse(q.where, functools.partial(_findVars, res=VS)) # all query types have a where part + # depth-first recursive generation of mapped query tree M = translateGroupGraphPattern(q.where) aggregate = False @@ -679,6 +681,12 @@ def translate(q: CompValue) -> Tuple[CompValue, List[Variable]]: if not q.projection: # select * + + # Find the first child projection in each branch of the mapped query tree, + # then include the variables it projects out in our projected variables. + for child_projection in _find_first_child_projections(M): + VS |= set(child_projection.PV) + PV = list(VS) else: PV = list() @@ -731,6 +739,21 @@ def translate(q: CompValue) -> Tuple[CompValue, List[Variable]]: return M, PV +def _find_first_child_projections(M: CompValue) -> Iterable[CompValue]: + """ + Recursively find the first child instance of a Projection operation in each of + the branches of the query execution plan/tree. + """ + + for child_op in M.values(): + if isinstance(child_op, CompValue): + if child_op.name == "Project": + yield child_op + else: + for child_projection in _find_first_child_projections(child_op): + yield child_projection + + # type error: Missing return statement def simplify(n: Any) -> Optional[CompValue]: # type: ignore[return] """Remove joins to empty BGPs""" |