Repository: RDFLib/rdflib

Issue:
Generated VALUES block for federated query binds blank nodes with invalid variable names
In the following query, the generated `VALUES` block contains bound bnodes, when they probably shouldn't. For example, we're getting `VALUES (_:Nd1ab3cb93cb6459fa46ff4e37aef1925, …` using the following query. By converting `[] rdfs:label "EN Singular"` (in `graph` and the query) to `<http://example.com/foo> rdfs:label "EN Singular"`, this all works as expected.

```python
import rdflib
import urllib.error

if __name__ == '__main__':
    graph = rdflib.Graph()
    graph.update(
        '''
        PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
        PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
        
        INSERT DATA {
            [] rdfs:label "EN Singular";
                rdf:value "house"@en.
        }
        '''
    )
    try:
        query_result = graph.query(
            '''
            PREFIX dct: <http://purl.org/dc/terms/>
            PREFIX ontolex: <http://www.w3.org/ns/lemon/ontolex#>
            PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
            PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
            PREFIX wd: <http://www.wikidata.org/entity/>
            PREFIX wikibase: <http://wikiba.se/ontology#>
    
            SELECT * WHERE {
                [] rdfs:label "EN Singular";
                    rdf:value ?enSingular.

                SERVICE <https://query.wikidata.org/sparql> {
                    ?enSingularLexicalEntry a ontolex:LexicalEntry;
                        dct:language wd:Q1860;
                        wikibase:lemma ?enSingular;
                        ontolex:lexicalForm ?enLexicalForm.
                }
            }
            '''
        )
        print(query_result.bindings)
    except urllib.error.HTTPError as e:
        print(e.fp.read().decode("utf-8"))
```

```bash
ERROR:root:SPARQL-QUERY: queryStr=PREFIX wikibase:<http://wikiba.se/ontology#> PREFIX wd:<http://www.wikidata.org/entity/> PREFIX ontolex:<http://www.w3.org/ns/lemon/ontolex#> PREFIX dct:<http://purl.org/dc/terms/> PREFIX xml:<http://www.w3.org/XML/1998/namespace> PREFIX xsd:<http://www.w3.org/2001/XMLSchema#> PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#> PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX owl:<http://www.w3.org/2002/07/owl#> SELECT REDUCED * WHERE {
                    ?enSingularLexicalEntry a ontolex:LexicalEntry;
                        dct:language wd:Q1860;
                        wikibase:lemma ?enSingular;
                        ontolex:lexicalForm ?enLexicalForm.
                }VALUES (_:Nd1ab3cb93cb6459fa46ff4e37aef1925 ?enSingular) {(_:N048ccf10ebd344d29b5675a21ebd4f7b "house"@en)}
java.util.concurrent.ExecutionException: org.openrdf.query.MalformedQueryException: Encountered " <BLANK_NODE_LABEL> "_:Nd1ab3cb93cb6459fa46ff4e37aef1925 "" at line 6, column 26.
Was expecting one of:
    ")" ...
    <VAR1> ...
    <VAR2> ...
    
	at java.util.concurrent.FutureTask.report(FutureTask.java:122)
	at java.util.concurrent.FutureTask.get(FutureTask.java:206)
	at com.bigdata.rdf.sail.webapp.BigdataServlet.submitApiTask(BigdataServlet.java:292)
	at com.bigdata.rdf.sail.webapp.QueryServlet.doSparqlQuery(QueryServlet.java:678)
	at com.bigdata.rdf.sail.webapp.QueryServlet.doPost(QueryServlet.java:275)
	at com.bigdata.rdf.sail.webapp.RESTServlet.doPost(RESTServlet.java:269)
	at com.bigdata.rdf.sail.webapp.MultiTenancyServlet.doPost(MultiTenancyServlet.java:195)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:865)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1655)
	at org.wikidata.query.rdf.blazegraph.throttling.ThrottlingFilter.doFilter(ThrottlingFilter.java:320)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
	at org.wikidata.query.rdf.blazegraph.throttling.SystemOverloadFilter.doFilter(SystemOverloadFilter.java:82)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
	at ch.qos.logback.classic.helpers.MDCInsertingServletFilter.doFilter(MDCInsertingServletFilter.java:49)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
	at org.wikidata.query.rdf.blazegraph.filters.QueryEventSenderFilter.doFilter(QueryEventSenderFilter.java:116)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
	at org.wikidata.query.rdf.blazegraph.filters.ClientIPFilter.doFilter(ClientIPFilter.java:43)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
	at org.wikidata.query.rdf.blazegraph.filters.JWTIdentityFilter.doFilter(JWTIdentityFilter.java:66)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
	at org.wikidata.query.rdf.blazegraph.filters.RealAgentFilter.doFilter(RealAgentFilter.java:33)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1642)
	at org.wikidata.query.rdf.blazegraph.filters.RequestConcurrencyFilter.doFilter(RequestConcurrencyFilter.java:50)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1634)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1242)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:220)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.Server.handle(Server.java:503)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
	at java.lang.Thread.run(Thread.java:750)
Caused by: org.openrdf.query.MalformedQueryException: Encountered " <BLANK_NODE_LABEL> "_:Nd1ab3cb93cb6459fa46ff4e37aef1925 "" at line 6, column 26.
Was expecting one of:
    ")" ...
    <VAR1> ...
    <VAR2> ...
    
	at com.bigdata.rdf.sail.sparql.Bigdata2ASTSPARQLParser.parseQuery2(Bigdata2ASTSPARQLParser.java:400)
	at com.bigdata.rdf.sail.webapp.QueryServlet$SparqlQueryTask.call(QueryServlet.java:741)
	at com.bigdata.rdf.sail.webapp.QueryServlet$SparqlQueryTask.call(QueryServlet.java:695)
	at com.bigdata.rdf.task.ApiTaskForIndexManager.call(ApiTaskForIndexManager.java:68)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	... 1 more
Caused by: com.bigdata.rdf.sail.sparql.ast.ParseException: Encountered " <BLANK_NODE_LABEL> "_:Nd1ab3cb93cb6459fa46ff4e37aef1925 "" at line 6, column 26.
Was expecting one of:
    ")" ...
    <VAR1> ...
    <VAR2> ...
    
	at com.bigdata.rdf.sail.sparql.ast.SyntaxTreeBuilder.generateParseException(SyntaxTreeBuilder.java:9722)
	at com.bigdata.rdf.sail.sparql.ast.SyntaxTreeBuilder.jj_consume_token(SyntaxTreeBuilder.java:9589)
	at com.bigdata.rdf.sail.sparql.ast.SyntaxTreeBuilder.InlineDataFull(SyntaxTreeBuilder.java:1205)
	at com.bigdata.rdf.sail.sparql.ast.SyntaxTreeBuilder.DataBlock(SyntaxTreeBuilder.java:1140)
	at com.bigdata.rdf.sail.sparql.ast.SyntaxTreeBuilder.BindingsClause(SyntaxTreeBuilder.java:1044)
	at com.bigdata.rdf.sail.sparql.ast.SyntaxTreeBuilder.SelectQuery(SyntaxTreeBuilder.java:382)
	at com.bigdata.rdf.sail.sparql.ast.SyntaxTreeBuilder.Query(SyntaxTreeBuilder.java:328)
	at com.bigdata.rdf.sail.sparql.ast.SyntaxTreeBuilder.QueryContainer(SyntaxTreeBuilder.java:216)
	at com.bigdata.rdf.sail.sparql.ast.SyntaxTreeBuilder.parseQuery(SyntaxTreeBuilder.java:32)
	at com.bigdata.rdf.sail.sparql.Bigdata2ASTSPARQLParser.parseQuery2(Bigdata2ASTSPARQLParser.java:336)
	... 7 more
Traceback (most recent call last):
  File "/Users/veyndan/Library/Application Support/JetBrains/IntelliJIdea2022.2/scratches/scratch_3.py", line 41, in <module>
    print(query_result.bindings)
  File "/Users/veyndan/Development/myankiplugin/.venv/lib/python3.9/site-packages/rdflib/query.py", line 184, in bindings
    self._bindings += list(self._genbindings)
  File "/Users/veyndan/Development/myankiplugin/.venv/lib/python3.9/site-packages/rdflib/plugins/sparql/evaluate.py", line 550, in <genexpr>
    return (row.project(project.PV) for row in res)
  File "/Users/veyndan/Development/myankiplugin/.venv/lib/python3.9/site-packages/rdflib/plugins/sparql/evaluate.py", line 123, in evalLazyJoin
    for b in evalPart(c, join.p2):
  File "/Users/veyndan/Development/myankiplugin/.venv/lib/python3.9/site-packages/rdflib/plugins/sparql/evaluate.py", line 342, in evalServiceQuery
    response = urlopen(
  File "/opt/homebrew/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 214, in urlopen
    return opener.open(url, data, timeout)
  File "/opt/homebrew/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 523, in open
    response = meth(req, response)
  File "/opt/homebrew/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 632, in http_response
    response = self.parent.error(
  File "/opt/homebrew/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 561, in error
    return self._call_chain(*args)
  File "/opt/homebrew/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 494, in _call_chain
    result = func(*args)
  File "/opt/homebrew/Cellar/python@3.9/3.9.13_1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/urllib/request.py", line 641, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 400: Bad Request
```

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/51779754/badge)](https://coveralls.io/builds/51779754)

Coverage decreased (-0.01%) to 90.452% when pulling **abcf85029b37c8fdd5dd367a92a137a2becc0e04 on veyndan:veyndan/2022-08-18/2079** into **a39d1436e00affc3cba9e903b22700029d8e8163 on RDFLib:master**.

aucampia: Thanks for the PR, I will review it tonight (CET).

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d006172c..bede2f68 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -267,6 +267,24 @@ and will be removed for release.
 <!-- -->
 <!-- -->
 
+
+<!-- -->
+<!-- -->
+<!-- CHANGE BARRIER: START PR #2079 -->
+<!-- -->
+<!-- -->
+
+- Fixed the generation of VALUES block for federated queries.
+  The values block was including non-variable values like BNodes which resulted
+  in invalid queries.
+  [PR #2079](https://github.com/RDFLib/rdflib/pull/2079).
+
+<!-- -->
+<!-- -->
+<!-- CHANGE BARRIER: END PR #2079 -->
+<!-- -->
+<!-- -->
+
 <!-- -->
 <!-- -->
 <!-- CHANGE BARRIER: START -->
diff --git a/rdflib/plugins/sparql/evaluate.py b/rdflib/plugins/sparql/evaluate.py
index 7b0f6e50..706b7673 100644
--- a/rdflib/plugins/sparql/evaluate.py
+++ b/rdflib/plugins/sparql/evaluate.py
@@ -386,7 +386,7 @@ def _buildQueryStringForServiceCall(ctx: QueryContext, match: re.Match) -> str:
         base = ctx.prologue.base  # type: ignore[union-attr]
         if base is not None and len(base) > 0:
             service_query = "BASE <" + base + "> " + service_query
-    sol = ctx.solution()
+    sol = [v for v in ctx.solution() if isinstance(v, Variable)]
     if len(sol) > 0:
         variables = " ".join([v.n3() for v in sol])
         variables_bound = " ".join([ctx.get(v).n3() for v in sol])


Test patch:
diff --git a/test/test_sparql/test_service.py b/test/test_sparql/test_service.py
index 8ed09cc8..53019771 100644
--- a/test/test_sparql/test_service.py
+++ b/test/test_sparql/test_service.py
@@ -70,6 +70,41 @@ def test_service_with_bind():
         assert len(r) == 3
 
 
+def test_service_with_bound_solutions():
+    g = Graph()
+    g.update(
+        """
+        INSERT DATA {
+          []
+            <http://www.w3.org/2002/07/owl#sameAs> <http://de.dbpedia.org/resource/John_Lilburne> ;
+            <http://purl.org/dc/terms/subject> <http://dbpedia.org/resource/Category:1614_births> .
+        }
+        """
+    )
+    q = """
+        SELECT ?sameAs ?dbpComment ?subject WHERE {
+          []
+            <http://www.w3.org/2002/07/owl#sameAs> ?sameAs ;
+            <http://purl.org/dc/terms/subject> ?subject .
+
+          SERVICE <http://DBpedia.org/sparql> {
+            SELECT ?sameAs ?dbpComment ?subject WHERE {
+              <http://dbpedia.org/resource/John_Lilburne>
+                <http://www.w3.org/2002/07/owl#sameAs> ?sameAs ;
+                <http://www.w3.org/2000/01/rdf-schema#comment> ?dbpComment ;
+                <http://purl.org/dc/terms/subject> ?subject .
+            }
+          }
+        }
+        LIMIT 2
+        """
+    results = helper.query_with_retry(g, q)
+    assert len(results) == 2
+
+    for r in results:
+        assert len(r) == 3
+
+
 def test_service_with_values():
     g = Graph()
     q = """select ?sameAs ?dbpComment ?subject
@@ -326,6 +361,7 @@ def test_with_mock(
 if __name__ == "__main__":
     test_service()
     test_service_with_bind()
+    test_service_with_bound_solutions()
     test_service_with_values()
     test_service_with_implicit_select()
     test_service_with_implicit_select_and_prefix()