Skip to content

Commit 334042e

Browse files
GH-4811 process also optional TEs when handling BIND
Signed-off-by: damyan.ognyanov <damyan.ognyanov@ontotext.com>
1 parent 743673b commit 334042e

File tree

3 files changed

+50
-5
lines changed

3 files changed

+50
-5
lines changed

core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/GraphPattern.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public void addRequiredTE(TupleExpr te) {
103103
*/
104104
void clearRequiredTEs() {
105105
requiredTEs.clear();
106+
optionalTEs.clear();
106107
}
107108

108109
public void addRequiredSP(Var subjVar, Var predVar, Var objVar) {
@@ -173,6 +174,18 @@ public void clear() {
173174
public TupleExpr buildTupleExpr() {
174175
TupleExpr result = buildJoinFromRequiredTEs();
175176

177+
result = buildOptionalTE(result);
178+
179+
for (ValueExpr constraint : constraints) {
180+
result = new Filter(result, constraint);
181+
}
182+
return result;
183+
}
184+
185+
/**
186+
* Build optionals to the supplied TE
187+
*/
188+
public TupleExpr buildOptionalTE(TupleExpr result) {
176189
for (Map.Entry<TupleExpr, List<ValueExpr>> entry : optionalTEs) {
177190
List<ValueExpr> constraints = entry.getValue();
178191
if (constraints != null && !constraints.isEmpty()) {
@@ -186,11 +199,6 @@ public TupleExpr buildTupleExpr() {
186199
result = new LeftJoin(result, entry.getKey());
187200
}
188201
}
189-
190-
for (ValueExpr constraint : constraints) {
191-
result = new Filter(result, constraint);
192-
}
193-
194202
return result;
195203
}
196204

core/queryparser/sparql/src/main/java/org/eclipse/rdf4j/query/parser/sparql/TupleExprBuilder.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2378,6 +2378,8 @@ public Object visit(ASTBind node, Object data) throws VisitorException {
23782378

23792379
// get a tupleExpr that represents the basic graph pattern, sofar.
23802380
TupleExpr arg = graphPattern.buildJoinFromRequiredTEs();
2381+
// apply optionals, if any
2382+
arg = graphPattern.buildOptionalTE(arg);
23812383

23822384
// check if alias is not previously used in the BGP
23832385
if (arg.getBindingNames().contains(alias)) {

core/queryparser/sparql/src/test/java/org/eclipse/rdf4j/query/parser/sparql/TupleExprBuilderTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,41 @@ public void testServiceGraphPatternChopping() throws Exception {
266266

267267
}
268268

269+
@Test
270+
public void testOtionalBindCoalesce() throws Exception {
271+
StringBuilder qb = new StringBuilder();
272+
qb.append("SELECT ?result \n");
273+
qb.append("WHERE { \n");
274+
qb.append("OPTIONAL {\n" +
275+
" OPTIONAL {\n" +
276+
" BIND(\"value\" AS ?foo)\n" +
277+
" }\n" +
278+
" BIND(COALESCE(?foo, \"no value\") AS ?result)\n" +
279+
" }");
280+
qb.append(" } ");
281+
282+
ASTQueryContainer qc = SyntaxTreeBuilder.parseQuery(qb.toString());
283+
TupleExpr result = builder.visit(qc, null);
284+
String expected = "Projection\n" +
285+
" ProjectionElemList\n" +
286+
" ProjectionElem \"result\"\n" +
287+
" LeftJoin\n" +
288+
" SingletonSet\n" +
289+
" Extension\n" +
290+
" LeftJoin\n" +
291+
" SingletonSet\n" +
292+
" Extension\n" +
293+
" SingletonSet\n" +
294+
" ExtensionElem (foo)\n" +
295+
" ValueConstant (value=\"value\")\n" +
296+
" ExtensionElem (result)\n" +
297+
" Coalesce\n" +
298+
" Var (name=foo)\n" +
299+
" ValueConstant (value=\"no value\")\n";
300+
assertEquals(expected.replace("\r\n", "\n"), result.toString().replace("\r\n", "\n"));
301+
// System.out.println(result);
302+
}
303+
269304
private class ServiceNodeFinder extends AbstractASTVisitor {
270305

271306
private final List<String> graphPatterns = new ArrayList<>();

0 commit comments

Comments
 (0)