Skip to content

Commit 2a24692

Browse files
authored
GH-5167 bug fix for exception with complex path in rsx:targetShape (#5177)
2 parents e25913a + 7c982dd commit 2a24692

141 files changed

Lines changed: 1820 additions & 75 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ShapeValidationContainer.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
import java.util.function.Supplier;
1717
import java.util.stream.Collectors;
1818

19-
import org.apache.commons.text.StringEscapeUtils;
2019
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
21-
import org.eclipse.rdf4j.sail.SailConnection;
2220
import org.eclipse.rdf4j.sail.SailException;
2321
import org.eclipse.rdf4j.sail.shacl.ast.Shape;
2422
import org.eclipse.rdf4j.sail.shacl.ast.planNodes.PlanNode;

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/StatementMatcher.java

Lines changed: 123 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
package org.eclipse.rdf4j.sail.shacl.ast;
1212

1313
import java.util.ArrayList;
14+
import java.util.Collections;
1415
import java.util.HashSet;
16+
import java.util.LinkedHashSet;
1517
import java.util.List;
1618
import java.util.Objects;
1719
import java.util.Set;
@@ -31,10 +33,10 @@ public class StatementMatcher {
3133
private final Variable<IRI> predicate;
3234
private final Variable<? extends Value> object;
3335

34-
// private final Set<String> varNames;
36+
// private final Set<String> varNames;
3537
private final Targetable origin;
3638

37-
private final Set<String> inheritedVarNames;
39+
private Set<String> inheritedVarNames;
3840

3941
private List<StatementMatcher> subset = List.of();
4042

@@ -216,37 +218,47 @@ private static String formatForToString(String field, String name, Value value)
216218

217219
private StatementMatcher swap(Variable<?> existingVariable, Variable<?> newVariable) {
218220
String subjectName = getSubjectName();
221+
String subjectBasename = getSubjectBasename();
219222
Resource subjectValue = getSubjectValue();
223+
220224
String predicateName = getPredicateName();
225+
String predicateBasename = getPredicateBasename();
221226
IRI predicateValue = getPredicateValue();
227+
222228
String objectName = getObjectName();
229+
String objectBasename = getObjectBasename();
223230
Value objectValue = getObjectValue();
231+
224232
boolean changed = false;
225233

226234
if (Objects.equals(existingVariable.name, subjectName)
227235
&& Objects.equals(existingVariable.value, subjectValue)) {
228236
changed = true;
229237
subjectName = newVariable.name;
230238
subjectValue = (Resource) newVariable.value;
239+
subjectBasename = newVariable.baseName;
231240
}
232241

233242
if (Objects.equals(existingVariable.name, predicateName)
234243
&& Objects.equals(existingVariable.value, predicateValue)) {
235244
changed = true;
236245
predicateName = newVariable.name;
237246
predicateValue = (IRI) newVariable.value;
247+
predicateBasename = newVariable.baseName;
238248
}
239249

240250
if (Objects.equals(existingVariable.name, objectName) && Objects.equals(existingVariable.value, objectValue)) {
241251
changed = true;
242252
objectName = newVariable.name;
243253
objectValue = newVariable.value;
254+
objectBasename = newVariable.baseName;
244255
}
245256

246257
if (changed) {
247258
assert subset.isEmpty();
248-
return new StatementMatcher(new Variable<>(subjectName, subjectValue),
249-
new Variable<>(predicateName, predicateValue), new Variable<>(objectName, objectValue), origin,
259+
return new StatementMatcher(new Variable<>(subjectName, subjectValue, subjectBasename),
260+
new Variable<>(predicateName, predicateValue, predicateBasename),
261+
new Variable<>(objectName, objectValue, objectBasename), origin,
250262
inheritedVarNames);
251263
}
252264
return this;
@@ -268,6 +280,10 @@ public String getSubjectName() {
268280
return subject.name;
269281
}
270282

283+
public String getSubjectBasename() {
284+
return subject.baseName;
285+
}
286+
271287
public Resource getSubjectValue() {
272288
return subject.value;
273289
}
@@ -280,6 +296,10 @@ public String getPredicateName() {
280296
return predicate.name;
281297
}
282298

299+
public String getPredicateBasename() {
300+
return predicate.baseName;
301+
}
302+
283303
public IRI getPredicateValue() {
284304
return predicate.value;
285305
}
@@ -292,6 +312,10 @@ public String getObjectName() {
292312
return object.name;
293313
}
294314

315+
public String getObjectBasename() {
316+
return object.baseName;
317+
}
318+
295319
public Value getObjectValue() {
296320
return object.value;
297321
}
@@ -376,13 +400,13 @@ public String getSparqlValuesDecl(Set<String> varNamesRestriction, boolean addIn
376400
return sb.toString();
377401
}
378402

379-
public Set<String> getVarNames(Set<String> varNamesRestriction, boolean addInheritedVarNames,
403+
public LinkedHashSet<String> getVarNames(Set<String> varNamesRestriction, boolean addInheritedVarNames,
380404
Set<String> varNamesInQueryFragment) {
381405
if (varNamesRestriction.isEmpty()) {
382-
return Set.of();
406+
return new LinkedHashSet<>();
383407
}
384408

385-
HashSet<String> ret = new HashSet<>();
409+
LinkedHashSet<String> ret = new LinkedHashSet<>();
386410
if (subject.name != null && varNamesRestriction.contains(subject.name)
387411
&& varNamesInQueryFragment.contains(subject.name)) {
388412
ret.add(subject.name);
@@ -462,6 +486,26 @@ public boolean hasObject(Variable<Value> variable) {
462486
return variable.name.equals(object.name);
463487
}
464488

489+
public Set<String> getInheritedVarNames() {
490+
return Set.copyOf(inheritedVarNames);
491+
}
492+
493+
public Set<String> getVarNames() {
494+
Set<String> varNames = new HashSet<>();
495+
496+
if (subject.name != null) {
497+
varNames.add(subject.name);
498+
}
499+
if (predicate.name != null) {
500+
varNames.add(predicate.name);
501+
}
502+
if (object.name != null) {
503+
varNames.add(object.name);
504+
}
505+
506+
return Collections.unmodifiableSet(varNames);
507+
}
508+
465509
public static class StableRandomVariableProvider {
466510

467511
// We just need a random base that isn't used elsewhere in the ShaclSail, but we don't want it to be stable so
@@ -485,9 +529,12 @@ public StableRandomVariableProvider(String prefix) {
485529
* increments of one.
486530
*
487531
* @param inputQuery the query string that should be normalized
532+
* @param union
488533
* @return a normalized query string
489534
*/
490-
public static String normalize(String inputQuery) {
535+
public static String normalize(String inputQuery, List<? extends Variable> protectedVars,
536+
List<StatementMatcher> union) {
537+
491538
if (!inputQuery.contains(BASE)) {
492539
return inputQuery;
493540
}
@@ -513,18 +560,30 @@ public static String normalize(String inputQuery) {
513560
if (lowest == 0 && incrementsOfOne) {
514561
return inputQuery;
515562
}
563+
String joinedProtectedVars = protectedVars.stream()
564+
.map(Variable::getName)
565+
.filter(Objects::nonNull)
566+
.filter(s -> s.contains(BASE))
567+
.collect(Collectors.joining());
516568

517-
return normalizeRange(inputQuery, lowest, highest);
569+
return normalizeRange(inputQuery, lowest, highest, joinedProtectedVars, union);
518570
}
519571

520-
private static String normalizeRange(String inputQuery, int lowest, int highest) {
572+
private static String normalizeRange(String inputQuery, int lowest, int highest, String joinedProtectedVars,
573+
List<StatementMatcher> union) {
521574

522575
String normalizedQuery = inputQuery;
523576
for (int i = 0; i <= highest; i++) {
524-
if (!normalizedQuery.contains(BASE + i + "_")) {
577+
String replacement = BASE + i + "_";
578+
if (!normalizedQuery.contains(replacement)) {
525579
for (int j = Math.max(i + 1, lowest); j <= highest; j++) {
526-
if (normalizedQuery.contains(BASE + j + "_")) {
527-
normalizedQuery = normalizedQuery.replace(BASE + j + "_", BASE + i + "_");
580+
String original = BASE + j + "_";
581+
if (normalizedQuery.contains(original)) {
582+
if (joinedProtectedVars.contains(original)) {
583+
continue;
584+
}
585+
normalizedQuery = normalizedQuery.replace(original, replacement);
586+
replaceInStatementMatcher(union, original, replacement);
528587
break;
529588
}
530589
}
@@ -534,6 +593,13 @@ private static String normalizeRange(String inputQuery, int lowest, int highest)
534593
return normalizedQuery;
535594
}
536595

596+
private static void replaceInStatementMatcher(List<StatementMatcher> statementMatchers, String original,
597+
String replacement) {
598+
for (StatementMatcher statementMatcher : statementMatchers) {
599+
statementMatcher.replaceVariableName(original, replacement);
600+
}
601+
}
602+
537603
public Variable<Value> next() {
538604
counter++;
539605

@@ -552,6 +618,44 @@ public Variable<Value> current() {
552618
}
553619
}
554620

621+
private void replaceVariableName(String original, String replacement) {
622+
623+
if (subject.name != null && subject.name.contains(original)) {
624+
subject.name = subject.name.replace(original, replacement);
625+
}
626+
if (subject.baseName != null && subject.baseName.contains(original)) {
627+
subject.baseName = subject.baseName.replace(original, replacement);
628+
}
629+
if (predicate.name != null && predicate.name.contains(original)) {
630+
predicate.name = predicate.name.replace(original, replacement);
631+
}
632+
if (predicate.baseName != null && predicate.baseName.contains(original)) {
633+
predicate.baseName = predicate.baseName.replace(original, replacement);
634+
}
635+
if (object.name != null && object.name.contains(original)) {
636+
object.name = object.name.replace(original, replacement);
637+
}
638+
if (object.baseName != null && object.baseName.contains(original)) {
639+
object.baseName = object.baseName.replace(original, replacement);
640+
}
641+
642+
boolean contains = false;
643+
for (String inheritedVarName : inheritedVarNames) {
644+
if (inheritedVarName.contains(original)) {
645+
contains = true;
646+
break;
647+
}
648+
}
649+
if (contains) {
650+
HashSet<String> newInheritedVarNames = new HashSet<>();
651+
for (String inheritedVarName : inheritedVarNames) {
652+
newInheritedVarNames.add(inheritedVarName.replace(original, replacement));
653+
}
654+
inheritedVarNames = newInheritedVarNames;
655+
}
656+
657+
}
658+
555659
public static class Variable<T extends Value> {
556660
public static final Variable<Value> VALUE = new Variable<>("value");
557661
public static final Variable<Value> THIS = new Variable<>("this");
@@ -576,6 +680,12 @@ public Variable(Variable<?> baseVariable, String name) {
576680
this.baseName = baseVariable.name;
577681
}
578682

683+
public Variable(String name, T value, String baseName) {
684+
this.name = name;
685+
this.value = value;
686+
this.baseName = baseName;
687+
}
688+
579689
public Variable(T value) {
580690
this.value = value;
581691
}

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/BindSelect.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public BindSelect(SailConnection connection, Resource[] dataGraph, SparqlFragmen
9090
throw new IllegalStateException();
9191
}
9292

93-
this.query = StatementMatcher.StableRandomVariableProvider.normalize(query.getFragment());
93+
this.query = StatementMatcher.StableRandomVariableProvider.normalize(query.getFragment(), vars, List.of());
9494
this.prefixes = query.getNamespacesForSparql();
9595
this.direction = direction;
9696
this.includePropertyShapeValues = includePropertyShapeValues;

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/BulkedExternalInnerJoin.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import java.util.ArrayDeque;
1515
import java.util.LinkedHashMap;
16+
import java.util.List;
1617
import java.util.Objects;
1718
import java.util.function.Function;
1819

@@ -25,7 +26,6 @@
2526
import org.eclipse.rdf4j.query.algebra.TupleExpr;
2627
import org.eclipse.rdf4j.query.algebra.evaluation.iterator.PeekMarkIterator;
2728
import org.eclipse.rdf4j.sail.SailConnection;
28-
import org.eclipse.rdf4j.sail.memory.MemoryStoreConnection;
2929
import org.eclipse.rdf4j.sail.shacl.ast.SparqlFragment;
3030
import org.eclipse.rdf4j.sail.shacl.ast.StatementMatcher;
3131
import org.eclipse.rdf4j.sail.shacl.ast.constraintcomponents.ConstraintComponent;
@@ -67,7 +67,7 @@ public BulkedExternalInnerJoin(PlanNode leftNode, SailConnection connection, Res
6767

6868
this.leftNode = PlanNodeHelper.handleSorting(this, leftNode, connectionsGroup);
6969
this.query = query.getNamespacesForSparql() + StatementMatcher.StableRandomVariableProvider
70-
.normalize(query.getFragment());
70+
.normalize(query.getFragment(), List.of(), List.of());
7171
this.connection = connection;
7272
assert this.connection != null;
7373
this.skipBasedOnPreviousConnection = skipBasedOnPreviousConnection;

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/BulkedExternalLeftOuterJoin.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
package org.eclipse.rdf4j.sail.shacl.ast.planNodes;
1313

1414
import java.util.ArrayDeque;
15+
import java.util.List;
1516
import java.util.Objects;
1617
import java.util.function.Function;
1718

@@ -23,7 +24,6 @@
2324
import org.eclipse.rdf4j.query.algebra.TupleExpr;
2425
import org.eclipse.rdf4j.query.algebra.evaluation.iterator.PeekMarkIterator;
2526
import org.eclipse.rdf4j.sail.SailConnection;
26-
import org.eclipse.rdf4j.sail.memory.MemoryStoreConnection;
2727
import org.eclipse.rdf4j.sail.shacl.ast.SparqlFragment;
2828
import org.eclipse.rdf4j.sail.shacl.ast.StatementMatcher;
2929
import org.eclipse.rdf4j.sail.shacl.wrapper.data.ConnectionsGroup;
@@ -51,7 +51,7 @@ public BulkedExternalLeftOuterJoin(PlanNode leftNode, SailConnection connection,
5151
leftNode = PlanNodeHelper.handleSorting(this, leftNode, connectionsGroup);
5252
this.leftNode = leftNode;
5353
this.query = query.getNamespacesForSparql()
54-
+ StatementMatcher.StableRandomVariableProvider.normalize(query.getFragment());
54+
+ StatementMatcher.StableRandomVariableProvider.normalize(query.getFragment(), List.of(), List.of());
5555
this.connection = connection;
5656
assert this.connection != null;
5757
this.mapper = mapper;

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/ExternalFilterByQuery.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
package org.eclipse.rdf4j.sail.shacl.ast.planNodes;
1313

14+
import java.util.List;
1415
import java.util.Objects;
1516
import java.util.function.BiFunction;
1617
import java.util.function.Function;
@@ -59,15 +60,15 @@ public ExternalFilterByQuery(SailConnection connection, Resource[] dataGraph, Pl
5960
if (map != null) {
6061
this.queryString = queryFragment.getNamespacesForSparql()
6162
+ StatementMatcher.StableRandomVariableProvider.normalize("SELECT * "
62-
+ " WHERE {\n" + queryFragment.getFragment() + "\n}");
63+
+ " WHERE {\n" + queryFragment.getFragment() + "\n}", List.of(queryVariable), List.of());
6364

6465
} else {
6566
this.queryString = queryFragment.getNamespacesForSparql()
6667
+ StatementMatcher.StableRandomVariableProvider
6768
.normalize("SELECT " + queryVariable.asSparqlVariable()
68-
+ " WHERE {\n" + queryFragment.getFragment() + "\n}");
69+
+ " WHERE {\n" + queryFragment.getFragment() + "\n}", List.of(queryVariable),
70+
List.of());
6971
}
70-
7172
try {
7273
this.query = SparqlQueryParserCache.get(queryString);
7374
} catch (MalformedQueryException e) {

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/Formatter.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import org.eclipse.rdf4j.model.vocabulary.DCAT;
2020
import org.eclipse.rdf4j.model.vocabulary.FOAF;
2121
import org.eclipse.rdf4j.model.vocabulary.RDF;
22-
import org.eclipse.rdf4j.model.vocabulary.RDFS;
2322
import org.eclipse.rdf4j.model.vocabulary.SHACL;
2423
import org.eclipse.rdf4j.model.vocabulary.XSD;
2524

core/sail/shacl/src/main/java/org/eclipse/rdf4j/sail/shacl/ast/planNodes/PlanNode.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@
1515
import java.util.Set;
1616

1717
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
18-
import org.eclipse.rdf4j.model.IRI;
1918
import org.eclipse.rdf4j.model.Resource;
2019
import org.eclipse.rdf4j.model.Value;
21-
import org.eclipse.rdf4j.model.vocabulary.FOAF;
22-
import org.eclipse.rdf4j.model.vocabulary.RDF;
2320

2421
/**
2522
* @author Håvard Mikkelsen Ottestad

0 commit comments

Comments
 (0)