summaryrefslogtreecommitdiff
path: root/rdflib/plugins/sparql/algebra.py
diff options
context:
space:
mode:
authorRob B <73846016+robons@users.noreply.github.com>2023-01-29 15:50:07 +0000
committerGitHub <noreply@github.com>2023-01-29 16:50:07 +0100
commitc5c16dfafaf32dc46a06381a774822eb9be8cfbc (patch)
treedb8b55f88e5aeae4c35f0c721973331152a7b1aa /rdflib/plugins/sparql/algebra.py
parentfbb8279f0127e45cfa7741a9054de86284b795e7 (diff)
downloadrdflib-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.py23
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"""